]> granicus.if.org Git - pdns/commitdiff
recursor timestamps, recursor any address, auth consolidation: teach recursor about...
authorbert hubert <bert.hubert@netherlabs.nl>
Thu, 8 Jan 2015 15:40:13 +0000 (16:40 +0100)
committerbert hubert <bert.hubert@netherlabs.nl>
Thu, 8 Jan 2015 15:40:13 +0000 (16:40 +0100)
teach recursor to measure 'received' timestamps, teach it to drop queries that have been sitting in a queue for a second already, add too-old-drops metric for this
unify some code with the auth server

pdns/iputils.cc
pdns/iputils.hh
pdns/nameserver.cc
pdns/pdns_recursor.cc
pdns/rec_channel_rec.cc
pdns/syncres.hh
pdns/toysdig.cc

index 11f8181af5ab43041c04e134e5243ff0ad4c6e0a..2f09d51924c71600655b80846a2762b8c09f7729 100644 (file)
@@ -133,3 +133,21 @@ int sendfromto(int sock, const char* data, int len, int flags, const ComboAddres
   }
   return sendmsg(sock, &msgh, flags);
 }
+
+// be careful: when using this for receive purposes, make sure addr->sin4.sin_family is set appropriately so getSocklen works!
+// be careful: when using this function for *send* purposes, be sure to set cbufsize to 0!
+void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr)
+{
+  iov->iov_base = data;
+  iov->iov_len  = datalen;
+
+  memset(msgh, 0, sizeof(struct msghdr));
+  
+  msgh->msg_control = cbuf;
+  msgh->msg_controllen = cbufsize;
+  msgh->msg_name = addr;
+  msgh->msg_namelen = addr->getSocklen();
+  msgh->msg_iov  = iov;
+  msgh->msg_iovlen = 1;
+  msgh->msg_flags = 0;
+}
index 99abd3384e2b35de1cd505b753290a43c8104b69..8ac7fb215ec9004935bec46c1b9d9ca1067e5c04 100644 (file)
@@ -441,6 +441,5 @@ int SSetsockopt(int sockfd, int level, int opname, int value);
 bool IsAnyAddress(const ComboAddress& addr);
 bool HarvestDestinationAddress(struct msghdr* msgh, ComboAddress* destination);
 bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv);
-
-
+void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
 #endif
index fca61417007c28a4098da7b61371b762f2129352..99be86b996f7f15513aa9db2a8e9b29994fd47d4 100644 (file)
@@ -295,14 +295,7 @@ void UDPNameserver::send(DNSPacket *p)
   else
     numanswered6++;
 
-  /* Set up iov and msgh structures. */
-  memset(&msgh, 0, sizeof(struct msghdr));
-  iov.iov_base = (void*)buffer.c_str();
-  iov.iov_len = buffer.length();
-  msgh.msg_iov = &iov;
-  msgh.msg_iovlen = 1;
-  msgh.msg_name = (struct sockaddr*)&p->d_remote;
-  msgh.msg_namelen = p->d_remote.getSocklen();
+  fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)buffer.c_str(), buffer.length(), &p->d_remote);
 
   if(p->d_anyLocal) {
     addCMsgSrcAddr(&msgh, cbuf, p->d_anyLocal.get_ptr());
@@ -327,18 +320,8 @@ DNSPacket *UDPNameserver::receive(DNSPacket *prefilled)
   struct iovec iov;
   char cbuf[256];
 
-  iov.iov_base = mesg;
-  iov.iov_len  = sizeof(mesg);
-
-  memset(&msgh, 0, sizeof(struct msghdr));
-  
-  msgh.msg_control = cbuf;
-  msgh.msg_controllen = sizeof(cbuf);
-  msgh.msg_name = &remote;
-  msgh.msg_namelen = sizeof(remote);
-  msgh.msg_iov  = &iov;
-  msgh.msg_iovlen = 1;
-  msgh.msg_flags = 0;
+  remote.sin6.sin6_family=AF_INET6; // make sure it is big enough
+  fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), mesg, sizeof(mesg), &remote);
   
   int err;
   vector<struct pollfd> rfds= d_rfds;
index 56568eb54116f34678f8e9b861d6e146a56a79fb..22811e0fefddb7fe9f45b962565fe6f944b59f03 100644 (file)
@@ -149,6 +149,12 @@ struct DNSComboWriter {
     d_remote=*sa;
   }
 
+  void setLocal(const ComboAddress& sa)
+  {
+    d_local=sa;
+  }
+
+
   void setSocket(int sock)
   {
     d_socket=sock;
@@ -160,7 +166,7 @@ struct DNSComboWriter {
   }
 
   struct timeval d_now;
-  ComboAddress d_remote;
+  ComboAddress d_remote, d_local;
   bool d_tcp;
   int d_socket;
   shared_ptr<TCPConnection> d_tcpConnection;
@@ -596,7 +602,6 @@ void startDoResolve(void *p)
       }
       catch(ImmediateServFailException &e) {
         L<<Logger::Error<<"Sending SERVFAIL to "<<dc->getRemote()<<" during resolve of '"<<dc->d_mdp.d_qname<<"' because: "<<e.reason<<endl;
-
         res = RCode::ServFail;
       }
 
@@ -675,7 +680,13 @@ void startDoResolve(void *p)
     g_rs.submitResponse(dc->d_mdp.d_qtype, packet.size(), !dc->d_tcp);
     updateResponseStats(res, dc->d_remote, packet.size(), &dc->d_mdp.d_qname, dc->d_mdp.d_qtype);
     if(!dc->d_tcp) {
-      sendto(dc->d_socket, (const char*)&*packet.begin(), packet.size(), 0, (struct sockaddr *)(&dc->d_remote), dc->d_remote.getSocklen());
+      struct msghdr msgh;
+      struct iovec iov;
+      char cbuf[256];
+      fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)&*packet.begin(), packet.size(), &dc->d_remote);
+      if(dc->d_local.sin4.sin_family)
+       addCMsgSrcAddr(&msgh, cbuf, &dc->d_local);
+      sendmsg(dc->d_socket, &msgh, 0);
       if(!SyncRes::s_nopacketcache && !variableAnswer ) {
         t_packetCache->insertResponsePacket(string((const char*)&*packet.begin(), packet.size()),
                                             g_now.tv_sec, 
@@ -913,8 +924,16 @@ void handleNewTCPQuestion(int fd, FDMultiplexer::funcparam_t& )
   }
 }
  
-string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, int fd)
+string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, const ComboAddress& destaddr, struct timeval tv, int fd)
 {
+  struct timeval diff = g_now - tv;
+  double delta=(diff.tv_sec*1000 + diff.tv_usec/1000.0);
+  
+  if(delta > 1000.0) {
+    g_stats.tooOldDrops++;
+    return 0;
+  }
+
   ++g_stats.qcounter;
   if(fromaddr.sin4.sin_family==AF_INET6)
      g_stats.ipv6qcounter++;
@@ -930,7 +949,16 @@ string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fr
       g_stats.packetCacheHits++;
       SyncRes::s_queries++;
       ageDNSPacket(response, age);
-      sendto(fd, response.c_str(), response.length(), 0, (struct sockaddr*) &fromaddr, fromaddr.getSocklen());
+      struct msghdr msgh;
+      struct iovec iov;
+      char cbuf[256];
+      fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)response.c_str(), response.length(), const_cast<ComboAddress*>(&fromaddr));
+      if(destaddr.sin4.sin_family) {
+       cerr<<"Add!"<<endl;
+       addCMsgSrcAddr(&msgh, cbuf, &destaddr);
+      }
+      sendmsg(fd, &msgh, 0);
+
       if(response.length() >= sizeof(struct dnsheader)) {
         struct dnsheader dh;
         memcpy(&dh, response.c_str(), sizeof(dh));
@@ -956,21 +984,28 @@ string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fr
   DNSComboWriter* dc = new DNSComboWriter(question.c_str(), question.size(), g_now);
   dc->setSocket(fd);
   dc->setRemote(&fromaddr);
+  dc->setLocal(destaddr);
 
   dc->d_tcp=false;
   MT->makeThread(startDoResolve, (void*) dc); // deletes dc
   return 0;
 } 
  
+
 void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var)
 {
   int len;
   char data[1500];
   ComboAddress fromaddr;
-  socklen_t addrlen=sizeof(fromaddr);
-  
+  struct msghdr msgh;
+  struct iovec iov;
+  char cbuf[256];
+
+  fromaddr.sin6.sin6_family=AF_INET6; // this makes sure fromaddr is big enough
+  fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), data, sizeof(data), &fromaddr);
+
   for(;;) 
-  if((len=recvfrom(fd, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen)) >= 0) {
+  if((len=recvmsg(fd, &msgh, 0)) >= 0) {
     if(t_remotes)
       t_remotes->push_back(fromaddr);
 
@@ -1002,10 +1037,15 @@ void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var)
       }
       else {
         string question(data, len);
+       struct timeval tv={0,0};
+       HarvestTimestamp(&msgh, &tv);
+       ComboAddress dest;
+       memset(&dest, 0, sizeof(dest)); // this makes sure we igore this address if not returned by recvmsg above
+       HarvestDestinationAddress(&msgh, &dest);
         if(g_weDistributeQueries)
-          distributeAsyncFunction(question, boost::bind(doProcessUDPQuestion, question, fromaddr, fd));
+          distributeAsyncFunction(question, boost::bind(doProcessUDPQuestion, question, fromaddr, dest, tv, fd));
         else
-          doProcessUDPQuestion(question, fromaddr, fd);
+          doProcessUDPQuestion(question, fromaddr, dest, tv, fd);
       }
     }
     catch(MOADNSException& mde) {
@@ -1096,10 +1136,6 @@ void makeUDPServerSockets()
   if(locals.empty())
     throw PDNSException("No local address specified");
   
-  if(::arg()["local-address"]=="0.0.0.0") {
-    L<<Logger::Warning<<"It is advised to bind to explicit addresses with the --local-address option"<<endl;
-  }
-
   for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
     ServiceTuple st;
     st.port=::arg().asNum("local-port");
@@ -1119,6 +1155,12 @@ void makeUDPServerSockets()
     if(fd < 0) {
       throw PDNSException("Making a UDP server socket for resolver: "+netstringerror());
     }
+    setSocketTimestamps(fd);
+    int one;
+    if(IsAnyAddress(sin)) {
+      setsockopt(fd, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one));     // linux supports this, so why not - might fail on other systems
+      setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); 
+    }
 
     Utility::setCloseOnExec(fd);
 
index 73ded636e08a72dd87aa78e8c8ea4c4d4680b8b2..0c5600e6d8cf017e6109a1a6610f626876bdb712 100644 (file)
@@ -511,6 +511,7 @@ RecursorControlParser::RecursorControlParser()
 
   addGetStat("client-parse-errors", &g_stats.clientParseError);
   addGetStat("server-parse-errors", &g_stats.serverParseError);
+  addGetStat("too-old-drops", &g_stats.tooOldDrops);
 
   addGetStat("answers0-1", &g_stats.answers0_1);
   addGetStat("answers1-10", &g_stats.answers1_10);
index d345dd91cf3dc8fb045ca4a96cccb97291d66fc0..f92a4d44affdd4f4bc8a97a701908e19d6fbc1d6 100644 (file)
@@ -558,6 +558,7 @@ struct RecursorStats
   uint64_t tcpClientOverflow;
   uint64_t clientParseError;
   uint64_t serverParseError;
+  uint64_t tooOldDrops;
   uint64_t unexpectedCount;
   uint64_t caseMismatchCount;
   uint64_t spoofCount;
index ed5323be577afbdac296fb3bd0250946574654d4..707007c05a234e6bcc3a785b5228925e01b4d92c 100644 (file)
@@ -20,7 +20,7 @@ try
 
   Socket sock(AF_INET, SOCK_DGRAM);
   ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
-  for(unsigned int n=0; n < 100; ++n) {
+  for(unsigned int n=0; n < 20000; ++n) {
     vector<uint8_t> packet;
     string qname;