From a3e7b73528a96a3642adb42dc1e729ea2e8765f4 Mon Sep 17 00:00:00 2001 From: bert hubert Date: Thu, 17 Dec 2015 11:34:11 +0100 Subject: [PATCH] move lua scripts in resolver over to glorious luawrapper4, plus vamp up semantics --- pdns/lua-recursor.cc | 14 +-- pdns/lua-recursor4.cc | 246 ++++++++++++++++++++++++++++++++++++++++-- pdns/lua-recursor4.hh | 37 ++++++- pdns/pdns_recursor.cc | 26 ++--- pdns/syncres.cc | 6 +- pdns/syncres.hh | 7 +- 6 files changed, 300 insertions(+), 36 deletions(-) diff --git a/pdns/lua-recursor.cc b/pdns/lua-recursor.cc index 56c02ca21..5064dbc30 100644 --- a/pdns/lua-recursor.cc +++ b/pdns/lua-recursor.cc @@ -3,7 +3,7 @@ #endif #include "lua-recursor.hh" // to avoid including all of syncres.hh -int directResolve(const std::string& qname, const QType& qtype, int qclass, vector& ret); +int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector& ret); #if !defined(HAVE_LUA) @@ -81,7 +81,7 @@ RecursorLua::RecursorLua(const std::string &fname) lua_setglobal(d_lua, "getregisteredname"); } -int followCNAMERecords(vector& ret, const QType& qtype) +static int followCNAMERecords(vector& ret, const QType& qtype) { vector resolved; string target; // XXX DNSNAME PAIN @@ -97,7 +97,7 @@ int followCNAMERecords(vector& ret, const QType& qtype) if(target[target.size()-1]!='.') target.append(1, '.'); - int rcode=directResolve(target, qtype, 1, resolved); // 1 == class + int rcode=directResolve(DNSName(target), qtype, 1, resolved); // 1 == class for(const DNSRecord& rr : resolved) { @@ -108,9 +108,9 @@ int followCNAMERecords(vector& ret, const QType& qtype) } -int getFakeAAAARecords(const std::string& qname, const std::string& prefix, vector& ret) +static int getFakeAAAARecords(const std::string& qname, const std::string& prefix, vector& ret) { - int rcode=directResolve(qname, QType(QType::A), 1, ret); + int rcode=directResolve(DNSName(qname), QType(QType::A), 1, ret); ComboAddress prefixAddress(prefix); @@ -129,7 +129,7 @@ int getFakeAAAARecords(const std::string& qname, const std::string& prefix, vect return rcode; } -int getFakePTRRecords(const DNSName& qname, const std::string& prefix, vector& ret) +static int getFakePTRRecords(const DNSName& qname, const std::string& prefix, vector& ret) { /* qname has a reverse ordered IPv6 address, need to extract the underlying IPv4 address from it and turn it into an IPv4 in-addr.arpa query */ @@ -148,7 +148,7 @@ int getFakePTRRecords(const DNSName& qname, const std::string& prefix, vector& ret, const QType& qtype) +{ + vector resolved; + DNSName target; + for(const DNSRecord& rr : ret) { + if(rr.d_type == QType::CNAME) { + target=getRR(rr)->getTarget(); + break; + } + } + if(target.empty()) + return 0; + + int rcode=directResolve(target, qtype, 1, resolved); // 1 == class + + for(const DNSRecord& rr : resolved) { + ret.push_back(rr); + } + return rcode; + +} + +static int getFakeAAAARecords(const DNSName& qname, const std::string& prefix, vector& ret) +{ + int rcode=directResolve(qname, QType(QType::A), 1, ret); + + ComboAddress prefixAddress(prefix); + + for(DNSRecord& rr : ret) + { + if(rr.d_type == QType::A && rr.d_place==DNSResourceRecord::ANSWER) { + ComboAddress ipv4(getRR(rr)->getCA()); + uint32_t tmp; + memcpy((void*)&tmp, &ipv4.sin4.sin_addr.s_addr, 4); + // tmp=htonl(tmp); + memcpy(((char*)&prefixAddress.sin6.sin6_addr.s6_addr)+12, &tmp, 4); + rr.d_content = std::make_shared(prefixAddress); + rr.d_type = QType::AAAA; + } + } + return rcode; +} + +static int getFakePTRRecords(const DNSName& qname, const std::string& prefix, vector& ret) +{ + /* qname has a reverse ordered IPv6 address, need to extract the underlying IPv4 address from it + and turn it into an IPv4 in-addr.arpa query */ + ret.clear(); + vector parts = qname.getRawLabels(); + + if(parts.size() < 8) + return -1; + + string newquery; + for(int n = 0; n < 4; ++n) { + newquery += + lexical_cast(strtol(parts[n*2].c_str(), 0, 16) + 16*strtol(parts[n*2+1].c_str(), 0, 16)); + newquery.append(1,'.'); + } + newquery += "in-addr.arpa."; + + + int rcode = directResolve(DNSName(newquery), QType(QType::PTR), 1, ret); + for(DNSRecord& rr : ret) + { + if(rr.d_type == QType::PTR && rr.d_place==DNSResourceRecord::ANSWER) { + rr.d_name = qname; + } + } + return rcode; + +} + +vector > RecursorLua4::DNSQuestion::getRecords() +{ + vector > ret; + int num=1; + for(const auto& r : records) { + ret.push_back({num++, r}); + } + return ret; +} +void RecursorLua4::DNSQuestion::setRecords(const vector >& recs) +{ + records.clear(); + for(const auto& p : recs) { + records.push_back(p.second); + cout<<"Setting: "<getZoneRepresentation()< ttl) +{ + DNSRecord dr; + dr.d_name=qname; + dr.d_ttl=ttl.get_value_or(3600); + dr.d_type = type; + dr.d_place = place; + dr.d_content = shared_ptr(DNSRecordContent::mastermake(type, 1, content)); + records.push_back(dr); +} + +void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional ttl) +{ + addRecord(type, content, DNSResourceRecord::ANSWER, ttl); +} + RecursorLua4::RecursorLua4(const std::string& fname) { d_lw = new LuaContext; d_lw->writeFunction("newDN", [](const std::string& dom){ return DNSName(dom); }); d_lw->registerFunction("isPartOf", &DNSName::isPartOf); - d_lw->registerFunction("toString", &ComboAddress::toString); - d_lw->registerFunction("toString", &DNSName::toString); + //d_lw->registerFunction("toString", &ComboAddress::toString); + d_lw->registerFunction("toString", [](const DNSName&dn ) { return dn.toString(); }); + d_lw->registerMember("qname", &DNSQuestion::qname); + d_lw->registerMember("qtype", &DNSQuestion::qtype); + d_lw->registerMember("rcode", &DNSQuestion::rcode); + d_lw->registerMember("variable", &DNSQuestion::variable); + d_lw->registerMember("followupFunction", &DNSQuestion::followupFunction); + d_lw->registerMember("followupPrefix", &DNSQuestion::followupPrefix); + d_lw->registerMember("followupName", &DNSQuestion::followupName); + d_lw->registerMember("name", &DNSRecord::d_name); + d_lw->registerMember("type", &DNSRecord::d_type); + d_lw->registerMember("ttl", &DNSRecord::d_ttl); + + d_lw->registerFunction("getContent", [](const DNSRecord& dr) { return dr.d_content->getZoneRepresentation(); }); + + + d_lw->registerFunction("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.d_content = shared_ptr(DNSRecordContent::mastermake(dr.d_type, 1, newContent)); }); + d_lw->registerFunction("addAnswer", &DNSQuestion::addAnswer); + d_lw->registerFunction("getRecords", &DNSQuestion::getRecords); + d_lw->registerFunction("setRecords", &DNSQuestion::setRecords); + + d_lw->writeFunction("newDS", []() { return SuffixMatchNode(); }); + d_lw->registerFunction > >)>("add", + [](SuffixMatchNode&smn, const boost::variant > >& in) + { + try { + if(auto s = boost::get(&in)) { + smn.add(DNSName(*s)); + } + else if(auto v = boost::get > >(&in)) { + for(const auto& s : *v) + smn.add(DNSName(s.second)); + } + else + smn.add(boost::get(in)); + } + catch(std::exception& e) { cerr<registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check); + + + vector> pd{ + {"PASS", (int)PolicyDecision::PASS}, {"DROP", (int)PolicyDecision::DROP}, + {"TRUNCATE", (int)PolicyDecision::TRUNCATE} + }; + + for(const auto& n : QType::names) + pd.push_back({n.first, n.second}); + - vector> pd{{"PASS", PolicyDecision::PASS}, {"DROP", PolicyDecision::DROP}, {"TRUNCATE", PolicyDecision::TRUNCATE}}; d_lw->writeVariable("pdns", pd); ifstream ifs(fname); if(!ifs) { - theL()<<"Unable to read configuration file from '"<executeCode(ifs); + + d_preresolve = d_lw->readVariable>("preresolve").get_value_or(0); + d_nodata = d_lw->readVariable>("nodata").get_value_or(0); + d_nxdomain = d_lw->readVariable>("nxdomain").get_value_or(0); + d_postresolve = d_lw->readVariable>("postresolve").get_value_or(0); + + // d_ipfilter = d_lw->readVariable>("ipfilter").get_value_or(0); } bool RecursorLua4::preresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, vector& res, int& ret, bool* variable) { - const auto function = d_lw->readVariable>("preresolve"); - if(!function) + return genhook(d_preresolve, remote, local, query, qtype, res, ret, variable); +} + +bool RecursorLua4::nxdomain(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, vector& res, int& ret, bool* variable) +{ + return genhook(d_nxdomain, remote, local, query, qtype, res, ret, variable); +} + +bool RecursorLua4::nodata(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, vector& res, int& ret, bool* variable) +{ + return genhook(d_nodata, remote, local, query, qtype, res, ret, variable); +} + +bool RecursorLua4::postresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, vector& res, int& ret, bool* variable) +{ + return genhook(d_postresolve, remote, local, query, qtype, res, ret, variable); +} + +bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, vector& res, int& ret) +{ + return genhook(d_postresolve, ns, requestor, query, qtype, res, ret, 0); +} + +bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh) +{ + if(d_ipfilter) + return d_ipfilter(remote, local); +} + +bool RecursorLua4::genhook(luacall_t& func, const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, vector& res, int& ret, bool* variable) +{ + if(!func) return false; - ret = function(remote, local, query, qtype.getCode()); - return true; -} \ No newline at end of file + + auto dq = std::make_shared(); + dq->qname = query; + dq->qtype = qtype.getCode(); + dq->local=local; + dq->remote=remote; + dq->records = res; + + bool handled=func(dq); + if(variable) *variable = dq->variable; // could still be set to indicate this *name* is variable + + if(handled) { + ret=dq->rcode; + + if(!dq->followupFunction.empty()) { + if(dq->followupFunction=="followCNAMERecords") { + ret = followCNAMERecords(dq->records, qtype); + } + else if(dq->followupFunction=="getFakeAAAARecords") { + ret=getFakeAAAARecords(dq->followupName, dq->followupPrefix, dq->records); + } + else if(dq->followupFunction=="getFakePTRRecords") { + ret=getFakePTRRecords(dq->followupName, dq->followupPrefix, dq->records); + } + } + res=dq->records; + + + + } + + + // see if they added followup work for us too + return handled; +} diff --git a/pdns/lua-recursor4.hh b/pdns/lua-recursor4.hh index 15ee5e07a..f10032f67 100644 --- a/pdns/lua-recursor4.hh +++ b/pdns/lua-recursor4.hh @@ -2,15 +2,48 @@ #include "iputils.hh" #include "dnsname.hh" #include "namespaces.hh" +#include "dnsrecords.hh" class LuaContext; -class RecursorLua4 +class RecursorLua4 : public boost::noncopyable { public: explicit RecursorLua4(const std::string& fname); - // ~RecursorLua(); + bool preresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, vector& res, int& ret, bool* variable); + bool nxdomain(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, vector& res, int& ret, bool* variable); + bool nodata(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, vector& res, int& ret, bool* variable); + bool postresolve(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, vector& res, int& ret, bool* variable); + + bool preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, vector& res, int& ret); + bool ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader&); + private: + struct DNSQuestion + { + DNSName qname; + uint16_t qtype; + ComboAddress local, remote; + int rcode{0}; + // struct dnsheader, packet length would be great + vector records; + void addAnswer(uint16_t type, const std::string& content, boost::optional ttl); + void addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional ttl); + vector > getRecords(); + void setRecords(const vector >& records); + bool variable{false}; + + string followupFunction; + string followupPrefix; + DNSName followupName; + }; + + LuaContext* d_lw; + typedef std::function)> luacall_t; + luacall_t d_preresolve, d_nxdomain, d_nodata, d_postresolve, d_preoutquery, d_postoutquery; + bool genhook(luacall_t& func, const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, vector& res, int& ret, bool* variable); + typedef std::function ipfilter_t; + ipfilter_t d_ipfilter; }; diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index ab7dd54a8..df26a74a3 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -96,7 +96,7 @@ uint64_t g_latencyStatSize; bool g_logCommonErrors; bool g_anyToTcp; uint16_t g_udpTruncationThreshold, g_outgoingEDNSBufsize; -__thread shared_ptr* t_pdl; +__thread shared_ptr* t_pdl; __thread addrringbuf_t* t_remotes, *t_servfailremotes, *t_largeanswerremotes; @@ -596,7 +596,6 @@ catch(...) void startDoResolve(void *p) { - RecursorLua4 rl4("./recursor4.lua"); DNSComboWriter* dc=(DNSComboWriter *)p; try { t_queryring->push_back(make_pair(dc->d_mdp.d_qname, dc->d_mdp.d_qtype)); @@ -717,7 +716,7 @@ void startDoResolve(void *p) } - if(/* !t_pdl->get() ||*/ !rl4.preresolve(dc->d_remote, local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer)) { + if(!t_pdl->get() || !(*t_pdl)->preresolve(dc->d_remote, local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer)) { try { res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret); } @@ -767,7 +766,7 @@ void startDoResolve(void *p) ret.push_back(spoofed); goto haveAnswer; } - + if(t_pdl->get()) { if(res == RCode::NoError) { auto i=ret.cbegin(); @@ -776,11 +775,11 @@ void startDoResolve(void *p) break; if(i == ret.cend()) (*t_pdl)->nodata(dc->d_remote,local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer); - } - else if(res == RCode::NXDomain) - (*t_pdl)->nxdomain(dc->d_remote,local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer); - + } + else if(res == RCode::NXDomain) + (*t_pdl)->nxdomain(dc->d_remote,local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer); + (*t_pdl)->postresolve(dc->d_remote,local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer); } } @@ -1197,7 +1196,10 @@ string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fr } if(t_pdl->get()) { - if((*t_pdl)->ipfilter(fromaddr, destaddr)) { + struct dnsheader dh; + memcpy(&dh, response.c_str(), sizeof(dh)); + + if((*t_pdl)->ipfilter(fromaddr, destaddr, dh)) { if(!g_quiet) L<getTid()<<"/"<numProcesses()<<"] DROPPED question from "<(new RecursorLua(fname)); + *t_pdl = shared_ptr(new RecursorLua4(fname)); } } catch(std::exception& e) { @@ -2395,11 +2397,11 @@ try L<(); + t_pdl = new shared_ptr(); try { if(!::arg()["lua-dns-script"].empty()) { - *t_pdl = shared_ptr(new RecursorLua(::arg()["lua-dns-script"])); + *t_pdl = shared_ptr(new RecursorLua4(::arg()["lua-dns-script"])); L< -#include "lua-recursor.hh" +#include "lua-recursor4.hh" #include "utility.hh" #include "syncres.hh" #include @@ -1369,13 +1369,13 @@ int SyncRes::doResolveAt(set nameservers, DNSName auth, bool flawedNSSe // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc -int directResolve(const std::string& qname, const QType& qtype, int qclass, vector& ret) +int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector& ret) { struct timeval now; gettimeofday(&now, 0); SyncRes sr(now); - int res = sr.beginResolve(DNSName(qname), QType(qtype), qclass, ret); // DNSName conversion XXX + int res = sr.beginResolve(qname, QType(qtype), qclass, ret); return res; } diff --git a/pdns/syncres.hh b/pdns/syncres.hh index 4612c2741..2b18b02ea 100644 --- a/pdns/syncres.hh +++ b/pdns/syncres.hh @@ -22,10 +22,11 @@ #include #include "mtasker.hh" #include "iputils.hh" + #include "filterpo.hh" void primeHints(void); -class RecursorLua; +class RecursorLua4; struct BothRecordsAndSignatures { @@ -292,7 +293,7 @@ public: return d_trace.str(); } - void setLuaEngine(shared_ptr pdl) + void setLuaEngine(shared_ptr pdl) { d_pdl = pdl; } @@ -474,7 +475,7 @@ private: vector getAddrs(const DNSName &qname, int depth, set& beenthere); private: ostringstream d_trace; - shared_ptr d_pdl; + shared_ptr d_pdl; string d_prefix; bool d_cacheonly; bool d_nocache; -- 2.40.0