From: bert hubert Date: Fri, 27 Feb 2015 20:44:12 +0000 (+0100) Subject: implement Marek Vavrusa's suggestion that dnsdist could be used for 'split horizon... X-Git-Tag: dnsdist-1.0.0-alpha1~248^2~88^2~106 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=75a2db752e67833fae6e5bb0f7a3d0b23680f472;p=thirdparty%2Fpdns.git implement Marek Vavrusa's suggestion that dnsdist could be used for 'split horizon' setups, plus document it. --- diff --git a/pdns/README-dnsdist.md b/pdns/README-dnsdist.md index 4e5c47aca0..1da9dbe555 100644 --- a/pdns/README-dnsdist.md +++ b/pdns/README-dnsdist.md @@ -156,7 +156,7 @@ example: ``` counter=0 servers=getServers() -function luaroundrobin(remote, qname, qtype) +function luaroundrobin(remote, qname, qtype, dh) counter=counter+1 return servers[1+(counter % #servers)] end @@ -167,6 +167,27 @@ setServerPolicy(luaroundrobin) Incidentally, this is similar to setting: `setServerPolicy(roundrobin)` which uses the C++ based roundrobin policy. +To implement a split horizon, try: + +``` +authServer=newServer2{address="2001:888:2000:1d::2", order=12} +-- order=12 is the current hack to make sure this server does +-- generally get used, will be replaced by dedicated pools later + +function splitSetup(remote, qname, qtype, dh) + if(dh:getRD() == false) + then + return authServer + else + return firstAvailable(remote, qname, qtype, dh) + end +end +``` + +This will forward queries that don't want recursion to a specific +server, and will apply the default load balancing policy to all +other queries. + Running it for real ------------------- First run on the command line, and generate a key: diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index f5625046ef..547be2ec9f 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -44,6 +44,7 @@ /* Known sins: We replace g_ACL w/o locking, might crash + g_policy too probably No centralized statistics We neglect to do recvfromto() on 0.0.0.0 Receiver is currently singlethreaded (not that bad actually) @@ -292,19 +293,9 @@ struct ClientState std::mutex g_luamutex; LuaContext g_lua; -std::function(const ComboAddress& remote, const DNSName& qname, uint16_t qtype)> g_policy; +std::function(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)> g_policy; -shared_ptr getLuaDownstream(const ComboAddress& remote, const DNSName& qname, uint16_t qtype) -{ - //auto pickServer=g_lua.readVariable (void)> >("pickServer"); - - std::lock_guard lock(g_luamutex); - - auto pickServer=g_lua.readVariable(ComboAddress, DNSName, uint16_t)> >("pickServer"); - return pickServer(remote, DNSName(qname), qtype); -} - -shared_ptr firstAvailable(const ComboAddress& remote, const DNSName& qname, uint16_t qtype) +shared_ptr firstAvailable(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh) { for(auto& d : g_dstates) { if(d->isUp() && d->qps.check()) @@ -424,7 +415,7 @@ try } else { std::lock_guard lock(g_luamutex); - ss = g_policy(remote, qname, qtype).get(); + ss = g_policy(remote, qname, qtype, dh).get(); } ss->queries++; @@ -485,9 +476,12 @@ catch(...) Let's start naively. */ -int getTCPDownstream(DownstreamState** ds, const ComboAddress& remote, const DNSName& qname, uint16_t qtype) +int getTCPDownstream(DownstreamState** ds, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh) { - *ds = g_policy(remote, qname, qtype).get(); + { + std::lock_guard lock(g_luamutex); + *ds = g_policy(remote, qname, qtype, dh).get(); + } vinfolog("TCP connecting to downstream %s", (*ds)->remote.toStringWithPort()); int sock = SSocket((*ds)->remote.sin4.sin_family, SOCK_STREAM, 0); @@ -578,13 +572,6 @@ void* tcpClientThread(int pipefd) ci=*citmp; delete citmp; - if(dsock == -1) { - - dsock = getTCPDownstream(&ds, ci.remote, DNSName(), 0); - } - else { - vinfolog("Reusing existing TCP connection to %s", ds->remote.toStringWithPort()); - } uint16_t qlen, rlen; try { @@ -596,12 +583,22 @@ void* tcpClientThread(int pipefd) ds->outstanding++; char query[qlen]; readn2(ci.fd, query, qlen); + uint16_t qtype; + DNSName qname(query, qlen, 12, false, &qtype); + struct dnsheader* dh =(dnsheader*)query; + if(dsock == -1) { + dsock = getTCPDownstream(&ds, ci.remote, qname, qtype, dh); + } + else { + vinfolog("Reusing existing TCP connection to %s", ds->remote.toStringWithPort()); + } + // FIXME: drop AXFR queries here, they confuse us retry:; if(!putMsgLen(dsock, qlen)) { vinfolog("Downstream connection to %s died on us, getting a new one!", ds->remote.toStringWithPort()); close(dsock); - dsock=getTCPDownstream(&ds, ci.remote, DNSName(), 0); + dsock=getTCPDownstream(&ds, ci.remote, qname, qtype, dh); goto retry; } @@ -610,7 +607,7 @@ void* tcpClientThread(int pipefd) if(!getMsgLen(dsock, &rlen)) { vinfolog("Downstream connection to %s died on us phase 2, getting a new one!", ds->remote.toStringWithPort()); close(dsock); - dsock=getTCPDownstream(&ds, ci.remote, DNSName(), 0); + dsock=getTCPDownstream(&ds, ci.remote, qname, qtype, dh); goto retry; } @@ -854,7 +851,7 @@ void setupLua(bool client) } ); - g_lua.writeFunction("setServerPolicy", [](std::function(const ComboAddress&, const DNSName&, uint16_t)> func) { + g_lua.writeFunction("setServerPolicy", [](std::function(const ComboAddress&, const DNSName&, uint16_t, dnsheader*)> func) { g_policy = func; }); @@ -944,6 +941,11 @@ void setupLua(bool client) dh.rd=v; }); + g_lua.registerFunction("getRD", [](dnsheader& dh) { + return (bool)dh.rd; + }); + + g_lua.registerFunction("setTC", [](dnsheader& dh, bool v) { dh.tc=v; }); diff --git a/pdns/dnsdistconf.lua b/pdns/dnsdistconf.lua index 17941d02e0..12b64037fd 100644 --- a/pdns/dnsdistconf.lua +++ b/pdns/dnsdistconf.lua @@ -43,10 +43,20 @@ counter=0 servers=getServers() -- called to pick a downstream server -function luaroundrobin(remote, qname, qtype) +function luaroundrobin(remote, qname, qtype, dh) counter=counter+1; return servers[1+(counter % #servers)] end -- setServerPolicy(luaroundrobin) +authServer=newServer2{address="2001:888:2000:1d::2", order=12} + +function splitSetup(remote, qname, qtype, dh) + if(dh:getRD() == false) + then + return authServer + else + return firstAvailable(remote, qname, qtype, dh) + end +end \ No newline at end of file