[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