upstream pull

This commit is contained in:
r4sas 2017-02-13 14:17:48 +03:00
commit 44cfe6af1c
12 changed files with 121 additions and 40 deletions

View File

@ -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<std::mutex> 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;
}

View File

@ -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<std::string, std::string> 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<std::string, std::string> params;
ReadI2CPOptionsFromConfig ("socksproxy.", params);

View File

@ -16,6 +16,7 @@
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
#include "Identity.h"
#include "Config.h"
#include "version.h"
@ -85,6 +86,7 @@ namespace config {
("httpproxy.address", value<std::string>()->default_value("127.0.0.1"), "HTTP Proxy listen address")
("httpproxy.port", value<uint16_t>()->default_value(4444), "HTTP Proxy listen port")
("httpproxy.keys", value<std::string>()->default_value(""), "File to persist HTTP Proxy keys")
("httpproxy.signaturetype", value<i2p::data::SigningKeyType>()->default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default")
("httpproxy.inbound.length", value<std::string>()->default_value("3"), "HTTP proxy inbound tunnel length")
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length")
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity")
@ -100,6 +102,7 @@ namespace config {
("socksproxy.address", value<std::string>()->default_value("127.0.0.1"), "SOCKS Proxy listen address")
("socksproxy.port", value<uint16_t>()->default_value(4447), "SOCKS Proxy listen port")
("socksproxy.keys", value<std::string>()->default_value(""), "File to persist SOCKS Proxy keys")
("socksproxy.signaturetype", value<i2p::data::SigningKeyType>()->default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default")
("socksproxy.inbound.length", value<std::string>()->default_value("3"), "SOCKS proxy inbound tunnel length")
("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length")
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity")

View File

@ -14,8 +14,8 @@ namespace client
{
LeaseSetDestination::LeaseSetDestination (bool isPublic, const std::map<std::string, std::string> * 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)
@ -477,13 +488,18 @@ namespace client
// "this" added due to bug in gcc 4.7-4.8
[s,this](std::shared_ptr<i2p::data::LeaseSet> 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());
@ -493,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 ())

View File

@ -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<I2NPMessage> msg);
@ -146,9 +148,11 @@ namespace client
std::shared_ptr<i2p::data::LocalLeaseSet> m_LeaseSet;
bool m_IsPublic;
uint32_t m_PublishReplyToken;
uint64_t m_LastSubmissionTime; // in seconds
std::set<i2p::data::IdentHash> 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:

View File

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

6
HTTP.h
View File

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

2
SSU.h
View File

@ -30,7 +30,7 @@ namespace transport
struct SSUPacket
{
i2p::crypto::AESAlignedBuffer<SSU_MTU_V4 + 18> buf; // max MTU + iv + size
i2p::crypto::AESAlignedBuffer<SSU_MTU_V6 + 18> buf; // max MTU + iv + size
boost::asio::ip::udp::endpoint from;
size_t len;
};

View File

@ -462,6 +462,7 @@ namespace transport
else
++it;
}
if (m_SentMessages.empty ()) return; // nothing to resend
if (numResent < MAX_OUTGOING_WINDOW_SIZE)
ScheduleResend ();
else

View File

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

View File

@ -0,0 +1,30 @@
# Basic profile for i2pd
# Should work without modifications with Ubuntu/Debian packages
# Author: Darknet Villain <supervillain@riseup.net>
#
#include <tunables/global>
/usr/sbin/i2pd {
#include <abstractions/base>
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,
}

View File

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