From owner-freebsd-net@FreeBSD.ORG Thu May 3 02:18:58 2007 Return-Path: X-Original-To: freebsd-net@freebsd.org Delivered-To: freebsd-net@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id D44B116A402 for ; Thu, 3 May 2007 02:18:58 +0000 (UTC) (envelope-from mluckie@cs.waikato.ac.nz) Received: from zombie.scms.waikato.ac.nz (mail.scms.waikato.ac.nz [130.217.241.36]) by mx1.freebsd.org (Postfix) with ESMTP id 6DE9813C45B for ; Thu, 3 May 2007 02:18:58 +0000 (UTC) (envelope-from mluckie@cs.waikato.ac.nz) Received: from sorcerer.cs.waikato.ac.nz ([130.217.251.39]) by zombie.scms.waikato.ac.nz with esmtps (TLSv1:AES256-SHA:256) (Exim 4.52) id 1HjQdf-0004cT-OL for freebsd-net@freebsd.org; Thu, 03 May 2007 14:01:47 +1200 Received: from mluckie by sorcerer.cs.waikato.ac.nz with local (Exim 4.67 (FreeBSD)) (envelope-from ) id 1HjQde-000P8i-Sd for freebsd-net@freebsd.org; Thu, 03 May 2007 14:01:46 +1200 Date: Thu, 3 May 2007 14:01:46 +1200 From: Matthew Luckie To: freebsd-net@freebsd.org Message-ID: <20070503020146.GA96616@sorcerer.cs.waikato.ac.nz> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.2.2i Sender: Matthew Luckie Subject: UDP checksums in ICMP quotes X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 03 May 2007 02:18:58 -0000 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;