responsestats.hh webserver.hh dnsname.hh dnspacket.hh ednssubnet.hh \
filterpo.hh rpzloader.hh ixfr.hh gss_context.hh resolver.hh dnssecinfra.hh \
dnsseckeeper.hh statbag.hh ueberbackend.hh sha.hh dnsbackend.hh comment.hh \
-validate.hh validate-recursor.hh"
+validate.hh validate-recursor.hh sortlist.hh"
CFILES="syncres.cc iputils.cc misc.cc unix_utility.cc qtype.cc \
logger.cc arguments.cc lwres.cc pdns_recursor.cc lua-iputils.cc \
dnslabeltext.cc json.cc ws-recursor.cc ws-api.cc version.cc dns_random.cc \
responsestats.cc webserver.cc rec-carbon.cc secpoll-recursor.cc dnsname.cc \
filterpo.cc rpzloader.cc ixfr.cc dnssecinfra.cc gss_context.cc resolver.cc \
-ednssubnet.cc validate.cc validate-recursor.cc mbedtlssigners.cc"
+ednssubnet.cc validate.cc validate-recursor.cc mbedtlssigners.cc rec-lua-conf.cc \
+sortlist.cc"
./mkpubsuffixcc
cp -a ../ext/mbedtls/library/{rsa.c,bignum.c,oid.c,asn1parse.c,ctr_drbg.c,entropy.c,entropy_poll.c,timing.c} $DIRNAME/ext/mbedtls/library
cp -a ../ext/yahttp/ $DIRNAME/ext/yahttp
+
+mkdir -p $DIRNAME/ext/luawrapper/include
+cp ../ext/luawrapper/include/LuaContext.hpp $DIRNAME/ext/luawrapper/include
echo '#include "../../../config.h"' > $DIRNAME/ext/yahttp/yahttp/yahttp-config.h
mkdir $DIRNAME/rrd
cp tools/rrd/{create,update,makegraphs,index.html} $DIRNAME/rrd
version.o responsestats.o webserver.o ext/yahttp/yahttp/reqresp.o ext/yahttp/yahttp/router.o \
rec-carbon.o secpoll-recursor.o lua-iputils.o iputils.o dnsname.o \
rpzloader.o filterpo.o resolver.o ixfr.o dnssecinfra.o gss_context.o \
-ednssubnet.o validate.o validate-recursor.o mbedtlssigners.o
+ednssubnet.o validate.o validate-recursor.o mbedtlssigners.o \
+rec-lua-conf.o sortlist.o
REC_CONTROL_OBJECTS=rec_channel.o rec_control.o arguments.o misc.o \
unix_utility.o logger.o qtype.o dnslabeltext.o dnsname.o
rec-carbon.cc \
rec_channel.cc rec_channel.hh \
rec_channel_rec.cc \
+ rec-lua-conf.cc \
recpacketcache.cc recpacketcache.hh \
recursor_cache.cc recursor_cache.hh \
reczones.cc \
secpoll-recursor.hh \
selectmplexer.cc \
sillyrecords.cc \
+ sortlist.cc sortlist.hh \
statbag.cc \
syncres.cc syncres.hh \
unix_utility.cc \
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+
#include <netdb.h>
#include <sys/stat.h>
#include <unistd.h>
#include "syncres.hh"
#include <fcntl.h>
#include <fstream>
+#include "sortlist.hh"
+extern SortList g_sortlist;
#include "sstuff.hh"
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include "statbag.hh"
StatBag S;
#endif
-
+void loadRecursorLuaConfig(const std::string& fname);
__thread FDMultiplexer* t_fdm;
__thread unsigned int t_id;
unsigned int g_maxTCPPerClient;
if(ret.size()) {
orderAndShuffle(ret);
+ if(auto sl = g_sortlist.getOrderCmp(dc->d_remote)) {
+ sort(ret.begin(), ret.end(), *sl);
+ variableAnswer=true;
+ }
for(auto i=ret.cbegin(); i!=ret.cend(); ++i) {
pw.startRecord(i->d_name, i->d_type, i->d_ttl, i->d_class, i->d_place);
minTTL = min(minTTL, i->d_ttl);
::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
::arg().set("rpz-files", "RPZ files to load in order, domain or domain=policy pairs separated by commas")="";
::arg().set("rpz-masters", "RPZ master servers, address:name pairs separated by commas")="";
+ ::arg().set("lua-config-file", "More powerful configuration options")="";
::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
::arg().parse(argc,argv);
+ loadRecursorLuaConfig(::arg()["lua-config-file"]);
+
::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
if(::arg().asNum("threads")==1)
--- /dev/null
+#include "ext/luawrapper/include/LuaContext.hpp"
+#include <fstream>
+#include "namespaces.hh"
+#include "logger.hh"
+#include "sortlist.hh"
+
+SortList g_sortlist;
+void loadRecursorLuaConfig(const std::string& fname)
+{
+ LuaContext Lua;
+ if(fname.empty())
+ return;
+ ifstream ifs(fname);
+ if(!ifs) {
+ theL()<<"Unable to read configuration file from '"<<fname<<"': "<<strerror(errno)<<endl;
+ return;
+ }
+ Lua.writeFunction("clearSortlist", []() { g_sortlist.clear(); });
+
+ /* we can get: "1.2.3.4"
+ {"1.2.3.4", "4.5.6.7"}
+ {"1.2.3.4", {"4.5.6.7", "8.9.10.11"}}
+ */
+
+ typedef vector<pair<int,boost::variant<string, vector<pair<int, string> > > > > argvec_t;
+ Lua.writeFunction("addSortList",
+ [](const std::string& formask_,
+ const boost::variant<string, argvec_t>& masks,
+ boost::optional<int> order_)
+ {
+ try {
+ Netmask formask(formask_);
+ int order = order_ ? (*order_) : g_sortlist.getMaxOrder(formask)+1;
+ if(auto str = boost::get<string>(&masks))
+ g_sortlist.addEntry(formask, Netmask(*str), order);
+ else {
+
+ auto vec = boost::get<argvec_t>(&masks);
+ for(const auto& e : *vec) {
+ if(auto s = boost::get<string>(&e.second)) {
+ g_sortlist.addEntry(formask, Netmask(*s), order);
+ }
+ else {
+ const auto& v =boost::get<vector<pair<int, string> > >(e.second);
+ for(const auto& e : v)
+ g_sortlist.addEntry(formask, Netmask(e.second), order);
+ }
+ ++order;
+ }
+ }
+ }
+ catch(std::exception& e) {
+ theL()<<Logger::Error<<"Error in addSortList: "<<e.what()<<endl;
+ }
+ });
+ Lua.executeCode(ifs);
+
+}
--- /dev/null
+#include "sortlist.hh"
+#include "dnsrecords.hh"
+
+void SortList::clear()
+{
+ d_sortlist.clear();
+}
+
+int SortList::getMaxOrder(const Netmask& formask) const
+{
+ int order=0;
+
+ auto place = d_sortlist.lookup(formask);
+ if(place && place->first == formask) {
+ for(const auto& o : place->second.d_orders)
+ order = std::max(order, o->second); // aki, shouldn't this be o.second?
+ }
+
+ return order;
+}
+
+void SortList::addEntry(const Netmask& formask, const Netmask& valmask, int order)
+{
+ if(order < 0) {
+ order=getMaxOrder(formask);
+ ++order;
+ }
+ // cout<<"Adding for netmask "<<formask.toString()<<" the order instruction that "<<valmask.toString()<<" is order "<<order<<endl;
+ d_sortlist[formask].d_orders[valmask]=order;
+}
+
+std::unique_ptr<SortListOrderCmp> SortList::getOrderCmp(const ComboAddress& who)
+{
+ if(!d_sortlist.match(who)) {
+ return std::unique_ptr<SortListOrderCmp>();
+ }
+ auto fnd = d_sortlist.lookup(who);
+ // cerr<<"Returning sort order for "<<who.toString()<<", have "<<fnd->second.d_orders.size()<<" entries"<<endl;
+ return make_unique<SortListOrderCmp>(fnd->second);
+}
+
+bool SortListOrderCmp::operator()(const ComboAddress& a, const ComboAddress& b) const
+{
+ int aOrder=std::numeric_limits<int>::max();
+ int bOrder=aOrder;
+
+ if(d_slo.d_orders.match(a))
+ aOrder = d_slo.d_orders[a];
+ if(d_slo.d_orders.match(b))
+ bOrder = d_slo.d_orders[b];
+
+ return aOrder < bOrder;
+}
+
+static ComboAddress getAddr(const DNSRecord& dr)
+{
+ if(auto addr=getRR<ARecordContent>(dr)) {
+ return addr->getCA();
+ }
+ else
+ return getRR<AAAARecordContent>(dr)->getCA();
+}
+bool SortListOrderCmp::operator()(const DNSRecord& ar, const DNSRecord& br) const
+{
+ if(ar.d_type < br.d_type)
+ return true;
+ if(ar.d_type > br.d_type)
+ return false;
+
+ if(ar.d_type != QType::A && ar.d_type != QType::AAAA)
+ return false; // all other types are equal among themselves
+
+ int aOrder=std::numeric_limits<int>::max();
+ int bOrder=aOrder;
+
+ ComboAddress a=getAddr(ar), b=getAddr(br);
+
+ if(d_slo.d_orders.match(a))
+ aOrder = d_slo.d_orders.lookup(a)->second;
+ else {
+ // cout<<"Could not find anything for "<<a.toString()<<" in our orders!"<<endl;
+ }
+ if(d_slo.d_orders.match(b))
+ bOrder = d_slo.d_orders.lookup(b)->second;
+ else {
+ // cout<<"Could not find anything for "<<b.toString()<<" in our orders!"<<endl;
+ }
+ return aOrder < bOrder;
+}
--- /dev/null
+#pragma once
+#include "iputils.hh"
+#include "dnsrecords.hh"
+
+struct SortListOrder
+{
+ NetmaskTree<int> d_orders;
+};
+
+
+struct SortListOrderCmp
+{
+ SortListOrderCmp(SortListOrder slo) : d_slo(slo) {}
+ bool operator()(const ComboAddress& a, const ComboAddress& b) const;
+ bool operator()(const DNSRecord& a, const DNSRecord& b) const;
+ const SortListOrder d_slo;
+};
+
+class SortList {
+public:
+ void clear();
+ void addEntry(const Netmask& covers, const Netmask& answermask, int order=-1);
+ int getMaxOrder(const Netmask& formask) const;
+ std::unique_ptr<SortListOrderCmp> getOrderCmp(const ComboAddress& who);
+private:
+
+ NetmaskTree<SortListOrder> d_sortlist;
+};