diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index cd17660a..580e9156 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -58,9 +58,9 @@ namespace config { ("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") - ("ntcp", value()->default_value(false), "Enable NTCP transport (default: disabled)") + ("ntcp", value()->default_value(false), "Enable NTCP transport (default: disabled)") ("ssu", value()->default_value(true), "Enable SSU transport (default: enabled)") - ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") + ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") @@ -97,7 +97,8 @@ 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.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") @@ -114,7 +115,8 @@ 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.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/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 85d83bf0..e7c37fdd 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1148,7 +1148,7 @@ namespace transport NTCP2Server::NTCP2Server (): RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()), - m_Resolver(GetService ()) + m_Resolver(GetService ()), m_ProxyType(eNoProxy), m_ProxyEndpoint(nullptr) { } @@ -1164,25 +1164,23 @@ namespace transport StartIOService (); if(UsingProxy()) { - LogPrint(eLogError, "NTCP2: USING PROXY "); + LogPrint(eLogInfo, "NTCP2: Using proxy to connect to peers"); // TODO: resolve proxy until it is resolved boost::asio::ip::tcp::resolver::query q(m_ProxyAddress, std::to_string(m_ProxyPort)); boost::system::error_code e; auto itr = m_Resolver.resolve(q, e); if(e) - { LogPrint(eLogError, "NTCP2: Failed to resolve proxy ", e.message()); - } else { m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint(*itr)); if (m_ProxyEndpoint) - LogPrint(eLogError, "NTCP2: m_ProxyEndpoint ", *m_ProxyEndpoint); + LogPrint(eLogDebug, "NTCP2: m_ProxyEndpoint ", *m_ProxyEndpoint); } } else { - LogPrint(eLogError, "NTCP2: NOTUSING PROXY "); + LogPrint(eLogInfo, "NTCP2: Proxy is not used"); auto& addresses = context.GetRouterInfo ().GetAddresses (); for (const auto& address: addresses) { @@ -1426,6 +1424,31 @@ namespace transport } } + void NTCP2Server::ConnectWithProxy (const std::string& host, uint16_t port, RemoteAddressType addrtype, std::shared_ptr conn) + { + if(!m_ProxyEndpoint) return; + GetService().post([this, host, port, addrtype, conn]() { + if (this->AddNTCP2Session (conn)) + { + + auto timer = std::make_shared(GetService()); + auto timeout = NTCP_CONNECT_TIMEOUT * 5; + conn->SetTerminationTimeout(timeout * 2); + timer->expires_from_now (boost::posix_time::seconds(timeout)); + timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds"); + i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); + conn->Terminate (); + } + }); + conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer, host, port, addrtype)); + } + }); + } + void NTCP2Server::UseProxy(ProxyType proxytype, const std::string & addr, uint16_t port) { m_ProxyType = proxytype; @@ -1443,14 +1466,14 @@ namespace transport return; } switch (m_ProxyType) - { + { case eSocksProxy: { // TODO: support username/password auth etc static const uint8_t buff[3] = {0x05, 0x01, 0x00}; - boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(), - [] (const boost::system::error_code & ec, std::size_t transferred) - { + boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(), + [] (const boost::system::error_code & ec, std::size_t transferred) + { (void) transferred; if(ec) { @@ -1505,8 +1528,8 @@ namespace transport out << req.to_string(); boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(), - [](const boost::system::error_code & ec, std::size_t transferred) - { + [](const boost::system::error_code & ec, std::size_t transferred) + { (void) transferred; if(ec) LogPrint(eLogError, "NTCP2: http proxy write error ", ec.message()); @@ -1549,38 +1572,13 @@ namespace transport } default: LogPrint(eLogError, "NTCP2: unknown proxy type, invalid state"); - } + } } - void NTCP2Server::ConnectWithProxy (const std::string& host, uint16_t port, RemoteAddressType addrtype, std::shared_ptr conn) - { - if(!m_ProxyEndpoint) return; - GetService().post([this, host, port, addrtype, conn]() { - if (this->AddNTCP2Session (conn)) - { - - auto timer = std::make_shared(GetService()); - auto timeout = NTCP_CONNECT_TIMEOUT * 5; - conn->SetTerminationTimeout(timeout * 2); - timer->expires_from_now (boost::posix_time::seconds(timeout)); - timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) - { - if (ecode != boost::asio::error::operation_aborted) - { - LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds"); - i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); - conn->Terminate (); - } - }); - conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer, host, port, addrtype)); - } - }); - } - void NTCP2Server::AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) { // build request - size_t sz = 0; + size_t sz = 6; // header + port auto buff = std::make_shared >(256); auto readbuff = std::make_shared >(256); (*buff)[0] = 0x05; @@ -1590,37 +1588,27 @@ namespace transport if(addrtype == eIP4Address) { (*buff)[3] = 0x01; - auto addr = boost::asio::ip::address::from_string(host).to_v4(); - auto addrbytes = addr.to_bytes(); - auto addrsize = addrbytes.size(); - memcpy(buff->data () + 4, addrbytes.data(), addrsize); + auto addrbytes = boost::asio::ip::address::from_string(host).to_v4().to_bytes(); + sz += 4; + memcpy(buff->data () + 4, addrbytes.data(), 4); } else if (addrtype == eIP6Address) { (*buff)[3] = 0x04; - auto addr = boost::asio::ip::address::from_string(host).to_v6(); - auto addrbytes = addr.to_bytes(); - auto addrsize = addrbytes.size(); - memcpy(buff->data () + 4, addrbytes.data(), addrsize); + auto addrbytes = boost::asio::ip::address::from_string(host).to_v6().to_bytes(); + sz += 16; + memcpy(buff->data () + 4, addrbytes.data(), 16); } else if (addrtype == eHostname) { - (*buff)[3] = 0x03; - size_t addrsize = host.size(); - sz = addrsize + 1 + 4; - if (2 + sz > buff->size ()) - { - // too big - return; - } - (*buff)[4] = (uint8_t) addrsize; - memcpy(buff->data() + 5, host.c_str(), addrsize); + // We mustn't really fall here because all connections are made to IP addresses + LogPrint(eLogError, "NTCP2: Tried to connect to domain name via socks proxy"); + return; } - htobe16buf(buff->data () + sz, port); - sz += 2; - boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff->data (), sz), boost::asio::transfer_all(), - [](const boost::system::error_code & ec, std::size_t written) - { + htobe16buf(buff->data () + sz - 2, port); + boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff->data (), sz), boost::asio::transfer_all(), + [buff](const boost::system::error_code & ec, std::size_t written) + { if(ec) { LogPrint(eLogError, "NTCP2: failed to write handshake to socks proxy ", ec.message()); @@ -1628,9 +1616,9 @@ namespace transport } }); - boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 10), - [timer, conn, sz, readbuff](const boost::system::error_code & e, std::size_t transferred) - { + boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 10), + [timer, conn, sz, readbuff](const boost::system::error_code & e, std::size_t transferred) + { if(e) { LogPrint(eLogError, "NTCP2: socks proxy read error ", e.message()); @@ -1650,6 +1638,5 @@ namespace transport conn->Terminate(); }); } - } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 11ae5995..10170fda 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -274,7 +274,7 @@ namespace transport std::map > m_NTCP2Sessions; std::list > m_PendingIncomingSessions; - ProxyType m_ProxyType =eNoProxy; + ProxyType m_ProxyType; std::string m_ProxyAddress; uint16_t m_ProxyPort; boost::asio::ip::tcp::resolver m_Resolver; diff --git a/libi2pd/NTCPSession.cpp b/libi2pd/NTCPSession.cpp index 9711ffb0..ae94553c 100644 --- a/libi2pd/NTCPSession.cpp +++ b/libi2pd/NTCPSession.cpp @@ -1193,7 +1193,6 @@ namespace transport void NTCPServer::AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) { - // build request size_t sz = 0; uint8_t buff[256]; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 804f26cb..bb74e2ad 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -176,7 +176,7 @@ namespace transport if (proxyurl.schema == "http") proxytype = NTCPServer::eHTTPProxy; - m_NTCPServer->UseProxy(proxytype, proxyurl.host, proxyurl.port) ; + m_NTCPServer->UseProxy(proxytype, proxyurl.host, proxyurl.port); m_NTCPServer->Start(); if(!m_NTCPServer->NetworkIsReady()) { @@ -194,7 +194,7 @@ namespace transport return; } // create NTCP2. TODO: move to acceptor - bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); + bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) { if(!ntcp2proxy.empty()) @@ -209,7 +209,7 @@ namespace transport if (proxyurl.schema == "http") proxytype = NTCP2Server::eHTTPProxy; - m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port) ; + m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port); m_NTCP2Server->Start(); } else @@ -424,36 +424,36 @@ namespace transport { if (peer.router) // we have RI already { - if (!peer.numAttempts) // NTCP2 - { - peer.numAttempts++; - if (m_NTCP2Server) // we support NTCP2 - { - // NTCP2 have priority over NTCP - auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only - if (address) - { - auto s = std::make_shared (*m_NTCP2Server, peer.router); - - if(m_NTCP2Server->UsingProxy()) - { - NTCP2Server::RemoteAddressType remote = NTCP2Server::eIP4Address; - std::string addr = address->host.to_string(); - - if(address->host.is_v6()) - remote = NTCP2Server::eIP6Address; - - m_NTCP2Server->ConnectWithProxy(addr, address->port, remote, s); - } - else - m_NTCP2Server->Connect (address->host, address->port, s); - return true; - } - } - } + if (!peer.numAttempts) // NTCP2 + { + peer.numAttempts++; + if (m_NTCP2Server) // we support NTCP2 + { + // NTCP2 have priority over NTCP + auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only + if (address) + { + auto s = std::make_shared (*m_NTCP2Server, peer.router); + + if(m_NTCP2Server->UsingProxy()) + { + NTCP2Server::RemoteAddressType remote = NTCP2Server::eIP4Address; + std::string addr = address->host.to_string(); + + if(address->host.is_v6()) + remote = NTCP2Server::eIP6Address; + + m_NTCP2Server->ConnectWithProxy(addr, address->port, remote, s); + } + else + m_NTCP2Server->Connect (address->host, address->port, s); + return true; + } + } + } if (peer.numAttempts == 1) // NTCP1 { - peer.numAttempts++; + peer.numAttempts++; auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); if (address && m_NTCPServer) { diff --git a/libi2pd_client/SOCKS.cpp b/libi2pd_client/SOCKS.cpp index 9cb69590..a70ac2b7 100644 --- a/libi2pd_client/SOCKS.cpp +++ b/libi2pd_client/SOCKS.cpp @@ -118,7 +118,7 @@ namespace proxy boost::asio::const_buffers_1 GenerateSOCKS5SelectAuth(authMethods method); boost::asio::const_buffers_1 GenerateSOCKS4Response(errTypes error, uint32_t ip, uint16_t port); boost::asio::const_buffers_1 GenerateSOCKS5Response(errTypes error, addrTypes type, const address &addr, uint16_t port); - boost::asio::const_buffers_1 GenerateUpstreamRequest(); + boost::asio::const_buffers_1 GenerateUpstreamRequest(); bool Socks5ChooseAuth(); void SocksRequestFailed(errTypes error); void SocksRequestSuccess(); @@ -128,27 +128,27 @@ namespace proxy void HandleStreamRequestComplete (std::shared_ptr stream); void ForwardSOCKS(); - void SocksUpstreamSuccess(); - void AsyncUpstreamSockRead(); - void SendUpstreamRequest(); + void SocksUpstreamSuccess(); + void AsyncUpstreamSockRead(); + void SendUpstreamRequest(); void HandleUpstreamData(uint8_t * buff, std::size_t len); - void HandleUpstreamSockSend(const boost::system::error_code & ecode, std::size_t bytes_transfered); - void HandleUpstreamSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); - void HandleUpstreamConnected(const boost::system::error_code & ecode, + void HandleUpstreamSockSend(const boost::system::error_code & ecode, std::size_t bytes_transfered); + void HandleUpstreamSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); + void HandleUpstreamConnected(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr); - void HandleUpstreamResolved(const boost::system::error_code & ecode, + void HandleUpstreamResolved(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr); - boost::asio::ip::tcp::resolver m_proxy_resolver; - uint8_t m_sock_buff[socks_buffer_size]; - std::shared_ptr m_sock, m_upstreamSock; + boost::asio::ip::tcp::resolver m_proxy_resolver; + uint8_t m_sock_buff[socks_buffer_size]; + std::shared_ptr m_sock, m_upstreamSock; std::shared_ptr m_stream; uint8_t *m_remaining_data; //Data left to be sent uint8_t *m_remaining_upstream_data; //upstream data left to be forwarded uint8_t m_response[7+max_socks_hostname_size]; - uint8_t m_upstream_response[SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE]; - uint8_t m_upstream_request[14+max_socks_hostname_size]; - std::size_t m_upstream_response_len; + uint8_t m_upstream_response[SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE]; + uint8_t m_upstream_request[14+max_socks_hostname_size]; + std::size_t m_upstream_response_len; address m_address; //Address std::size_t m_remaining_data_len; //Size of the data left to be sent uint32_t m_4aip; //Used in 4a requests @@ -161,11 +161,11 @@ namespace proxy cmdTypes m_cmd; // Command requested state m_state; const bool m_UseUpstreamProxy; // do we want to use the upstream proxy for non i2p addresses? - const std::string m_UpstreamProxyAddress; - const uint16_t m_UpstreamProxyPort; + const std::string m_UpstreamProxyAddress; + const uint16_t m_UpstreamProxyPort; public: - SOCKSHandler(SOCKSServer * parent, std::shared_ptr sock, const std::string & upstreamAddr, const uint16_t upstreamPort, const bool useUpstream) : + SOCKSHandler(SOCKSServer * parent, std::shared_ptr sock, const std::string & upstreamAddr, const uint16_t upstreamPort, const bool useUpstream) : I2PServiceHandler(parent), m_proxy_resolver(parent->GetService()), m_sock(sock), m_stream(nullptr), @@ -226,7 +226,7 @@ namespace proxy boost::asio::const_buffers_1 SOCKSHandler::GenerateSOCKS5Response(SOCKSHandler::errTypes error, SOCKSHandler::addrTypes type, const SOCKSHandler::address &addr, uint16_t port) { - size_t size = 6; + size_t size = 6; // header + port assert(error <= SOCKS5_ADDR_UNSUP); m_response[0] = '\x05'; //Version m_response[1] = error; //Response code @@ -235,15 +235,15 @@ namespace proxy switch (type) { case ADDR_IPV4: - size = 10; + size += 4; htobe32buf(m_response + 4, addr.ip); break; case ADDR_IPV6: - size = 22; + size += 16; memcpy(m_response + 4, addr.ipv6, 16); break; case ADDR_DNS: - size = 7 + addr.dns.size; + size += (1 + addr.dns.size); /* name length + domain name */ m_response[4] = addr.dns.size; memcpy(m_response + 5, addr.dns.value, addr.dns.size); // replace type to IPv4 for support socks5 clients