Ethereal-dev: Re: [ethereal-dev] Ethereal and UDP checksums..
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Guy Harris <gharris@xxxxxxxxxxxx>
Date: Wed, 10 May 2000 22:22:16 -0700
On Wed, May 10, 2000 at 02:21:38PM +0300, Markus Stenberg wrote: > Apparently Ethereal did not check UDP checksums.. so I wrote quickie hack > to do it. > > There are some problems with the hack, mainly, the 12-byte global character > array used for transferring UDP pseudoheader data from IP to UDP handler, > as there doesn't seem any other way to do it (elegantly). Well, here's a patch with TCP checksumming stuff I did a couple of weeks ago (when we were having a problem at Network Appliance with a software release under development - not yet released - that looked as if it might be a checksumming problem, and did, in fact, turn out to be a checksum bug), to which I've added UDP checksumming support. It generates the pseudoheaders from the IP (v4 or v6) addresses handed in via the "packet_info" structure and the IP protocol type value for the protocol in question (TCP or UDP), and has a checksumming routine that's the BSD checksum routine modified to take a scatter/gather list of pointer/length values rather than an mbuf chain. It doesn't checksum packets where we didn't capture all the data; unfortunately, it *does* checksum fragmented IP datagrams, which it shouldn't do (the IP layer needs to supply a "fragmented" indication to TCP and UDP to do that) - in the long term, I'd like to be able to have Ethereal reassemble fragmented IP datagrams, so that, for example, an NFS READDIR or READDIRPLUS reply that fits in more than one link-layer packet can be dissected in its entirety, rather than just having the first fragment dissected (a capability I could've used several years ago; that was one of the things that first got me interested in packet analyzers), in which case, if we have all of the fragments, we *could* checksum the datagram, although IP would still need to tell TCP and UDP whether it found all of the fragments. There's also a problem with the version of the BSD copyright/license in that code - I have the impression that the "give credit" clause: * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. conflicts with clause 6 of the GPL: 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. as it "imposes [a] further restriction" over and above "these terms and conditions" (i.e., over and above what's in the GPL). I don't know if the removal of that clause, which I think the folks at UCB removed recently, retroactively affects code with the "give credit" clause in it, nor do I know if there are any versions of the BSD checksum code without that clause. I didn't find any portable C checksumming code in the Linux kernel when I last checked, although I may have missed it; I don't want to have only assembler-language code, as I don't want to oblige Ethereal users to 1) be running an GNU as-compatible assembler (and don't want to have to cook up a way to arrange to pick the "right" assembler-language code for the assembler the platform has) or 2) be running a processor currently supported by Linux. It may be that a simple checksum routine is Fast Enough. I've attached the patch, as well as the "in_cksum.h" and "in_cksum.c" files for the checksumming code.
? in_cksum.h ? in_cksum.c ? errs Index: Makefile.am =================================================================== RCS file: /usr/local/cvsroot/ethereal/Makefile.am,v retrieving revision 1.193 diff -c -r1.193 Makefile.am *** Makefile.am 2000/05/05 09:32:00 1.193 --- Makefile.am 2000/05/11 04:45:12 *************** *** 248,253 **** --- 248,255 ---- etypes.h \ follow.c \ follow.h \ + in_cksum.c \ + in_cksum.h \ inet_v6defs.h \ ipproto.c \ ipv4.c \ Index: packet-ip.c =================================================================== RCS file: /usr/local/cvsroot/ethereal/packet-ip.c,v retrieving revision 1.84 diff -c -r1.84 packet-ip.c *** packet-ip.c 2000/05/10 21:36:55 1.84 --- packet-ip.c 2000/05/11 04:45:16 *************** *** 40,45 **** --- 40,46 ---- #include <glib.h> #include "packet.h" #include "resolv.h" + #include "in_cksum.h" #ifdef NEED_SNPRINTF_H # ifdef HAVE_STDARG_H *************** *** 805,825 **** static char *ip_checksum_state(e_ip *iph) { ! unsigned long Sum; ! unsigned char *Ptr, *PtrEnd; ! unsigned short word; ! ! Sum = 0; ! PtrEnd = (lo_nibble(iph->ip_v_hl) * 4 + (char *)iph); ! for (Ptr = (unsigned char *) iph; Ptr < PtrEnd; Ptr += 2) { ! memcpy(&word, Ptr, sizeof word); ! Sum += word; ! } ! ! Sum = (Sum & 0xFFFF) + (Sum >> 16); ! Sum = (Sum & 0xFFFF) + (Sum >> 16); ! if (Sum != 0xffff) return "incorrect"; return "correct"; --- 806,816 ---- static char *ip_checksum_state(e_ip *iph) { ! vec_t cksum_vec[1]; ! cksum_vec[0].ptr = (const guint8 *)iph; ! cksum_vec[0].len = lo_nibble(iph->ip_v_hl) * 4; ! if (in_cksum(&cksum_vec[0], 1) != 0) return "incorrect"; return "correct"; Index: packet-tcp.c =================================================================== RCS file: /usr/local/cvsroot/ethereal/packet-tcp.c,v retrieving revision 1.73 diff -c -r1.73 packet-tcp.c *** packet-tcp.c 2000/05/05 09:32:05 1.73 --- packet-tcp.c 2000/05/11 04:45:18 *************** *** 40,45 **** --- 40,46 ---- #include "globals.h" #include "resolv.h" #include "follow.h" + #include "in_cksum.h" #ifdef NEED_SNPRINTF_H # ifdef HAVE_STDARG_H *************** *** 422,427 **** --- 423,430 ---- guint hlen; guint optlen; guint packet_max = pi.len; + vec_t cksum_vec[4]; + guint32 phdr[2]; /* To do: Check for {cap len,pkt len} < struct len */ /* Avoids alignment problems on many architectures. */ *************** *** 497,503 **** proto_tree_add_item(field_tree, hf_tcp_flags_syn, offset + 13, 1, th.th_flags); proto_tree_add_item(field_tree, hf_tcp_flags_fin, offset + 13, 1, th.th_flags); proto_tree_add_item(tcp_tree, hf_tcp_window_size, offset + 14, 2, th.th_win); ! proto_tree_add_item(tcp_tree, hf_tcp_checksum, offset + 16, 2, th.th_sum); if (th.th_flags & TH_URG) proto_tree_add_item(tcp_tree, hf_tcp_urgent_pointer, offset + 18, 2, th.th_urp); } --- 500,543 ---- proto_tree_add_item(field_tree, hf_tcp_flags_syn, offset + 13, 1, th.th_flags); proto_tree_add_item(field_tree, hf_tcp_flags_fin, offset + 13, 1, th.th_flags); proto_tree_add_item(tcp_tree, hf_tcp_window_size, offset + 14, 2, th.th_win); ! if (pi.captured_len >= pi.len) { ! /* The packet isn't truncated, so we can checksum it. ! XXX - we have to check whether this is part of a fragmented ! IP datagram, too.... */ ! ! /* Set up the fields of the pseudo-header. */ ! cksum_vec[0].ptr = pi.src.data; ! cksum_vec[0].len = pi.src.len; ! cksum_vec[1].ptr = pi.dst.data; ! cksum_vec[1].len = pi.dst.len; ! cksum_vec[2].ptr = (const guint8 *)&phdr; ! switch (pi.src.type) { ! ! case AT_IPv4: ! phdr[0] = htonl((IP_PROTO_TCP<<16) + END_OF_FRAME); ! cksum_vec[2].len = 4; ! break; ! ! case AT_IPv6: ! phdr[0] = htonl(END_OF_FRAME); ! phdr[1] = htonl(IP_PROTO_TCP); ! cksum_vec[2].len = 8; ! break; ! ! default: ! /* TCP runs only atop IPv4 and IPv6.... */ ! g_assert_not_reached(); ! break; ! } ! cksum_vec[3].ptr = &pd[offset]; ! cksum_vec[3].len = END_OF_FRAME; ! proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, offset + 16, 2, ! th.th_sum, "Checksum: 0x%04x (%s)", th.th_sum, ! (in_cksum(&cksum_vec[0], 4) == 0) ? "correct" : "incorrect"); ! } else { ! proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, offset + 16, 2, ! th.th_sum, "Checksum: 0x%04x", th.th_sum); ! } if (th.th_flags & TH_URG) proto_tree_add_item(tcp_tree, hf_tcp_urgent_pointer, offset + 18, 2, th.th_urp); } Index: packet-udp.c =================================================================== RCS file: /usr/local/cvsroot/ethereal/packet-udp.c,v retrieving revision 1.69 diff -c -r1.69 packet-udp.c *** packet-udp.c 2000/04/20 07:05:57 1.69 --- packet-udp.c 2000/05/11 04:45:19 *************** *** 43,48 **** --- 43,49 ---- #include <glib.h> #include "globals.h" #include "resolv.h" + #include "in_cksum.h" #include "plugins.h" #include "packet-udp.h" *************** *** 146,151 **** --- 147,154 ---- guint16 uh_sport, uh_dport, uh_ulen, uh_sum; proto_tree *udp_tree; proto_item *ti; + vec_t cksum_vec[4]; + guint32 phdr[2]; if (!BYTES_ARE_IN_FRAME(offset, sizeof(e_udphdr))) { dissect_data(pd, offset, fd, tree); *************** *** 178,185 **** proto_tree_add_item_hidden(udp_tree, hf_udp_port, offset+2, 2, uh_dport); proto_tree_add_item(udp_tree, hf_udp_length, offset + 4, 2, uh_ulen); ! proto_tree_add_uint_format(udp_tree, hf_udp_checksum, offset + 6, 2, uh_sum, ! "Checksum: 0x%04x", uh_sum); } /* Skip over header */ --- 181,224 ---- proto_tree_add_item_hidden(udp_tree, hf_udp_port, offset+2, 2, uh_dport); proto_tree_add_item(udp_tree, hf_udp_length, offset + 4, 2, uh_ulen); ! if (pi.captured_len >= pi.len) { ! /* The packet isn't truncated, so we can checksum it. ! XXX - we have to check whether this is part of a fragmented ! IP datagram, too.... */ ! ! /* Set up the fields of the pseudo-header. */ ! cksum_vec[0].ptr = pi.src.data; ! cksum_vec[0].len = pi.src.len; ! cksum_vec[1].ptr = pi.dst.data; ! cksum_vec[1].len = pi.dst.len; ! cksum_vec[2].ptr = (const guint8 *)&phdr; ! switch (pi.src.type) { ! ! case AT_IPv4: ! phdr[0] = htonl((IP_PROTO_UDP<<16) + END_OF_FRAME); ! cksum_vec[2].len = 4; ! break; ! ! case AT_IPv6: ! phdr[0] = htonl(END_OF_FRAME); ! phdr[1] = htonl(IP_PROTO_UDP); ! cksum_vec[2].len = 8; ! break; ! ! default: ! /* TCP runs only atop IPv4 and IPv6.... */ ! g_assert_not_reached(); ! break; ! } ! cksum_vec[3].ptr = &pd[offset]; ! cksum_vec[3].len = END_OF_FRAME; ! proto_tree_add_uint_format(udp_tree, hf_udp_checksum, offset + 6, 2, ! uh_sum, "Checksum: 0x%04x (%s)", uh_sum, ! (in_cksum(&cksum_vec[0], 4) == 0) ? "correct" : "incorrect"); ! } else { ! proto_tree_add_uint_format(udp_tree, hf_udp_checksum, offset + 6, 2, ! uh_sum, "Checksum: 0x%04x", uh_sum); ! } } /* Skip over header */
typedef struct { const guint8 *ptr; int len; } vec_t; extern int in_cksum(const vec_t *vec, int veclen);
/* * Copyright (c) 1988, 1992, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/netinet/in_cksum.c,v 1.5.4.1 1999/08/29 16:29:34 peter Exp $ */ #include <glib.h> #include "in_cksum.h" /* * Checksum routine for Internet Protocol family headers (Portable Version). * * This routine is very heavily used in the network * code and should be modified for each CPU to be as fast as possible. */ #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} int in_cksum(const vec_t *vec, int veclen) { register const guint16 *w; register int sum = 0; register int mlen = 0; int byte_swapped = 0; union { char c[2]; guint16 s; } s_util; union { guint16 s[2]; long l; } l_util; for (; veclen != 0; vec++, veclen--) { if (vec->len == 0) continue; w = (const guint16 *)vec->ptr; if (mlen == -1) { /* * The first byte of this chunk is the continuation * of a word spanning between this chunk and the * last chunk. * * s_util.c[0] is already saved when scanning previous * chunk. */ s_util.c[1] = *(char *)w; sum += s_util.s; w = (const guint16 *)((const guint8 *)w + 1); mlen = vec->len - 1; } else mlen = vec->len; /* * Force to even boundary. */ if ((1 & (int) w) && (mlen > 0)) { REDUCE; sum <<= 8; s_util.c[0] = *(const guint8 *)w; w = (const guint16 *)((const guint8 *)w + 1); mlen--; byte_swapped = 1; } /* * Unroll the loop to make overhead from * branches &c small. */ while ((mlen -= 32) >= 0) { sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; w += 16; } mlen += 32; while ((mlen -= 8) >= 0) { sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; w += 4; } mlen += 8; if (mlen == 0 && byte_swapped == 0) continue; REDUCE; while ((mlen -= 2) >= 0) { sum += *w++; } if (byte_swapped) { REDUCE; sum <<= 8; byte_swapped = 0; if (mlen == -1) { s_util.c[1] = *(char *)w; sum += s_util.s; mlen = 0; } else mlen = -1; } else if (mlen == -1) s_util.c[0] = *(char *)w; } if (mlen == -1) { /* The last mbuf has odd # of bytes. Follow the standard (the odd byte may be shifted left by 8 bits or not as determined by endian-ness of the machine) */ s_util.c[1] = 0; sum += s_util.s; } REDUCE; return (~sum & 0xffff); }
- References:
- [ethereal-dev] Ethereal and UDP checksums..
- From: Markus Stenberg
- [ethereal-dev] Ethereal and UDP checksums..
- Prev by Date: Re: [ethereal-dev] Re: [ethereal-users] RTP
- Next by Date: [ethereal-dev] Newbie question
- Previous by thread: [ethereal-dev] Ethereal and UDP checksums..
- Next by thread: [ethereal-dev] packet-giop.h
- Index(es):