handler: gather real ip for rules, check X-Real-IP

This commit is contained in:
Vaxry
2025-04-15 14:37:54 +01:00
parent a0577efed7
commit 15689ca20a
4 changed files with 60 additions and 19 deletions

View File

@@ -8,6 +8,7 @@
#include "../headers/gitProtocolHeader.hpp" #include "../headers/gitProtocolHeader.hpp"
#include "../headers/acceptLanguageHeader.hpp" #include "../headers/acceptLanguageHeader.hpp"
#include "../headers/setCookieHeader.hpp" #include "../headers/setCookieHeader.hpp"
#include "../headers/xrealip.hpp"
#include "../debug/log.hpp" #include "../debug/log.hpp"
#include "../GlobalState.hpp" #include "../GlobalState.hpp"
#include "../config/Config.hpp" #include "../config/Config.hpp"
@@ -57,17 +58,10 @@ std::string CServerHandler::fingerprintForRequest(const Pistache::Http::Request&
const auto HEADERS = req.headers(); const auto HEADERS = req.headers();
std::shared_ptr<const Pistache::Http::Header::AcceptEncoding> acceptEncodingHeader; std::shared_ptr<const Pistache::Http::Header::AcceptEncoding> acceptEncodingHeader;
std::shared_ptr<const Pistache::Http::Header::UserAgent> userAgentHeader; std::shared_ptr<const Pistache::Http::Header::UserAgent> userAgentHeader;
std::shared_ptr<const CFConnectingIPHeader> cfHeader;
std::shared_ptr<const AcceptLanguageHeader> languageHeader; std::shared_ptr<const AcceptLanguageHeader> languageHeader;
std::string input = "checkpoint-"; std::string input = "checkpoint-";
try {
cfHeader = Pistache::Http::Header::header_cast<CFConnectingIPHeader>(HEADERS.get("cf-connecting-ip"));
} catch (std::exception& e) {
; // silent ignore
}
try { try {
acceptEncodingHeader = Pistache::Http::Header::header_cast<Pistache::Http::Header::AcceptEncoding>(HEADERS.get("Accept-Encoding")); acceptEncodingHeader = Pistache::Http::Header::header_cast<Pistache::Http::Header::AcceptEncoding>(HEADERS.get("Accept-Encoding"));
} catch (std::exception& e) { } catch (std::exception& e) {
@@ -86,8 +80,7 @@ std::string CServerHandler::fingerprintForRequest(const Pistache::Http::Request&
; // silent ignore ; // silent ignore
} }
if (cfHeader) input += ipForRequest(req);
input += cfHeader->ip();
// TODO: those seem to change. Find better things to hash. // TODO: those seem to change. Find better things to hash.
// if (acceptEncodingHeader) // if (acceptEncodingHeader)
// input += HEADERS.getRaw("Accept-Encoding").value(); // input += HEADERS.getRaw("Accept-Encoding").value();
@@ -96,8 +89,6 @@ std::string CServerHandler::fingerprintForRequest(const Pistache::Http::Request&
if (userAgentHeader) if (userAgentHeader)
input += userAgentHeader->agent(); input += userAgentHeader->agent();
input += req.address().host();
return g_pCrypto->sha256(input); return g_pCrypto->sha256(input);
} }
@@ -105,6 +96,31 @@ bool CServerHandler::isResourceCheckpoint(const std::string_view& res) {
return res == "/checkpoint/NotoSans.woff"; return res == "/checkpoint/NotoSans.woff";
} }
std::string CServerHandler::ipForRequest(const Pistache::Http::Request& req) {
std::shared_ptr<const CFConnectingIPHeader> cfHeader;
std::shared_ptr<const XRealIPHeader> xRealIPHeader;
try {
cfHeader = Pistache::Http::Header::header_cast<CFConnectingIPHeader>(req.headers().get("cf-connecting-ip"));
} catch (std::exception& e) {
; // silent ignore
}
try {
xRealIPHeader = Pistache::Http::Header::header_cast<XRealIPHeader>(req.headers().get("X-Real-IP"));
} catch (std::exception& e) {
; // silent ignore
}
if (cfHeader)
return cfHeader->ip();
if (xRealIPHeader)
return xRealIPHeader->ip();
return req.address().host();
}
void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter response) { void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter response) {
const auto HEADERS = req.headers(); const auto HEADERS = req.headers();
std::shared_ptr<const Pistache::Http::Header::Host> hostHeader; std::shared_ptr<const Pistache::Http::Header::Host> hostHeader;
@@ -161,11 +177,9 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt
Debug::log(LOG, "New request: {}:{}{}", hostHeader->host(), hostHeader->port().toString(), req.resource()); Debug::log(LOG, "New request: {}:{}{}", hostHeader->host(), hostHeader->port().toString(), req.resource());
Debug::log(LOG, " | Request author: IP {}", req.address().host()); const auto REQUEST_IP = ipForRequest(req);
if (cfHeader)
Debug::log(LOG, " | CloudFlare reports IP: {}", cfHeader->ip()); Debug::log(LOG, " | Request author: IP {}, direct: {}", REQUEST_IP, req.address().host());
else
Debug::log(TRACE, "Connection does not come through CloudFlare");
if (userAgentHeader) if (userAgentHeader)
Debug::log(LOG, " | UA: {}", userAgentHeader->agent()); Debug::log(LOG, " | UA: {}", userAgentHeader->agent());
@@ -216,7 +230,7 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt
int challengeDifficulty = g_pConfig->m_config.default_challenge_difficulty; int challengeDifficulty = g_pConfig->m_config.default_challenge_difficulty;
if (!g_pConfig->m_parsedConfigDatas.ip_configs.empty()) { if (!g_pConfig->m_parsedConfigDatas.ip_configs.empty()) {
const auto IP = CIP(req.address().host()); const auto IP = CIP(REQUEST_IP);
for (const auto& ic : g_pConfig->m_parsedConfigDatas.ip_configs) { for (const auto& ic : g_pConfig->m_parsedConfigDatas.ip_configs) {
bool matched = false; bool matched = false;
@@ -230,11 +244,11 @@ void CServerHandler::onRequest(const Pistache::Http::Request& req, Pistache::Htt
if (matched) { if (matched) {
if (ic.action == CConfig::IP_ACTION_ALLOW) { if (ic.action == CConfig::IP_ACTION_ALLOW) {
Debug::log(LOG, " | Action: PASS (ip rule matched for {})", req.address().host()); Debug::log(LOG, " | Action: PASS (ip rule matched for {})", REQUEST_IP);
proxyPass(req, response); proxyPass(req, response);
return; return;
} else if (ic.action == CConfig::IP_ACTION_DENY) { } else if (ic.action == CConfig::IP_ACTION_DENY) {
Debug::log(LOG, " | Action: DENY (ip rule matched for {})", req.address().host()); Debug::log(LOG, " | Action: DENY (ip rule matched for {})", REQUEST_IP);
response.send(Pistache::Http::Code::Forbidden, "Forbidden"); response.send(Pistache::Http::Code::Forbidden, "Forbidden");
return; return;
} }

View File

@@ -20,6 +20,7 @@ class CServerHandler : public Pistache::Http::Handler {
void proxyPass(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response); void proxyPass(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response);
void challengeSubmitted(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response); void challengeSubmitted(const Pistache::Http::Request& req, Pistache::Http::ResponseWriter& response);
std::string fingerprintForRequest(const Pistache::Http::Request& req); std::string fingerprintForRequest(const Pistache::Http::Request& req);
std::string ipForRequest(const Pistache::Http::Request& req);
bool isResourceCheckpoint(const std::string_view& res); bool isResourceCheckpoint(const std::string_view& res);

24
src/headers/xrealip.hpp Normal file
View File

@@ -0,0 +1,24 @@
#include <pistache/http_headers.h>
#include <pistache/net.h>
class XRealIPHeader : public Pistache::Http::Header::Header {
public:
NAME("X-Real-IP");
XRealIPHeader() = default;
void parse(const std::string& str) override {
m_ip = str;
}
void write(std::ostream& os) const override {
os << m_ip;
}
std::string ip() const {
return m_ip;
}
private:
std::string m_ip = "";
};

View File

@@ -14,6 +14,7 @@
#include "headers/gitProtocolHeader.hpp" #include "headers/gitProtocolHeader.hpp"
#include "headers/acceptLanguageHeader.hpp" #include "headers/acceptLanguageHeader.hpp"
#include "headers/setCookieHeader.hpp" #include "headers/setCookieHeader.hpp"
#include "headers/xrealip.hpp"
#include "debug/log.hpp" #include "debug/log.hpp"
@@ -78,6 +79,7 @@ int main(int argc, char** argv, char** envp) {
Pistache::Http::Header::Registry::instance().registerHeader<GitProtocolHeader>(); Pistache::Http::Header::Registry::instance().registerHeader<GitProtocolHeader>();
Pistache::Http::Header::Registry::instance().registerHeader<AcceptLanguageHeader>(); Pistache::Http::Header::Registry::instance().registerHeader<AcceptLanguageHeader>();
Pistache::Http::Header::Registry::instance().registerHeader<SetCookieHeader>(); Pistache::Http::Header::Registry::instance().registerHeader<SetCookieHeader>();
Pistache::Http::Header::Registry::instance().registerHeader<XRealIPHeader>();
g_pCrypto = std::make_unique<CCrypto>(); g_pCrypto = std::make_unique<CCrypto>();