#<text/plain; charset=iso-8859-1
Here is a technical note about UDP checksums
(which should be mandatory for DNS, perhaps we should
write a RFC about this ?)
Francis.Dupont(a)inria.fr
IP checksums are the 1-complement of the 1-complement sum
of a part of the packet viewed as a 16-bit integer vector.
There are two zeros in the 1-complement arithmetic, 0x0000
and 0xffff. Usually only 0x0000 is the legal value but
for UDP/IPv4 zeros have special meanings because the
checksum is optional (but must be enabled by default,
cf RFC 1122 4.1.3.4 page 78-79) :
- 0x0000 means the checksum is not used
- 0xffff means the checksum is used and its value is zero
Unix OSs have a kernel flag named usually "udpcksum"
settable by a binary editor, config tools (like sysctl,
ndd, no, ...) and defined in .../sys/netinet/in_proto.c
which is distributed in the source form in order to
allow the setting of various TCP/IP flags.
On output 4.4 BSD Lite code is (cf TCP/IP Illustrated vol 2) :
/*
* Stuff checksum and output datagram.
*/
ui->ui_sum = 0;
if (udpcksum) {
if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
ui->ui_sum = 0xffff;
}
(lines 388-395 of .../sys/netinet/udp_usrreq.c)
On input the code is :
/*
* Checksum extended UDP header and data.
*/
if (udpcksum && uh->uh_sum) {
((struct ipovly *)ip)->ih_next = 0;
((struct ipovly *)ip)->ih_prev = 0;
((struct ipovly *)ip)->ih_x1 = 0;
((struct ipovly *)ip)->ih_len = uh->uh_ulen;
if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) {
udpstat.udps_badsum++;
m_freem(m);
return;
}
}
(lines 107-120 of .../sys/netinet/udp_usrreq.c)
The best way to test whether the UDP checksum is enabled
is to see if the field is 0x0000 or not with a tool
like etherfind, snoop, tcpdump (just try the command
tcpdump udp port 53 and 'udp[6:2] == 0'
if you believe this problem is anecdotal :-).
The ZoneCheck tool written by Benont Grangi for the NIC France
(available at URL:http://www.nic.fr/ZoneCheck/sources.html)
uses a little tool named ckudpcksum which can give an hint
(URL:ftp://ftp.nic.fr/pub/programmes/DNS/ckudpcksum.tar.gz).
It sends UDP packets with a *wrong* checksum in order to see
if the target host verified checksums of incoming UDP packets.
It is a legitimate test for a new DNS server and can be used
with DNS clients where UDP checksums for incoming and outgoing
packets are not managed independently (it was the first purpose
of this program but it is not possible to do it very easily
and I have suggested this trick to Benont).