From d545a87234dba34aa5fc7eddda06e073b9011999 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Tue, 19 Nov 2019 11:49:25 +0100 Subject: [PATCH] dnsdist: Add response flags to ERCodeAction, HTTPStatusAction and RCodeAction --- pdns/dnsdist-lua-actions.cc | 108 ++++++++++++------------ pdns/dnsdist-lua.hh | 25 ++---- pdns/dnsdistdist/docs/rules-actions.rst | 36 +++++++- 3 files changed, 95 insertions(+), 74 deletions(-) diff --git a/pdns/dnsdist-lua-actions.cc b/pdns/dnsdist-lua-actions.cc index a60bd1f77b..cc714d23d3 100644 --- a/pdns/dnsdist-lua-actions.cc +++ b/pdns/dnsdist-lua-actions.cc @@ -306,6 +306,7 @@ public: { dq->dh->rcode = d_rcode; dq->dh->qr = true; // for good measure + setResponseHeadersFromConfig(*dq->dh, d_responseConfig); return Action::HeaderModify; } std::string toString() const override @@ -313,6 +314,7 @@ public: return "set rcode "+std::to_string(d_rcode); } + ResponseConfig d_responseConfig; private: uint8_t d_rcode; }; @@ -326,6 +328,7 @@ public: dq->dh->rcode = (d_rcode & 0xF); dq->ednsRCode = ((d_rcode & 0xFFF0) >> 4); dq->dh->qr = true; // for good measure + setResponseHeadersFromConfig(*dq->dh, d_responseConfig); return Action::HeaderModify; } std::string toString() const override @@ -333,6 +336,7 @@ public: return "set ercode "+ERCode::to_s(d_rcode); } + ResponseConfig d_responseConfig; private: uint8_t d_rcode; }; @@ -444,21 +448,7 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu char* dest = ((char*)dq->dh) + dq->len; dq->dh->qr = true; // for good measure - if (d_setAA) { - dq->dh->aa = *d_setAA; - } - if (d_setAD) { - dq->dh->ad = *d_setAD; - } - else { - dq->dh->ad = false; - } - if (d_setRA) { - dq->dh->ra = *d_setRA; - } - else { - dq->dh->ra = dq->dh->rd; // for good measure - } + setResponseHeadersFromConfig(*dq->dh, d_responseConfig); dq->dh->ancount = 0; dq->dh->arcount = 0; // for now, forget about your EDNS, we're marching over it @@ -1192,6 +1182,7 @@ public: dq->du->setHTTPResponse(d_code, d_body, d_contentType); dq->dh->qr = true; // for good measure + setResponseHeadersFromConfig(*dq->dh, d_responseConfig); return Action::HeaderModify; } @@ -1199,6 +1190,8 @@ public: { return "return an HTTP status of " + std::to_string(d_code); } + + ResponseConfig d_responseConfig; private: std::string d_body; std::string d_contentType; @@ -1257,23 +1250,42 @@ static void addAction(GlobalStateHolder > *someRulActions, const luadn }); } -typedef std::unordered_map > spoofparams_t; +typedef std::unordered_map > responseParams_t; -static void parseSpoofConfig(boost::optional vars, boost::optional& setAA, boost::optional& setAD, boost::optional& setRA) +static void parseResponseConfig(boost::optional vars, ResponseConfig& config) { if (vars) { if (vars->count("aa")) { - setAA = boost::get((*vars)["aa"]); + config.setAA = boost::get((*vars)["aa"]); } if (vars->count("ad")) { - setAD = boost::get((*vars)["ad"]); + config.setAD = boost::get((*vars)["ad"]); } if (vars->count("ra")) { - setRA = boost::get((*vars)["ra"]); + config.setRA = boost::get((*vars)["ra"]); } } } +void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config) +{ + if (config.setAA) { + dh.aa = *config.setAA; + } + if (config.setAD) { + dh.ad = *config.setAD; + } + else { + dh.ad = false; + } + if (config.setRA) { + dh.ra = *config.setRA; + } + else { + dh.ra = dh.rd; // for good measure + } +} + void setupLuaActions() { g_lua.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr action, boost::optional params) { @@ -1366,7 +1378,7 @@ void setupLuaActions() return std::shared_ptr(new QPSPoolAction(limit, a)); }); - g_lua.writeFunction("SpoofAction", [](boost::variant>> inp, boost::optional b, boost::optional vars ) { + g_lua.writeFunction("SpoofAction", [](boost::variant>> inp, boost::optional b, boost::optional vars ) { vector addrs; if(auto s = boost::get(&inp)) addrs.push_back(ComboAddress(*s)); @@ -1380,41 +1392,18 @@ void setupLuaActions() } auto ret = std::shared_ptr(new SpoofAction(addrs)); - boost::optional setAA = boost::none; - boost::optional setAD = boost::none; - boost::optional setRA = boost::none; - parseSpoofConfig(vars, setAA, setAD, setRA); auto sa = std::dynamic_pointer_cast(ret); - if (setAA) { - sa->setAA(*setAA); - } - if (setAD) { - sa->setAD(*setAD); - } - if (setRA) { - sa->setRA(*setRA); - } + parseResponseConfig(vars, sa->d_responseConfig); return ret; }); - g_lua.writeFunction("SpoofCNAMEAction", [](const std::string& a, boost::optional vars) { + g_lua.writeFunction("SpoofCNAMEAction", [](const std::string& a, boost::optional vars) { auto ret = std::shared_ptr(new SpoofAction(a)); - boost::optional setAA = boost::none; - boost::optional setAD = boost::none; - boost::optional setRA = boost::none; - parseSpoofConfig(vars, setAA, setAD, setRA); + ResponseConfig responseConfig; + parseResponseConfig(vars, responseConfig); auto sa = std::dynamic_pointer_cast(ret); - if (setAA) { - sa->setAA(*setAA); - } - if (setAD) { - sa->setAD(*setAD); - } - if (setRA) { - sa->setRA(*setRA); - } + sa->d_responseConfig = responseConfig; return ret; - }); g_lua.writeFunction("DropAction", []() { @@ -1449,12 +1438,18 @@ void setupLuaActions() return std::shared_ptr(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false)); }); - g_lua.writeFunction("RCodeAction", [](uint8_t rcode) { - return std::shared_ptr(new RCodeAction(rcode)); + g_lua.writeFunction("RCodeAction", [](uint8_t rcode, boost::optional vars) { + auto ret = std::shared_ptr(new RCodeAction(rcode)); + auto rca = std::dynamic_pointer_cast(ret); + parseResponseConfig(vars, rca->d_responseConfig); + return ret; }); - g_lua.writeFunction("ERCodeAction", [](uint8_t rcode) { - return std::shared_ptr(new ERCodeAction(rcode)); + g_lua.writeFunction("ERCodeAction", [](uint8_t rcode, boost::optional vars) { + auto ret = std::shared_ptr(new ERCodeAction(rcode)); + auto erca = std::dynamic_pointer_cast(ret); + parseResponseConfig(vars, erca->d_responseConfig); + return ret; }); g_lua.writeFunction("SkipCacheAction", []() { @@ -1606,8 +1601,11 @@ void setupLuaActions() }); #ifdef HAVE_DNS_OVER_HTTPS - g_lua.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional contentType) { - return std::shared_ptr(new HTTPStatusAction(status, body, contentType ? *contentType : "")); + g_lua.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional contentType, boost::optional vars) { + auto ret = std::shared_ptr(new HTTPStatusAction(status, body, contentType ? *contentType : "")); + auto hsa = std::dynamic_pointer_cast(ret); + parseResponseConfig(vars, hsa->d_responseConfig); + return ret; }); #endif /* HAVE_DNS_OVER_HTTPS */ diff --git a/pdns/dnsdist-lua.hh b/pdns/dnsdist-lua.hh index 89f49c0ee9..aa33859c80 100644 --- a/pdns/dnsdist-lua.hh +++ b/pdns/dnsdist-lua.hh @@ -21,6 +21,14 @@ */ #pragma once +struct ResponseConfig +{ + boost::optional setAA{boost::none}; + boost::optional setAD{boost::none}; + boost::optional setRA{boost::none}; +}; +void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config); + class LuaAction : public DNSAction { public: @@ -73,26 +81,11 @@ public: return ret; } - void setAA(bool aa) - { - d_setAA = aa; - } - - void setAD(bool ad) - { - d_setAD = ad; - } - void setRA(bool ra) - { - d_setRA = ra; - } + ResponseConfig d_responseConfig; private: std::vector d_addrs; DNSName d_cname; - boost::optional d_setAA{boost::none}; - boost::optional d_setAD{boost::none}; - boost::optional d_setRA{boost::none}; }; typedef boost::variant>, std::shared_ptr, DNSName, vector > > luadnsrule_t; diff --git a/pdns/dnsdistdist/docs/rules-actions.rst b/pdns/dnsdistdist/docs/rules-actions.rst index 9a2d68aa31..1d698b69d5 100644 --- a/pdns/dnsdistdist/docs/rules-actions.rst +++ b/pdns/dnsdistdist/docs/rules-actions.rst @@ -960,24 +960,44 @@ The following actions exist. :param int v6: The IPv6 netmask length -.. function:: ERCodeAction(rcode) +.. function:: ERCodeAction(rcode [, options]) .. versionadded:: 1.4.0 + .. versionchanged:: 1.5.0 + Added the optional parameter ``options``. + Reply immediately by turning the query into a response with the specified EDNS extended ``rcode``. ``rcode`` can be specified as an integer or as one of the built-in :ref:`DNSRCode`. :param int rcode: The extended RCODE to respond with. + :param table options: A table with key: value pairs with options. -.. function:: HTTPStatusAction(status, body, contentType="") + Options: + + * ``aa``: bool - Set the AA bit to this value (true means the bit is set, false means it's cleared). Default is to clear it. + * ``ad``: bool - Set the AD bit to this value (true means the bit is set, false means it's cleared). Default is to clear it. + * ``ra``: bool - Set the RA bit to this value (true means the bit is set, false means it's cleared). Default is to copy the value of the RD bit from the incoming query. + +.. function:: HTTPStatusAction(status, body, contentType="" [, options]) .. versionadded:: 1.4.0 + .. versionchanged:: 1.5.0 + Added the optional parameter ``options``. + Return an HTTP response with a status code of ''status''. For HTTP redirects, ''body'' should be the redirect URL. :param int status: The HTTP status code to return. :param string body: The body of the HTTP response, or a URL if the status code is a redirect (3xx). :param string contentType: The HTTP Content-Type header to return for a 200 response, ignored otherwise. Default is ''application/dns-message''. + :param table options: A table with key: value pairs with options. + + Options: + + * ``aa``: bool - Set the AA bit to this value (true means the bit is set, false means it's cleared). Default is to clear it. + * ``ad``: bool - Set the AD bit to this value (true means the bit is set, false means it's cleared). Default is to clear it. + * ``ra``: bool - Set the RA bit to this value (true means the bit is set, false means it's cleared). Default is to copy the value of the RD bit from the incoming query. .. function:: KeyValueStoreLookupAction(kvs, lookupKey, destinationTag) @@ -1092,12 +1112,22 @@ The following actions exist. :param int maxqps: The QPS limit for that pool :param string poolname: The name of the pool -.. function:: RCodeAction(rcode) +.. function:: RCodeAction(rcode [, options]) + + .. versionchanged:: 1.5.0 + Added the optional parameter ``options``. Reply immediately by turning the query into a response with the specified ``rcode``. ``rcode`` can be specified as an integer or as one of the built-in :ref:`DNSRCode`. :param int rcode: The RCODE to respond with. + :param table options: A table with key: value pairs with options. + + Options: + + * ``aa``: bool - Set the AA bit to this value (true means the bit is set, false means it's cleared). Default is to clear it. + * ``ad``: bool - Set the AD bit to this value (true means the bit is set, false means it's cleared). Default is to clear it. + * ``ra``: bool - Set the RA bit to this value (true means the bit is set, false means it's cleared). Default is to copy the value of the RD bit from the incoming query. .. function:: RemoteLogAction(remoteLogger[, alterFunction [, options]]) -- 2.47.2