From c010c83654e5c7baabf492f82aa43999eacaf44a Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 10 Feb 2017 12:51:55 -0500 Subject: [PATCH 1/7] signaturetype ofr HTTP and SOCKS proxy --- ClientContext.cpp | 6 ++++-- Config.cpp | 3 +++ docs/configuration.md | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ClientContext.cpp b/ClientContext.cpp index 0354e708..3edafd88 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -50,11 +50,12 @@ namespace client std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys); std::string httpProxyAddr; i2p::config::GetOption("httpproxy.address", httpProxyAddr); uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort); + i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType); LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort); if (httpProxyKeys.length () > 0) { i2p::data::PrivateKeys keys; - if(LoadPrivateKeys (keys, httpProxyKeys, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)) + if(LoadPrivateKeys (keys, httpProxyKeys, sigType)) { std::map params; ReadI2CPOptionsFromConfig ("httpproxy.", params); @@ -80,11 +81,12 @@ namespace client uint16_t socksProxyPort; i2p::config::GetOption("socksproxy.port", socksProxyPort); std::string socksOutProxyAddr; i2p::config::GetOption("socksproxy.outproxy", socksOutProxyAddr); uint16_t socksOutProxyPort; i2p::config::GetOption("socksproxy.outproxyport", socksOutProxyPort); + i2p::data::SigningKeyType sigType; i2p::config::GetOption("socksproxy.signaturetype", sigType); LogPrint(eLogInfo, "Clients: starting SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort); if (socksProxyKeys.length () > 0) { i2p::data::PrivateKeys keys; - if (LoadPrivateKeys (keys, socksProxyKeys, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)) + if (LoadPrivateKeys (keys, socksProxyKeys, sigType)) { std::map params; ReadI2CPOptionsFromConfig ("socksproxy.", params); diff --git a/Config.cpp b/Config.cpp index b8008bc3..7f8f2f53 100644 --- a/Config.cpp +++ b/Config.cpp @@ -16,6 +16,7 @@ #include #include +#include "Identity.h" #include "Config.h" #include "version.h" @@ -85,6 +86,7 @@ namespace config { ("httpproxy.address", value()->default_value("127.0.0.1"), "HTTP Proxy listen address") ("httpproxy.port", value()->default_value(4444), "HTTP Proxy listen port") ("httpproxy.keys", value()->default_value(""), "File to persist HTTP Proxy keys") + ("httpproxy.signaturetype", value()->default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default") ("httpproxy.inbound.length", value()->default_value("3"), "HTTP proxy inbound tunnel length") ("httpproxy.outbound.length", value()->default_value("3"), "HTTP proxy outbound tunnel length") ("httpproxy.inbound.quantity", value()->default_value("5"), "HTTP proxy inbound tunnels quantity") @@ -100,6 +102,7 @@ namespace config { ("socksproxy.address", value()->default_value("127.0.0.1"), "SOCKS Proxy listen address") ("socksproxy.port", value()->default_value(4447), "SOCKS Proxy listen port") ("socksproxy.keys", value()->default_value(""), "File to persist SOCKS Proxy keys") + ("socksproxy.signaturetype", value()->default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default") ("socksproxy.inbound.length", value()->default_value("3"), "SOCKS proxy inbound tunnel length") ("socksproxy.outbound.length", value()->default_value("3"), "SOCKS proxy outbound tunnel length") ("socksproxy.inbound.quantity", value()->default_value("5"), "SOCKS proxy inbound tunnels quantity") diff --git a/docs/configuration.md b/docs/configuration.md index 4894bfe3..8f17b220 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -46,6 +46,7 @@ All options below still possible in cmdline, but better write it in config file: * --httpproxy.address= - The address to listen on (HTTP Proxy) * --httpproxy.port= - The port to listen on (HTTP Proxy) 4444 by default * --httpproxy.keys= - optional keys file for HTTP proxy local destination +* --httpproxy.signaturetype= - signature type for new keys if keys file is set. 7 by default * --httpproxy.inbound.length= - Inbound tunnels length if keys is set. 3 by default * --httpproxy.inbound.quantity= - Inbound tunnels quantity if keys is set. 5 by default * --httpproxy.outbound.length= - Outbound tunnels length if keys is set. 3 by default @@ -55,6 +56,7 @@ All options below still possible in cmdline, but better write it in config file: * --socksproxy.address= - The address to listen on (SOCKS Proxy) * --socksproxy.port= - The port to listen on (SOCKS Proxy). 4447 by default * --socksproxy.keys= - optional keys file for SOCKS proxy local destination +* --socksproxy.signaturetype= - signature type for new keys if keys file is set. 7 by default * --socksproxy.inbound.length= - Inbound tunnels length if keys is set. 3 by default * --socksproxy.inbound.quantity= - Inbound tunnels quantity if keys is set. 5 by default * --socksproxy.outbound.length= - Outbound tunnels length if keys is set. 3 by default From 25559f1772774c81392ab07314fc3878cda67d59 Mon Sep 17 00:00:00 2001 From: Darknet Villain Date: Fri, 10 Feb 2017 13:51:19 -0500 Subject: [PATCH 2/7] Added AppArmor profile --- contrib/apparmor/usr.sbin.i2pd | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 contrib/apparmor/usr.sbin.i2pd diff --git a/contrib/apparmor/usr.sbin.i2pd b/contrib/apparmor/usr.sbin.i2pd new file mode 100644 index 00000000..ab6c8b44 --- /dev/null +++ b/contrib/apparmor/usr.sbin.i2pd @@ -0,0 +1,30 @@ +# Basic profile for i2pd +# Should work without modifications with Ubuntu/Debian packages +# Author: Darknet Villain +# +#include + +/usr/sbin/i2pd { + #include + + network inet dgram, + network inet stream, + network inet6 dgram, + network inet6 stream, + network netlink raw, + + /etc/gai.conf r, + /etc/host.conf r, + /etc/hosts r, + /etc/nsswitch.conf r, + /run/resolvconf/resolv.conf r, + + # path specific (feel free to modify if you have another paths) + /etc/i2pd/** r, + /var/lib/i2pd/** rw, + /var/log/i2pd.log w, + /var/run/i2pd/i2pd.pid rw, + /usr/sbin/i2pd mr, + + +} From 13111c4b424eb83d28c913b16f8400ce5e0d55ab Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 11 Feb 2017 18:18:37 -0500 Subject: [PATCH 3/7] don't re-schedule resend timer if nothing to resend --- SSUData.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/SSUData.cpp b/SSUData.cpp index 5ca4dac3..32e66e22 100644 --- a/SSUData.cpp +++ b/SSUData.cpp @@ -462,6 +462,7 @@ namespace transport else ++it; } + if (m_SentMessages.empty ()) return; // nothing to resend if (numResent < MAX_OUTGOING_WINDOW_SIZE) ScheduleResend (); else From 1ddc96f965ecc35357f25fabbd1fe559a3c512d6 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 12 Feb 2017 10:08:52 -0500 Subject: [PATCH 4/7] correct publication verification --- Destination.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Destination.cpp b/Destination.cpp index f3cb9af8..ac812da4 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -477,13 +477,18 @@ namespace client // "this" added due to bug in gcc 4.7-4.8 [s,this](std::shared_ptr leaseSet) { - if (leaseSet && s->m_LeaseSet) + if (leaseSet) { - // we got latest LeasetSet - LogPrint (eLogDebug, "Destination: published LeaseSet verified for ", GetIdentHash().ToBase32()); - s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL)); - s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1)); - return; + if (s->m_LeaseSet && *s->m_LeaseSet == *leaseSet) + { + // we got latest LeasetSet + LogPrint (eLogDebug, "Destination: published LeaseSet verified for ", GetIdentHash().ToBase32()); + s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL)); + s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1)); + return; + } + else + LogPrint (eLogDebug, "Destination: LeaseSet is different than just published for ", GetIdentHash().ToBase32()); } else LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet for ", GetIdentHash().ToBase32()); From c231eff4b1d74c2f09b1bd3584923f7e1ffc718c Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 12 Feb 2017 10:12:12 -0500 Subject: [PATCH 5/7] MTU size of 1488 for ipv6 --- SSU.h | 2 +- SSUData.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SSU.h b/SSU.h index c241b903..ee49c6a4 100644 --- a/SSU.h +++ b/SSU.h @@ -30,7 +30,7 @@ namespace transport struct SSUPacket { - i2p::crypto::AESAlignedBuffer buf; // max MTU + iv + size + i2p::crypto::AESAlignedBuffer buf; // max MTU + iv + size boost::asio::ip::udp::endpoint from; size_t len; }; diff --git a/SSUData.h b/SSUData.h index f3ad9ea8..8f625fe1 100644 --- a/SSUData.h +++ b/SSUData.h @@ -21,13 +21,13 @@ namespace transport #ifdef MESHNET const size_t SSU_MTU_V6 = 1286; #else - const size_t SSU_MTU_V6 = 1472; + const size_t SSU_MTU_V6 = 1488; #endif const size_t IPV4_HEADER_SIZE = 20; const size_t IPV6_HEADER_SIZE = 40; const size_t UDP_HEADER_SIZE = 8; const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456 - const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1424 + const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1440 const int RESEND_INTERVAL = 3; // in seconds const int MAX_NUM_RESENDS = 5; const int DECAY_INTERVAL = 20; // in seconds From b097938f4711fa6a721d97e56e96fb7aa159959a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 12 Feb 2017 15:11:19 -0500 Subject: [PATCH 6/7] compressed addressbook request --- AddressBook.cpp | 50 ++++++++++++++++++++++++++++++------------------- HTTP.cpp | 13 +++++++++---- HTTP.h | 6 +++--- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/AddressBook.cpp b/AddressBook.cpp index 20a118fb..c41dec50 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -705,6 +705,7 @@ namespace client i2p::http::HTTPReq req; req.AddHeader("Host", dest_host); req.AddHeader("User-Agent", "Wget/1.11.4"); + req.AddHeader("X-Accept-Encoding", "x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n"); req.AddHeader("Connection", "close"); if (!m_Etag.empty()) req.AddHeader("If-None-Match", m_Etag); @@ -721,7 +722,9 @@ namespace client std::string response; uint8_t recv_buf[4096]; bool end = false; - while (!end) { + int numAttempts = 5; + while (!end) + { stream->AsyncReceive (boost::asio::buffer (recv_buf, 4096), [&](const boost::system::error_code& ecode, std::size_t bytes_transferred) { @@ -734,60 +737,69 @@ namespace client 30); // wait for 30 seconds std::unique_lock l(newDataReceivedMutex); if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout) + { LogPrint (eLogError, "Addressbook: subscriptions request timeout expired"); + numAttempts++; + if (numAttempts > 5) end = true; + } } // process remaining buffer - while (size_t len = stream->ReadSome (recv_buf, sizeof(recv_buf))) { + while (size_t len = stream->ReadSome (recv_buf, sizeof(recv_buf))) response.append ((char *)recv_buf, len); - } /* parse response */ i2p::http::HTTPRes res; int res_head_len = res.parse(response); - if (res_head_len < 0) { + if (res_head_len < 0) + { LogPrint(eLogError, "Addressbook: can't parse http response from ", dest_host); return false; } - if (res_head_len == 0) { + if (res_head_len == 0) + { LogPrint(eLogError, "Addressbook: incomplete http response from ", dest_host, ", interrupted by timeout"); return false; } /* assert: res_head_len > 0 */ response.erase(0, res_head_len); - if (res.code == 304) { + if (res.code == 304) + { LogPrint (eLogInfo, "Addressbook: no updates from ", dest_host, ", code 304"); return false; } - if (res.code != 200) { + if (res.code != 200) + { LogPrint (eLogWarning, "Adressbook: can't get updates from ", dest_host, ", response code ", res.code); return false; } int len = res.content_length(); - if (response.empty()) { + if (response.empty()) + { LogPrint(eLogError, "Addressbook: empty response from ", dest_host, ", expected ", len, " bytes"); return false; } - if (len > 0 && len != (int) response.length()) { - LogPrint(eLogError, "Addressbook: response size mismatch, expected: ", response.length(), ", got: ", len, "bytes"); + if (!res.is_gzipped () && len > 0 && len != (int) response.length()) + { + LogPrint(eLogError, "Addressbook: response size mismatch, expected: ", len, ", got: ", response.length(), "bytes"); return false; } /* assert: res.code == 200 */ auto it = res.headers.find("ETag"); - if (it != res.headers.end()) { - m_Etag = it->second; - } + if (it != res.headers.end()) m_Etag = it->second; it = res.headers.find("If-Modified-Since"); - if (it != res.headers.end()) { - m_LastModified = it->second; - } - if (res.is_chunked()) { + if (it != res.headers.end()) m_LastModified = it->second; + if (res.is_chunked()) + { std::stringstream in(response), out; i2p::http::MergeChunkedResponse (in, out); response = out.str(); - } else if (res.is_gzipped()) { + } + else if (res.is_gzipped()) + { std::stringstream out; i2p::data::GzipInflator inflator; inflator.Inflate ((const uint8_t *) response.data(), response.length(), out); - if (out.fail()) { + if (out.fail()) + { LogPrint(eLogError, "Addressbook: can't gunzip http response"); return false; } diff --git a/HTTP.cpp b/HTTP.cpp index 6ab6ecf4..77922686 100644 --- a/HTTP.cpp +++ b/HTTP.cpp @@ -312,7 +312,8 @@ namespace http { return ""; } - bool HTTPRes::is_chunked() { + bool HTTPRes::is_chunked() const + { auto it = headers.find("Transfer-Encoding"); if (it == headers.end()) return false; @@ -321,16 +322,20 @@ namespace http { return false; } - bool HTTPRes::is_gzipped() { + bool HTTPRes::is_gzipped(bool includingI2PGzip) const + { auto it = headers.find("Content-Encoding"); if (it == headers.end()) return false; /* no header */ if (it->second.find("gzip") != std::string::npos) return true; /* gotcha! */ + if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos) + return true; return false; } - - long int HTTPMsg::content_length() { + + long int HTTPMsg::content_length() const + { unsigned long int length = 0; auto it = headers.find("Content-Length"); if (it == headers.end()) diff --git a/HTTP.h b/HTTP.h index 3175cb79..251d98bc 100644 --- a/HTTP.h +++ b/HTTP.h @@ -64,7 +64,7 @@ namespace http { void del_header(const char *name); /** @brief Returns declared message length or -1 if unknown */ - long int content_length(); + long int content_length() const; }; struct HTTPReq @@ -129,10 +129,10 @@ namespace http { void write(std::ostream & o); /** @brief Checks that response declared as chunked data */ - bool is_chunked(); + bool is_chunked() const ; /** @brief Checks that response contains compressed data */ - bool is_gzipped(); + bool is_gzipped(bool includingI2PGzip = true) const; }; /** From 422f8b36607a81a3780d5857a5a7b1bba1cd1cbd Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 12 Feb 2017 20:52:46 -0500 Subject: [PATCH 7/7] publish with min interval of 20 seconds --- Destination.cpp | 21 +++++++++++++++++++-- Destination.h | 6 +++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Destination.cpp b/Destination.cpp index ac812da4..06fcf6b3 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -14,8 +14,8 @@ namespace client { LeaseSetDestination::LeaseSetDestination (bool isPublic, const std::map * params): m_IsRunning (false), m_Thread (nullptr), m_IsPublic (isPublic), - m_PublishReplyToken (0), m_PublishConfirmationTimer (m_Service), - m_PublishVerificationTimer (m_Service), m_CleanupTimer (m_Service) + m_PublishReplyToken (0), m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service), + m_PublishVerificationTimer (m_Service), m_PublishDelayTimer (m_Service), m_CleanupTimer (m_Service) { int inLen = DEFAULT_INBOUND_TUNNEL_LENGTH; int inQty = DEFAULT_INBOUND_TUNNELS_QUANTITY; @@ -426,6 +426,16 @@ namespace client LogPrint (eLogDebug, "Destination: Publishing LeaseSet is pending"); return; } + auto ts = i2p::util::GetSecondsSinceEpoch (); + if (ts < m_LastSubmissionTime + PUBLISH_MIN_INTERVAL) + { + LogPrint (eLogDebug, "Destination: Publishing LeaseSet is too fast. Wait for ", PUBLISH_MIN_INTERVAL, " seconds"); + m_PublishDelayTimer.cancel (); + m_PublishDelayTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_MIN_INTERVAL)); + m_PublishDelayTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishDelayTimer, + shared_from_this (), std::placeholders::_1)); + return; + } auto outbound = m_Pool->GetNextOutboundTunnel (); if (!outbound) { @@ -453,6 +463,7 @@ namespace client m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, shared_from_this (), std::placeholders::_1)); outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg); + m_LastSubmissionTime = ts; } void LeaseSetDestination::HandlePublishConfirmationTimer (const boost::system::error_code& ecode) @@ -498,6 +509,12 @@ namespace client } } + void LeaseSetDestination::HandlePublishDelayTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + Publish (); + } + bool LeaseSetDestination::RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete) { if (!m_Pool || !IsReady ()) diff --git a/Destination.h b/Destination.h index 7a4e0b64..e077c016 100644 --- a/Destination.h +++ b/Destination.h @@ -30,6 +30,7 @@ namespace client const uint8_t PROTOCOL_TYPE_RAW = 18; const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds const int PUBLISH_VERIFICATION_TIMEOUT = 10; // in seconds after successfull publish + const int PUBLISH_MIN_INTERVAL = 20; // in seconds const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds @@ -122,6 +123,7 @@ namespace client void Publish (); void HandlePublishConfirmationTimer (const boost::system::error_code& ecode); void HandlePublishVerificationTimer (const boost::system::error_code& ecode); + void HandlePublishDelayTimer (const boost::system::error_code& ecode); void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len); void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len); void HandleDeliveryStatusMessage (std::shared_ptr msg); @@ -146,9 +148,11 @@ namespace client std::shared_ptr m_LeaseSet; bool m_IsPublic; uint32_t m_PublishReplyToken; + uint64_t m_LastSubmissionTime; // in seconds std::set m_ExcludedFloodfills; // for publishing - boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer, m_CleanupTimer; + boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer, + m_PublishDelayTimer, m_CleanupTimer; public: