This commit is contained in:
UnknownObject
2026-06-30 17:49:51 +08:00
commit 292c09619e
200 changed files with 23718 additions and 0 deletions
+200
View File
@@ -0,0 +1,200 @@
#include "ServerProcessor.h"
#include "ServerLogger.h"
#include "PathTraversal.h"
#include "HTTPObjectsBridge.h"
#include "UNSResponseBuilder.h"
#include <mutex>
#include <typeinfo>
#include <typeindex>
#include <unordered_map>
#ifdef __GNUG__
#include <cxxabi.h>
#include <cstdlib>
#endif
// demangle(GNU)/回退(其他编译器)
static std::string demangle_name(const char* name)
{
#ifdef __GNUG__
int status = 0;
char *dem = abi::__cxa_demangle(name, nullptr, nullptr, &status);
std::string ret = (status == 0 && dem) ? dem : name;
std::free(dem);
return ret;
#else
return name;
#endif
}
// RTTI 名称缓存(线程安全)
static const std::string& RTTISubClassName(const std::type_info &ti)
{
using key_t = std::type_index;
static std::mutex m;
static std::unordered_map<key_t, std::string> cache;
key_t k(ti);
// 快速检查(持锁短时间)
{
std::lock_guard<std::mutex> g(m);
auto it = cache.find(k);
if (it != cache.end())
return it->second;
}
// 若未缓存,先在无锁区做 demangle(可能较慢),然后再插入缓存
std::string dem = demangle_name(ti.name());
{
std::lock_guard<std::mutex> g(m);
auto [it, inserted] = cache.emplace(k, std::move(dem));
return it->second;
}
}
class ServerProcessor::Impl
{
public:
bool IPCheck = false;
IPTablePtr BlockedIPs = nullptr;
std::map<std::string, bool> StreamInfo;
};
ServerProcessor::ServerProcessor() : pimpl(std::make_unique<Impl>())
{
}
ServerProcessor::~ServerProcessor() = default;
void ServerProcessor::EnableIPCheck()
{
pimpl->IPCheck = true;
return;
}
void ServerProcessor::DisableIPCheck()
{
pimpl->IPCheck = false;
return;
}
void ServerProcessor::UpdateBlockedIPList(IPTablePtr ips)
{
pimpl->BlockedIPs = ips;
return;
}
void ServerProcessor::AppenedBlockedIP(DateTime::Span block_time, std::string ip)
{
DateTime expr_time = (DateTime::Now() += block_time);
IPList li{ ip };
pimpl->BlockedIPs->Appened(expr_time, li);
pimpl->BlockedIPs->Update();
SCLOG_INFO("IP: [%s] has been blocked untill {%s}", ip.c_str(), std::string(expr_time).c_str());
return;
}
uns::HTTPMethod ServerProcessor::GetMethod(uns::RequestPtr request)
{
std::string method = request->GetImpl()->webcc_req->method();
if (method == "GET")
return uns::HTTPMethod::H_GET;
else if (method == "PUT")
return uns::HTTPMethod::H_PUT;
else if (method == "POST")
return uns::HTTPMethod::H_POST;
else if (method == "HEAD")
return uns::HTTPMethod::H_HEAD;
else if (method == "TRACE")
return uns::HTTPMethod::H_TRACE;
else if (method == "PATCH")
return uns::HTTPMethod::H_PATCH;
else if (method == "DELETE")
return uns::HTTPMethod::H_DELETE;
else if (method == "OPTIONS")
return uns::HTTPMethod::H_OPTIONS;
else if (method == "CONNECT")
return uns::HTTPMethod::H_CONNECT;
else
return uns::HTTPMethod::H_UNKNOWN;
}
void ServerProcessor::AddStreamSettings(std::string method, bool stream)
{
pimpl->StreamInfo.insert(std::pair<std::string, bool>(method, stream));
return;
}
uns::PathTraversalDefenceLevel ServerProcessor::PTDefence()
{
return uns::PathTraversalDefenceLevel::DenyAll;
}
bool ServerProcessor::IsPathSafe(const std::string& raw_path)
{
return false;
}
uns::ResponsePtr ServerProcessor::Handle(uns::RequestPtr request)
{
std::string x_real_ip;
if(request->GetImpl()->webcc_req->HasHeader("X-Real-IP"))
x_real_ip = request->GetImpl()->webcc_req->GetHeader("X-Real-IP");
std::string req_ip = (x_real_ip.empty() ? request->GetImpl()->webcc_req->address() : x_real_ip);
SCLOGF_INFO("Request recived by {{{}}}, ip: [{}], method: {}, URL: {}", RTTISubClassName(typeid(*this)), req_ip, request->GetImpl()->webcc_req->method(), request->GetImpl()->webcc_req->url().path());
if (pimpl->IPCheck && (pimpl->BlockedIPs != nullptr))
{
pimpl->BlockedIPs->Update();
if (pimpl->BlockedIPs->IPExist(req_ip))
return uns::ResponseBuilder().IPBlocked()();
}
// path test
std::string path = request->GetImpl()->webcc_req->url().path();
auto status = PathTraversal::AnalyzeUrlTraversal(path);
if(status != PathTraversal::UrlSafetyStatus::Safe)
SCLOGF_WARNING("PathTraversal Detected: {}, Level: {}", path, PathTraversal::ToString(status));
switch(PTDefence())
{
case uns::PathTraversalDefenceLevel::DenyAll:
if(status != PathTraversal::UrlSafetyStatus::Safe)
return uns::ResponseBuilder().Forbidden()();
break;
case uns::PathTraversalDefenceLevel::AutoNormalize:
{
if(status == PathTraversal::UrlSafetyStatus::EvasiveTraversal)
return uns::ResponseBuilder().Forbidden()();
auto decoded_path = PathTraversal::UrlDecode(path);
if(!IsPathSafe(decoded_path))
return uns::ResponseBuilder().Forbidden()();
auto url = request->GetImpl()->webcc_req->url();
url.ForceSet_Path(PathTraversal::NormalizeUrlPath(decoded_path));
request->GetImpl()->webcc_req->set_url(std::move(url));
break;
}
case uns::PathTraversalDefenceLevel::AllowNormal:
{
if(status == PathTraversal::UrlSafetyStatus::EvasiveTraversal)
return uns::ResponseBuilder().Forbidden()();
auto decoded_path = PathTraversal::UrlDecode(path);
if(!IsPathSafe(decoded_path))
return uns::ResponseBuilder().Forbidden()();
auto url = request->GetImpl()->webcc_req->url();
url.ForceSet_Path(decoded_path);
request->GetImpl()->webcc_req->set_url(std::move(url));
break;
}
default:
break; //Check Bypassed by [AllowAll]
}
uns::ResponsePtr ptr = Processor(request);
return ptr;
}
bool ServerProcessor::Stream(const std::string& method)
{
if (pimpl->StreamInfo.find(method) != pimpl->StreamInfo.end())
return pimpl->StreamInfo.at(method);
else
return false;
}