Ethereal-dev: [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: Markus Stenberg <mstenber@xxxxxxxxxxxxxx>
Date: 10 May 2000 14:21:38 +0300
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).

diff -w -u ethereal-0.8.8/packet-ip.c ethereal-0.8.8-custom/packet-ip.c
--- ethereal-0.8.8/packet-ip.c	Tue May  9 06:15:24 2000
+++ ethereal-0.8.8-custom/packet-ip.c	Wed May 10 14:17:06 2000
@@ -803,28 +803,44 @@
   "Not set"
 };
 
-static char *ip_checksum_state(e_ip *iph)
+unsigned long ip_checksum(unsigned char *start,
+                          unsigned char *ptrEnd)
 {
-    unsigned long Sum;
-    unsigned char *Ptr, *PtrEnd;
+    unsigned char *ptr;
+    unsigned long Sum = 0;
     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);
+    for (ptr = start ; ptr < ptrEnd; ptr += 2) {
+	memcpy(&word, ptr, sizeof word);
         Sum += word;
     }
+    return Sum;
+}
 
+int ip_checksum_verify(unsigned long Sum)
+{
     Sum = (Sum & 0xFFFF) + (Sum >> 16);
     Sum = (Sum & 0xFFFF) + (Sum >> 16);
 
-    if (Sum != 0xffff)
+    return Sum == 0xffff;
+}
+
+static char *ip_checksum_state(e_ip *iph)
+{
+    unsigned long Sum;
+    unsigned char *ptrEnd;
+
+    ptrEnd = (lo_nibble(iph->ip_v_hl) * 4 + (char *)iph);
+    Sum = ip_checksum((unsigned char *) iph, ptrEnd);
+
+    if (!ip_checksum_verify(Sum))
         return "incorrect";
 
     return "correct";
 }
 
+char global_ugly_hack_buf[12];
+
 void
 dissect_ip(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
   e_ip       iph;
@@ -935,6 +951,10 @@
         "Header checksum: 0x%04x (%s)", iph.ip_sum, ip_checksum_state((e_ip*) &pd[offset]));
     proto_tree_add_item(ip_tree, hf_ip_src, offset + 12, 4, iph.ip_src);
     proto_tree_add_item(ip_tree, hf_ip_dst, offset + 16, 4, iph.ip_dst);
+    memcpy(global_ugly_hack_buf, &iph.ip_src, 4);
+    memcpy(global_ugly_hack_buf+4, &iph.ip_dst, 4);
+    global_ugly_hack_buf[8] = 0;
+    global_ugly_hack_buf[9] = iph.ip_p;
     proto_tree_add_item_hidden(ip_tree, hf_ip_addr, offset + 12, 4, iph.ip_src);
     proto_tree_add_item_hidden(ip_tree, hf_ip_addr, offset + 16, 4, iph.ip_dst);
 
diff -w -u ethereal-0.8.8/packet-udp.c ethereal-0.8.8-custom/packet-udp.c
--- ethereal-0.8.8/packet-udp.c	Tue May  9 06:15:24 2000
+++ ethereal-0.8.8-custom/packet-udp.c	Wed May 10 14:19:18 2000
@@ -139,6 +139,28 @@
     dissect_data(pd, offset, fd, tree);
 }
 
+extern char global_ugly_hack_buf[12];
+
+unsigned long ip_checksum(unsigned char *start,
+                          unsigned char *ptrEnd);
+
+int ip_checksum_verify(unsigned long Sum);
+
+const char *udp_checksum(const u_char *pd, int offset, frame_data *fd,
+                         e_udphdr uh)
+{
+  unsigned long cks1, cks2;
+
+  memcpy(global_ugly_hack_buf + 10, &uh.uh_ulen, 2);
+  /* Now we have valid pseudo header (hopefully).
+     Next step is calculating the actual checksum of the whole body of message,
+     and that is somewhat painful */
+  cks1 = ip_checksum(global_ugly_hack_buf, global_ugly_hack_buf+12);
+  cks2 = ip_checksum(pd+offset, pd+fd->pkt_len);
+  if (!ip_checksum_verify(cks1+cks2))
+    return "INCORRECT!!!";
+  return "correct";
+}
 
 static void
 dissect_udp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
@@ -146,7 +168,7 @@
   guint16    uh_sport, uh_dport, uh_ulen, uh_sum;
   proto_tree *udp_tree;
   proto_item *ti;
-
+  const char *checksum_str;
   if (!BYTES_ARE_IN_FRAME(offset, sizeof(e_udphdr))) {
     dissect_data(pd, offset, fd, tree);
     return;
@@ -159,11 +181,15 @@
   uh_ulen  = ntohs(uh.uh_ulen);
   uh_sum   = ntohs(uh.uh_sum);
   
+  checksum_str = udp_checksum(pd, offset, fd, uh);
+
   if (check_col(fd, COL_PROTOCOL))
     col_add_str(fd, COL_PROTOCOL, "UDP");
   if (check_col(fd, COL_INFO))
-    col_add_fstr(fd, COL_INFO, "Source port: %s  Destination port: %s",
-	    get_udp_port(uh_sport), get_udp_port(uh_dport));
+    col_add_fstr(fd, COL_INFO, "Source port: %s  Destination port: %s  Checksum: %s",
+	    get_udp_port(uh_sport), get_udp_port(uh_dport),
+                 checksum_str
+                 );
     
   if (tree) {
     ti = proto_tree_add_item(tree, proto_udp, offset, 8);
@@ -179,7 +205,7 @@
 
     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);
+	"Checksum: 0x%04x (%s)", uh_sum, checksum_str);
   }
 
   /* Skip over header */


-- 
"...Unix, MS-DOS, and Windows NT (also known as the Good, the Bad, and
the Ugly)."
	- Matt Welsh