Add Hodor whitelists (#2154)
This commit is contained in:
parent
2911a7c08a
commit
fee34095a2
|
@ -71,7 +71,9 @@ IPs or users. the default value is 600.
|
||||||
"ip_capacity": 0,
|
"ip_capacity": 0,
|
||||||
"user_capacity": 0
|
"user_capacity": 0
|
||||||
},...
|
},...
|
||||||
]
|
],
|
||||||
|
// Trusted proxy ip or cidr
|
||||||
|
"trust_ips": ["127.0.0.1", "172.16.0.0/12"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@endcode
|
@endcode
|
||||||
|
@ -137,12 +139,14 @@ class DROGON_EXPORT Hodor : public drogon::Plugin<Hodor>
|
||||||
std::function<HttpResponsePtr(const drogon::HttpRequestPtr &)>
|
std::function<HttpResponsePtr(const drogon::HttpRequestPtr &)>
|
||||||
rejectResponseFactory_;
|
rejectResponseFactory_;
|
||||||
|
|
||||||
|
RealIpResolver::CIDRs trustCIDRs_;
|
||||||
|
|
||||||
void onHttpRequest(const drogon::HttpRequestPtr &,
|
void onHttpRequest(const drogon::HttpRequestPtr &,
|
||||||
AdviceCallback &&,
|
AdviceCallback &&,
|
||||||
AdviceChainCallback &&);
|
AdviceChainCallback &&);
|
||||||
bool checkLimit(const drogon::HttpRequestPtr &req,
|
bool checkLimit(const drogon::HttpRequestPtr &req,
|
||||||
const LimitStrategy &strategy,
|
const LimitStrategy &strategy,
|
||||||
const std::string &ip,
|
const trantor::InetAddress &ip,
|
||||||
const std::optional<std::string> &userId);
|
const std::optional<std::string> &userId);
|
||||||
HttpResponsePtr rejectResponse_;
|
HttpResponsePtr rejectResponse_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,7 +57,6 @@ class DROGON_EXPORT RealIpResolver : public drogon::Plugin<RealIpResolver>
|
||||||
private:
|
private:
|
||||||
const trantor::InetAddress &getRealAddr(
|
const trantor::InetAddress &getRealAddr(
|
||||||
const drogon::HttpRequestPtr &req) const;
|
const drogon::HttpRequestPtr &req) const;
|
||||||
bool matchCidr(const trantor::InetAddress &addr) const;
|
|
||||||
|
|
||||||
struct CIDR
|
struct CIDR
|
||||||
{
|
{
|
||||||
|
@ -66,7 +65,12 @@ class DROGON_EXPORT RealIpResolver : public drogon::Plugin<RealIpResolver>
|
||||||
in_addr_t mask_{32};
|
in_addr_t mask_{32};
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<CIDR> trustCIDRs_;
|
using CIDRs = std::vector<CIDR>;
|
||||||
|
static bool matchCidr(const trantor::InetAddress &addr,
|
||||||
|
const CIDRs &trustCIDRs);
|
||||||
|
|
||||||
|
friend class Hodor;
|
||||||
|
CIDRs trustCIDRs_;
|
||||||
std::string fromHeader_;
|
std::string fromHeader_;
|
||||||
std::string attributeKey_;
|
std::string attributeKey_;
|
||||||
bool useXForwardedFor_{false};
|
bool useXForwardedFor_{false};
|
||||||
|
|
|
@ -105,6 +105,17 @@ void Hodor::initAndStart(const Json::Value &config)
|
||||||
limitStrategies_.emplace_back(makeLimitStrategy(subLimit));
|
limitStrategies_.emplace_back(makeLimitStrategy(subLimit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Json::Value &trustIps = config["trust_ips"];
|
||||||
|
if (!trustIps.isNull() && !trustIps.isArray())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid trusted_ips. Should be array.");
|
||||||
|
}
|
||||||
|
for (const auto &ipOrCidr : trustIps)
|
||||||
|
{
|
||||||
|
trustCIDRs_.emplace_back(ipOrCidr.asString());
|
||||||
|
}
|
||||||
|
|
||||||
app().registerPreHandlingAdvice([this](const drogon::HttpRequestPtr &req,
|
app().registerPreHandlingAdvice([this](const drogon::HttpRequestPtr &req,
|
||||||
AdviceCallback &&acb,
|
AdviceCallback &&acb,
|
||||||
AdviceChainCallback &&accb) {
|
AdviceChainCallback &&accb) {
|
||||||
|
@ -119,9 +130,13 @@ void Hodor::shutdown()
|
||||||
|
|
||||||
bool Hodor::checkLimit(const drogon::HttpRequestPtr &req,
|
bool Hodor::checkLimit(const drogon::HttpRequestPtr &req,
|
||||||
const LimitStrategy &strategy,
|
const LimitStrategy &strategy,
|
||||||
const std::string &ip,
|
const trantor::InetAddress &ip,
|
||||||
const std::optional<std::string> &userId)
|
const std::optional<std::string> &userId)
|
||||||
{
|
{
|
||||||
|
if (RealIpResolver::matchCidr(ip, trustCIDRs_))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (strategy.regexFlag)
|
if (strategy.regexFlag)
|
||||||
{
|
{
|
||||||
if (!std::regex_match(req->path(), strategy.urlsRegex))
|
if (!std::regex_match(req->path(), strategy.urlsRegex))
|
||||||
|
@ -140,7 +155,7 @@ bool Hodor::checkLimit(const drogon::HttpRequestPtr &req,
|
||||||
{
|
{
|
||||||
RateLimiterPtr limiterPtr;
|
RateLimiterPtr limiterPtr;
|
||||||
strategy.ipLimiterMapPtr->modify(
|
strategy.ipLimiterMapPtr->modify(
|
||||||
ip,
|
ip.toIpNetEndian(),
|
||||||
[this, &limiterPtr, &strategy](RateLimiterPtr &ptr) {
|
[this, &limiterPtr, &strategy](RateLimiterPtr &ptr) {
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
{
|
{
|
||||||
|
@ -207,10 +222,9 @@ void Hodor::onHttpRequest(const drogon::HttpRequestPtr &req,
|
||||||
drogon::AdviceCallback &&adviceCallback,
|
drogon::AdviceCallback &&adviceCallback,
|
||||||
drogon::AdviceChainCallback &&chainCallback)
|
drogon::AdviceChainCallback &&chainCallback)
|
||||||
{
|
{
|
||||||
auto ip =
|
const trantor::InetAddress &ip =
|
||||||
(useRealIpResolver_ ? drogon::plugin::RealIpResolver::GetRealAddr(req)
|
useRealIpResolver_ ? drogon::plugin::RealIpResolver::GetRealAddr(req)
|
||||||
: req->peerAddr())
|
: req->peerAddr();
|
||||||
.toIpNetEndian();
|
|
||||||
std::optional<std::string> userId;
|
std::optional<std::string> userId;
|
||||||
if (userIdGetter_)
|
if (userIdGetter_)
|
||||||
{
|
{
|
||||||
|
|
|
@ -96,21 +96,20 @@ void RealIpResolver::initAndStart(const Json::Value &config)
|
||||||
}
|
}
|
||||||
|
|
||||||
const Json::Value &trustIps = config["trust_ips"];
|
const Json::Value &trustIps = config["trust_ips"];
|
||||||
if (!trustIps.isArray())
|
if (!trustIps.isNull() && !trustIps.isArray())
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Invalid trusted_ips. Should be array.");
|
throw std::runtime_error("Invalid trusted_ips. Should be array.");
|
||||||
}
|
}
|
||||||
for (const auto &elem : trustIps)
|
for (const auto &ipOrCidr : trustIps)
|
||||||
{
|
{
|
||||||
std::string ipOrCidr = elem.asString();
|
trustCIDRs_.emplace_back(ipOrCidr.asString());
|
||||||
trustCIDRs_.emplace_back(ipOrCidr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drogon::app().registerPreRoutingAdvice([this](const HttpRequestPtr &req) {
|
drogon::app().registerPreRoutingAdvice([this](const HttpRequestPtr &req) {
|
||||||
const auto &headers = req->headers();
|
const auto &headers = req->headers();
|
||||||
auto ipHeaderFind = headers.find(fromHeader_);
|
auto ipHeaderFind = headers.find(fromHeader_);
|
||||||
const trantor::InetAddress &peerAddr = req->getPeerAddr();
|
const trantor::InetAddress &peerAddr = req->getPeerAddr();
|
||||||
if (ipHeaderFind == headers.end() || !matchCidr(peerAddr))
|
if (ipHeaderFind == headers.end() || !matchCidr(peerAddr, trustCIDRs_))
|
||||||
{
|
{
|
||||||
// Target header is empty, or
|
// Target header is empty, or
|
||||||
// direct peer is already a non-proxy
|
// direct peer is already a non-proxy
|
||||||
|
@ -139,7 +138,7 @@ void RealIpResolver::initAndStart(const Json::Value &config)
|
||||||
while (!(ip = parser.getNext()).empty())
|
while (!(ip = parser.getNext()).empty())
|
||||||
{
|
{
|
||||||
trantor::InetAddress addr = parseAddress(ip);
|
trantor::InetAddress addr = parseAddress(ip);
|
||||||
if (addr.isUnspecified() || matchCidr(addr))
|
if (addr.isUnspecified() || matchCidr(addr, trustCIDRs_))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -177,9 +176,10 @@ const trantor::InetAddress &RealIpResolver::getRealAddr(
|
||||||
return attributesPtr->get<trantor::InetAddress>(attributeKey_);
|
return attributesPtr->get<trantor::InetAddress>(attributeKey_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RealIpResolver::matchCidr(const trantor::InetAddress &addr) const
|
bool RealIpResolver::matchCidr(const trantor::InetAddress &addr,
|
||||||
|
const CIDRs &trustCIDRs)
|
||||||
{
|
{
|
||||||
for (auto &cidr : trustCIDRs_)
|
for (const auto &cidr : trustCIDRs)
|
||||||
{
|
{
|
||||||
if ((addr.ipNetEndian() & cidr.mask_) == cidr.addr_)
|
if ((addr.ipNetEndian() & cidr.mask_) == cidr.addr_)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue