Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 3 May 2007 14:01:46 +1200
From:      Matthew Luckie <mluckie@cs.waikato.ac.nz>
To:        freebsd-net@freebsd.org
Subject:   UDP checksums in ICMP quotes
Message-ID:  <20070503020146.GA96616@sorcerer.cs.waikato.ac.nz>

next in thread | raw e-mail | index | archive | help
At the moment, freebsd checks a UDP checksum in place, overwriting
whatever is there.  This has a side effect of the ICMP code sending back
the first eight bytes of the UDP payload with 2 bytes different to
what that system sent.

For example:

listening on lo0, link-type NULL (BSD loopback), capture size 1500 bytes
13:41:24.382239 IP localhost.40858 > localhost.33435: UDP, length 12
        0x0000:  0200 0000 4500 0028 9f9b 0000 0111 1c28
        0x0010:  7f00 0001 7f00 0001 9f9a 829b 0014 df8d
        0x0020:  0000 0000 0000 0000 0000 0000
13:41:24.382250 IP localhost > localhost: ICMP localhost udp port 33435 unreachable, length 36
        0x0000:  0200 0000 4500 0038 00cc 0000 4001 7bf7
        0x0010:  7f00 0001 7f00 0001 0303 dab2 0000 0000
        0x0020:  4500 0028 9f9b 0000 0111 1c28 7f00 0001
        0x0030:  7f00 0001 9f9a 829b 0014 0000

With the patch below, the checksum is not checked in place -- i.e.

13:54:47.371646 IP localhost.33826 > localhost.33435: UDP, length 12
        0x0000:  0200 0000 4500 0028 8423 0000 0111 37a0
        0x0010:  7f00 0001 7f00 0001 8422 829b 0014 fb05
        0x0020:  0000 0000 0000 0000 0000 0000
13:54:47.371658 IP localhost > localhost: ICMP localhost udp port 33435 unreachable, length 36
        0x0000:  0200 0000 4500 0038 001b 0000 4001 7ca8
        0x0010:  7f00 0001 7f00 0001 0303 fb24 0000 0000
        0x0020:  4500 0028 8423 0000 0111 37a0 7f00 0001
        0x0030:  7f00 0001 8422 829b 0014 fb05

Patch is against -current, but applies just fine to FreeBSD 6.2 as well.

--- udp_usrreq.c.orig	Thu May  3 12:24:55 2007
+++ udp_usrreq.c	Thu May  3 12:26:47 2007
@@ -248,23 +248,24 @@
 	 * Checksum extended UDP header and data.
 	 */
 	if (uh->uh_sum) {
+		u_short uh_sum;
 		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
 			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
-				uh->uh_sum = m->m_pkthdr.csum_data;
+				uh_sum = m->m_pkthdr.csum_data;
 			else
-				uh->uh_sum = in_pseudo(ip->ip_src.s_addr,
+				uh_sum = in_pseudo(ip->ip_src.s_addr,
 				    ip->ip_dst.s_addr, htonl((u_short)len +
 				    m->m_pkthdr.csum_data + IPPROTO_UDP));
-			uh->uh_sum ^= 0xffff;
+			uh_sum ^= 0xffff;
 		} else {
 			char b[9];
 			bcopy(((struct ipovly *)ip)->ih_x1, b, 9);
 			bzero(((struct ipovly *)ip)->ih_x1, 9);
 			((struct ipovly *)ip)->ih_len = uh->uh_ulen;
-			uh->uh_sum = in_cksum(m, len + sizeof (struct ip));
+			uh_sum = in_cksum(m, len + sizeof (struct ip));
 			bcopy(b, ((struct ipovly *)ip)->ih_x1, 9);
 		}
-		if (uh->uh_sum) {
+		if (uh_sum) {
 			udpstat.udps_badsum++;
 			m_freem(m);
 			return;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070503020146.GA96616>