Package: pdns
Severity: wishlist
Tags: patch

Hi pdns maintainers,

the attached dpatch

## DP: Adds support for maximum TCP request time (command line arg).

is used here (UI) to improve pdns. It applies cleanly to 2.9.21.2-1
after the existing dpatches.

We would be enlightened if you could review it and eventually consider 
adding it to the Debian package.      

Thanks!

Stephan

-- System Information:
Debian Release: 5.0
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.26-1-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
#! /bin/sh /usr/share/dpatch/dpatch-run
## ui-20_max-tcp-request-time.dpatch by Stephan Suerken <[email protected]>
##
## All lines beginning with `## DP:' are a description of the patch.
##
## DP: Adds support for maximum TCP request time (command line arg).

@DPATCH@
diff -urNad trunk~/pdns/common_startup.cc trunk/pdns/common_startup.cc
--- trunk~/pdns/common_startup.cc	2009-01-05 13:14:42.000000000 +0000
+++ trunk/pdns/common_startup.cc	2009-01-05 13:14:42.000000000 +0000
@@ -111,6 +111,7 @@
   arg().set("soa-expire-default","Default SOA expire")="604800";
 
   arg().set("default-ttl","Seconds a result is valid if not set otherwise")="3600";
+  arg().set("max-tcp-request-time","Maximum number of seconds a TCP client may take completing a request")="120";
   arg().set("max-tcp-connections","Maximum number of TCP connections")="10";
   arg().set("tcp-idle-timeout","Number of seconds a TCP client can be idle during a request")="10";
   arg().setSwitch("no-shuffle","Set this to prevent random shuffling of answers - for regression testing")="off";
diff -urNad trunk~/pdns/misc.cc trunk/pdns/misc.cc
--- trunk~/pdns/misc.cc	2009-01-05 13:14:42.000000000 +0000
+++ trunk/pdns/misc.cc	2009-01-05 13:14:42.000000000 +0000
@@ -597,3 +597,23 @@
 
   return dom.substr(0,dom.size()-1);
 }
+
+void addTimeval(struct timeval & tv, const struct timeval & add)
+{
+  tv.tv_usec += add.tv_usec;
+  if (tv.tv_usec >= 1000000) {
+    tv.tv_usec -= 1000000;
+    ++tv.tv_sec;
+  }
+  tv.tv_sec += add.tv_sec;
+}
+
+void subTimeval(struct timeval & tv, const struct timeval & sub)
+{
+  if (tv.tv_usec < sub.tv_usec) {
+    tv.tv_usec += 1000000;
+    --tv.tv_sec;
+  }
+  tv.tv_usec -= sub.tv_usec;
+  tv.tv_sec -= sub.tv_sec;
+}
diff -urNad trunk~/pdns/misc.hh trunk/pdns/misc.hh
--- trunk~/pdns/misc.hh	2009-01-05 13:14:42.000000000 +0000
+++ trunk/pdns/misc.hh	2009-01-05 13:14:42.000000000 +0000
@@ -91,6 +91,18 @@
 uint32_t getLong(const unsigned char *p);
 uint32_t getLong(const char *p);
 boost::optional<int> logFacilityToLOG(unsigned int facility);
+void addTimeval(struct timeval & tv, const struct timeval & add);
+void subTimeval(struct timeval & tv, const struct timeval & sub);
+
+inline bool timevalZero(const struct timeval & tv)
+{
+  return (tv.tv_sec<0 || (tv.tv_sec==0 && tv.tv_usec==0));
+}
+
+inline int waitForData(int fd, const struct timeval & tv)
+{
+   return waitForData(fd, tv.tv_sec, tv.tv_usec);
+}
 
 inline void putLong(unsigned char* p, uint32_t val)
 {
diff -urNad trunk~/pdns/pdns.conf-dist trunk/pdns/pdns.conf-dist
--- trunk~/pdns/pdns.conf-dist	2009-01-05 13:14:42.000000000 +0000
+++ trunk/pdns/pdns.conf-dist	2009-01-05 13:14:42.000000000 +0000
@@ -334,4 +334,8 @@
 #
 # wildcards=
 
+#################################
+# max-tcp-request-time Maximum number of seconds a TCP client may take completing a request
+#
+# max-tcp-request-time=120
 
diff -urNad trunk~/pdns/resolver.cc trunk/pdns/resolver.cc
--- trunk~/pdns/resolver.cc	2009-01-05 13:14:42.000000000 +0000
+++ trunk/pdns/resolver.cc	2009-01-05 13:14:42.000000000 +0000
@@ -111,30 +111,6 @@
   }
 }
 
-char* Resolver::sendReceive(const string &ip, uint16_t remotePort, const char *packet, int length, unsigned int *replen)
-{
-  makeTCPSocket(ip, remotePort);
-
-  if(sendData(packet,length,d_sock)<0) 
-    throw ResolverException("Unable to send packet to remote nameserver "+ip+": "+stringerror());
-
-  int plen=getLength();
-  if(plen<0)
-    throw ResolverException("EOF trying to get length of answer from remote TCP server");
-
-  char *answer=new char[plen];
-  try {
-    timeoutReadn(answer,plen);
-    *replen=plen;
-    return answer;
-  }
-  catch(...) {
-    delete answer;
-    throw; // whop!
-  }
-  return 0;
-}
-
 int Resolver::notify(int sock, const string &domain, const string &ip, uint16_t id)
 {
   vector<uint8_t> packet;
@@ -337,15 +313,21 @@
   return 1;
 }
 
-int Resolver::getLength()
+int Resolver::getLength(struct timeval &req_time)
 {
   int bytesLeft=2;
   unsigned char buf[2];
   
   while(bytesLeft) {
+    // FIXED, check for expired request time 
+    if(timevalZero(req_time))
+      throw ResolverException("Closing connection to remote TCP client max. request time reached");
+    // FIXED, decrease request time
+    struct timeval tv={10,0};
+    subTimeval(req_time, tv);
     // FIXED, select timeout was not handled
     int ret=0;
-    if(waitForData(d_sock, 10)<1) {
+    if(waitForData(d_sock, tv)<1) {
       Utility::closesocket(d_sock);
       d_sock=-1;
       throw ResolverException("Waiting on data from remote TCP client: "+stringerror());
@@ -357,6 +339,8 @@
     if(!ret) 
       return -1;
     
+    // FIXED, increase request time again 
+    addTimeval(req_time, tv);
     bytesLeft-=ret;
   }
   return buf[0]*256+buf[1];
@@ -371,7 +355,9 @@
   }
 
   // d_sock is connected and is about to spit out a packet
-  int len=getLength();
+  // FIXED, get and pass max request time 
+  struct timeval time_left={arg().asNum("max-tcp-request-time"),0};
+  int len=getLength(time_left);
   if(len<0)
     throw ResolverException("EOF trying to read axfr chunk from remote TCP client");
   
diff -urNad trunk~/pdns/resolver.hh trunk/pdns/resolver.hh
--- trunk~/pdns/resolver.hh	2007-04-21 13:56:36.000000000 +0000
+++ trunk/pdns/resolver.hh	2009-01-05 13:14:42.000000000 +0000
@@ -60,7 +60,6 @@
   void sendResolve(const string &ip, const char *domain, int type);
 
   int receiveResolve(struct sockaddr* fromaddr, Utility::socklen_t addrlen);
-  char* sendReceive(const string &ip, uint16_t remotePort, const char *packet, int length, unsigned int *replylen);
   void getSoaSerial(const string &, const string &, uint32_t *);
   int axfrChunk(Resolver::res_t &res);
   vector<DNSResourceRecord> result();
@@ -72,7 +71,7 @@
   void timeoutReadn(char *buffer, int bytes);
   int d_sock;
   unsigned char *d_buf;
-  int getLength();
+  int getLength(struct timeval &req_time);
   int d_len;
   int d_soacount;
   string d_domain;
diff -urNad trunk~/pdns/tcpreceiver.cc trunk/pdns/tcpreceiver.cc
--- trunk~/pdns/tcpreceiver.cc	2009-01-05 13:14:42.000000000 +0000
+++ trunk/pdns/tcpreceiver.cc	2009-01-05 13:14:42.000000000 +0000
@@ -76,16 +76,22 @@
 }
 
 // throws AhuException if things didn't go according to plan, returns 0 if really 0 bytes were read
-int readnWithTimeout(int fd, void* buffer, unsigned int n, bool throwOnEOF=true)
+int readnWithTimeout(int fd, void* buffer, unsigned int n, struct timeval &req_time, bool throwOnEOF=true)
 {
   unsigned int bytes=n;
   char *ptr = (char*)buffer;
   int ret;
   while(bytes) {
+    // FIXED, check for expired request time 
+    if(timevalZero(req_time))
+      throw AhuException("Closing connection to remote TCP client. Maximum request time reached");
+    // FIXED, decrease request time
+    struct timeval tv={5,0};
+    subTimeval(req_time, tv);
     ret=read(fd, ptr, bytes);
     if(ret < 0) {
       if(errno==EAGAIN) {
-	ret=waitForData(fd, 5);
+	ret=waitForData(fd, tv);
 	if(ret < 0)
 	  throw AhuException("Waiting for data read");
 	if(!ret)
@@ -102,6 +108,8 @@
 	throw AhuException("Did not fulfill read from TCP due to EOF");
     }
     
+    // FIXED, increase request time again 
+    addTimeval(req_time, tv);
     ptr += ret;
     bytes -= ret;
   }
@@ -177,16 +185,16 @@
 }
 
 
-void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote)
+void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress& remote, struct timeval &req_time)
 try
 {
-  readnWithTimeout(fd, mesg, pktlen);
+  readnWithTimeout(fd, mesg, pktlen, req_time);
 }
 catch(AhuException& ae) {
     throw AhuException("Error reading DNS data from TCP client "+remote.toString()+": "+ae.reason);
 }
 
-static void proxyQuestion(shared_ptr<DNSPacket> packet)
+static void proxyQuestion(shared_ptr<DNSPacket> packet, struct timeval &req_time)
 {
   int sock=socket(AF_INET, SOCK_STREAM, 0);
   if(sock < 0)
@@ -209,11 +217,13 @@
     
     int ret;
     
-    ret=readnWithTimeout(sock, &len, 2);
+  // FIXED, pass max request time to readnWithTimeout call
+  ret=readnWithTimeout(sock, &len, 2, req_time);
     len=ntohs(len);
 
     char answer[len];
-    ret=readnWithTimeout(sock, answer, len);
+  // FIXED, pass max request time to readnWithTimeout call
+  ret=readnWithTimeout(sock, answer, len, req_time);
 
     slen=htons(len);
     writenWithTimeout(packet->getSocket(), &slen, 2);
@@ -241,6 +251,8 @@
     DLOG(L<<"TCP Connection accepted on fd "<<fd<<endl);
     
     for(;;) {
+      // FIXED, getting max request value
+      struct timeval time_left={arg().asNum("max-tcp-request-time"),0};
       ComboAddress remote;
       socklen_t remotelen=sizeof(remote);
       if(getpeername(fd, (struct sockaddr *)&remote, &remotelen) < 0) {
@@ -249,7 +261,8 @@
       }
 
       uint16_t pktlen;
-      if(!readnWithTimeout(fd, &pktlen, 2, false))
+	  // fix, passing max request time to readnWithTimeout call
+      if(!readnWithTimeout(fd, &pktlen, 2, time_left, false))
 	break;
       else
 	pktlen=ntohs(pktlen);
@@ -259,7 +272,8 @@
 	break;
       }
       
-      getQuestion(fd,mesg,pktlen,remote);
+	  // fix, passing max request time to getQuestion call
+      getQuestion(fd,mesg,pktlen,remote,time_left);
       S.inc("tcp-queries");      
 
       packet=shared_ptr<DNSPacket>(new DNSPacket);
@@ -297,7 +311,7 @@
 	reply=shared_ptr<DNSPacket>(s_P->questionOrRecurse(packet.get(), &shouldRecurse)); // we really need to ask the backend :-)
 
 	if(shouldRecurse) {
-	  proxyQuestion(packet);
+	  proxyQuestion(packet,time_left);
 	  continue;
 	}
       }
diff -urNad trunk~/pdns/tcpreceiver.hh trunk/pdns/tcpreceiver.hh
--- trunk~/pdns/tcpreceiver.hh	2007-04-21 13:56:36.000000000 +0000
+++ trunk/pdns/tcpreceiver.hh	2009-01-05 13:14:42.000000000 +0000
@@ -50,7 +50,7 @@
 
   static void sendPacket(boost::shared_ptr<DNSPacket> p, int outsock);
   static int readLength(int fd, ComboAddress *remote);
-  static void getQuestion(int fd, char *mesg, int pktlen, const ComboAddress& remote);
+  static void getQuestion(int fd, char *mesg, int pktlen, const ComboAddress& remote, struct timeval &req_time);
   static int doAXFR(const string &target, boost::shared_ptr<DNSPacket> q, int outsock);
   static bool canDoAXFR(boost::shared_ptr<DNSPacket> q);
   static void *doConnection(void *data);

Reply via email to