]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
initial stab at 'ALIAS' or 'ANAME' records for PowerDNS. To use, set an ALIAS record...
authorbert hubert <bert.hubert@netherlabs.nl>
Sun, 21 Sep 2014 10:35:37 +0000 (12:35 +0200)
committerbert hubert <bert.hubert@netherlabs.nl>
Sun, 21 Sep 2014 10:35:37 +0000 (12:35 +0200)
@ IN SOA ns1 ahu 2014091619 7200 3600 1209600 3600
@ IN NS ns1
@ IN NS ns2
www IN CNAME xs.powerdns.com.
ns1 IN A 1.2.3.4
ns2 IN A 4.3.2.1
@ IN ALIAS www.powerdns.com.
@ IN MX 25 outpost.ds9a.nl.
elsewhere IN CNAME @

Semantics are that real records override the ALIAS. We only reach out to the alias record if nothing else matched.
this currently breaks ANY queries for the apex btw.

pdns/dnsproxy.cc
pdns/dnsproxy.hh
pdns/dnsrecords.cc
pdns/dnsrecords.hh
pdns/packethandler.cc
pdns/qtype.hh
pdns/sdig.cc

index 00fd5899e9788188be83c449167282a307a3920d..e674f3d4858ba9bc220f5c83c2f5fe67bf045ba5 100644 (file)
@@ -28,7 +28,7 @@
 #include "dns.hh"
 #include "logger.hh"
 #include "statbag.hh"
-
+#include <boost/foreach.hpp>
 
 extern StatBag S;
 extern PacketCache PC;
@@ -106,6 +106,7 @@ bool DNSProxy::sendPacket(DNSPacket *p)
     ce.qtype = p->qtype.getCode();
     ce.qname = p->qdomain;
     ce.anyLocal = p->d_anyLocal;
+    ce.complete=0;
     d_conntrack[id]=ce;
   }
   p->d.id=id^d_xor;
@@ -120,6 +121,42 @@ bool DNSProxy::sendPacket(DNSPacket *p)
   return true;
 
 }
+
+//! look up qname aname with r->qtype, plonk it in the answer section of 'r' with name target
+bool DNSProxy::completePacket(DNSPacket *r, const std::string& target,const std::string& aname)
+{
+  uint16_t id;
+  {
+    Lock l(&d_lock);
+    id=getID_locked();
+
+    ConntrackEntry ce;
+    ce.id       = r->d.id;
+    ce.remote =   r->d_remote;
+    ce.outsock  = r->getSocket();
+    ce.created  = time( NULL );
+    ce.qtype = r->qtype.getCode();
+    ce.qname = stripDot(target);
+    ce.anyLocal = r->d_anyLocal;
+    ce.complete = r;
+    ce.aname=aname;
+    d_conntrack[id]=ce;
+  }
+
+  vector<uint8_t> packet;
+  DNSPacketWriter pw(packet, target, r->qtype.getCode());
+  pw.getHeader()->rd=true;
+  pw.getHeader()->id=id ^ d_xor;
+
+  if(send(d_sock,&packet[0], packet.size() , 0)<0) { // zoom
+    L<<Logger::Error<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl;
+  }
+
+  return true;
+
+}
+
+
 /** This finds us an unused or stale ID. Does not actually clean the contents */
 int DNSProxy::getID_locked()
 {
@@ -130,11 +167,13 @@ int DNSProxy::getID_locked()
       return n;
     }
     else if(i->second.created<time(0)-60) {
-      if(i->second.created)
+      if(i->second.created) {
         L<<Logger::Warning<<"Recursive query for remote "<<
           i->second.remote.toStringWithPort()<<" with internal id "<<n<<
           " was not answered by backend within timeout, reusing id"<<endl;
-      
+       
+       delete i->second.complete;
+      }
       return n;
     }
   }
@@ -182,6 +221,7 @@ void DNSProxy::mainloop(void)
           L<<Logger::Error<<"Received packet from recursor backend with id "<<(d.id^d_xor)<<" which is a duplicate"<<endl;
           continue;
         }
+       
         d.id=i->second.id;
         memcpy(buffer,&d,sizeof(d));  // commit spoofed id
 
@@ -191,14 +231,56 @@ void DNSProxy::mainloop(void)
 
         if(p.qtype.getCode() != i->second.qtype || p.qdomain != i->second.qname) {
           L<<Logger::Error<<"Discarding packet from recursor backend with id "<<(d.id^d_xor)<<
-            ", qname or qtype mismatch"<<endl;
+            ", qname or qtype mismatch ("<<p.qtype.getCode()<<" v " <<i->second.qtype<<", "<<p.qdomain<<" v "<<i->second.qname<<")"<<endl;
           continue;
         }
 
         /* Set up iov and msgh structures. */
         memset(&msgh, 0, sizeof(struct msghdr));
-        iov.iov_base = buffer;
-        iov.iov_len = len;
+       string reply; // needs to be alive at time of sendmsg!
+       if(i->second.complete) {
+
+         MOADNSParser mdp(p.getString());
+         //      cerr<<"Got completion, "<<mdp.d_answers.size()<<" answers, rcode: "<<mdp.d_header.rcode<<endl;
+         for(MOADNSParser::answers_t::const_iterator j=mdp.d_answers.begin(); j!=mdp.d_answers.end(); ++j) {        
+           //      cerr<<"comp: "<<(int)j->first.d_place-1<<" "<<j->first.d_label<<" " << DNSRecordContent::NumberToType(j->first.d_type)<<" "<<j->first.d_content->getZoneRepresentation()<<endl;
+           if(j->first.d_place == DNSRecord::Answer || (j->first.d_place == DNSRecord::Nameserver && j->first.d_type == QType::SOA)) {
+           
+             DNSResourceRecord rr;
+
+             if(j->first.d_type == i->second.qtype || j->first.d_type==QType::SOA) {
+               rr.qname=i->second.aname;
+               rr.qtype = j->first.d_type;
+               rr.ttl=j->first.d_ttl;
+               rr.d_place= (DNSResourceRecord::Place)j->first.d_place;
+               shared_ptr<MXRecordContent> mx=boost::dynamic_pointer_cast<MXRecordContent>(j->first.d_content);
+               shared_ptr<SRVRecordContent> srv=boost::dynamic_pointer_cast<SRVRecordContent>(j->first.d_content);
+               if(mx) {
+                 rr.content=mx->d_mxname;
+                 rr.priority=mx->d_preference;
+               }
+               else if(srv) {
+                 rr.content = lexical_cast<string>(srv->d_weight)+" "+lexical_cast<string>(srv->d_port)+" "+srv->d_target;
+                 rr.priority=srv->d_preference;
+               }
+               else {
+                 rr.content=j->first.d_content->getZoneRepresentation();
+               }
+               i->second.complete->addRecord(rr);
+             }
+           }
+         }
+         i->second.complete->setRcode(mdp.d_header.rcode);
+         reply=i->second.complete->getString();
+         iov.iov_base = (void*)reply.c_str();
+         iov.iov_len = reply.length();
+         delete i->second.complete;
+         i->second.complete=0;
+       }
+       else {
+         iov.iov_base = buffer;
+         iov.iov_len = len;
+       }
         msgh.msg_iov = &iov;
         msgh.msg_iovlen = 1;
         msgh.msg_name = (struct sockaddr*)&i->second.remote;
index 95ba9ab01d7f394834809c7f5bf625fbcf22b48d..32155fdcd985c61befbb7dba02a02f1b73d18e62 100644 (file)
@@ -55,6 +55,7 @@ public:
   void go(); //!< launches the actual thread
   void onlyFrom(const string &ips); //!< Only these netmasks are allowed to recurse via us
   bool sendPacket(DNSPacket *p);    //!< send out a packet and make a conntrack entry to we can send back the answer
+  bool completePacket(DNSPacket *r, const std::string& target,const std::string& aname);
 
   void mainloop();                  //!< this is the main loop that receives reply packets and sends them out again
   static void *launchhelper(void *p)
@@ -80,6 +81,8 @@ private:
     time_t created;
     string qname;
     uint16_t qtype;
+    DNSPacket* complete;
+    string aname;
     boost::optional<ComboAddress> anyLocal;
   };
 
index f54041923627d062d8053267a12e8ab46a47901a..4c9a05407e6c70275d8206ef6e2a58b3e8116246 100644 (file)
@@ -121,6 +121,7 @@ boilerplate_conv(AAAA, ns_t_aaaa, conv.xfrIP6(d_ip6); );
 boilerplate_conv(NS, ns_t_ns, conv.xfrLabel(d_content, true));
 boilerplate_conv(PTR, ns_t_ptr, conv.xfrLabel(d_content, true));
 boilerplate_conv(CNAME, ns_t_cname, conv.xfrLabel(d_content, true));
+boilerplate_conv(ALIAS, QType::ALIAS, conv.xfrLabel(d_content, true));
 boilerplate_conv(DNAME, ns_t_dname, conv.xfrLabel(d_content));
 boilerplate_conv(MR, ns_t_mr, conv.xfrLabel(d_alias, true));
 boilerplate_conv(MINFO, ns_t_minfo, conv.xfrLabel(d_rmailbx, true); conv.xfrLabel(d_emailbx, true));
@@ -497,6 +498,7 @@ void reportOtherTypes()
 {
    AFSDBRecordContent::report();
    DNAMERecordContent::report();
+   ALIASRecordContent::report();
    SPFRecordContent::report();
    NAPTRRecordContent::report();
    LOCRecordContent::report();
index 893f71a9f08596001ca826bc8a55f5fd3726e471..4f864483a2d7910d19ae474560b03c747528e465 100644 (file)
@@ -84,7 +84,6 @@ public:
 
   includeboilerplate(MX)
 
-private:
   uint16_t d_preference;
   string d_mxname;
 };
@@ -132,7 +131,6 @@ public:
 
   includeboilerplate(SRV)
 
-private:
   uint16_t d_preference, d_weight, d_port;
   string d_target;
 };
@@ -201,6 +199,16 @@ private:
   string d_content;
 };
 
+class ALIASRecordContent : public DNSRecordContent
+{
+public:
+  includeboilerplate(ALIAS)
+
+private:
+  string d_content;
+};
+
+
 class DNAMERecordContent : public DNSRecordContent
 {
 public:
index 1e7bcdb9ae3f4c5f8196977e3329e3e1c157ea91..1d66a9793152ed18904003690f90cf16cb52b159 100644 (file)
@@ -970,6 +970,7 @@ DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
 
   vector<DNSResourceRecord> rrset;
   bool weDone=0, weRedirected=0, weHaveUnauth=0;
+  string haveAlias;
 
   DNSPacket *r=0;
   bool noCache=false;
@@ -1159,6 +1160,7 @@ DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
     // see what we get..
     B.lookup(QType(QType::ANY), target, p, sd.domain_id);
     rrset.clear();
+    haveAlias.clear();
     weDone = weRedirected = weHaveUnauth =  false;
     
     while(B.get(rr)) {
@@ -1179,6 +1181,10 @@ DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
       if(rr.qtype.getCode() == QType::CNAME && p->qtype.getCode() != QType::CNAME) 
         weRedirected=1;
 
+      if(DP && rr.qtype.getCode() == QType::ALIAS) {
+       haveAlias=rr.content;
+      }
+
       // Filter out all SOA's and add them in later
       if(rr.qtype.getCode() == QType::SOA)
         continue;
@@ -1198,13 +1204,19 @@ DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
     }
 
 
-    DLOG(L<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<endl);
+    DLOG(L<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
     if(p->qtype.getCode() == QType::DS && weHaveUnauth &&  !weDone && !weRedirected && d_dk.isSecuredZone(sd.qname)) {
       DLOG(L<<"Q for DS of a name for which we do have NS, but for which we don't have on a zone with DNSSEC need to provide an AUTH answer that proves we don't"<<endl);
       makeNOError(p, r, target, "", sd, 1);
       goto sendit;
     }
 
+    if(!haveAlias.empty() && !weDone) {
+      DLOG(L<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
+      DP->completePacket(r, haveAlias, target);
+      return 0;
+    }
+
     if(rrset.empty()) {
       DLOG(L<<"checking qtype.getCode() ["<<(p->qtype.getCode())<<"] against QType::DS ["<<(QType::DS)<<"]"<<endl);
       if(p->qtype.getCode() == QType::DS)
@@ -1217,7 +1229,7 @@ DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
         }
       }
 
-      
+
       DLOG(L<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
       bool wereRetargeted(false), nodata(false);
       string wildcard;
index ba83eb298e900fdf678714a6aa3d8526bdc3b723..27430fdc13c46c180ac4d0fb0eff567b158c250b 100644 (file)
@@ -82,7 +82,7 @@ public:
 #undef DS
   enum typeenum {A=1, NS=2, CNAME=5, SOA=6, MR=9, PTR=12, HINFO=13, MX=15, TXT=16, RP=17, AFSDB=18, SIG=24, KEY=25, AAAA=28, LOC=29, SRV=33, NAPTR=35, KX=36,
                 CERT=37, A6=38, DNAME=39, OPT=41, DS=43, SSHFP=44, IPSECKEY=45, RRSIG=46, NSEC=47, DNSKEY=48, DHCID=49, NSEC3=50, NSEC3PARAM=51,
-     TLSA=52, SPF=99, EUI48=108, EUI64=109, TSIG=250, IXFR=251, AXFR=252, MAILB=253, MAILA=254, ANY=255, URL=256, MBOXFW=257, CURL=258, ADDR=259, DLV=32769} types;
+                TLSA=52, SPF=99, EUI48=108, EUI64=109, TSIG=250, IXFR=251, AXFR=252, MAILB=253, MAILA=254, ANY=255, URL=256, MBOXFW=257, CURL=258, ADDR=259, ALIAS=260, DLV=32769} types;
   typedef pair<string,uint16_t> namenum;
   static vector<namenum> names;
 
@@ -166,6 +166,7 @@ private:
       qtype_insert("MBOXFW", 257);
       qtype_insert("CURL", 258);
       qtype_insert("ADDR", 259);
+      qtype_insert("ALIAS", 260);
       qtype_insert("DLV", 32769);
     }
   } initializer;
index 08a015cd7736311acf80b5df19fa295789a4095e..e4e9e9c759a964fc82ae0250f79466c417e29b5e 100644 (file)
@@ -62,7 +62,7 @@ try
   }
   //  pw.setRD(true);
  
 /*
+ /*
   pw.startRecord("powerdns.com", DNSRecordContent::TypeToNumber("NS"));
   NSRecordContent nrc("ns1.powerdns.com");
   nrc.toPacket(pw);