Nmap Development mailing list archives

[PATCH] Consolidate TCP/UDP checksum code


From: Kris Katterjohn <katterjohn () gmail com>
Date: Sun, 10 Dec 2006 18:50:52 -0600

This adds a magic_tcpudp_cksum() function to handle the pseudo-header
checksum stuff for TCP and UDP packets instead of doing the same thing 4
different times across multiple files/functions.

Judging by tcpdump output, all checksums come out correct.

It's a diff against 4.20

Thanks,
Kris Katterjohn
--- x/osscan.cc 2006-12-07 21:01:19.000000000 -0600
+++ y/osscan.cc 2006-12-10 18:15:41.000000000 -0600
@@ -139,13 +139,6 @@ unsigned char *data = packet + 28;
 unsigned short realcheck; /* the REAL checksum */
 int res;
 int decoy;
-struct pseudo_udp_hdr {
-  struct in_addr source;
-  struct in_addr dest;        
-  u8 zero;
-  u8 proto;        
-  u16 length;
-} *pseudo = (struct pseudo_udp_hdr *) ((char *)udp - 12) ;
 
 if (!patternbyte) patternbyte = (get_random_uint() % 60) + 65;
 memset(data, patternbyte, datalen);
@@ -169,15 +162,9 @@ for(decoy=0; decoy < o.numdecoys; decoy+
   udp->uh_dport = htons(dport);
   udp->uh_ulen = htons(8 + datalen);
 
-  /* Now the pseudo header for checksuming */
-  pseudo->source.s_addr = source->s_addr;
-  pseudo->dest.s_addr = victim->s_addr;
-  pseudo->proto = IPPROTO_UDP;
-  pseudo->length = htons(sizeof(udphdr_bsd) + datalen);
-  
   /* OK, now we should be able to compute a valid checksum */
-  realcheck = in_cksum((unsigned short *)pseudo, 20 /* pseudo + UDP headers */ +
-                      datalen);
+  realcheck = magic_tcpudp_cksum(source, victim, IPPROTO_UDP,
+                                sizeof(udphdr_bsd) + datalen, (char *) udp);
 #if STUPID_SOLARIS_CHECKSUM_BUG
   udp->uh_sum = sizeof(udphdr_bsd) + datalen;
 #else
@@ -187,9 +174,6 @@ for(decoy=0; decoy < o.numdecoys; decoy+
   if ( o.badsum )
     udp->uh_sum++;
 
-  /* Goodbye, pseudo header! */
-  memset(pseudo, 0, sizeof(*pseudo));
-  
   /* Now for the ip header */
   ip->ip_v = 4;
   ip->ip_hl = 5;

--- x/osscan2.cc        2006-12-07 20:11:08.000000000 -0600
+++ y/osscan2.cc        2006-12-10 18:15:56.000000000 -0600
@@ -3009,13 +3009,6 @@ int send_closedudp_probe_2(struct udppro
   unsigned short realcheck; /* the REAL checksum */
   int res;
   int decoy;
-  struct pseudo_udp_hdr {
-    struct in_addr source;
-    struct in_addr dest;        
-    u8 zero;
-    u8 proto;        
-    u16 length;
-  } *pseudo = (struct pseudo_udp_hdr *) ((char *)udp - 12) ;
 
   /* if (!patternbyte) patternbyte = (get_random_uint() % 60) + 65; */
   memset(data, patternbyte, datalen);
@@ -3043,24 +3036,15 @@ int send_closedudp_probe_2(struct udppro
     udp->uh_dport = htons(dport);
     udp->uh_ulen = htons(8 + datalen);
 
-    /* Now the psuedo header for checksuming */
-    pseudo->source.s_addr = source->s_addr;
-    pseudo->dest.s_addr = victim->s_addr;
-    pseudo->proto = IPPROTO_UDP;
-    pseudo->length = htons(sizeof(udphdr_bsd) + datalen);
-  
     /* OK, now we should be able to compute a valid checksum */
-    realcheck = in_cksum((unsigned short *)pseudo, 20 /* pseudo + UDP headers */ +
-                         datalen);
+    realcheck = magic_tcpudp_cksum(source, victim, IPPROTO_UDP,
+                                  sizeof(udphdr_bsd) + datalen, (char *) udp);
 #if STUPID_SOLARIS_CHECKSUM_BUG
     udp->uh_sum = sizeof(udphdr_bsd) + datalen;
 #else
     udp->uh_sum = realcheck;
 #endif
 
-    /* Goodbye, pseudo header! */
-    memset(pseudo, 0, sizeof(*pseudo));
-  
     /* Now for the ip header */
     ip->ip_v = 4;
     ip->ip_hl = 5;

--- x/tcpip.cc  2006-12-07 21:01:19.000000000 -0600
+++ y/tcpip.cc  2006-12-10 18:21:00.000000000 -0600
@@ -957,6 +957,28 @@ answer = ~sum;          /* ones-compleme
 return(answer);
 }
 
+/* for computing TCP/UDP checksums, see TCP/IP Illustrated p. 145 */
+unsigned short magic_tcpudp_cksum(const struct in_addr *src,
+                                 const struct in_addr *dst,
+                                 u8 proto, u16 len, char *hstart)
+{
+       struct pseudo {
+               struct in_addr src;
+               struct in_addr dst;        
+               u8 zero;
+               u8 proto;        
+               u16 length;
+       } *hdr = (struct pseudo *) (hstart - sizeof(struct pseudo));
+
+       hdr->src = *src;
+       hdr->dst = *dst;
+       hdr->zero = 0;
+       hdr->proto = proto;
+       hdr->length = htons(len);
+
+       return in_cksum((unsigned short *) hdr, len + sizeof(struct pseudo));
+}
+
 /* LEGACY resolve() function that only supports IPv4 -- see IPv6 version
    above.  Tries to resolve given hostname and stores
    result in ip .  returns 0 if hostname cannot
@@ -1098,21 +1120,11 @@ u8 *build_tcp_raw(const struct in_addr *
                  u8 *tcpopt, int tcpoptlen,
                  char *data, u16 datalen, u32 *outpacketlen) {
 
-struct pseudo_header { 
-  /*for computing TCP checksum, see TCP/IP Illustrated p. 145 */
-  u32 s_addy;
-  u32 d_addr;
-  u8 zer0;
-  u8 protocol;
-  u16 length;
-};
 int packetlen = sizeof(struct ip) + ipoptlen + 
        sizeof(struct tcphdr) + tcpoptlen + datalen;
 u8 *packet = (u8 *) safe_malloc(packetlen);
 struct ip *ip = (struct ip *) packet;
 struct tcphdr *tcp = (struct tcphdr *) ((u8*)ip + sizeof(struct ip) + ipoptlen);
-struct pseudo_header *pseudo = 
-       (struct pseudo_header *) ((u8*)tcp - sizeof(struct pseudo_header));
 static int myttl = 0;
 
 assert(victim);
@@ -1130,12 +1142,6 @@ if (ttl == -1) {
   myttl = ttl;
 }
 
-pseudo->s_addy = source->s_addr;
-pseudo->d_addr = victim->s_addr;
-pseudo->zer0   = 0;
-pseudo->protocol = IPPROTO_TCP;
-pseudo->length = htons(sizeof(struct tcphdr) + tcpoptlen + datalen);
-
 /* Fill tcp header */
 memset(tcp, 0, sizeof(struct tcphdr));
 tcp->th_sport = htons(sport);
@@ -1174,8 +1180,9 @@ if (data && datalen)
 #if STUPID_SOLARIS_CHECKSUM_BUG
 tcp->th_sum = sizeof(struct tcphdr) + tcpoptlen + datalen; 
 #else
-tcp->th_sum = in_cksum((unsigned short *)pseudo, sizeof(struct tcphdr) + 
-                      tcpoptlen + sizeof(struct pseudo_header) + datalen);
+tcp->th_sum = magic_tcpudp_cksum(source, victim, IPPROTO_TCP,
+                                sizeof(struct tcphdr) + tcpoptlen + datalen,
+                                (char *) tcp);
 #endif
 
 if ( o.badsum )
@@ -1583,15 +1590,6 @@ u8 *build_udp_raw(struct in_addr *source
   udphdr_bsd *udp = (udphdr_bsd *) ((u8*)ip + sizeof(struct ip) + ipoptlen);
   static int myttl = 0;
   
-  struct pseudo_udp_hdr {
-    struct in_addr source;
-    struct in_addr dest;        
-    u8 zer0;
-    u8 proto;        
-    u16 length;
-  } *pseudo = (struct pseudo_udp_hdr *) ((u8 *)udp - sizeof(struct pseudo_udp_hdr));
-
-
   /* check that required fields are there and not too silly */
   assert(victim);
   assert(source);
@@ -1613,18 +1611,12 @@ u8 *build_udp_raw(struct in_addr *source
   if (data)
     memcpy((u8*)udp + sizeof(udphdr_bsd), data, datalen);
   
-  /* Now the pseudo header for checksuming */
-  pseudo->source.s_addr = source->s_addr;
-  pseudo->dest.s_addr = victim->s_addr;
-  pseudo->zer0  = 0;
-  pseudo->proto = IPPROTO_UDP;
-  pseudo->length = htons(sizeof(udphdr_bsd) + datalen);
-  
   /* OK, now we should be able to compute a valid checksum */
 #if STUPID_SOLARIS_CHECKSUM_BUG
   udp->uh_sum = sizeof(udphdr_bsd) + datalen;
 #else
-  udp->uh_sum = in_cksum((unsigned short *)pseudo, 20 /* pseudo + UDP headers */ + datalen);
+  udp->uh_sum = magic_tcpudp_cksum(source, victim, IPPROTO_UDP,
+                                  sizeof(udphdr_bsd) + datalen, (char *) udp);
 #endif
   
   if ( o.badsum )

--- x/tcpip.h   2006-11-20 01:56:52.000000000 -0600
+++ y/tcpip.h   2006-12-10 18:15:10.000000000 -0600
@@ -513,6 +513,10 @@ bool routethrough(const struct sockaddr_
 
 unsigned short in_cksum(u16 *ptr,int nbytes);
 
+unsigned short magic_tcpudp_cksum(const struct in_addr *src,
+                                 const struct in_addr *dst,
+                                 u8 proto, u16 len, char *hstart);
+
 /* Build and send a raw tcp packet.  If TTL is -1, a partially random
    (but likely large enough) one is chosen */
 int send_tcp_raw( int sd, struct eth_nfo *eth,


_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org

Current thread: