diff --git a/ClientContext.cpp b/ClientContext.cpp index 3b814260..e89e7eb7 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -404,17 +404,19 @@ namespace client } if (type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) { // udp client - // TODO: ip6 and hostnames + // TODO: hostnames boost::asio::ip::udp::endpoint end(boost::asio::ip::address::from_string(address), port); - if (!localDestination) { + if (!localDestination) + { localDestination = m_SharedLocalDestination; } auto clientTunnel = new I2PUDPClientTunnel(name, dest, end, localDestination, destinationPort); - if(m_ClientForwards.insert(std::make_pair(end, std::unique_ptr(clientTunnel))).second) { + if(m_ClientForwards.insert(std::make_pair(end, std::unique_ptr(clientTunnel))).second) + { clientTunnel->Start(); - } else { - LogPrint(eLogError, "Clients: I2P Client forward for endpoint ", end, " already exists"); } + else + LogPrint(eLogError, "Clients: I2P Client forward for endpoint ", end, " already exists"); } else { // tcp client @@ -443,7 +445,8 @@ namespace client bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true); i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN); - + std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); + // I2CP std::map options; ReadI2CPOptions (section, options); @@ -455,22 +458,26 @@ namespace client localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ()); if (!localDestination) localDestination = CreateNewLocalDestination (k, true, &options); - if (type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER) { + if (type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER) + { // udp server tunnel - // TODO: ipv6 and hostnames + // TODO: hostnames + auto localAddress = boost::asio::ip::address::from_string(address); boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port); - I2PUDPServerTunnel * serverTunnel = new I2PUDPServerTunnel(name, localDestination, endpoint, port); + I2PUDPServerTunnel * serverTunnel = new I2PUDPServerTunnel(name, localDestination, localAddress, endpoint, port); std::lock_guard lock(m_ForwardsMutex); if(m_ServerForwards.insert( std::make_pair( std::make_pair( localDestination->GetIdentHash(), port), - std::unique_ptr(serverTunnel))).second) { + std::unique_ptr(serverTunnel))).second) + { serverTunnel->Start(); - LogPrint(eLogInfo, "Clients: I2P Server Forward created for UDP Endpoint ", host, ":", port, " via ",localDestination->GetIdentHash().ToBase32()); - } else { - LogPrint(eLogError, "Clients: I2P Server Forward for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash()), "/", port, "already exists"); + LogPrint(eLogInfo, "Clients: I2P Server Forward created for UDP Endpoint ", host, ":", port, " bound on ", address, " for ",localDestination->GetIdentHash().ToBase32()); } + else + LogPrint(eLogError, "Clients: I2P Server Forward for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash()), "/", port, "already exists"); + continue; } diff --git a/ClientContext.h b/ClientContext.h index 5a054f29..0ff7993f 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -41,7 +41,8 @@ namespace client const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist"; const char I2P_SERVER_TUNNEL_GZIP[] = "gzip"; const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword"; - + const char I2P_SERVER_TUNNEL_ADDRESS[] = "address"; + class ClientContext { public: diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index 6cc21e85..db8831be 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -532,7 +532,7 @@ namespace client { std::lock_guard lock(m_SessionsMutex); auto session = ObtainUDPSession(from, toPort, fromPort); - session->IPSocket.send_to(boost::asio::buffer(buf, len), m_Endpoint); + session->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint); session->LastActivity = i2p::util::GetMillisecondsSinceEpoch(); } @@ -548,20 +548,25 @@ namespace client UDPSession * I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort) { auto ih = from.GetIdentHash(); - for ( UDPSession * s : m_Sessions ) { - if ( s->Identity == ih) { - /** found existing */ + for ( UDPSession * s : m_Sessions ) + { + if ( s->Identity == ih) + { + /** found existing session */ LogPrint(eLogDebug, "UDPServer: found session ", s->IPSocket.local_endpoint(), " ", ih.ToBase32()); return s; } } - /** create new */ - boost::asio::ip::udp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"), 0); - m_Sessions.push_back(new UDPSession(ep, m_LocalDest, m_Endpoint, ih, localPort, remotePort)); + /** create new udp session */ + boost::asio::ip::udp::endpoint ep(m_LocalAddress, 0); + m_Sessions.push_back(new UDPSession(ep, m_LocalDest, m_RemoteEndpoint, ih, localPort, remotePort)); return m_Sessions.back(); } - UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint, const std::shared_ptr & localDestination, boost::asio::ip::udp::endpoint endpoint, const i2p::data::IdentHash to, uint16_t ourPort, uint16_t theirPort) : + UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint, + const std::shared_ptr & localDestination, + boost::asio::ip::udp::endpoint endpoint, const i2p::data::IdentHash to, + uint16_t ourPort, uint16_t theirPort) : m_Destination(localDestination->GetDatagramDestination()), m_Service(localDestination->GetService()), IPSocket(localDestination->GetService(), localEndpoint), @@ -577,18 +582,20 @@ namespace client void UDPSession::Receive() { LogPrint(eLogDebug, "UDPSession: Receive"); - IPSocket.async_receive_from(boost::asio::buffer(m_Buffer, I2P_UDP_MAX_MTU), FromEndpoint, std::bind(&UDPSession::HandleReceived, this, std::placeholders::_1, std::placeholders::_2)); + IPSocket.async_receive_from(boost::asio::buffer(m_Buffer, I2P_UDP_MAX_MTU), + FromEndpoint, std::bind(&UDPSession::HandleReceived, this, std::placeholders::_1, std::placeholders::_2)); } void UDPSession::HandleReceived(const boost::system::error_code & ecode, std::size_t len) { - if(!ecode) { + if(!ecode) + { LogPrint(eLogDebug, "UDPSession: forward ", len, "B from ", FromEndpoint); LastActivity = i2p::util::GetMillisecondsSinceEpoch(); uint8_t * data = new uint8_t[len]; memcpy(data, m_Buffer, len); m_Service.post([&,len, data] () { - m_Destination->SendDatagramTo(data, len, Identity, 0, 0); + m_Destination->SendDatagramTo(data, len, Identity, 0, 0); delete [] data; }); @@ -600,9 +607,12 @@ namespace client - I2PUDPServerTunnel::I2PUDPServerTunnel(const std::string & name, std::shared_ptr localDestination, boost::asio::ip::udp::endpoint forwardTo, uint16_t port) : + I2PUDPServerTunnel::I2PUDPServerTunnel(const std::string & name, std::shared_ptr localDestination, + const boost::asio::ip::address& localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port) : + m_LocalAddress(localAddress), + m_Name(name), LocalPort(port), - m_Endpoint(forwardTo) + m_RemoteEndpoint(forwardTo) { m_LocalDest = localDestination; m_LocalDest->Start(); @@ -613,9 +623,8 @@ namespace client I2PUDPServerTunnel::~I2PUDPServerTunnel() { auto dgram = m_LocalDest->GetDatagramDestination(); - if (dgram) { - dgram->ResetReceiver(); - } + if (dgram) dgram->ResetReceiver(); + LogPrint(eLogInfo, "UDPServer: done"); } @@ -623,7 +632,11 @@ namespace client m_LocalDest->Start(); } - I2PUDPClientTunnel::I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest, boost::asio::ip::udp::endpoint localEndpoint, std::shared_ptr localDestination, uint16_t remotePort) : + I2PUDPClientTunnel::I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest, + boost::asio::ip::udp::endpoint localEndpoint, + std::shared_ptr localDestination, + uint16_t remotePort) : + m_Name(name), m_Session(nullptr), m_RemoteDest(remoteDest), m_RemoteIdent(nullptr), @@ -654,50 +667,57 @@ namespace client m_RemoteIdent = new i2p::data::IdentHash; m_RemoteIdent->Fill(0); - while(!context.GetAddressBook().GetIdentHash(m_RemoteDest, *m_RemoteIdent) && !m_cancel_resolve) { + while(!context.GetAddressBook().GetIdentHash(m_RemoteDest, *m_RemoteIdent) && !m_cancel_resolve) + { LogPrint(eLogWarning, "UDP Tunnel: failed to lookup ", m_RemoteDest); std::this_thread::sleep_for(std::chrono::seconds(1)); } - if(m_cancel_resolve) { + if(m_cancel_resolve) + { LogPrint(eLogError, "UDP Tunnel: lookup of ", m_RemoteDest, " was cancelled"); return; } LogPrint(eLogInfo, "UDP Tunnel: resolved ", m_RemoteDest, " to ", m_RemoteIdent->ToBase32()); // delete existing session if(m_Session) delete m_Session; + boost::asio::ip::udp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"), 0); m_Session = new UDPSession(m_LocalEndpoint, m_LocalDest, ep, *m_RemoteIdent, LocalPort, RemotePort); } void I2PUDPClientTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) { - if(m_RemoteIdent && from.GetIdentHash() == *m_RemoteIdent) { + if(m_RemoteIdent && from.GetIdentHash() == *m_RemoteIdent) + { // address match - if(m_Session) { + if(m_Session) + { // tell session LogPrint(eLogDebug, "UDP Client: got ", len, "B from ", from.GetIdentHash().ToBase32()); m_Session->IPSocket.send_to(boost::asio::buffer(buf, len), m_Session->FromEndpoint); - } else { - LogPrint(eLogWarning, "UDP Client: no session"); } - } else { - LogPrint(eLogWarning, "UDP Client: unwarrented traffic from ", from.GetIdentHash().ToBase32()); + else + LogPrint(eLogWarning, "UDP Client: no session"); } + else + LogPrint(eLogWarning, "UDP Client: unwarrented traffic from ", from.GetIdentHash().ToBase32()); + } - + I2PUDPClientTunnel::~I2PUDPClientTunnel() { auto dgram = m_LocalDest->GetDatagramDestination(); - if (dgram) { - dgram->ResetReceiver(); - } + if (dgram) dgram->ResetReceiver(); + if (m_Session) delete m_Session; m_cancel_resolve = true; - if(m_ResolveThread) { + + if(m_ResolveThread) + { m_ResolveThread->join(); delete m_ResolveThread; m_ResolveThread = nullptr; } if (m_RemoteIdent) delete m_RemoteIdent; } -} -} +} +} diff --git a/I2PTunnel.h b/I2PTunnel.h index 63341679..76bfc36b 100644 --- a/I2PTunnel.h +++ b/I2PTunnel.h @@ -132,74 +132,86 @@ namespace client }; - /** 2 minute timeout for udp sessions */ - const uint64_t I2P_UDP_SESSION_TIMEOUT = 1000 * 60 * 2; - - /** max size for i2p udp */ - const size_t I2P_UDP_MAX_MTU = i2p::datagram::MAX_DATAGRAM_SIZE; - - struct UDPSession - { - i2p::datagram::DatagramDestination * m_Destination; - boost::asio::io_service & m_Service; - boost::asio::ip::udp::socket IPSocket; - i2p::data::IdentHash Identity; - boost::asio::ip::udp::endpoint FromEndpoint; - boost::asio::ip::udp::endpoint SendEndpoint; - uint64_t LastActivity; - - uint16_t LocalPort; - uint16_t RemotePort; - - uint8_t m_Buffer[I2P_UDP_MAX_MTU]; - - UDPSession(boost::asio::ip::udp::endpoint localEndpoint, const std::shared_ptr & localDestination, boost::asio::ip::udp::endpoint remote, const i2p::data::IdentHash ident, uint16_t ourPort, uint16_t theirPort); - - void HandleReceived(const boost::system::error_code & ecode, std::size_t len); - void Receive(); - }; - - /** server side udp tunnel, many i2p inbound to 1 ip outbound */ - class I2PUDPServerTunnel - { - public: - I2PUDPServerTunnel(const std::string & name, std::shared_ptr localDestination, boost::asio::ip::udp::endpoint forwardTo, uint16_t port); - ~I2PUDPServerTunnel(); - /** expire stale udp conversations */ - void ExpireStale(const uint64_t delta=I2P_UDP_SESSION_TIMEOUT); - void Start(); - private: - void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); - UDPSession * ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort); - private: - const uint16_t LocalPort; - boost::asio::ip::udp::endpoint m_Endpoint; - std::mutex m_SessionsMutex; - std::vector m_Sessions; - std::shared_ptr m_LocalDest; - uint8_t m_Buffer[I2P_UDP_MAX_MTU]; - }; - - class I2PUDPClientTunnel - { - public: - I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest, boost::asio::ip::udp::endpoint localEndpoint, std::shared_ptr localDestination, uint16_t remotePort); - ~I2PUDPClientTunnel(); - void Start(); - private: - void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); - void TryResolving(); - UDPSession * m_Session; - const std::string m_RemoteDest; - std::shared_ptr m_LocalDest; - const boost::asio::ip::udp::endpoint m_LocalEndpoint; - i2p::data::IdentHash * m_RemoteIdent; - std::thread * m_ResolveThread; - uint16_t LocalPort; - uint16_t RemotePort; - bool m_cancel_resolve; - }; - + /** 2 minute timeout for udp sessions */ + const uint64_t I2P_UDP_SESSION_TIMEOUT = 1000 * 60 * 2; + + /** max size for i2p udp */ + const size_t I2P_UDP_MAX_MTU = i2p::datagram::MAX_DATAGRAM_SIZE; + + struct UDPSession + { + i2p::datagram::DatagramDestination * m_Destination; + boost::asio::io_service & m_Service; + boost::asio::ip::udp::socket IPSocket; + i2p::data::IdentHash Identity; + boost::asio::ip::udp::endpoint FromEndpoint; + boost::asio::ip::udp::endpoint SendEndpoint; + uint64_t LastActivity; + + uint16_t LocalPort; + uint16_t RemotePort; + + uint8_t m_Buffer[I2P_UDP_MAX_MTU]; + + UDPSession(boost::asio::ip::udp::endpoint localEndpoint, + const std::shared_ptr & localDestination, + boost::asio::ip::udp::endpoint remote, const i2p::data::IdentHash ident, + uint16_t ourPort, uint16_t theirPort); + void HandleReceived(const boost::system::error_code & ecode, std::size_t len); + void Receive(); + }; + + /** server side udp tunnel, many i2p inbound to 1 ip outbound */ + class I2PUDPServerTunnel + { + public: + I2PUDPServerTunnel(const std::string & name, + std::shared_ptr localDestination, + const boost::asio::ip::address & localAddress, + boost::asio::ip::udp::endpoint forwardTo, uint16_t port); + ~I2PUDPServerTunnel(); + /** expire stale udp conversations */ + void ExpireStale(const uint64_t delta=I2P_UDP_SESSION_TIMEOUT); + void Start(); + const char * GetName() const { return m_Name.c_str(); } + private: + void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + UDPSession * ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort); + private: + const std::string m_Name; + const uint16_t LocalPort; + boost::asio::ip::address m_LocalAddress; + boost::asio::ip::udp::endpoint m_RemoteEndpoint; + std::mutex m_SessionsMutex; + std::vector m_Sessions; + std::shared_ptr m_LocalDest; + }; + + class I2PUDPClientTunnel + { + public: + I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest, + boost::asio::ip::udp::endpoint localEndpoint, std::shared_ptr localDestination, + uint16_t remotePort); + ~I2PUDPClientTunnel(); + void Start(); + const char * GetName() const { return m_Name.c_str(); } + + private: + void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + void TryResolving(); + const std::string m_Name; + UDPSession * m_Session; + const std::string m_RemoteDest; + std::shared_ptr m_LocalDest; + const boost::asio::ip::udp::endpoint m_LocalEndpoint; + i2p::data::IdentHash * m_RemoteIdent; + std::thread * m_ResolveThread; + uint16_t LocalPort; + uint16_t RemotePort; + bool m_cancel_resolve; + }; + class I2PServerTunnel: public I2PService { public: