diff --git a/example/config.jsonc b/example/config.jsonc index f0e7faf..ee5d051 100644 --- a/example/config.jsonc +++ b/example/config.jsonc @@ -12,6 +12,22 @@ // this address should be local (127.0.0.1). Other configurations are not supported. "forward_address": "127.0.0.1:3000", + // if you want to separate domains, you can set up proxy rules for Host -> dest + // if none match, forward_address will be used. + "proxy_rules": [ + { + // If there is a port specified, it will have to match. + // If there is no port specified, it's any port. + "host": "myepic.domain.com:80", + "destination": "127.0.0.1:8080" + }, + { + // Anything to myepic.domain.com that isn't myepic.domain.com:80 goes to 127.0.0.1:8081 + "host": "myepic.domain.com", + "destination": "127.0.0.1:8081" + } + ], + // max request size of 10MB "max_request_size": 10000000, diff --git a/src/config/Config.hpp b/src/config/Config.hpp index ed66bee..bf36cae 100644 --- a/src/config/Config.hpp +++ b/src/config/Config.hpp @@ -19,6 +19,11 @@ class CConfig { std::string resource = ""; }; + struct SProxyRule { + std::string host = ""; + std::string destination = ""; + }; + struct SConfig { int port = 3001; std::string forward_address = "127.0.0.1:3000"; @@ -31,6 +36,7 @@ class CConfig { std::vector rules = {}; int default_challenge_difficulty = 4; bool async_proxy = true; + std::vector proxy_rules; } m_config; struct { diff --git a/src/core/Handler.cpp b/src/core/Handler.cpp index 5f8e111..721f91c 100644 --- a/src/core/Handler.cpp +++ b/src/core/Handler.cpp @@ -204,12 +204,9 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt if (g_pConfig->m_config.git_host) { // TODO: ratelimit this, probably. - const auto RES = req.resource(); - bool validGitResource = - RES.ends_with("/info/refs") || RES.ends_with("/info/packs") || - RES.ends_with("HEAD") || RES.ends_with(".git") || - RES.ends_with("/git-upload-pack") || - RES.ends_with("/git-receive-pack"); + const auto RES = req.resource(); + bool validGitResource = RES.ends_with("/info/refs") || RES.ends_with("/info/packs") || RES.ends_with("HEAD") || RES.ends_with(".git") || + RES.ends_with("/git-upload-pack") || RES.ends_with("/git-receive-pack"); if (RES.contains("/objects/")) { const std::string_view repo = std::string_view{RES}.substr(0, RES.find("/objects/")); @@ -253,8 +250,7 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt Debug::log(LOG, " | Action: CHALLENGE (rule)"); challengeDifficulty = ic.difficulty.value_or(g_pConfig->m_config.default_challenge_difficulty); break; - default: - Debug::log(LOG, " | Invalid rule found (no action) skipping"); + default: Debug::log(LOG, " | Invalid rule found (no action) skipping"); } if (ic.action == IP_ACTION_CHALLENGE) @@ -369,9 +365,9 @@ void CServerHandler::serveStop(const Pistache::Http::Request& req, Pistache::Htt const auto NONCE = generateNonce(); const auto CHALLENGE = CChallenge(fingerprintForRequest(req), NONCE, difficulty); - auto hostDomain = req.headers().getRaw("Host").value(); + auto hostDomain = req.headers().getRaw("Host").value(); if (hostDomain.contains(":")) - hostDomain = hostDomain.substr(0, hostDomain.find(':')); + hostDomain = hostDomain.substr(0, hostDomain.find(':')); page.add("challengeDifficulty", CTinylatesProp(std::to_string(difficulty))); page.add("challengeNonce", CTinylatesProp(NONCE)); @@ -417,14 +413,27 @@ void CServerHandler::proxyPassAsync(const Pistache::Http::Request& req, Pistache } void CServerHandler::proxyPassInternal(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response, bool async) { - const std::string FORWARD_ADDR = g_pConfig->m_config.forward_address; + std::string forwardAddress = g_pConfig->m_config.forward_address; + const auto HOST = Pistache::Http::Header::header_cast(req.headers().get("Host")); - Debug::log(TRACE, "Method ({}): Forwarding to {}", (uint32_t)req.method(), FORWARD_ADDR + req.resource()); + for (const auto& R : g_pConfig->m_config.proxy_rules) { + if (R.host.contains(":")) { + if (R.host == HOST->host() + ":" + std::to_string(HOST->port())) { + forwardAddress = R.destination; + break; + } + } else if (HOST->host() == R.host) { + forwardAddress = R.destination; + break; + } + } + + Debug::log(TRACE, "Method ({}): Forwarding to {}", (uint32_t)req.method(), forwardAddress + req.resource()); Pistache::Http::Experimental::Client client; client.init(Pistache::Http::Experimental::Client::options().maxConnectionsPerHost(32).maxResponseSize(g_pConfig->m_config.max_request_size).threads(4)); - auto builder = client.prepareRequest(FORWARD_ADDR + req.resource(), req.method()); + auto builder = client.prepareRequest(forwardAddress + req.resource(), req.method()); builder.body(req.body()); for (auto it = req.cookies().begin(); it != req.cookies().end(); ++it) { builder.cookie(*it);