diff --git a/Makefile b/Makefile index b5739c46..d9d9b4c9 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,8 @@ CFLAGS = -g -Wall -std=c++0x OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \ obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \ obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \ - obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o + obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o \ + obj/UPnP.o INCFLAGS = LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LIBS = diff --git a/RouterContext.cpp b/RouterContext.cpp index 768b92a3..1d3d2c02 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -43,7 +43,7 @@ namespace i2p void RouterContext::OverrideNTCPAddress (const char * host, int port) { m_RouterInfo.CreateBuffer (); - auto address = m_RouterInfo.GetNTCPAddress (); + auto address = const_cast(m_RouterInfo.GetNTCPAddress ()); if (address) { address->host = boost::asio::ip::address::from_string (host); diff --git a/RouterInfo.cpp b/RouterInfo.cpp index f4668921..e1ae0a2d 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -303,17 +303,17 @@ namespace data return m_SupportedTransports & (eSSUV4 | eSSUV6); } - RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) + const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const { return GetAddress (eTransportNTCP, v4only); } - RouterInfo::Address * RouterInfo::GetSSUAddress (bool v4only) + const RouterInfo::Address * RouterInfo::GetSSUAddress (bool v4only) const { return GetAddress (eTransportSSU, v4only); } - RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only) + const RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only) const { for (auto& address : m_Addresses) { diff --git a/RouterInfo.h b/RouterInfo.h index 3b28fee7..3c08d8d1 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -54,8 +54,8 @@ namespace data const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; }; uint64_t GetTimestamp () const { return m_Timestamp; }; std::vector
& GetAddresses () { return m_Addresses; }; - Address * GetNTCPAddress (bool v4only = true); - Address * GetSSUAddress (bool v4only = true); + const Address * GetNTCPAddress (bool v4only = true) const; + const Address * GetSSUAddress (bool v4only = true) const; const RoutingKey& GetRoutingKey () const { return m_RoutingKey; }; void AddNTCPAddress (const char * host, int port); @@ -91,7 +91,7 @@ namespace data size_t ReadString (char * str, std::istream& s); void WriteString (const std::string& str, std::ostream& s); void UpdateIdentHashBase64 (); - Address * GetAddress (TransportStyle s, bool v4only); + const Address * GetAddress (TransportStyle s, bool v4only) const; private: diff --git a/SSU.cpp b/SSU.cpp index 57ebdce9..c0715d9e 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -14,8 +14,8 @@ namespace i2p namespace ssu { - SSUSession::SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint, - i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint), + SSUSession::SSUSession (SSUServer * server, boost::asio::ip::udp::endpoint& remoteEndpoint, + const i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router), m_State (eSessionStateUnknown) { } @@ -273,7 +273,7 @@ namespace ssu m_Server->Send (buf, 480, m_RemoteEndpoint); } - bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len) + bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, const i2p::data::RouterInfo& r, uint8_t * buf, size_t len) { auto address = r.GetSSUAddress (); if (address) @@ -299,7 +299,8 @@ namespace ssu return false; } - void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey) + void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, + const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey) { if (len < sizeof (SSUHeader)) { @@ -320,7 +321,7 @@ namespace ssu i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, header->mac); } - void SSUSession::Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey) + void SSUSession::Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey) { if (len < sizeof (SSUHeader)) { @@ -335,7 +336,7 @@ namespace ssu m_Decryption.ProcessData (encrypted, encrypted, encryptedLen); } - bool SSUSession::Validate (uint8_t * buf, size_t len, uint8_t * macKey) + bool SSUSession::Validate (uint8_t * buf, size_t len, const uint8_t * macKey) { if (len < sizeof (SSUHeader)) { @@ -535,7 +536,7 @@ namespace ssu LogPrint ("SSU receive error: ", ecode.message ()); } - SSUSession * SSUServer::GetSession (i2p::data::RouterInfo * router) + SSUSession * SSUServer::GetSession (const i2p::data::RouterInfo * router) { SSUSession * session = nullptr; if (router) diff --git a/SSU.h b/SSU.h index 15467262..fd2b8304 100644 --- a/SSU.h +++ b/SSU.h @@ -62,8 +62,8 @@ namespace ssu { public: - SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint, - i2p::data::RouterInfo * router = nullptr); + SSUSession (SSUServer * server, boost::asio::ip::udp::endpoint& remoteEndpoint, + const i2p::data::RouterInfo * router = nullptr); void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void Connect (); @@ -86,16 +86,16 @@ namespace ssu void SendMsgAck (uint32_t msgID); void SendSesionDestroyed (); - bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len); - void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); - void Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey); - bool Validate (uint8_t * buf, size_t len, uint8_t * macKey); + bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, const i2p::data::RouterInfo& r, uint8_t * buf, size_t len); + void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey); + void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey); + bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey); private: SSUServer * m_Server; boost::asio::ip::udp::endpoint m_RemoteEndpoint; - i2p::data::RouterInfo * m_RemoteRouter; + const i2p::data::RouterInfo * m_RemoteRouter; SessionState m_State; CryptoPP::CBC_Mode::Encryption m_Encryption; CryptoPP::CBC_Mode::Decryption m_Decryption; @@ -111,7 +111,7 @@ namespace ssu ~SSUServer (); void Start (); void Stop (); - SSUSession * GetSession (i2p::data::RouterInfo * router); + SSUSession * GetSession (const i2p::data::RouterInfo * router); void DeleteSession (SSUSession * session); void DeleteAllSessions (); diff --git a/Transports.cpp b/Transports.cpp index 8ea6c05f..dc76b35c 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -55,8 +55,7 @@ namespace i2p } } - // TODO: do it for SSU only - DetectExternalIP (); + //DetectExternalIP (); } void Transports::Stop () @@ -189,7 +188,7 @@ namespace i2p { auto router = i2p::data::netdb.GetRandomRouter (); if (router && router->IsSSU () && m_SSUServer) - m_SSUServer->GetSession (const_cast(router)); //TODO + m_SSUServer->GetSession (router); } if (m_Timer) { diff --git a/UPnP.cpp b/UPnP.cpp new file mode 100644 index 00000000..ebadc80f --- /dev/null +++ b/UPnP.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include "Log.h" +#include "UPnP.h" + +namespace i2p +{ + UPnP::UPnP (): m_Timer (m_Service), + m_Endpoint (boost::asio::ip::udp::v4 (), UPNP_REPLY_PORT), + m_MulticastEndpoint (boost::asio::ip::address::from_string (UPNP_GROUP), UPNP_PORT), + m_Socket (m_Service, m_Endpoint.protocol ()) + { + m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (65535)); + m_Socket.set_option (boost::asio::socket_base::send_buffer_size (65535)); + m_Socket.set_option(boost::asio::ip::udp::socket::reuse_address(true)); + } + + UPnP::~UPnP () + { + } + + void UPnP::Run () + { + DiscoverRouter (); + m_Service.run (); + } + + void UPnP::DiscoverRouter () + { + m_Timer.expires_from_now (boost::posix_time::seconds(5)); // 5 seconds + m_Timer.async_wait (boost::bind (&UPnP::HandleTimer, this, boost::asio::placeholders::error)); + + std::string address = UPNP_GROUP; + address += ":" + boost::lexical_cast(UPNP_PORT); + std::string request = "M-SEARCH * HTTP/1.1\r\n" + "HOST: " + address + "\r\n" + "ST:" + UPNP_ROUTER + "\r\n" + "MAN:\"ssdp:discover\"\r\n" + "MX:3\r\n" + "\r\n\r\n"; + m_Socket.send_to (boost::asio::buffer (request.c_str (), request.length ()), m_MulticastEndpoint); + Receive (); + } + + void UPnP::Receive () + { + m_Socket.async_receive_from (boost::asio::buffer (m_ReceiveBuffer, UPNP_MAX_PACKET_LEN), m_SenderEndpoint, + boost::bind (&UPnP::HandleReceivedFrom, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + + void UPnP::HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred) + { + LogPrint ("UPnP: ", bytes_transferred, " received from ", m_SenderEndpoint.address ()); + std::string str (m_ReceiveBuffer, bytes_transferred); + LogPrint (str); + m_Timer.cancel (); + } + + void UPnP::HandleTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint ("UPnP: timeout expired"); + m_Service.stop (); + } + } +} diff --git a/UPnP.h b/UPnP.h new file mode 100644 index 00000000..3b5122d1 --- /dev/null +++ b/UPnP.h @@ -0,0 +1,41 @@ +#ifndef UPNP_H__ +#define UPNP_H__ + +#include + +namespace i2p +{ + const int UPNP_MAX_PACKET_LEN = 1500; + const char UPNP_GROUP[] = "239.255.255.250"; + const int UPNP_PORT = 1900; + const int UPNP_REPLY_PORT = 1901; + const char UPNP_ROUTER[] = "urn:schemas-upnp-org:device:InternetGatewayDevice:1"; + + class UPnP + { + public: + + UPnP (); + ~UPnP (); + + void Run (); + + + private: + + void DiscoverRouter (); + void Receive (); + void HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred); + void HandleTimer (const boost::system::error_code& ecode); + + private: + + boost::asio::io_service m_Service; + boost::asio::deadline_timer m_Timer; + boost::asio::ip::udp::endpoint m_Endpoint, m_MulticastEndpoint, m_SenderEndpoint; + boost::asio::ip::udp::socket m_Socket; + char m_ReceiveBuffer[UPNP_MAX_PACKET_LEN]; + }; +} + +#endif diff --git a/hmac.h b/hmac.h index 6e9c042b..971b9f1a 100644 --- a/hmac.h +++ b/hmac.h @@ -13,7 +13,7 @@ namespace crypto const uint64_t IPAD = 0x3636363636363636; const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C; - inline void HMACMD5Digest (uint8_t * msg, size_t len, uint8_t * key, uint8_t * digest) + inline void HMACMD5Digest (uint8_t * msg, size_t len, const uint8_t * key, uint8_t * digest) // key is 32 bytes // digest is 16 bytes // block size is 64 bytes