From 59e081f41e40cb981a359fef22bf9d4e91c6d5a7 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Thu, 30 Jul 2015 22:06:42 +0200 Subject: [PATCH 01/18] Fix typo "Chipher" -> "Cipher" --- crypto/aes.cpp | 18 +++++++++--------- crypto/aes.h | 20 ++++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/crypto/aes.cpp b/crypto/aes.cpp index a4fee883..ef388976 100644 --- a/crypto/aes.cpp +++ b/crypto/aes.cpp @@ -45,7 +45,7 @@ void ECBCryptoAESNI::ExpandKey (const AESKey& key) ); } -void ECBEncryptionAESNI::Encrypt (const ChipherBlock * in, ChipherBlock * out) +void ECBEncryptionAESNI::Encrypt (const CipherBlock * in, CipherBlock * out) { __asm__ ( @@ -57,7 +57,7 @@ void ECBEncryptionAESNI::Encrypt (const ChipherBlock * in, ChipherBlock * out) } -void ECBDecryptionAESNI::Decrypt (const ChipherBlock * in, ChipherBlock * out) +void ECBDecryptionAESNI::Decrypt (const CipherBlock * in, CipherBlock * out) { __asm__ ( @@ -94,7 +94,7 @@ void ECBDecryptionAESNI::SetKey (const AESKey& key) #endif -void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) +void CBCEncryption::Encrypt (int numBlocks, const CipherBlock * in, CipherBlock * out) { #ifdef AESNI __asm__ @@ -131,7 +131,7 @@ void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out) // len/16 int numBlocks = len >> 4; if (numBlocks > 0) - Encrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out); + Encrypt (numBlocks, (const CipherBlock *)in, (CipherBlock *)out); } void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out) @@ -151,11 +151,11 @@ void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out) : "%xmm0", "%xmm1", "memory" ); #else - Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); + Encrypt (1, (const CipherBlock *)in, (CipherBlock *)out); #endif } -void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) +void CBCDecryption::Decrypt (int numBlocks, const CipherBlock * in, CipherBlock * out) { #ifdef AESNI __asm__ @@ -181,7 +181,7 @@ void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBloc #else for (int i = 0; i < numBlocks; i++) { - ChipherBlock tmp = in[i]; + CipherBlock tmp = in[i]; m_ECBDecryption.Decrypt (in + i, out + i); out[i] ^= m_IV; m_IV = tmp; @@ -193,7 +193,7 @@ void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out) { int numBlocks = len >> 4; if (numBlocks > 0) - Decrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out); + Decrypt (numBlocks, (const CipherBlock *)in, (CipherBlock *)out); } void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out) @@ -213,7 +213,7 @@ void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out) : "%xmm0", "%xmm1", "memory" ); #else - Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); + Decrypt (1, (const CipherBlock *)in, (CipherBlock *)out); #endif } diff --git a/crypto/aes.h b/crypto/aes.h index 6e763125..fa46ceaf 100644 --- a/crypto/aes.h +++ b/crypto/aes.h @@ -10,11 +10,11 @@ namespace i2p { namespace crypto { - struct ChipherBlock + struct CipherBlock { uint8_t buf[16]; - void operator^=(const ChipherBlock& other) // XOR + void operator^=(const CipherBlock& other) // XOR { #if defined(__x86_64__) // for Intel x64 __asm__ @@ -81,7 +81,7 @@ namespace crypto public: void SetKey (const AESKey& key) { ExpandKey (key); }; - void Encrypt (const ChipherBlock * in, ChipherBlock * out); + void Encrypt (const CipherBlock * in, CipherBlock * out); }; class ECBDecryptionAESNI: public ECBCryptoAESNI @@ -89,7 +89,7 @@ namespace crypto public: void SetKey (const AESKey& key); - void Decrypt (const ChipherBlock * in, ChipherBlock * out); + void Decrypt (const CipherBlock * in, CipherBlock * out); }; typedef ECBEncryptionAESNI ECBEncryption; @@ -105,7 +105,7 @@ namespace crypto { m_Encryption.SetKey (key, 32); } - void Encrypt (const ChipherBlock * in, ChipherBlock * out) + void Encrypt (const CipherBlock * in, CipherBlock * out) { m_Encryption.ProcessData (out->buf, in->buf, 16); } @@ -123,7 +123,7 @@ namespace crypto { m_Decryption.SetKey (key, 32); } - void Decrypt (const ChipherBlock * in, ChipherBlock * out) + void Decrypt (const CipherBlock * in, CipherBlock * out) { m_Decryption.ProcessData (out->buf, in->buf, 16); } @@ -151,13 +151,13 @@ namespace crypto void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes void SetIV (const uint8_t * iv) { memcpy (m_LastBlock.buf, iv, 16); }; // 16 bytes - void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); + void Encrypt (int numBlocks, const CipherBlock * in, CipherBlock * out); void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out); void Encrypt (const uint8_t * in, uint8_t * out); // one block private: - ChipherBlock m_LastBlock; + CipherBlock m_LastBlock; ECBEncryption m_ECBEncryption; }; @@ -171,13 +171,13 @@ namespace crypto void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes void SetIV (const uint8_t * iv) { memcpy (m_IV.buf, iv, 16); }; // 16 bytes - void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); + void Decrypt (int numBlocks, const CipherBlock * in, CipherBlock * out); void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out); void Decrypt (const uint8_t * in, uint8_t * out); // one block private: - ChipherBlock m_IV; + CipherBlock m_IV; ECBDecryption m_ECBDecryption; }; From 5d0b24d6961815c4290781b96b1e38d038669aeb Mon Sep 17 00:00:00 2001 From: EinMByte Date: Fri, 31 Jul 2015 13:01:49 +0200 Subject: [PATCH 02/18] Add tests for AES CBC (mainly important for custom AESNI implementation). --- crypto/aes.h | 9 ++- filelist.mk | 2 +- tests/Crypto.cpp | 204 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 tests/Crypto.cpp diff --git a/crypto/aes.h b/crypto/aes.h index fa46ceaf..15e95433 100644 --- a/crypto/aes.h +++ b/crypto/aes.h @@ -146,7 +146,7 @@ namespace crypto { SetKey(key); SetIV(iv); - }; + } void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes void SetIV (const uint8_t * iv) { memcpy (m_LastBlock.buf, iv, 16); }; // 16 bytes @@ -168,6 +168,13 @@ namespace crypto CBCDecryption () { memset (m_IV.buf, 0, 16); }; + CBCDecryption(const AESKey& key, const uint8_t* iv) + : CBCDecryption() + { + SetKey(key); + SetIV(iv); + } + void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes void SetIV (const uint8_t * iv) { memcpy (m_IV.buf, iv, 16); }; // 16 bytes diff --git a/filelist.mk b/filelist.mk index e276c1cc..e7f29f23 100644 --- a/filelist.mk +++ b/filelist.mk @@ -30,4 +30,4 @@ LIB_SRC := $(COMMON_SRC) \ api.cpp TESTS_SRC := $(COMMON_SRC) \ - tests/Utility.cpp tests/Identity.cpp tests/Base64.cpp + tests/Utility.cpp tests/Identity.cpp tests/Base64.cpp tests/Crypto.cpp diff --git a/tests/Crypto.cpp b/tests/Crypto.cpp new file mode 100644 index 00000000..fe6d9ba3 --- /dev/null +++ b/tests/Crypto.cpp @@ -0,0 +1,204 @@ +#define BOOST_TEST_DYN_LINK + +#include +#include "crypto/aes.h" + +using namespace i2p::crypto; + +BOOST_AUTO_TEST_SUITE(CryptographyTests) + +BOOST_AUTO_TEST_CASE(XorZeroCipherBlocks) +{ + CipherBlock block = {}; + block ^= block; + const CipherBlock result = {}; + BOOST_CHECK_EQUAL_COLLECTIONS(result.buf, result.buf + 16, block.buf, block.buf + 16); +} + +BOOST_AUTO_TEST_CASE(XorSelfCipherBlocks) +{ + CipherBlock block = { + 0xc9, 0x4c, 0xaf, 0x5, 0x9c, 0x1c, 0x10, 0x1e, 0x20, 0xb3, 0x7e, + 0xcf, 0xf5, 0xbf, 0xf0, 0xd6 + }; + block ^= block; + const CipherBlock result = {}; + BOOST_CHECK_EQUAL_COLLECTIONS(result.buf, result.buf + 16, block.buf, block.buf + 16); +} + +BOOST_AUTO_TEST_CASE(XorCipherBlocks) +{ + const CipherBlock block1 = { + 0xc9, 0x4c, 0xaf, 0x5, 0x9c, 0x1c, 0x10, 0x1e, 0x20, 0xb3, 0x7e, + 0xcf, 0xf5, 0xbf, 0xf0, 0xd6 + }; + CipherBlock block2 = { + 0x2e, 0xfb, 0x26, 0xa9, 0x90, 0x3b, 0xf7, 0xc8, 0x5c, 0xfe, 0x20, + 0x23, 0x1d, 0xaf, 0x67, 0xac + }; + block2 ^= block1; + const CipherBlock result = { + 0xe7, 0xb7, 0x89, 0xac, 0xc, 0x27, 0xe7, 0xd6, 0x7c, 0x4d, 0x5e, + 0xec, 0xe8, 0x10, 0x97, 0x7a + }; + BOOST_CHECK_EQUAL_COLLECTIONS(block2.buf, block2.buf + 16, result.buf, result.buf + 16); +} + +// NIST test parameters +// see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf +struct AesCbcFixture { + + AesCbcFixture() + : cbc_encrypt(AESKey(key), iv), cbc_decrypt(AESKey(key), iv) {} + + uint8_t key[32] = { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, + 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, + 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, + 0xdf, 0xf4 + }; + + uint8_t iv[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + + CBCEncryption cbc_encrypt; + CBCDecryption cbc_decrypt; + +}; + +BOOST_FIXTURE_TEST_CASE(AesCbcSingleBlockEncrypt, AesCbcFixture) +{ + uint8_t output[16] = {}; + + const uint8_t input[] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, + 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }; + const uint8_t result[] = { + 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, + 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6 + }; + cbc_encrypt.Encrypt(input, output); + + BOOST_CHECK_EQUAL_COLLECTIONS(output, output + 16, result, result + 16); +} + +BOOST_FIXTURE_TEST_CASE(AesCbcSingleBlockDecrypt, AesCbcFixture) +{ + uint8_t output[16] = {}; + + const uint8_t input[] = { + 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, + 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6 + }; + const uint8_t result[] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, + 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }; + cbc_decrypt.Decrypt(input, output); + + BOOST_CHECK_EQUAL_COLLECTIONS(output, output + 16, result, result + 16); +} + +BOOST_FIXTURE_TEST_CASE(AesCbcEncrypt, AesCbcFixture) +{ + CipherBlock output[4] = {}; + + CipherBlock input[4] = {}; + input[0] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, + 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }; + input[1] = { + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, + 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 + }; + input[2] = { + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, + 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef + }; + input[3] = { + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, + 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 + }; + + CipherBlock result[4] = {}; + result[0] = { + 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, + 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6 + }; + result[1] = { + 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, + 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d + }; + result[2] = { + 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, + 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61 + }; + result[3] = { + 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, + 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b + }; + cbc_encrypt.Encrypt(4, input, output); + + for(int i = 0; i < 3; ++i) { + BOOST_CHECK_EQUAL_COLLECTIONS( + output[i].buf, output[i].buf + 16, + result[i].buf, result[i].buf + 16 + ); + } +} + +BOOST_FIXTURE_TEST_CASE(AesCbcDecrypt, AesCbcFixture) +{ + CipherBlock output[4] = {}; + + CipherBlock input[4] = {}; + input[0] = { + 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, + 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6 + }; + input[1] = { + 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, + 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d + }; + input[2] = { + 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, + 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61 + }; + input[3] = { + 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, + 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b + }; + + CipherBlock result[4] = {}; + result[0] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, + 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }; + result[1] = { + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, + 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 + }; + result[2] = { + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, + 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef + }; + result[3] = { + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, + 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 + }; + cbc_decrypt.Decrypt(4, input, output); + + for(int i = 0; i < 3; ++i) { + BOOST_CHECK_EQUAL_COLLECTIONS( + output[i].buf, output[i].buf + 16, + result[i].buf, result[i].buf + 16 + ); + } +} + + +BOOST_AUTO_TEST_SUITE_END() From af4719d6654fee0e034da8c3dc756674247b96c5 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Fri, 31 Jul 2015 13:11:47 +0200 Subject: [PATCH 03/18] Move AESNIMacros.h to crypto/ --- AESNIMacros.h => crypto/AESNIMacros.h | 0 tunnel/TunnelCrypto.cpp | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename AESNIMacros.h => crypto/AESNIMacros.h (100%) diff --git a/AESNIMacros.h b/crypto/AESNIMacros.h similarity index 100% rename from AESNIMacros.h rename to crypto/AESNIMacros.h diff --git a/tunnel/TunnelCrypto.cpp b/tunnel/TunnelCrypto.cpp index 50241a19..834be06d 100644 --- a/tunnel/TunnelCrypto.cpp +++ b/tunnel/TunnelCrypto.cpp @@ -1,6 +1,6 @@ #include "TunnelCrypto.h" #include "TunnelBase.h" -#include "AESNIMacros.h" +#include "crypto/AESNIMacros.h" namespace i2p { namespace crypto { From 1f90b08445953fc0feaca6eaf3812ba7b2f2814d Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sat, 1 Aug 2015 16:48:35 +0200 Subject: [PATCH 04/18] Began separation of i2pcontrol (untested). --- ClientContext.h | 2 +- I2PControl.cpp | 418 -------------------------------- I2PControl.h | 149 ------------ Makefile | 3 + filelist.mk | 6 +- i2pcontrol/I2PControl.cpp | 254 +++++++++++++++++++ i2pcontrol/I2PControl.h | 136 +++++++++++ i2pcontrol/I2PControlServer.cpp | 178 ++++++++++++++ i2pcontrol/I2PControlServer.h | 58 +++++ 9 files changed, 634 insertions(+), 570 deletions(-) delete mode 100644 I2PControl.cpp delete mode 100644 I2PControl.h create mode 100644 i2pcontrol/I2PControl.cpp create mode 100644 i2pcontrol/I2PControl.h create mode 100644 i2pcontrol/I2PControlServer.cpp create mode 100644 i2pcontrol/I2PControlServer.h diff --git a/ClientContext.h b/ClientContext.h index 52a7a0e7..b4d8b35a 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -11,7 +11,7 @@ #include "SAM.h" #include "BOB.h" #include "AddressBook.h" -#include "I2PControl.h" +#include "i2pcontrol/I2PControlServer.h" namespace i2p { diff --git a/I2PControl.cpp b/I2PControl.cpp deleted file mode 100644 index 4e993aa9..00000000 --- a/I2PControl.cpp +++ /dev/null @@ -1,418 +0,0 @@ -// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy -#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 7)) - -#include "I2PControl.h" -#include -#include -#include -#include -#if !GCC47_BOOST149 -#include -#endif -#include "util/Log.h" -#include "NetDb.h" -#include "RouterContext.h" -#include "Daemon.h" -#include "tunnel/Tunnel.h" -#include "util/Timestamp.h" -#include "transport/Transports.h" -#include "version.h" - -namespace i2p -{ -namespace client -{ - I2PControlService::I2PControlService(const std::string& address, int port) - : m_Password(I2P_CONTROL_DEFAULT_PASSWORD), m_IsRunning(false), - m_Thread(nullptr), m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint( - boost::asio::ip::address::from_string(address), port) - ), - m_ShutdownTimer (m_Service) - { - m_MethodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlService::AuthenticateHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlService::EchoHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlService::I2PControlHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlService::RouterInfoHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlService::RouterManagerHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlService::NetworkSettingHandler; - - // RouterInfo - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlService::UptimeHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlService::VersionHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_STATUS] = &I2PControlService::StatusHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS] = &I2PControlService::NetDbKnownPeersHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS] = &I2PControlService::NetDbActivePeersHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_STATUS] = &I2PControlService::NetStatusHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlService::TunnelsParticipatingHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_IB_1S] = &I2PControlService::InboundBandwidth1S ; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_OB_1S] = &I2PControlService::OutboundBandwidth1S ; - - // RouterManager - m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN] = &I2PControlService::ShutdownHandler; - m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL] = &I2PControlService::ShutdownGracefulHandler; - m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlService::ReseedHandler; - } - - I2PControlService::~I2PControlService () - { - Stop (); - } - - void I2PControlService::Start () - { - if (!m_IsRunning) - { - Accept (); - m_IsRunning = true; - m_Thread = new std::thread (std::bind (&I2PControlService::Run, this)); - } - } - - void I2PControlService::Stop () - { - if (m_IsRunning) - { - m_IsRunning = false; - m_Acceptor.cancel (); - m_Service.stop (); - if (m_Thread) - { - m_Thread->join (); - delete m_Thread; - m_Thread = nullptr; - } - } - } - - void I2PControlService::Run () - { - while (m_IsRunning) - { - try - { - m_Service.run (); - } - catch (std::exception& ex) - { - LogPrint (eLogError, "I2PControl: ", ex.what ()); - } - } - } - - void I2PControlService::Accept () - { - auto newSocket = std::make_shared (m_Service); - m_Acceptor.async_accept (*newSocket, std::bind (&I2PControlService::HandleAccept, this, - std::placeholders::_1, newSocket)); - } - - void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) - { - if (ecode != boost::asio::error::operation_aborted) - Accept (); - - if (!ecode) - { - LogPrint (eLogInfo, "New I2PControl request from ", socket->remote_endpoint ()); - std::this_thread::sleep_for (std::chrono::milliseconds(5)); - ReadRequest (socket); - } - else - LogPrint (eLogError, "I2PControl accept error: ", ecode.message ()); - } - - void I2PControlService::ReadRequest (std::shared_ptr socket) - { - auto request = std::make_shared(); - socket->async_read_some ( -#if BOOST_VERSION >= 104900 - boost::asio::buffer (*request), -#else - boost::asio::buffer (request->data (), request->size ()), -#endif - std::bind(&I2PControlService::HandleRequestReceived, this, - std::placeholders::_1, std::placeholders::_2, socket, request)); - } - - void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode, - size_t bytes_transferred, std::shared_ptr socket, - std::shared_ptr buf) - { - if (ecode) - { - LogPrint (eLogError, "I2PControl read error: ", ecode.message ()); - } - else - { - try - { - bool isHtml = !memcmp (buf->data (), "POST", 4); - std::stringstream ss; - ss.write (buf->data (), bytes_transferred); - if (isHtml) - { - std::string header; - while (!ss.eof () && header != "\r") - std::getline(ss, header); - if (ss.eof ()) - { - LogPrint (eLogError, "Malformed I2PControl request. HTTP header expected"); - return; // TODO: - } - } -#if GCC47_BOOST149 - LogPrint (eLogError, "json_read is not supported due bug in boost 1.49 with gcc 4.7"); -#else - boost::property_tree::ptree pt; - boost::property_tree::read_json (ss, pt); - - std::string method = pt.get(I2P_CONTROL_PROPERTY_METHOD); - auto it = m_MethodHandlers.find (method); - if (it != m_MethodHandlers.end ()) - { - std::ostringstream response; - response << "{\"id\":" << pt.get(I2P_CONTROL_PROPERTY_ID) << ",\"result\":{"; - - (this->*(it->second))(pt.get_child (I2P_CONTROL_PROPERTY_PARAMS), response); - response << "},\"jsonrpc\":\"2.0\"}"; - SendResponse (socket, buf, response, isHtml); - } - else - LogPrint (eLogWarning, "Unknown I2PControl method ", method); -#endif - } - catch (std::exception& ex) - { - LogPrint (eLogError, "I2PControl handle request: ", ex.what ()); - } - catch (...) - { - LogPrint (eLogError, "I2PControl handle request unknown exception"); - } - } - } - - void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const - { - ss << "\"" << name << "\":" << value; - } - - void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const - { - ss << "\"" << name << "\":"; - if (value.length () > 0) - ss << "\"" << value << "\""; - else - ss << "null"; - } - - void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, double value) const - { - ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value; - } - - void I2PControlService::SendResponse (std::shared_ptr socket, - 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); - } - 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)); - } - - void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, - std::shared_ptr socket, std::shared_ptr buf) - { - if (ecode) - LogPrint (eLogError, "I2PControl write error: ", ecode.message ()); - socket->close (); - } - -// handlers - - void I2PControlService::AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - int api = params.get (I2P_CONTROL_PARAM_API); - auto password = params.get (I2P_CONTROL_PARAM_PASSWORD); - LogPrint (eLogDebug, "I2PControl Authenticate API=", api, " Password=", password); - if (password != m_Password) - LogPrint (eLogError, "I2PControl Authenticate Invalid password ", password, " expected ", m_Password); - InsertParam (results, I2P_CONTROL_PARAM_API, api); - results << ","; - std::string token = boost::lexical_cast(i2p::util::GetSecondsSinceEpoch ()); - m_Tokens.insert (token); - InsertParam (results, I2P_CONTROL_PARAM_TOKEN, token); - } - - void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - auto echo = params.get (I2P_CONTROL_PARAM_ECHO); - LogPrint (eLogDebug, "I2PControl Echo Echo=", echo); - InsertParam (results, I2P_CONTROL_PARAM_RESULT, echo); - } - - -// I2PControl - - void I2PControlService::I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - LogPrint (eLogDebug, "I2PControl I2PControl"); - for (auto& it: params) - { - LogPrint (eLogDebug, it.first); - auto it1 = m_I2PControlHandlers.find (it.first); - if (it1 != m_I2PControlHandlers.end ()) - (this->*(it1->second))(it.second.data ()); - else - LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it.first); - } - } - -// RouterInfo - - void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - LogPrint (eLogDebug, "I2PControl RouterInfo"); - for (auto it = params.begin (); it != params.end (); it++) - { - if (it != params.begin ()) results << ","; - LogPrint (eLogDebug, it->first); - auto it1 = m_RouterInfoHandlers.find (it->first); - if (it1 != m_RouterInfoHandlers.end ()) - (this->*(it1->second))(results); - else - LogPrint (eLogError, "I2PControl RouterInfo unknown request ", it->first); - } - } - - void I2PControlService::UptimeHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_UPTIME, (int)i2p::context.GetUptime ()*1000); - } - - void I2PControlService::VersionHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_VERSION, VERSION); - } - - void I2PControlService::StatusHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_STATUS, "???"); // TODO: - } - - void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, i2p::data::netdb.GetNumRouters ()); - } - - void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS, (int)i2p::transport::transports.GetPeers ().size ()); - } - - void I2PControlService::NetStatusHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_NET_STATUS, (int)i2p::context.GetStatus ()); - } - - void I2PControlService::TunnelsParticipatingHandler (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING, (int)i2p::tunnel::tunnels.GetTransitTunnels ().size ()); - } - - void I2PControlService::InboundBandwidth1S (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_IB_1S, (double)i2p::transport::transports.GetInBandwidth ()); - } - - void I2PControlService::OutboundBandwidth1S (std::ostringstream& results) - { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_OB_1S, (double)i2p::transport::transports.GetOutBandwidth ()); - } - -// RouterManager - - void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - LogPrint (eLogDebug, "I2PControl RouterManager"); - for (auto it = params.begin (); it != params.end (); it++) - { - if (it != params.begin ()) results << ","; - LogPrint (eLogDebug, it->first); - auto it1 = m_RouterManagerHandlers.find (it->first); - if (it1 != m_RouterManagerHandlers.end ()) - (this->*(it1->second))(results); - else - LogPrint (eLogError, "I2PControl RouterManager unknown request ", it->first); - } - } - - - void I2PControlService::ShutdownHandler (std::ostringstream& results) - { - LogPrint (eLogInfo, "Shutdown requested"); - InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, ""); - m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent - m_ShutdownTimer.async_wait ( - [](const boost::system::error_code& ecode) - { - Daemon.running = 0; - }); - } - - void I2PControlService::ShutdownGracefulHandler (std::ostringstream& results) - { - i2p::context.SetAcceptsTunnels (false); - int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout (); - LogPrint (eLogInfo, "Graceful shutdown requested. Will shutdown after ", timeout, " seconds"); - InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL, ""); - m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second - m_ShutdownTimer.async_wait ( - [](const boost::system::error_code& ecode) - { - Daemon.running = 0; - }); - } - - void I2PControlService::ReseedHandler (std::ostringstream& results) - { - LogPrint (eLogInfo, "Reseed requested"); - InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, ""); - i2p::data::netdb.Reseed (); - } - -// network setting - void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results) - { - LogPrint (eLogDebug, "I2PControl NetworkSetting"); - for (auto it = params.begin (); it != params.end (); it++) - { - if (it != params.begin ()) results << ","; - LogPrint (eLogDebug, it->first); - auto it1 = m_NetworkSettingHandlers.find (it->first); - if (it1 != m_NetworkSettingHandlers.end ()) - (this->*(it1->second))(it->second.data (), results); - else - LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it->first); - } - } - -} -} diff --git a/I2PControl.h b/I2PControl.h deleted file mode 100644 index 9dae9344..00000000 --- a/I2PControl.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef I2P_CONTROL_H__ -#define I2P_CONTROL_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace i2p -{ -namespace client -{ - const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024; - typedef std::array I2PControlBuffer; - - const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie"; - - const char I2P_CONTROL_PROPERTY_ID[] = "id"; - const char I2P_CONTROL_PROPERTY_METHOD[] = "method"; - const char I2P_CONTROL_PROPERTY_PARAMS[] = "params"; - const char I2P_CONTROL_PROPERTY_RESULT[] = "result"; - - // methods - const char I2P_CONTROL_METHOD_AUTHENTICATE[] = "Authenticate"; - const char I2P_CONTROL_METHOD_ECHO[] = "Echo"; - const char I2P_CONTROL_METHOD_I2PCONTROL[] = "I2PControl"; - const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo"; - const char I2P_CONTROL_METHOD_ROUTER_MANAGER[] = "RouterManager"; - const char I2P_CONTROL_METHOD_NETWORK_SETTING[] = "NetworkSetting"; - - // params - const char I2P_CONTROL_PARAM_API[] = "API"; - const char I2P_CONTROL_PARAM_PASSWORD[] = "Password"; - const char I2P_CONTROL_PARAM_TOKEN[] = "Token"; - const char I2P_CONTROL_PARAM_ECHO[] = "Echo"; - const char I2P_CONTROL_PARAM_RESULT[] = "Result"; - - // I2PControl - const char I2P_CONTROL_I2PCONTROL_ADDRESS[] = "i2pcontrol.address"; - const char I2P_CONTROL_I2PCONTROL_PASSWORD[] = "i2pcontrol.password"; - const char I2P_CONTROL_I2PCONTROL_PORT[] = "i2pcontrol.port"; - - // RouterInfo requests - const char I2P_CONTROL_ROUTER_INFO_UPTIME[] = "i2p.router.uptime"; - const char I2P_CONTROL_ROUTER_INFO_VERSION[] = "i2p.router.version"; - const char I2P_CONTROL_ROUTER_INFO_STATUS[] = "i2p.router.status"; - const char I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers"; - const char I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS[] = "i2p.router.netdb.activepeers"; - const char I2P_CONTROL_ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status"; - const char I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating"; - const char I2P_CONTROL_ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s"; - const char I2P_CONTROL_ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s"; - - // RouterManager requests - const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN[] = "Shutdown"; - const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful"; - const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed"; - - class I2PControlService - { - public: - - I2PControlService(const std::string& address, int port); - ~I2PControlService (); - - void Start (); - void Stop (); - - private: - - void Run (); - void Accept (); - void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); - 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 SendResponse (std::shared_ptr socket, - 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); - - private: - - void InsertParam (std::ostringstream& ss, const std::string& name, int value) const; - void InsertParam (std::ostringstream& ss, const std::string& name, double value) const; - void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const; - - // methods - typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results); - - void AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results); - - // I2PControl - typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value); - - // RouterInfo - typedef void (I2PControlService::*RouterInfoRequestHandler)(std::ostringstream& results); - void UptimeHandler (std::ostringstream& results); - void VersionHandler (std::ostringstream& results); - void StatusHandler (std::ostringstream& results); - void NetDbKnownPeersHandler (std::ostringstream& results); - void NetDbActivePeersHandler (std::ostringstream& results); - void NetStatusHandler (std::ostringstream& results); - void TunnelsParticipatingHandler (std::ostringstream& results); - void InboundBandwidth1S (std::ostringstream& results); - void OutboundBandwidth1S (std::ostringstream& results); - - // RouterManager - typedef void (I2PControlService::*RouterManagerRequestHandler)(std::ostringstream& results); - void ShutdownHandler (std::ostringstream& results); - void ShutdownGracefulHandler (std::ostringstream& results); - void ReseedHandler (std::ostringstream& results); - - // NetworkSetting - typedef void (I2PControlService::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results); - - private: - - std::string m_Password; - bool m_IsRunning; - std::thread * m_Thread; - - boost::asio::io_service m_Service; - boost::asio::ip::tcp::acceptor m_Acceptor; - boost::asio::deadline_timer m_ShutdownTimer; - std::set m_Tokens; - - std::map m_MethodHandlers; - std::map m_I2PControlHandlers; - std::map m_RouterInfoHandlers; - std::map m_RouterManagerHandlers; - std::map m_NetworkSettingHandlers; - }; -} -} - -#endif - diff --git a/Makefile b/Makefile index cd4961f4..06926c82 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,7 @@ mk_build_dir: mkdir -p obj/util mkdir -p obj/crypto mkdir -p obj/tunnel + mkdir -p obj/i2pcontrol mk_build_test_dir: mkdir -p obj/tests @@ -51,6 +52,7 @@ deps: @mkdir -p obj/util @mkdir -p obj/crypto @mkdir -p obj/tunnel + @mkdir -p obj/i2pcontrol $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS) @sed -i -e '/\.o:/ s/^/obj\//' $(DEPS) @@ -61,6 +63,7 @@ obj/%.o : %.cpp @mkdir -p obj/util @mkdir -p obj/crypto @mkdir -p obj/tunnel + @mkdir -p obj/i2pcontrol $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $< # '-' is 'ignore if missing' on first run diff --git a/filelist.mk b/filelist.mk index e7f29f23..b44a02eb 100644 --- a/filelist.mk +++ b/filelist.mk @@ -16,7 +16,8 @@ ifeq ($(UNAME),Darwin) # Else will get linker error about unknown symbols. - torkel COMMON_SRC += \ AddressBook.cpp BOB.cpp ClientContext.cpp Daemon.cpp I2PTunnel.cpp I2PService.cpp \ - SAM.cpp SOCKS.cpp UPnP.cpp HTTPProxy.cpp i2p.cpp DaemonLinux.cpp I2PControl.cpp \ + SAM.cpp SOCKS.cpp UPnP.cpp HTTPProxy.cpp i2p.cpp DaemonLinux.cpp \ + i2pcontrol/I2PControlServer.cpp i2pcontrol/I2PControl.cpp \ HTTPServer.cpp endif @@ -24,7 +25,8 @@ endif # also: Daemon{Linux,Win32}.cpp will be added later DAEMON_SRC = $(COMMON_SRC) \ AddressBook.cpp BOB.cpp ClientContext.cpp Daemon.cpp I2PTunnel.cpp I2PService.cpp \ - SAM.cpp SOCKS.cpp HTTPServer.cpp HTTPProxy.cpp I2PControl.cpp i2p.cpp + SAM.cpp SOCKS.cpp HTTPServer.cpp HTTPProxy.cpp i2pcontrol/I2PControl.cpp \ + i2pcontrol/I2PControlServer.cpp i2p.cpp LIB_SRC := $(COMMON_SRC) \ api.cpp diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp new file mode 100644 index 00000000..3e693efc --- /dev/null +++ b/i2pcontrol/I2PControl.cpp @@ -0,0 +1,254 @@ +// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy +// #define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 7)) +// TODO: handle this somewhere, but definitely not here + +#include "I2PControl.h" +#include "util/Log.h" +#include +#include +#include "util/Timestamp.h" +#include +#include "transport/Transports.h" +#include "tunnel/Tunnel.h" +#include "NetDb.h" +#include "version.h" +#include "Daemon.h" + +namespace i2p { +namespace client { + +I2PControlSession::Response::Response(const std::string& id, const std::string& version) + : id(id), version(version), parameters() +{ + +} + +std::string I2PControlSession::Response::toJsonString() const +{ + std::ostringstream oss; + oss << "{\"id\":" << id << ",\"result\":{"; + oss << "},\"jsonrpc\":\"" << version << "\"}"; + for(auto& pair : parameters) + oss << '"' << pair.first << "\":" << pair.second << ", "; + return oss.str(); +} + +void I2PControlSession::Response::setParam(const std::string& param, const std::string& value) +{ + parameters[param] = value.empty() ? "\"" + value + "\"" : "null"; +} + +void I2PControlSession::Response::setParam(const std::string& param, int value) +{ + parameters[param] = std::to_string(value); +} + +void I2PControlSession::Response::setParam(const std::string& param, double value) +{ + std::ostringstream oss; + oss << std::fixed << std::setprecision(2) << value; + parameters[param] = oss.str(); +} + +I2PControlSession::I2PControlSession(boost::asio::io_service& ios) + : password(I2P_CONTROL_DEFAULT_PASSWORD), service(ios), shutdownTimer(ios) +{ + // Method handlers + methodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlSession::handleAuthenticate; + methodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlSession::handleEcho; + methodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlSession::handleI2PControl; + methodHandlers[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlSession::handleRouterInfo; + methodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlSession::handleRouterManager; + methodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlSession::handleNetworkSetting; + // RouterInfo handlers + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlSession::handleUptime; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlSession::handleVersion; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_STATUS] = &I2PControlSession::handleStatus; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS]= &I2PControlSession::handleNetDbKnownPeers; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS] = &I2PControlSession::handleNetDbActivePeers; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_STATUS] = &I2PControlSession::handleNetStatus; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlSession::handleTunnelsParticipating; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_IB_1S] = &I2PControlSession::handleInBandwidth1S; + routerInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_OB_1S] = &I2PControlSession::handleOutBandwidth1S; + + // RouterManager handlers + routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN] = &I2PControlSession::handleShutdown; + routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL] = &I2PControlSession::handleShutdownGraceful; + routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlSession::handleReseed; +} + +I2PControlSession::Response I2PControlSession::handleRequest(std::stringstream& request) +{ + boost::property_tree::ptree pt; + boost::property_tree::read_json(request, pt); + + std::string method = pt.get(I2P_CONTROL_PROPERTY_METHOD); + auto it = methodHandlers.find(method); + if(it == methodHandlers.end()) { // Not found + LogPrint(eLogWarning, "Unknown I2PControl method ", method); + return Response("error"); // TODO: indicate the error through i2pcontrol + } + + Response response(pt.get(I2P_CONTROL_PROPERTY_ID)); + // Call the appropriate handler + (this->*(it->second))(pt.get_child(I2P_CONTROL_PROPERTY_PARAMS), response); + return response; +} + +void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& response) +{ + int api = pt.get(I2P_CONTROL_PARAM_API); + const std::string given_pass = pt.get(I2P_CONTROL_PARAM_PASSWORD); + LogPrint(eLogDebug, "I2PControl Authenticate API = ", api, " Password = ", password); + if(given_pass != password) { + LogPrint( + eLogError, "I2PControl Authenticate Invalid password ", password, + " expected ", password + ); + return; + } + const std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch()); + response.setParam(I2P_CONTROL_PARAM_API, api); + response.setParam(I2P_CONTROL_PARAM_TOKEN, token); + // TODO: store tokens to do something useful with them +} + +void I2PControlSession::handleEcho(const PropertyTree& pt, Response& response) +{ + const std::string echo = pt.get(I2P_CONTROL_PARAM_ECHO); + LogPrint(eLogDebug, "I2PControl Echo Echo = ", echo); + response.setParam(I2P_CONTROL_PARAM_RESULT, echo); +} + +void I2PControlSession::handleI2PControl(const PropertyTree& pt, Response& response) +{ + LogPrint(eLogDebug, "I2PControl I2PControl"); + // TODO: implement + +} + +void I2PControlSession::handleRouterInfo(const PropertyTree& pt, Response& response) +{ + LogPrint(eLogDebug, "I2PControl RouterInfo"); + for(auto pair : pt) { + LogPrint(eLogDebug, pair.first); + auto it = routerInfoHandlers.find(pair.first); + if(it != routerInfoHandlers.end()) + (this->*(it->second))(response); + else + LogPrint(eLogError, "I2PControl RouterInfo unknown request ", it->first); + } +} + +void I2PControlSession::handleRouterManager(const PropertyTree& pt, Response& response) +{ + LogPrint(eLogDebug, "I2PControl RouterManager"); + for(auto pair : pt) { + LogPrint(eLogDebug, pair.first); + auto it = routerManagerHandlers.find(pair.first); + if(it != routerManagerHandlers.end()) + (this->*(it->second))(response); + else + LogPrint(eLogError, "I2PControl RouterManager unknown request ", it->first); + } +} + +void I2PControlSession::handleNetworkSetting(const PropertyTree& pt, Response& response) +{ + +} + +void I2PControlSession::handleUptime(Response& response) +{ + response.setParam(I2P_CONTROL_ROUTER_INFO_UPTIME, (int)i2p::context.GetUptime()*1000); +} + +void I2PControlSession::handleVersion(Response& response) +{ + response.setParam(I2P_CONTROL_ROUTER_INFO_VERSION, VERSION); +} + +void I2PControlSession::handleStatus(Response& response) +{ + response.setParam(I2P_CONTROL_ROUTER_INFO_STATUS, "???"); // TODO: +} + +void I2PControlSession::handleNetDbKnownPeers(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, i2p::data::netdb.GetNumRouters() + ); +} + +void I2PControlSession::handleNetDbActivePeers(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, + i2p::data::netdb.GetNumRouters() + ); +} + +void I2PControlSession::handleNetStatus(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS, + (int)i2p::transport::transports.GetPeers().size() + ); +} + +void I2PControlSession::handleTunnelsParticipating(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING, + (int)i2p::tunnel::tunnels.GetTransitTunnels().size() + ); +} + +void I2PControlSession::handleInBandwidth1S(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_BW_IB_1S, + (double)i2p::transport::transports.GetInBandwidth() + ); +} + +void I2PControlSession::handleOutBandwidth1S(Response& response) +{ + response.setParam( + I2P_CONTROL_ROUTER_INFO_BW_OB_1S, + (double)i2p::transport::transports.GetOutBandwidth() + ); +} + +void I2PControlSession::handleShutdown(Response& response) +{ + LogPrint(eLogInfo, "Shutdown requested"); + response.setParam(I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, ""); + // 1 second to make sure response has been sent + shutdownTimer.expires_from_now(boost::posix_time::seconds(1)); + shutdownTimer.async_wait([](const boost::system::error_code& ecode) { + Daemon.running = 0; + }); +} + +void I2PControlSession::handleShutdownGraceful(Response& response) +{ + i2p::context.SetAcceptsTunnels(false); + int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout(); + LogPrint(eLogInfo, "Graceful shutdown requested. Will shutdown after ", timeout, " seconds"); + response.setParam(I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL, ""); + shutdownTimer.expires_from_now(boost::posix_time::seconds(timeout + 1)); + shutdownTimer.async_wait([](const boost::system::error_code& ecode) { + Daemon.running = 0; + }); +} + +void I2PControlSession::handleReseed(Response& response) +{ + LogPrint(eLogInfo, "Reseed requested"); + response.setParam(I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, ""); + i2p::data::netdb.Reseed(); +} + +} +} diff --git a/i2pcontrol/I2PControl.h b/i2pcontrol/I2PControl.h new file mode 100644 index 00000000..1011d4d5 --- /dev/null +++ b/i2pcontrol/I2PControl.h @@ -0,0 +1,136 @@ +#ifndef I2PCONTROL_H__ +#define I2PCONTROL_H__ + +#include +#include +#include +#include +#include + +namespace i2p { +namespace client { + +const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie"; + +const char I2P_CONTROL_PROPERTY_ID[] = "id"; +const char I2P_CONTROL_PROPERTY_METHOD[] = "method"; +const char I2P_CONTROL_PROPERTY_PARAMS[] = "params"; +const char I2P_CONTROL_PROPERTY_RESULT[] = "result"; + +// methods +const char I2P_CONTROL_METHOD_AUTHENTICATE[] = "Authenticate"; +const char I2P_CONTROL_METHOD_ECHO[] = "Echo"; +const char I2P_CONTROL_METHOD_I2PCONTROL[] = "I2PControl"; +const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo"; +const char I2P_CONTROL_METHOD_ROUTER_MANAGER[] = "RouterManager"; +const char I2P_CONTROL_METHOD_NETWORK_SETTING[] = "NetworkSetting"; + +// params +const char I2P_CONTROL_PARAM_API[] = "API"; +const char I2P_CONTROL_PARAM_PASSWORD[] = "Password"; +const char I2P_CONTROL_PARAM_TOKEN[] = "Token"; +const char I2P_CONTROL_PARAM_ECHO[] = "Echo"; +const char I2P_CONTROL_PARAM_RESULT[] = "Result"; + +// I2PControl +const char I2P_CONTROL_I2PCONTROL_ADDRESS[] = "i2pcontrol.address"; +const char I2P_CONTROL_I2PCONTROL_PASSWORD[] = "i2pcontrol.password"; +const char I2P_CONTROL_I2PCONTROL_PORT[] = "i2pcontrol.port"; + +// RouterInfo requests +const char I2P_CONTROL_ROUTER_INFO_UPTIME[] = "i2p.router.uptime"; +const char I2P_CONTROL_ROUTER_INFO_VERSION[] = "i2p.router.version"; +const char I2P_CONTROL_ROUTER_INFO_STATUS[] = "i2p.router.status"; +const char I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers"; +const char I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS[] = "i2p.router.netdb.activepeers"; +const char I2P_CONTROL_ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status"; +const char I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating"; +const char I2P_CONTROL_ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s"; +const char I2P_CONTROL_ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s"; + +// RouterManager requests +const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN[] = "Shutdown"; +const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful"; +const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed"; + +/** + * "Null" I2P control implementation, does not do actual networking. + */ +class I2PControlSession { + +public: + class Response { + std::string id; + std::string version; + std::map parameters; + public: + Response(const std::string& id, const std::string& version = "2.0"); + std::string toJsonString() const; + + /** + * Set an ouptut parameter to a specified string. + * @todo escape quotes + */ + void setParam(const std::string& param, const std::string& value); + void setParam(const std::string& param, int value); + void setParam(const std::string& param, double value); + }; + + /** + * Sets up the appropriate handlers. + * @param ios the parent io_service object + */ + I2PControlSession(boost::asio::io_service& ios); + + /** + * Handle a json string with I2PControl instructions. + */ + Response handleRequest(std::stringstream& request); +private: + // For convenience + typedef boost::property_tree::ptree PropertyTree; + // Handler types + typedef void (I2PControlSession::*MethodHandler)( + const PropertyTree& pt, Response& results + ); + typedef void (I2PControlSession::*RequestHandler)(Response& results); + + // Method handlers + void handleAuthenticate(const PropertyTree& pt, Response& response); + void handleEcho(const PropertyTree& pt, Response& response); + void handleI2PControl(const PropertyTree& pt, Response& response); + void handleRouterInfo(const PropertyTree& pt, Response& response); + void handleRouterManager(const PropertyTree& pt, Response& response); + void handleNetworkSetting(const PropertyTree& pt, Response& response); + + // RouterInfo handlers + void handleUptime(Response& response); + void handleVersion(Response& response); + void handleStatus(Response& response); + void handleNetDbKnownPeers(Response& response); + void handleNetDbActivePeers(Response& response); + void handleNetStatus(Response& response); + void handleTunnelsParticipating(Response& response); + void handleInBandwidth1S(Response& response); + void handleOutBandwidth1S(Response& response); + + // RouterManager handlers + void handleShutdown(Response& response); + void handleShutdownGraceful(Response& response); + void handleReseed(Response& response); + + std::string password; + + std::map methodHandlers; + std::map routerInfoHandlers; + std::map routerManagerHandlers; + std::map networkSettingHandlers; + + boost::asio::io_service& service; + boost::asio::deadline_timer shutdownTimer; +}; + +} +} + +#endif // I2PCONTROL_H__ diff --git a/i2pcontrol/I2PControlServer.cpp b/i2pcontrol/I2PControlServer.cpp new file mode 100644 index 00000000..ceb947fa --- /dev/null +++ b/i2pcontrol/I2PControlServer.cpp @@ -0,0 +1,178 @@ +#include "I2PControlServer.h" +#include +#include +#include +#include "util/Log.h" +#include "util/Timestamp.h" +#include "version.h" + +namespace i2p +{ +namespace client +{ + I2PControlService::I2PControlService(const std::string& address, int port) + : m_Session(m_Service), m_IsRunning(false), m_Thread(nullptr), + m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint( + boost::asio::ip::address::from_string(address), port) + ) + { + } + + I2PControlService::~I2PControlService () + { + Stop (); + } + + void I2PControlService::Start () + { + if (!m_IsRunning) + { + Accept (); + m_IsRunning = true; + m_Thread = new std::thread (std::bind (&I2PControlService::Run, this)); + } + } + + void I2PControlService::Stop () + { + if (m_IsRunning) + { + m_IsRunning = false; + m_Acceptor.cancel (); + m_Service.stop (); + if (m_Thread) + { + m_Thread->join (); + delete m_Thread; + m_Thread = nullptr; + } + } + } + + void I2PControlService::Run () + { + while (m_IsRunning) + { + try + { + m_Service.run (); + } + catch (std::exception& ex) + { + LogPrint (eLogError, "I2PControl: ", ex.what ()); + } + } + } + + void I2PControlService::Accept () + { + auto newSocket = std::make_shared (m_Service); + m_Acceptor.async_accept (*newSocket, std::bind (&I2PControlService::HandleAccept, this, + std::placeholders::_1, newSocket)); + } + + void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) + { + if (ecode != boost::asio::error::operation_aborted) + Accept (); + + if (!ecode) + { + LogPrint (eLogInfo, "New I2PControl request from ", socket->remote_endpoint ()); + std::this_thread::sleep_for (std::chrono::milliseconds(5)); + ReadRequest (socket); + } + else + LogPrint (eLogError, "I2PControl accept error: ", ecode.message ()); + } + + void I2PControlService::ReadRequest (std::shared_ptr socket) + { + auto request = std::make_shared(); + socket->async_read_some ( +#if BOOST_VERSION >= 104900 + boost::asio::buffer (*request), +#else + boost::asio::buffer (request->data (), request->size ()), +#endif + std::bind(&I2PControlService::HandleRequestReceived, this, + std::placeholders::_1, std::placeholders::_2, socket, request)); + } + + void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode, + size_t bytes_transferred, std::shared_ptr socket, + std::shared_ptr buf) + { + if (ecode) + { + LogPrint (eLogError, "I2PControl read error: ", ecode.message ()); + } + else + { + try + { + bool isHtml = !memcmp (buf->data (), "POST", 4); + std::stringstream ss; + ss.write (buf->data (), bytes_transferred); + if (isHtml) + { + std::string header; + while (!ss.eof () && header != "\r") + std::getline(ss, header); + if (ss.eof ()) + { + LogPrint (eLogError, "Malformed I2PControl request. HTTP header expected"); + return; // TODO: + } + } + + I2PControlSession::Response response = m_Session.handleRequest(ss); + SendResponse(socket, buf, response.toJsonString(), isHtml); + } + catch (const std::exception& ex) + { + LogPrint (eLogError, "I2PControl handle request: ", ex.what ()); + } + catch (...) + { + LogPrint (eLogError, "I2PControl handle request unknown exception"); + } + } + } + + void I2PControlService::SendResponse (std::shared_ptr socket, + std::shared_ptr buf, const std::string& response, bool isHtml) + { + size_t len = response.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); + } + memcpy (buf->data () + offset, response.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)); + } + + void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, + std::shared_ptr socket, std::shared_ptr buf) + { + if (ecode) + LogPrint (eLogError, "I2PControl write error: ", ecode.message ()); + socket->close (); + } + +} +} diff --git a/i2pcontrol/I2PControlServer.h b/i2pcontrol/I2PControlServer.h new file mode 100644 index 00000000..7113288b --- /dev/null +++ b/i2pcontrol/I2PControlServer.h @@ -0,0 +1,58 @@ +#ifndef I2P_CONTROL_SERVER_H__ +#define I2P_CONTROL_SERVER_H__ + +#include "I2PControl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace i2p { +namespace client { + +const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024; +typedef std::array I2PControlBuffer; + +class I2PControlService { +public: + + I2PControlService(const std::string& address, int port); + ~I2PControlService (); + + void Start (); + void Stop (); + +private: + + void Run (); + void Accept (); + void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); + 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 SendResponse (std::shared_ptr socket, + std::shared_ptr buf, const std::string& response, bool isHtml); + void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, + std::shared_ptr socket, std::shared_ptr buf); + +private: + + bool m_IsRunning; + std::thread * m_Thread; + + boost::asio::io_service m_Service; + boost::asio::ip::tcp::acceptor m_Acceptor; + + I2PControlSession m_Session; + +}; +} +} + +#endif + From 996c36b93de9776cca3751d9fcfdf97d68ff9f3e Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sat, 1 Aug 2015 18:34:02 +0200 Subject: [PATCH 05/18] Fixes for I2PControl. --- i2pcontrol/I2PControl.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp index 3e693efc..86d85f5e 100644 --- a/i2pcontrol/I2PControl.cpp +++ b/i2pcontrol/I2PControl.cpp @@ -27,15 +27,18 @@ std::string I2PControlSession::Response::toJsonString() const { std::ostringstream oss; oss << "{\"id\":" << id << ",\"result\":{"; + for(auto it = parameters.begin(); it != parameters.end(); ++it) { + if(it != parameters.begin()) + oss << ','; + oss << '"' << it->first << "\":" << it->second; + } oss << "},\"jsonrpc\":\"" << version << "\"}"; - for(auto& pair : parameters) - oss << '"' << pair.first << "\":" << pair.second << ", "; return oss.str(); } void I2PControlSession::Response::setParam(const std::string& param, const std::string& value) { - parameters[param] = value.empty() ? "\"" + value + "\"" : "null"; + parameters[param] = value.empty() ? "null" : "\"" + value + "\""; } void I2PControlSession::Response::setParam(const std::string& param, int value) @@ -130,26 +133,27 @@ void I2PControlSession::handleI2PControl(const PropertyTree& pt, Response& respo void I2PControlSession::handleRouterInfo(const PropertyTree& pt, Response& response) { LogPrint(eLogDebug, "I2PControl RouterInfo"); - for(auto pair : pt) { + for(const auto& pair : pt) { LogPrint(eLogDebug, pair.first); auto it = routerInfoHandlers.find(pair.first); + LogPrint(eLogDebug, "Still going"); if(it != routerInfoHandlers.end()) (this->*(it->second))(response); else - LogPrint(eLogError, "I2PControl RouterInfo unknown request ", it->first); + LogPrint(eLogError, "I2PControl RouterInfo unknown request ", pair.first); } } void I2PControlSession::handleRouterManager(const PropertyTree& pt, Response& response) { LogPrint(eLogDebug, "I2PControl RouterManager"); - for(auto pair : pt) { + for(const auto& pair : pt) { LogPrint(eLogDebug, pair.first); auto it = routerManagerHandlers.find(pair.first); if(it != routerManagerHandlers.end()) (this->*(it->second))(response); else - LogPrint(eLogError, "I2PControl RouterManager unknown request ", it->first); + LogPrint(eLogError, "I2PControl RouterManager unknown request ", pair.first); } } From 9cca01d159bb9583f9079a85424cd410db2f6c60 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sat, 1 Aug 2015 23:10:10 +0200 Subject: [PATCH 06/18] Error handling and authentication for I2PControl. --- i2pcontrol/I2PControl.cpp | 121 ++++++++++++++++++++++++++++++++------ i2pcontrol/I2PControl.h | 36 +++++++++++- 2 files changed, 137 insertions(+), 20 deletions(-) diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp index 86d85f5e..ae895606 100644 --- a/i2pcontrol/I2PControl.cpp +++ b/i2pcontrol/I2PControl.cpp @@ -17,8 +17,8 @@ namespace i2p { namespace client { -I2PControlSession::Response::Response(const std::string& id, const std::string& version) - : id(id), version(version), parameters() +I2PControlSession::Response::Response(const std::string& version) + : id(), version(version), error(ErrorCode::None), parameters() { } @@ -32,10 +32,42 @@ std::string I2PControlSession::Response::toJsonString() const oss << ','; oss << '"' << it->first << "\":" << it->second; } - oss << "},\"jsonrpc\":\"" << version << "\"}"; + oss << "},\"jsonrpc\":\"" << version << '"'; + if(error != ErrorCode::None) + oss << ",\"error\":{\"code\":" << static_cast(error) + << ",\"message\":\"" << getErrorMsg() << "\"" << "}"; + oss << "}"; return oss.str(); } +std::string I2PControlSession::Response::getErrorMsg() const +{ + switch(error) { + case ErrorCode::MethodNotFound: + return "Method not found."; + case ErrorCode::InvalidParameters: + return "Invalid parameters."; + case ErrorCode::InvalidRequest: + return "Invalid request."; + case ErrorCode::ParseError: + return "Json parse error."; + case ErrorCode::InvalidPassword: + return "Invalid password."; + case ErrorCode::NoToken: + return "No authentication token given."; + case ErrorCode::NonexistantToken: + return "Nonexistant authentication token given."; + case ErrorCode::ExpiredToken: + return "Exipred authentication token given."; + case ErrorCode::UnspecifiedVersion: + return "Version not specified."; + case ErrorCode::UnsupportedVersion: + return "Version not supported."; + default: + return ""; + }; +} + void I2PControlSession::Response::setParam(const std::string& param, const std::string& value) { parameters[param] = value.empty() ? "null" : "\"" + value + "\""; @@ -53,8 +85,18 @@ void I2PControlSession::Response::setParam(const std::string& param, double valu parameters[param] = oss.str(); } +void I2PControlSession::Response::setError(ErrorCode code) +{ + error = code; +} + +void I2PControlSession::Response::setId(const std::string& identifier) +{ + id = identifier; +} + I2PControlSession::I2PControlSession(boost::asio::io_service& ios) - : password(I2P_CONTROL_DEFAULT_PASSWORD), service(ios), shutdownTimer(ios) + : password(I2P_CONTROL_DEFAULT_PASSWORD), tokens(), service(ios), shutdownTimer(ios) { // Method handlers methodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlSession::handleAuthenticate; @@ -85,22 +127,54 @@ I2PControlSession::Response I2PControlSession::handleRequest(std::stringstream& boost::property_tree::ptree pt; boost::property_tree::read_json(request, pt); - std::string method = pt.get(I2P_CONTROL_PROPERTY_METHOD); - auto it = methodHandlers.find(method); - if(it == methodHandlers.end()) { // Not found - LogPrint(eLogWarning, "Unknown I2PControl method ", method); - return Response("error"); // TODO: indicate the error through i2pcontrol + Response response; + try { + response.setId(pt.get(I2P_CONTROL_PROPERTY_ID)); + + std::string method = pt.get(I2P_CONTROL_PROPERTY_METHOD); + auto it = methodHandlers.find(method); + if(it == methodHandlers.end()) { // Not found + LogPrint(eLogWarning, "Unknown I2PControl method ", method); + response.setError(ErrorCode::MethodNotFound); + return response; + } + + PropertyTree params = pt.get_child(I2P_CONTROL_PROPERTY_PARAMS); + if(method != I2P_CONTROL_METHOD_AUTHENTICATE && !authenticate(params, response)) { + LogPrint(eLogWarning, "I2PControl invalid token presented"); + return response; + } + // Call the appropriate handler + (this->*(it->second))(params, response); + + } catch(const boost::property_tree::ptree_error& error) { + response.setError(ErrorCode::ParseError); + } catch(...) { + response.setError(ErrorCode::InternalError); } - Response response(pt.get(I2P_CONTROL_PROPERTY_ID)); - // Call the appropriate handler - (this->*(it->second))(pt.get_child(I2P_CONTROL_PROPERTY_PARAMS), response); return response; } +bool I2PControlSession::authenticate(const PropertyTree& pt, Response& response) +{ + try { + std::string token = pt.get(I2P_CONTROL_PARAM_TOKEN); + if(tokens.find(token) == tokens.end()) { + response.setError(ErrorCode::NonexistantToken); + return false; + } + } catch(const boost::property_tree::ptree_error& error) { + response.setError(ErrorCode::NoToken); + return false; + } + + return true; +} + void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& response) { - int api = pt.get(I2P_CONTROL_PARAM_API); + const int api = pt.get(I2P_CONTROL_PARAM_API); const std::string given_pass = pt.get(I2P_CONTROL_PARAM_PASSWORD); LogPrint(eLogDebug, "I2PControl Authenticate API = ", api, " Password = ", password); if(given_pass != password) { @@ -108,12 +182,14 @@ void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& res eLogError, "I2PControl Authenticate Invalid password ", password, " expected ", password ); + response.setError(ErrorCode::InvalidPassword); return; } + // TODO: generate a secure token const std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch()); response.setParam(I2P_CONTROL_PARAM_API, api); response.setParam(I2P_CONTROL_PARAM_TOKEN, token); - // TODO: store tokens to do something useful with them + tokens.insert(token); } void I2PControlSession::handleEcho(const PropertyTree& pt, Response& response) @@ -134,13 +210,16 @@ void I2PControlSession::handleRouterInfo(const PropertyTree& pt, Response& respo { LogPrint(eLogDebug, "I2PControl RouterInfo"); for(const auto& pair : pt) { + if(pair.first == I2P_CONTROL_PARAM_TOKEN) + continue; LogPrint(eLogDebug, pair.first); auto it = routerInfoHandlers.find(pair.first); - LogPrint(eLogDebug, "Still going"); - if(it != routerInfoHandlers.end()) + if(it != routerInfoHandlers.end()) { (this->*(it->second))(response); - else + } else { LogPrint(eLogError, "I2PControl RouterInfo unknown request ", pair.first); + response.setError(ErrorCode::InvalidRequest); + } } } @@ -148,12 +227,16 @@ void I2PControlSession::handleRouterManager(const PropertyTree& pt, Response& re { LogPrint(eLogDebug, "I2PControl RouterManager"); for(const auto& pair : pt) { + if(pair.first == I2P_CONTROL_PARAM_TOKEN) + continue; LogPrint(eLogDebug, pair.first); auto it = routerManagerHandlers.find(pair.first); - if(it != routerManagerHandlers.end()) + if(it != routerManagerHandlers.end()) { (this->*(it->second))(response); - else + } else { LogPrint(eLogError, "I2PControl RouterManager unknown request ", pair.first); + response.setError(ErrorCode::InvalidRequest); + } } } diff --git a/i2pcontrol/I2PControl.h b/i2pcontrol/I2PControl.h index 1011d4d5..eae0a6f3 100644 --- a/i2pcontrol/I2PControl.h +++ b/i2pcontrol/I2PControl.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -55,16 +56,36 @@ const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed"; /** * "Null" I2P control implementation, does not do actual networking. + * @note authentication tokens are per-session */ class I2PControlSession { public: + enum class ErrorCode { + None = 0, + // JSON-RPC2 + MethodNotFound = 32601, + InvalidParameters = 32602, + InvalidRequest = 32600, + InternalError = 32603, + ParseError = 32700, + // I2PControl specific + InvalidPassword = 32001, + NoToken = 32002, + NonexistantToken = 32003, + ExpiredToken = 32004, + UnspecifiedVersion = 32005, + UnsupportedVersion = 32006 + }; + class Response { std::string id; std::string version; + ErrorCode error; std::map parameters; + public: - Response(const std::string& id, const std::string& version = "2.0"); + Response(const std::string& version = "2.0"); std::string toJsonString() const; /** @@ -74,6 +95,11 @@ public: void setParam(const std::string& param, const std::string& value); void setParam(const std::string& param, int value); void setParam(const std::string& param, double value); + + void setError(ErrorCode code); + void setId(const std::string& identifier); + + std::string getErrorMsg() const; }; /** @@ -95,6 +121,13 @@ private: ); typedef void (I2PControlSession::*RequestHandler)(Response& results); + + /** + * Tries to authenticate by checking whether the given token is valid. + * Sets the appropriate error code in the given response. + */ + bool authenticate(const PropertyTree& pt, Response& response); + // Method handlers void handleAuthenticate(const PropertyTree& pt, Response& response); void handleEcho(const PropertyTree& pt, Response& response); @@ -120,6 +153,7 @@ private: void handleReseed(Response& response); std::string password; + std::set tokens; std::map methodHandlers; std::map routerInfoHandlers; From c7f4a79b2cd8868dbadebfc7f803c1d0d187d3f8 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 12:57:16 +0200 Subject: [PATCH 07/18] Destroy I2PControlSession before io_service, cancel waiting operations. --- i2pcontrol/I2PControl.cpp | 11 +++++++++++ i2pcontrol/I2PControl.h | 13 +++++++++++-- i2pcontrol/I2PControlServer.cpp | 7 +++++-- i2pcontrol/I2PControlServer.h | 2 +- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp index ae895606..0d642ce9 100644 --- a/i2pcontrol/I2PControl.cpp +++ b/i2pcontrol/I2PControl.cpp @@ -122,6 +122,17 @@ I2PControlSession::I2PControlSession(boost::asio::io_service& ios) routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlSession::handleReseed; } +I2PControlSession::~I2PControlSession() +{ + stop(); +} + +void I2PControlSession::stop() +{ + boost::system::error_code e; // Make sure this doesn't throw + shutdownTimer.cancel(e); +} + I2PControlSession::Response I2PControlSession::handleRequest(std::stringstream& request) { boost::property_tree::ptree pt; diff --git a/i2pcontrol/I2PControl.h b/i2pcontrol/I2PControl.h index eae0a6f3..5d021172 100644 --- a/i2pcontrol/I2PControl.h +++ b/i2pcontrol/I2PControl.h @@ -57,6 +57,7 @@ const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed"; /** * "Null" I2P control implementation, does not do actual networking. * @note authentication tokens are per-session + * @warning an I2PControlSession must be destroyed before its io_service */ class I2PControlSession { @@ -104,10 +105,19 @@ public: /** * Sets up the appropriate handlers. - * @param ios the parent io_service object + * @param ios the parent io_service object, must remain valid throughout + * the lifetime of this I2PControlSession. */ I2PControlSession(boost::asio::io_service& ios); + ~I2PControlSession(); + + /** + * Cancels all operations that are waiting. + * @note must not be called before destruction, destructor handles this + */ + void stop(); + /** * Handle a json string with I2PControl instructions. */ @@ -120,7 +130,6 @@ private: const PropertyTree& pt, Response& results ); typedef void (I2PControlSession::*RequestHandler)(Response& results); - /** * Tries to authenticate by checking whether the given token is valid. diff --git a/i2pcontrol/I2PControlServer.cpp b/i2pcontrol/I2PControlServer.cpp index ceb947fa..119e3835 100644 --- a/i2pcontrol/I2PControlServer.cpp +++ b/i2pcontrol/I2PControlServer.cpp @@ -11,11 +11,12 @@ namespace i2p namespace client { I2PControlService::I2PControlService(const std::string& address, int port) - : m_Session(m_Service), m_IsRunning(false), m_Thread(nullptr), + : m_Session(new I2PControlSession(m_Service)), m_IsRunning(false), m_Thread(nullptr), m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint( boost::asio::ip::address::from_string(address), port) ) { + } I2PControlService::~I2PControlService () @@ -39,6 +40,8 @@ namespace client { m_IsRunning = false; m_Acceptor.cancel (); + // Delete the session before the io_service is stopped and destroyed + delete m_Session; m_Service.stop (); if (m_Thread) { @@ -126,7 +129,7 @@ namespace client } } - I2PControlSession::Response response = m_Session.handleRequest(ss); + I2PControlSession::Response response = m_Session->handleRequest(ss); SendResponse(socket, buf, response.toJsonString(), isHtml); } catch (const std::exception& ex) diff --git a/i2pcontrol/I2PControlServer.h b/i2pcontrol/I2PControlServer.h index 7113288b..eaffb213 100644 --- a/i2pcontrol/I2PControlServer.h +++ b/i2pcontrol/I2PControlServer.h @@ -48,7 +48,7 @@ private: boost::asio::io_service m_Service; boost::asio::ip::tcp::acceptor m_Acceptor; - I2PControlSession m_Session; + I2PControlSession* m_Session; }; } From 109127a39ee76a43af3e1236b61ab5ab25c31d4e Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 14:46:39 +0200 Subject: [PATCH 08/18] Generate random I2PControl tokens. --- i2pcontrol/I2PControl.cpp | 27 +++++++++++++++++++++++---- i2pcontrol/I2PControl.h | 6 ++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp index 0d642ce9..e3bdfb87 100644 --- a/i2pcontrol/I2PControl.cpp +++ b/i2pcontrol/I2PControl.cpp @@ -3,11 +3,16 @@ // TODO: handle this somewhere, but definitely not here #include "I2PControl.h" -#include "util/Log.h" #include #include -#include "util/Timestamp.h" + +#include +#include +#include + #include +#include "util/Log.h" +#include "util/Timestamp.h" #include "transport/Transports.h" #include "tunnel/Tunnel.h" #include "NetDb.h" @@ -183,6 +188,21 @@ bool I2PControlSession::authenticate(const PropertyTree& pt, Response& response) return true; } +std::string I2PControlSession::generateToken() const +{ + const std::size_t token_size = 8; // 64 bits of security + + byte random_data[token_size] = {}; + CryptoPP::AutoSeededRandomPool rng; + rng.GenerateBlock(random_data, token_size); + std::string token; + CryptoPP::StringSource ss( + random_data, token_size, true, + new CryptoPP::HexEncoder(new CryptoPP::StringSink(token)) + ); + return token; +} + void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& response) { const int api = pt.get(I2P_CONTROL_PARAM_API); @@ -196,8 +216,7 @@ void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& res response.setError(ErrorCode::InvalidPassword); return; } - // TODO: generate a secure token - const std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch()); + const std::string token = generateToken(); response.setParam(I2P_CONTROL_PARAM_API, api); response.setParam(I2P_CONTROL_PARAM_TOKEN, token); tokens.insert(token); diff --git a/i2pcontrol/I2PControl.h b/i2pcontrol/I2PControl.h index 5d021172..3f3b52be 100644 --- a/i2pcontrol/I2PControl.h +++ b/i2pcontrol/I2PControl.h @@ -137,6 +137,12 @@ private: */ bool authenticate(const PropertyTree& pt, Response& response); + /** + * Generate a random authentication token. + * @return 8 random bytes as a hexadecimal string + */ + std::string generateToken() const; + // Method handlers void handleAuthenticate(const PropertyTree& pt, Response& response); void handleEcho(const PropertyTree& pt, Response& response); From 69d93146f2f7d7fb5ac0b80caaae4f4f475b564d Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 16:32:54 +0200 Subject: [PATCH 09/18] Expire tokens, use std::shared_ptr for I2PControlSession. --- i2pcontrol/I2PControl.cpp | 46 +++++++++++++++++++++++++++++---- i2pcontrol/I2PControl.h | 26 +++++++++++++++---- i2pcontrol/I2PControlServer.cpp | 9 ++++--- i2pcontrol/I2PControlServer.h | 2 +- 4 files changed, 69 insertions(+), 14 deletions(-) diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp index e3bdfb87..071dd60a 100644 --- a/i2pcontrol/I2PControl.cpp +++ b/i2pcontrol/I2PControl.cpp @@ -101,7 +101,8 @@ void I2PControlSession::Response::setId(const std::string& identifier) } I2PControlSession::I2PControlSession(boost::asio::io_service& ios) - : password(I2P_CONTROL_DEFAULT_PASSWORD), tokens(), service(ios), shutdownTimer(ios) + : password(I2P_CONTROL_DEFAULT_PASSWORD), tokens(), tokensMutex(), + service(ios), shutdownTimer(ios), expireTokensTimer(ios) { // Method handlers methodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlSession::handleAuthenticate; @@ -127,15 +128,16 @@ I2PControlSession::I2PControlSession(boost::asio::io_service& ios) routerManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlSession::handleReseed; } -I2PControlSession::~I2PControlSession() +void I2PControlSession::start() { - stop(); + startExpireTokensJob(); } void I2PControlSession::stop() { boost::system::error_code e; // Make sure this doesn't throw shutdownTimer.cancel(e); + expireTokensTimer.cancel(e); } I2PControlSession::Response I2PControlSession::handleRequest(std::stringstream& request) @@ -176,10 +178,17 @@ bool I2PControlSession::authenticate(const PropertyTree& pt, Response& response) { try { std::string token = pt.get(I2P_CONTROL_PARAM_TOKEN); - if(tokens.find(token) == tokens.end()) { + + std::lock_guard lock(tokensMutex); + auto it = tokens.find(token); + if(it == tokens.end()) { response.setError(ErrorCode::NonexistantToken); return false; + } else if(util::GetSecondsSinceEpoch() - it->second > I2P_CONTROL_TOKEN_LIFETIME) { + response.setError(ErrorCode::ExpiredToken); + return false; } + } catch(const boost::property_tree::ptree_error& error) { response.setError(ErrorCode::NoToken); return false; @@ -219,7 +228,9 @@ void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& res const std::string token = generateToken(); response.setParam(I2P_CONTROL_PARAM_API, api); response.setParam(I2P_CONTROL_PARAM_TOKEN, token); - tokens.insert(token); + + std::lock_guard lock(tokensMutex); + tokens.insert(std::make_pair(token, util::GetSecondsSinceEpoch())); } void I2PControlSession::handleEcho(const PropertyTree& pt, Response& response) @@ -367,5 +378,30 @@ void I2PControlSession::handleReseed(Response& response) i2p::data::netdb.Reseed(); } +void I2PControlSession::expireTokens(const boost::system::error_code& error) +{ + if(error == boost::asio::error::operation_aborted) + return; // Do not restart timer, shutting down + + startExpireTokensJob(); + LogPrint(eLogDebug, "I2PControl is expiring tokens."); + const uint64_t now = util::GetSecondsSinceEpoch(); + std::lock_guard lock(tokensMutex); + for(auto it = tokens.begin(); it != tokens.end(); ) { + if(now - it->second > I2P_CONTROL_TOKEN_LIFETIME) + it = tokens.erase(it); + else + ++it; + } +} + +void I2PControlSession::startExpireTokensJob() +{ + expireTokensTimer.expires_from_now(boost::posix_time::seconds(I2P_CONTROL_TOKEN_LIFETIME)); + expireTokensTimer.async_wait(std::bind( + &I2PControlSession::expireTokens, shared_from_this(), std::placeholders::_1 + )); +} + } } diff --git a/i2pcontrol/I2PControl.h b/i2pcontrol/I2PControl.h index 3f3b52be..ef423bd2 100644 --- a/i2pcontrol/I2PControl.h +++ b/i2pcontrol/I2PControl.h @@ -4,14 +4,15 @@ #include #include #include -#include #include +#include #include namespace i2p { namespace client { const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie"; +const uint64_t I2P_CONTROL_TOKEN_LIFETIME = 600; // Token lifetime in seconds const char I2P_CONTROL_PROPERTY_ID[] = "id"; const char I2P_CONTROL_PROPERTY_METHOD[] = "method"; @@ -57,9 +58,10 @@ const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed"; /** * "Null" I2P control implementation, does not do actual networking. * @note authentication tokens are per-session + * @note I2PControlSession must always be used as a std::shared_ptr * @warning an I2PControlSession must be destroyed before its io_service */ -class I2PControlSession { +class I2PControlSession : public std::enable_shared_from_this { public: enum class ErrorCode { @@ -110,11 +112,16 @@ public: */ I2PControlSession(boost::asio::io_service& ios); - ~I2PControlSession(); + /** + * Starts the I2PControlSession. + * In essence, this starts the expireTokensTimer. + * @note should always be called after construction + */ + void start(); /** * Cancels all operations that are waiting. - * @note must not be called before destruction, destructor handles this + * @note it's a good idea to call this before destruction (shared_ptr reset) */ void stop(); @@ -143,6 +150,13 @@ private: */ std::string generateToken() const; + void startExpireTokensJob(); + + /** + * Expire tokens that are too old. + */ + void expireTokens(const boost::system::error_code& error); + // Method handlers void handleAuthenticate(const PropertyTree& pt, Response& response); void handleEcho(const PropertyTree& pt, Response& response); @@ -168,7 +182,8 @@ private: void handleReseed(Response& response); std::string password; - std::set tokens; + std::map tokens; + std::mutex tokensMutex; std::map methodHandlers; std::map routerInfoHandlers; @@ -177,6 +192,7 @@ private: boost::asio::io_service& service; boost::asio::deadline_timer shutdownTimer; + boost::asio::deadline_timer expireTokensTimer; }; } diff --git a/i2pcontrol/I2PControlServer.cpp b/i2pcontrol/I2PControlServer.cpp index 119e3835..79b599be 100644 --- a/i2pcontrol/I2PControlServer.cpp +++ b/i2pcontrol/I2PControlServer.cpp @@ -11,7 +11,8 @@ namespace i2p namespace client { I2PControlService::I2PControlService(const std::string& address, int port) - : m_Session(new I2PControlSession(m_Service)), m_IsRunning(false), m_Thread(nullptr), + : m_Session(std::make_shared(m_Service)), + m_IsRunning(false), m_Thread(nullptr), m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint( boost::asio::ip::address::from_string(address), port) ) @@ -29,6 +30,7 @@ namespace client if (!m_IsRunning) { Accept (); + m_Session->start(); m_IsRunning = true; m_Thread = new std::thread (std::bind (&I2PControlService::Run, this)); } @@ -40,8 +42,9 @@ namespace client { m_IsRunning = false; m_Acceptor.cancel (); - // Delete the session before the io_service is stopped and destroyed - delete m_Session; + m_Session->stop(); + // Release ownership before the io_service is stopped and destroyed + m_Session.reset(); m_Service.stop (); if (m_Thread) { diff --git a/i2pcontrol/I2PControlServer.h b/i2pcontrol/I2PControlServer.h index eaffb213..8f3a3782 100644 --- a/i2pcontrol/I2PControlServer.h +++ b/i2pcontrol/I2PControlServer.h @@ -48,7 +48,7 @@ private: boost::asio::io_service m_Service; boost::asio::ip::tcp::acceptor m_Acceptor; - I2PControlSession* m_Session; + std::shared_ptr m_Session; }; } From 833a606b1361d03360220e872c5911591fe3c163 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 16:38:46 +0200 Subject: [PATCH 10/18] Add a constant for the I2PControl token size. --- i2pcontrol/I2PControl.cpp | 8 +++----- i2pcontrol/I2PControl.h | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp index 071dd60a..8e680307 100644 --- a/i2pcontrol/I2PControl.cpp +++ b/i2pcontrol/I2PControl.cpp @@ -199,14 +199,12 @@ bool I2PControlSession::authenticate(const PropertyTree& pt, Response& response) std::string I2PControlSession::generateToken() const { - const std::size_t token_size = 8; // 64 bits of security - - byte random_data[token_size] = {}; + byte random_data[I2P_CONTROL_TOKEN_SIZE] = {}; CryptoPP::AutoSeededRandomPool rng; - rng.GenerateBlock(random_data, token_size); + rng.GenerateBlock(random_data, I2P_CONTROL_TOKEN_SIZE); std::string token; CryptoPP::StringSource ss( - random_data, token_size, true, + random_data, I2P_CONTROL_TOKEN_SIZE, true, new CryptoPP::HexEncoder(new CryptoPP::StringSink(token)) ); return token; diff --git a/i2pcontrol/I2PControl.h b/i2pcontrol/I2PControl.h index ef423bd2..4a164790 100644 --- a/i2pcontrol/I2PControl.h +++ b/i2pcontrol/I2PControl.h @@ -13,6 +13,7 @@ namespace client { const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie"; const uint64_t I2P_CONTROL_TOKEN_LIFETIME = 600; // Token lifetime in seconds +const std::size_t I2P_CONTROL_TOKEN_SIZE = 8; // Token size in bytes const char I2P_CONTROL_PROPERTY_ID[] = "id"; const char I2P_CONTROL_PROPERTY_METHOD[] = "method"; From c10d0fdb7e672ad7084475e7f12b24815d99f190 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 17:02:53 +0200 Subject: [PATCH 11/18] Make i2pcontrol error codes negative. --- i2pcontrol/I2PControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp index 8e680307..20724032 100644 --- a/i2pcontrol/I2PControl.cpp +++ b/i2pcontrol/I2PControl.cpp @@ -39,7 +39,7 @@ std::string I2PControlSession::Response::toJsonString() const } oss << "},\"jsonrpc\":\"" << version << '"'; if(error != ErrorCode::None) - oss << ",\"error\":{\"code\":" << static_cast(error) + oss << ",\"error\":{\"code\":" << -static_cast(error) << ",\"message\":\"" << getErrorMsg() << "\"" << "}"; oss << "}"; return oss.str(); From 8434863beb6f5b13cfcd02d41e1969fa66967f54 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 17:14:36 +0200 Subject: [PATCH 12/18] Fixed typos (thx zzz) --- i2pcontrol/I2PControl.cpp | 6 +++--- i2pcontrol/I2PControl.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp index 20724032..38eecf42 100644 --- a/i2pcontrol/I2PControl.cpp +++ b/i2pcontrol/I2PControl.cpp @@ -60,8 +60,8 @@ std::string I2PControlSession::Response::getErrorMsg() const return "Invalid password."; case ErrorCode::NoToken: return "No authentication token given."; - case ErrorCode::NonexistantToken: - return "Nonexistant authentication token given."; + case ErrorCode::NonexistentToken: + return "Nonexistent authentication token given."; case ErrorCode::ExpiredToken: return "Exipred authentication token given."; case ErrorCode::UnspecifiedVersion: @@ -182,7 +182,7 @@ bool I2PControlSession::authenticate(const PropertyTree& pt, Response& response) std::lock_guard lock(tokensMutex); auto it = tokens.find(token); if(it == tokens.end()) { - response.setError(ErrorCode::NonexistantToken); + response.setError(ErrorCode::NonexistentToken); return false; } else if(util::GetSecondsSinceEpoch() - it->second > I2P_CONTROL_TOKEN_LIFETIME) { response.setError(ErrorCode::ExpiredToken); diff --git a/i2pcontrol/I2PControl.h b/i2pcontrol/I2PControl.h index 4a164790..c7563288 100644 --- a/i2pcontrol/I2PControl.h +++ b/i2pcontrol/I2PControl.h @@ -76,7 +76,7 @@ public: // I2PControl specific InvalidPassword = 32001, NoToken = 32002, - NonexistantToken = 32003, + NonexistentToken = 32003, ExpiredToken = 32004, UnspecifiedVersion = 32005, UnsupportedVersion = 32006 From 843abb60dd307599ee2286a209ae161d745621a4 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 19:59:16 +0200 Subject: [PATCH 13/18] Make i2pcontrol password configurable. --- ClientContext.cpp | 3 ++- i2pcontrol/I2PControl.cpp | 4 ++-- i2pcontrol/I2PControl.h | 4 +++- i2pcontrol/I2PControlServer.cpp | 10 ++++------ i2pcontrol/I2PControlServer.h | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/ClientContext.cpp b/ClientContext.cpp index 9ffd2303..9b4f7f17 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -116,7 +116,8 @@ namespace client if(i2pcontrolPort) { m_I2PControlService = new I2PControlService( i2p::util::config::GetArg("-i2pcontroladdress", "127.0.0.1"), - i2pcontrolPort + i2pcontrolPort, + i2p::util::config::GetArg("-i2pcontrolpassword", I2P_CONTROL_DEFAULT_PASSWORD) ); m_I2PControlService->Start(); LogPrint("I2PControl started"); diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp index 38eecf42..656560de 100644 --- a/i2pcontrol/I2PControl.cpp +++ b/i2pcontrol/I2PControl.cpp @@ -100,8 +100,8 @@ void I2PControlSession::Response::setId(const std::string& identifier) id = identifier; } -I2PControlSession::I2PControlSession(boost::asio::io_service& ios) - : password(I2P_CONTROL_DEFAULT_PASSWORD), tokens(), tokensMutex(), +I2PControlSession::I2PControlSession(boost::asio::io_service& ios, const std::string& pass) + : password(pass), tokens(), tokensMutex(), service(ios), shutdownTimer(ios), expireTokensTimer(ios) { // Method handlers diff --git a/i2pcontrol/I2PControl.h b/i2pcontrol/I2PControl.h index c7563288..eb9b3eab 100644 --- a/i2pcontrol/I2PControl.h +++ b/i2pcontrol/I2PControl.h @@ -108,10 +108,12 @@ public: /** * Sets up the appropriate handlers. + * @param pass the password required to authenticate (i.e. obtains a token) * @param ios the parent io_service object, must remain valid throughout * the lifetime of this I2PControlSession. */ - I2PControlSession(boost::asio::io_service& ios); + I2PControlSession(boost::asio::io_service& ios, + const std::string& pass = I2P_CONTROL_DEFAULT_PASSWORD); /** * Starts the I2PControlSession. diff --git a/i2pcontrol/I2PControlServer.cpp b/i2pcontrol/I2PControlServer.cpp index 79b599be..5c956112 100644 --- a/i2pcontrol/I2PControlServer.cpp +++ b/i2pcontrol/I2PControlServer.cpp @@ -6,12 +6,10 @@ #include "util/Timestamp.h" #include "version.h" -namespace i2p -{ -namespace client -{ - I2PControlService::I2PControlService(const std::string& address, int port) - : m_Session(std::make_shared(m_Service)), +namespace i2p { +namespace client { + I2PControlService::I2PControlService(const std::string& address, int port, const std::string& pass) + : m_Session(std::make_shared(m_Service, pass)), m_IsRunning(false), m_Thread(nullptr), m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint( boost::asio::ip::address::from_string(address), port) diff --git a/i2pcontrol/I2PControlServer.h b/i2pcontrol/I2PControlServer.h index 8f3a3782..2eb13654 100644 --- a/i2pcontrol/I2PControlServer.h +++ b/i2pcontrol/I2PControlServer.h @@ -21,7 +21,7 @@ typedef std::array I2PControlBuffer; class I2PControlService { public: - I2PControlService(const std::string& address, int port); + I2PControlService(const std::string& address, int port, const std::string& pass); ~I2PControlService (); void Start (); From 79768cf783c14101221cc43fd01fb988e88e9e7c Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 20:39:10 +0200 Subject: [PATCH 14/18] Mention I2PControl password option in README. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 43dcaac5..df80c3b9 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ Cmdline options * --bobaddress= - Address of BOB service, 127.0.0.1 by default (only used if BOB is on) * --i2pcontrolport= - Port of I2P control service. Usually 7650. I2PControl is off if not specified * --i2pcontroladdress= - Address of I2P control service, 127.0.0.1 by default (only used if I2PControl is on) +* --i2pcontrolpassword= - I2P control service password, "itoopie" by default * --conf= - Config file (default: ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf) This parameter will be silently ignored if the specified config file does not exist. Options specified on the command line take precedence over those in the config file. From 999001733dbb3755c0bc3c2f9736f00eb66adbd7 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 20:42:01 +0200 Subject: [PATCH 15/18] Fix I2PControl invalid password error message. --- i2pcontrol/I2PControl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i2pcontrol/I2PControl.cpp b/i2pcontrol/I2PControl.cpp index 656560de..f44709a7 100644 --- a/i2pcontrol/I2PControl.cpp +++ b/i2pcontrol/I2PControl.cpp @@ -214,10 +214,10 @@ void I2PControlSession::handleAuthenticate(const PropertyTree& pt, Response& res { const int api = pt.get(I2P_CONTROL_PARAM_API); const std::string given_pass = pt.get(I2P_CONTROL_PARAM_PASSWORD); - LogPrint(eLogDebug, "I2PControl Authenticate API = ", api, " Password = ", password); + LogPrint(eLogDebug, "I2PControl Authenticate API = ", api, " Password = ", given_pass); if(given_pass != password) { LogPrint( - eLogError, "I2PControl Authenticate Invalid password ", password, + eLogError, "I2PControl Authenticate Invalid password ", given_pass, " expected ", password ); response.setError(ErrorCode::InvalidPassword); From c3685927d23b3a14bf70baedff62436bec088fef Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 22:01:09 +0200 Subject: [PATCH 16/18] Modfiy indention and spaces in I2PControlServer.h/cpp --- i2pcontrol/I2PControlServer.cpp | 280 +++++++++++++++----------------- i2pcontrol/I2PControlServer.h | 20 +-- 2 files changed, 143 insertions(+), 157 deletions(-) diff --git a/i2pcontrol/I2PControlServer.cpp b/i2pcontrol/I2PControlServer.cpp index 5c956112..0a945c91 100644 --- a/i2pcontrol/I2PControlServer.cpp +++ b/i2pcontrol/I2PControlServer.cpp @@ -8,175 +8,163 @@ namespace i2p { namespace client { - I2PControlService::I2PControlService(const std::string& address, int port, const std::string& pass) - : m_Session(std::make_shared(m_Service, pass)), - m_IsRunning(false), m_Thread(nullptr), - m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint( - boost::asio::ip::address::from_string(address), port) - ) - { - } +I2PControlService::I2PControlService(const std::string& address, int port, const std::string& pass) + : m_Session(std::make_shared(m_Service, pass)), + m_IsRunning(false), m_Thread(nullptr), + m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint( + boost::asio::ip::address::from_string(address), port) + ) +{ - I2PControlService::~I2PControlService () - { - Stop (); - } +} - void I2PControlService::Start () - { - if (!m_IsRunning) - { - Accept (); - m_Session->start(); - m_IsRunning = true; - m_Thread = new std::thread (std::bind (&I2PControlService::Run, this)); - } - } +I2PControlService::~I2PControlService() +{ + Stop(); +} - void I2PControlService::Stop () - { - if (m_IsRunning) - { - m_IsRunning = false; - m_Acceptor.cancel (); - m_Session->stop(); - // Release ownership before the io_service is stopped and destroyed - m_Session.reset(); - m_Service.stop (); - if (m_Thread) - { - m_Thread->join (); - delete m_Thread; - m_Thread = nullptr; - } - } +void I2PControlService::Start() +{ + if(!m_IsRunning) { + Accept(); + m_Session->start(); + m_IsRunning = true; + m_Thread = new std::thread(std::bind(&I2PControlService::Run, this)); } +} - void I2PControlService::Run () - { - while (m_IsRunning) - { - try - { - m_Service.run (); - } - catch (std::exception& ex) - { - LogPrint (eLogError, "I2PControl: ", ex.what ()); - } +void I2PControlService::Stop() +{ + if(m_IsRunning) { + m_IsRunning = false; + m_Acceptor.cancel(); + m_Session->stop(); + // Release ownership before the io_service is stopped and destroyed + m_Session.reset(); + m_Service.stop(); + if(m_Thread) + { + m_Thread->join(); + delete m_Thread; + m_Thread = nullptr; } } +} - void I2PControlService::Accept () - { - auto newSocket = std::make_shared (m_Service); - m_Acceptor.async_accept (*newSocket, std::bind (&I2PControlService::HandleAccept, this, - std::placeholders::_1, newSocket)); - } +void I2PControlService::Run() +{ + while(m_IsRunning) { + try { + m_Service.run(); + } catch(const std::exception& ex) { + LogPrint(eLogError, "I2PControl: ", ex.what()); + } + } +} + +void I2PControlService::Accept() +{ + auto newSocket = std::make_shared(m_Service); + m_Acceptor.async_accept(*newSocket, std::bind(&I2PControlService::HandleAccept, this, + std::placeholders::_1, newSocket)); +} - void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) +void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) +{ + if(ecode != boost::asio::error::operation_aborted) + Accept(); + + if(!ecode) { - if (ecode != boost::asio::error::operation_aborted) - Accept (); - - if (!ecode) - { - LogPrint (eLogInfo, "New I2PControl request from ", socket->remote_endpoint ()); - std::this_thread::sleep_for (std::chrono::milliseconds(5)); - ReadRequest (socket); - } - else - LogPrint (eLogError, "I2PControl accept error: ", ecode.message ()); + LogPrint(eLogInfo, "New I2PControl request from ", socket->remote_endpoint()); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + ReadRequest(socket); } + else + LogPrint(eLogError, "I2PControl accept error: ", ecode.message()); +} - void I2PControlService::ReadRequest (std::shared_ptr socket) - { - auto request = std::make_shared(); - socket->async_read_some ( +void I2PControlService::ReadRequest(std::shared_ptr socket) +{ + auto request = std::make_shared(); + socket->async_read_some( #if BOOST_VERSION >= 104900 - boost::asio::buffer (*request), + boost::asio::buffer(*request), #else - boost::asio::buffer (request->data (), request->size ()), + boost::asio::buffer(request->data(), request->size()), #endif - std::bind(&I2PControlService::HandleRequestReceived, this, - std::placeholders::_1, std::placeholders::_2, socket, request)); + std::bind(&I2PControlService::HandleRequestReceived, this, + std::placeholders::_1, std::placeholders::_2, socket, request)); +} + +void I2PControlService::HandleRequestReceived(const boost::system::error_code& ecode, + size_t bytes_transferred, std::shared_ptr socket, + std::shared_ptr buf) +{ + if(ecode) { + LogPrint(eLogError, "I2PControl read error: ", ecode.message()); + return; } - void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode, - size_t bytes_transferred, std::shared_ptr socket, - std::shared_ptr buf) - { - if (ecode) - { - LogPrint (eLogError, "I2PControl read error: ", ecode.message ()); - } - else - { - try - { - bool isHtml = !memcmp (buf->data (), "POST", 4); - std::stringstream ss; - ss.write (buf->data (), bytes_transferred); - if (isHtml) - { - std::string header; - while (!ss.eof () && header != "\r") - std::getline(ss, header); - if (ss.eof ()) - { - LogPrint (eLogError, "Malformed I2PControl request. HTTP header expected"); - return; // TODO: - } - } - - I2PControlSession::Response response = m_Session->handleRequest(ss); - SendResponse(socket, buf, response.toJsonString(), isHtml); - } - catch (const std::exception& ex) - { - LogPrint (eLogError, "I2PControl handle request: ", ex.what ()); - } - catch (...) - { - LogPrint (eLogError, "I2PControl handle request unknown exception"); + try { + bool isHtml = !memcmp(buf->data(), "POST", 4); + std::stringstream ss; + ss.write(buf->data(), bytes_transferred); + if(isHtml) { + std::string header; + while(!ss.eof() && header != "\r") + std::getline(ss, header); + if(ss.eof()) { + LogPrint(eLogError, "Malformed I2PControl request. HTTP header expected"); + return; // TODO: } } - } - void I2PControlService::SendResponse (std::shared_ptr socket, - std::shared_ptr buf, const std::string& response, bool isHtml) - { - size_t len = response.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); - } - memcpy (buf->data () + offset, response.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)); + I2PControlSession::Response response = m_Session->handleRequest(ss); + SendResponse(socket, buf, response.toJsonString(), isHtml); + } catch(const std::exception& ex) { + LogPrint(eLogError, "I2PControl handle request: ", ex.what()); + } catch(...) { + LogPrint(eLogError, "I2PControl handle request unknown exception"); } +} - void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, - std::shared_ptr socket, std::shared_ptr buf) - { - if (ecode) - LogPrint (eLogError, "I2PControl write error: ", ecode.message ()); - socket->close (); - } +void I2PControlService::SendResponse(std::shared_ptr socket, + std::shared_ptr buf, const std::string& response, bool isHtml) +{ + size_t len = response.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); + } + memcpy(buf->data() + offset, response.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 + ) + ); +} + +void I2PControlService::HandleResponseSent(const boost::system::error_code& ecode, std::size_t bytes_transferred, + std::shared_ptr socket, std::shared_ptr buf) +{ + if(ecode) + LogPrint(eLogError, "I2PControl write error: ", ecode.message()); + socket->close(); +} } } diff --git a/i2pcontrol/I2PControlServer.h b/i2pcontrol/I2PControlServer.h index 2eb13654..48b84101 100644 --- a/i2pcontrol/I2PControlServer.h +++ b/i2pcontrol/I2PControlServer.h @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include namespace i2p { @@ -22,22 +20,22 @@ class I2PControlService { public: I2PControlService(const std::string& address, int port, const std::string& pass); - ~I2PControlService (); + ~I2PControlService(); - void Start (); - void Stop (); + void Start(); + void Stop(); private: - void Run (); - void Accept (); + void Run(); + void Accept(); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); - void ReadRequest (std::shared_ptr socket); - void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred, + 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 SendResponse (std::shared_ptr socket, + void SendResponse(std::shared_ptr socket, std::shared_ptr buf, const std::string& response, bool isHtml); - void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, + void HandleResponseSent(const boost::system::error_code& ecode, std::size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf); private: From 12dd8a394d801bfea5a733224cb10c14c1ec5635 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 23:18:55 +0200 Subject: [PATCH 17/18] Fix building without AESNI. --- build/CMakeLists.txt | 3 ++- tunnel/TunnelCrypto.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index f7f85a16..59fe111b 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -62,7 +62,8 @@ set (DAEMON_SRC "${CMAKE_SOURCE_DIR}/HTTPProxy.cpp" "${CMAKE_SOURCE_DIR}/HTTPServer.cpp" "${CMAKE_SOURCE_DIR}/I2PService.cpp" - "${CMAKE_SOURCE_DIR}/I2PControl.cpp" + "${CMAKE_SOURCE_DIR}/i2pcontrol/I2PControl.cpp" + "${CMAKE_SOURCE_DIR}/i2pcontrol/I2PServer.cpp" "${CMAKE_SOURCE_DIR}/I2PTunnel.cpp" "${CMAKE_SOURCE_DIR}/SAM.cpp" "${CMAKE_SOURCE_DIR}/SOCKS.cpp" diff --git a/tunnel/TunnelCrypto.cpp b/tunnel/TunnelCrypto.cpp index 834be06d..e24f6997 100644 --- a/tunnel/TunnelCrypto.cpp +++ b/tunnel/TunnelCrypto.cpp @@ -40,10 +40,10 @@ void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out) : "%xmm0", "%xmm1", "cc", "memory" ); #else - m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv + m_IVEncryption.Encrypt ((const CipherBlock *)in, (CipherBlock *)out); // iv m_LayerEncryption.SetIV (out); m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data - m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv + m_IVEncryption.Encrypt ((CipherBlock *)out, (CipherBlock *)out); // double iv #endif } @@ -77,10 +77,10 @@ void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out) : "%xmm0", "%xmm1", "%xmm2", "cc", "memory" ); #else - m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv + m_IVDecryption.Decrypt ((const CipherBlock *)in, (CipherBlock *)out); // iv m_LayerDecryption.SetIV (out); m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data - m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv + m_IVDecryption.Decrypt ((CipherBlock *)out, (CipherBlock *)out); // double iv #endif } From 2db3fe36d11a4b9a8c591d54db2a4b2f7d0b3ef7 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 2 Aug 2015 23:22:13 +0200 Subject: [PATCH 18/18] Fix building with CMake (typo in commit 12dd8a3) --- build/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 59fe111b..875c745b 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -63,7 +63,7 @@ set (DAEMON_SRC "${CMAKE_SOURCE_DIR}/HTTPServer.cpp" "${CMAKE_SOURCE_DIR}/I2PService.cpp" "${CMAKE_SOURCE_DIR}/i2pcontrol/I2PControl.cpp" - "${CMAKE_SOURCE_DIR}/i2pcontrol/I2PServer.cpp" + "${CMAKE_SOURCE_DIR}/i2pcontrol/I2PControlServer.cpp" "${CMAKE_SOURCE_DIR}/I2PTunnel.cpp" "${CMAKE_SOURCE_DIR}/SAM.cpp" "${CMAKE_SOURCE_DIR}/SOCKS.cpp"