From c994c11d8c82d3ee8809d28d48167215c0c3e8b6 Mon Sep 17 00:00:00 2001 From: hagen Date: Fri, 27 May 2016 00:00:00 +0000 Subject: [PATCH 01/11] * HTTPProxy.{cpp,h} : rename classes, drop typedef --- HTTPProxy.cpp | 65 ++++++++++++++++++++++++--------------------------- HTTPProxy.h | 18 ++++++-------- 2 files changed, 38 insertions(+), 45 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index f681f365..6915274c 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -21,12 +21,10 @@ #include "I2PTunnel.h" #include "Config.h" -namespace i2p -{ -namespace proxy -{ +namespace i2p { +namespace proxy { static const size_t http_buffer_size = 8192; - class HTTPProxyHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this + class HTTPReqHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this { private: enum state @@ -67,26 +65,26 @@ namespace proxy public: - HTTPProxyHandler(HTTPProxyServer * parent, std::shared_ptr sock) : + HTTPReqHandler(HTTPProxy * parent, std::shared_ptr sock) : I2PServiceHandler(parent), m_sock(sock) { EnterState(GET_METHOD); } - ~HTTPProxyHandler() { Terminate(); } + ~HTTPReqHandler() { Terminate(); } void Handle () { AsyncSockRead(); } }; - void HTTPProxyHandler::AsyncSockRead() + void HTTPReqHandler::AsyncSockRead() { LogPrint(eLogDebug, "HTTPProxy: async sock read"); if(m_sock) { m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size), - std::bind(&HTTPProxyHandler::HandleSockRecv, shared_from_this(), + std::bind(&HTTPReqHandler::HandleSockRecv, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } else { LogPrint(eLogError, "HTTPProxy: no socket for read"); } } - void HTTPProxyHandler::Terminate() { + void HTTPReqHandler::Terminate() { if (Kill()) return; if (m_sock) { @@ -99,7 +97,7 @@ namespace proxy /* All hope is lost beyond this point */ //TODO: handle this apropriately - void HTTPProxyHandler::HTTPRequestFailed(const char *message) + void HTTPReqHandler::HTTPRequestFailed(const char *message) { std::size_t size = std::strlen(message); std::stringstream ss; @@ -108,29 +106,28 @@ namespace proxy ss << "Content-Length: " << std::to_string(size + 2) << "\r\n" << "\r\n"; /* end of headers */ ss << message << "\r\n"; - m_Response = ss.str(); - boost::asio::async_write(*m_sock, boost::asio::buffer(m_Response), - std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); + std::string response = ss.str(); + boost::asio::async_write(*m_sock, boost::asio::buffer(response, response.size()), + std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } - void HTTPProxyHandler::RedirectToJumpService(/*HTTPProxyHandler::errTypes error*/) + void HTTPReqHandler::RedirectToJumpService(/*HTTPReqHandler::errTypes error*/) { std::stringstream response; std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); response << "HTTP/1.1 302 Found\r\nLocation: http://" << httpAddr << ":" << httpPort << "/?page=jumpservices&address=" << m_address << "\r\n\r\n"; - m_Response = response.str (); - boost::asio::async_write(*m_sock, boost::asio::buffer(m_Response), - std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); + boost::asio::async_write(*m_sock, boost::asio::buffer(response.str (),response.str ().length ()), + std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } - void HTTPProxyHandler::EnterState(HTTPProxyHandler::state nstate) + void HTTPReqHandler::EnterState(HTTPReqHandler::state nstate) { m_state = nstate; } - void HTTPProxyHandler::ExtractRequest() + void HTTPReqHandler::ExtractRequest() { LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url); std::string server=""; @@ -150,7 +147,7 @@ namespace proxy m_path = path; } - bool HTTPProxyHandler::ValidateHTTPRequest() + bool HTTPReqHandler::ValidateHTTPRequest() { if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" ) { @@ -161,7 +158,7 @@ namespace proxy return true; } - void HTTPProxyHandler::HandleJumpServices() + void HTTPReqHandler::HandleJumpServices() { static const char * helpermark1 = "?i2paddresshelper="; static const char * helpermark2 = "&i2paddresshelper="; @@ -193,7 +190,7 @@ namespace proxy m_path.erase(addressHelperPos); } - bool HTTPProxyHandler::IsI2PAddress() + bool HTTPReqHandler::IsI2PAddress() { auto pos = m_address.rfind (".i2p"); if (pos != std::string::npos && (pos+4) == m_address.length ()) @@ -203,7 +200,7 @@ namespace proxy return false; } - bool HTTPProxyHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len) + bool HTTPReqHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len) { ExtractRequest(); //TODO: parse earlier if (!ValidateHTTPRequest()) return false; @@ -258,7 +255,7 @@ namespace proxy return true; } - bool HTTPProxyHandler::HandleData(uint8_t *http_buff, std::size_t len) + bool HTTPReqHandler::HandleData(uint8_t *http_buff, std::size_t len) { while (len > 0) { @@ -309,7 +306,7 @@ namespace proxy return true; } - void HTTPProxyHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len) + void HTTPReqHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len) { LogPrint(eLogDebug, "HTTPProxy: sock recv: ", len, " bytes"); if(ecode) @@ -324,7 +321,7 @@ namespace proxy if (m_state == DONE) { LogPrint(eLogDebug, "HTTPProxy: requested: ", m_url); - GetOwner()->CreateStream (std::bind (&HTTPProxyHandler::HandleStreamRequestComplete, + GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1), m_address, m_port); } else @@ -333,14 +330,14 @@ namespace proxy } - void HTTPProxyHandler::SentHTTPFailed(const boost::system::error_code & ecode) + void HTTPReqHandler::SentHTTPFailed(const boost::system::error_code & ecode) { if (ecode) LogPrint (eLogError, "HTTPProxy: Closing socket after sending failure because: ", ecode.message ()); Terminate(); } - void HTTPProxyHandler::HandleStreamRequestComplete (std::shared_ptr stream) + void HTTPReqHandler::HandleStreamRequestComplete (std::shared_ptr stream) { if (stream) { @@ -358,14 +355,14 @@ namespace proxy } } - HTTPProxyServer::HTTPProxyServer(const std::string& address, int port, std::shared_ptr localDestination): + HTTPProxy::HTTPProxy(const std::string& address, int port, std::shared_ptr localDestination): TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()) { } - std::shared_ptr HTTPProxyServer::CreateHandler(std::shared_ptr socket) + std::shared_ptr HTTPProxy::CreateHandler(std::shared_ptr socket) { - return std::make_shared (this, socket); + return std::make_shared (this, socket); } -} -} +} // http +} // i2p diff --git a/HTTPProxy.h b/HTTPProxy.h index 0356adb5..29b997eb 100644 --- a/HTTPProxy.h +++ b/HTTPProxy.h @@ -1,25 +1,21 @@ #ifndef HTTP_PROXY_H__ #define HTTP_PROXY_H__ -namespace i2p -{ -namespace proxy -{ - class HTTPProxyServer: public i2p::client::TCPIPAcceptor +namespace i2p { +namespace proxy { + class HTTPProxy: public i2p::client::TCPIPAcceptor { public: - HTTPProxyServer(const std::string& address, int port, std::shared_ptr localDestination = nullptr); - ~HTTPProxyServer() {}; + HTTPProxy(const std::string& address, int port, std::shared_ptr localDestination = nullptr); + ~HTTPProxy() {}; protected: // Implements TCPIPAcceptor std::shared_ptr CreateHandler(std::shared_ptr socket); const char* GetName() { return "HTTP Proxy"; } }; - - typedef HTTPProxyServer HTTPProxy; -} -} +} // http +} // i2p #endif From 61868d97c4d3f3ab15aa1ff2b8f6a5f413cc6720 Mon Sep 17 00:00:00 2001 From: hagen Date: Fri, 27 May 2016 00:00:00 +0000 Subject: [PATCH 02/11] * HTTPProxy.cpp : migrate HTTPRequestFailed(), RedirectToJumpService() to new http classes --- HTTPProxy.cpp | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 6915274c..06753b78 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -20,6 +20,7 @@ #include "I2PEndian.h" #include "I2PTunnel.h" #include "Config.h" +#include "HTTP.h" namespace i2p { namespace proxy { @@ -42,7 +43,7 @@ namespace proxy { void Terminate(); void AsyncSockRead(); void HTTPRequestFailed(const char *message); - void RedirectToJumpService(); + void RedirectToJumpService(std::string & host); void ExtractRequest(); bool IsI2PAddress(); bool ValidateHTTPRequest(); @@ -99,26 +100,33 @@ namespace proxy { //TODO: handle this apropriately void HTTPReqHandler::HTTPRequestFailed(const char *message) { - std::size_t size = std::strlen(message); - std::stringstream ss; - ss << "HTTP/1.0 500 Internal Server Error\r\n" - << "Content-Type: text/plain\r\n"; - ss << "Content-Length: " << std::to_string(size + 2) << "\r\n" - << "\r\n"; /* end of headers */ - ss << message << "\r\n"; - std::string response = ss.str(); + i2p::http::HTTPRes res; + res.code = 500; + res.add_header("Content-Type", "text/plain"); + res.add_header("Connection", "close"); + res.body = message; + res.body += "\r\n"; + std::string response = res.to_string(); boost::asio::async_write(*m_sock, boost::asio::buffer(response, response.size()), std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } - void HTTPReqHandler::RedirectToJumpService(/*HTTPReqHandler::errTypes error*/) + void HTTPReqHandler::RedirectToJumpService(std::string & host) { - std::stringstream response; - std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); - uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); + i2p::http::HTTPRes res; + i2p::http::URL url; - response << "HTTP/1.1 302 Found\r\nLocation: http://" << httpAddr << ":" << httpPort << "/?page=jumpservices&address=" << m_address << "\r\n\r\n"; - boost::asio::async_write(*m_sock, boost::asio::buffer(response.str (),response.str ().length ()), + i2p::config::GetOption("http.address", url.host); + i2p::config::GetOption("http.port", url.port); + url.path = "/"; + url.query = "page=jumpservices&address="; + url.query += host; + + res.code = 302; /* redirect */ + res.add_header("Location", url.to_string().c_str()); + + std::string response = res.to_string(); + boost::asio::async_write(*m_sock, boost::asio::buffer(response, response.length()), std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } @@ -210,7 +218,7 @@ namespace proxy { if (IsI2PAddress ()) { if (!i2p::client::context.GetAddressBook ().GetIdentHash (m_address, identHash)){ - RedirectToJumpService(); + RedirectToJumpService(m_address); return false; } } From 0de1e2c6fc6b8592b9db4a3c27751ec28e5e242b Mon Sep 17 00:00:00 2001 From: hagen Date: Fri, 27 May 2016 00:00:00 +0000 Subject: [PATCH 03/11] * HTTPProxy.cpp : extract IsI2PAddress() from class and generalize --- HTTPProxy.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 06753b78..cbbd66c4 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -24,6 +24,15 @@ namespace i2p { namespace proxy { + bool str_rmatch(std::string & str, const char *suffix) { + auto pos = str.rfind (suffix); + if (pos == std::string::npos) + return false; /* not found */ + if (str.length() == (pos + std::strlen(suffix))) + return true; /* match */ + return false; + } + static const size_t http_buffer_size = 8192; class HTTPReqHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this { @@ -45,7 +54,6 @@ namespace proxy { void HTTPRequestFailed(const char *message); void RedirectToJumpService(std::string & host); void ExtractRequest(); - bool IsI2PAddress(); bool ValidateHTTPRequest(); void HandleJumpServices(); bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len); @@ -198,16 +206,6 @@ namespace proxy { m_path.erase(addressHelperPos); } - bool HTTPReqHandler::IsI2PAddress() - { - auto pos = m_address.rfind (".i2p"); - if (pos != std::string::npos && (pos+4) == m_address.length ()) - { - return true; - } - return false; - } - bool HTTPReqHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len) { ExtractRequest(); //TODO: parse earlier @@ -215,14 +213,13 @@ namespace proxy { HandleJumpServices(); i2p::data::IdentHash identHash; - if (IsI2PAddress ()) + if (str_rmatch(m_address, ".i2p")) { if (!i2p::client::context.GetAddressBook ().GetIdentHash (m_address, identHash)){ RedirectToJumpService(m_address); return false; } } - m_request = m_method; m_request.push_back(' '); @@ -335,7 +332,6 @@ namespace proxy { else AsyncSockRead(); } - } void HTTPReqHandler::SentHTTPFailed(const boost::system::error_code & ecode) From 2bf32fb3fadd82ccefaf4bdb7e664d42f51e797d Mon Sep 17 00:00:00 2001 From: hagen Date: Fri, 27 May 2016 00:00:00 +0000 Subject: [PATCH 04/11] * HTTPProxy.cpp : kill ExtractRequest(), drop boost::regex --- HTTPProxy.cpp | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index cbbd66c4..2001f620 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -1,7 +1,5 @@ #include #include -#include -#include #include #include #include @@ -53,7 +51,6 @@ namespace proxy { void AsyncSockRead(); void HTTPRequestFailed(const char *message); void RedirectToJumpService(std::string & host); - void ExtractRequest(); bool ValidateHTTPRequest(); void HandleJumpServices(); bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len); @@ -143,26 +140,6 @@ namespace proxy { m_state = nstate; } - void HTTPReqHandler::ExtractRequest() - { - LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url); - std::string server=""; - std::string port="80"; - boost::regex rHTTP("http://(.*?)(:(\\d+))?(/.*)"); - boost::smatch m; - std::string path; - if(boost::regex_search(m_url, m, rHTTP, boost::match_extra)) - { - server=m[1].str(); - if (m[2].str() != "") port=m[3].str(); - path=m[4].str(); - } - LogPrint(eLogDebug, "HTTPProxy: server: ", server, ", port: ", port, ", path: ", path); - m_address = server; - m_port = boost::lexical_cast(port); - m_path = path; - } - bool HTTPReqHandler::ValidateHTTPRequest() { if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" ) @@ -208,7 +185,11 @@ namespace proxy { bool HTTPReqHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len) { - ExtractRequest(); //TODO: parse earlier + i2p::http::URL url; + url.parse(m_url); + m_address = url.host; /* < compatibility */ + m_port = url.port; /* < compatibility */ + m_path = url.path; /* < compatibility */ if (!ValidateHTTPRequest()) return false; HandleJumpServices(); From 5c9a69e0e81fdb759d91bb42c0e2ab130f631099 Mon Sep 17 00:00:00 2001 From: hagen Date: Fri, 27 May 2016 00:00:00 +0000 Subject: [PATCH 05/11] * drop boost_regex from build deps --- .travis.yml | 1 - Makefile.bsd | 2 +- Makefile.homebrew | 2 +- Makefile.linux | 3 +-- Makefile.mingw | 1 - Makefile.osx | 2 +- Reseed.cpp | 1 - appveyor.yml | 2 +- build/CMakeLists.txt | 2 +- build/Dockerfile | 2 +- debian/control | 1 - docs/build_notes_cross.md | 2 +- docs/build_notes_unix.md | 1 - docs/build_notes_windows.md | 4 ++-- stdafx.h | 1 - 15 files changed, 10 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index c791187d..d83cdbc0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,6 @@ addons: - libboost-date-time-dev - libboost-filesystem-dev - libboost-program-options-dev - - libboost-regex-dev - libboost-system-dev - libboost-thread-dev - libminiupnpc-dev diff --git a/Makefile.bsd b/Makefile.bsd index 255233f1..d6871f07 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -9,4 +9,4 @@ CXXFLAGS = -O2 NEEDED_CXXFLAGS = -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 INCFLAGS = -I/usr/include/ -I/usr/local/include/ LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread +LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread diff --git a/Makefile.homebrew b/Makefile.homebrew index 163b7950..6ce513fe 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -6,7 +6,7 @@ CXX = clang++ CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include LDFLAGS = -L${SSLROOT}/lib -L${BOOSTROOT}/lib -LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread +LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread ifeq ($(USE_UPNP),1) LDFLAGS += -ldl diff --git a/Makefile.linux b/Makefile.linux index 791382c6..70307267 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -32,7 +32,6 @@ ifeq ($(USE_STATIC),yes) LDLIBS = $(LIBDIR)/libboost_system.a LDLIBS += $(LIBDIR)/libboost_date_time.a LDLIBS += $(LIBDIR)/libboost_filesystem.a - LDLIBS += $(LIBDIR)/libboost_regex.a LDLIBS += $(LIBDIR)/libboost_program_options.a LDLIBS += $(LIBDIR)/libcrypto.a LDLIBS += $(LIBDIR)/libssl.a @@ -40,7 +39,7 @@ ifeq ($(USE_STATIC),yes) LDLIBS += -lpthread -static-libstdc++ -static-libgcc USE_AESNI := no else - LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread + LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread endif # UPNP Support (miniupnpc 1.5 or 1.6) diff --git a/Makefile.mingw b/Makefile.mingw index 5fe3c479..0390d66a 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -13,7 +13,6 @@ LDLIBS = \ -Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \ - -Wl,-Bstatic -lboost_regex$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_program_options$(BOOST_SUFFIX) \ -Wl,-Bstatic -lssl \ -Wl,-Bstatic -lcrypto \ diff --git a/Makefile.osx b/Makefile.osx index 71f95a7f..ef236c9a 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -3,7 +3,7 @@ CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX #CXXFLAGS = -g -O2 -Wall -std=c++11 INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/usr/local/ssl/lib -LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread +LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread ifeq ($(USE_UPNP),1) LDFLAGS += -ldl diff --git a/Reseed.cpp b/Reseed.cpp index ddefc460..6f27891d 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include diff --git a/appveyor.yml b/appveyor.yml index 6600714d..6018bea0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -125,7 +125,7 @@ install: - cd %BOOST_ROOT% - if defined msvc if not exist "stage%bitness%\lib\%boostlib%boost_system-vc%msvc%0-mt%boostdbg%*" ( bootstrap > c:\projects\instdir\build_boost.log - && b2 toolset=msvc-%msvc%.0 %boost_variant% link=%type% runtime-link=%type% address-model=%bitness% --build-type=minimal --with-filesystem --with-program_options --with-regex --with-date_time --stagedir=stage%bitness% >> c:\projects\instdir\build_boost.log + && b2 toolset=msvc-%msvc%.0 %boost_variant% link=%type% runtime-link=%type% address-model=%bitness% --build-type=minimal --with-filesystem --with-program_options --with-date_time --stagedir=stage%bitness% >> c:\projects\instdir\build_boost.log || type c:\projects\instdir\build_boost.log ) - if defined msvc if not exist C:\stage\OpenSSL-Win%bitness%-vc%msvc%-%type%\ ( diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 7944e2ec..4a1bfe2b 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -242,7 +242,7 @@ endif() target_link_libraries(i2pdclient libi2pd) -find_package ( Boost COMPONENTS system filesystem regex program_options date_time REQUIRED ) +find_package ( Boost COMPONENTS system filesystem program_options date_time REQUIRED ) if(NOT DEFINED Boost_INCLUDE_DIRS) message(SEND_ERROR "Boost is not found, or your boost version was bellow 1.46. Please download Boost!") endif() diff --git a/build/Dockerfile b/build/Dockerfile index f570bd79..751fe956 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,7 +1,7 @@ FROM ubuntu RUN apt-get update && apt-get install -y libboost-dev libboost-filesystem-dev \ - libboost-program-options-dev libboost-regex-dev libboost-date-time-dev \ + libboost-program-options-dev libboost-date-time-dev \ libssl-dev git build-essential RUN git clone https://github.com/PurpleI2P/i2pd.git diff --git a/debian/control b/debian/control index ceca7a5f..78906ba4 100644 --- a/debian/control +++ b/debian/control @@ -4,7 +4,6 @@ Priority: extra Maintainer: hagen Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~), gcc (>= 4.7) | clang (>= 3.3), - libboost-regex-dev, libboost-system-dev (>= 1.46), libboost-date-time-dev, libboost-filesystem-dev, diff --git a/docs/build_notes_cross.md b/docs/build_notes_cross.md index d819ba34..78d60e6a 100644 --- a/docs/build_notes_cross.md +++ b/docs/build_notes_cross.md @@ -22,7 +22,7 @@ Proceed with building Boost normal way, but let's define dedicated staging direc ```sh ./bootstrap.sh ./b2 toolset=gcc-mingw target-os=windows variant=release link=static runtime-link=static address-model=64 \ - --build-type=minimal --with-filesystem --with-program_options --with-regex --with-date_time \ + --build-type=minimal --with-filesystem --with-program_options --with-date_time \ --stagedir=stage-mingw-64 cd .. ``` diff --git a/docs/build_notes_unix.md b/docs/build_notes_unix.md index 05605343..cdde1ee7 100644 --- a/docs/build_notes_unix.md +++ b/docs/build_notes_unix.md @@ -46,7 +46,6 @@ sudo apt-get install \ libboost-date-time-dev \ libboost-filesystem-dev \ libboost-program-options-dev \ - libboost-regex-dev \ libboost-system-dev \ libboost-thread-dev \ libssl-dev diff --git a/docs/build_notes_windows.md b/docs/build_notes_windows.md index 81e0dfc2..921a6110 100644 --- a/docs/build_notes_windows.md +++ b/docs/build_notes_windows.md @@ -110,11 +110,11 @@ prompt to build Boost) and run the following: cd C:\dev\boost bootstrap - b2 toolset=msvc-12.0 --build-type=complete --with-filesystem --with-program_options --with-regex --with-date_time + b2 toolset=msvc-12.0 --build-type=complete --with-filesystem --with-program_options --with-date_time If you are on 64-bit Windows and you want to build 64-bit version as well - b2 toolset=msvc-12.0 --build-type=complete --stagedir=stage64 address-model=64 --with-filesystem --with-program_options --with-regex --with-date_time + b2 toolset=msvc-12.0 --build-type=complete --stagedir=stage64 address-model=64 --with-filesystem --with-program_options --with-date_time After Boost is compiled, set the environment variable `BOOST_ROOT` to the directory Boost was unpacked to, e.g., C:\dev\boost. diff --git a/stdafx.h b/stdafx.h index ed13bf8b..42490354 100644 --- a/stdafx.h +++ b/stdafx.h @@ -33,7 +33,6 @@ #include #include -#include #include #include #include From a5f49550b3c6a010b7cc933c5cab628f6fced3f9 Mon Sep 17 00:00:00 2001 From: hagen Date: Fri, 27 May 2016 00:00:00 +0000 Subject: [PATCH 06/11] * HTTPProxy.cpp : unwrap AsyncSockRead() --- HTTPProxy.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 2001f620..42e4fc72 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -81,13 +81,13 @@ namespace proxy { void HTTPReqHandler::AsyncSockRead() { LogPrint(eLogDebug, "HTTPProxy: async sock read"); - if(m_sock) { - m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size), - std::bind(&HTTPReqHandler::HandleSockRecv, shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); - } else { + if (!m_sock) { LogPrint(eLogError, "HTTPProxy: no socket for read"); + return; } + m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size), + std::bind(&HTTPReqHandler::HandleSockRecv, shared_from_this(), + std::placeholders::_1, std::placeholders::_2)); } void HTTPReqHandler::Terminate() { From dba7a2ee4f32ac6d2b0c4ed01a73150c0f42a132 Mon Sep 17 00:00:00 2001 From: hagen Date: Fri, 27 May 2016 00:00:00 +0000 Subject: [PATCH 07/11] * HTTPProxy.cpp : HandleJumpServices() -> ExtractAddressHelper() --- HTTPProxy.cpp | 57 +++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 42e4fc72..884d2521 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -52,7 +52,7 @@ namespace proxy { void HTTPRequestFailed(const char *message); void RedirectToJumpService(std::string & host); bool ValidateHTTPRequest(); - void HandleJumpServices(); + bool ExtractAddressHelper(i2p::http::URL & url, std::string & b64); bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len); void SentHTTPFailed(const boost::system::error_code & ecode); void HandleStreamRequestComplete (std::shared_ptr stream); @@ -123,12 +123,14 @@ namespace proxy { i2p::config::GetOption("http.address", url.host); i2p::config::GetOption("http.port", url.port); + url.schema = "http"; url.path = "/"; url.query = "page=jumpservices&address="; url.query += host; res.code = 302; /* redirect */ res.add_header("Location", url.to_string().c_str()); + res.add_header("Connection", "close"); std::string response = res.to_string(); boost::asio::async_write(*m_sock, boost::asio::buffer(response, response.length()), @@ -151,47 +153,40 @@ namespace proxy { return true; } - void HTTPReqHandler::HandleJumpServices() + bool HTTPReqHandler::ExtractAddressHelper(i2p::http::URL & url, std::string & b64) { - static const char * helpermark1 = "?i2paddresshelper="; - static const char * helpermark2 = "&i2paddresshelper="; - size_t addressHelperPos1 = m_path.rfind (helpermark1); - size_t addressHelperPos2 = m_path.rfind (helpermark2); - size_t addressHelperPos; - if (addressHelperPos1 == std::string::npos) - { - if (addressHelperPos2 == std::string::npos) - return; //Not a jump service - else - addressHelperPos = addressHelperPos2; - } - else - { - if (addressHelperPos2 == std::string::npos) - addressHelperPos = addressHelperPos1; - else if ( addressHelperPos1 > addressHelperPos2 ) - addressHelperPos = addressHelperPos1; - else - addressHelperPos = addressHelperPos2; - } - auto base64 = m_path.substr (addressHelperPos + strlen(helpermark1)); - base64 = i2p::util::http::urlDecode(base64); //Some of the symbols may be urlencoded - LogPrint (eLogInfo, "HTTPProxy: jump service for ", m_address, ", inserting to address book"); - //TODO: this is very dangerous and broken. We should ask the user before doing anything see http://pastethis.i2p/raw/pn5fL4YNJL7OSWj3Sc6N/ - //TODO: we could redirect the user again to avoid dirtiness in the browser - i2p::client::context.GetAddressBook ().InsertAddress (m_address, base64); - m_path.erase(addressHelperPos); + const char *param = "i2paddresshelper="; + std::size_t pos = url.query.find(param); + std::size_t len = std::strlen(param); + std::map params; + + if (pos == std::string::npos) + return false; /* not found */ + if (!url.parse_query(params)) + return false; + + std::string value = params["i2paddresshelper"]; + len += value.length(); + b64 = i2p::http::UrlDecode(value); + url.query.replace(pos, len, ""); + return true; } bool HTTPReqHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len) { + std::string b64; i2p::http::URL url; url.parse(m_url); m_address = url.host; /* < compatibility */ m_port = url.port; /* < compatibility */ m_path = url.path; /* < compatibility */ if (!ValidateHTTPRequest()) return false; - HandleJumpServices(); + + /* TODO: notify user */ + if (ExtractAddressHelper(url, b64)) { + i2p::client::context.GetAddressBook ().InsertAddress (url.host, b64); + LogPrint (eLogInfo, "HTTPProxy: added b64 from addresshelper for ", url.host, " to address book"); + } i2p::data::IdentHash identHash; if (str_rmatch(m_address, ".i2p")) From 4098a5c08e636d786f68b22e94e8e7996f095380 Mon Sep 17 00:00:00 2001 From: hagen Date: Fri, 27 May 2016 00:00:00 +0000 Subject: [PATCH 08/11] * HTTPProxy.cpp : rename variable --- HTTPProxy.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 884d2521..bd03a6a6 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -31,7 +31,6 @@ namespace proxy { return false; } - static const size_t http_buffer_size = 8192; class HTTPReqHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this { private: @@ -57,7 +56,7 @@ namespace proxy { void SentHTTPFailed(const boost::system::error_code & ecode); void HandleStreamRequestComplete (std::shared_ptr stream); - uint8_t m_http_buff[http_buffer_size]; + uint8_t m_downstream_recv_buf[8192]; std::shared_ptr m_sock; std::string m_request; //Data left to be sent std::string m_Response; @@ -85,7 +84,7 @@ namespace proxy { LogPrint(eLogError, "HTTPProxy: no socket for read"); return; } - m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size), + m_sock->async_receive(boost::asio::buffer(m_downstream_recv_buf, sizeof(m_downstream_recv_buf)), std::bind(&HTTPReqHandler::HandleSockRecv, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } @@ -297,7 +296,7 @@ namespace proxy { return; } - if (HandleData(m_http_buff, len)) + if (HandleData(m_downstream_recv_buf, len)) { if (m_state == DONE) { From a9f3235fd3f1163eeb97329c1749887aa3bd9e22 Mon Sep 17 00:00:00 2001 From: hagen Date: Fri, 27 May 2016 00:00:00 +0000 Subject: [PATCH 09/11] * HTTPProxy.cpp : unwrap HandleStreamRequestComplete() --- HTTPProxy.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index bd03a6a6..7150e14f 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -318,20 +318,18 @@ namespace proxy { void HTTPReqHandler::HandleStreamRequestComplete (std::shared_ptr stream) { - if (stream) - { - if (Kill()) return; - LogPrint (eLogInfo, "HTTPProxy: New I2PTunnel connection"); - auto connection = std::make_shared(GetOwner(), m_sock, stream); - GetOwner()->AddHandler (connection); - connection->I2PConnect (reinterpret_cast(m_request.data()), m_request.size()); - Done(shared_from_this()); - } - else - { + if (!stream) { LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info"); HTTPRequestFailed("error when creating the stream, check logs"); + return; } + if (Kill()) + return; + LogPrint (eLogDebug, "HTTPProxy: New I2PTunnel connection"); + auto connection = std::make_shared(GetOwner(), m_sock, stream); + GetOwner()->AddHandler (connection); + connection->I2PConnect (reinterpret_cast(m_request.data()), m_request.size()); + Done (shared_from_this()); } HTTPProxy::HTTPProxy(const std::string& address, int port, std::shared_ptr localDestination): From 347157b9992a07290bb45e815398a27106e43333 Mon Sep 17 00:00:00 2001 From: hagen Date: Fri, 27 May 2016 00:00:00 +0000 Subject: [PATCH 10/11] * HTTPProxy.cpp : direct use of parsed url parts in CreateHTTPRequest() --- HTTPProxy.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 7150e14f..43ee8631 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -188,10 +188,10 @@ namespace proxy { } i2p::data::IdentHash identHash; - if (str_rmatch(m_address, ".i2p")) + if (str_rmatch(url.host, ".i2p")) { - if (!i2p::client::context.GetAddressBook ().GetIdentHash (m_address, identHash)){ - RedirectToJumpService(m_address); + if (!i2p::client::context.GetAddressBook ().GetIdentHash (url.host, identHash)){ + RedirectToJumpService(url.host); return false; } } From d0ffaab339b6aa21d5f4ec4be2b71c7e5e051ecb Mon Sep 17 00:00:00 2001 From: hagen Date: Fri, 27 May 2016 00:00:00 +0000 Subject: [PATCH 11/11] * HTTPProxy: * use new http classes instead homemade parser * proper error handling for "address not found", "addresshelper" and "not .i2p domain" cases * use std::vector instead uint8_t[] for buffers * general code cleanup --- HTTPProxy.cpp | 221 +++++++++++++++----------------------------------- 1 file changed, 66 insertions(+), 155 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 43ee8631..cc534470 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -34,45 +34,26 @@ namespace proxy { class HTTPReqHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this { private: - enum state - { - GET_METHOD, - GET_HOSTNAME, - GET_HTTPV, - GET_HTTPVNL, //TODO: fallback to finding HOst: header if needed - DONE - }; - - void EnterState(state nstate); - bool HandleData(uint8_t *http_buff, std::size_t len); + + bool HandleRequest(std::size_t len); void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); void Terminate(); void AsyncSockRead(); void HTTPRequestFailed(const char *message); void RedirectToJumpService(std::string & host); - bool ValidateHTTPRequest(); bool ExtractAddressHelper(i2p::http::URL & url, std::string & b64); - bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len); + void SanitizeHTTPRequest(i2p::http::HTTPReq & req); void SentHTTPFailed(const boost::system::error_code & ecode); void HandleStreamRequestComplete (std::shared_ptr stream); - uint8_t m_downstream_recv_buf[8192]; std::shared_ptr m_sock; - std::string m_request; //Data left to be sent - std::string m_Response; - std::string m_url; //URL - std::string m_method; //Method - std::string m_version; //HTTP version - std::string m_address; //Address - std::string m_path; //Path - int m_port; //Port - state m_state;//Parsing state + std::vector m_recv_buf; /* as "downstream recieve buffer", from client to me */ + std::vector m_send_buf; /* as "upstream send buffer", from me to remote host */ public: HTTPReqHandler(HTTPProxy * parent, std::shared_ptr sock) : - I2PServiceHandler(parent), m_sock(sock) - { EnterState(GET_METHOD); } + I2PServiceHandler(parent), m_sock(sock), m_recv_buf(8192), m_send_buf(0) {}; ~HTTPReqHandler() { Terminate(); } void Handle () { AsyncSockRead(); } }; @@ -84,7 +65,7 @@ namespace proxy { LogPrint(eLogError, "HTTPProxy: no socket for read"); return; } - m_sock->async_receive(boost::asio::buffer(m_downstream_recv_buf, sizeof(m_downstream_recv_buf)), + m_sock->async_receive(boost::asio::buffer(m_recv_buf), std::bind(&HTTPReqHandler::HandleSockRecv, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } @@ -100,8 +81,6 @@ namespace proxy { Done(shared_from_this()); } - /* All hope is lost beyond this point */ - //TODO: handle this apropriately void HTTPReqHandler::HTTPRequestFailed(const char *message) { i2p::http::HTTPRes res; @@ -136,22 +115,6 @@ namespace proxy { std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } - void HTTPReqHandler::EnterState(HTTPReqHandler::state nstate) - { - m_state = nstate; - } - - bool HTTPReqHandler::ValidateHTTPRequest() - { - if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" ) - { - LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version); - HTTPRequestFailed("unsupported HTTP version"); - return false; - } - return true; - } - bool HTTPReqHandler::ExtractAddressHelper(i2p::http::URL & url, std::string & b64) { const char *param = "i2paddresshelper="; @@ -171,118 +134,74 @@ namespace proxy { return true; } - bool HTTPReqHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len) + void HTTPReqHandler::SanitizeHTTPRequest(i2p::http::HTTPReq & req) { - std::string b64; + req.del_header("Referer"); + req.add_header("Connection", "close", true); + req.add_header("User-Agent", "MYOB/6.66 (AN/ON)", true); + } + + /** + * @param len length of data in m_recv_buf + * @return true on processed request or false if more data needed + */ + bool HTTPReqHandler::HandleRequest(std::size_t len) + { + i2p::http::HTTPReq req; i2p::http::URL url; - url.parse(m_url); - m_address = url.host; /* < compatibility */ - m_port = url.port; /* < compatibility */ - m_path = url.path; /* < compatibility */ - if (!ValidateHTTPRequest()) return false; + std::string b64; + + int req_len = 0; + + req_len = req.parse((const char *) m_recv_buf.data(), len); + if (req_len == 0) + return false; /* need more data */ + if (req_len < 0) { + LogPrint(eLogError, "HTTPProxy: unable to parse request"); + HTTPRequestFailed("invalid request"); + return true; /* parse error */ + } + + /* parsing success, now let's look inside request */ + LogPrint(eLogDebug, "HTTPProxy: requested: ", req.uri); + url.parse(req.uri); - /* TODO: notify user */ if (ExtractAddressHelper(url, b64)) { i2p::client::context.GetAddressBook ().InsertAddress (url.host, b64); - LogPrint (eLogInfo, "HTTPProxy: added b64 from addresshelper for ", url.host, " to address book"); + std::string message = "added b64 from addresshelper for " + url.host + " to address book"; + LogPrint (eLogInfo, "HTTPProxy: ", message); + message += ", please reload page"; + HTTPRequestFailed(message.c_str()); + return true; /* request processed */ } i2p::data::IdentHash identHash; - if (str_rmatch(url.host, ".i2p")) - { - if (!i2p::client::context.GetAddressBook ().GetIdentHash (url.host, identHash)){ + if (str_rmatch(url.host, ".i2p")) { + if (!i2p::client::context.GetAddressBook ().GetIdentHash (url.host, identHash)) { RedirectToJumpService(url.host); - return false; + return true; /* request processed */ } + /* TODO: outproxy handler here */ + } else { + std::string message = "Host " + url.host + " not inside i2p network, but outproxy support still missing"; + HTTPRequestFailed(message.c_str()); + LogPrint (eLogWarning, "HTTPProxy: ", message); + return true; } + SanitizeHTTPRequest(req); - m_request = m_method; - m_request.push_back(' '); - m_request += m_path; - m_request.push_back(' '); - m_request += m_version; - m_request.push_back('\r'); - m_request.push_back('\n'); - m_request.append("Connection: close\r\n"); - // TODO: temporary shortcut. Must be implemented properly - uint8_t * eol = nullptr; - bool isEndOfHeader = false; - while (!isEndOfHeader && len && (eol = (uint8_t *)memchr (http_buff, '\r', len))) - { - if (eol) - { - *eol = 0; eol++; - if (strncmp ((const char *)http_buff, "Referer", 7) && strncmp ((const char *)http_buff, "Connection", 10)) // strip out referer and connection - { - if (!strncmp ((const char *)http_buff, "User-Agent", 10)) // replace UserAgent - m_request.append("User-Agent: MYOB/6.66 (AN/ON)"); - else - m_request.append ((const char *)http_buff); - m_request.append ("\r\n"); - } - isEndOfHeader = !http_buff[0]; - auto l = eol - http_buff; - http_buff = eol; - len -= l; - if (len > 0) // \r - { - http_buff++; - len--; - } - } - } - m_request.append(reinterpret_cast(http_buff),len); - return true; - } + /* drop original request from input buffer */ + m_recv_buf.erase(m_recv_buf.begin(), m_recv_buf.begin() + req_len); + + /* build new buffer from modified request and data from original request */ + std::string request = req.to_string(); + m_send_buf.assign(request.begin(), request.end()); + m_send_buf.insert(m_send_buf.end(), m_recv_buf.begin(), m_recv_buf.end()); + + /* connect to destination */ + GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete, + shared_from_this(), std::placeholders::_1), url.host, url.port); - bool HTTPReqHandler::HandleData(uint8_t *http_buff, std::size_t len) - { - while (len > 0) - { - //TODO: fallback to finding HOst: header if needed - switch (m_state) - { - case GET_METHOD: - switch (*http_buff) - { - case ' ': EnterState(GET_HOSTNAME); break; - default: m_method.push_back(*http_buff); break; - } - break; - case GET_HOSTNAME: - switch (*http_buff) - { - case ' ': EnterState(GET_HTTPV); break; - default: m_url.push_back(*http_buff); break; - } - break; - case GET_HTTPV: - switch (*http_buff) - { - case '\r': EnterState(GET_HTTPVNL); break; - default: m_version.push_back(*http_buff); break; - } - break; - case GET_HTTPVNL: - switch (*http_buff) - { - case '\n': EnterState(DONE); break; - default: - LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff)); - HTTPRequestFailed("rejected invalid request"); - return false; - } - break; - default: - LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state); - HTTPRequestFailed("invalid parser state"); - return false; - } - http_buff++; - len--; - if (m_state == DONE) - return CreateHTTPRequest(http_buff,len); - } return true; } @@ -296,17 +215,9 @@ namespace proxy { return; } - if (HandleData(m_downstream_recv_buf, len)) - { - if (m_state == DONE) - { - LogPrint(eLogDebug, "HTTPProxy: requested: ", m_url); - GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete, - shared_from_this(), std::placeholders::_1), m_address, m_port); - } - else - AsyncSockRead(); - } + if (HandleRequest(len)) + return; /* request processed */ + AsyncSockRead(); } void HTTPReqHandler::SentHTTPFailed(const boost::system::error_code & ecode) @@ -328,7 +239,7 @@ namespace proxy { LogPrint (eLogDebug, "HTTPProxy: New I2PTunnel connection"); auto connection = std::make_shared(GetOwner(), m_sock, stream); GetOwner()->AddHandler (connection); - connection->I2PConnect (reinterpret_cast(m_request.data()), m_request.size()); + connection->I2PConnect (m_send_buf.data(), m_send_buf.size()); Done (shared_from_this()); }