The function should look like this:
```
-function luarule(remote, qname, qtype, dh, len)
- if(qtype==35) -- NAPTR
+function luarule(dq)
+ if(dq.qtype==35) -- NAPTR
then
return DNSAction.Pool, "abuse" -- send to abuse pool
else
```
counter=0
-function luaroundrobin(servers, remote, qname, qtype, dh)
+function luaroundrobin(servers, dq)
counter=counter+1
return servers[1+(counter % #servers)]
end
```
authServer=newServer({address="2001:888:2000:1d::2", pool="auth"})
-function splitSetup(servers, remote, qname, qtype, dh)
- if(dh:getRD() == false)
+function splitSetup(servers, dq)
+ if(dq.dh:getRD() == false)
then
- return leastOutstanding.policy(getPoolServers("auth"), remote, qname, qtype, dh)
+ return leastOutstanding.policy(getPoolServers("auth"), dq)
else
- return leastOutstanding.policy(servers, remote, qname, qtype, dh)
+ return leastOutstanding.policy(servers, dq)
end
end
* `newDNSName(name)`: make a DNSName based on this .-terminated name
* member `isPartOf(dnsname)`: is this dnsname part of that dnsname
* member `tostring()`: return as a human friendly . terminated string
+ * DNSQuestion related:
+ * member `dh`: DNSHeader
+ * member `len`: the question length
+ * member `localaddr`: ComboAddress of the local bind this question was received on
+ * member `qname`: DNSName of this question
+ * member `qtype`: QType (as an unsigned integer) of this question
+ * member `remoteaddr`: ComboAddress of the remote client
+ * member `rcode`: RCode of this question
+ * member `size`: the total size of the buffer starting at `dh`
+ * member `tcp`: whether this question was received over a TCP socket
* DNSHeader related
* member `getRD()`: get recursion desired flag
* member `setRD(bool)`: set recursion desired flag
---------
`dnsdist` can call Lua per packet if so configured, and will do so with the following hooks:
- * `bool blockFilter(ComboAddress, DNSName, qtype, DNSHeader)`: if defined, called for every function. If this
+ * `bool blockFilter(ComboAddress, DNSQuestion)`: if defined, called for every function. If this
returns true, the packet is dropped. If false is returned, `dnsdist` will check if the DNSHeader indicates
the packet is now a query response. If so, `dnsdist` will answer the client directly with the modified packet.
- * `server policy(candidates, ComboAddress, DNSName, qtype, DNSHeader)`: if configured with `setServerPolicyLua()`
+ * `server policy(candidates, DNSQuestion)`: if configured with `setServerPolicyLua()`
gets called for every packet. Candidates is a table of potential servers to pick from, ComboAddress is the
address of the requestor, DNSName and qtype describe name and type of query. DNSHeader meanwhile is available for
your inspection.
class LuaAction : public DNSAction
{
public:
- typedef std::function<std::tuple<int, string>(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t len, uint16_t bufferSize)> func_t;
+ typedef std::function<std::tuple<int, string>(DNSQuestion* dq)> func_t;
LuaAction(LuaAction::func_t func) : d_func(func)
{}
- Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
- auto ret = d_func(remote, qname, qtype, dh, len, bufferSize);
+ auto ret = d_func(dq);
if(ruleresult)
*ruleresult=std::get<1>(ret);
return (Action)std::get<0>(ret);
}
- string toString() const
+ string toString() const override
{
return "Lua script";
}
}
int matches=0;
+ ComboAddress dummy("127.0.0.1");
DTime dt;
dt.set();
for(int n=0; n < times; ++n) {
const item& i = items[n % items.size()];
- struct dnsheader* dh = (struct dnsheader*)&i.packet[0];
- if(rule->matches(i.rem, i.qname, i.qtype, dh, i.packet.size()))
+ DNSQuestion dq(&i.qname, i.qtype, &i.rem, &i.rem, (struct dnsheader*)&i.packet[0], i.packet.size(), i.packet.size(), false);
+ if(rule->matches(&dq))
matches++;
}
double udiff=dt.udiff();
g_lua.registerFunction("tostring", &ComboAddress::toString);
g_lua.registerFunction("tostringWithPort", &ComboAddress::toStringWithPort);
+ g_lua.registerFunction("toString", &ComboAddress::toString);
+ g_lua.registerFunction("toStringWithPort", &ComboAddress::toStringWithPort);
g_lua.registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
g_lua.registerFunction("isPartOf", &DNSName::isPartOf);
g_lua.registerFunction<string(DNSName::*)()>("tostring", [](const DNSName&dn ) { return dn.toString(); });
+ g_lua.registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); });
g_lua.writeFunction("newDNSName", [](const std::string& name) { return DNSName(name); });
g_lua.writeFunction("newSuffixMatchNode", []() { return SuffixMatchNode(); });
}
});
+ /* DNSQuestion bindings */
+ /* PowerDNS DNSQuestion compat */
+ g_lua.registerMember<const ComboAddress (DNSQuestion::*)>("localaddr", [](const DNSQuestion& dq) -> const ComboAddress { return *dq.local; }, [](DNSQuestion& dq, const ComboAddress newLocal) { (void) newLocal; });
+ g_lua.registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName { return *dq.qname; }, [](DNSQuestion& dq, const DNSName newName) { (void) newName; });
+ g_lua.registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; });
+ g_lua.registerMember<int (DNSQuestion::*)>("rcode", [](const DNSQuestion& dq) -> int { return dq.dh->rcode; }, [](DNSQuestion& dq, int newRCode) { dq.dh->rcode = newRCode; });
+ g_lua.registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress { return *dq.remote; }, [](DNSQuestion& dq, const ComboAddress newRemote) { (void) newRemote; });
+ /* DNSDist DNSQuestion */
+ g_lua.registerMember("dh", &DNSQuestion::dh);
+ g_lua.registerMember<uint16_t (DNSQuestion::*)>("len", [](const DNSQuestion& dq) -> uint16_t { return dq.len; }, [](DNSQuestion& dq, uint16_t newlen) { dq.len = newlen; });
+ g_lua.registerMember<size_t (DNSQuestion::*)>("size", [](const DNSQuestion& dq) -> size_t { return dq.size; }, [](DNSQuestion& dq, size_t newSize) { (void) newSize; });
+ g_lua.registerMember<bool (DNSQuestion::*)>("tcp", [](const DNSQuestion& dq) -> bool { return dq.tcp; }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; });
+
g_lua.writeFunction("setMaxTCPClientThreads", [](uint64_t max) { g_maxTCPClientThreads = max; });
g_lua.writeFunction("setECSSourcePrefixV4", [](uint16_t prefix) { g_ECSSourcePrefixV4=prefix; });
/* we get launched with a pipe on which we receive file descriptors from clients that we own
from that point on */
- typedef std::function<bool(ComboAddress, DNSName, uint16_t, dnsheader*)> blockfilter_t;
+ typedef std::function<bool(const DNSQuestion*)> blockfilter_t;
blockfilter_t blockFilter = 0;
{
size_t querySize = qlen <= 4096 ? qlen + 512 : qlen;
char queryBuffer[querySize];
const char* query = queryBuffer;
- uint16_t queryLen = qlen;
- readn2WithTimeout(ci.fd, queryBuffer, queryLen, g_tcpRecvTimeout);
+ readn2WithTimeout(ci.fd, queryBuffer, qlen, g_tcpRecvTimeout);
#ifdef HAVE_DNSCRYPT
std::shared_ptr<DnsCryptQuery> dnsCryptQuery = 0;
dnsCryptQuery = std::make_shared<DnsCryptQuery>();
uint16_t decryptedQueryLen = 0;
vector<uint8_t> response;
- bool decrypted = handleDnsCryptQuery(ci.cs->dnscryptCtx, queryBuffer, queryLen, dnsCryptQuery, &decryptedQueryLen, true, response);
+ bool decrypted = handleDnsCryptQuery(ci.cs->dnscryptCtx, queryBuffer, qlen, dnsCryptQuery, &decryptedQueryLen, true, response);
if (!decrypted) {
if (response.size() > 0) {
}
break;
}
- queryLen = decryptedQueryLen;
+ qlen = decryptedQueryLen;
}
#endif
uint16_t qtype;
unsigned int consumed = 0;
- DNSName qname(query, queryLen, sizeof(dnsheader), false, &qtype, 0, &consumed);
+ DNSName qname(query, qlen, sizeof(dnsheader), false, &qtype, 0, &consumed);
+ DNSQuestion dq(&qname, qtype, &ci.cs->local, &ci.remote, (dnsheader*)query, querySize, qlen, true);
string ruleresult;
- struct dnsheader* dh =(dnsheader*)query;
- const uint16_t * flags = getFlagsFromDNSHeader(dh);
+ const uint16_t * flags = getFlagsFromDNSHeader(dq.dh);
uint16_t origFlags = *flags;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
{
WriteLock wl(&g_rings.queryLock);
- g_rings.queryRing.push_back({now,ci.remote,qname,queryLen,qtype,*dh});
+ g_rings.queryRing.push_back({now,ci.remote,qname,dq.len,dq.qtype,*dq.dh});
}
g_stats.queries++;
}
}
- if (dh->rd) {
+ if (dq.dh->rd) {
g_stats.rdQueries++;
}
if(blockFilter) {
std::lock_guard<std::mutex> lock(g_luamutex);
- if(blockFilter(ci.remote, qname, qtype, dh)) {
+ if(blockFilter(&dq)) {
g_stats.blockFilter++;
goto drop;
}
- if(dh->tc && dh->qr) { // don't truncate on TCP/IP!
- dh->tc=false; // maybe we should just pass blockFilter the TCP status
- dh->qr=false;
+ if(dq.dh->tc && dq.dh->qr) { // don't truncate on TCP/IP!
+ dq.dh->tc=false; // maybe we should just pass blockFilter the TCP status
+ dq.dh->qr=false;
}
}
DNSAction::Action action=DNSAction::Action::None;
for(const auto& lr : *localRulactions) {
- if(lr.first->matches(ci.remote, qname, qtype, dh, queryLen)) {
- action=(*lr.second)(ci.remote, qname, qtype, dh, queryLen, querySize, &ruleresult);
+ if(lr.first->matches(&dq)) {
+ action=(*lr.second)(&dq, &ruleresult);
if(action != DNSAction::Action::None) {
lr.first->d_matches++;
break;
goto drop;
case DNSAction::Action::Nxdomain:
- dh->rcode = RCode::NXDomain;
- dh->qr=true;
+ dq.dh->rcode = RCode::NXDomain;
+ dq.dh->qr=true;
g_stats.ruleNXDomain++;
break;
case DNSAction::Action::Pool:
break;
}
- if(dh->qr) { // something turned it into a response
- if (putNonBlockingMsgLen(ci.fd, queryLen, g_tcpSendTimeout))
- writen2WithTimeout(ci.fd, query, queryLen, g_tcpSendTimeout);
+ if(dq.dh->qr) { // something turned it into a response
+ if (putNonBlockingMsgLen(ci.fd, dq.len, g_tcpSendTimeout))
+ writen2WithTimeout(ci.fd, query, dq.len, g_tcpSendTimeout);
g_stats.selfAnswered++;
goto drop;
{
std::lock_guard<std::mutex> lock(g_luamutex);
- ds = localPolicy->policy(getDownstreamCandidates(g_dstates.getCopy(), pool), ci.remote, qname, qtype, dh);
+ ds = localPolicy->policy(getDownstreamCandidates(g_dstates.getCopy(), pool), &dq);
}
int dsock;
if(!ds) {
}
if (ds->useECS) {
- uint16_t newLen = queryLen;
- handleEDNSClientSubnet(queryBuffer, querySize, consumed, &newLen, largerQuery, &ednsAdded, ci.remote);
+ uint16_t newLen = dq.len;
+ handleEDNSClientSubnet(queryBuffer, dq.size, consumed, &newLen, largerQuery, &ednsAdded, ci.remote);
if (largerQuery.empty() == false) {
query = largerQuery.c_str();
- queryLen = largerQuery.size();
- querySize = largerQuery.size();
+ dq.len = largerQuery.size();
+ dq.size = largerQuery.size();
} else {
- queryLen = newLen;
+ dq.len = newLen;
}
}
ds->queries++;
ds->outstanding++;
- if(qtype == QType::AXFR || qtype == QType::IXFR) // XXX fixme we really need to do better
+ if(dq.qtype == QType::AXFR || dq.qtype == QType::IXFR) // XXX fixme we really need to do better
break;
uint16_t downstream_failures=0;
break;
}
- if(!sendNonBlockingMsgLen(dsock, queryLen, ds->tcpSendTimeout, ds->remote, ds->sourceAddr, ds->sourceItf)) {
+ if(!sendNonBlockingMsgLen(dsock, dq.len, ds->tcpSendTimeout, ds->remote, ds->sourceAddr, ds->sourceItf)) {
vinfolog("Downstream connection to %s died on us, getting a new one!", ds->getName());
close(dsock);
sockets[ds->remote]=dsock=setupTCPDownstream(ds);
try {
if (ds->sourceItf == 0) {
- writen2WithTimeout(dsock, query, queryLen, ds->tcpSendTimeout);
+ writen2WithTimeout(dsock, query, dq.len, ds->tcpSendTimeout);
}
else {
- sendMsgWithTimeout(dsock, query, queryLen, ds->tcpSendTimeout, ds->remote, ds->sourceAddr, ds->sourceItf);
+ sendMsgWithTimeout(dsock, query, dq.len, ds->tcpSendTimeout, ds->remote, ds->sourceAddr, ds->sourceItf);
}
}
catch(const runtime_error& e) {
unsigned int udiff = 1000000.0*DiffTime(now,answertime);
{
std::lock_guard<std::mutex> lock(g_rings.respMutex);
- g_rings.respRing.push_back({answertime, ci.remote, qname, qtype, (unsigned int)udiff, (unsigned int)responseLen, *dh, ds->remote});
+ g_rings.respRing.push_back({answertime, ci.remote, qname, dq.qtype, (unsigned int)udiff, (unsigned int)responseLen, *dq.dh, ds->remote});
}
largerQuery.clear();
GlobalStateHolder<ServerPolicy> g_policy;
-shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)
+shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const DNSQuestion* dq)
{
for(auto& d : servers) {
if(d.second->isUp() && d.second->qps.check())
return d.second;
}
- return leastOutstanding(servers, remote, qname, qtype, dh);
+ return leastOutstanding(servers, dq);
}
// get server with least outstanding queries, and within those, with the lowest order, and within those: the fastest
-shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)
+shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const DNSQuestion* dq)
{
vector<pair<tuple<int,int,double>, shared_ptr<DownstreamState>>> poss;
/* so you might wonder, why do we go through this trouble? The data on which we sort could change during the sort,
return poss.begin()->second;
}
-shared_ptr<DownstreamState> valrandom(unsigned int val, const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)
+shared_ptr<DownstreamState> valrandom(unsigned int val, const NumberedServerVector& servers, const DNSQuestion* dq)
{
vector<pair<int, shared_ptr<DownstreamState>>> poss;
int sum=0;
return p->second;
}
-shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)
+shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const DNSQuestion* dq)
{
- return valrandom(random(), servers, remote, qname, qtype, dh);
+ return valrandom(random(), servers, dq);
}
static uint32_t g_hashperturb;
-shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)
+shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const DNSQuestion* dq)
{
- return valrandom(qname.hash(g_hashperturb), servers, remote, qname, qtype, dh);
+ return valrandom(dq->qname->hash(g_hashperturb), servers, dq);
}
-shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)
+shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const DNSQuestion* dq)
{
NumberedServerVector poss;
string largerQuery;
uint16_t qtype;
- typedef std::function<bool(ComboAddress, DNSName, uint16_t, dnsheader*)> blockfilter_t;
+ typedef std::function<bool(DNSQuestion*)> blockfilter_t;
blockfilter_t blockFilter = 0;
{
std::lock_guard<std::mutex> lock(g_luamutex);
std::shared_ptr<DnsCryptQuery> dnsCryptQuery = 0;
#endif
char* query = packet;
- size_t querySize = sizeof(packet);
ssize_t ret = recvmsg(cs->udpFD, &msgh, 0);
cs->queries++;
continue;
}
- uint16_t len = ret;
-
+ uint16_t len = (uint16_t) ret;
#ifdef HAVE_DNSCRYPT
if (cs->dnscryptCtx) {
vector<uint8_t> response;
const uint16_t origFlags = *flags;
unsigned int consumed = 0;
DNSName qname(query, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+
+ DNSQuestion dq(&qname, qtype, &cs->local, &remote, dh, sizeof(packet), len, false);
+
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
{
WriteLock wl(&g_rings.queryLock);
- g_rings.queryRing.push_back({now,remote,qname,len,qtype,*dh});
+ g_rings.queryRing.push_back({now,remote,qname,dq.len,dq.qtype,*dq.dh});
}
if(auto got=localDynBlock->lookup(remote)) {
if(blockFilter) {
std::lock_guard<std::mutex> lock(g_luamutex);
- if(blockFilter(remote, qname, qtype, dh)) {
+ if(blockFilter(&dq)) {
g_stats.blockFilter++;
continue;
}
string pool;
for(const auto& lr : *localRulactions) {
- if(lr.first->matches(remote, qname, qtype, dh, len)) {
- action=(*lr.second)(remote, qname, qtype, dh, len, querySize, &ruleresult);
+ if(lr.first->matches(&dq)) {
+ action=(*lr.second)(&dq, &ruleresult);
if(action != DNSAction::Action::None) {
lr.first->d_matches++;
break;
g_stats.ruleDrop++;
continue;
case DNSAction::Action::Nxdomain:
- dh->rcode = RCode::NXDomain;
- dh->qr=true;
+ dq.dh->rcode = RCode::NXDomain;
+ dq.dh->qr=true;
g_stats.ruleNXDomain++;
break;
case DNSAction::Action::Pool:
break;
}
- if(dh->qr) { // something turned it into a response
+ if(dq.dh->qr) { // something turned it into a response
char* response = query;
- uint16_t responseLen = len;
+ uint16_t responseLen = dq.len;
#ifdef HAVE_DNSCRYPT
- uint16_t responseSize = querySize;
+ uint16_t responseSize = dq.size;
#endif
g_stats.selfAnswered++;
auto policy=localPolicy->policy;
{
std::lock_guard<std::mutex> lock(g_luamutex);
- ss = policy(candidates, remote, qname, qtype, dh).get();
+ ss = policy(candidates, &dq).get();
}
if(!ss) {
ids->origRemote = remote;
ids->sentTime.start();
ids->qname = qname;
- ids->qtype = qtype;
+ ids->qtype = dq.qtype;
ids->origDest.sin4.sin_family=0;
ids->delayMsec = delayMsec;
ids->origFlags = origFlags;
dh->id = idOffset;
if (ss->useECS) {
- handleEDNSClientSubnet(query, querySize, consumed, &len, largerQuery, &(ids->ednsAdded), remote);
+ handleEDNSClientSubnet(query, dq.size, consumed, &dq.len, largerQuery, &(ids->ednsAdded), remote);
}
if (largerQuery.empty()) {
- ret = udpClientSendRequestToBackend(ss, ss->fd, query, len);
+ ret = udpClientSendRequestToBackend(ss, ss->fd, query, dq.len);
}
else {
ret = udpClientSendRequestToBackend(ss, ss->fd, largerQuery.c_str(), largerQuery.size());
};
using servers_t =vector<std::shared_ptr<DownstreamState>>;
+struct DNSQuestion
+{
+ DNSQuestion(const DNSName* name, uint16_t type, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t queryLen, bool isTcp): qname(name), qtype(type), local(lc), remote(rem), dh(header), size(bufferSize), len(queryLen), tcp(isTcp) {};
+
+ const DNSName* qname;
+ const uint16_t qtype;
+ const ComboAddress* local;
+ const ComboAddress* remote;
+ struct dnsheader* dh;
+ size_t size;
+ uint16_t len;
+ const bool tcp;
+};
+
template <class T> using NumberedVector = std::vector<std::pair<unsigned int, T> >;
void* responderThread(std::shared_ptr<DownstreamState> state);
class DNSRule
{
public:
- virtual bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const =0;
+ virtual bool matches(const DNSQuestion* dq) const =0;
virtual string toString() const = 0;
mutable std::atomic<uint64_t> d_matches{0};
};
{
public:
enum class Action { Drop, Nxdomain, Spoof, Allow, HeaderModify, Pool, Delay, None};
- virtual Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const =0;
+ virtual Action operator()(DNSQuestion*, string* ruleresult) const =0;
virtual string toString() const = 0;
};
using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
-typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)> policyfunc_t;
+typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t;
struct ServerPolicy
{
vector<std::function<void(void)>> setupLua(bool client, const std::string& config);
NumberedServerVector getDownstreamCandidates(const servers_t& servers, const std::string& pool);
-std::shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
+std::shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const DNSQuestion* dq);
-std::shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
-std::shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
-std::shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
-std::shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
+std::shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const DNSQuestion* dq);
+std::shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const DNSQuestion* dq);
+std::shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const DNSQuestion* dq);
+std::shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const DNSQuestion* dq);
int getEDNSZ(const char* packet, unsigned int len);
uint16_t getEDNSOptionCode(const char * packet, size_t len);
void dnsdistWebserverThread(int sock, const ComboAddress& local, const string& password);
addQPSPoolRule("com.", 100, "abuse")
-function luarule(remote, qname, qtype, dh, len)
- if(qtype==35) -- NAPTR
+function luarule(dq)
+ if(dq.qtype==35) -- NAPTR
then
return DNSAction.Pool, "abuse" -- send to abuse pool
else
print(string.format("Have %d entries in truncate NMG", truncateNMG:size()))
-function blockFilter(remote, qname, qtype, dh)
- print(string.format("Got query from %s, (%s) port number: %d", remote:tostring(), remote:tostringWithPort(), remote:getPort()))
- if(qtype==255 or truncateNMG:match(remote))
+function blockFilter(dq)
+ print(string.format("Got query from %s, (%s) port number: %d", dq.remoteaddr:toString(), dq.remoteaddr:toStringWithPort(), dq.remoteaddr:getPort()))
+ if(dq.qtype==255 or truncateNMG:match(dq.remoteaddr))
then
-- print("any query, tc=1")
- dh:setTC(true)
- dh:setQR(true)
+ dq.dh:setTC(true)
+ dq.dh:setQR(true)
end
- if(qname:isPartOf(block))
+ if(dq.qname:isPartOf(block))
then
print("Blocking *.powerdns.org")
return true
counter=0
-- called to pick a downstream server, ignores 'up' status
-function luaroundrobin(servers, remote, qname, qtype, dh)
+function luaroundrobin(servers, dq)
counter=counter+1;
return servers[1+(counter % #servers)]
end
d_qps(qps), d_ipv4trunc(ipv4trunc), d_ipv6trunc(ipv6trunc)
{}
- bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
+ bool matches(const DNSQuestion* dq) const override
{
- ComboAddress zeroport(remote);
+ ComboAddress zeroport(*dq->remote);
zeroport.sin4.sin_port=0;
zeroport.truncate(zeroport.sin4.sin_family == AF_INET ? d_ipv4trunc : d_ipv6trunc);
auto iter = d_limits.find(zeroport);
{}
- bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
+ bool matches(const DNSQuestion* qd) const override
{
return d_qps.check();
}
{
}
- bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
+ bool matches(const DNSQuestion* dq) const override
{
- return d_nmg.match(remote);
+ return d_nmg.match(*dq->remote);
}
string toString() const override
{
public:
AllRule() {}
- bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
+ bool matches(const DNSQuestion* dq) const override
{
return true;
}
{
}
- bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
+ bool matches(const DNSQuestion* dq) const override
{
- return dh->cd || (getEDNSZ((const char*)dh, len) & EDNS_HEADER_FLAG_DO); // turns out dig sets ad by default..
+ return dq->dh->cd || (getEDNSZ((const char*)dq->dh, dq->len) & EDNS_HEADER_FLAG_DO); // turns out dig sets ad by default..
}
string toString() const override
d_rules.push_back(r.second);
}
- bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
+ bool matches(const DNSQuestion* dq) const override
{
auto iter = d_rules.begin();
for(; iter != d_rules.end(); ++iter)
- if(!(*iter)->matches(remote, qname, qtype, dh, len))
+ if(!(*iter)->matches(dq))
break;
return iter == d_rules.end();
}
{
}
- bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
+ bool matches(const DNSQuestion* dq) const override
{
- return d_regex.match(qname.toStringNoDot());
+ return d_regex.match(dq->qname->toStringNoDot());
}
string toString() const override
SuffixMatchNodeRule(const SuffixMatchNode& smn) : d_smn(smn)
{
}
- bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
+ bool matches(const DNSQuestion* dq) const override
{
- return d_smn.check(qname);
+ return d_smn.check(*dq->qname);
}
string toString() const override
{
QTypeRule(uint16_t qtype) : d_qtype(qtype)
{
}
- bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
+ bool matches(const DNSQuestion* dq) const override
{
- return d_qtype == qtype;
+ return d_qtype == dq->qtype;
}
string toString() const override
{
class DropAction : public DNSAction
{
public:
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
return Action::Drop;
}
class AllowAction : public DNSAction
{
public:
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
return Action::Allow;
}
public:
QPSAction(int limit) : d_qps(limit, limit)
{}
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
if(d_qps.check())
return Action::Allow;
public:
DelayAction(int msec) : d_msec(msec)
{}
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
*ruleresult=std::to_string(d_msec);
return Action::Delay;
{
public:
PoolAction(const std::string& pool) : d_pool(pool) {}
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
*ruleresult=d_pool;
return Action::Pool;
{
public:
QPSPoolAction(unsigned int limit, const std::string& pool) : d_qps(limit, limit), d_pool(pool) {}
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
if(d_qps.check()) {
*ruleresult=d_pool;
{
public:
RCodeAction(int rcode) : d_rcode(rcode) {}
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
- dh->rcode = d_rcode;
- dh->qr = true; // for good measure
+ dq->dh->rcode = d_rcode;
+ dq->dh->qr = true; // for good measure
return Action::HeaderModify;
}
string toString() const override
class TCAction : public DNSAction
{
public:
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
- dh->tc = true;
- dh->qr = true; // for good measure
+ dq->dh->tc = true;
+ dq->dh->qr = true; // for good measure
return Action::HeaderModify;
}
string toString() const override
SpoofAction(const ComboAddress& a) : d_a(a) { d_aaaa.sin4.sin_family = 0;}
SpoofAction(const ComboAddress& a, const ComboAddress& aaaa) : d_a(a), d_aaaa(aaaa) {}
SpoofAction(const string& cname): d_cname(cname) { d_a.sin4.sin_family = 0; d_aaaa.sin4.sin_family = 0; }
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
+ uint16_t qtype = dq->qtype;
if(d_cname.empty() &&
((qtype == QType::A && d_a.sin4.sin_family == 0) ||
(qtype == QType::AAAA && d_aaaa.sin4.sin_family == 0) || (qtype != QType::A && qtype != QType::AAAA)))
0, 0, 0, 60, // TTL
0, rdatalen};
- DNSName ignore((char*)dh, len, sizeof(dnsheader), false, 0, 0, &consumed);
+ DNSName ignore((char*)dq->dh, dq->len, sizeof(dnsheader), false, 0, 0, &consumed);
- if (bufferSize < (sizeof(dnsheader) + consumed + 4 + sizeof(recordstart) + rdatalen)) {
+ if (dq->size < (sizeof(dnsheader) + consumed + 4 + sizeof(recordstart) + rdatalen)) {
return Action::None;
}
- dh->qr = true; // for good measure
- dh->ra = dh->rd; // for good measure
- dh->ad = false;
- dh->ancount = htons(1);
- dh->arcount = 0; // for now, forget about your EDNS, we're marching over it
+ dq->dh->qr = true; // for good measure
+ dq->dh->ra = dq->dh->rd; // for good measure
+ dq->dh->ad = false;
+ dq->dh->ancount = htons(1);
+ dq->dh->arcount = 0; // for now, forget about your EDNS, we're marching over it
- char* dest = ((char*)dh) +sizeof(dnsheader) + consumed + 4;
+ char* dest = ((char*)dq->dh) +sizeof(dnsheader) + consumed + 4;
memcpy(dest, recordstart, sizeof(recordstart));
if(qtype==QType::A)
memcpy(dest+sizeof(recordstart), &d_a.sin4.sin_addr.s_addr, 4);
string wireData = d_cname.toDNSString();
memcpy(dest+sizeof(recordstart), wireData.c_str(), wireData.length());
}
- len = (dest + sizeof(recordstart) + rdatalen) - (char*)dh;
+ dq->len = (dest + sizeof(recordstart) + rdatalen) - (char*)dq->dh;
return Action::HeaderModify;
}
string toString() const override
class NoRecurseAction : public DNSAction
{
public:
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
- dh->rd = false;
+ dq->dh->rd = false;
return Action::HeaderModify;
}
string toString() const override
if(d_fp)
fclose(d_fp);
}
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
if(!d_fp) {
- vinfolog("Packet from %s for %s %s with id %d", remote.toStringWithPort(), qname.toString(), QType(qtype).getName(), dh->id);
+ vinfolog("Packet from %s for %s %s with id %d", dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id);
}
else {
- string out = qname.toDNSString();
+ string out = dq->qname->toDNSString();
fwrite(out.c_str(), 1, out.size(), d_fp);
- fwrite((void*)&qtype, 1, 2, d_fp);
+ fwrite((void*)&dq->qtype, 1, 2, d_fp);
}
return Action::None;
}
class DisableValidationAction : public DNSAction
{
public:
- DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, uint16_t& len, uint16_t bufferSize, string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
{
- dh->cd = true;
+ dq->dh->cd = true;
return Action::HeaderModify;
}
string toString() const override
mySMN:add(newDNSName("nameAndQtype.tests.powerdns.com."))
addAction(AndRule{SuffixMatchNodeRule(mySMN), QTypeRule("TXT")}, RCodeAction(4))
block=newDNSName("powerdns.org.")
- function blockFilter(remote, qname, qtype, dh)
- if(qname:isPartOf(block))
+ function blockFilter(dq)
+ if(dq.qname:isPartOf(block))
then
print("Blocking *.powerdns.org")
return true
_config_template = """
truncateTC(true)
block=newDNSName("powerdns.org.")
- function blockFilter(remote, qname, qtype, dh)
- if(qname:isPartOf(block))
+ function blockFilter(dq)
+ if(dq.qname:isPartOf(block))
then
print("Blocking *.powerdns.org")
return true
_config_template = """
truncateTC(true)
block=newDNSName("powerdns.org.")
- function blockFilter(remote, qname, qtype, dh)
- if(qname:isPartOf(block))
+ function blockFilter(dq)
+ if(dq.qname:isPartOf(block))
then
print("Blocking *.powerdns.org")
return true