]> granicus.if.org Git - pdns/commitdiff
replace old lua example script by new one, we have reached feature parity
authorbert hubert <bert.hubert@netherlabs.nl>
Mon, 21 Dec 2015 11:02:39 +0000 (11:02 +0000)
committerbert hubert <bert.hubert@netherlabs.nl>
Mon, 21 Dec 2015 11:02:39 +0000 (11:02 +0000)
pdns/lua-recursor4.cc
pdns/lua-recursor4.hh
pdns/powerdns-example-script.lua

index 07657533b10ca6d5271bae4c5015eca688946a5c..d4352c60f7ea331319b402a0f13fac9dd6447d68 100644 (file)
@@ -138,10 +138,10 @@ void RecursorLua4::DNSQuestion::setRecords(const vector<pair<int, DNSRecord> >&
   }
 }
 
-void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl)
+void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl, boost::optional<string> name)
 {
   DNSRecord dr;
-  dr.d_name=qname;
+  dr.d_name=name ? DNSName(*name) : qname;
   dr.d_ttl=ttl.get_value_or(3600);
   dr.d_type = type;
   dr.d_place = place;
@@ -149,9 +149,9 @@ void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& cont
   records.push_back(dr);
 }
 
-void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl)
+void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl, boost::optional<string> name)
 {
-  addRecord(type, content, DNSResourceRecord::ANSWER, ttl);
+  addRecord(type, content, DNSResourceRecord::ANSWER, ttl, name);
 }
   
 RecursorLua4::RecursorLua4(const std::string& fname)
index f8c574c5dc2f33d1c3bb7e824e17ddda159765d0..6af51a50942f59e95d816a7fe788f3c8d17e7931 100644 (file)
@@ -28,8 +28,8 @@ private:
     int rcode{0};
     // struct dnsheader, packet length would be great
     vector<DNSRecord> records;
-    void addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl);
-    void addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl);
+    void addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl, boost::optional<string> name);
+    void addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl, boost::optional<string> name);
     vector<pair<int,DNSRecord> > getRecords();
     void setRecords(const vector<pair<int,DNSRecord> >& records);
     bool variable{false};
index 6a3412b8be26cc898eb86d16e2100d12030690c5..f67cd455c5e659dd8003b57374a239db7b945665 100644 (file)
-pdnslog("pdns-recursor starting!", pdns.loglevels.Info)
-function endswith(s, send)
-        return #s >= #send and s:find(send, #s-#send+1, true) and true or false
+pdnslog("pdns-recursor Lua script starting!", pdns.loglevels.Warning)
+
+blockset = newDS()
+blockset:add{"powerdns.org", "xxx"}
+
+dropset = newDS();
+dropset:add("123.cn")
+
+malwareset = newDS()
+malwareset:add("nl")
+
+-- shows the various ways of blocking, dropping, changing questions
+-- return false to say you did not take over the question, but we'll still listen to 'variable'
+-- to selectively disable the cache
+function preresolve1(dq)
+       print("Got question for "..dq.qname:toString())
+        
+        if blockset:check(dq.qname) then
+                dq.variable = true  -- disable packet cache in any case
+                if dq.qtype == pdns.A then
+                       dq:addAnswer(pdns.A, "1.2.3.4")
+                       dq:addAnswer(pdns.TXT, "\"Hello!\"", 3601) -- ttl       
+                       return true;
+               end
+        end
+        
+        if dropset:check(dq.qname) then
+               dq.rcode = pdns.DROP  
+               return true;
+        end
+
+               
+        
+        if malwareset:check(dq.qname) then
+               dq:addAnswer(pdns.CNAME, "xs.powerdns.com.")
+               dq.rcode = 0
+               dq.followupFunction="followCNAMERecords"    -- this makes PowerDNS lookup your CNAME
+               return true;
+        end        
+        
+       return false; 
 end
 
-function preresolve ( remoteip, domain, qtype )
 
-       print ("prequery handler called for: ", remoteip, "local: ", getlocaladdress(), domain, qtype)
-       pdnslog("a test message.. received query from "..remoteip.." on "..getlocaladdress(), pdns.loglevels.Info);
-
-       if endswith(domain, "f.f.7.7.b.1.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa.")
-       then
-               print("This is our faked AAAA record in reverse")
-               return "getFakePTRRecords", domain, "fe80::21b::77ff:0:0"
-       end
-
-       if domain == "www.followme.com."
-       then
-               print ("Need to CNAME www.followme.com to www.powerdns.com")
-               return "followCNAMERecords", 0, {{qtype=pdns.CNAME, content="www.powerdns.com"}}
-       end
-
-       if domain == "www.donotanswer.org."
-       then
-               print("we won't answer a query for donotanswer.org")
-               return pdns.DROP, {}
-       end
-
-       if domain == "www.donotcache.org."
-       then
-               print("making sure www.donotcache.org will never end up in the cache", pdns.loglevels.Debug)
-               setvariable()
-               return pdns.PASS, {}
-       end
-
-       if domain == "www.powerdns.org." 
-       then
-               local ret={}
-               ret[1]= {qtype=pdns.A, content="85.17.220.215", ttl=86400}
-               print "dealing!"
-               return 0, ret
-       elseif domain == "www.baddomain.com."
-       then
-               print "dealing - faking nx"
-               return pdns.NXDOMAIN, {}
-       elseif domain == "echo."
-       then
-               print "dealing with echo!"
-               return 0, {{qtype=pdns.A, content=remoteip}}
-       elseif domain == "echo6."
-       then
-               print "dealing with echo6!"
-               return 0, {{qtype=pdns.AAAA, content=remoteip}}
-       else
-               print "not dealing!"
-               return pdns.PASS, {}
-       end
+-- this implements DNS64
+
+function nodata(dq)
+        if dq.qtype == pdns.AAAA then
+               dq.followupFunction="getFakeAAAARecords"
+               dq.followupName=dq.qname
+               dq.followupPrefix="fe80::"
+               return true
+        end
+        
+        if dq.qtype == pdns.PTR then
+               dq.followupFunction="getFakePTRRecords"
+               dq.followupName=dq.qname
+               dq.followupPrefix="fe80::"
+               return true
+        end        
+       return false
 end
 
-function nxdomain ( remoteip, domain, qtype )
-       print ("nxhandler called for: ", remoteip, getlocaladdress(), domain, qtype, pdns.AAAA)
-       if qtype ~= pdns.A then 
-               pdnslog("Only A records", pdns.loglevels.Error)
-       return pdns.PASS, {} 
-       end  --  only A records
-       if not string.find(domain, "^www%.") then 
-               pdnslog("Only strings that start with www.", pdns.loglevels.Error)
-       return pdns.PASS, {} 
-       end  -- only things that start with www.
-       
-       setvariable()
-       if matchnetmask(remoteip, {"127.0.0.1/32", "10.1.0.0/16"}) 
-       then 
-               print "dealing"
-               local ret={}
-               ret[1]={qtype=pdns.CNAME, content="www.webserver.com", ttl=3602}
-               ret[2]={qname="www.webserver.com", qtype=pdns.A, content="1.2.3.4", ttl=3602}
-               ret[3]={qname="webserver.com", qtype=pdns.NS, content="ns1.webserver.com", place=2}
---             ret[1]={15, "25 ds9a.nl", 3602}
-               return 0, ret
-       else
-               print "not dealing"
-               return pdns.PASS, ret
-       end
-end
 
-function axfrfilter(remoteip, zone, qname, qtype, ttl, content)
-       if qtype ~= pdns.SOA or zone ~= "secured-by-gost.org"
-       then
-               local ret = {}
-               return pdns.PASS, ret
-       end
+badips = newNMG()
+badips:addMask("127.0.0.0/8")
 
-       print "got soa!"
-       local ret={}
-       ret[1]={qname=qname, qtype=qtype, content=content, ttl=ttl}
-       ret[2]={qname=qname, qtype=pdns.TXT, content=os.date("Retrieved at %Y-%m-%d %H:%M"), ttl=ttl}
-       return 0, ret
+-- this check is applied before any packet parsing is done
+function ipfilter(loc, rem)
+       print("ipfilter called, rem: ", rem:toString(), badips:match(rem))
+       return badips:match(rem)
 end
 
-function nodata ( remoteip, domain, qtype, records )
-       print ("nodata called for: ", remoteip, getlocaladdress(), domain, qtype)
-       if qtype ~= pdns.AAAA then return pdns.PASS, {} end  --  only AAAA records
-
-       setvariable()
-       return "getFakeAAAARecords", domain, "fe80::21b:77ff:0:0"
-end    
-
--- records contains the entire packet, ready for your modifying pleasure
-function postresolve ( remoteip, domain, qtype, records, origrcode )
-       print ("postresolve called for: ", remoteip, getlocaladdress(), domain, qtype, origrcode, pdns.loglevels.Info)
-
-       for key,val in ipairs(records) 
-       do
-               if(val.content == '173.201.188.46' and val.qtype == pdns.A)
-               then
-                       val.content = '127.0.0.1'
-                       setvariable()
-               end
-               if val.qtype == pdns.A and matchnetmask(remoteip, "192.168.0.0/16") and matchnetmask(val.content, "85.17.219.0/24") 
+-- postresolve runs after the packet has been answered, and can be used to change things
+-- or still drop
+function postresolve(dq)
+       print("postresolve called for ",dq.qname:toString())
+       local records = dq:getRecords()
+       for k,v in pairs(records) do
+               print(k, v.name:toString(), v:getContent())
+               if v.type == pdns.A and v:getContent() == "185.31.17.73"
                then
-                       val.content = string.gsub(val.content, "^85.17.219.", "192.168.219.", 1)
-                       setvariable()
+                       print("Changing content!")
+                       v:changeContent("130.161.252.29")
+                       v.ttl=1
                end
-               
-       --      print(val.content)
-       end
-       return origrcode, records
-end    
-
-function prequery ( dnspacket )
-       -- pdnslog ("prequery called for ".. tostring(dnspacket) )
-       qname, qtype = dnspacket:getQuestion()
-       pdnslog ("q: ".. qname.." "..qtype)
-       if qtype == pdns.A and qname == "www.domain.com" 
-       then
-               pdnslog ("calling dnspacket:setRcode", pdns.loglevels.Debug)
-               dnspacket:setRcode(pdns.NXDOMAIN)
-               pdnslog ("called dnspacket:setRcode", pdns.loglevels.Debug)
-               pdnslog ("adding records", pdns.loglevels.Debug)
-               local ret = {}
-               ret[1] = {qname=qname, qtype=qtype, content="1.2.3.4", place=2}
-               ret[2] = {qname=qname, qtype=pdns.TXT, content=os.date("Retrieved at %Y-%m-%d %H:%M"), ttl=ttl}
-               dnspacket:addRecords(ret)
-               pdnslog ("returning true", pdns.loglevels.Debug)
-               return true
-       end
-       pdnslog ("returning false")
-       return false
-end
-
-
--- rename this function to 'postresolve' (and make sure you remove the other one!) to implement djb dnscache-like TTL hiding
-function hidettl ( remoteip, domain, qtype, records, origrcode )
-       for key,val in ipairs(records)
-       do
-               val.ttl=0
-       end
-       return origrcode, records
-end
-
-nmg=iputils.newnmgroup()
-nmg:add("192.121.121.0/24")
-
-ipset=iputils.newipset()
-
-function preoutquery(remoteip, domain, qtype)
-       print("pdns wants to ask "..remoteip:tostring().." about "..domain.." "..qtype.." on behalf of requestor "..getlocaladdress())
-       if(nmg:match(remoteip))
-       then
-               print("We matched the group "..nmg:tostring().."! Killing query dead & adding requestor "..getlocaladdress().." to block list")
-               ipset[iputils.newca(getlocaladdress())]=1
-               return -3,{}
        end
-       return -1,{}
+       dq:setRecords(records)
+       return true
 end
 
+nxdomainsuffix=newDN("com")
 
-local delcount=0
-
-function ipfilter(remoteip)
-       delcount=delcount+1
-       
-       if((delcount % 10000)==0)
+function preresolve(dq)
+       print("Hooking: ",dq.qname:toString())
+       if dq.qname:isPartOf(nxdomainsuffix)
        then
-               print("Clearing ipset!")
-               ipset=iputils.newipset()  -- clear it
-       end
-       
-       if(ipset[remoteip] ~= nil) then
-               return 1
+               dq.rcode=0 -- make it a normal answer
+               dq:addAnswer(pdns.CNAME, "ourhelpfulservice.com")
+               dq:addAnswer(pdns.A, "1.2.3.4", 60, "ourhelpfulservice.com")
+               return true
        end
-       return -1
-end
+       return false
+end
\ No newline at end of file