[Pdns-dev] TXT data with more than 256 bytes screwed up (with solution)

Pablo Martín pablo.martin at fon.com
Mon Apr 16 16:52:16 CEST 2007


Hello.

Fist of all, I am as dumb as to send an email to this mailing list with a from: different from the one I was registered with. Probably there will appear a copy of this post in pdns-users... apologies for that.

While developing a custom backend over PowerDNS, I noticed that TXT answers with more than 256 bytes where screwed up by PowerDNS.

This was noticed both by the resolver library, in this case, djbdns, and by the protocol parser built into wireshark (ethereal).

Reading the old 2.9.20 source tree, I found the reason:

http://wiki.powerdns.com/cgi-bin/trac.fcgi/browser/tags/rel-2-9-20/pdns/dnspacket.cc

801 	void DNSPacket::addTXTorSPFRecord(uint16_t qtype, string domain, string txt, uint32_t ttl)
802 	{
803 	 string piece1;
804 	 //xtoqname(domain, &piece1);
805 	 toqname(domain, &piece1);
806 	 char p[10];
807 	 makeHeader(p, qtype, ttl);
808 	 string piece3;
809 	 piece3.reserve(txt.length()+1);
810 	 piece3.append(1,txt.length());
811 	 piece3.append(txt);
812 	
813 	 p[8]=piece3.length()/256;;
814 	 p[9]=piece3.length()%256;
815 	
816 	 stringbuffer+=piece1;
817 	 stringbuffer.append(p,10);
818 	 stringbuffer+=piece3;
819 	
820 	 d.ancount++;
821 	}

The p[8] and p[9] bytes are filled with the data, as specified by the standard, and then the string "piece3" is appended. The string piece3 consists of 1 BYTE holding the txt string length and the txt string itself.

If the string has more than 256 bytes, the txt.length() is truncated, holding only txt.length()%256.

The DNS standard says the data in the TXT record comprise several strings in the form

[data length] [string length] [string    ] [string length] [string   ] ...
     2 bytes    1 byte          l bytes       1 byte        l bytes    ...

And PowerDNS is sending

[data length] [string length] [string    ]
    2 bytes     length%4       n bytes  

In the resolver, the parsing of this malformed packet goes as follows

 Read data length (for example, 270 bytes)
 Read first string length (270%256 = 14 bytes)
 Read fist string (14 bytes)
 As 14 bytes < 270 bytes, read the next byte as if it where the next string length ...
 Try to read that length (arbitrary data)
 ...
 (and screw up)

The code in PowerDNS 2.9.20 only works (sending correct packets) when p[8] piece3.length()/256; is 0

I havent seen the new 2.9.21 (soon 3.0) code, but after building SVN rev 1029, it still happens.

Rewriting the DNSPacket::addTXTorSPFRecord() to divide the txt string into 255 byte chunks and append the strings in order:

void DNSPacket::addTXTorSPFRecord(uint16_t qtype, string domain, string txt, uint32_t ttl)
{
  string piece1;
  int totalength, chunks, reminder, i;
  string buffer;
  //xtoqname(domain, &piece1);
  toqname(domain, &piece1);
  char p[10];
  makeHeader(p, qtype, ttl);

  chunks = txt.length()/255;
  reminder = txt.length()%255;
  totalength = txt.length() + chunks + ((reminder)?1:0);

  p[8]=totalength/256;
  p[9]=totalength%256;
  
  stringbuffer+=piece1;
  stringbuffer.append(p,10);
  buffer.reserve(256);

  for (i = 0; i < chunks; i++) {
        buffer = "";
        buffer.append(1, 255);
        buffer.append(txt.substr(i * 255, 255));
        stringbuffer += buffer;
  }
  buffer = "";
  buffer.append(1, (unsigned char)reminder);
  buffer.append(txt.substr(chunks * 255, reminder));
  stringbuffer += buffer;
  d.ancount++;
}

With this fix, PowerDNS 2.9.20 sends correct TXT answers up to the standard 64 KB

Bye,

Pablo Martín Medrano
Firmware Team. Fon Wireless Ltd.



More information about the Pdns-dev mailing list