<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="Generator" CONTENT="MS Exchange Server version 5.5.2654.45">
<TITLE>truncated udp query and odd tcp behaviour (patch included)</TITLE>
</HEAD>
<BODY>

<P><FONT SIZE=2>hi!</FONT>
</P>

<P><FONT SIZE=2>after implementing the ldap backend, doing some testing and </FONT>
<BR><FONT SIZE=2>pulling my hair out because of pdns tcp query behavior i have </FONT>
<BR><FONT SIZE=2>created a patch that solves those issues.</FONT>
</P>
<BR>

<P><FONT SIZE=2>setup:</FONT>
</P>

<P>        <FONT SIZE=2>pdns_server-2.9.20 running on *:53</FONT>
<BR>                <FONT SIZE=2>configured to use ldap (strict)</FONT>
<BR>                <FONT SIZE=2>configured to use recurser</FONT>
</P>

<P>        <FONT SIZE=2>pdns_recurser-3.1.4 running on 127.0.0.1:5353</FONT>
</P>

<P>        <FONT SIZE=2>openldap with dnsdomain2 schema</FONT>
</P>

<P><FONT SIZE=2>symtom 1)</FONT>
</P>

<P>        <FONT SIZE=2>"host [ip address]" works and returns [name]</FONT>
<BR>        <FONT SIZE=2>"dig -x [ip address]" works and returns [name]</FONT>
</P>

<P><FONT SIZE=2>symtom 2)</FONT>
</P>

<P>        <FONT SIZE=2>"host [name]" returns:</FONT>
<BR>                <FONT SIZE=2>Host [name] not found: 3(NXDOMAIN)</FONT>
<BR>        <FONT SIZE=2>"dig [name]" returns:   </FONT>
<BR>                <FONT SIZE=2>; <<>> DiG 9.2.4 <<>> [name]</FONT>
<BR>                <FONT SIZE=2>; (1 server found)</FONT>
<BR>                <FONT SIZE=2>;; global options:  printcmd</FONT>
<BR>                <FONT SIZE=2>;; Got answer:</FONT>
<BR>                <FONT SIZE=2>;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 5070</FONT>
<BR>                <FONT SIZE=2>;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0</FONT>
<BR>        
<BR>                <FONT SIZE=2>;; QUESTION SECTION:</FONT>
<BR>                <FONT SIZE=2>;[name].                    IN      A</FONT>
</P>

<P>                <FONT SIZE=2>;; AUTHORITY SECTION:</FONT>
<BR>                <FONT SIZE=2>.                       1995    IN      SOA     [my upstream server soa record]</FONT>
</P>

<P><FONT SIZE=2>change 1)</FONT>
<BR>        <FONT SIZE=2>i have enabled the following:</FONT>
<BR>                <FONT SIZE=2>allow-recursion-override=on</FONT>
<BR>                <FONT SIZE=2>allow-recursion=yes</FONT>
<BR>                <FONT SIZE=2>lazy-recursion=yes</FONT>
</P>

<P><FONT SIZE=2>symtom 3)</FONT>
</P>

<P>        <FONT SIZE=2>"host [name]" returns:</FONT>
<BR>                <FONT SIZE=2>;; Warning: Message parser reports malformed message packet.</FONT>
<BR>                <FONT SIZE=2>;; Truncated, retrying in TCP mode.</FONT>
<BR>                <FONT SIZE=2>Host [name] not found: 3(NXDOMAIN)</FONT>
<BR>        <FONT SIZE=2>"dig [name]" returns:   </FONT>
<BR>                <FONT SIZE=2>;; Warning: Message parser reports malformed message packet.</FONT>
<BR>                <FONT SIZE=2>;; Truncated, retrying in TCP mode.</FONT>
<BR>                <FONT SIZE=2>; <<>> DiG 9.2.4 <<>> [name]</FONT>
<BR>                <FONT SIZE=2>; (1 server found)</FONT>
<BR>                <FONT SIZE=2>;; global options:  printcmd</FONT>
<BR>                <FONT SIZE=2>;; Got answer:</FONT>
<BR>                <FONT SIZE=2>;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 5070</FONT>
<BR>                <FONT SIZE=2>;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0</FONT>
<BR>        
<BR>                <FONT SIZE=2>;; QUESTION SECTION:</FONT>
<BR>                <FONT SIZE=2>;[name].                    IN      A</FONT>
</P>

<P>                <FONT SIZE=2>;; AUTHORITY SECTION:</FONT>
<BR>                <FONT SIZE=2>.                       1995    IN      SOA     [my upstream server soa record]</FONT>
</P>

<P>        <FONT SIZE=2>tcpdump on the client reports truncated dns-udp packets with many A records </FONT>
<BR>                <FONT SIZE=2>(ok the host in question has ~200 of them)</FONT>
<BR>                <FONT SIZE=2>and a failed dns-tcp query</FONT>
</P>

<P>        <FONT SIZE=2>tcpdump on the server yields that the udp query results in a ldap query</FONT>
<BR>                <FONT SIZE=2>the tcp query results in a dns query to the recurser</FONT>
</P>

<P><FONT SIZE=2>fact)</FONT>
<BR>        <FONT SIZE=2>all of my unix boxen (linux, solaris, aix) set the </FONT>
<BR>        <FONT SIZE=2>recursion bit in their libc implementation.</FONT>
</P>
<BR>

<P><FONT SIZE=2>looking at the code of "tcpreceiver.cc" the processing sequence of the query seams odd</FONT>
<BR><FONT SIZE=2>and the config-statements i thought should influence the behaviour are not even checked.</FONT>
</P>

<P><FONT SIZE=2>so this is the patch:</FONT>
</P>

<P><FONT SIZE=2>****************************************************************************************</FONT>
<BR><FONT SIZE=2>--- ./pdns/tcpreceiver.cc.old   2006-12-12 18:01:09.000000000 +0100</FONT>
<BR><FONT SIZE=2>+++ ./pdns/tcpreceiver.cc       2006-12-12 18:22:38.000000000 +0100</FONT>
<BR><FONT SIZE=2>@@ -172,8 +172,41 @@</FONT>
<BR><FONT SIZE=2>        continue;</FONT>
<BR><FONT SIZE=2>       }</FONT>
</P>

<P><FONT SIZE=2>+      /* first we look into the cache */</FONT>
<BR><FONT SIZE=2>+      DNSPacket* cached=new DNSPacket;</FONT>
<BR><FONT SIZE=2>+      if((!packet->d.rd || arg().mustDo("allow-recursion-override")) && (PC.get(packet, cached)))</FONT>
<BR><FONT SIZE=2>+      { // short circuit - does the PacketCache recognize this question?</FONT>
<BR><FONT SIZE=2>+        cached->setRemote((struct sockaddr *)(packet->remote), sizeof(struct sockaddr_in));</FONT>
<BR><FONT SIZE=2>+        cached->spoofID(packet->d.id);</FONT>
<BR><FONT SIZE=2>+       delete packet;</FONT>
<BR><FONT SIZE=2>+        if(sendDelPacket(cached, fd)<0)</FONT>
<BR><FONT SIZE=2>+          goto out;</FONT>
<BR><FONT SIZE=2>+</FONT>
<BR><FONT SIZE=2>+        S.inc("tcp-answers");</FONT>
<BR><FONT SIZE=2>+        continue;</FONT>
<BR><FONT SIZE=2>+      }</FONT>
<BR><FONT SIZE=2>+      else</FONT>
<BR><FONT SIZE=2>+        delete cached;</FONT>
<BR><FONT SIZE=2>+</FONT>
<BR><FONT SIZE=2>+      /* now we look into the backends */</FONT>
<BR><FONT SIZE=2>+      DNSPacket *reply;</FONT>
<BR><FONT SIZE=2>+      if(!packet->d.rd || arg().mustDo("allow-recursion-override"))</FONT>
<BR><FONT SIZE=2>+      {</FONT>
<BR><FONT SIZE=2>+        Lock l(&s_plock);</FONT>
<BR><FONT SIZE=2>+        reply=s_P->question(packet); // we really need to ask the backend :-)</FONT>
<BR><FONT SIZE=2>+        if(reply)  // able to write an answer?</FONT>
<BR><FONT SIZE=2>+        {</FONT>
<BR><FONT SIZE=2>+          delete packet;</FONT>
<BR><FONT SIZE=2>+          if(sendDelPacket(reply, fd)<0)</FONT>
<BR><FONT SIZE=2>+            goto out;</FONT>
<BR><FONT SIZE=2>+</FONT>
<BR><FONT SIZE=2>+          S.inc("tcp-answers");</FONT>
<BR><FONT SIZE=2>+          continue;</FONT>
<BR><FONT SIZE=2>+       }</FONT>
<BR><FONT SIZE=2>+      }</FONT>
</P>

<P><FONT SIZE=2>-      if(packet->d.rd && arg().mustDo("recursor")) {</FONT>
<BR><FONT SIZE=2>+      /* now we recurse upstream */</FONT>
<BR><FONT SIZE=2>+      if(arg().mustDo("recursor")) {</FONT>
<BR><FONT SIZE=2>        // now what</FONT>
<BR><FONT SIZE=2>        // this is a pretty rare event all in all, so we can afford to be slow</FONT>
</P>

<P><FONT SIZE=2>@@ -188,6 +221,7 @@</FONT>
</P>

<P><FONT SIZE=2>        char *buffer=res.sendReceive(st.host,st.port,packet->getRaw(),packet->len,&len);</FONT>
<BR><FONT SIZE=2>         DLOG(L<<"got an answer from recursor: "<<len<<" bytes, "<<(int)buffer<<endl);</FONT>
<BR><FONT SIZE=2>+       delete packet;</FONT>
<BR><FONT SIZE=2>        if(buffer) {</FONT>
<BR><FONT SIZE=2>          sendData(buffer,len,fd);</FONT>
<BR><FONT SIZE=2>          DLOG(L<<"sent out to customer: "<<len<<" bytes"<<endl);</FONT>
<BR><FONT SIZE=2>@@ -198,32 +232,7 @@</FONT>
<BR><FONT SIZE=2>        continue;</FONT>
<BR><FONT SIZE=2>       }</FONT>
</P>

<P><FONT SIZE=2>-      DNSPacket* cached=new DNSPacket;</FONT>
<BR><FONT SIZE=2>-      if(!packet->d.rd && (PC.get(packet, cached))) { // short circuit - does the PacketCache recognize this question?</FONT>
<BR><FONT SIZE=2>-       cached->setRemote((struct sockaddr *)(packet->remote), sizeof(struct sockaddr_in));</FONT>
<BR><FONT SIZE=2>-       cached->spoofID(packet->d.id);</FONT>
<BR><FONT SIZE=2>-       if(sendDelPacket(cached, fd)<0)</FONT>
<BR><FONT SIZE=2>-         goto out;</FONT>
<BR><FONT SIZE=2>-</FONT>
<BR><FONT SIZE=2>-       S.inc("tcp-answers");</FONT>
<BR><FONT SIZE=2>-       continue;</FONT>
<BR><FONT SIZE=2>-      }</FONT>
<BR><FONT SIZE=2>-      else</FONT>
<BR><FONT SIZE=2>-       delete cached;</FONT>
<BR><FONT SIZE=2>-</FONT>
<BR><FONT SIZE=2>-      DNSPacket *reply;</FONT>
<BR><FONT SIZE=2>-      {</FONT>
<BR><FONT SIZE=2>-       Lock l(&s_plock);</FONT>
<BR><FONT SIZE=2>-       reply=s_P->question(packet); // we really need to ask the backend :-)</FONT>
<BR><FONT SIZE=2>-      }</FONT>
<BR><FONT SIZE=2>-</FONT>
<BR><FONT SIZE=2>       delete packet;</FONT>
<BR><FONT SIZE=2>-</FONT>
<BR><FONT SIZE=2>-      if(!reply)  // unable to write an answer?</FONT>
<BR><FONT SIZE=2>-       break;</FONT>
<BR><FONT SIZE=2>-</FONT>
<BR><FONT SIZE=2>-      S.inc("tcp-answers");</FONT>
<BR><FONT SIZE=2>-      sendDelPacket(reply, fd);</FONT>
<BR><FONT SIZE=2>     }</FONT>
</P>

<P><FONT SIZE=2>   out:;</FONT>
<BR><FONT SIZE=2>****************************************************************************************</FONT>
</P>
<BR>

<P><FONT SIZE=2>i also added some "delete packet;" to avoid leaks.</FONT>
</P>
<BR>

<P><FONT SIZE=2>cheers,</FONT>
<BR><FONT SIZE=2>--</FONT>
<BR><FONT SIZE=2>Alfred Reibenschuh</FONT>
<BR><FONT SIZE=2>INFORMATIONS-TECHNOLOGIE AUSTRIA GMBH</FONT>
<BR><FONT SIZE=2>Netzwerk-Management</FONT>
<BR><FONT SIZE=2>A-1020 Wien, Lassallestrasse 5</FONT>
<BR><FONT SIZE=2>T: ++43-1-21717-58947</FONT>
<BR><FONT SIZE=2>F: ++43-1-21717-58979</FONT>
<BR><FONT SIZE=2>E: alfred.reibenschuh@it-austria.com</FONT>
<BR><FONT SIZE=2>W: <A HREF="http://www.it-austria.com" TARGET="_blank">http://www.it-austria.com</A></FONT>
<BR><FONT SIZE=2>--</FONT>
<BR><FONT SIZE=2>Diese Nachricht und allfällige angehängte Dokumente sind vertraulich und nur für den/die Adressaten bestimmt. Sollten Sie nicht der beabsichtigte Adressat sein, ist jede Offenlegung, Weiterleitung oder sonstige Verwendung dieser Information nicht gestattet. In diesem Fall bitten wir, den Absender zu verständigen und die Information zu vernichten. Für Übermittlungsfehler oder sonstige Irrtümer bei Übermittlung besteht keine Haftung. </FONT></P>

<P><FONT SIZE=2>This message and any attached files are confidential and intended solely for the addressee(s). Any publication, transmission or other use of the information by a person or entity other than the intended addressee is prohibited. If you receive this in error please contact the sender and delete the material. The sender does not accept liability for any errors or omissions as a result of the transmission. </FONT></P>

</BODY>
</HTML>