diff -Nru i2pd-0.7.0/api.cpp i2pd-0.8.0/api.cpp --- i2pd-0.7.0/api.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/api.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -39,11 +39,11 @@ { LogPrint("Shutdown started."); i2p::tunnel::tunnels.Stop(); - LogPrint("Tunnels stoped"); + LogPrint("Tunnels stopped"); i2p::transport::transports.Stop(); - LogPrint("Transports stoped"); + LogPrint("Transports stopped"); i2p::data::netdb.Stop(); - LogPrint("NetDB stoped"); + LogPrint("NetDB stopped"); StopLog (); } diff -Nru i2pd-0.7.0/ClientContext.cpp i2pd-0.8.0/ClientContext.cpp --- i2pd-0.7.0/ClientContext.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/ClientContext.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -1,4 +1,7 @@ #include +#include +#include +#include #include "util.h" #include "Log.h" #include "Identity.h" @@ -11,9 +14,8 @@ ClientContext context; ClientContext::ClientContext (): m_SharedLocalDestination (nullptr), - m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_IrcTunnel (nullptr), - m_ServerTunnel (nullptr), m_SamBridge (nullptr), m_BOBCommandChannel (nullptr), - m_I2PControlService (nullptr) + m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr), + m_BOBCommandChannel (nullptr), m_I2PControlService (nullptr) { } @@ -21,8 +23,6 @@ { delete m_HttpProxy; delete m_SocksProxy; - delete m_IrcTunnel; - delete m_ServerTunnel; delete m_SamBridge; delete m_BOBCommandChannel; delete m_I2PControlService; @@ -37,12 +37,15 @@ m_SharedLocalDestination->Start (); } + // proxies m_HttpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyport", 4446)); m_HttpProxy->Start(); LogPrint("HTTP Proxy started"); m_SocksProxy = new i2p::proxy::SOCKSProxy(i2p::util::config::GetArg("-socksproxyport", 4447)); m_SocksProxy->Start(); LogPrint("SOCKS Proxy Started"); + + // I2P tunnels std::string ircDestination = i2p::util::config::GetArg("-ircdest", ""); if (ircDestination.length () > 0) // ircdest is presented { @@ -50,19 +53,25 @@ std::string ircKeys = i2p::util::config::GetArg("-irckeys", ""); if (ircKeys.length () > 0) localDestination = LoadLocalDestination (ircKeys, false); - m_IrcTunnel = new I2PClientTunnel (ircDestination, i2p::util::config::GetArg("-ircport", 6668), localDestination); - m_IrcTunnel->Start (); + auto ircPort = i2p::util::config::GetArg("-ircport", 6668); + auto ircTunnel = new I2PClientTunnel (ircDestination, ircPort, localDestination); + ircTunnel->Start (); + m_ClientTunnels.insert (std::make_pair(ircPort, std::unique_ptr(ircTunnel))); LogPrint("IRC tunnel started"); } std::string eepKeys = i2p::util::config::GetArg("-eepkeys", ""); if (eepKeys.length () > 0) // eepkeys file is presented { auto localDestination = LoadLocalDestination (eepKeys, true); - m_ServerTunnel = new I2PServerTunnel (i2p::util::config::GetArg("-eephost", "127.0.0.1"), + auto serverTunnel = new I2PServerTunnel (i2p::util::config::GetArg("-eephost", "127.0.0.1"), i2p::util::config::GetArg("-eepport", 80), localDestination); - m_ServerTunnel->Start (); + serverTunnel->Start (); + m_ServerTunnels.insert (std::make_pair(localDestination->GetIdentHash (), std::unique_ptr(serverTunnel))); LogPrint("Server tunnel started"); } + ReadTunnels (); + + // SAM int samPort = i2p::util::config::GetArg("-samport", 0); if (samPort) { @@ -70,6 +79,8 @@ m_SamBridge->Start (); LogPrint("SAM bridge started"); } + + // BOB int bobPort = i2p::util::config::GetArg("-bobport", 0); if (bobPort) { @@ -77,6 +88,8 @@ m_BOBCommandChannel->Start (); LogPrint("BOB command channel started"); } + + // I2P Control int i2pcontrolPort = i2p::util::config::GetArg("-i2pcontrolport", 0); if (i2pcontrolPort) { @@ -93,45 +106,43 @@ m_HttpProxy->Stop(); delete m_HttpProxy; m_HttpProxy = nullptr; - LogPrint("HTTP Proxy stoped"); + LogPrint("HTTP Proxy stopped"); m_SocksProxy->Stop(); delete m_SocksProxy; m_SocksProxy = nullptr; - LogPrint("SOCKS Proxy stoped"); - if (m_IrcTunnel) + LogPrint("SOCKS Proxy stopped"); + for (auto& it: m_ClientTunnels) { - m_IrcTunnel->Stop (); - delete m_IrcTunnel; - m_IrcTunnel = nullptr; - LogPrint("IRC tunnel stoped"); - } - if (m_ServerTunnel) - { - m_ServerTunnel->Stop (); - delete m_ServerTunnel; - m_ServerTunnel = nullptr; - LogPrint("Server tunnel stoped"); - } + it.second->Stop (); + LogPrint("I2P client tunnel on port ", it.first, " stopped"); + } + m_ClientTunnels.clear (); + for (auto& it: m_ServerTunnels) + { + it.second->Stop (); + LogPrint("I2P server tunnel stopped"); + } + m_ServerTunnels.clear (); if (m_SamBridge) { m_SamBridge->Stop (); delete m_SamBridge; m_SamBridge = nullptr; - LogPrint("SAM brdige stoped"); + LogPrint("SAM brdige stopped"); } if (m_BOBCommandChannel) { m_BOBCommandChannel->Stop (); delete m_BOBCommandChannel; m_BOBCommandChannel = nullptr; - LogPrint("BOB command channel stoped"); + LogPrint("BOB command channel stopped"); } if (m_I2PControlService) { m_I2PControlService->Stop (); delete m_I2PControlService; m_I2PControlService = nullptr; - LogPrint("I2PControl stoped"); + LogPrint("I2PControl stopped"); } for (auto it: m_Destinations) @@ -173,10 +184,20 @@ LogPrint ("New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " created"); } - auto localDestination = new ClientDestination (keys, isPublic); + ClientDestination * localDestination = nullptr; std::unique_lock l(m_DestinationsMutex); - m_Destinations[localDestination->GetIdentHash ()] = localDestination; - localDestination->Start (); + auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ()); + if (it != m_Destinations.end ()) + { + LogPrint (eLogWarning, "Local destination ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " alreday exists"); + localDestination = it->second; + } + else + { + localDestination = new ClientDestination (keys, isPublic); + m_Destinations[localDestination->GetIdentHash ()] = localDestination; + localDestination->Start (); + } return localDestination; } @@ -235,5 +256,80 @@ return it->second; return nullptr; } + + void ClientContext::ReadTunnels () + { + std::ifstream ifs (i2p::util::filesystem::GetFullPath (TUNNELS_CONFIG_FILENAME)); + if (ifs.good ()) + { + boost::program_options::options_description params ("I2P tunnels parameters"); + params.add_options () + // client + (I2P_CLIENT_TUNNEL_NAME, boost::program_options::value >(), "tunnel name") + (I2P_CLIENT_TUNNEL_PORT, boost::program_options::value >(), "Local port") + (I2P_CLIENT_TUNNEL_DESTINATION, boost::program_options::value >(), "destination") + (I2P_CLIENT_TUNNEL_KEYS, boost::program_options::value >(), "keys") + // server + (I2P_SERVER_TUNNEL_NAME, boost::program_options::value >(), "tunnel name") + (I2P_SERVER_TUNNEL_HOST, boost::program_options::value >(), "host") + (I2P_SERVER_TUNNEL_PORT, boost::program_options::value >(), "port") + (I2P_SERVER_TUNNEL_KEYS, boost::program_options::value >(), "keys") + ; + + + boost::program_options::variables_map vm; + try + { + boost::program_options::store (boost::program_options::parse_config_file (ifs, params), vm); + boost::program_options::notify (vm); + } + catch (boost::program_options::error& ex) + { + LogPrint (eLogError, "Can't parse ", TUNNELS_CONFIG_FILENAME,": ", ex.what ()); + return; + } + + if (vm.count (I2P_CLIENT_TUNNEL_NAME) > 0) + { + auto names = vm[I2P_CLIENT_TUNNEL_NAME].as >(); + int numClientTunnels = names.size (); + auto ports = vm[I2P_CLIENT_TUNNEL_PORT].as >(); + auto destinations = vm[I2P_CLIENT_TUNNEL_DESTINATION].as >(); + auto keys = vm[I2P_CLIENT_TUNNEL_KEYS].as >(); + + for (int i = 0; i < numClientTunnels; i++) + { + ClientDestination * localDestination = nullptr; + if (keys[i].length () > 0) + localDestination = LoadLocalDestination (keys[i], false); + auto clientTunnel = new I2PClientTunnel (destinations[i], ports[i], localDestination); + if (m_ClientTunnels.insert (std::make_pair (ports[i], std::unique_ptr(clientTunnel))).second) + clientTunnel->Start (); + else + LogPrint (eLogError, "I2P client tunnel with port ", ports[i], " already exists"); + } + LogPrint (eLogInfo, numClientTunnels, " I2P client tunnels created"); + } + + if (vm.count (I2P_SERVER_TUNNEL_NAME) > 0) + { + auto names = vm[I2P_SERVER_TUNNEL_NAME].as >(); + int numServerTunnels = names.size (); + auto hosts = vm[I2P_SERVER_TUNNEL_HOST].as >(); + auto ports = vm[I2P_SERVER_TUNNEL_PORT].as >(); + auto keys = vm[I2P_SERVER_TUNNEL_KEYS].as >(); + for (int i = 0; i < numServerTunnels; i++) + { + auto localDestination = LoadLocalDestination (keys[i], true); + auto serverTunnel = new I2PServerTunnel (hosts[i], ports[i], localDestination); + if (m_ServerTunnels.insert (std::make_pair (localDestination->GetIdentHash (), std::unique_ptr(serverTunnel))).second) + serverTunnel->Start (); + else + LogPrint (eLogError, "I2P server tunnel for destination ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), " already exists"); + } + LogPrint (eLogInfo, numServerTunnels, " I2P server tunnels created"); + } + } + } } } diff -Nru i2pd-0.7.0/ClientContext.h i2pd-0.8.0/ClientContext.h --- i2pd-0.7.0/ClientContext.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/ClientContext.h 2015-02-22 22:07:42.000000000 +0000 @@ -1,7 +1,9 @@ #ifndef CLIENT_CONTEXT_H__ #define CLIENT_CONTEXT_H__ +#include #include +#include #include "Destination.h" #include "HTTPProxy.h" #include "SOCKS.h" @@ -15,6 +17,16 @@ { namespace client { + const char I2P_CLIENT_TUNNEL_NAME[] = "client.name"; + const char I2P_CLIENT_TUNNEL_PORT[] = "client.port"; + const char I2P_CLIENT_TUNNEL_DESTINATION[] = "client.destination"; + const char I2P_CLIENT_TUNNEL_KEYS[] = "client.keys"; + const char I2P_SERVER_TUNNEL_NAME[] = "server.name"; + const char I2P_SERVER_TUNNEL_HOST[] = "server.host"; + const char I2P_SERVER_TUNNEL_PORT[] = "server.port"; + const char I2P_SERVER_TUNNEL_KEYS[] = "server.keys"; + const char TUNNELS_CONFIG_FILENAME[] = "tunnels.cfg"; + class ClientContext { public: @@ -35,7 +47,12 @@ ClientDestination * LoadLocalDestination (const std::string& filename, bool isPublic); AddressBook& GetAddressBook () { return m_AddressBook; }; - + const SAMBridge * GetSAMBridge () const { return m_SamBridge; }; + + private: + + void ReadTunnels (); + private: std::mutex m_DestinationsMutex; @@ -46,8 +63,8 @@ i2p::proxy::HTTPProxy * m_HttpProxy; i2p::proxy::SOCKSProxy * m_SocksProxy; - I2PClientTunnel * m_IrcTunnel; - I2PServerTunnel * m_ServerTunnel; + std::map > m_ClientTunnels; // port->tunnel + std::map > m_ServerTunnels; // destination->tunnel SAMBridge * m_SamBridge; BOBCommandChannel * m_BOBCommandChannel; I2PControlService * m_I2PControlService; diff -Nru i2pd-0.7.0/contrib/certificates/reseed/cheezybudz_at_mail.i2p.crt i2pd-0.8.0/contrib/certificates/reseed/cheezybudz_at_mail.i2p.crt --- i2pd-0.7.0/contrib/certificates/reseed/cheezybudz_at_mail.i2p.crt 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.8.0/contrib/certificates/reseed/cheezybudz_at_mail.i2p.crt 2015-02-22 22:07:42.000000000 +0000 @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFhTCCA22gAwIBAgIEeCJXkjANBgkqhkiG9w0BAQ0FADBzMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEcMBoGA1UEAwwTY2hlZXp5YnVkekBt +YWlsLmkycDAeFw0xNDEyMTYyMTU3MTZaFw0yNDEyMTUyMTU3MTZaMHMxCzAJBgNV +BAYTAlhYMQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBB +bm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRwwGgYDVQQDDBNjaGVlenli +dWR6QG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgLkj +Jsp8pjRi5N/JHHz+MXisgbI9G0vpd3yDhHvae3oF87iiQbxflcdcoH0l5RZL0cAn +w4amhqoOk2qhf+NSAEkiPWhk7CzPBRwDExEM/gmHYLWXbfnoHGaEls9ORGuDlDmN +hCFJVrxaZocIOi/7gZ4A+tC8wq+1aoe0Yhr381OW59w9AdUAWjBWibO3V59dEklL +7HqfOc2v7AMKDLJWgPekj8ZbqA9lRxHM6Djtjz4d9QXeQa8j3xLXTX1QbkvJBBX1 +9Rzi/Nzv622lzoZ/Z/61jW7Bz+h9aJ6qp4on9K4ygUw/VduTOH/1ryQmw87x4MFQ +Z/Y86lOl7XZxBjtpYpGQW/5LmBe2BCfWgIYe9N5ionNgAe5TNEIDngP9AvJmcTyF +KcGgOgXQO9EeHEdgf4nC6RbGrb2sBtRjWJv5nOhHRG9tpwYkw/Zc5ZNHOymYpPMg +wce3me+1psJFt+gXhDcvxpRgTZpXfz91K/nKt3+szcYFluqhJLi6nL1TmXQVn51X +lGD1bcy1VUof+uKyb223JX5rm9WQ48GzUfy5cK4o+khEo0RLb21FwG5iJwVzhtoN +xQS1TO6pwLn8Si1ePRwntzlOm8DPIwdUkPBQNJ9DDkcdVia2GgbVM6LH8lrukekq +soYfwmOTsFRkGo04ujDI/IeMrl3zmJphyQkGx18CAwEAAaMhMB8wHQYDVR0OBBYE +FJ2MHeHnfCpEuYvC/9eK2ML9ne2eMA0GCSqGSIb3DQEBDQUAA4ICAQA3XUS7Zw1i +RJWPSu2oLzV7oTtIW5po2Gd5BL3oU6BvlK1zLw/z/soF/LopeHQudBYxYckyv4MG +gTNS9fcKkVdhNyLI/R2S0nQ/VFhTzuvq8HnnTOpvopA/cXTQlgrhGB2ajIZMYsXe +lei0V5H23etXTbYZWK6/IgoALk5vowde9lpJEIBhupIafqFg0tAo4LX07/eNxDOp +nXrShsYhHNaRhglS+0Gqj1UK0WvgMJxQKJm/VLi7jx8vfRkqXs/b76XT+VMQuUJd +l5llQwpOicQhX/ZTAO+iWrDaO7mz/ZDweLxnfWd3m2JwDJlE9K5l98zdcve96NRZ +ePnK8vBoAPQ9iHhwFSC5GpirK1KmT/BDLjqEF3H/HgPdPWSh97AUFpBryEIdZk1q +Czi9DCvwHNpbpI20Fo48+2N7sbvq4onZZqx5V0SjTj/9bHSSDwG9ok1JqWoZmRvo +p4MIywAJowlvPNc++jSHT3R7segeNUi/UdYCmm70j1av+0aEknmvPtF6atsHJ22X +5OMBhiPi1pudFWFJFWk4WOjrK/juwHHfHNgFVyziva4q6wPKrPno0gO5pCpfRUld +QAoSPgo8LAB3dugt5Xfsuone2GhLi1SLQlWFJWHswd/ypWa0FB+xn6Edkc1noOWY +06dwfEP/gTCAnSplLyrFWxnyHManBxq/bQ== +-----END CERTIFICATE----- diff -Nru i2pd-0.7.0/contrib/certificates/reseed/swat_at_mail.i2p.crt i2pd-0.8.0/contrib/certificates/reseed/swat_at_mail.i2p.crt --- i2pd-0.7.0/contrib/certificates/reseed/swat_at_mail.i2p.crt 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/contrib/certificates/reseed/swat_at_mail.i2p.crt 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFVjCCAz6gAwIBAgIEU71jgDANBgkqhkiG9w0BAQ0FADBtMQswCQYDVQQGEwJY -WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt -b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwNc3dhdEBtYWlsLmky -cDAeFw0xNDA3MDkxNTQ1MDRaFw0yNDA3MDgxNTQ1MDRaMG0xCzAJBgNVBAYTAlhY -MQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1v -dXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1zd2F0QG1haWwuaTJw -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjSj53hsbTqtzbnlf5LbR -HmfdC2br9QZaB9e5IQKprlTptdzqTrt2LRS6ZaJ06BKJgX3AfLflvyeUDUPoyg63 -I9a1kb1AsrcxvMkHXTUwPaO09caO5/CiQ3zx/iuTl4e0MmGe3cz7jsvZNdOVH0ba -B691GB2UBq2QjobGx01qjWtACCmoQIcEur2ns/l+VzAextBL70dSPN6EJAonQnWc -JvHf1vhXp5DWasaIovm8haNo48QpCo7NllsAjiONQM9rrJITvzFG9hX9cv/B1Kr4 -LCebTXv58ViXXFsnxYhktAFwP33fn1eCLraJ/BpaDR4+s3ovMC/7S+g5//+sQTd1 -pR/kXx4BmZWZdzs083Z/2skQON75j/qnMhUQqpFCqUImm4lOhlIGbzFJ4GQM6VCR -V4BbvC3XuDc6vlivLzWpUEU7Kc6YnfGgi2G//ZCj2CAoR7qZs/n9997C8oAvGY5z -XGVC/GqIFHuFvnDfPDvxGovYjLJ0KrNtAmp2Rb5812glnVdPwbRYRUBg3ICbNey3 -rmGPURDq0aHMTzX4gtM+/hCYYVnkzNMQvYuw9EZLZrK/XdM1a0U4kajZSKKJsTmW -uQwXSUVjTKQh//yL4zPoELucFk5r7apLePEm6aCeWuY2wVkR8KEFgNanwDckWQAm -Lk9r2t+Y/l2jS2NqBWFyr+cCAwEAATANBgkqhkiG9w0BAQ0FAAOCAgEAgFSquj/0 -iZYpFI1XarSIVpGMo0WLAmb9GZCn5yoXSeE6eypI/hHhXA4Bjdk2Ae33pXPNcCV8 -oT/gHj8943Wx7CTxty2zHzIsd92/HG2EG6U/HPp5l7yIJQaWoe/9tjQoaBhipZOK -+MiytkoBWkyXFqXnKQPExiadWB8axHtt66vrikOcSx6Ur3u5DPKybvY4fsuvo4+I -cLLgoueFm6I1WhmkVmjtm4k2yZ/Z3NEYjg52rv8NuYhRwK2JrQeRzMZv/zt5KhOt -05woHrzymjfFBu0M8uxX7EGZBIsc8zcEY7JL/NSMArw/QCgLU5bQF6+CsyxWUkt1 -obMRXU1oS9GjC/1F0kw52NOz2qzBn9tZBc1zs8+GLpYBUf9KiUMFOfJpkr706VqC -orgxRYwncicq+de2PlesxJb3DNPFuAzUNzAqxcVYDoFPAiL1zCEl0nhBrbN+x93X -ojTfV3UlbMjMkQKveYJxsi5/+jO1dHIkXpzK4bwFwHmJ2RCa6PualWhuXldX6mR+ -APoY6xeoPRlyKk+POrSwU+hywUudyPuFyzDMo8n1w4CyqL+/ky3YsLfGBM1phbb2 -GEnZ0J1HW34Pnie1rzaCak+3RfaZsImCwh1xXl/H7Ka9bLeUIfOuipSSroctdaiG -84wIiEjxgjW2ldM37gTX2XtE/blB1YPIZ5U= ------END CERTIFICATE----- diff -Nru i2pd-0.7.0/contrib/certificates/router/orignal_at_mail.i2p.crt i2pd-0.8.0/contrib/certificates/router/orignal_at_mail.i2p.crt --- i2pd-0.7.0/contrib/certificates/router/orignal_at_mail.i2p.crt 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.8.0/contrib/certificates/router/orignal_at_mail.i2p.crt 2015-02-22 22:07:42.000000000 +0000 @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVDCCAzwCCQC2r1XWYtqtAzANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQGEwJY +WDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMRMwEQYDVQQKDApQdXJwbGUgSTJQ +MQ0wCwYDVQQLDARJMlBEMR8wHQYJKoZIhvcNAQkBFhBvcmlnbmFsQG1haWwuaTJw +MB4XDTE1MDIyMjEzNTgxOFoXDTI1MDIxOTEzNTgxOFowbDELMAkGA1UEBhMCWFgx +CzAJBgNVBAgMAlhYMQswCQYDVQQHDAJYWDETMBEGA1UECgwKUHVycGxlIEkyUDEN +MAsGA1UECwwESTJQRDEfMB0GCSqGSIb3DQEJARYQb3JpZ25hbEBtYWlsLmkycDCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALp3D/gdvFjrMm+IE8tHZCWE +hQ6Pp0CCgCGDBC3WQFLqR98bqVPl4UwRG/MKY/LY7Woai06JNmGcpfw0LMoNnHxT +bvKtDRe/8kQdhdLHhgIkWKSbMvTAl7uUdV6FzsPgDR0x7scoFVWEhkF0wfmzGF2V +yr/WCBQejFPu69z03m5tRQ8Xjp2txWV45RawUmFu50bgbZvLCSLfTkIvxmfJzgPN +pJ3sPa/g7TBZl2uEiAu4uaEKvTuuzStOWCGgFaHYFVlTfFXTvmhFMqHfaidtzrlu +H35WGrmIWTDl6uGPC5QkSppvkj73rDj5aEyPzWMz5DN3YeECoVSchN+OJJCM6m7+ +rLFYXghVEp2h+T9O1GBRfcHlQ2E3CrWWvxhmK8dfteJmd501dyNX2paeuIg/aPFO +54/8m2r11uyF29hgY8VWLdXtqvwhKuK36PCzofEwDp9QQX8GRsEV4pZTrn4bDhGo +kb9BF7TZTqtL3uyiRmIyBXrNNiYlA1Xm4fyKRtxl0mrPaUXdgdnCt3KxOAJ8WM2B +7L/kk9U8C/nexHbMxIZfTap49XcUg5dxSO9kOBosIOcCUms8sAzBPDV2tWAByhYF +jI/Tutbd3F0+fvcmTcIFOlGbOxKgO2SfwXjv/44g/3LMK6IAMFB9UOc8KhnnJP0f +uAHvMXn1ahRs4pM1VizLAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAIOxdaXT+wfu +nv/+1hy5T4TlRMNNsuj79ROcy6Mp+JwMG50HjTc0qTlXh8C7nHybDJn4v7DA+Nyn +RxT0J5I+Gqn+Na9TaC9mLeX/lwe8/KomyhBWxjrsyWj1V6v/cLO924S2rtcfzMDm +l3SFh9YHM1KF/R9N1XYBwtMzr3bupWDnE1yycYp1F4sMLr5SMzMQ0svQpQEM2/y5 +kly8+eUzryhm+ag9x1686uEG5gxhQ1eHQoZEaClHUOsV+28+d5If7cqcYx9Hf5Tt +CiVjJQzdxBF+6GeiJtKxnLtevqlkbyIJt6Cm9/7YIy/ovRGF2AKSYN6oCwmZQ6i1 +8nRnFq5zE7O94m+GXconWZxy0wVqA6472HThMi7S+Tk/eLYen2ilGY+KCb9a0FH5 +5MOuWSoJZ8/HfW2VeQmL8EjhWm5F2ybg28wgXK4BOGR3jQi03Fsc+AFidnWxSKo0 +aiJoPgOsfyu8/fnCcAi07kSmjzUKIWskApgcpGQLNXHFK9mtg7+VA8esRnfLlKtP +tJf+nNAPY1sqHfGBzh7WWGWal5RGHF5nEm3ta3oiFF5sMKCJ6C87zVwFkEcRytGC +xOGmiG1O1RPrO5NG7rZUaQ4y1OKl2Y1H+nGONzZ3mvoAOvxEq6JtUnU2kZscpPlk +fpeOSDoGBYJGbIpzDreBDhxaZrwGq36k +-----END CERTIFICATE----- diff -Nru i2pd-0.7.0/contrib/certificates/ssl/cert.smartcom.org.crt i2pd-0.8.0/contrib/certificates/ssl/cert.smartcom.org.crt --- i2pd-0.7.0/contrib/certificates/ssl/cert.smartcom.org.crt 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/contrib/certificates/ssl/cert.smartcom.org.crt 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW -MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg -Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 -MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi -U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh -cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk -pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf -OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C -Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT -Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi -HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM -Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w -+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ -Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 -Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B -26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID -AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE -FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j -ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js -LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM -BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 -Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy -dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh -cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh -YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg -dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp -bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ -YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT -TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ -9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 -jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW -FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz -ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 -ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L -EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu -L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq -yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC -O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V -um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh -NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= ------END CERTIFICATE----- diff -Nru i2pd-0.7.0/contrib/certificates/ssl/i2p.feared.eu.crt i2pd-0.8.0/contrib/certificates/ssl/i2p.feared.eu.crt --- i2pd-0.7.0/contrib/certificates/ssl/i2p.feared.eu.crt 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/contrib/certificates/ssl/i2p.feared.eu.crt 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDhTCCAm2gAwIBAgIJAPVgXcMcr3zqMA0GCSqGSIb3DQEBBQUAMFkxCzAJBgNV -BAYTAkVVMQ8wDQYDVQQIDAZFdXJvcGUxDDAKBgNVBAoMA0kyUDETMBEGA1UECwwK -T3V0cHJveGllczEWMBQGA1UEAwwNaTJwLmZlYXJlZC5ldTAeFw0xMjEwMjkxNzMw -MDZaFw0yMTAxMTUxNzMwMDZaMFkxCzAJBgNVBAYTAkVVMQ8wDQYDVQQIDAZFdXJv -cGUxDDAKBgNVBAoMA0kyUDETMBEGA1UECwwKT3V0cHJveGllczEWMBQGA1UEAwwN -aTJwLmZlYXJlZC5ldTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOUh -y2+6Q4RO+b5WPXX/cZ/9fiI7aWGe/C7z0083HOEqnkgGCYgxFWUCed6/eZbYoZ7/ -PV1BAuEereNwTp+Ov7fQB2H73O9sSAEejW6O4C2PZiZWaPxpZiTJNENbLOZxJnIN -+fSqmA5pqvGkYAJ2heZH4v4tayun7Vib58GWuizhzJ4EvhOrOrLq/YHrxMn++r4e -kNNbq4QzWpfxNa7ocDY9OJh5qFzuc+6wKj1m1syK6euDqs5d6X+y0aDTMgRxey2b -tkmNx9wC0flLg1oMcv9o1zN+dENy7Inkd/SqbSjLUqDTJzdq6xURVsgLoV63pb6r -B4gbGIlriYWK/mOPTTkCAwEAAaNQME4wHQYDVR0OBBYEFOI94JZ3Rb2RVmr8QjOp -u3KfVSrNMB8GA1UdIwQYMBaAFOI94JZ3Rb2RVmr8QjOpu3KfVSrNMAwGA1UdEwQF -MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAD7bI05zg9nf9qanq4ZNw/rvEzYQRBmy -MqzZjcwBMGvbcEbS+zYAdAkfxmN3l/AT4I4z138Om0ud4ZJUQTVlRsJkMlmLD4Rt -Jbi2rl7mrY7Qupgu5hvgH+ZaEWr7LTq+tFjPycRS+zijw9NToKeAsgEex9zYIOYD -BxDUn/trvyA41ItvegWh803IsZUBb45Via+bopid9aFFkejRrck9hhcQ6fVh2yju -nuVwHrxNvGc0NmmJ7zI+nPESFS+TAYbWXikDhc5Vtyiuoz47WZU1cgXYYMejK4WA -+3GLvei7qKm4GOJSg7BngF5Iyj/n7ML1rBqTlN3KA1YOgpGCwJlKzto= ------END CERTIFICATE----- diff -Nru i2pd-0.7.0/contrib/certificates/ssl/i2p.mooo.com2.crt i2pd-0.8.0/contrib/certificates/ssl/i2p.mooo.com2.crt --- i2pd-0.7.0/contrib/certificates/ssl/i2p.mooo.com2.crt 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.8.0/contrib/certificates/ssl/i2p.mooo.com2.crt 2015-02-22 22:07:42.000000000 +0000 @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDvTCCAqWgAwIBAgIJAOeW0ejPrHimMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNV +BAYTAlVTMQ0wCwYDVQQIDARub25lMQ0wCwYDVQQHDARub25lMQ0wCwYDVQQKDARu +b25lMQ0wCwYDVQQLDARub25lMRUwEwYDVQQDDAxpMnAubW9vby5jb20xEzARBgkq +hkiG9w0BCQEWBG5vbmUwHhcNMTUwMjA4MTczMzA5WhcNMTkwMzE5MTczMzA5WjB1 +MQswCQYDVQQGEwJVUzENMAsGA1UECAwEbm9uZTENMAsGA1UEBwwEbm9uZTENMAsG +A1UECgwEbm9uZTENMAsGA1UECwwEbm9uZTEVMBMGA1UEAwwMaTJwLm1vb28uY29t +MRMwEQYJKoZIhvcNAQkBFgRub25lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAqxej7oRl9GOb8benIBCENrJXoow1iWhI9M+2nU0SaonrCDql5M2YMlwd +HzYUWtFbRjz2NinjB0fgFq9cfzHfr1Sc8k/OeGg1jvNfqt8wWo9tryQNjiHtDQUZ +6lQ5T13I+lj0CBasowgbApKQfrYjvaeuTaVYTfP8IVA60hoUQ+sy9JN+Unsx3/0Y +PLLd98+bT27qYuBNRB1g/ifUTd9Wosj2PevGBlCxYDaUjmCG4Q8kcQr87KvM6RTu +3AV61s/Wyy1j2YemlGG/ZhJ44YnlVMSu1vTjt9HInVf3lRRx/+RzbQO3lqeVC8LC +Bq3KbSlfJVx4vHslfHwBFw9A4rmD1QIDAQABo1AwTjAdBgNVHQ4EFgQUsSUvX0ED +yivB67iksVwZ+b8vLtQwHwYDVR0jBBgwFoAUsSUvX0EDyivB67iksVwZ+b8vLtQw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAde4wts7Q8TylFEc38ftJ +2f285fFIR7P1SSbBcHPK2eBwLEg0zJyFrCeiHuEpPrn+d5GqL2zOskjfcESGmDBT +aFajj8jPBJj/AmpkdWJG6a1YKro5tu9wrlenGwHOHu2/Cl0IJvafxrOs2x4G+2Nl +5Hcw/FIy8mK7eIch4pACfi0zNMZ6KMCKfX9bxPrQo78WdBfVjbrIBlgyOQJ5NJEF +JlWvS7Butv7eERi4I2huN5VRJSCFzjbuO+tjP3I8IB6WgdBmTeqq8ObtXRgahBuD +ZmkvqVSfIzK5JN4GjO8FOdCBomuwm9A92kgmAptwQwAHM9qCDJpH8L07/7poxlGb +iA== +-----END CERTIFICATE----- diff -Nru i2pd-0.7.0/contrib/certificates/ssl/i2pseed.zarrenspry.info.crt i2pd-0.8.0/contrib/certificates/ssl/i2pseed.zarrenspry.info.crt --- i2pd-0.7.0/contrib/certificates/ssl/i2pseed.zarrenspry.info.crt 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.8.0/contrib/certificates/ssl/i2pseed.zarrenspry.info.crt 2015-02-22 22:07:42.000000000 +0000 @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEkzCCA3ugAwIBAgIJAKsW7idQxp0aMA0GCSqGSIb3DQEBCwUAMIHfMQswCQYD +VQQGEwJVSzEgMB4GA1UECAwXaTJwc2VlZC56YXJyZW5zcHJ5LmluZm8xIDAeBgNV +BAcMF2kycHNlZWQuemFycmVuc3ByeS5pbmZvMSAwHgYDVQQKDBdpMnBzZWVkLnph +cnJlbnNwcnkuaW5mbzEgMB4GA1UECwwXaTJwc2VlZC56YXJyZW5zcHJ5LmluZm8x +IDAeBgNVBAMMF2kycHNlZWQuemFycmVuc3ByeS5pbmZvMSYwJAYJKoZIhvcNAQkB +FhdpMnBzZWVkLnphcnJlbnNwcnkuaW5mbzAeFw0xNDEyMjgxOTI3MDdaFw0xOTAy +MDUxOTI3MDdaMIHfMQswCQYDVQQGEwJVSzEgMB4GA1UECAwXaTJwc2VlZC56YXJy +ZW5zcHJ5LmluZm8xIDAeBgNVBAcMF2kycHNlZWQuemFycmVuc3ByeS5pbmZvMSAw +HgYDVQQKDBdpMnBzZWVkLnphcnJlbnNwcnkuaW5mbzEgMB4GA1UECwwXaTJwc2Vl +ZC56YXJyZW5zcHJ5LmluZm8xIDAeBgNVBAMMF2kycHNlZWQuemFycmVuc3ByeS5p +bmZvMSYwJAYJKoZIhvcNAQkBFhdpMnBzZWVkLnphcnJlbnNwcnkuaW5mbzCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANrEncHwS+7R0Ti/jZa2Ex7ujglV +huYO59nLxeAOpEQwn6V41X5+L0hmhM0zuYavuP1jzKfF/Cn0CG1PqkGbEnXrTOGf +4gMj2wy/UVVFXaPQwldi+CEiNo6nI5S+T/upg5VK6M5/ahYbfIbX5xF27QNPV5qW +RnM0VK4gIQkFFtpiI0dFcEU9VYe+cg7a4Jvxc5LzqaIBZHWMX6alPfBT70LkYiiQ +76IRw5oBmqZjfIdiudRhFkezMkDomKSgLR2/0HJbekq2WeLXJLMPM1rdpCYldBEi +t6Zng9uAJa1mA6Al4RhO1aQEPj9Vo5h+Vj6FHJAJJcb+YW6wLKBkJVGLF4UCAwEA +AaNQME4wHQYDVR0OBBYEFL538Fr1l/9YQgG+iZvJUuOzAaVaMB8GA1UdIwQYMBaA +FL538Fr1l/9YQgG+iZvJUuOzAaVaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAKq7KEnR0V43PsA5D23Lhawy5W/BDs4RO3LkYSxi+zR4EAMC8RhafrmG +6IZVp+ykplZtFK3Kkw1osakcvmHRLoPCXPWLibXtWMEpmH4GhWJKf5Ct1kY0VkEE +ALP7vCtjDm5l6WBaNOZYv25wwg5wgjyhzfJtLxzyRRPOjUuv0M3FFwJEAauzoo+4 +nle91IHNcWPIq1kgWUwWBHpLgZ2RpSOZS9MBOCkjHwQhoebhpgwSPgUHvBJ7FoLb +AeAdwpgPdIQ9gZEZEPfCPfG/Qp60yLAhkT2CF7F1h47VYe8LGBDbd1HGpSwjulq/ +lnvV4zDIoKhbQhUpxwgHo79nxcgddOA= +-----END CERTIFICATE----- diff -Nru i2pd-0.7.0/contrib/certificates/ssl/netdb.i2p2.no2.crt i2pd-0.8.0/contrib/certificates/ssl/netdb.i2p2.no2.crt --- i2pd-0.7.0/contrib/certificates/ssl/netdb.i2p2.no2.crt 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.8.0/contrib/certificates/ssl/netdb.i2p2.no2.crt 2015-02-22 22:07:42.000000000 +0000 @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID1TCCAr2gAwIBAgIJAOd9wIt+w/I5MA0GCSqGSIb3DQEBCwUAMIGAMQswCQYD +VQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzEMMAoGA1UECgwD +STJQMQwwCgYDVQQLDANJMlAxFjAUBgNVBAMMDW5ldGRiLmkycDIubm8xHzAdBgkq +hkiG9w0BCQEWEG1lZWhAaTJwbWFpbC5vcmcwHhcNMTQxMjA2MjM1OTM1WhcNMjAw +NTI4MjM1OTM1WjCBgDELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNV +BAcMBE9zbG8xDDAKBgNVBAoMA0kyUDEMMAoGA1UECwwDSTJQMRYwFAYDVQQDDA1u +ZXRkYi5pMnAyLm5vMR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmtRtAALMImh0G0X+AtMpJNBa +HduNkg5t+0juitKRboXXAp5k7yN9qnimlBxlAicNb+QubcDuL+WV91NKz43dd6Xp +SAewqMFRPUAki8uYzoh+hQEfzyd3NmadUKquYZsYwomhHnraOmLZLbxD6ED3FEwl +hGBJwYnhyMZUCgB5+DEEHg8RdLz+H0bMrwz3e7/0lMtH6lM1lIHz0KBULWLp7Om0 +sk3rmmhPUIXqfoY8X3vClI74o0KcslMVaF4rt3lAHdoi3lwA6Qbdqq9nC9rPWHUS +USQQ/MKsNfDTGsHkbW2l0VgNvJkw92DwHTXSJrsEqgkdV/B1hHxCKgL44c/CbwID +AQABo1AwTjAdBgNVHQ4EFgQUCkebDZE05yKMbXORa6gO+aLdCscwHwYDVR0jBBgw +FoAUCkebDZE05yKMbXORa6gO+aLdCscwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQsFAAOCAQEAfHO0g5M//X5xDIuXGCeqQMUrF3r1N45a+0kqo2b/rd9USueNGrJl +KE7MfDgShy2d4strZ1m0M4StW0RlUUZ4V4FYwzcknF6VXbOQK3BTrAeOwuxsrHoT +abrMZ36ABYur5WakOYtPyQ5oXFUAIpGBe9LH7q3XLegSOfftvc2xdJ+VK0n4MEfY +GfaRGMNW/pxGYLWvao3soOJMtp6cQ5KIYGuX92DMon/UgPBqEygeUj7aIqjhRss0 +b0dUZQyHccAG+e5NeTF2ifHCEh2rZY18VGxPL7KLrCQigu5lif1TTv5CDO5rKrHl +TuTOsnooMxUH4ThIVI9cxXk6bzRMehLghA== +-----END CERTIFICATE----- diff -Nru i2pd-0.7.0/contrib/certificates/ssl/reseed.info.crt i2pd-0.8.0/contrib/certificates/ssl/reseed.info.crt --- i2pd-0.7.0/contrib/certificates/ssl/reseed.info.crt 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/contrib/certificates/ssl/reseed.info.crt 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDRDCCAiwCCQDCm/Zrmali9zANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJB -VTETMBEGA1UECBMKU29tZS1TdGF0ZTELMAkGA1UEBxMCSEgxDDAKBgNVBAoTA0ky -UDEPMA0GA1UECxMGcmVzZWVkMRQwEgYDVQQDEwtyZXNlZWQuaW5mbzAeFw0xMjEw -MjcxODU3NDNaFw0xNjEyMDUxODU3NDNaMGQxCzAJBgNVBAYTAkFVMRMwEQYDVQQI -EwpTb21lLVN0YXRlMQswCQYDVQQHEwJISDEMMAoGA1UEChMDSTJQMQ8wDQYDVQQL -EwZyZXNlZWQxFDASBgNVBAMTC3Jlc2VlZC5pbmZvMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAt9nz0iUvjdX4Hkhfk0FbBOeEP4i/FG3V4VrEdQfcviSF -XgzGYeRtGsvrFWP/5+6bcGnOkIy/jrKJfij3AjKJh8gTzqiNNNnV8VcHwFSNp+hZ -D4BM+UHPACV1Pjd3HQe6f0+LvcTs3HQgIkNkwUyqRuXOm/5Mk6SWSu1740aSwHCj -Kk0x1FByzI0YBvXCPX6TVk6sJqKkQyLzK0CSGSeqUq8GvGCq+jT9k62Su7ooxCwi -GzxaFjMdVYxuI8cuT5Cni+SUw1Ia8vhESnIy6slwzk37xNI80VuMvRT6rD2KcXDH -mK7ml1qL0rJWoF5AE+x/nen4V41mouv1W9rk3wTlTQIDAQABMA0GCSqGSIb3DQEB -BQUAA4IBAQAr6RBviBDW4bnPDTcdtstTDdaYX9yzoh+zzeGB0dUR26GKoOjpSItb -B9nrsW1eJ2wbblfGBUoXhcmNByKHXXHejMhmurHjdei2BuLbTsknN8DPKXu5UF9z -cg4cKQkxgzXOcNYlaF4+sfwFXDHJ4we/8vduVgkyo8R66543/Sh/nIMvq2slRT4w -wIBOVcMb2XxlbdwHW9XALAz9sto+4GH9GAC24f8ngluOpHijMnOOIo4dHibQ5hM9 -KcDpHezP0ugMTAxS2NmtVahwAqa2IjpqR7aEQ2wLvxQzDqrXo93L93+b2FKRUQXH -Duud/n/w0kVV3DaIGikOsJayoanR+9HD ------END CERTIFICATE----- diff -Nru i2pd-0.7.0/Daemon.cpp i2pd-0.8.0/Daemon.cpp --- i2pd-0.7.0/Daemon.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/Daemon.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -128,15 +128,15 @@ { LogPrint("Shutdown started."); i2p::client::context.Stop(); - LogPrint("Client stoped"); + LogPrint("Client stopped"); i2p::tunnel::tunnels.Stop(); - LogPrint("Tunnels stoped"); + LogPrint("Tunnels stopped"); i2p::transport::transports.Stop(); - LogPrint("Transports stoped"); + LogPrint("Transports stopped"); i2p::data::netdb.Stop(); - LogPrint("NetDB stoped"); + LogPrint("NetDB stopped"); d.httpServer->Stop(); - LogPrint("HTTP Server stoped"); + LogPrint("HTTP Server stopped"); #ifdef USE_UPNP i2p::UPnP::upnpc.Stop(); #endif diff -Nru i2pd-0.7.0/debian/changelog i2pd-0.8.0/debian/changelog --- i2pd-0.7.0/debian/changelog 2015-02-04 13:04:18.000000000 +0000 +++ i2pd-0.8.0/debian/changelog 2015-02-23 12:31:41.000000000 +0000 @@ -1,3 +1,119 @@ +i2pd (0.8.0-1~trusty+1) trusty; urgency=medium + + * Uploading to PPA + + -- Kill Your TV Mon, 23 Feb 2015 12:31:31 +0000 + +i2pd (0.8.0-1) unstable; urgency=medium + + [ Kill Your TV ] + * New upstream version + + [ orignal ] + * fixed build for boost below 1.49 + * fixed compilation bug for boost < 1.49 and boost 1.49 with gcc 4.7 + * cleand destination requests every 15 seconds + * fixed memory leak + * cleanup from extra log messages + * check for duplicate msgID + * use unique_ptr for incomplete message + * use unique_ptr for requested destination + * use shared_ptr for inbound tunnels + * teminate non-connected NTCP session + * check accepted socket for error + * drop second incoming connection with same identity + * check if connection to peer exists already + * fixed race condition + + [ Francisco Blas (klondike) Izquierdo Riera ] + * Get Jump services working again although, at what price\! + * URLdecode the base64 part of the key + + [ orignal ] + * fixed race condition + * fixed memory leak + * clean obsolete SSU data + + [ Kill Your TV ] + * Sync reseed servers with the java router + + [ orignal ] + * read more data from socket if available + * use 'available' method + * separate receivers thread + * terminate receivers + * receive multiple UDP packets + * don't look for session if a packet is from same endpoint as previous + * delete messages sent to disconnected session + * fxied race condition + * allow netDb cleanup after every 500 messages + * don't insert same transit tunnel twice + * terminate non-responding NTCP sessions by timeout + * ban abusing IPs + * fixed memory leak + * ban abusing ipv6 addresses + * use insert instead [] + * complete session if presented + * cleanup dead peers + * fixed race condition + + [ multikatt ] + * typo: stoped->stopped + + [ orignal ] + * fixed hand at shutdown + * fixed race condition + * fixed memory leak + * config file for I2PTunnels + * read tunnels.cfg + * make sure only one I2P tunnel per local prot + * doesn't create same local destination twice + * multiple server I2P tunnels + * read all sections from tunnels.cfg + * don't throw exception + * catch sendto exception + * fixed typo + * unique_ptr for sent and incomplete messages + * fixed crash + + [ Kill Your TV ] + * Remove reseed host, no longer in use + + [ orignal ] + * SSU data receive batching + + [ Kill Your TV ] + * New certificate; will be switched on the server for a future release. + + [ orignal ] + * client hello for HTTPS + * process server certificate + * send ClientKeyExchange + * calculate master secret + * MAC and encryption keys + * reduced amount of logging + * hanshakes hash and finishes message + * tls 1.2 and RSA_WITH_AES_256_CBC_SHA256 + * send ChangeCipherSpecs + * tls encrypt and decrypt + * encrypt finishes message + * moved https code to TlsSession + * calculate MAC + * use 256 bytes block for keys expansion + * fixed incorrect MAC calculation + * proper handshake messages hash calculations + * send and receive data + * extract https content + * ClientKeyExchange length depend on key length from ceritifcate + * include https hosts to reseeder's list + * show SAM sessions through web interface + * 128 bytes key expansion + * original_at_mail.i2p.crt added + * handle incoming connection failure + * Update version.h + + -- Kill Your TV Mon, 23 Feb 2015 01:47:29 +0000 + i2pd (0.7.0-1~trusty+1) trusty; urgency=medium * Building for Trusty diff -Nru i2pd-0.7.0/Destination.cpp i2pd-0.8.0/Destination.cpp --- i2pd-0.7.0/Destination.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/Destination.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -192,7 +192,7 @@ m_Service.post (std::bind (&ClientDestination::HandleDeliveryStatusMessage, this, msg)); } - void ClientDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from) + void ClientDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) { uint8_t typeID = buf[I2NP_HEADER_TYPEID_OFFSET]; switch (typeID) diff -Nru i2pd-0.7.0/Destination.h i2pd-0.8.0/Destination.h --- i2pd-0.7.0/Destination.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/Destination.h 2015-02-22 22:07:42.000000000 +0000 @@ -86,7 +86,7 @@ // implements GarlicDestination const i2p::data::LeaseSet * GetLeaseSet (); - void HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from); + void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); // override GarlicDestination bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); diff -Nru i2pd-0.7.0/Garlic.cpp i2pd-0.8.0/Garlic.cpp --- i2pd-0.7.0/Garlic.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/Garlic.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -400,7 +400,7 @@ } void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr decryption, - i2p::tunnel::InboundTunnel * from) + std::shared_ptr from) { uint16_t tagCount = bufbe16toh (buf); buf += 2; len -= 2; @@ -439,7 +439,7 @@ HandleGarlicPayload (buf, payloadSize, from); } - void GarlicDestination::HandleGarlicPayload (uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from) + void GarlicDestination::HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr from) { int numCloves = buf[0]; LogPrint (numCloves," cloves"); diff -Nru i2pd-0.7.0/Garlic.h i2pd-0.8.0/Garlic.h --- i2pd-0.7.0/Garlic.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/Garlic.h 2015-02-22 22:07:42.000000000 +0000 @@ -121,7 +121,7 @@ virtual void SetLeaseSetUpdated (); virtual const i2p::data::LeaseSet * GetLeaseSet () = 0; // TODO - virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from) = 0; + virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) = 0; protected: @@ -131,8 +131,8 @@ private: void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr decryption, - i2p::tunnel::InboundTunnel * from); - void HandleGarlicPayload (uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from); + std::shared_ptr from); + void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr from); private: diff -Nru i2pd-0.7.0/HTTPProxy.cpp i2pd-0.8.0/HTTPProxy.cpp --- i2pd-0.7.0/HTTPProxy.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/HTTPProxy.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -5,6 +5,7 @@ #include #include #include "HTTPProxy.h" +#include "util.h" #include "Identity.h" #include "Streaming.h" #include "Destination.h" @@ -35,6 +36,7 @@ void HTTPRequestFailed(/*std::string message*/); void ExtractRequest(); bool ValidateHTTPRequest(); + void HandleJumpServices(); bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len); void SentHTTPFailed(const boost::system::error_code & ecode); void HandleStreamRequestComplete (std::shared_ptr stream); @@ -124,9 +126,41 @@ return true; } + void HTTPProxyHandler::HandleJumpServices() { + static const char * helpermark1 = "?i2paddresshelper="; + static const char * helpermark2 = "&i2paddresshelper="; + size_t addressHelperPos1 = m_path.rfind (helpermark1); + size_t addressHelperPos2 = m_path.rfind (helpermark2); + size_t addressHelperPos; + if (addressHelperPos1 == std::string::npos) + { + if (addressHelperPos2 == std::string::npos) + return; //Not a jump service + else + addressHelperPos = addressHelperPos2; + } + else + { + if (addressHelperPos2 == std::string::npos) + addressHelperPos = addressHelperPos1; + else if ( addressHelperPos1 > addressHelperPos2 ) + addressHelperPos = addressHelperPos1; + else + addressHelperPos = addressHelperPos2; + } + auto base64 = m_path.substr (addressHelperPos + strlen(helpermark1)); + base64 = i2p::util::http::urlDecode(base64); //Some of the symbols may be urlencoded + LogPrint (eLogDebug,"Jump service for ", m_address, " found at ", base64, ". Inserting to address book"); + //TODO: this is very dangerous and broken. We should ask the user before doing anything see http://pastethis.i2p/raw/pn5fL4YNJL7OSWj3Sc6N/ + //TODO: we could redirect the user again to avoid dirtiness in the browser + i2p::client::context.GetAddressBook ().InsertAddress (m_address, base64); + m_path.erase(addressHelperPos); + } + bool HTTPProxyHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len) { ExtractRequest(); //TODO: parse earlier if (!ValidateHTTPRequest()) return false; + HandleJumpServices(); m_request = m_method; m_request.push_back(' '); m_request += m_path; diff -Nru i2pd-0.7.0/HTTPServer.cpp i2pd-0.8.0/HTTPServer.cpp --- i2pd-0.7.0/HTTPServer.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/HTTPServer.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -469,6 +469,9 @@ const char HTTP_COMMAND_LOCAL_DESTINATIONS[] = "local_destinations"; const char HTTP_COMMAND_LOCAL_DESTINATION[] = "local_destination"; const char HTTP_PARAM_BASE32_ADDRESS[] = "b32"; + const char HTTP_COMMAND_SAM_SESSIONS[] = "sam_sessions"; + const char HTTP_COMMAND_SAM_SESSION[] = "sam_session"; + const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; namespace misc_strings { @@ -673,7 +676,10 @@ s << "
Local destinations"; s << "
Tunnels"; s << "
Transit tunnels"; - s << "
Transports
"; + s << "
Transports"; + if (i2p::client::context.GetSAMBridge ()) + s << "
SAM sessions"; + s << "
"; if (i2p::context.AcceptsTunnels ()) s << "
Stop accepting tunnels
"; @@ -706,6 +712,15 @@ auto b32 = params[HTTP_PARAM_BASE32_ADDRESS]; ShowLocalDestination (b32, s); } + else if (cmd == HTTP_COMMAND_SAM_SESSIONS) + ShowSAMSessions (s); + else if (cmd == HTTP_COMMAND_SAM_SESSION) + { + std::map params; + ExtractParams (command.substr (paramsPos), params); + auto id = params[HTTP_PARAM_SAM_SESSION_ID]; + ShowSAMSession (id, s); + } } void HTTPConnection::ShowTransports (std::stringstream& s) @@ -743,6 +758,8 @@ s << endpoint.address ().to_string () << ":" << endpoint.port (); if (!outgoing) s << "-->"; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; + if (it.second->GetRelayTag ()) + s << " [itag:" << it.second->GetRelayTag () << "]"; s << "
"; s << std::endl; } @@ -848,6 +865,51 @@ } } } + + void HTTPConnection::ShowSAMSessions (std::stringstream& s) + { + auto sam = i2p::client::context.GetSAMBridge (); + if (sam) + { + for (auto& it: sam->GetSessions ()) + { + s << ""; + s << it.first << "
" << std::endl; + } + } + } + + void HTTPConnection::ShowSAMSession (const std::string& id, std::stringstream& s) + { + auto sam = i2p::client::context.GetSAMBridge (); + if (sam) + { + auto session = sam->FindSession (id); + if (session) + { + for (auto it: session->sockets) + { + switch (it->GetSocketType ()) + { + case i2p::client::eSAMSocketTypeSession: + s << "session"; + break; + case i2p::client::eSAMSocketTypeStream: + s << "stream"; + break; + case i2p::client::eSAMSocketTypeAcceptor: + s << "acceptor"; + break; + default: + s << "unknown"; + } + s << " [" << it->GetSocket ().remote_endpoint() << "]"; + s << "
" << std::endl; + } + } + } + } void HTTPConnection::StartAcceptingTunnels (std::stringstream& s) { diff -Nru i2pd-0.7.0/HTTPServer.h i2pd-0.8.0/HTTPServer.h --- i2pd-0.7.0/HTTPServer.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/HTTPServer.h 2015-02-22 22:07:42.000000000 +0000 @@ -69,6 +69,8 @@ void ShowTransitTunnels (std::stringstream& s); void ShowLocalDestinations (std::stringstream& s); void ShowLocalDestination (const std::string& b32, std::stringstream& s); + void ShowSAMSessions (std::stringstream& s); + void ShowSAMSession (const std::string& id, std::stringstream& s); void StartAcceptingTunnels (std::stringstream& s); void StopAcceptingTunnels (std::stringstream& s); void FillContent (std::stringstream& s); diff -Nru i2pd-0.7.0/I2NPProtocol.cpp i2pd-0.8.0/I2NPProtocol.cpp --- i2pd-0.7.0/I2NPProtocol.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/I2NPProtocol.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -71,7 +71,7 @@ return msg; } - I2NPMessage * CreateI2NPMessage (const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from) + I2NPMessage * CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr from) { I2NPMessage * msg = NewI2NPMessage (); memcpy (msg->GetBuffer (), buf, len); @@ -82,7 +82,7 @@ I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID) { - I2NPMessage * m = NewI2NPMessage (); + I2NPMessage * m = NewI2NPShortMessage (); uint8_t * buf = m->GetPayload (); if (msgID) { @@ -578,11 +578,9 @@ switch (msg->GetTypeID ()) { case eI2NPTunnelData: - LogPrint ("TunnelData"); m_TunnelMsgs.push_back (msg); break; case eI2NPTunnelGateway: - LogPrint ("TunnelGateway"); m_TunnelGatewayMsgs.push_back (msg); break; default: diff -Nru i2pd-0.7.0/I2NPProtocol.h i2pd-0.8.0/I2NPProtocol.h --- i2pd-0.7.0/I2NPProtocol.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/I2NPProtocol.h 2015-02-22 22:07:42.000000000 +0000 @@ -2,9 +2,10 @@ #define I2NP_PROTOCOL_H__ #include +#include #include +#include #include -#include #include "I2PEndian.h" #include "Identity.h" #include "RouterInfo.h" @@ -108,7 +109,7 @@ { uint8_t * buf; size_t len, offset, maxLen; - i2p::tunnel::InboundTunnel * from; + std::shared_ptr from; I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2), offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header @@ -195,7 +196,7 @@ void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID = 0); void RenewI2NPMessageHeader (I2NPMessage * msg); I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID = 0); - I2NPMessage * CreateI2NPMessage (const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from = nullptr); + I2NPMessage * CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr from = nullptr); I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID); I2NPMessage * CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, diff -Nru i2pd-0.7.0/I2PControl.cpp i2pd-0.8.0/I2PControl.cpp --- i2pd-0.7.0/I2PControl.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/I2PControl.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -1,11 +1,15 @@ -#include "I2PControl.h" +// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy +#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 7)) +#include "I2PControl.h" #include #include #include #include #include +#if !GCC47_BOOST149 #include +#endif #include "Log.h" #include "NetDb.h" #include "RouterContext.h" @@ -111,7 +115,12 @@ void I2PControlService::ReadRequest (std::shared_ptr socket) { auto request = std::make_shared(); - socket->async_read_some (boost::asio::buffer (*request), + socket->async_read_some ( +#if BOOST_VERSION >= 104900 + boost::asio::buffer (*request), +#else + boost::asio::buffer (request->data (), request->size ()), +#endif std::bind(&I2PControlService::HandleRequestReceived, this, std::placeholders::_1, std::placeholders::_2, socket, request)); } @@ -142,8 +151,12 @@ return; // TODO: } } +#if GCC47_BOOST149 + LogPrint (eLogError, "json_read is not supported due bug in boost 1.49 with gcc 4.7"); +#else boost::property_tree::ptree pt; boost::property_tree::read_json (ss, pt); + std::string method = pt.get(I2P_CONTROL_PROPERTY_METHOD); auto it = m_MethodHandlers.find (method); if (it != m_MethodHandlers.end ()) @@ -161,6 +174,7 @@ } else LogPrint (eLogWarning, "Unknown I2PControl method ", method); +#endif } catch (std::exception& ex) { @@ -187,7 +201,11 @@ pt.put ("jsonrpc", "2.0"); std::ostringstream ss; +#if GCC47_BOOST149 + LogPrint (eLogError, "json_write is not supported due bug in boost 1.49 with gcc 4.7"); +#else boost::property_tree::write_json (ss, pt, false); +#endif size_t len = ss.str ().length (), offset = 0; if (isHtml) { diff -Nru i2pd-0.7.0/NetDb.cpp i2pd-0.8.0/NetDb.cpp --- i2pd-0.7.0/NetDb.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/NetDb.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -117,14 +117,12 @@ m_Thread = 0; } m_LeaseSets.clear(); - for (auto r: m_RequestedDestinations) - delete r.second; m_RequestedDestinations.clear (); } void NetDb::Run () { - uint32_t lastSave = 0, lastPublish = 0, lastExploratory = 0; + uint32_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0; while (m_IsRunning) { try @@ -132,6 +130,7 @@ I2NPMessage * msg = m_Queue.GetNextWithTimeout (15000); // 15 sec if (msg) { + int numMsgs = 0; while (msg) { switch (msg->GetTypeID ()) @@ -152,16 +151,19 @@ LogPrint ("NetDb: unexpected message type ", msg->GetTypeID ()); i2p::HandleI2NPMessage (msg); } + if (numMsgs > 100) break; msg = m_Queue.Get (); + numMsgs++; } - } - else - { - if (!m_IsRunning) break; - ManageRequests (); - } + } + if (!m_IsRunning) break; uint64_t ts = i2p::util::GetSecondsSinceEpoch (); + if (ts - lastManageRequest >= 15) // manage requests every 15 seconds + { + ManageRequests (); + lastManageRequest = ts; + } if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute { if (lastSave) @@ -183,7 +185,8 @@ { numRouters = 800/numRouters; if (numRouters < 1) numRouters = 1; - if (numRouters > 9) numRouters = 9; + if (numRouters > 9) numRouters = 9; + ManageRequests (); Explore (numRouters); lastExploratory = ts; } @@ -233,13 +236,12 @@ { it->second->Success (r); std::unique_lock l(m_RequestedDestinationsMutex); - delete it->second; m_RequestedDestinations.erase (it); } } void NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, - i2p::tunnel::InboundTunnel * from) + std::shared_ptr from) { if (!from) // unsolicited LS must be received directly { @@ -453,18 +455,18 @@ void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete) { // request RouterInfo directly - RequestedDestination * dest = CreateRequestedDestination (destination, false); - if (requestComplete) + auto dest = new RequestedDestination (destination, false); // non-exploratory + dest->SetRequestComplete (requestComplete); { - if (dest->IsRequestComplete ()) // if set already - { + std::unique_lock l(m_RequestedDestinationsMutex); + if (!m_RequestedDestinations.insert (std::make_pair (destination, + std::unique_ptr (dest))).second) // not inserted + { LogPrint (eLogWarning, "Destination ", destination.ToBase64(), " is requested already"); - requestComplete (nullptr); // TODO: implement it better return; } - else - dest->SetRequestComplete (requestComplete); - } + } + auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ()); if (floodfill) transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); @@ -472,7 +474,8 @@ { LogPrint (eLogError, "No floodfills found"); dest->Fail (); - DeleteRequestedDestination (dest); + std::unique_lock l(m_RequestedDestinationsMutex); + m_RequestedDestinations.erase (destination); } } @@ -512,6 +515,7 @@ auto floodfill = GetClosestFloodfill (buf + DATABASE_STORE_KEY_OFFSET, excluded); if (floodfill) { + excluded.insert (floodfill->GetIdentHash ()); auto floodMsg = NewI2NPShortMessage (); uint8_t * payload = floodMsg->GetPayload (); memcpy (payload, buf, 33); // key + type @@ -541,13 +545,20 @@ i2p::DeleteI2NPMessage (m); return; } - CryptoPP::Gunzip decompressor; - decompressor.Put (buf + offset, size); - decompressor.MessageEnd(); - uint8_t uncompressed[2048]; - size_t uncomressedSize = decompressor.MaxRetrievable (); - decompressor.Get (uncompressed, uncomressedSize); - AddRouterInfo (buf + DATABASE_STORE_KEY_OFFSET, uncompressed, uncomressedSize); + try + { + CryptoPP::Gunzip decompressor; + decompressor.Put (buf + offset, size); + decompressor.MessageEnd(); + uint8_t uncompressed[2048]; + size_t uncomressedSize = decompressor.MaxRetrievable (); + decompressor.Get (uncompressed, uncomressedSize); + AddRouterInfo (buf + DATABASE_STORE_KEY_OFFSET, uncompressed, uncomressedSize); + } + catch (CryptoPP::Exception& ex) + { + LogPrint (eLogError, "DatabaseStore: ", ex.what ()); + } } i2p::DeleteI2NPMessage (m); } @@ -563,19 +574,19 @@ auto it = m_RequestedDestinations.find (IdentHash (buf)); if (it != m_RequestedDestinations.end ()) { - RequestedDestination * dest = it->second; + auto& dest = it->second; bool deleteDest = true; if (num > 0) { auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr; auto inbound = pool ? pool->GetNextInboundTunnel () : nullptr; - std::vector msgs; if (!dest->IsExploratory ()) { // reply to our destination. Try other floodfills if (outbound && inbound ) { + std::vector msgs; auto count = dest->GetExcludedPeers ().size (); if (count < 7) { @@ -603,16 +614,16 @@ } else LogPrint (key, " was not found on 7 floodfills"); + + if (msgs.size () > 0) + outbound->SendTunnelDataMsg (msgs); } } - if (outbound && msgs.size () > 0) - outbound->SendTunnelDataMsg (msgs); if (deleteDest) { // no more requests for the destinationation. delete it it->second->Fail (); - delete it->second; m_RequestedDestinations.erase (it); } } @@ -620,7 +631,6 @@ { // no more requests for detination possible. delete it it->second->Fail (); - delete it->second; m_RequestedDestinations.erase (it); } } @@ -784,7 +794,16 @@ for (int i = 0; i < numDestinations; i++) { rnd.GenerateBlock (randomHash, 32); - RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), true); + auto dest = new RequestedDestination (randomHash, true); // exploratory + { + std::unique_lock l(m_RequestedDestinationsMutex); + if (!m_RequestedDestinations.insert (std::make_pair (randomHash, + std::unique_ptr (dest))).second) // not inserted + { + LogPrint (eLogWarning, "Exploratory destination is requested already"); + return; + } + } auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ()); if (floodfill && !floodfills.count (floodfill.get ())) // request floodfill only once { @@ -808,7 +827,10 @@ i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); } else - DeleteRequestedDestination (dest); + { + std::unique_lock l(m_RequestedDestinationsMutex); + m_RequestedDestinations.erase (dest->GetDestination ()); + } } if (throughTunnels && msgs.size () > 0) outbound->SendTunnelDataMsg (msgs); @@ -828,31 +850,7 @@ excluded.insert (floodfill->GetIdentHash ()); } } - } - - RequestedDestination * NetDb::CreateRequestedDestination (const IdentHash& dest, bool isExploratory) - { - std::unique_lock l(m_RequestedDestinationsMutex); - auto it = m_RequestedDestinations.find (dest); - if (it == m_RequestedDestinations.end ()) // not exist yet - { - RequestedDestination * d = new RequestedDestination (dest, isExploratory); - m_RequestedDestinations[dest] = d; - return d; - } - else - return it->second; - } - - void NetDb::DeleteRequestedDestination (RequestedDestination * dest) - { - if (dest) - { - std::unique_lock l(m_RequestedDestinationsMutex); - m_RequestedDestinations.erase (dest->GetDestination ()); - delete dest; - } - } + } std::shared_ptr NetDb::GetRandomRouter () const { @@ -976,16 +974,17 @@ void NetDb::ManageRequests () { uint64_t ts = i2p::util::GetSecondsSinceEpoch (); + std::unique_lock l(m_RequestedDestinationsMutex); for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();) { - auto dest = it->second; + auto& dest = it->second; bool done = false; - if (!dest->IsExploratory () && ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute + if (ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute { if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds { auto count = dest->GetExcludedPeers ().size (); - if (count < 7) + if (!dest->IsExploratory () && count < 7) { auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); auto outbound = pool->GetNextOutboundTunnel (); @@ -1004,19 +1003,17 @@ } else { - LogPrint (eLogWarning, dest->GetDestination ().ToBase64 (), " not found after 7 attempts"); + if (!dest->IsExploratory ()) + LogPrint (eLogWarning, dest->GetDestination ().ToBase64 (), " not found after 7 attempts"); done = true; } } } - else // delete previous exploratory + else // delete obsolete request done = true; if (done) - { - delete it->second; it = m_RequestedDestinations.erase (it); - } else it++; } diff -Nru i2pd-0.7.0/NetDb.h i2pd-0.8.0/NetDb.h --- i2pd-0.7.0/NetDb.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/NetDb.h 2015-02-22 22:07:42.000000000 +0000 @@ -67,7 +67,7 @@ void AddRouterInfo (const uint8_t * buf, int len); void AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len); - void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from); + void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, std::shared_ptr from); std::shared_ptr FindRouter (const IdentHash& ident) const; std::shared_ptr FindLeaseSet (const IdentHash& destination) const; @@ -104,9 +104,6 @@ void ManageLeaseSets (); void ManageRequests (); - RequestedDestination * CreateRequestedDestination (const IdentHash& dest, bool isExploratory = false); - void DeleteRequestedDestination (RequestedDestination * dest); - template std::shared_ptr GetRandomRouter (Filter filter) const; @@ -118,7 +115,7 @@ mutable std::mutex m_FloodfillsMutex; std::list > m_Floodfills; std::mutex m_RequestedDestinationsMutex; - std::map m_RequestedDestinations; + std::map > m_RequestedDestinations; bool m_IsRunning; std::thread * m_Thread; diff -Nru i2pd-0.7.0/NTCPSession.cpp i2pd-0.8.0/NTCPSession.cpp --- i2pd-0.7.0/NTCPSession.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/NTCPSession.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -20,8 +20,9 @@ { NTCPSession::NTCPSession (NTCPServer& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter), m_Server (server), m_Socket (m_Server.GetService ()), - m_TerminationTimer (m_Server.GetService ()), m_IsEstablished (false), m_ReceiveBufferOffset (0), - m_NextMessage (nullptr), m_IsSending (false), m_NumSentBytes (0), m_NumReceivedBytes (0) + m_TerminationTimer (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), + m_ReceiveBufferOffset (0), m_NextMessage (nullptr), m_IsSending (false), + m_NumSentBytes (0), m_NumReceivedBytes (0) { m_DHKeysPair = transports.GetNextDHKeysPair (); m_Establisher = new Establisher; @@ -30,10 +31,6 @@ NTCPSession::~NTCPSession () { delete m_Establisher; - if (m_NextMessage) - i2p::DeleteI2NPMessage (m_NextMessage); - for (auto it: m_SendQueue) - DeleteI2NPMessage (it); } void NTCPSession::CreateAESKey (uint8_t * pubKey, i2p::crypto::AESKey& key) @@ -72,13 +69,31 @@ } } + void NTCPSession::Done () + { + m_Server.GetService ().post (std::bind (&NTCPSession::Terminate, shared_from_this ())); + } + void NTCPSession::Terminate () { - m_IsEstablished = false; - m_Socket.close (); - transports.PeerDisconnected (shared_from_this ()); - m_Server.RemoveNTCPSession (shared_from_this ()); - LogPrint (eLogInfo, "NTCP session terminated"); + if (!m_IsTerminated) + { + m_IsTerminated = true; + m_IsEstablished = false; + m_Socket.close (); + transports.PeerDisconnected (shared_from_this ()); + m_Server.RemoveNTCPSession (shared_from_this ()); + for (auto it: m_SendQueue) + DeleteI2NPMessage (it); + m_SendQueue.clear (); + if (m_NextMessage) + { + i2p::DeleteI2NPMessage (m_NextMessage); + m_NextMessage = nullptr; + } + m_TerminationTimer.cancel (); + LogPrint (eLogInfo, "NTCP session terminated"); + } } void NTCPSession::Connected () @@ -111,14 +126,22 @@ boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase1, sizeof (NTCPPhase1)), boost::asio::transfer_all (), std::bind(&NTCPSession::HandlePhase1Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + ScheduleTermination (); } void NTCPSession::ServerLogin () { - // receive Phase1 - boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase1, sizeof (NTCPPhase1)), boost::asio::transfer_all (), - std::bind(&NTCPSession::HandlePhase1Received, shared_from_this (), - std::placeholders::_1, std::placeholders::_2)); + boost::system::error_code ec; + auto ep = m_Socket.remote_endpoint(ec); + if (!ec) + { + m_ConnectedFrom = ep.address (); + // receive Phase1 + boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase1, sizeof (NTCPPhase1)), boost::asio::transfer_all (), + std::bind(&NTCPSession::HandlePhase1Received, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); + ScheduleTermination (); + } } void NTCPSession::HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -316,6 +339,11 @@ uint8_t * buf = m_ReceiveBuffer; uint16_t size = bufbe16toh (buf); m_RemoteIdentity.FromBuffer (buf + 2, size); + if (m_Server.FindNTCPSession (m_RemoteIdentity.GetIdentHash ())) + { + LogPrint (eLogError, "NTCP session already exists"); + Terminate (); + } size_t expectedSize = size + 2/*size*/ + 4/*timestamp*/ + m_RemoteIdentity.GetSignatureLen (); size_t paddingLen = expectedSize & 0x0F; if (paddingLen) paddingLen = (16 - paddingLen); @@ -460,6 +488,7 @@ if (ecode) { LogPrint (eLogError, "Read error: ", ecode.message ()); + if (!m_NumReceivedBytes) m_Server.Ban (m_ConnectedFrom); //if (ecode != boost::asio::error::operation_aborted) Terminate (); } @@ -470,19 +499,46 @@ if (m_ReceiveBufferOffset >= 16) { - uint8_t * nextBlock = m_ReceiveBuffer; - while (m_ReceiveBufferOffset >= 16) - { - if (!DecryptNextBlock (nextBlock)) // 16 bytes + int numReloads = 0; + do + { + uint8_t * nextBlock = m_ReceiveBuffer; + while (m_ReceiveBufferOffset >= 16) { - Terminate (); - return; + if (!DecryptNextBlock (nextBlock)) // 16 bytes + { + Terminate (); + return; + } + nextBlock += 16; + m_ReceiveBufferOffset -= 16; + } + if (m_ReceiveBufferOffset > 0) + memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset); + + // try to read more + if (numReloads < 5) + { + boost::system::error_code ec; + size_t moreBytes = m_Socket.available(ec); + if (moreBytes) + { + if (moreBytes > NTCP_BUFFER_SIZE - m_ReceiveBufferOffset) + moreBytes = NTCP_BUFFER_SIZE - m_ReceiveBufferOffset; + moreBytes = m_Socket.read_some (boost::asio::buffer (m_ReceiveBuffer + m_ReceiveBufferOffset, moreBytes)); + if (ec) + { + LogPrint (eLogError, "Read more bytes error: ", ec.message ()); + Terminate (); + return; + } + m_NumReceivedBytes += moreBytes; + m_ReceiveBufferOffset += moreBytes; + numReloads++; + } } - nextBlock += 16; - m_ReceiveBufferOffset -= 16; } - if (m_ReceiveBufferOffset > 0) - memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset); + while (m_ReceiveBufferOffset >= 16); m_Handler.Flush (); } @@ -632,6 +688,11 @@ { if (msg) { + if (m_IsTerminated) + { + DeleteI2NPMessage (msg); + return; + } if (m_IsSending) m_SendQueue.push_back (msg); else @@ -646,6 +707,12 @@ void NTCPSession::PostI2NPMessages (std::vector msgs) { + if (m_IsTerminated) + { + for (auto it: msgs) + DeleteI2NPMessage (it); + return; + } if (m_IsSending) { for (auto it: msgs) @@ -792,8 +859,28 @@ { if (!error) { - LogPrint (eLogInfo, "Connected from ", conn->GetSocket ().remote_endpoint()); - conn->ServerLogin (); + boost::system::error_code ec; + auto ep = conn->GetSocket ().remote_endpoint(ec); + if (!ec) + { + LogPrint (eLogInfo, "Connected from ", ep); + auto it = m_BanList.find (ep.address ()); + if (it != m_BanList.end ()) + { + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + if (ts < it->second) + { + LogPrint (eLogInfo, ep.address (), " is banned for ", it->second - ts, " more seconds"); + conn = nullptr; + } + else + m_BanList.erase (it); + } + if (conn) + conn->ServerLogin (); + } + else + LogPrint (eLogError, "Connected from error ", ec.message ()); } @@ -809,8 +896,28 @@ { if (!error) { - LogPrint (eLogInfo, "Connected from ", conn->GetSocket ().remote_endpoint()); - conn->ServerLogin (); + boost::system::error_code ec; + auto ep = conn->GetSocket ().remote_endpoint(ec); + if (!ec) + { + LogPrint (eLogInfo, "Connected from ", ep); + auto it = m_BanList.find (ep.address ()); + if (it != m_BanList.end ()) + { + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + if (ts < it->second) + { + LogPrint (eLogInfo, ep.address (), " is banned for ", it->second - ts, " more seconds"); + conn = nullptr; + } + else + m_BanList.erase (it); + } + if (conn) + conn->ServerLogin (); + } + else + LogPrint (eLogError, "Connected from error ", ec.message ()); } if (error != boost::asio::error::operation_aborted) @@ -838,10 +945,8 @@ { LogPrint (eLogError, "Connect error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) - { i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ().GetIdentHash (), true); - conn->Terminate (); - } + conn->Terminate (); } else { @@ -851,5 +956,12 @@ conn->ClientLogin (); } } + + void NTCPServer::Ban (const boost::asio::ip::address& addr) + { + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + m_BanList[addr] = ts + NTCP_BAN_EXPIRATION_TIMEOUT; + LogPrint (eLogInfo, addr, " has been banned for ", NTCP_BAN_EXPIRATION_TIMEOUT, " seconds"); + } } } diff -Nru i2pd-0.7.0/NTCPSession.h i2pd-0.8.0/NTCPSession.h --- i2pd-0.7.0/NTCPSession.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/NTCPSession.h 2015-02-22 22:07:42.000000000 +0000 @@ -45,6 +45,7 @@ const size_t NTCP_BUFFER_SIZE = 4160; // fits 4 tunnel messages (4*1028) const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes const size_t NTCP_DEFAULT_PHASE3_SIZE = 2/*size*/ + i2p::data::DEFAULT_IDENTITY_SIZE/*387*/ + 4/*ts*/ + 15/*padding*/ + 40/*signature*/; // 448 + const int NTCP_BAN_EXPIRATION_TIMEOUT = 70; // in second class NTCPServer; class NTCPSession: public TransportSession, public std::enable_shared_from_this @@ -54,6 +55,7 @@ NTCPSession (NTCPServer& server, std::shared_ptr in_RemoteRouter = nullptr); ~NTCPSession (); void Terminate (); + void Done (); boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; bool IsEstablished () const { return m_IsEstablished; }; @@ -113,7 +115,7 @@ NTCPServer& m_Server; boost::asio::ip::tcp::socket m_Socket; boost::asio::deadline_timer m_TerminationTimer; - bool m_IsEstablished; + bool m_IsEstablished, m_IsTerminated; i2p::crypto::CBCDecryption m_Decryption; i2p::crypto::CBCEncryption m_Encryption; @@ -137,6 +139,7 @@ std::vector m_SendQueue; size_t m_NumSentBytes, m_NumReceivedBytes; + boost::asio::ip::address m_ConnectedFrom; // for ban }; // TODO: move to NTCP.h/.cpp @@ -156,7 +159,8 @@ void Connect (const boost::asio::ip::address& address, int port, std::shared_ptr conn); boost::asio::io_service& GetService () { return m_Service; }; - + void Ban (const boost::asio::ip::address& addr); + private: void Run (); @@ -174,6 +178,7 @@ boost::asio::ip::tcp::acceptor * m_NTCPAcceptor, * m_NTCPV6Acceptor; std::mutex m_NTCPSessionsMutex; std::map > m_NTCPSessions; + std::map m_BanList; // IP -> ban expiration time in seconds public: diff -Nru i2pd-0.7.0/Reseed.cpp i2pd-0.8.0/Reseed.cpp --- i2pd-0.7.0/Reseed.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/Reseed.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -3,10 +3,11 @@ #include #include #include -#include +#include #include #include #include +#include #include #include "I2PEndian.h" #include "Reseed.h" @@ -23,34 +24,29 @@ { static std::vector httpReseedHostList = { - "http://193.150.121.66/netDb/", - "http://netdb.i2p2.no/", - "http://reseed.i2p-projekt.de/", - "http://cowpuncher.drollette.com/netdb/", + // "http://193.150.121.66/netDb/", // unstable + // "http://us.reseed.i2p2.no/", // misconfigured, not serving reseed data + // "http://jp.reseed.i2p2.no/", // Really outdated RIs + "http://netdb.i2p2.no/", // only SU3 (v2) support "http://i2p.mooo.com/netDb/", - "http://reseed.info/", "http://uk.reseed.i2p2.no/", - "http://us.reseed.i2p2.no/", - "http://jp.reseed.i2p2.no/", - "http://i2p-netdb.innovatio.no/", - "http://ieb9oopo.mooo.com" + "http://i2p-netdb.innovatio.no/" }; //TODO: Remember to add custom port support. Not all serves on 443 static std::vector httpsReseedHostList = { - "https://193.150.121.66/netDb/", - "https://netdb.i2p2.no/", - "https://reseed.i2p-projekt.de/", - "https://cowpuncher.drollette.com/netdb/", - "https://i2p.mooo.com/netDb/", - "https://reseed.info/", - "https://i2p-netdb.innovatio.no/", - "https://ieb9oopo.mooo.com/", - "https://ssl.webpack.de/ivae2he9.sg4.e-plaza.de/" // Only HTTPS and SU3 (v2) support + // "https://193.150.121.66/netDb/", // unstable + // "https://i2p-netdb.innovatio.no/",// Vuln to POODLE + "https://netdb.i2p2.no/", // Only SU3 (v2) support + "https://reseed.i2p-projekt.de/", // Only HTTPS + "https://cowpuncher.drollette.com/netdb/", // Only HTTPS and SU3 (v2) support -- will move to a new location + // following hosts are fine but don't support AES256 + /*"https://i2p.mooo.com/netDb/", + "https://link.mx24.eu/", // Only HTTPS and SU3 (v2) support + "https://i2pseed.zarrenspry.info/", // Only HTTPS and SU3 (v2) support + "https://ieb9oopo.mooo.com/" // Only HTTPS and SU3 (v2) support*/ }; - //TODO: Implement v2 reseeding. Lightweight zip library is needed. - //TODO: Implement SU3, utils. Reseeder::Reseeder() { } @@ -61,17 +57,9 @@ bool Reseeder::reseedNow() { + // This method is deprecated try { - // Seems like the best place to try to intercept with SSL - /*ssl_server = true; - try { - // SSL - } - catch (std::exception& e) - { - LogPrint("Exception in SSL: ", e.what()); - }*/ std::string reseedHost = httpReseedHostList[(rand() % httpReseedHostList.size())]; LogPrint("Reseeding from ", reseedHost); std::string content = i2p::util::http::httpRequest(reseedHost); @@ -132,16 +120,17 @@ int Reseeder::ReseedNowSU3 () { CryptoPP::AutoSeededRandomPool rnd; - auto ind = rnd.GenerateWord32 (0, httpReseedHostList.size() - 1); - std::string reseedHost = httpReseedHostList[ind]; - return ReseedFromSU3 (reseedHost); + auto ind = rnd.GenerateWord32 (0, httpReseedHostList.size() - 1 + httpsReseedHostList.size () - 1); + std::string reseedHost = (ind < httpReseedHostList.size()) ? httpReseedHostList[ind] : + httpsReseedHostList[ind - httpReseedHostList.size()]; + return ReseedFromSU3 (reseedHost, ind >= httpReseedHostList.size()); } - int Reseeder::ReseedFromSU3 (const std::string& host) + int Reseeder::ReseedFromSU3 (const std::string& host, bool https) { std::string url = host + "i2pseeds.su3"; LogPrint (eLogInfo, "Dowloading SU3 from ", host); - std::string su3 = i2p::util::http::httpRequest (url); + std::string su3 = https ? HttpsRequest (url) : i2p::util::http::httpRequest (url); if (su3.length () > 0) { std::stringstream s(su3); @@ -404,75 +393,81 @@ decoder.Attach (new CryptoPP::Redirector (queue)); decoder.Put ((const uint8_t *)base64.data(), base64.length()); decoder.MessageEnd (); - - // extract X.509 - CryptoPP::BERSequenceDecoder x509Cert (queue); - CryptoPP::BERSequenceDecoder tbsCert (x509Cert); - // version - uint32_t ver; - CryptoPP::BERGeneralDecoder context (tbsCert, CryptoPP::CONTEXT_SPECIFIC | CryptoPP::CONSTRUCTED); - CryptoPP::BERDecodeUnsigned(context, ver, CryptoPP::INTEGER); - // serial - CryptoPP::Integer serial; - serial.BERDecode(tbsCert); - // signature - CryptoPP::BERSequenceDecoder signature (tbsCert); - signature.SkipAll(); - // issuer - std::string name; - CryptoPP::BERSequenceDecoder issuer (tbsCert); - { - CryptoPP::BERSetDecoder c (issuer); c.SkipAll(); - CryptoPP::BERSetDecoder st (issuer); st.SkipAll(); - CryptoPP::BERSetDecoder l (issuer); l.SkipAll(); - CryptoPP::BERSetDecoder o (issuer); o.SkipAll(); - CryptoPP::BERSetDecoder ou (issuer); ou.SkipAll(); - CryptoPP::BERSetDecoder cn (issuer); - { - CryptoPP::BERSequenceDecoder attributes (cn); - { - CryptoPP::BERGeneralDecoder ident(attributes, CryptoPP::OBJECT_IDENTIFIER); - ident.SkipAll (); - CryptoPP::BERDecodeTextString (attributes, name, CryptoPP::UTF8_STRING); - } - } - } - issuer.SkipAll(); - // validity - CryptoPP::BERSequenceDecoder validity (tbsCert); - validity.SkipAll(); - // subject - CryptoPP::BERSequenceDecoder subject (tbsCert); - subject.SkipAll(); - // public key - CryptoPP::BERSequenceDecoder publicKey (tbsCert); - { - CryptoPP::BERSequenceDecoder ident (publicKey); - ident.SkipAll (); - CryptoPP::BERGeneralDecoder key (publicKey, CryptoPP::BIT_STRING); - key.Skip (1); // FIXME: probably bug in crypto++ - CryptoPP::BERSequenceDecoder keyPair (key); - CryptoPP::Integer n; - n.BERDecode (keyPair); - if (name.length () > 0) - { - PublicKey value; - n.Encode (value, 512); - m_SigningKeys[name] = value; - } - else - LogPrint (eLogWarning, "Unknown issuer. Skipped"); - } - publicKey.SkipAll(); - - tbsCert.SkipAll(); - x509Cert.SkipAll(); + LoadCertificate (queue); } else LogPrint (eLogError, "Can't open certificate file ", filename); } + std::string Reseeder::LoadCertificate (CryptoPP::ByteQueue& queue) + { + // extract X.509 + CryptoPP::BERSequenceDecoder x509Cert (queue); + CryptoPP::BERSequenceDecoder tbsCert (x509Cert); + // version + uint32_t ver; + CryptoPP::BERGeneralDecoder context (tbsCert, CryptoPP::CONTEXT_SPECIFIC | CryptoPP::CONSTRUCTED); + CryptoPP::BERDecodeUnsigned(context, ver, CryptoPP::INTEGER); + // serial + CryptoPP::Integer serial; + serial.BERDecode(tbsCert); + // signature + CryptoPP::BERSequenceDecoder signature (tbsCert); + signature.SkipAll(); + + // issuer + std::string name; + CryptoPP::BERSequenceDecoder issuer (tbsCert); + { + CryptoPP::BERSetDecoder c (issuer); c.SkipAll(); + CryptoPP::BERSetDecoder st (issuer); st.SkipAll(); + CryptoPP::BERSetDecoder l (issuer); l.SkipAll(); + CryptoPP::BERSetDecoder o (issuer); o.SkipAll(); + CryptoPP::BERSetDecoder ou (issuer); ou.SkipAll(); + CryptoPP::BERSetDecoder cn (issuer); + { + CryptoPP::BERSequenceDecoder attributes (cn); + { + CryptoPP::BERGeneralDecoder ident(attributes, CryptoPP::OBJECT_IDENTIFIER); + ident.SkipAll (); + CryptoPP::BERDecodeTextString (attributes, name, CryptoPP::UTF8_STRING); + } + } + } + issuer.SkipAll(); + // validity + CryptoPP::BERSequenceDecoder validity (tbsCert); + validity.SkipAll(); + // subject + CryptoPP::BERSequenceDecoder subject (tbsCert); + subject.SkipAll(); + // public key + CryptoPP::BERSequenceDecoder publicKey (tbsCert); + { + CryptoPP::BERSequenceDecoder ident (publicKey); + ident.SkipAll (); + CryptoPP::BERGeneralDecoder key (publicKey, CryptoPP::BIT_STRING); + key.Skip (1); // FIXME: probably bug in crypto++ + CryptoPP::BERSequenceDecoder keyPair (key); + CryptoPP::Integer n; + n.BERDecode (keyPair); + if (name.length () > 0) + { + PublicKey value; + n.Encode (value, 512); + m_SigningKeys[name] = value; + } + else + LogPrint (eLogWarning, "Unknown issuer. Skipped"); + } + publicKey.SkipAll(); + + tbsCert.SkipAll(); + x509Cert.SkipAll(); + return name; + } + void Reseeder::LoadCertificates () { boost::filesystem::path reseedDir = i2p::util::filesystem::GetCertificatesDir() / "reseed"; @@ -495,7 +490,335 @@ } LogPrint (eLogInfo, numCertificates, " certificates loaded"); } + + std::string Reseeder::HttpsRequest (const std::string& address) + { + i2p::util::http::url u(address); + TlsSession session (u.host_, 443); + + // send request + std::stringstream ss; + ss << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_ + << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n"; + session.Send ((uint8_t *)ss.str ().c_str (), ss.str ().length ()); + + // read response + std::stringstream rs; + while (session.Receive (rs)) + ; + return i2p::util::http::GetHttpContent (rs); + } + + TlsSession::TlsSession (const std::string& host, int port): + m_Seqn (0) + { + m_Site.connect(host, boost::lexical_cast(port)); + if (m_Site.good ()) + { + Handshake (); + } + else + LogPrint (eLogError, "Can't connect to ", host, ":", port); + } + void TlsSession::Handshake () + { + static uint8_t clientHello[] = + { + 0x16, // handshake + 0x03, 0x03, // version (TLS 1.2) + 0x00, 0x2F, // length of handshake + // handshake + 0x01, // handshake type (client hello) + 0x00, 0x00, 0x2B, // length of handshake payload + // client hello + 0x03, 0x03, // highest version supported (TLS 1.2) + 0x45, 0xFA, 0x01, 0x19, 0x74, 0x55, 0x18, 0x36, + 0x42, 0x05, 0xC1, 0xDD, 0x4A, 0x21, 0x80, 0x80, + 0xEC, 0x37, 0x11, 0x93, 0x16, 0xF4, 0x66, 0x00, + 0x12, 0x67, 0xAB, 0xBA, 0xFF, 0x29, 0x13, 0x9E, // 32 random bytes + 0x00, // session id length + 0x00, 0x02, // chiper suites length + 0x00, 0x3D, // RSA_WITH_AES_256_CBC_SHA256 + 0x01, // compression methods length + 0x00, // no compression + 0x00, 0x00 // extensions length + }; + + static uint8_t changeCipherSpecs[] = + { + 0x14, // change cipher specs + 0x03, 0x03, // version (TLS 1.2) + 0x00, 0x01, // length + 0x01 // type + }; + + static uint8_t finished[] = + { + 0x16, // handshake + 0x03, 0x03, // version (TLS 1.2) + 0x00, 0x50, // length of handshake (80 bytes) + // handshake (encrypted) + // unencrypted context + // 0x14 handshake type (finished) + // 0x00, 0x00, 0x0C length of handshake payload + // 12 bytes of verified data + }; + + // send ClientHello + m_Site.write ((char *)clientHello, sizeof (clientHello)); + m_FinishedHash.Update (clientHello + 5, sizeof (clientHello) - 5); + // read ServerHello + uint8_t type; + m_Site.read ((char *)&type, 1); + uint16_t version; + m_Site.read ((char *)&version, 2); + uint16_t length; + m_Site.read ((char *)&length, 2); + length = be16toh (length); + char * serverHello = new char[length]; + m_Site.read (serverHello, length); + m_FinishedHash.Update ((uint8_t *)serverHello, length); + uint8_t serverRandom[32]; + if (serverHello[0] == 0x02) // handshake type server hello + memcpy (serverRandom, serverHello + 6, 32); + else + LogPrint (eLogError, "Unexpected handshake type ", (int)serverHello[0]); + delete[] serverHello; + // read Certificate + m_Site.read ((char *)&type, 1); + m_Site.read ((char *)&version, 2); + m_Site.read ((char *)&length, 2); + length = be16toh (length); + char * certificate = new char[length]; + m_Site.read (certificate, length); + m_FinishedHash.Update ((uint8_t *)certificate, length); + CryptoPP::RSA::PublicKey publicKey; + // 0 - handshake type + // 1 - 3 - handshake payload length + // 4 - 6 - length of array of certificates + // 7 - 9 - length of certificate + if (certificate[0] == 0x0B) // handshake type certificate + publicKey = ExtractPublicKey ((uint8_t *)certificate + 10, length - 10); + else + LogPrint (eLogError, "Unexpected handshake type ", (int)certificate[0]); + delete[] certificate; + // read ServerHelloDone + m_Site.read ((char *)&type, 1); + m_Site.read ((char *)&version, 2); + m_Site.read ((char *)&length, 2); + length = be16toh (length); + char * serverHelloDone = new char[length]; + m_Site.read (serverHelloDone, length); + m_FinishedHash.Update ((uint8_t *)serverHelloDone, length); + if (serverHelloDone[0] != 0x0E) // handshake type hello done + LogPrint (eLogError, "Unexpected handshake type ", (int)serverHelloDone[0]); + delete[] serverHelloDone; + // our turn now + // generate secret key + uint8_t secret[48]; + secret[0] = 3; secret[1] = 3; // version + m_Rnd.GenerateBlock (secret + 2, 46); // 46 random bytes + // encrypt RSA + CryptoPP::RSAES_PKCS1v15_Encryptor encryptor(publicKey); + size_t encryptedLen = encryptor.CiphertextLength (48); // number of bytes for encrypted 48 bytes, usually 256 (2048 bits key) + uint8_t * encrypted = new uint8_t[encryptedLen + 2]; // + 2 bytes for length + htobe16buf (encrypted, encryptedLen); // first two bytes means length + encryptor.Encrypt (m_Rnd, secret, 48, encrypted + 2); + // send ClientKeyExchange + // 0x10 - handshake type "client key exchange" + SendHandshakeMsg (0x10, encrypted, encryptedLen + 2); + delete[] encrypted; + // send ChangeCipherSpecs + m_Site.write ((char *)changeCipherSpecs, sizeof (changeCipherSpecs)); + // calculate master secret + uint8_t masterSecret[48], random[64]; + memcpy (random, clientHello + 11, 32); + memcpy (random + 32, serverRandom, 32); + PRF (secret, "master secret", random, 64, 48, masterSecret); + // expand master secret + uint8_t keys[128]; // clientMACKey(32), serverMACKey(32), clientKey(32), serverKey(32) + memcpy (random, serverRandom, 32); + memcpy (random + 32, clientHello + 11, 32); + PRF (masterSecret, "key expansion", random, 64, 128, keys); + memcpy (m_MacKey, keys, 32); + m_Encryption.SetKey (keys + 64); + m_Decryption.SetKey (keys + 96); + + // send finished + uint8_t finishedHashDigest[32], finishedPayload[40], encryptedPayload[80]; + finishedPayload[0] = 0x14; // handshake type (finished) + finishedPayload[1] = 0; finishedPayload[2] = 0; finishedPayload[3] = 0x0C; // 12 bytes + m_FinishedHash.Final (finishedHashDigest); + PRF (masterSecret, "client finished", finishedHashDigest, 32, 12, finishedPayload + 4); + uint8_t mac[32]; + CalculateMAC (0x16, finishedPayload, 16, mac); + Encrypt (finishedPayload, 16, mac, encryptedPayload); + m_Site.write ((char *)finished, sizeof (finished)); + m_Site.write ((char *)encryptedPayload, 80); + // read ChangeCipherSpecs + uint8_t changeCipherSpecs1[6]; + m_Site.read ((char *)changeCipherSpecs1, 6); + // read finished + m_Site.read ((char *)&type, 1); + m_Site.read ((char *)&version, 2); + m_Site.read ((char *)&length, 2); + length = be16toh (length); + char * finished1 = new char[length]; + m_Site.read (finished1, length); + delete[] finished1; + } + + void TlsSession::SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len) + { + uint8_t handshakeHeader[9]; + handshakeHeader[0] = 0x16; // handshake + handshakeHeader[1] = 0x03; handshakeHeader[2] = 0x03; // version is always TLS 1.2 (3,3) + htobe16buf (handshakeHeader + 3, len + 4); // length of payload + //payload starts + handshakeHeader[5] = handshakeType; // handshake type + handshakeHeader[6] = 0; // highest byte of payload length is always zero + htobe16buf (handshakeHeader + 7, len); // length of data + m_Site.write ((char *)handshakeHeader, 9); + m_FinishedHash.Update (handshakeHeader + 5, 4); // only payload counts + m_Site.write ((char *)data, len); + m_FinishedHash.Update (data, len); + } + + void TlsSession::PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, + size_t len, uint8_t * buf) + { + // secret is assumed 48 bytes + // random is not more than 64 bytes + CryptoPP::HMAC hmac (secret, 48); + uint8_t seed[96]; size_t seedLen; + seedLen = strlen (label); + memcpy (seed, label, seedLen); + memcpy (seed + seedLen, random, randomLen); + seedLen += randomLen; + + size_t offset = 0; + uint8_t a[128]; + hmac.CalculateDigest (a, seed, seedLen); + while (offset < len) + { + memcpy (a + 32, seed, seedLen); + hmac.CalculateDigest (buf + offset, a, seedLen + 32); + offset += 32; + hmac.CalculateDigest (a, a, 32); + } + } + + size_t TlsSession::Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) + { + size_t size = 0; + m_Rnd.GenerateBlock (out, 16); // iv + size += 16; + m_Encryption.SetIV (out); + memcpy (out + size, in, len); + size += len; + memcpy (out + size, mac, 32); + size += 32; + uint8_t paddingSize = len + 1; + paddingSize &= 0x0F; // %16 + if (paddingSize > 0) paddingSize = 16 - paddingSize; + memset (out + size, paddingSize, paddingSize + 1); // paddind and last byte are equal to padding size + size += paddingSize + 1; + m_Encryption.Encrypt (out + 16, size - 16, out + 16); + return size; + } + + size_t TlsSession::Decrypt (uint8_t * buf, size_t len) + { + m_Decryption.SetIV (buf); + m_Decryption.Decrypt (buf + 16, len - 16, buf + 16); + return len - 48 - buf[len -1] - 1; // IV(16), mac(32) and padding + } + + void TlsSession::CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac) + { + uint8_t header[13]; // seqn (8) + type (1) + version (2) + length (2) + htobe64buf (header, m_Seqn); + header[8] = type; header[9] = 3; header[10] = 3; // 3,3 means TLS 1.2 + htobe16buf (header + 11, len); + CryptoPP::HMAC hmac (m_MacKey, 32); + hmac.Update (header, 13); + hmac.Update (buf, len); + hmac.Final (mac); + m_Seqn++; + } + + CryptoPP::RSA::PublicKey TlsSession::ExtractPublicKey (const uint8_t * certificate, size_t len) + { + CryptoPP::ByteQueue queue; + queue.Put (certificate, len); + queue.MessageEnd (); + // extract X.509 + CryptoPP::BERSequenceDecoder x509Cert (queue); + CryptoPP::BERSequenceDecoder tbsCert (x509Cert); + // version + uint32_t ver; + CryptoPP::BERGeneralDecoder context (tbsCert, CryptoPP::CONTEXT_SPECIFIC | CryptoPP::CONSTRUCTED); + CryptoPP::BERDecodeUnsigned(context, ver, CryptoPP::INTEGER); + // serial + CryptoPP::Integer serial; + serial.BERDecode(tbsCert); + // signature + CryptoPP::BERSequenceDecoder signature (tbsCert); + signature.SkipAll(); + // issuer + CryptoPP::BERSequenceDecoder issuer (tbsCert); + issuer.SkipAll(); + // validity + CryptoPP::BERSequenceDecoder validity (tbsCert); + validity.SkipAll(); + // subject + CryptoPP::BERSequenceDecoder subject (tbsCert); + subject.SkipAll(); + // public key + CryptoPP::BERSequenceDecoder publicKey (tbsCert); + CryptoPP::BERSequenceDecoder ident (publicKey); + ident.SkipAll (); + CryptoPP::BERGeneralDecoder key (publicKey, CryptoPP::BIT_STRING); + key.Skip (1); // FIXME: probably bug in crypto++ + CryptoPP::BERSequenceDecoder keyPair (key); + CryptoPP::Integer n, e; + n.BERDecode (keyPair); + e.BERDecode (keyPair); + + CryptoPP::RSA::PublicKey ret; + ret.Initialize (n, e); + return ret; + } + + void TlsSession::Send (const uint8_t * buf, size_t len) + { + uint8_t * out = new uint8_t[len + 64 + 5]; // 64 = 32 mac + 16 iv + upto 16 padding, 5 = header + out[0] = 0x17; // application data + out[1] = 0x03; out[2] = 0x03; // version + uint8_t mac[32]; + CalculateMAC (0x17, buf, len, mac); + size_t encryptedLen = Encrypt (buf, len, mac, out + 5); + htobe16buf (out + 3, encryptedLen); + m_Site.write ((char *)out, encryptedLen + 5); + delete[] out; + } + + bool TlsSession::Receive (std::ostream& rs) + { + if (m_Site.eof ()) return false; + uint8_t type; uint16_t version, length; + m_Site.read ((char *)&type, 1); + m_Site.read ((char *)&version, 2); + m_Site.read ((char *)&length, 2); + length = be16toh (length); + uint8_t * buf = new uint8_t[length]; + m_Site.read ((char *)buf, length); + size_t decryptedLen = Decrypt (buf, length); + rs.write ((char *)buf + 16, decryptedLen); + delete[] buf; + return true; + } } } diff -Nru i2pd-0.7.0/Reseed.h i2pd-0.8.0/Reseed.h --- i2pd-0.7.0/Reseed.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/Reseed.h 2015-02-22 22:07:42.000000000 +0000 @@ -5,7 +5,11 @@ #include #include #include +#include +#include +#include #include "Identity.h" +#include "aes.h" namespace i2p { @@ -24,21 +28,54 @@ int ReseedNowSU3 (); void LoadCertificates (); - + private: void LoadCertificate (const std::string& filename); + std::string LoadCertificate (CryptoPP::ByteQueue& queue); // returns issuer's name - int ReseedFromSU3 (const std::string& host); + int ReseedFromSU3 (const std::string& host, bool https = false); int ProcessSU3File (const char * filename); int ProcessSU3Stream (std::istream& s); bool FindZipDataDescriptor (std::istream& s); + + std::string HttpsRequest (const std::string& address); private: std::map m_SigningKeys; }; + + class TlsSession + { + public: + + TlsSession (const std::string& host, int port); + void Send (const uint8_t * buf, size_t len); + bool Receive (std::ostream& rs); + + private: + + void Handshake (); + void SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len); + CryptoPP::RSA::PublicKey ExtractPublicKey (const uint8_t * certificate, size_t len); + void PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, + size_t len, uint8_t * buf); + void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac); + size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out); + size_t Decrypt (uint8_t * buf, size_t len); // pyaload is buf + 16 + + private: + + uint64_t m_Seqn; + boost::asio::ip::tcp::iostream m_Site; + CryptoPP::SHA256 m_FinishedHash; + CryptoPP::AutoSeededRandomPool m_Rnd; + i2p::crypto::CBCEncryption m_Encryption; + i2p::crypto::CBCDecryption m_Decryption; + uint8_t m_MacKey[32]; // client + }; } } diff -Nru i2pd-0.7.0/RouterContext.cpp i2pd-0.8.0/RouterContext.cpp --- i2pd-0.7.0/RouterContext.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/RouterContext.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -215,7 +215,7 @@ fk.write ((char *)&keys, sizeof (keys)); } - void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from) + void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) { i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from)); } diff -Nru i2pd-0.7.0/RouterContext.h i2pd-0.8.0/RouterContext.h --- i2pd-0.7.0/RouterContext.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/RouterContext.h 2015-02-22 22:07:42.000000000 +0000 @@ -54,7 +54,7 @@ // implements GarlicDestination const i2p::data::LeaseSet * GetLeaseSet () { return nullptr; }; - void HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from); + void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); private: diff -Nru i2pd-0.7.0/SAM.cpp i2pd-0.8.0/SAM.cpp --- i2pd-0.7.0/SAM.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/SAM.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -680,8 +680,15 @@ { if (!ecode) { - LogPrint ("New SAM connection from ", socket->GetSocket ().remote_endpoint ()); - socket->ReceiveHandshake (); + boost::system::error_code ec; + auto ep = socket->GetSocket ().remote_endpoint (ec); + if (!ec) + { + LogPrint ("New SAM connection from ", ep); + socket->ReceiveHandshake (); + } + else + LogPrint (eLogError, "SAM connection from error ", ec.message ()); } else LogPrint ("SAM accept error: ", ecode.message ()); @@ -738,7 +745,7 @@ } } - SAMSession * SAMBridge::FindSession (const std::string& id) + SAMSession * SAMBridge::FindSession (const std::string& id) const { std::unique_lock l(m_SessionsMutex); auto it = m_Sessions.find (id); diff -Nru i2pd-0.7.0/SAM.h i2pd-0.8.0/SAM.h --- i2pd-0.7.0/SAM.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/SAM.h 2015-02-22 22:07:42.000000000 +0000 @@ -79,6 +79,7 @@ boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; void ReceiveHandshake (); void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; }; + SAMSocketType GetSocketType () const { return m_SocketType; }; private: @@ -150,7 +151,7 @@ SAMSession * CreateSession (const std::string& id, const std::string& destination, // empty string means transient const std::map * params); void CloseSession (const std::string& id); - SAMSession * FindSession (const std::string& id); + SAMSession * FindSession (const std::string& id) const; private: @@ -170,9 +171,14 @@ boost::asio::ip::tcp::acceptor m_Acceptor; boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint; boost::asio::ip::udp::socket m_DatagramSocket; - std::mutex m_SessionsMutex; + mutable std::mutex m_SessionsMutex; std::map m_Sessions; uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; + + public: + + // for HTTP + const decltype(m_Sessions)& GetSessions () const { return m_Sessions; }; }; } } diff -Nru i2pd-0.7.0/SSU.cpp i2pd-0.8.0/SSU.cpp --- i2pd-0.7.0/SSU.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/SSU.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -9,10 +9,11 @@ { namespace transport { - SSUServer::SSUServer (int port): m_Thread (nullptr), m_ThreadV6 (nullptr), m_Work (m_Service), - m_WorkV6 (m_ServiceV6),m_Endpoint (boost::asio::ip::udp::v4 (), port), - m_EndpointV6 (boost::asio::ip::udp::v6 (), port), m_Socket (m_Service, m_Endpoint), - m_SocketV6 (m_ServiceV6), m_IntroducersUpdateTimer (m_Service) + SSUServer::SSUServer (int port): m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr), + m_Work (m_Service), m_WorkV6 (m_ServiceV6), m_ReceiversWork (m_ReceiversService), + m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port), + m_Socket (m_ReceiversService, m_Endpoint), m_SocketV6 (m_ReceiversService), + m_IntroducersUpdateTimer (m_Service) { m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (65535)); m_Socket.set_option (boost::asio::socket_base::send_buffer_size (65535)); @@ -33,12 +34,13 @@ void SSUServer::Start () { m_IsRunning = true; + m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this)); m_Thread = new std::thread (std::bind (&SSUServer::Run, this)); - m_Service.post (std::bind (&SSUServer::Receive, this)); + m_ReceiversService.post (std::bind (&SSUServer::Receive, this)); if (context.SupportsV6 ()) { m_ThreadV6 = new std::thread (std::bind (&SSUServer::RunV6, this)); - m_ServiceV6.post (std::bind (&SSUServer::ReceiveV6, this)); + m_ReceiversService.post (std::bind (&SSUServer::ReceiveV6, this)); } if (i2p::context.IsUnreachable ()) ScheduleIntroducersUpdateTimer (); @@ -52,6 +54,13 @@ m_Socket.close (); m_ServiceV6.stop (); m_SocketV6.close (); + m_ReceiversService.stop (); + if (m_ReceiversThread) + { + m_ReceiversThread->join (); + delete m_ReceiversThread; + m_ReceiversThread = nullptr; + } if (m_Thread) { m_Thread->join (); @@ -95,6 +104,21 @@ } } } + + void SSUServer::RunReceivers () + { + while (m_IsRunning) + { + try + { + m_ReceiversService.run (); + } + catch (std::exception& ex) + { + LogPrint (eLogError, "SSU receivers: ", ex.what ()); + } + } + } void SSUServer::AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay) { @@ -119,52 +143,100 @@ void SSUServer::Receive () { - m_Socket.async_receive_from (boost::asio::buffer (m_ReceiveBuffer, SSU_MTU_V4), m_SenderEndpoint, - boost::bind (&SSUServer::HandleReceivedFrom, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + SSUPacket * packet = new SSUPacket (); + m_Socket.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from, + std::bind (&SSUServer::HandleReceivedFrom, this, std::placeholders::_1, std::placeholders::_2, packet)); } void SSUServer::ReceiveV6 () { - m_SocketV6.async_receive_from (boost::asio::buffer (m_ReceiveBufferV6, SSU_MTU_V6), m_SenderEndpointV6, - boost::bind (&SSUServer::HandleReceivedFromV6, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + SSUPacket * packet = new SSUPacket (); + m_SocketV6.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V6), packet->from, + std::bind (&SSUServer::HandleReceivedFromV6, this, std::placeholders::_1, std::placeholders::_2, packet)); } - void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred) + void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet) { if (!ecode) { - HandleReceivedBuffer (m_SenderEndpoint, m_ReceiveBuffer, bytes_transferred); + packet->len = bytes_transferred; + std::vector packets; + packets.push_back (packet); + + boost::system::error_code ec; + size_t moreBytes = m_Socket.available(ec); + while (moreBytes && packets.size () < 25) + { + packet = new SSUPacket (); + packet->len = m_Socket.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from); + packets.push_back (packet); + moreBytes = m_Socket.available(); + } + + m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets)); Receive (); } else + { LogPrint ("SSU receive error: ", ecode.message ()); + delete packet; + } } - void SSUServer::HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred) + void SSUServer::HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet) { if (!ecode) { - HandleReceivedBuffer (m_SenderEndpointV6, m_ReceiveBufferV6, bytes_transferred); + packet->len = bytes_transferred; + std::vector packets; + packets.push_back (packet); + + size_t moreBytes = m_SocketV6.available (); + while (moreBytes && packets.size () < 25) + { + packet = new SSUPacket (); + packet->len = m_SocketV6.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V6), packet->from); + packets.push_back (packet); + moreBytes = m_SocketV6.available(); + } + + m_ServiceV6.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets)); ReceiveV6 (); } else + { LogPrint ("SSU V6 receive error: ", ecode.message ()); + delete packet; + } } - void SSUServer::HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred) + void SSUServer::HandleReceivedPackets (std::vector packets) { - std::shared_ptr session; - auto it = m_Sessions.find (from); - if (it != m_Sessions.end ()) - session = it->second; - if (!session) + std::shared_ptr session; + for (auto it1: packets) { - session = std::make_shared (*this, from); - session->WaitForConnect (); - m_Sessions[from] = session; - LogPrint ("New SSU session from ", from.address ().to_string (), ":", from.port (), " created"); + auto packet = it1; + if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous + { + if (session) session->FlushData (); + auto it = m_Sessions.find (packet->from); + if (it != m_Sessions.end ()) + session = it->second; + if (!session) + { + session = std::make_shared (*this, packet->from); + session->WaitForConnect (); + { + std::unique_lock l(m_SessionsMutex); + m_Sessions[packet->from] = session; + } + LogPrint ("New SSU session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created"); + } + } + session->ProcessNextMessage (packet->buf, packet->len, packet->from); + delete packet; } - session->ProcessNextMessage (buf, bytes_transferred, from); + if (session) session->FlushData (); } std::shared_ptr SSUServer::FindSession (std::shared_ptr router) const @@ -206,8 +278,10 @@ { // otherwise create new session session = std::make_shared (*this, remoteEndpoint, router, peerTest); - m_Sessions[remoteEndpoint] = session; - + { + std::unique_lock l(m_SessionsMutex); + m_Sessions[remoteEndpoint] = session; + } if (!router->UsesIntroducer ()) { // connect directly @@ -243,6 +317,7 @@ introducer = &(address->introducers[0]); // TODO: boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort); introducerSession = std::make_shared (*this, introducerEndpoint, router); + std::unique_lock l(m_SessionsMutex); m_Sessions[introducerEndpoint] = introducerSession; } // introduce @@ -250,12 +325,16 @@ "] through introducer ", introducer->iHost, ":", introducer->iPort); session->WaitForIntroduction (); if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable - Send (m_ReceiveBuffer, 0, remoteEndpoint); // send HolePunch + { + uint8_t buf[1]; + Send (buf, 0, remoteEndpoint); // send HolePunch + } introducerSession->Introduce (introducer->iTag, introducer->iKey); } else { LogPrint (eLogWarning, "Can't connect to unreachable router. No introducers presented"); + std::unique_lock l(m_SessionsMutex); m_Sessions.erase (remoteEndpoint); session.reset (); } @@ -273,12 +352,14 @@ if (session) { session->Close (); + std::unique_lock l(m_SessionsMutex); m_Sessions.erase (session->GetRemoteEndpoint ()); } } void SSUServer::DeleteAllSessions () { + std::unique_lock l(m_SessionsMutex); for (auto it: m_Sessions) it.second->Close (); m_Sessions.clear (); diff -Nru i2pd-0.7.0/SSUData.cpp i2pd-0.8.0/SSUData.cpp --- i2pd-0.7.0/SSUData.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/SSUData.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -11,7 +11,8 @@ namespace transport { SSUData::SSUData (SSUSession& session): - m_Session (session), m_ResendTimer (session.m_Server.GetService ()) + m_Session (session), m_ResendTimer (session.GetService ()), m_DecayTimer (session.GetService ()), + m_IncompleteMessagesCleanupTimer (session.GetService ()) { m_MaxPacketSize = session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE; m_PacketSize = m_MaxPacketSize; @@ -22,16 +23,20 @@ SSUData::~SSUData () { - for (auto it: m_IncomleteMessages) - if (it.second) - { - DeleteI2NPMessage (it.second->msg); - delete it.second; - } - for (auto it: m_SentMessages) - delete it.second; } + void SSUData::Start () + { + ScheduleIncompleteMessagesCleanup (); + } + + void SSUData::Stop () + { + m_ResendTimer.cancel (); + m_DecayTimer.cancel (); + m_IncompleteMessagesCleanupTimer.cancel (); + } + void SSUData::AdjustPacketSize (const i2p::data::RouterInfo& remoteRouter) { auto ssuAddress = remoteRouter.GetSSUAddress (); @@ -69,7 +74,6 @@ auto it = m_SentMessages.find (msgID); if (it != m_SentMessages.end ()) { - delete it->second; m_SentMessages.erase (it); if (m_SentMessages.empty ()) m_ResendTimer.cancel (); @@ -143,8 +147,7 @@ uint32_t fragmentInfo = bufbe32toh (frag); // fragment info uint16_t fragmentSize = fragmentInfo & 0x1FFF; // bits 0 - 13 bool isLast = fragmentInfo & 0x010000; // bit 16 - uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17 - LogPrint (eLogDebug, "SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last"); + uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17 if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE) { LogPrint (eLogError, "Fragment size ", fragmentSize, "exceeds max SSU packet size"); @@ -153,22 +156,19 @@ // find message with msgID I2NPMessage * msg = nullptr; - IncompleteMessage * incompleteMessage = nullptr; - auto it = m_IncomleteMessages.find (msgID); - if (it != m_IncomleteMessages.end ()) - { + auto it = m_IncompleteMessages.find (msgID); + if (it != m_IncompleteMessages.end ()) // message exists - incompleteMessage = it->second; - msg = incompleteMessage->msg; - } + msg = it->second->msg; else { // create new message msg = NewI2NPMessage (); msg->len -= I2NP_SHORT_HEADER_SIZE; - incompleteMessage = new IncompleteMessage (msg); - m_IncomleteMessages[msgID] = incompleteMessage; - } + it = m_IncompleteMessages.insert (std::make_pair (msgID, + std::unique_ptr(new IncompleteMessage (msg)))).first; + } + std::unique_ptr& incompleteMessage = it->second; // handle current fragment if (fragmentNum == incompleteMessage->nextFragmentNum) @@ -182,7 +182,7 @@ // try saved fragments for (auto it1 = incompleteMessage->savedFragments.begin (); it1 != incompleteMessage->savedFragments.end ();) { - auto savedFragment = *it1; + auto& savedFragment = *it1; if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum) { memcpy (msg->buf + msg->len, savedFragment->buf, savedFragment->len); @@ -190,7 +190,6 @@ isLast = savedFragment->isLast; incompleteMessage->nextFragmentNum++; incompleteMessage->savedFragments.erase (it1++); - delete savedFragment; } else break; @@ -209,11 +208,10 @@ // missing fragment LogPrint (eLogWarning, "Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID); auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast); - if (!incompleteMessage->savedFragments.insert (savedFragment).second) - { + if (incompleteMessage->savedFragments.insert (std::unique_ptr(savedFragment)).second) + incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch (); + else LogPrint (eLogWarning, "Fragment ", (int)fragmentNum, " of message ", msgID, " already saved"); - delete savedFragment; - } } isLast = false; } @@ -221,8 +219,8 @@ if (isLast) { // delete incomplete message - delete incompleteMessage; - m_IncomleteMessages.erase (msgID); + incompleteMessage->msg = nullptr; + m_IncompleteMessages.erase (msgID); // process message SendMsgAck (msgID); msg->FromSSU (msgID); @@ -230,7 +228,10 @@ { if (!m_ReceivedMessages.count (msgID)) { - if (m_ReceivedMessages.size () > 100) m_ReceivedMessages.clear (); + if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES) + m_ReceivedMessages.clear (); + else + ScheduleDecay (); m_ReceivedMessages.insert (msgID); m_Handler.PutNextMessage (msg); } @@ -257,10 +258,13 @@ SendFragmentAck (msgID, fragmentNum); buf += fragmentSize; } - if (numFragments > 0) - m_Handler.Flush (); } + void SSUData::FlushReceivedMessage () + { + m_Handler.Flush (); + } + void SSUData::ProcessMessage (uint8_t * buf, size_t len) { //uint8_t * start = buf; @@ -293,10 +297,14 @@ } if (m_SentMessages.empty ()) // schedule resend at first message only ScheduleResend (); - SentMessage * sentMessage = new SentMessage; - m_SentMessages[msgID] = sentMessage; - sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL; - sentMessage->numResends = 0; + + auto ret = m_SentMessages.insert (std::make_pair (msgID, std::unique_ptr(new SentMessage))); + std::unique_ptr& sentMessage = ret.first->second; + if (ret.second) + { + sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL; + sentMessage->numResends = 0; + } auto& fragments = sentMessage->fragments; size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3) size_t len = msg->GetLength (); @@ -335,8 +343,14 @@ // encrypt message with session key m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size); - m_Session.Send (buf, size); - + try + { + m_Session.Send (buf, size); + } + catch (boost::system::system_error& ec) + { + LogPrint (eLogError, "Can't send SSU fragment ", ec.what ()); + } if (!isLast) { len -= payloadSize; @@ -403,26 +417,90 @@ m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode) { s->m_Data.HandleResendTimer (ecode); }); } - + void SSUData::HandleResendTimer (const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) { uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - for (auto it : m_SentMessages) + for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();) { - if (ts >= it.second->nextResendTime && it.second->numResends < MAX_NUM_RESENDS) + if (ts >= it->second->nextResendTime) { - for (auto& f: it.second->fragments) - if (f) m_Session.Send (f->buf, f->len); // resend - - it.second->numResends++; - it.second->nextResendTime += it.second->numResends*RESEND_INTERVAL; + if (it->second->numResends < MAX_NUM_RESENDS) + { + for (auto& f: it->second->fragments) + if (f) + { + try + { + m_Session.Send (f->buf, f->len); // resend + } + catch (boost::system::system_error& ec) + { + LogPrint (eLogError, "Can't resend SSU fragment ", ec.what ()); + } + } + + it->second->numResends++; + it->second->nextResendTime += it->second->numResends*RESEND_INTERVAL; + it++; + } + else + { + LogPrint (eLogError, "SSU message has not been ACKed after ", MAX_NUM_RESENDS, " attempts. Deleted"); + it = m_SentMessages.erase (it); + } } + else + it++; } ScheduleResend (); } } + + void SSUData::ScheduleDecay () + { + m_DecayTimer.cancel (); + m_DecayTimer.expires_from_now (boost::posix_time::seconds(DECAY_INTERVAL)); + auto s = m_Session.shared_from_this(); + m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode) + { s->m_Data.HandleDecayTimer (ecode); }); + } + + void SSUData::HandleDecayTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + m_ReceivedMessages.clear (); + } + + void SSUData::ScheduleIncompleteMessagesCleanup () + { + m_IncompleteMessagesCleanupTimer.cancel (); + m_IncompleteMessagesCleanupTimer.expires_from_now (boost::posix_time::seconds(INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT)); + auto s = m_Session.shared_from_this(); + m_IncompleteMessagesCleanupTimer.async_wait ([s](const boost::system::error_code& ecode) + { s->m_Data.HandleIncompleteMessagesCleanupTimer (ecode); }); + } + + void SSUData::HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();) + { + if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT) + { + LogPrint (eLogError, "SSU message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds. Deleted"); + it = m_IncompleteMessages.erase (it); + } + else + it++; + } + ScheduleIncompleteMessagesCleanup (); + } + } } } diff -Nru i2pd-0.7.0/SSUData.h i2pd-0.8.0/SSUData.h --- i2pd-0.7.0/SSUData.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/SSUData.h 2015-02-22 22:07:42.000000000 +0000 @@ -26,6 +26,9 @@ const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1424 const int RESEND_INTERVAL = 3; // in seconds const int MAX_NUM_RESENDS = 5; + const int DECAY_INTERVAL = 20; // in seconds + const int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check + const int INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds // data flags const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02; const uint8_t DATA_FLAG_WANT_REPLY = 0x04; @@ -48,7 +51,7 @@ struct FragmentCmp { - bool operator() (const Fragment * f1, const Fragment * f2) const + bool operator() (const std::unique_ptr& f1, const std::unique_ptr& f2) const { return f1->fragmentNum < f2->fragmentNum; }; @@ -58,10 +61,11 @@ { I2NPMessage * msg; int nextFragmentNum; - std::set savedFragments; + uint32_t lastFragmentInsertTime; // in seconds + std::set, FragmentCmp> savedFragments; - IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (0) {}; - ~IncompleteMessage () { for (auto it: savedFragments) { delete it; }; }; + IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {}; + ~IncompleteMessage () { if (msg) DeleteI2NPMessage (msg); }; }; struct SentMessage @@ -79,7 +83,11 @@ SSUData (SSUSession& session); ~SSUData (); + void Start (); + void Stop (); + void ProcessMessage (uint8_t * buf, size_t len); + void FlushReceivedMessage (); void Send (i2p::I2NPMessage * msg); void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent); @@ -94,16 +102,22 @@ void ScheduleResend (); void HandleResendTimer (const boost::system::error_code& ecode); + + void ScheduleDecay (); + void HandleDecayTimer (const boost::system::error_code& ecode); + + void ScheduleIncompleteMessagesCleanup (); + void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode); void AdjustPacketSize (const i2p::data::RouterInfo& remoteRouter); private: SSUSession& m_Session; - std::map m_IncomleteMessages; - std::map m_SentMessages; + std::map > m_IncompleteMessages; + std::map > m_SentMessages; std::set m_ReceivedMessages; - boost::asio::deadline_timer m_ResendTimer; + boost::asio::deadline_timer m_ResendTimer, m_DecayTimer, m_IncompleteMessagesCleanupTimer; int m_MaxPacketSize, m_PacketSize; i2p::I2NPMessagesHandler m_Handler; }; diff -Nru i2pd-0.7.0/SSU.h i2pd-0.8.0/SSU.h --- i2pd-0.7.0/SSU.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/SSU.h 2015-02-22 22:07:42.000000000 +0000 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "aes.h" #include "I2PEndian.h" @@ -22,6 +23,13 @@ const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour const size_t SSU_MAX_NUM_INTRODUCERS = 3; + + struct SSUPacket + { + i2p::crypto::AESAlignedBuffer<1500> buf; + boost::asio::ip::udp::endpoint from; + size_t len; + }; class SSUServer { @@ -49,11 +57,12 @@ void Run (); void RunV6 (); + void RunReceivers (); void Receive (); void ReceiveV6 (); - void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred); - void HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred); - void HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred); + void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet); + void HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet); + void HandleReceivedPackets (std::vector packets); template std::shared_ptr GetRandomSession (Filter filter); @@ -65,16 +74,14 @@ private: bool m_IsRunning; - std::thread * m_Thread, * m_ThreadV6; - boost::asio::io_service m_Service, m_ServiceV6; - boost::asio::io_service::work m_Work, m_WorkV6; + std::thread * m_Thread, * m_ThreadV6, * m_ReceiversThread; + boost::asio::io_service m_Service, m_ServiceV6, m_ReceiversService; + boost::asio::io_service::work m_Work, m_WorkV6, m_ReceiversWork; boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6; boost::asio::ip::udp::socket m_Socket, m_SocketV6; - boost::asio::ip::udp::endpoint m_SenderEndpoint, m_SenderEndpointV6; boost::asio::deadline_timer m_IntroducersUpdateTimer; std::list m_Introducers; // introducers we are connected to - i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V4> m_ReceiveBuffer; - i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V6> m_ReceiveBufferV6; + std::mutex m_SessionsMutex; std::map > m_Sessions; std::map m_Relays; // we are introducer diff -Nru i2pd-0.7.0/SSUSession.cpp i2pd-0.8.0/SSUSession.cpp --- i2pd-0.7.0/SSUSession.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/SSUSession.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -15,10 +15,9 @@ { SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, std::shared_ptr router, bool peerTest ): TransportSession (router), - m_Server (server), m_RemoteEndpoint (remoteEndpoint), - m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), - m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0), - m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0) + m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_Timer (GetService ()), + m_PeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0), + m_NumSentBytes (0), m_NumReceivedBytes (0), m_Data (*this), m_IsDataReceived (false) { m_CreationTime = i2p::util::GetSecondsSinceEpoch (); } @@ -26,6 +25,11 @@ SSUSession::~SSUSession () { } + + boost::asio::io_service& SSUSession::GetService () + { + return IsV6 () ? m_Server.GetServiceV6 () : m_Server.GetService (); + } void SSUSession::CreateAESandMacKey (const uint8_t * pubKey) { @@ -126,7 +130,6 @@ switch (header->GetPayloadType ()) { case PAYLOAD_TYPE_DATA: - LogPrint (eLogDebug, "SSU data received"); ProcessData (buf + sizeof (SSUHeader), len - sizeof (SSUHeader)); break; case PAYLOAD_TYPE_SESSION_REQUEST: @@ -755,10 +758,18 @@ void SSUSession::Close () { + m_State = eSessionStateClosed; SendSesionDestroyed (); transports.PeerDisconnected (shared_from_this ()); + m_Data.Stop (); + m_Timer.cancel (); } + void SSUSession::Done () + { + GetService ().post (std::bind (&SSUSession::Failed, shared_from_this ())); + } + void SSUSession::Established () { m_State = eSessionStateEstablished; @@ -767,6 +778,7 @@ delete m_DHKeysPair; m_DHKeysPair = nullptr; } + m_Data.Start (); m_Data.Send (CreateDatabaseStoreMsg ()); transports.PeerConnected (shared_from_this ()); if (m_PeerTest && (m_RemoteRouter && m_RemoteRouter->IsPeerTesting ())) @@ -818,33 +830,53 @@ void SSUSession::SendI2NPMessage (I2NPMessage * msg) { - boost::asio::io_service& service = IsV6 () ? m_Server.GetServiceV6 () : m_Server.GetService (); - service.post (std::bind (&SSUSession::PostI2NPMessage, shared_from_this (), msg)); + GetService ().post (std::bind (&SSUSession::PostI2NPMessage, shared_from_this (), msg)); } void SSUSession::PostI2NPMessage (I2NPMessage * msg) { if (msg) - m_Data.Send (msg); + { + if (m_State == eSessionStateEstablished) + m_Data.Send (msg); + else + DeleteI2NPMessage (msg); + } } void SSUSession::SendI2NPMessages (const std::vector& msgs) { - boost::asio::io_service& service = IsV6 () ? m_Server.GetServiceV6 () : m_Server.GetService (); - service.post (std::bind (&SSUSession::PostI2NPMessages, shared_from_this (), msgs)); + GetService ().post (std::bind (&SSUSession::PostI2NPMessages, shared_from_this (), msgs)); } void SSUSession::PostI2NPMessages (std::vector msgs) { - for (auto it: msgs) - if (it) m_Data.Send (it); + if (m_State == eSessionStateEstablished) + { + for (auto it: msgs) + if (it) m_Data.Send (it); + } + else + { + for (auto it: msgs) + DeleteI2NPMessage (it); + } } void SSUSession::ProcessData (uint8_t * buf, size_t len) { m_Data.ProcessMessage (buf, len); + m_IsDataReceived = true; } + void SSUSession::FlushData () + { + if (m_IsDataReceived) + { + m_Data.FlushReceivedMessage (); + m_IsDataReceived = false; + } + } void SSUSession::ProcessPeerTest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { diff -Nru i2pd-0.7.0/SSUSession.h i2pd-0.8.0/SSUSession.h --- i2pd-0.7.0/SSUSession.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/SSUSession.h 2015-02-22 22:07:42.000000000 +0000 @@ -45,6 +45,7 @@ eSessionStateUnknown, eSessionStateIntroduced, eSessionStateEstablished, + eSessionStateClosed, eSessionStateFailed }; @@ -63,6 +64,7 @@ void Introduce (uint32_t iTag, const uint8_t * iKey); void WaitForIntroduction (); void Close (); + void Done (); boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); }; void SendI2NPMessage (I2NPMessage * msg); @@ -77,8 +79,11 @@ uint32_t GetRelayTag () const { return m_RelayTag; }; uint32_t GetCreationTime () const { return m_CreationTime; }; + void FlushData (); + private: + boost::asio::io_service& GetService (); void CreateAESandMacKey (const uint8_t * pubKey); void PostI2NPMessage (I2NPMessage * msg); @@ -133,9 +138,10 @@ i2p::crypto::CBCDecryption m_SessionKeyDecryption; i2p::crypto::AESKey m_SessionKey; i2p::crypto::MACKey m_MacKey; - SSUData m_Data; size_t m_NumSentBytes, m_NumReceivedBytes; uint32_t m_CreationTime; // seconds since epoch + SSUData m_Data; + bool m_IsDataReceived; }; diff -Nru i2pd-0.7.0/TransitTunnel.cpp i2pd-0.8.0/TransitTunnel.cpp --- i2pd-0.7.0/TransitTunnel.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/TransitTunnel.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -35,7 +35,6 @@ { EncryptTunnelMsg (tunnelMsg); - LogPrint (eLogDebug, "TransitTunnel: ",GetTunnelID (),"->", GetNextTunnelID ()); m_NumTransmittedBytes += tunnelMsg->GetLength (); htobe32buf (tunnelMsg->GetPayload (), GetNextTunnelID ()); FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData); @@ -44,9 +43,9 @@ void TransitTunnelParticipant::FlushTunnelDataMsgs () { - LogPrint (eLogDebug, "TransitTunnel: flush"); if (!m_TunnelDataMsgs.empty ()) { + LogPrint (eLogDebug, "TransitTunnel: ",GetTunnelID (),"->", GetNextTunnelID (), " ", m_TunnelDataMsgs.size ()); i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs); m_TunnelDataMsgs.clear (); } @@ -75,7 +74,7 @@ void TransitTunnelGateway::FlushTunnelDataMsgs () { - LogPrint (eLogDebug, "TransitTunnel: gateway flush"); + std::unique_lock l(m_SendMutex); m_Gateway.SendBuffer (); } diff -Nru i2pd-0.7.0/Transports.cpp i2pd-0.8.0/Transports.cpp --- i2pd-0.7.0/Transports.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/Transports.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -95,7 +95,7 @@ Transports transports; Transports::Transports (): - m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), + m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_PeerCleanupTimer (m_Service), m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5) // 5 pre-generated keys { @@ -134,10 +134,13 @@ LogPrint ("SSU server already exists"); } } + m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT)); + m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); } void Transports::Stop () { + m_PeerCleanupTimer.cancel (); m_Peers.clear (); if (m_SSUServer) { @@ -202,7 +205,8 @@ if (it == m_Peers.end ()) { auto r = netdb.FindRouter (ident); - it = m_Peers.insert (std::pair(ident, { 0, r, nullptr})).first; + it = m_Peers.insert (std::pair(ident, { 0, r, nullptr, + i2p::util::GetSecondsSinceEpoch () })).first; if (!ConnectToPeer (ident, it->second)) { DeleteI2NPMessage (msg); @@ -228,7 +232,8 @@ if (it == m_Peers.end ()) { auto r = netdb.FindRouter (ident); - it = m_Peers.insert (std::pair(ident, { 0, r, nullptr})).first; + it = m_Peers.insert (std::pair(ident, { 0, r, nullptr, + i2p::util::GetSecondsSinceEpoch () })).first; if (!ConnectToPeer (ident, it->second)) { for (auto it1: msgs) @@ -255,7 +260,13 @@ auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); if (address) { +#if BOOST_VERSION >= 104900 if (!address->host.is_unspecified ()) // we have address now +#else + boost::system::error_code ecode; + address->host.to_string (ecode); + if (!ecode) +#endif { if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ()) { @@ -285,6 +296,7 @@ } } LogPrint (eLogError, "No NTCP and SSU addresses available"); + if (peer.session) peer.session->Done (); m_Peers.erase (ident); return false; } @@ -330,13 +342,13 @@ } void Transports::HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, - const i2p::data::IdentHash& ident, std::shared_ptr resolver) + i2p::data::IdentHash ident, std::shared_ptr resolver) { auto it1 = m_Peers.find (ident); - if (it1 != m_Peers.end () && it1->second.router) + if (it1 != m_Peers.end ()) { auto& peer = it1->second; - if (!ecode) + if (!ecode && peer.router) { auto address = (*it).endpoint ().address (); LogPrint (eLogInfo, (*it).host_name (), " has been resolved to ", address); @@ -348,10 +360,9 @@ return; } } + LogPrint (eLogError, "Unable to resolve NTCP address: ", ecode.message ()); + m_Peers.erase (it1); } - - LogPrint (eLogError, "Unable to resolve NTCP address: ", ecode.message ()); - m_Peers.erase (it1); } void Transports::CloseSession (std::shared_ptr router) @@ -399,12 +410,20 @@ auto it = m_Peers.find (ident); if (it != m_Peers.end ()) { - it->second.session = session; - session->SendI2NPMessages (it->second.delayedMessages); - it->second.delayedMessages.clear (); + if (!it->second.session) + { + it->second.session = session; + session->SendI2NPMessages (it->second.delayedMessages); + it->second.delayedMessages.clear (); + } + else + { + LogPrint (eLogError, "Session for ", ident.ToBase64 ().substr (0, 4), " already exists"); + session->Done (); + } } else // incoming connection - m_Peers[ident] = { 0, nullptr, session }; + m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, session, i2p::util::GetSecondsSinceEpoch () })); }); } @@ -414,7 +433,7 @@ { auto ident = session->GetRemoteIdentity ().GetIdentHash (); auto it = m_Peers.find (ident); - if (it != m_Peers.end ()) + if (it != m_Peers.end () && (!it->second.session || it->second.session == session)) { if (it->second.delayedMessages.size () > 0) ConnectToPeer (ident, it->second); @@ -423,6 +442,26 @@ } }); } + + void Transports::HandlePeerCleanupTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + auto ts = i2p::util::GetSecondsSinceEpoch (); + for (auto it = m_Peers.begin (); it != m_Peers.end (); ) + { + if (!it->second.session && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT) + { + LogPrint (eLogError, "Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds"); + it = m_Peers.erase (it); + } + else + it++; + } + m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT)); + m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); + } + } } } diff -Nru i2pd-0.7.0/TransportSession.h i2pd-0.8.0/TransportSession.h --- i2pd-0.7.0/TransportSession.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/TransportSession.h 2015-02-22 22:07:42.000000000 +0000 @@ -62,6 +62,7 @@ } virtual ~TransportSession () { delete m_DHKeysPair; }; + virtual void Done () = 0; std::shared_ptr GetRemoteRouter () { return m_RemoteRouter; }; const i2p::data::IdentityEx& GetRemoteIdentity () { return m_RemoteIdentity; }; diff -Nru i2pd-0.7.0/Transports.h i2pd-0.8.0/Transports.h --- i2pd-0.7.0/Transports.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/Transports.h 2015-02-22 22:07:42.000000000 +0000 @@ -56,15 +56,17 @@ int numAttempts; std::shared_ptr router; std::shared_ptr session; + uint64_t creationTime; std::vector delayedMessages; ~Peer () { for (auto it :delayedMessages) - i2p::DeleteI2NPMessage (it); + i2p::DeleteI2NPMessage (it); } }; + const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds class Transports { public: @@ -95,10 +97,11 @@ void PostMessages (i2p::data::IdentHash ident, std::vector msgs); void PostCloseSession (std::shared_ptr router); bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer); - + void HandlePeerCleanupTimer (const boost::system::error_code& ecode); + void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident); void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, - const i2p::data::IdentHash& ident, std::shared_ptr resolver); + i2p::data::IdentHash ident, std::shared_ptr resolver); void DetectExternalIP (); @@ -108,6 +111,7 @@ std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; + boost::asio::deadline_timer m_PeerCleanupTimer; NTCPServer * m_NTCPServer; SSUServer * m_SSUServer; diff -Nru i2pd-0.7.0/Tunnel.cpp i2pd-0.8.0/Tunnel.cpp --- i2pd-0.7.0/Tunnel.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/Tunnel.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -160,7 +160,7 @@ void InboundTunnel::HandleTunnelDataMsg (I2NPMessage * msg) { if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive - msg->from = this; + msg->from = shared_from_this (); EncryptTunnelMsg (msg); m_Endpoint.HandleDecryptedTunnelDataMsg (msg); } @@ -317,7 +317,11 @@ void Tunnels::AddTransitTunnel (TransitTunnel * tunnel) { std::unique_lock l(m_TransitTunnelsMutex); - m_TransitTunnels[tunnel->GetTunnelID ()] = tunnel; + if (!m_TransitTunnels.insert (std::make_pair (tunnel->GetTunnelID (), tunnel)).second) + { + LogPrint (eLogError, "Transit tunnel ", tunnel->GetTunnelID (), " already exists"); + delete tunnel; + } } void Tunnels::Start () diff -Nru i2pd-0.7.0/TunnelEndpoint.cpp i2pd-0.8.0/TunnelEndpoint.cpp --- i2pd-0.7.0/TunnelEndpoint.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/TunnelEndpoint.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -27,7 +27,6 @@ uint8_t * zero = (uint8_t *)memchr (decrypted + 4, 0, TUNNEL_DATA_ENCRYPTED_SIZE - 4); // witout 4-byte checksum if (zero) { - LogPrint ("TunnelMessage: zero found at ", (int)(zero-decrypted)); uint8_t * fragment = zero + 1; // verify checksum memcpy (msg->GetPayload () + TUNNEL_DATA_MSG_SIZE, msg->GetPayload () + 4, 16); // copy iv to the end @@ -35,7 +34,7 @@ CryptoPP::SHA256().CalculateDigest (hash, fragment, TUNNEL_DATA_MSG_SIZE -(fragment - msg->GetPayload ()) + 16); // payload + iv if (memcmp (hash, decrypted, 4)) { - LogPrint ("TunnelMessage: checksum verification failed"); + LogPrint (eLogError, "TunnelMessage: checksum verification failed"); i2p::DeleteI2NPMessage (msg); return; } @@ -57,17 +56,14 @@ switch (m.deliveryType) { case eDeliveryTypeLocal: // 0 - LogPrint ("Delivery type local"); break; case eDeliveryTypeTunnel: // 1 - LogPrint ("Delivery type tunnel"); m.tunnelID = bufbe32toh (fragment); fragment += 4; // tunnelID m.hash = i2p::data::IdentHash (fragment); fragment += 32; // hash break; case eDeliveryTypeRouter: // 2 - LogPrint ("Delivery type router"); m.hash = i2p::data::IdentHash (fragment); fragment += 32; // to hash break; @@ -81,7 +77,6 @@ // Message ID msgID = bufbe32toh (fragment); fragment += 4; - LogPrint ("Fragmented message ", msgID); isLastFragment = false; } } @@ -92,12 +87,10 @@ fragment += 4; fragmentNum = (flag >> 1) & 0x3F; // 6 bits isLastFragment = flag & 0x01; - LogPrint ("Follow on fragment ", fragmentNum, " of message ", msgID, isLastFragment ? " last" : " non-last"); } uint16_t size = bufbe16toh (fragment); fragment += 2; - LogPrint ("Fragment size=", (int)size); msg->offset = fragment - msg->buf; msg->len = msg->offset + size; @@ -121,9 +114,14 @@ if (!isFollowOnFragment) // create new incomlete message { m.nextFragmentNum = 1; - auto& msg = m_IncompleteMessages[msgID]; - msg = m; - HandleOutOfSequenceFragment (msgID, msg); + auto ret = m_IncompleteMessages.insert (std::pair(msgID, m)); + if (ret.second) + HandleOutOfSequenceFragment (msgID, ret.first->second); + else + { + LogPrint (eLogError, "Incomplete message ", msgID, "already exists"); + DeleteI2NPMessage (m.data); + } } else { @@ -131,8 +129,11 @@ HandleFollowOnFragment (msgID, isLastFragment, m); } } - else - LogPrint ("Message is fragmented, but msgID is not presented"); + else + { + LogPrint (eLogError, "Message is fragmented, but msgID is not presented"); + DeleteI2NPMessage (m.data); + } } fragment += size; @@ -140,7 +141,7 @@ } else { - LogPrint ("TunnelMessage: zero not found"); + LogPrint (eLogError, "TunnelMessage: zero not found"); i2p::DeleteI2NPMessage (msg); } } @@ -173,7 +174,7 @@ } else { - LogPrint ("Fragment ", m.nextFragmentNum, " of message ", msgID, "exceeds max I2NP message size. Message dropped"); + LogPrint (eLogError, "Fragment ", m.nextFragmentNum, " of message ", msgID, "exceeds max I2NP message size. Message dropped"); i2p::DeleteI2NPMessage (msg.data); m_IncompleteMessages.erase (it); } @@ -181,13 +182,13 @@ } else { - LogPrint ("Unexpected fragment ", (int)m.nextFragmentNum, " instead ", (int)msg.nextFragmentNum, " of message ", msgID, ". Saved"); + LogPrint (eLogInfo, "Unexpected fragment ", (int)m.nextFragmentNum, " instead ", (int)msg.nextFragmentNum, " of message ", msgID, ". Saved"); AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data); } } else { - LogPrint ("First fragment of message ", msgID, " not found. Saved"); + LogPrint (eLogInfo, "First fragment of message ", msgID, " not found. Saved"); AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data); } } @@ -208,7 +209,7 @@ { if (it->second.fragmentNum == msg.nextFragmentNum) { - LogPrint ("Out-of-sequence fragment ", (int)it->second.fragmentNum, " of message ", msgID, " found"); + LogPrint (eLogInfo, "Out-of-sequence fragment ", (int)it->second.fragmentNum, " of message ", msgID, " found"); auto size = it->second.data->GetLength (); memcpy (msg.data->buf + msg.data->len, it->second.data->GetBuffer (), size); // concatenate out-of-sync fragment msg.data->len += size; @@ -228,7 +229,7 @@ void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg) { - LogPrint ("TunnelMessage: handle fragment of ", msg.data->GetLength ()," bytes. Msg type ", (int)msg.data->GetTypeID ()); + LogPrint (eLogInfo, "TunnelMessage: handle fragment of ", msg.data->GetLength ()," bytes. Msg type ", (int)msg.data->GetTypeID ()); switch (msg.deliveryType) { case eDeliveryTypeLocal: @@ -257,13 +258,16 @@ } else // we shouldn't send this message. possible leakage { - LogPrint ("Message to another router arrived from an inbound tunnel. Dropped"); + LogPrint (eLogError, "Message to another router arrived from an inbound tunnel. Dropped"); i2p::DeleteI2NPMessage (msg.data); } } break; default: - LogPrint ("TunnelMessage: Unknown delivery type ", (int)msg.deliveryType); + { + LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType); + i2p::DeleteI2NPMessage (msg.data); + } }; } } diff -Nru i2pd-0.7.0/TunnelGateway.cpp i2pd-0.8.0/TunnelGateway.cpp --- i2pd-0.7.0/TunnelGateway.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/TunnelGateway.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -10,6 +10,12 @@ { namespace tunnel { + TunnelGatewayBuffer::~TunnelGatewayBuffer () + { + for (auto it: m_TunnelDataMsgs) + DeleteI2NPMessage (it); + } + void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block) { bool messageCreated = false; diff -Nru i2pd-0.7.0/TunnelGateway.h i2pd-0.8.0/TunnelGateway.h --- i2pd-0.7.0/TunnelGateway.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/TunnelGateway.h 2015-02-22 22:07:42.000000000 +0000 @@ -15,6 +15,7 @@ public: TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {}; + ~TunnelGatewayBuffer (); void PutI2NPMsg (const TunnelMessageBlock& block); const std::vector& GetTunnelDataMsgs () const { return m_TunnelDataMsgs; }; void ClearTunnelDataMsgs (); diff -Nru i2pd-0.7.0/Tunnel.h i2pd-0.8.0/Tunnel.h --- i2pd-0.7.0/Tunnel.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/Tunnel.h 2015-02-22 22:07:42.000000000 +0000 @@ -95,7 +95,7 @@ TunnelGateway m_Gateway; }; - class InboundTunnel: public Tunnel + class InboundTunnel: public Tunnel, public std::enable_shared_from_this { public: diff -Nru i2pd-0.7.0/util.cpp i2pd-0.8.0/util.cpp --- i2pd-0.7.0/util.cpp 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/util.cpp 2015-02-22 22:07:42.000000000 +0000 @@ -1,3 +1,4 @@ +#include #include #include #include @@ -241,40 +242,8 @@ // User-Agent is needed to get the server list routerInfo files. site << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_ << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n"; - // read response - std::string version, statusMessage; - site >> version; // HTTP version - int status; - site >> status; // status - std::getline (site, statusMessage); - if (status == 200) // OK - { - bool isChunked = false; - std::string header; - while (!site.eof () && header != "\r") - { - std::getline(site, header); - auto colon = header.find (':'); - if (colon != std::string::npos) - { - std::string field = header.substr (0, colon); - if (field == i2p::util::http::TRANSFER_ENCODING) - isChunked = (header.find ("chunked", colon + 1) != std::string::npos); - } - } - - std::stringstream ss; - if (isChunked) - MergeChunkedResponse (site, ss); - else - ss << site.rdbuf(); - return ss.str(); - } - else - { - LogPrint ("HTTP response ", status); - return ""; - } + // read response and extract content + return GetHttpContent (site); } else { @@ -289,6 +258,43 @@ } } + std::string GetHttpContent (std::istream& response) + { + std::string version, statusMessage; + response >> version; // HTTP version + int status; + response >> status; // status + std::getline (response, statusMessage); + if (status == 200) // OK + { + bool isChunked = false; + std::string header; + while (!response.eof () && header != "\r") + { + std::getline(response, header); + auto colon = header.find (':'); + if (colon != std::string::npos) + { + std::string field = header.substr (0, colon); + if (field == i2p::util::http::TRANSFER_ENCODING) + isChunked = (header.find ("chunked", colon + 1) != std::string::npos); + } + } + + std::stringstream ss; + if (isChunked) + MergeChunkedResponse (response, ss); + else + ss << response.rdbuf(); + return ss.str(); + } + else + { + LogPrint ("HTTP response ", status); + return ""; + } + } + void MergeChunkedResponse (std::istream& response, std::ostream& merged) { while (!response.eof ()) @@ -444,6 +450,16 @@ query_.assign(query_i, url_s.end()); } + std::string urlDecode(const std::string& data) + { + std::string res(data); + for (size_t pos = res.find('%'); pos != std::string::npos; pos = res.find('%',pos+1)) + { + char c = strtol(res.substr(pos+1,2).c_str(), NULL, 16); + res.replace(pos,3,1,c); + } + return res; + } } namespace net diff -Nru i2pd-0.7.0/util.h i2pd-0.8.0/util.h --- i2pd-0.7.0/util.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/util.h 2015-02-22 22:07:42.000000000 +0000 @@ -47,8 +47,10 @@ const char TRANSFER_ENCODING[] = "Transfer-Encoding"; std::string httpRequest(const std::string& address); + std::string GetHttpContent (std::istream& response); void MergeChunkedResponse (std::istream& response, std::ostream& merged); int httpRequestViaI2pProxy(const std::string& address, std::string &content); // return http code + std::string urlDecode(const std::string& data); struct url { url(const std::string& url_s); // omitted copy, ==, accessors, ... diff -Nru i2pd-0.7.0/version.h i2pd-0.8.0/version.h --- i2pd-0.7.0/version.h 2015-02-04 01:59:12.000000000 +0000 +++ i2pd-0.8.0/version.h 2015-02-22 22:07:42.000000000 +0000 @@ -2,7 +2,7 @@ #define _VERSION_H_ #define CODENAME "Purple" -#define VERSION "0.7.0" -#define I2P_VERSION "0.9.17" +#define VERSION "0.8.0" +#define I2P_VERSION "0.9.18" #endif