]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - pdns/dnsproxy.cc
Merge pull request #7870 from omoerbeek/stubquery-fix-arg
[thirdparty/pdns.git] / pdns / dnsproxy.cc
index 114c47253739dc1b947fc4d2b1832bd7310f0796..69e5fd1b56e4f856e44f8e9e8662db7836c31825 100644 (file)
@@ -32,6 +32,9 @@
 #include "logger.hh"
 #include "statbag.hh"
 #include "dns_random.hh"
+#include "stubresolver.hh"
+#include "arguments.hh"
+#include "threadname.hh"
 
 extern StatBag S;
 
@@ -76,7 +79,7 @@ DNSProxy::DNSProxy(const string &remote)
   }
 
   d_xor=dns_random(0xffff);
-  L<<Logger::Error<<"DNS Proxy launched, local port "<<ntohs(local.sin4.sin_port)<<", remote "<<d_remote.toStringWithPort()<<endl;
+  g_log<<Logger::Error<<"DNS Proxy launched, local port "<<ntohs(local.sin4.sin_port)<<", remote "<<d_remote.toStringWithPort()<<endl;
 } 
 
 void DNSProxy::go()
@@ -85,41 +88,45 @@ void DNSProxy::go()
   pthread_create(&tid,0,&launchhelper,this);
 }
 
-/** returns false if p->remote is not allowed to recurse via us */
-bool DNSProxy::sendPacket(DNSPacket *p)
+//! look up qname target with r->qtype, plonk it in the answer section of 'r' with name aname
+bool DNSProxy::completePacket(DNSPacket *r, const DNSName& target,const DNSName& aname, const uint8_t scopeMask)
 {
-  uint16_t id;
-  {
-    Lock l(&d_lock);
-    id=getID_locked();
+  if(r->d_tcp) {
+    vector<DNSZoneRecord> ips;
+    int ret1 = 0, ret2 = 0;
 
-    ConntrackEntry ce;
-    ce.id       = p->d.id;
-    ce.remote = p->d_remote;
-    ce.outsock  = p->getSocket();
-    ce.created  = time( NULL );
-    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;
-  p->commitD();
-  
-  const string& buffer = p->getString();
-  
-  if(send(d_sock,buffer.c_str(), buffer.length() , 0)<0) { // zoom
-    L<<Logger::Error<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl;
-  }
-  (*d_resquestions)++;
-  return true;
+    if(r->qtype == QType::A || r->qtype == QType::ANY)
+      ret1 = stubDoResolve(target, QType::A, ips);
+    if(r->qtype == QType::AAAA || r->qtype == QType::ANY)
+      ret2 = stubDoResolve(target, QType::AAAA, ips);
 
-}
+    if(ret1 != RCode::NoError || ret2 != RCode::NoError) {
+      g_log<<Logger::Error<<"Error resolving for "<<aname<<" ALIAS "<<target<<" over UDP, original query came in over TCP";
+      if (ret1 != RCode::NoError) {
+       g_log<<Logger::Error<<", A-record query returned "<<RCode::to_s(ret1);
+      }
+      if (ret2 != RCode::NoError) {
+       g_log<<Logger::Error<<", AAAA-record query returned "<<RCode::to_s(ret2);
+      }
+      g_log<<Logger::Error<<", returning SERVFAIL"<<endl;
+      r->clearRecords();
+      r->setRcode(RCode::ServFail);
+    } else {
+      for (auto &ip : ips)
+      {
+        ip.dr.d_name = aname;
+        r->addRecord(ip);
+      }
+    }
+
+    uint16_t len=htons(r->getString().length());
+    string buffer((const char*)&len, 2);
+    buffer.append(r->getString());
+    writen2WithTimeout(r->getSocket(), buffer.c_str(), buffer.length(), ::arg().asNum("tcp-idle-timeout"));
+
+    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 DNSName& target,const DNSName& aname)
-{
   uint16_t id;
   {
     Lock l(&d_lock);
@@ -135,6 +142,7 @@ bool DNSProxy::completePacket(DNSPacket *r, const DNSName& target,const DNSName&
     ce.anyLocal = r->d_anyLocal;
     ce.complete = r;
     ce.aname=aname;
+    ce.anameScopeMask = scopeMask;
     d_conntrack[id]=ce;
   }
 
@@ -144,7 +152,7 @@ bool DNSProxy::completePacket(DNSPacket *r, const DNSName& target,const DNSName&
   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;
+    g_log<<Logger::Error<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl;
   }
 
   return true;
@@ -163,7 +171,7 @@ int DNSProxy::getID_locked()
     }
     else if(i->second.created<time(0)-60) {
       if(i->second.created) {
-        L<<Logger::Warning<<"Recursive query for remote "<<
+        g_log<<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;
@@ -176,6 +184,7 @@ int DNSProxy::getID_locked()
 
 void DNSProxy::mainloop(void)
 {
+  setThreadName("pdns/dnsproxy");
   try {
     char buffer[1500];
     ssize_t len;
@@ -190,16 +199,16 @@ void DNSProxy::mainloop(void)
       len=recvfrom(d_sock, buffer, sizeof(buffer),0, (struct sockaddr*) &fromaddr, &fromaddrSize); // answer from our backend
       if(len<(ssize_t)sizeof(dnsheader)) {
         if(len<0)
-          L<<Logger::Error<<"Error receiving packet from recursor backend: "<<stringerror()<<endl;
+          g_log<<Logger::Error<<"Error receiving packet from recursor backend: "<<stringerror()<<endl;
         else if(len==0)
-          L<<Logger::Error<<"Error receiving packet from recursor backend, EOF"<<endl;
+          g_log<<Logger::Error<<"Error receiving packet from recursor backend, EOF"<<endl;
         else
-          L<<Logger::Error<<"Short packet from recursor backend, "<<len<<" bytes"<<endl;
+          g_log<<Logger::Error<<"Short packet from recursor backend, "<<len<<" bytes"<<endl;
         
         continue;
       }
       if (fromaddr != d_remote) {
-        L<<Logger::Error<<"Got answer from unexpected host "<<fromaddr.toStringWithPort()<<" instead of our recursor backend "<<d_remote.toStringWithPort()<<endl;
+        g_log<<Logger::Error<<"Got answer from unexpected host "<<fromaddr.toStringWithPort()<<" instead of our recursor backend "<<d_remote.toStringWithPort()<<endl;
         continue;
       }
       (*d_resanswers)++;
@@ -214,12 +223,12 @@ void DNSProxy::mainloop(void)
 #endif
         map_t::iterator i=d_conntrack.find(d.id^d_xor);
         if(i==d_conntrack.end()) {
-          L<<Logger::Error<<"Discarding untracked packet from recursor backend with id "<<(d.id^d_xor)<<
+          g_log<<Logger::Error<<"Discarding untracked packet from recursor backend with id "<<(d.id^d_xor)<<
             ". Conntrack table size="<<d_conntrack.size()<<endl;
           continue;
         }
         else if(i->second.created==0) {
-          L<<Logger::Error<<"Received packet from recursor backend with id "<<(d.id^d_xor)<<" which is a duplicate"<<endl;
+          g_log<<Logger::Error<<"Received packet from recursor backend with id "<<(d.id^d_xor)<<" which is a duplicate"<<endl;
           continue;
         }
        
@@ -231,44 +240,43 @@ void DNSProxy::mainloop(void)
         q.parse(buffer,(size_t)len);
 
         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)<<
+          g_log<<Logger::Error<<"Discarding packet from recursor backend with id "<<(d.id^d_xor)<<
             ", 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));
-       string reply; // needs to be alive at time of sendmsg!
-       if(i->second.complete) {
-
-         MOADNSParser mdp(false, 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 == DNSResourceRecord::ANSWER || (j->first.d_place == DNSResourceRecord::AUTHORITY && j->first.d_type == QType::SOA)) {
-           
-             if(j->first.d_type == i->second.qtype || (i->second.qtype == QType::ANY && (j->first.d_type == QType::A || j->first.d_type == QType::AAAA))) {
+        string reply; // needs to be alive at time of sendmsg!
+        MOADNSParser mdp(false, p.getString());
+        //       cerr<<"Got completion, "<<mdp.d_answers.size()<<" answers, rcode: "<<mdp.d_header.rcode<<endl;
+        if (mdp.d_header.rcode == RCode::NoError) {
+          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 == DNSResourceRecord::ANSWER || (j->first.d_place == DNSResourceRecord::AUTHORITY && j->first.d_type == QType::SOA)) {
+
+              if(j->first.d_type == i->second.qtype || (i->second.qtype == QType::ANY && (j->first.d_type == QType::A || j->first.d_type == QType::AAAA))) {
                 DNSZoneRecord dzr;
-               dzr.dr.d_name=i->second.aname;
-               dzr.dr.d_type = j->first.d_type;
-               dzr.dr.d_ttl=j->first.d_ttl;
-               dzr.dr.d_place= j->first.d_place;
-               dzr.dr.d_content=j->first.d_content;
-               i->second.complete->addRecord(dzr);
-             }
-           }
-         }
-         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;
-       }
+                dzr.dr.d_name=i->second.aname;
+                dzr.dr.d_type = j->first.d_type;
+                dzr.dr.d_ttl=j->first.d_ttl;
+                dzr.dr.d_place= j->first.d_place;
+                dzr.dr.d_content=j->first.d_content;
+                i->second.complete->addRecord(dzr);
+              }
+            }
+          }
+          i->second.complete->setRcode(mdp.d_header.rcode);
+        } else {
+          g_log<<Logger::Error<<"Error resolving for "<<i->second.aname<<" ALIAS "<<i->second.qname<<" over UDP, "<<QType(i->second.qtype).getName()<<"-record query returned "<<RCode::to_s(mdp.d_header.rcode)<<", returning SERVFAIL"<<endl;
+          i->second.complete->clearRecords();
+          i->second.complete->setRcode(RCode::ServFail);
+        }
+        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;
         msgh.msg_iov = &iov;
         msgh.msg_iovlen = 1;
         msgh.msg_name = (struct sockaddr*)&i->second.remote;
@@ -279,23 +287,23 @@ void DNSProxy::mainloop(void)
           addCMsgSrcAddr(&msgh, cbuf, i->second.anyLocal.get_ptr(), 0);
         }
         if(sendmsg(i->second.outsock, &msgh, 0) < 0)
-          L<<Logger::Warning<<"dnsproxy.cc: Error sending reply with sendmsg (socket="<<i->second.outsock<<"): "<<strerror(errno)<<endl;
-        
+          g_log<<Logger::Warning<<"dnsproxy.cc: Error sending reply with sendmsg (socket="<<i->second.outsock<<"): "<<strerror(errno)<<endl;
+
         i->second.created=0;
       }
     }
   }
   catch(PDNSException &ae) {
-    L<<Logger::Error<<"Fatal error in DNS proxy: "<<ae.reason<<endl;
+    g_log<<Logger::Error<<"Fatal error in DNS proxy: "<<ae.reason<<endl;
   }
   catch(std::exception &e) {
-    L<<Logger::Error<<"Communicator thread died because of STL error: "<<e.what()<<endl;
+    g_log<<Logger::Error<<"Communicator thread died because of STL error: "<<e.what()<<endl;
   }
   catch( ... )
   {
-    L << Logger::Error << "Caught unknown exception." << endl;
+    g_log << Logger::Error << "Caught unknown exception." << endl;
   }
-  L<<Logger::Error<<"Exiting because DNS proxy failed"<<endl;
+  g_log<<Logger::Error<<"Exiting because DNS proxy failed"<<endl;
   _exit(1);
 }