diff --git a/libabyss/include/abyss/server.hpp b/libabyss/include/abyss/server.hpp index b0f52441a..2c3192610 100644 --- a/libabyss/include/abyss/server.hpp +++ b/libabyss/include/abyss/server.hpp @@ -37,6 +37,10 @@ namespace abyss bool ShouldClose(llarp_time_t now) const; + /// return true if the host header is correct + virtual bool + ValidateHost(const std::string& host) const = 0; + private: ConnImpl* m_Impl; }; diff --git a/libabyss/src/client.cpp b/libabyss/src/client.cpp index dba23ba42..a5e712ca5 100644 --- a/libabyss/src/client.cpp +++ b/libabyss/src/client.cpp @@ -192,6 +192,7 @@ namespace abyss authgen << ", " << opt.first << "=" << opt.second; } m_SendHeaders.clear(); + m_SendHeaders.emplace("Host", "localhost"); m_SendHeaders.emplace("Authorization", authgen.str()); SendRequest(); return true; @@ -320,6 +321,7 @@ namespace abyss std::string body; std::stringstream ss; body = m_RequestBody.dump(); + m_SendHeaders.emplace("Host", "localhost"); m_SendHeaders.emplace("Content-Type", "application/json"); m_SendHeaders.emplace("Content-Length", std::to_string(body.size())); m_SendHeaders.emplace("Accept", "application/json"); diff --git a/libabyss/src/server.cpp b/libabyss/src/server.cpp index 58848488e..e85c29cdd 100644 --- a/libabyss/src/server.cpp +++ b/libabyss/src/server.cpp @@ -96,7 +96,8 @@ namespace abyss { // TODO: header whitelist return name == string_view("content-type") - || name == string_view("content-length"); + || name == string_view("content-length") + || name == string_view("host"); } bool @@ -162,6 +163,17 @@ namespace abyss { m_BodyParser.reset(json::MakeParser(contentLength)); } + itr = Header.Headers.find("host"); + if(itr == Header.Headers.end()) + { + return WriteResponseSimple(400, "Bad Request", "text/plain", + "no host header provided"); + } + if(not handler->ValidateHost(itr->second)) + { + return WriteResponseSimple(400, "Bad Request", "text/plain", + "invalid host header"); + } } if(!m_BodyParser->FeedData(buf, sz)) { diff --git a/llarp/rpc/rpc.cpp b/llarp/rpc/rpc.cpp index 1da0999a5..5b2b603a9 100644 --- a/llarp/rpc/rpc.cpp +++ b/llarp/rpc/rpc.cpp @@ -285,12 +285,16 @@ namespace llarp struct Handler : public ::abyss::httpd::IRPCHandler { + std::string expectedHostname; AbstractRouter* router; std::unordered_map< std::string, std::function< Response() > > m_dispatch; - Handler(::abyss::httpd::ConnImpl* conn, AbstractRouter* r) + Handler(::abyss::httpd::ConnImpl* conn, AbstractRouter* r, + std::string hostname) : ::abyss::httpd::IRPCHandler(conn) + , expectedHostname(std::move(hostname)) , router(r) , m_dispatch{ + {"llarp.admin.die", [=]() { return KillRouter(); }}, {"llarp.admin.wakeup", [=]() { return StartRouter(); }}, {"llarp.admin.link.neighbor", [=]() { return ListNeighbors(); }}, @@ -304,6 +308,12 @@ namespace llarp ~Handler() override = default; + bool + ValidateHost(const std::string& host) const override + { + return host == "localhost" || host == expectedHostname; + } + Response StartRouter() const { @@ -317,6 +327,15 @@ namespace llarp return router->ExtractStatus(); } + Response + KillRouter() const + { + if(not router->IsRunning()) + return {{"error", "already stopping"}}; + router->Stop(); + return {{"status", "OK"}}; + } + Response ListExitLevels() const { @@ -416,11 +435,15 @@ namespace llarp : ::abyss::httpd::BaseReqHandler(reqtimeout), router(r) { } + + std::string expectedHostname; + AbstractRouter* router; + ::abyss::httpd::IRPCHandler* CreateHandler(::abyss::httpd::ConnImpl* conn) override { - return new Handler(conn, router); + return new Handler(conn, router, expectedHostname); } }; @@ -447,15 +470,20 @@ namespace llarp sockaddr_in saddr; saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); saddr.sin_family = AF_INET; - saddr.sin_port = 0; + saddr.sin_port = 1190; auto idx = addr.find_first_of(':'); if(idx != std::string::npos) { + _handler.expectedHostname = addr.substr(0, idx); Addr netaddr{addr.substr(0, idx), addr.substr(1 + idx)}; saddr.sin_addr.s_addr = netaddr.ton(); saddr.sin_port = htons(netaddr.port()); } + else + { + _handler.expectedHostname = addr; + } return _handler.ServeAsync(router->netloop(), router->logic(), (const sockaddr*)&saddr); } diff --git a/test/test_libabyss.cpp b/test/test_libabyss.cpp index 2eb256bea..86a5da728 100644 --- a/test/test_libabyss.cpp +++ b/test/test_libabyss.cpp @@ -107,6 +107,12 @@ struct ServerHandler : public abyss::httpd::IRPCHandler { } + bool + ValidateHost(const std::string & /*hostname */) const override + { + return true; + } + Response HandleJSONRPC(Method_t method, const Params& /*params*/) {