Browse Source

Merge pull request #386 from PurpleI2P/openssl

recent changes
pull/394/head
orignal 9 years ago
parent
commit
5b0b0d6d36
  1. 30
      AddressBook.cpp
  2. 1
      AddressBook.h
  3. 38
      Base.cpp
  4. 7
      Base.h
  5. 24
      ClientContext.cpp
  6. 77
      Family.cpp
  7. 32
      Family.h
  8. 1
      NetDb.cpp
  9. 2
      NetDb.h
  10. 1
      build/CMakeLists.txt
  11. 3
      filelist.mk
  12. 1
      util.cpp
  13. 13
      util.h

30
AddressBook.cpp

@ -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;
}
} }
} }

1
AddressBook.h

@ -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

@ -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

@ -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;

24
ClientContext.cpp

@ -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

@ -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

@ -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

1
NetDb.cpp

@ -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

@ -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;

1
build/CMakeLists.txt

@ -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"
) )

3
filelist.mk

@ -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

@ -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

@ -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…
Cancel
Save