mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-14 17:08:09 +00:00
commit
5b0b0d6d36
@ -507,6 +507,8 @@ namespace client
|
|||||||
<< "Host: " << u.host_ << "\r\n"
|
<< "Host: " << u.host_ << "\r\n"
|
||||||
<< "Accept: */*\r\n"
|
<< "Accept: */*\r\n"
|
||||||
<< "User-Agent: Wget/1.11.4\r\n"
|
<< "User-Agent: Wget/1.11.4\r\n"
|
||||||
|
//<< "Accept-Encoding: gzip\r\n"
|
||||||
|
<< "X-Accept-Encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n"
|
||||||
<< "Connection: close\r\n";
|
<< "Connection: close\r\n";
|
||||||
if (m_Etag.length () > 0) // etag
|
if (m_Etag.length () > 0) // etag
|
||||||
request << i2p::util::http::IF_NONE_MATCH << ": \"" << m_Etag << "\"\r\n";
|
request << i2p::util::http::IF_NONE_MATCH << ": \"" << m_Etag << "\"\r\n";
|
||||||
@ -545,7 +547,7 @@ namespace client
|
|||||||
response >> status; // status
|
response >> status; // status
|
||||||
if (status == 200) // OK
|
if (status == 200) // OK
|
||||||
{
|
{
|
||||||
bool isChunked = false;
|
bool isChunked = false, isGzip = false;
|
||||||
std::string header, statusMessage;
|
std::string header, statusMessage;
|
||||||
std::getline (response, statusMessage);
|
std::getline (response, statusMessage);
|
||||||
// read until new line meaning end of header
|
// read until new line meaning end of header
|
||||||
@ -556,6 +558,8 @@ namespace client
|
|||||||
if (colon != std::string::npos)
|
if (colon != std::string::npos)
|
||||||
{
|
{
|
||||||
std::string field = header.substr (0, colon);
|
std::string field = header.substr (0, colon);
|
||||||
|
boost::to_lower (field); // field are not case-sensitive
|
||||||
|
colon++;
|
||||||
header.resize (header.length () - 1); // delete \r
|
header.resize (header.length () - 1); // delete \r
|
||||||
if (field == i2p::util::http::ETAG)
|
if (field == i2p::util::http::ETAG)
|
||||||
m_Etag = header.substr (colon + 1);
|
m_Etag = header.substr (colon + 1);
|
||||||
@ -563,6 +567,9 @@ namespace client
|
|||||||
m_LastModified = header.substr (colon + 1);
|
m_LastModified = header.substr (colon + 1);
|
||||||
else if (field == i2p::util::http::TRANSFER_ENCODING)
|
else if (field == i2p::util::http::TRANSFER_ENCODING)
|
||||||
isChunked = !header.compare (colon + 1, std::string::npos, "chunked");
|
isChunked = !header.compare (colon + 1, std::string::npos, "chunked");
|
||||||
|
else if (field == i2p::util::http::CONTENT_ENCODING)
|
||||||
|
isGzip = !header.compare (colon + 1, std::string::npos, "gzip") ||
|
||||||
|
!header.compare (colon + 1, std::string::npos, "x-i2p-gzip");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrint (eLogInfo, "Addressbook: ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified);
|
LogPrint (eLogInfo, "Addressbook: ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified);
|
||||||
@ -570,13 +577,13 @@ namespace client
|
|||||||
{
|
{
|
||||||
success = true;
|
success = true;
|
||||||
if (!isChunked)
|
if (!isChunked)
|
||||||
m_Book.LoadHostsFromStream (response);
|
success = ProcessResponse (response, isGzip);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// merge chunks
|
// merge chunks
|
||||||
std::stringstream merged;
|
std::stringstream merged;
|
||||||
i2p::util::http::MergeChunkedResponse (response, merged);
|
i2p::util::http::MergeChunkedResponse (response, merged);
|
||||||
m_Book.LoadHostsFromStream (merged);
|
success = ProcessResponse (merged, isGzip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -599,6 +606,23 @@ namespace client
|
|||||||
|
|
||||||
m_Book.DownloadComplete (success);
|
m_Book.DownloadComplete (success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AddressBookSubscription::ProcessResponse (std::stringstream& s, bool isGzip)
|
||||||
|
{
|
||||||
|
if (isGzip)
|
||||||
|
{
|
||||||
|
std::stringstream uncompressed;
|
||||||
|
i2p::data::GzipInflator inflator;
|
||||||
|
inflator.Inflate (s, uncompressed);
|
||||||
|
if (!uncompressed.fail ())
|
||||||
|
m_Book.LoadHostsFromStream (uncompressed);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_Book.LoadHostsFromStream (s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +92,7 @@ namespace client
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
void Request ();
|
void Request ();
|
||||||
|
bool ProcessResponse (std::stringstream& s, bool isGzip = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
38
Base.cpp
38
Base.cpp
@ -302,6 +302,44 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& s)
|
||||||
|
{
|
||||||
|
m_IsDirty = true;
|
||||||
|
uint8_t * out = new uint8_t[GZIP_CHUNK_SIZE];
|
||||||
|
m_Inflator.next_in = const_cast<uint8_t *>(in);
|
||||||
|
m_Inflator.avail_in = inLen;
|
||||||
|
int ret;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
m_Inflator.next_out = out;
|
||||||
|
m_Inflator.avail_out = GZIP_CHUNK_SIZE;
|
||||||
|
ret = inflate (&m_Inflator, Z_NO_FLUSH);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Decompression error ", ret);
|
||||||
|
inflateEnd (&m_Inflator);
|
||||||
|
s.setstate(std::ios_base::failbit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
s.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out);
|
||||||
|
}
|
||||||
|
while (!m_Inflator.avail_out); // more data to read
|
||||||
|
delete[] out;
|
||||||
|
return ret == Z_STREAM_END || ret < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GzipInflator::Inflate (std::istream& in, std::ostream& out)
|
||||||
|
{
|
||||||
|
uint8_t * buf = new uint8_t[GZIP_CHUNK_SIZE];
|
||||||
|
while (!in.eof ())
|
||||||
|
{
|
||||||
|
in.read ((char *)buf, GZIP_CHUNK_SIZE);
|
||||||
|
Inflate (buf, in.gcount (), out);
|
||||||
|
}
|
||||||
|
delete[] buf;
|
||||||
|
}
|
||||||
|
|
||||||
GzipDeflator::GzipDeflator (): m_IsDirty (false)
|
GzipDeflator::GzipDeflator (): m_IsDirty (false)
|
||||||
{
|
{
|
||||||
memset (&m_Deflator, 0, sizeof (m_Deflator));
|
memset (&m_Deflator, 0, sizeof (m_Deflator));
|
||||||
|
7
Base.h
7
Base.h
@ -5,6 +5,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@ -92,6 +93,7 @@ namespace data
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const size_t GZIP_CHUNK_SIZE = 16384;
|
||||||
class GzipInflator
|
class GzipInflator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -100,7 +102,10 @@ namespace data
|
|||||||
~GzipInflator ();
|
~GzipInflator ();
|
||||||
|
|
||||||
size_t Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen);
|
size_t Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen);
|
||||||
|
bool Inflate (const uint8_t * in, size_t inLen, std::ostream& s);
|
||||||
|
// return true when finshed or error, s failbit will be set in case of error
|
||||||
|
void Inflate (std::istream& in, std::ostream& out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
z_stream m_Inflator;
|
z_stream m_Inflator;
|
||||||
|
@ -37,6 +37,8 @@ namespace client
|
|||||||
m_SharedLocalDestination->Start ();
|
m_SharedLocalDestination->Start ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_AddressBook.Start ();
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> localDestination;
|
std::shared_ptr<ClientDestination> localDestination;
|
||||||
bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy);
|
bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy);
|
||||||
if (httproxy) {
|
if (httproxy) {
|
||||||
@ -94,25 +96,19 @@ namespace client
|
|||||||
m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort);
|
m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort);
|
||||||
m_BOBCommandChannel->Start ();
|
m_BOBCommandChannel->Start ();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_AddressBook.Start ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientContext::Stop ()
|
void ClientContext::Stop ()
|
||||||
{
|
{
|
||||||
if (m_HttpProxy) {
|
LogPrint(eLogInfo, "Clients: stopping HTTP Proxy");
|
||||||
LogPrint(eLogInfo, "Clients: stopping HTTP Proxy");
|
m_HttpProxy->Stop();
|
||||||
m_HttpProxy->Stop();
|
delete m_HttpProxy;
|
||||||
delete m_HttpProxy;
|
m_HttpProxy = nullptr;
|
||||||
m_HttpProxy = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_SocksProxy) {
|
LogPrint(eLogInfo, "Clients: stopping SOCKS Proxy");
|
||||||
LogPrint(eLogInfo, "Clients: stopping SOCKS Proxy");
|
m_SocksProxy->Stop();
|
||||||
m_SocksProxy->Stop();
|
delete m_SocksProxy;
|
||||||
delete m_SocksProxy;
|
m_SocksProxy = nullptr;
|
||||||
m_SocksProxy = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& it: m_ClientTunnels)
|
for (auto& it: m_ClientTunnels)
|
||||||
{
|
{
|
||||||
|
77
Family.cpp
Normal file
77
Family.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include "util.h"
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include "Log.h"
|
||||||
|
#include "Family.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace data
|
||||||
|
{
|
||||||
|
Families::Families ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Families::~Families ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Families::LoadCertificate (const std::string& filename)
|
||||||
|
{
|
||||||
|
SSL_CTX * ctx = SSL_CTX_new (TLSv1_method ());
|
||||||
|
int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
SSL * ssl = SSL_new (ctx);
|
||||||
|
X509 * cert = SSL_get_certificate (ssl);
|
||||||
|
// verify
|
||||||
|
if (cert)
|
||||||
|
{
|
||||||
|
// extract issuer name
|
||||||
|
char name[100];
|
||||||
|
X509_NAME_oneline (X509_get_issuer_name(cert), name, 100);
|
||||||
|
auto pkey = X509_get_pubkey (cert);
|
||||||
|
int keyType = EVP_PKEY_type(pkey->type);
|
||||||
|
switch (keyType)
|
||||||
|
{
|
||||||
|
case EVP_PKEY_DSA:
|
||||||
|
// TODO:
|
||||||
|
break;
|
||||||
|
case EVP_PKEY_EC:
|
||||||
|
{
|
||||||
|
//EC_KEY * ecKey = EVP_PKEY_get0_EC_KEY (pkey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LogPrint (eLogWarning, "Family: Certificate key type ", keyType, " is not supported");
|
||||||
|
}
|
||||||
|
EVP_PKEY_free (pkey);
|
||||||
|
}
|
||||||
|
SSL_free (ssl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "Family: Can't open certificate file ", filename);
|
||||||
|
SSL_CTX_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Families::LoadCertificates ()
|
||||||
|
{
|
||||||
|
boost::filesystem::path familyDir = i2p::util::filesystem::GetCertificatesDir() / "family";
|
||||||
|
|
||||||
|
if (!boost::filesystem::exists (familyDir)) return;
|
||||||
|
int numCertificates = 0;
|
||||||
|
boost::filesystem::directory_iterator end; // empty
|
||||||
|
for (boost::filesystem::directory_iterator it (familyDir); it != end; ++it)
|
||||||
|
{
|
||||||
|
if (boost::filesystem::is_regular_file (it->status()) && it->path ().extension () == ".crt")
|
||||||
|
{
|
||||||
|
LoadCertificate (it->path ().string ());
|
||||||
|
numCertificates++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (numCertificates > 0)
|
||||||
|
LogPrint (eLogInfo, "Family: ", numCertificates, " certificates loaded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
32
Family.h
Normal file
32
Family.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef FAMILY_H__
|
||||||
|
#define FAMILY_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include "Signature.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace data
|
||||||
|
{
|
||||||
|
class Families
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Families ();
|
||||||
|
~Families ();
|
||||||
|
void LoadCertificates ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void LoadCertificate (const std::string& filename);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::map<std::string, std::shared_ptr<i2p::crypto::Verifier> > m_SigningKeys;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -37,6 +37,7 @@ namespace data
|
|||||||
|
|
||||||
void NetDb::Start ()
|
void NetDb::Start ()
|
||||||
{
|
{
|
||||||
|
m_Families.LoadCertificates ();
|
||||||
Load ();
|
Load ();
|
||||||
if (m_RouterInfos.size () < 25) // reseed if # of router less than 50
|
if (m_RouterInfos.size () < 25) // reseed if # of router less than 50
|
||||||
Reseed ();
|
Reseed ();
|
||||||
|
2
NetDb.h
2
NetDb.h
@ -18,6 +18,7 @@
|
|||||||
#include "TunnelPool.h"
|
#include "TunnelPool.h"
|
||||||
#include "Reseed.h"
|
#include "Reseed.h"
|
||||||
#include "NetDbRequests.h"
|
#include "NetDbRequests.h"
|
||||||
|
#include "Family.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@ -95,6 +96,7 @@ namespace data
|
|||||||
|
|
||||||
GzipInflator m_Inflator;
|
GzipInflator m_Inflator;
|
||||||
Reseeder * m_Reseeder;
|
Reseeder * m_Reseeder;
|
||||||
|
Families m_Families;
|
||||||
|
|
||||||
friend class NetDbRequests;
|
friend class NetDbRequests;
|
||||||
NetDbRequests m_Requests;
|
NetDbRequests m_Requests;
|
||||||
|
@ -45,6 +45,7 @@ set (LIBI2PD_SRC
|
|||||||
"${CMAKE_SOURCE_DIR}/Base.cpp"
|
"${CMAKE_SOURCE_DIR}/Base.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/util.cpp"
|
"${CMAKE_SOURCE_DIR}/util.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/Datagram.cpp"
|
"${CMAKE_SOURCE_DIR}/Datagram.cpp"
|
||||||
|
"${CMAKE_SOURCE_DIR}/Family.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/Signature.cpp"
|
"${CMAKE_SOURCE_DIR}/Signature.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/api.cpp"
|
"${CMAKE_SOURCE_DIR}/api.cpp"
|
||||||
)
|
)
|
||||||
|
@ -4,7 +4,8 @@ LIB_SRC = \
|
|||||||
Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \
|
Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \
|
||||||
SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
|
SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
|
||||||
Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \
|
Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \
|
||||||
Destination.cpp Base.cpp I2PEndian.cpp Config.cpp util.cpp api.cpp
|
Destination.cpp Base.cpp I2PEndian.cpp Config.cpp Family.cpp util.cpp \
|
||||||
|
api.cpp
|
||||||
|
|
||||||
LIB_CLIENT_SRC = \
|
LIB_CLIENT_SRC = \
|
||||||
AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \
|
AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \
|
||||||
|
1
util.cpp
1
util.cpp
@ -212,6 +212,7 @@ namespace http
|
|||||||
if (colon != std::string::npos)
|
if (colon != std::string::npos)
|
||||||
{
|
{
|
||||||
std::string field = header.substr (0, colon);
|
std::string field = header.substr (0, colon);
|
||||||
|
boost::to_lower (field);
|
||||||
if (field == i2p::util::http::TRANSFER_ENCODING)
|
if (field == i2p::util::http::TRANSFER_ENCODING)
|
||||||
isChunked = (header.find ("chunked", colon + 1) != std::string::npos);
|
isChunked = (header.find ("chunked", colon + 1) != std::string::npos);
|
||||||
}
|
}
|
||||||
|
13
util.h
13
util.h
@ -29,12 +29,15 @@ namespace util
|
|||||||
|
|
||||||
namespace http
|
namespace http
|
||||||
{
|
{
|
||||||
const char ETAG[] = "ETag";
|
// in (lower case)
|
||||||
|
const char ETAG[] = "etag"; // ETag
|
||||||
|
const char LAST_MODIFIED[] = "last-modified"; // Last-Modified
|
||||||
|
const char TRANSFER_ENCODING[] = "transfer-encoding"; // Transfer-Encoding
|
||||||
|
const char CONTENT_ENCODING[] = "content-encoding"; // Content-Encoding
|
||||||
|
// out
|
||||||
const char IF_NONE_MATCH[] = "If-None-Match";
|
const char IF_NONE_MATCH[] = "If-None-Match";
|
||||||
const char IF_MODIFIED_SINCE[] = "If-Modified-Since";
|
const char IF_MODIFIED_SINCE[] = "If-Modified-Since";
|
||||||
const char LAST_MODIFIED[] = "Last-Modified";
|
|
||||||
const char TRANSFER_ENCODING[] = "Transfer-Encoding";
|
|
||||||
|
|
||||||
std::string GetHttpContent (std::istream& response);
|
std::string GetHttpContent (std::istream& response);
|
||||||
void MergeChunkedResponse (std::istream& response, std::ostream& merged);
|
void MergeChunkedResponse (std::istream& response, std::ostream& merged);
|
||||||
std::string urlDecode(const std::string& data);
|
std::string urlDecode(const std::string& data);
|
||||||
|
Loading…
Reference in New Issue
Block a user