diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 1ba22303..184e02b1 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -494,8 +494,9 @@ namespace http { auto ntcpServer = i2p::transport::transports.GetNTCPServer (); if (ntcpServer) { - s << "NTCP
\r\n"; - for (const auto& it: ntcpServer->GetNTCPSessions ()) + auto sessions = ntcpServer->GetNTCPSessions (); + s << "NTCP ( " << (int) sessions.size() << " )
\r\n"; + for (const auto& it: sessions ) { if (it.second && it.second->IsEstablished ()) { @@ -512,8 +513,9 @@ namespace http { auto ssuServer = i2p::transport::transports.GetSSUServer (); if (ssuServer) { - s << "
\r\nSSU
\r\n"; - for (const auto& it: ssuServer->GetSessions ()) + auto sessions = ssuServer->GetSessions (); + s << "
\r\nSSU ( " << (int) sessions.size() << " )
\r\n"; + for (const auto& it: sessions) { auto endpoint = it.second->GetRemoteEndpoint (); if (it.second->IsOutgoing ()) s << " ⇒ "; @@ -713,20 +715,22 @@ namespace http { } /* method #2: 'Authorization' header sent */ if (req.headers.count("Authorization") > 0) { + bool result = false; std::string provided = req.headers.find("Authorization")->second; std::string expected = user + ":" + pass; - char b64_creds[64]; + size_t b64_sz = i2p::data::Base64EncodingBufferSize(expected.length()) + 1; + char * b64_creds = new char[b64_sz]; std::size_t len = 0; - len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds)); + len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, b64_sz); /* if we decoded properly then check credentials */ if(len) { b64_creds[len] = '\0'; expected = "Basic "; expected += b64_creds; - return expected == provided; + result = expected == provided; } - /** we decoded wrong so it's not a correct login credential */ - return false; + delete [] b64_creds; + return result; } LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ()); diff --git a/I2PControl.cpp b/I2PControl.cpp index 3e2e3997..523f10e1 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include @@ -14,7 +16,6 @@ #include "Crypto.h" #include "FS.h" #include "Log.h" -#include "HTTP.h" #include "Config.h" #include "NetDb.h" #include "RouterContext.h" @@ -189,64 +190,71 @@ namespace client if (ecode) { LogPrint (eLogError, "I2PControl: read error: ", ecode.message ()); return; - } - /* try to parse received data */ - std::stringstream json; - std::string response; - bool isHTTP = false; - if (memcmp (buf->data (), "POST", 4) == 0) { - long int remains = 0; - isHTTP = true; - i2p::http::HTTPReq req; - std::size_t len = req.parse(buf->data(), bytes_transferred); - if (len <= 0) { - LogPrint(eLogError, "I2PControl: incomplete/malformed POST request"); - return; - } - /* append to json chunk of data from 1st request */ - json.write(buf->data() + len, bytes_transferred - len); - remains = req.content_length() - len; - /* if request has Content-Length header, fetch rest of data and store to json buffer */ - while (remains > 0) { - len = ((long int) buf->size() < remains) ? buf->size() : remains; - bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), len)); - json.write(buf->data(), bytes_transferred); - remains -= bytes_transferred; - } } else { - json.write(buf->data(), bytes_transferred); - } - LogPrint(eLogDebug, "I2PControl: json from request: ", json.str()); + try + { + bool isHtml = !memcmp (buf->data (), "POST", 4); + std::stringstream ss; + ss.write (buf->data (), bytes_transferred); + if (isHtml) + { + std::string header; + size_t contentLength = 0; + while (!ss.eof () && header != "\r") + { + std::getline(ss, header); + auto colon = header.find (':'); + if (colon != std::string::npos && header.substr (0, colon) == "Content-Length") + contentLength = std::stoi (header.substr (colon + 1)); + } + if (ss.eof ()) + { + LogPrint (eLogError, "I2PControl: malformed request, HTTP header expected"); + return; // TODO: + } + std::streamoff rem = contentLength + ss.tellg () - bytes_transferred; // more bytes to read + if (rem > 0) + { + bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), rem)); + ss.write (buf->data (), bytes_transferred); + } + } + std::ostringstream response; #if GCC47_BOOST149 - LogPrint (eLogError, "I2PControl: json_read is not supported due bug in boost 1.49 with gcc 4.7"); - BuildErrorResponse(response, 32603, "JSON requests is not supported with this version of boost"); + LogPrint (eLogError, "I2PControl: json_read is not supported due bug in boost 1.49 with gcc 4.7"); + response << "{\"id\":null,\"error\":"; + response << "{\"code\":-32603,\"message\":\"JSON requests is not supported with this version of boost\"},"; + response << "\"jsonrpc\":\"2.0\"}"; #else - /* now try to parse json itself */ - try { - boost::property_tree::ptree pt; - boost::property_tree::read_json (json, pt); - - std::string id = pt.get("id"); - std::string method = pt.get("method"); - auto it = m_MethodHandlers.find (method); - if (it != m_MethodHandlers.end ()) { - std::ostringstream ss; - ss << "{\"id\":" << id << ",\"result\":{"; - (this->*(it->second))(pt.get_child ("params"), ss); - ss << "},\"jsonrpc\":\"2.0\"}"; - response = ss.str(); - } else { - LogPrint (eLogWarning, "I2PControl: unknown method ", method); - BuildErrorResponse(response, 32601, "Method not found"); + boost::property_tree::ptree pt; + boost::property_tree::read_json (ss, pt); + + std::string id = pt.get("id"); + std::string method = pt.get("method"); + auto it = m_MethodHandlers.find (method); + if (it != m_MethodHandlers.end ()) + { + response << "{\"id\":" << id << ",\"result\":{"; + (this->*(it->second))(pt.get_child ("params"), response); + response << "},\"jsonrpc\":\"2.0\"}"; + } else { + LogPrint (eLogWarning, "I2PControl: unknown method ", method); + response << "{\"id\":null,\"error\":"; + response << "{\"code\":-32601,\"message\":\"Method not found\"},"; + response << "\"jsonrpc\":\"2.0\"}"; + } +#endif + SendResponse (socket, buf, response, isHtml); + } + catch (std::exception& ex) + { + LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ()); + } + catch (...) + { + LogPrint (eLogError, "I2PControl: handle request unknown exception"); } - } catch (std::exception& ex) { - LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ()); - BuildErrorResponse(response, 32603, ex.what()); - } catch (...) { - LogPrint (eLogError, "I2PControl: handle request unknown exception"); } -#endif - SendResponse (socket, buf, response, isHTTP); } void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const @@ -268,28 +276,27 @@ namespace client ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value; } - void I2PControlService::BuildErrorResponse (std::string & content, int code, const char *message) { - std::stringstream ss; - ss << "{\"id\":null,\"error\":"; - ss << "{\"code\":" << -code << ",\"message\":\"" << message << "\"},"; - ss << "\"jsonrpc\":\"2.0\"}"; - content = ss.str(); - } - void I2PControlService::SendResponse (std::shared_ptr socket, - std::shared_ptr buf, std::string& content, bool isHTTP) - { - if (isHTTP) { - i2p::http::HTTPRes res; - res.code = 200; - res.add_header("Content-Type", "application/json"); - res.add_header("Connection", "close"); - res.body = content; - std::string tmp = res.to_string(); - content = tmp; + std::shared_ptr buf, std::ostringstream& response, bool isHtml) + { + size_t len = response.str ().length (), offset = 0; + if (isHtml) + { + std::ostringstream header; + header << "HTTP/1.1 200 OK\r\n"; + header << "Connection: close\r\n"; + header << "Content-Length: " << boost::lexical_cast(len) << "\r\n"; + header << "Content-Type: application/json\r\n"; + header << "Date: "; + auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT"); + header.imbue(std::locale (header.getloc(), facet)); + header << boost::posix_time::second_clock::local_time() << "\r\n"; + header << "\r\n"; + offset = header.str ().size (); + memcpy (buf->data (), header.str ().c_str (), offset); } - std::copy(content.begin(), content.end(), buf->begin()); - boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), content.length()), + memcpy (buf->data () + offset, response.str ().c_str (), len); + boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len), boost::asio::transfer_all (), std::bind(&I2PControlService::HandleResponseSent, this, std::placeholders::_1, std::placeholders::_2, socket, buf)); @@ -316,7 +323,7 @@ namespace client } InsertParam (results, "API", api); results << ","; - std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch ()); + std::string token = boost::lexical_cast(i2p::util::GetSecondsSinceEpoch ()); m_Tokens.insert (token); InsertParam (results, "Token", token); } @@ -358,7 +365,7 @@ namespace client void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - for (auto it = params.begin (); it != params.end (); ++it) + for (auto it = params.begin (); it != params.end (); it++) { LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first); auto it1 = m_RouterInfoHandlers.find (it->first); @@ -434,7 +441,7 @@ namespace client void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - for (auto it = params.begin (); it != params.end (); ++it) + for (auto it = params.begin (); it != params.end (); it++) { if (it != params.begin ()) results << ","; LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first); @@ -483,7 +490,7 @@ namespace client // network setting void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - for (auto it = params.begin (); it != params.end (); ++it) + for (auto it = params.begin (); it != params.end (); it++) { if (it != params.begin ()) results << ","; LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first); @@ -529,7 +536,7 @@ namespace client X509_gmtime_adj (X509_get_notAfter (x509), I2P_CONTROL_CERTIFICATE_VALIDITY*24*60*60); // expiration X509_set_pubkey (x509, pkey); // public key X509_NAME * name = X509_get_subject_name (x509); - X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"RU", -1, -1, 0); // country (Russia by default) + X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"A1", -1, -1, 0); // country (Anonymous proxy) X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_ORGANIZATION, -1, -1, 0); // organization X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name X509_set_issuer_name (x509, name); // set issuer to ourselves diff --git a/I2PControl.h b/I2PControl.h index bd5b9bad..047c2fe2 100644 --- a/I2PControl.h +++ b/I2PControl.h @@ -45,9 +45,8 @@ namespace client void ReadRequest (std::shared_ptr socket); void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf); - void BuildErrorResponse (std::string & content, int code, const char *message); void SendResponse (std::shared_ptr socket, - std::shared_ptr buf, std::string& response, bool isHtml); + std::shared_ptr buf, std::ostringstream& response, bool isHtml); void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf); @@ -120,4 +119,3 @@ namespace client } #endif - diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 9e790966..44b4791e 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -493,7 +493,8 @@ namespace transport void NTCPSession::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - if (ecode) { + if (ecode) + { if (ecode != boost::asio::error::operation_aborted) LogPrint (eLogDebug, "NTCP: Read error: ", ecode.message ()); //if (ecode != boost::asio::error::operation_aborted) @@ -507,48 +508,66 @@ namespace transport if (m_ReceiveBufferOffset >= 16) { - int numReloads = 0; - do - { - uint8_t * nextBlock = m_ReceiveBuffer; - while (m_ReceiveBufferOffset >= 16) + // process received data + uint8_t * nextBlock = m_ReceiveBuffer; + while (m_ReceiveBufferOffset >= 16) + { + if (!DecryptNextBlock (nextBlock)) // 16 bytes { - if (!DecryptNextBlock (nextBlock)) // 16 bytes - { - Terminate (); - return; - } - nextBlock += 16; - m_ReceiveBufferOffset -= 16; + Terminate (); + return; } - 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 && !ec) - { - 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), ec); - if (ec) - { - LogPrint (eLogInfo, "NTCP: 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); + } + + // read and process more is available + boost::system::error_code ec; + size_t moreBytes = m_Socket.available(ec); + if (moreBytes && !ec) + { + uint8_t * buf = nullptr, * moreBuf = m_ReceiveBuffer; + if (moreBytes + m_ReceiveBufferOffset > NTCP_BUFFER_SIZE) + { + buf = new uint8_t[moreBytes + m_ReceiveBufferOffset + 16]; + moreBuf = buf; + uint8_t rem = ((size_t)buf) & 0x0f; + if (rem) moreBuf += (16 - rem); // align 16 + if (m_ReceiveBufferOffset) + memcpy (moreBuf, m_ReceiveBuffer, m_ReceiveBufferOffset); + } + moreBytes = m_Socket.read_some (boost::asio::buffer (moreBuf + m_ReceiveBufferOffset, moreBytes), ec); + if (ec) + { + LogPrint (eLogInfo, "NTCP: Read more bytes error: ", ec.message ()); + delete[] buf; + Terminate (); + return; + } + m_ReceiveBufferOffset += moreBytes; + m_NumReceivedBytes += moreBytes; + i2p::transport::transports.UpdateReceivedBytes (moreBytes); + // process more data + uint8_t * nextBlock = moreBuf; + while (m_ReceiveBufferOffset >= 16) + { + if (!DecryptNextBlock (nextBlock)) // 16 bytes + { + delete[] buf; + Terminate (); + return; } + nextBlock += 16; + m_ReceiveBufferOffset -= 16; } - while (m_ReceiveBufferOffset >= 16); - m_Handler.Flush (); - } + if (m_ReceiveBufferOffset > 0) + memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset); // nextBlock points to memory inside buf + delete[] buf; + } + m_Handler.Flush (); m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); Receive (); diff --git a/NTCPSession.h b/NTCPSession.h index b02543be..a5d6f99f 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -35,12 +35,11 @@ namespace transport }; const size_t NTCP_MAX_MESSAGE_SIZE = 16384; - const size_t NTCP_BUFFER_SIZE = 4160; // fits 4 tunnel messages (4*1028) + const size_t NTCP_BUFFER_SIZE = 1028; // fits 1 tunnel data message const int NTCP_CONNECT_TIMEOUT = 5; // 5 seconds const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes const int NTCP_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds 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 const int NTCP_CLOCK_SKEW = 60; // in seconds const int NTCP_MAX_OUTGOING_QUEUE_SIZE = 200; // how many messages we can queue up diff --git a/RouterContext.cpp b/RouterContext.cpp index 3c37e88c..966da6ac 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -266,8 +266,9 @@ namespace i2p } } // delete previous introducers - for (auto& addr : addresses) - addr->introducers.clear (); + for (auto& addr : addresses) + if (addr->ssu) + addr->ssu->introducers.clear (); // update UpdateRouterInfo (); @@ -298,7 +299,8 @@ namespace i2p } // delete previous introducers for (auto& addr : addresses) - addr->introducers.clear (); + if (addr->ssu) + addr->ssu->introducers.clear (); // update UpdateRouterInfo (); diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 4ae2f9e5..08d46ecb 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -175,11 +175,14 @@ namespace data if (!strcmp (transportStyle, "NTCP")) address->transportStyle = eTransportNTCP; else if (!strcmp (transportStyle, "SSU")) + { address->transportStyle = eTransportSSU; + address->ssu.reset (new SSUExt ()); + address->ssu->mtu = 0; + } else address->transportStyle = eTransportUnknown; address->port = 0; - address->mtu = 0; uint16_t size, r = 0; s.read ((char *)&size, sizeof (size)); if (!s) return; size = be16toh (size); @@ -220,9 +223,19 @@ namespace data else if (!strcmp (key, "port")) address->port = boost::lexical_cast(value); else if (!strcmp (key, "mtu")) - address->mtu = boost::lexical_cast(value); + { + if (address->ssu) + address->ssu->mtu = boost::lexical_cast(value); + else + LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP"); + } else if (!strcmp (key, "key")) - Base64ToByteStream (value, strlen (value), address->key, 32); + { + if (address->ssu) + Base64ToByteStream (value, strlen (value), address->ssu->key, 32); + else + LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP"); + } else if (!strcmp (key, "caps")) ExtractCaps (value); else if (key[0] == 'i') @@ -237,9 +250,9 @@ namespace data LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped"); if (s) continue; else return; } - if (index >= address->introducers.size ()) - address->introducers.resize (index + 1); - Introducer& introducer = address->introducers.at (index); + if (index >= address->ssu->introducers.size ()) + address->ssu->introducers.resize (index + 1); + Introducer& introducer = address->ssu->introducers.at (index); if (!strcmp (key, "ihost")) { boost::system::error_code ecode; @@ -417,10 +430,10 @@ namespace data if (address.transportStyle == eTransportSSU) { // write introducers if any - if (address.introducers.size () > 0) + if (address.ssu->introducers.size () > 0) { int i = 0; - for (const auto& introducer: address.introducers) + for (const auto& introducer: address.ssu->introducers) { WriteString ("ihost" + boost::lexical_cast(i), properties); properties << '='; @@ -429,7 +442,7 @@ namespace data i++; } i = 0; - for (const auto& introducer: address.introducers) + for (const auto& introducer: address.ssu->introducers) { WriteString ("ikey" + boost::lexical_cast(i), properties); properties << '='; @@ -441,7 +454,7 @@ namespace data i++; } i = 0; - for (const auto& introducer: address.introducers) + for (const auto& introducer: address.ssu->introducers) { WriteString ("iport" + boost::lexical_cast(i), properties); properties << '='; @@ -450,7 +463,7 @@ namespace data i++; } i = 0; - for (const auto& introducer: address.introducers) + for (const auto& introducer: address.ssu->introducers) { WriteString ("itag" + boost::lexical_cast(i), properties); properties << '='; @@ -463,16 +476,16 @@ namespace data WriteString ("key", properties); properties << '='; char value[64]; - size_t l = ByteStreamToBase64 (address.key, 32, value, 64); + size_t l = ByteStreamToBase64 (address.ssu->key, 32, value, 64); value[l] = 0; WriteString (value, properties); properties << ';'; // write mtu - if (address.mtu) + if (address.ssu->mtu) { WriteString ("mtu", properties); properties << '='; - WriteString (boost::lexical_cast(address.mtu), properties); + WriteString (boost::lexical_cast(address.ssu->mtu), properties); properties << ';'; } } @@ -589,7 +602,6 @@ namespace data addr->transportStyle = eTransportNTCP; addr->cost = 2; addr->date = 0; - addr->mtu = 0; for (const auto& it: *m_Addresses) // don't insert same address twice if (*it == *addr) return; m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4; @@ -604,8 +616,9 @@ namespace data addr->transportStyle = eTransportSSU; addr->cost = 10; // NTCP should have priority over SSU addr->date = 0; - addr->mtu = mtu; - memcpy (addr->key, key, 32); + addr->ssu.reset (new SSUExt ()); + addr->ssu->mtu = mtu; + memcpy (addr->ssu->key, key, 32); for (const auto& it: *m_Addresses) // don't insert same address twice if (*it == *addr) return; m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4; @@ -621,9 +634,9 @@ namespace data { if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) { - for (auto& intro: addr->introducers) + for (auto& intro: addr->ssu->introducers) if (intro.iTag == introducer.iTag) return false; // already presented - addr->introducers.push_back (introducer); + addr->ssu->introducers.push_back (introducer); return true; } } @@ -636,10 +649,10 @@ namespace data { if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) { - for (auto it = addr->introducers.begin (); it != addr->introducers.end (); ++it) + for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it) if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e) { - addr->introducers.erase (it); + addr->ssu->introducers.erase (it); return true; } } diff --git a/RouterInfo.h b/RouterInfo.h index c51d3ce4..7300e579 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -79,17 +79,22 @@ namespace data uint32_t iTag; }; + struct SSUExt + { + int mtu; + IntroKey key; // intro key for SSU + std::vector introducers; + }; + struct Address { TransportStyle transportStyle; boost::asio::ip::address host; std::string addressString; - int port, mtu; + int port; uint64_t date; uint8_t cost; - // SSU only - IntroKey key; // intro key for SSU - std::vector introducers; + std::unique_ptr ssu; // not null for SSU bool IsCompatible (const boost::asio::ip::address& other) const { diff --git a/SAM.cpp b/SAM.cpp index 2166ed72..929b144d 100644 --- a/SAM.cpp +++ b/SAM.cpp @@ -693,9 +693,9 @@ namespace client LogPrint (eLogDebug, "SAM: datagram received ", len); auto base64 = from.ToBase64 (); #ifdef _MSC_VER - size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len); + size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len); #else - size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len); + size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len); #endif if (len < SAM_SOCKET_BUFFER_SIZE - l) { diff --git a/SSU.cpp b/SSU.cpp index 9f74185f..9dc05608 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -417,7 +417,7 @@ namespace transport return; } // create new session - int numIntroducers = address->introducers.size (); + int numIntroducers = address->ssu->introducers.size (); if (numIntroducers > 0) { std::shared_ptr introducerSession; @@ -425,7 +425,7 @@ namespace transport // we might have a session to introducer already for (int i = 0; i < numIntroducers; i++) { - auto intr = &(address->introducers[i]); + auto intr = &(address->ssu->introducers[i]); boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort); if (ep.address ().is_v4 ()) // ipv4 only { diff --git a/SSUData.cpp b/SSUData.cpp index cb20b3e8..b9b1d93e 100644 --- a/SSUData.cpp +++ b/SSUData.cpp @@ -54,23 +54,23 @@ namespace transport { if (remoteRouter) return; auto ssuAddress = remoteRouter->GetSSUAddress (); - if (ssuAddress && ssuAddress->mtu) + if (ssuAddress && ssuAddress->ssu->mtu) { if (m_Session.IsV6 ()) - m_PacketSize = ssuAddress->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; + m_PacketSize = ssuAddress->ssu->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; else - m_PacketSize = ssuAddress->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; + m_PacketSize = ssuAddress->ssu->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; if (m_PacketSize > 0) { // make sure packet size multiple of 16 m_PacketSize >>= 4; m_PacketSize <<= 4; if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize; - LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->mtu, " packet size=", m_PacketSize); + LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize); } else { - LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->mtu); + LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu); m_PacketSize = m_MaxPacketSize; } } diff --git a/SSUSession.cpp b/SSUSession.cpp index dbb26bc9..050b2f9a 100644 --- a/SSUSession.cpp +++ b/SSUSession.cpp @@ -22,14 +22,14 @@ namespace transport { // we are client auto address = router->GetSSUAddress (false); - if (address) m_IntroKey = address->key; + if (address) m_IntroKey = address->ssu->key; m_Data.AdjustPacketSize (router); // mtu } else { // we are server auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false); - if (address) m_IntroKey = address->key; + if (address) m_IntroKey = address->ssu->key; } m_CreationTime = i2p::util::GetSecondsSinceEpoch (); } @@ -115,8 +115,8 @@ namespace transport LogPrint (eLogInfo, "SSU is not supported"); return; } - if (Validate (buf, len, address->key)) - Decrypt (buf, len, address->key); + if (Validate (buf, len, address->ssu->key)) + Decrypt (buf, len, address->ssu->key); else { LogPrint (eLogWarning, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint); @@ -403,7 +403,7 @@ namespace transport payload += 2; *payload = 0; // challenge payload++; - memcpy (payload, (const uint8_t *)address->key, 32); + memcpy (payload, (const uint8_t *)address->ssu->key, 32); payload += 32; htobe32buf (payload, nonce); // nonce @@ -1081,7 +1081,7 @@ namespace transport // send our intro key to address instead it's own auto addr = i2p::context.GetRouterInfo ().GetSSUAddress (); if (addr) - memcpy (payload, addr->key, 32); // intro key + memcpy (payload, addr->ssu->key, 32); // intro key else LogPrint (eLogInfo, "SSU is not supported. Can't send peer test"); } @@ -1121,7 +1121,7 @@ namespace transport if (!nonce) nonce = 1; m_IsPeerTest = false; m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1, shared_from_this ()); - SendPeerTest (nonce, boost::asio::ip::address(), 0, address->key, false, false); // address and port always zero for Alice + SendPeerTest (nonce, boost::asio::ip::address(), 0, address->ssu->key, false, false); // address and port always zero for Alice } void SSUSession::SendKeepAlive () diff --git a/Transports.cpp b/Transports.cpp index dda9b7c6..1659eeed 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -384,7 +384,7 @@ namespace transport } } } - LogPrint (eLogError, "Transports: No NTCP or SSU addresses available"); + LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available"); peer.Done (); std::unique_lock l(m_PeersMutex); m_Peers.erase (ident); diff --git a/Tunnel.cpp b/Tunnel.cpp index e271052e..6f9346d2 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -19,36 +19,11 @@ namespace i2p { namespace tunnel -{ - - void TunnelLatency::AddSample(Sample s) - { - std::unique_lock l(m_access); - m_samples.push_back(s); - } - - bool TunnelLatency::HasSamples() const - { - std::unique_lock l(m_access); - return m_samples.size() > 0; - } - - TunnelLatency::Latency TunnelLatency::GetMeanLatency() const - { - std::unique_lock lock(m_access); - if (m_samples.size() > 0) { - Latency l = 0; - for(auto s : m_samples) - l += s; - return l / m_samples.size(); - } - return 0; - } - - +{ Tunnel::Tunnel (std::shared_ptr config): TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()), - m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false) + m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false), + m_Latency (0) { } diff --git a/Tunnel.h b/Tunnel.h index f3c31461..08533ec4 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -78,21 +78,6 @@ namespace tunnel eTunnelStateFailed, eTunnelStateExpiring }; - - /** @brief for storing latency history */ - struct TunnelLatency - { - typedef uint64_t Sample; - typedef uint64_t Latency; - - - void AddSample(Sample s); - bool HasSamples() const; - Latency GetMeanLatency() const; - - std::vector m_samples; - mutable std::mutex m_access; - }; class OutboundTunnel; class InboundTunnel; @@ -133,14 +118,14 @@ namespace tunnel void SendTunnelDataMsg (std::shared_ptr msg); void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out); - /** @brief add latency sample */ - void AddLatencySample(const uint64_t ms) { m_Latency.AddSample(ms); } - /** @brief get this tunnel's estimated latency */ - uint64_t GetMeanLatency() const { return m_Latency.GetMeanLatency(); } - /** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */ - bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const; + /** @brief add latency sample */ + void AddLatencySample(const uint64_t ms) { m_Latency = (m_Latency + ms) >> 1; } + /** @brief get this tunnel's estimated latency */ + uint64_t GetMeanLatency() const { return m_Latency; } + /** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */ + bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const; - bool LatencyIsKnown() const { return m_Latency.HasSamples(); } + bool LatencyIsKnown() const { return m_Latency > 0; } protected: void PrintHops (std::stringstream& s) const; @@ -152,7 +137,7 @@ namespace tunnel std::shared_ptr m_Pool; // pool, tunnel belongs to, or null TunnelState m_State; bool m_IsRecreated; - TunnelLatency m_Latency; + uint64_t m_Latency; // in milliseconds }; class OutboundTunnel: public Tunnel diff --git a/android/project.properties b/android/project.properties index 7ce68660..f72b9716 100644 --- a/android/project.properties +++ b/android/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-24 +target=android-25 diff --git a/android/res/drawable/icon.png b/android/res/drawable/icon.png index a5dc7b68..9a2f7404 100644 Binary files a/android/res/drawable/icon.png and b/android/res/drawable/icon.png differ diff --git a/android/res/drawable/itoopie_notification_icon.png b/android/res/drawable/itoopie_notification_icon.png index 8fbe2468..d055bc8f 100644 Binary files a/android/res/drawable/itoopie_notification_icon.png and b/android/res/drawable/itoopie_notification_icon.png differ diff --git a/docs/configuration.md b/docs/configuration.md index b04be9fb..3212aea9 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -73,9 +73,12 @@ All options below still possible in cmdline, but better write it in config file: * --i2cp.port= - Port of I2CP server. Usually 7654. Ignored for Andorid * --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't require I2CP -* --i2pcontrol.address= - The address to listen on (I2P control service) -* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified -* --i2pcontrol.enabled= - If I2P control is enabled. false by default +* --i2pcontrol.address= - The address to listen on (I2P control service) +* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified +* --i2pcontrol.enabled= - If I2P control is enabled. false by default +* --i2pcontrol.password= - I2P control authentication password. itoopie by default +* --i2pcontrol.cert= - I2P control HTTPS certificate file name. i2pcontrol.crt.pem by default +* --i2pcontrol.key= - I2P control HTTPS certificate key file name. i2pcontrol.key.pem by default * --upnp.enabled= - Enable or disable UPnP, false by default for CLI and true for GUI (Windows, Android) * --upnp.name= - Name i2pd appears in UPnP forwardings list. I2Pd by default diff --git a/qt/i2pd_qt/README.md b/qt/i2pd_qt/README.md new file mode 100644 index 00000000..94186ecf --- /dev/null +++ b/qt/i2pd_qt/README.md @@ -0,0 +1,3 @@ +# Build Requirements + + * Qt 5 is necessary (because Qt4 lacks QtWidgets/ folder)