Dear all,
I spend some time to further investigate on this bug. For example, I checked
also with the Free/Swan implementation of a dhcp relay agent.
During my investigations I found out that this bug also applies for bind9 when
sending over the loopback interface. This applies of you run applications and
a DNS server on the same machine. The attched example shows fetchmail
querying for a DNS lookup:
All tests were done using Ubuntu gutsy, but I believe they apply to Debian
systems in general.
The dhcpd bug can easily be solved by patching the function
decode_udp_ip_header in packet.c:
-------------------------------------------------------------------------------------------------------------------------
ssize_t decode_udp_ip_header (interface, buf, bufix, from, buflen)
struct interface_info *interface;
unsigned char *buf;
unsigned bufix;
struct sockaddr_in *from;
unsigned buflen;
{
[...]
/* Check the IP header checksum - it should be zero. */
++ip_packets_seen;
if (wrapsum (checksum (buf + bufix, ip_len, 0))) {
++ip_packets_bad_checksum;
if (ip_packets_seen > 4 &&
(ip_packets_seen / ip_packets_bad_checksum) < 2) {
log_info ("%d bad IP checksums seen in %d packets",
ip_packets_bad_checksum, ip_packets_seen);
ip_packets_seen = ip_packets_bad_checksum = 0;
}
return -1;
}
[...]
/* Compute UDP checksums, including the ``pseudo-header'', the UDP
header and the data. If the UDP checksum field is zero, we're
not supposed to do a checksum. */
data = buf + bufix + ip_len + sizeof *udp;
len = ulen - sizeof *udp;
++udp_packets_length_checked;
if (len + data > buf + bufix + buflen) {
++udp_packets_length_overflow;
if (udp_packets_length_checked > 4 &&
(udp_packets_length_checked /
udp_packets_length_overflow) < 2) {
log_info ("%d udp packets in %d too long - dropped",
udp_packets_length_overflow,
udp_packets_length_checked);
udp_packets_length_overflow =
udp_packets_length_checked = 0;
}
return -1;
}
if (len + data < buf + bufix + buflen &&
len + data != buf + bufix + buflen && !ignore)
log_debug ("accepting packet with data after udp payload.");
if (len + data > buf + bufix + buflen) {
log_debug ("dropping packet with bogus uh_ulen %ld",
(long)(len + sizeof *udp));
return -1;
}
usum = udp -> uh_sum;
udp -> uh_sum = 0;
sum = wrapsum (checksum ((unsigned char *)udp, sizeof *udp,
checksum (data, len,
checksum ((unsigned char *)
&ip.ip_src,
2 * sizeof ip.ip_src,
IPPROTO_UDP +
(u_int32_t)ulen))));
udp_packets_seen++;
if (usum && usum != sum) {
udp_packets_bad_checksum++;
if (udp_packets_seen > 4 &&
(udp_packets_seen / udp_packets_bad_checksum) < 2) {
log_info ("%d bad udp checksums in %d packets",
udp_packets_bad_checksum, udp_packets_seen);
udp_packets_seen = udp_packets_bad_checksum = 0;
}
// Ignore the udp checksum bug in debian systems
// return -1;
}
/* Copy out the port... */
memcpy (&from -> sin_port, &udp -> uh_sport, sizeof udp -> uh_sport);
return ip_len + sizeof *udp;
}
-------------------------------------------------------------------------------------------------------------------------
I haven't checked the bind9 code, yet. I'm also not sure if this problem is a
global one, i. e. all applications that send udp packets via loopback have
this problem.
Free/Swan dhcp relay agent by the way uses the socket datagram service.
Whereas dhcpd uses a raw socket.
I hope this helps you.
Best regards
Thomas
No. Time Source Destination Protocol
Info
79 09:18:37.877047 192.168.0.65 192.168.0.65 DNS
Standard query A pop3.strato.de
Frame 79 (74 bytes on wire, 74 bytes captured)
Arrival Time: Feb 25, 2008 09:18:37.877047000
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00
(00:00:00:00:00:00)
Internet Protocol, Src: 192.168.0.65 (192.168.0.65), Dst: 192.168.0.65
(192.168.0.65)
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
0000 00.. = Differentiated Services Codepoint: Default (0x00)
.... ..0. = ECN-Capable Transport (ECT): 0
.... ...0 = ECN-CE: 0
Total Length: 60
Identification: 0x771f (30495)
Flags: 0x04 (Don't Fragment)
0... = Reserved bit: Not set
.1.. = Don't fragment: Set
..0. = More fragments: Not set
Fragment offset: 0
Time to live: 64
Protocol: UDP (0x11)
Header checksum: 0x41bf [correct]
[Good: True]
[Bad : False]
Source: 192.168.0.65 (192.168.0.65)
Destination: 192.168.0.65 (192.168.0.65)
User Datagram Protocol, Src Port: 32781 (32781), Dst Port: domain (53)
Source port: 32781 (32781)
Destination port: domain (53)
Length: 40
Checksum: 0x820c [incorrect, should be 0x0f18 (maybe caused by "UDP
checksum offload"?)]
[Good Checksum: False]
[Bad Checksum: True]
Domain Name System (query)
[Response In: 80]
Transaction ID: 0x84dd
Flags: 0x0100 (Standard query)
0... .... .... .... = Response: Message is a query
.000 0... .... .... = Opcode: Standard query (0)
.... ..0. .... .... = Truncated: Message is not truncated
.... ...1 .... .... = Recursion desired: Do query recursively
.... .... .0.. .... = Z: reserved (0)
.... .... ...0 .... = Non-authenticated data OK: Non-authenticated data
is unacceptable
Questions: 1
Answer RRs: 0
Authority RRs: 0
Additional RRs: 0
Queries
pop3.strato.de: type A, class IN
Name: pop3.strato.de
Type: A (Host address)
Class: IN (0x0001)