--- Begin Message ---
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);
--- End Message ---