Add code to check the checksums of TCP segments and UDP datagrams;

replace the existing checksummer with a modified version of the BSD
checksumming code.  Add a flag to the "packet_info" structure to
indicate that a packet is the first fragment of a fragmented datagram,
so that the checksummers won't try to checksum those.

(It doesn't seem to add a lot of CPU overhead, so we don't introduce a
flag to disable it, yet.  Further checks may be necessary to see whether
the overhead is just swamped by other overheads when scanning through a
capture dissecting all frames, or if it truly is negligible.)

Make the Boolean preference option controlling whether to make the
top-level protocol tree item for TCP display a packet summary static to
the TCP dissector (it doesn't need to be accessible outside the TCP
dissector).

svn path=/trunk/; revision=2751
This commit is contained in:
Guy Harris 2000-12-13 02:24:23 +00:00
parent 10022aee67
commit 677a1c6dc2
8 changed files with 373 additions and 59 deletions

View File

@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
# $Id: Makefile.am,v 1.257 2000/12/03 09:18:20 guy Exp $
# $Id: Makefile.am,v 1.258 2000/12/13 02:24:21 guy Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@zing.org>
@ -277,6 +277,8 @@ ETHEREAL_COMMON_SOURCES = \
etypes.h \
follow.c \
follow.h \
in_cksum.c \
in_cksum.h \
ipproto.c \
llcsaps.h \
nlpid.h \

View File

@ -1,7 +1,7 @@
## Makefile for building ethereal.exe with Microsoft C and nmake
## Use: nmake -f makefile.nmake
#
# $Id: Makefile.nmake,v 1.66 2000/11/30 09:31:50 guy Exp $
# $Id: Makefile.nmake,v 1.67 2000/12/13 02:24:21 guy Exp $
include config.nmake
@ -174,6 +174,7 @@ ETHEREAL_COMMON_OBJECTS = \
column.obj \
follow.obj \
getopt.obj \
in_cksum.obj \
ipproto.obj \
prefs.obj \
print.obj \

View File

@ -1,7 +1,7 @@
/* packet.h
* Definitions for packet disassembly structures and routines
*
* $Id: packet.h,v 1.14 2000/12/04 06:37:46 guy Exp $
* $Id: packet.h,v 1.15 2000/12/13 02:24:23 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -170,7 +170,8 @@ typedef struct _packet_info {
address net_dst; /* network-layer destination address */
address src; /* source address (net if present, DL otherwise )*/
address dst; /* destination address (net if present, DL otherwise )*/
guint32 ipproto;
guint32 ipproto; /* IP protocol, if this is an IP packet */
gboolean fragmented; /* TRUE if the protocol is only a fragment */
port_type ptype; /* type of the following two port numbers */
guint32 srcport; /* source port */
guint32 destport; /* destination port */

214
in_cksum.c Normal file
View File

@ -0,0 +1,214 @@
/* in_cksum.c
* 4.4-Lite-2 Internet checksum routine, modified to take a vector of
* pointers/lengths giving the pieces to be checksummed.
*
* $Id: in_cksum.c,v 1.1 2000/12/13 02:24:22 guy Exp $
*/
/*
* 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. 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
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#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);
}
/*
* Given the host-byte-order value of the checksum field in a packet
* header, and the one's complement negation of the host-byte-order
* checksum of the packet, compute what the checksum field *should*
* have been.
*/
guint16
in_cksum_shouldbe(guint16 sum, guint16 computed_sum)
{
guint32 shouldbe;
/*
* The value that should have gone into the checksum field
* is the negative of the value gotten by summing up everything
* *but* the checksum field.
*
* We can compute that by subtracting the value of the checksum
* field from the sum of all the data in the packet, and then
* computing the negative of that value.
*
* "sum" is the value of the checksum field, and "computed_sum"
* is the negative of the sum of all the data in the packets,
* so that's -(-computed_sum - sum), or (sum + computed_sum).
*
* All the arithmetic in question is one's complement, so the
* addition must include an end-around carry; we do this by
* doing the arithmetic in 32 bits (with no sign-extension),
* and then adding the upper 16 bits of the sum, which contain
* the carry, to the lower 16 bits of the sum, and then do it
* again in case *that* sum produced a carry.
*
* As RFC 1071 notes, the checksum can be computed without
* byte-swapping the 16-bit words; summing 16-bit words
* on a big-endian machine gives a big-endian checksum, which
* can be directly stuffed into the big-endian checksum fields
* in protocol headers, and summing words on a little-endian
* machine gives a little-endian checksum, which must be
* byte-swapped before being stuffed into a big-endian checksum
* field.
*
* "computed_sum" is a host-byte-order value, so we must put
* it in network byte order before subtracting it from the
* network-byte-order value from the header; the adjusted
* checksum will be in network byte order, which is what
* we'll return.
*/
shouldbe = sum;
shouldbe += htons(computed_sum);
shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
return shouldbe;
}

14
in_cksum.h Normal file
View File

@ -0,0 +1,14 @@
/* in_cksum.h
* Declaration of Internet checksum routine.
*
* $Id: in_cksum.h,v 1.1 2000/12/13 02:24:22 guy Exp $
*/
typedef struct {
const guint8 *ptr;
int len;
} vec_t;
extern int in_cksum(const vec_t *vec, int veclen);
extern guint16 in_cksum_shouldbe(guint16 sum, guint16 computed_sum);

View File

@ -1,7 +1,7 @@
/* packet-ip.c
* Routines for IP and miscellaneous IP protocol packet disassembly
*
* $Id: packet-ip.c,v 1.109 2000/12/08 22:53:08 guy Exp $
* $Id: packet-ip.c,v 1.110 2000/12/13 02:24:21 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -52,6 +52,7 @@
#include "aftypes.h"
#include "packet-ip.h"
#include "packet-ipsec.h"
#include "in_cksum.h"
static void dissect_icmp(tvbuff_t *, packet_info *, proto_tree *);
static void dissect_igmp(tvbuff_t *, packet_info *, proto_tree *);
@ -749,49 +750,11 @@ static const true_false_string flags_set_truth = {
static guint16 ip_checksum(const guint8 *ptr, int len)
{
unsigned long Sum;
const unsigned char *Ptr, *PtrEnd;
vec_t cksum_vec[1];
Sum = 0;
PtrEnd = ptr + len;
for (Ptr = ptr; Ptr < PtrEnd; Ptr += 2) {
Sum += pntohs(Ptr);
}
Sum = (Sum & 0xFFFF) + (Sum >> 16);
Sum = (Sum & 0xFFFF) + (Sum >> 16);
return (guint16)~Sum;
}
static guint16 ip_checksum_shouldbe(guint16 sum, guint16 computed_sum)
{
guint32 shouldbe;
/*
* The value that should have gone into the checksum field
* is the negative of the value gotten by summing up everything
* *but* the checksum field.
*
* We can compute that by subtracting the value of the checksum
* field from the sum of all the data in the packet, and then
* computing the negative of that value.
*
* "sum" is the value of the checksum field, and "computed_sum"
* is the negative of the sum of all the data in the packets,
* so that's -(-computed_sum - sum), or (sum + computed_sum).
*
* All the arithmetic in question is one's complement, so the
* addition must include an end-around carry; we do this by
* doing the arithmetic in 32 bits (with no sign-extension),
* and then adding the upper 16 bits of the sum, which contain
* the carry, to the lower 16 bits of the sum, and then do it
* again in case *that* sum produced a carry.
*/
shouldbe = sum;
shouldbe += computed_sum;
shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
return shouldbe;
cksum_vec[0].ptr = ptr;
cksum_vec[0].len = len;
return in_cksum(&cksum_vec[0], 1);
}
void
@ -902,7 +865,7 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
else {
proto_tree_add_uint_format(ip_tree, hf_ip_checksum, tvb, offset + 10, 2, iph.ip_sum,
"Header checksum: 0x%04x (incorrect, should be 0x%04x)", iph.ip_sum,
ip_checksum_shouldbe(iph.ip_sum, ipsum));
in_cksum_shouldbe(iph.ip_sum, ipsum));
}
proto_tree_add_ipv4(ip_tree, hf_ip_src, tvb, offset + 12, 4, iph.ip_src);
@ -945,6 +908,15 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
return;
}
/*
* If this is the first fragment, but not the only fragment,
* tell the next protocol that.
*/
if (iph.ip_off & IP_MF)
pinfo->fragmented = TRUE;
else
pinfo->fragmented = FALSE;
/* Hand off to the next protocol.
XXX - setting the columns only after trying various dissectors means
@ -1126,7 +1098,7 @@ dissect_icmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_uint_format(icmp_tree, hf_icmp_checksum, tvb, 2, 2,
cksum,
"Checksum: 0x%04x (incorrect, should be 0x%04x)",
cksum, ip_checksum_shouldbe(cksum, computed_cksum));
cksum, in_cksum_shouldbe(cksum, computed_cksum));
}
} else {
proto_tree_add_uint(icmp_tree, hf_icmp_checksum, tvb, 2, 2, cksum);

View File

@ -1,7 +1,7 @@
/* packet-tcp.c
* Routines for TCP packet disassembly
*
* $Id: packet-tcp.c,v 1.91 2000/12/04 06:37:44 guy Exp $
* $Id: packet-tcp.c,v 1.92 2000/12/13 02:24:21 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -38,6 +38,7 @@
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "in_cksum.h"
#ifdef NEED_SNPRINTF_H
# include "snprintf.h"
@ -54,7 +55,7 @@
#include "strutil.h"
/* Place TCP summary in proto tree */
gboolean g_tcp_summary_in_tree = TRUE;
static gboolean tcp_summary_in_tree = TRUE;
extern FILE* data_out_file;
@ -434,6 +435,11 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
guint optlen;
guint32 seglen;
guint32 nxtseq;
guint len;
guint reported_len;
vec_t cksum_vec[4];
guint32 phdr[2];
guint16 computed_cksum;
guint length_remaining;
CHECK_DISPLAY_AS_DATA(proto_tcp, tvb, pinfo, tree);
@ -478,8 +484,11 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
hlen = hi_nibble(th.th_off_x2) * 4; /* TCP header length, in bytes */
reported_len = tvb_reported_length(tvb);
len = tvb_length(tvb);
/* Compute the length of data in this segment. */
seglen = tvb_reported_length(tvb) - hlen;
seglen = reported_len - hlen;
/* Compute the sequence number of next octet after this segment. */
nxtseq = th.th_seq + seglen;
@ -496,7 +505,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
if (tree) {
if (g_tcp_summary_in_tree) {
if (tcp_summary_in_tree) {
ti = proto_tree_add_protocol_format(tree, proto_tcp, tvb, offset, hlen, "Transmission Control Protocol, Src Port: %s (%u), Dst Port: %s (%u), Seq: %u, Ack: %u", get_tcp_port(th.th_sport), th.th_sport, get_tcp_port(th.th_dport), th.th_dport, th.th_seq, th.th_ack);
}
else {
@ -528,7 +537,52 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_boolean(field_tree, hf_tcp_flags_syn, tvb, offset + 13, 1, th.th_flags);
proto_tree_add_boolean(field_tree, hf_tcp_flags_fin, tvb, offset + 13, 1, th.th_flags);
proto_tree_add_uint(tcp_tree, hf_tcp_window_size, tvb, offset + 14, 2, th.th_win);
proto_tree_add_uint(tcp_tree, hf_tcp_checksum, tvb, offset + 16, 2, th.th_sum);
if (!pinfo->fragmented && len >= reported_len) {
/* The packet isn't part of a fragmented datagram and isn't
truncated, so we can checksum it.
XXX - make a bigger scatter-gather list once we do fragment
reassembly? */
/* Set up the fields of the pseudo-header. */
cksum_vec[0].ptr = pinfo->src.data;
cksum_vec[0].len = pinfo->src.len;
cksum_vec[1].ptr = pinfo->dst.data;
cksum_vec[1].len = pinfo->dst.len;
cksum_vec[2].ptr = (const guint8 *)&phdr;
switch (pinfo->src.type) {
case AT_IPv4:
phdr[0] = htonl((IP_PROTO_TCP<<16) + reported_len);
cksum_vec[2].len = 4;
break;
case AT_IPv6:
phdr[0] = htonl(reported_len);
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 = tvb_get_ptr(tvb, offset, len);
cksum_vec[3].len = reported_len;
computed_cksum = in_cksum(&cksum_vec[0], 4);
if (computed_cksum == 0) {
proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, tvb,
offset + 16, 2, th.th_sum, "Checksum: 0x%04x (correct)", th.th_sum);
} else {
proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, tvb,
offset + 16, 2, th.th_sum,
"Checksum: 0x%04x (incorrect, should be 0x%04x)", th.th_sum,
in_cksum_shouldbe(th.th_sum, computed_cksum));
}
} else {
proto_tree_add_uint_format(tcp_tree, hf_tcp_checksum, tvb,
offset + 16, 2, th.th_sum, "Checksum: 0x%04x", th.th_sum);
}
if (th.th_flags & TH_URG)
proto_tree_add_uint(tcp_tree, hf_tcp_urgent_pointer, tvb, offset + 18, 2, th.th_urp);
}
@ -689,12 +743,12 @@ proto_register_tcp(void)
subdissector_table = register_dissector_table("tcp.port");
register_heur_dissector_list("tcp", &heur_subdissector_list);
/* Register a configuration preferences */
/* Register configuration preferences */
tcp_module = prefs_register_module("tcp", "TCP", NULL);
prefs_register_bool_preference(tcp_module, "tcp_summary_in_tree",
"Show TCP summary in protocol tree",
"Whether the TCP summary line should be shown in the protocol tree",
&g_tcp_summary_in_tree);
&tcp_summary_in_tree);
}
void

View File

@ -1,7 +1,7 @@
/* packet-udp.c
* Routines for UDP packet disassembly
*
* $Id: packet-udp.c,v 1.79 2000/11/19 08:54:10 guy Exp $
* $Id: packet-udp.c,v 1.80 2000/12/13 02:24:21 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -44,6 +44,7 @@
#include <glib.h>
#include "globals.h"
#include "resolv.h"
#include "in_cksum.h"
#include "plugins.h"
#include "packet-udp.h"
@ -144,6 +145,11 @@ dissect_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
guint16 uh_sport, uh_dport, uh_ulen, uh_sum;
proto_tree *udp_tree;
proto_item *ti;
guint len;
guint reported_len;
vec_t cksum_vec[4];
guint32 phdr[2];
guint16 computed_cksum;
int offset = 0;
CHECK_DISPLAY_AS_DATA(proto_udp, tvb, pinfo, tree);
@ -176,8 +182,58 @@ dissect_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_uint_hidden(udp_tree, hf_udp_port, tvb, offset+2, 2, uh_dport);
proto_tree_add_uint(udp_tree, hf_udp_length, tvb, offset + 4, 2, uh_ulen);
proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb, offset + 6, 2, uh_sum,
"Checksum: 0x%04x", uh_sum);
reported_len = tvb_reported_length(tvb);
len = tvb_length(tvb);
if (uh_sum == 0) {
/* No checksum supplied in the packet. */
proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb,
offset + 6, 2, uh_sum, "Checksum: 0x%04x (none)", uh_sum);
} else if (!pinfo->fragmented && len >= reported_len) {
/* The packet isn't part of a fragmented datagram and isn't
truncated, so we can checksum it.
XXX - make a bigger scatter-gather list once we do fragment
reassembly? */
/* Set up the fields of the pseudo-header. */
cksum_vec[0].ptr = pinfo->src.data;
cksum_vec[0].len = pinfo->src.len;
cksum_vec[1].ptr = pinfo->dst.data;
cksum_vec[1].len = pinfo->dst.len;
cksum_vec[2].ptr = (const guint8 *)&phdr;
switch (pinfo->src.type) {
case AT_IPv4:
phdr[0] = htonl((IP_PROTO_UDP<<16) + reported_len);
cksum_vec[2].len = 4;
break;
case AT_IPv6:
phdr[0] = htonl(reported_len);
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 = tvb_get_ptr(tvb, offset, len);
cksum_vec[3].len = reported_len;
computed_cksum = in_cksum(&cksum_vec[0], 4);
if (computed_cksum == 0) {
proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb,
offset + 6, 2, uh_sum, "Checksum: 0x%04x (correct)", uh_sum);
} else {
proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb,
offset + 6, 2, uh_sum,
"Checksum: 0x%04x (incorrect, should be 0x%04x)", uh_sum,
in_cksum_shouldbe(uh_sum, computed_cksum));
}
} else {
proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb,
offset + 6, 2, uh_sum, "Checksum: 0x%04x", uh_sum);
}
}
/* Skip over header */