Diff for /embedaddon/libnet/src/libnet_checksum.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2012/02/21 22:14:23 version 1.1.1.2, 2013/07/22 11:54:42
Line 38 Line 38
 #else  #else
 #include "../include/win32/libnet.h"  #include "../include/win32/libnet.h"
 #endif  #endif
   
   /* FIXME - unit test these - 0 is debian's version, else is -RC1's */
   /* Note about aliasing warning:
    *
    *   http://mail.opensolaris.org/pipermail/tools-gcc/2005-August/000047.html
    *
    * See RFC 1071, and:
    *
    *   http://mathforum.org/library/drmath/view/54379.html
    */
   #undef DEBIAN
   /* Note: len is in bytes, not 16-bit words! */
 int  int
libnet_in_cksum(u_int16_t *addr, int len)libnet_in_cksum(uint16_t *addr, int len)
 {  {
     int sum;      int sum;
   #ifdef DEBIAN
       uint16_t last_byte;
   
     sum = 0;      sum = 0;
       last_byte = 0;
   #else
       union
       {
           uint16_t s;
           uint8_t b[2];
       }pad;
   
       sum = 0;
   #endif
   
     while (len > 1)      while (len > 1)
     {      {
         sum += *addr++;          sum += *addr++;
         len -= 2;          len -= 2;
     }      }
   #ifdef DEBIAN
     if (len == 1)      if (len == 1)
     {      {
        sum += *(u_int16_t *)addr;        *(uint8_t *)&last_byte = *(uint8_t *)addr;
         sum += last_byte;
 #else
     if (len == 1)
     {
         pad.b[0] = *(uint8_t *)addr;
         pad.b[1] = 0;
         sum += pad.s;
 #endif
     }      }
   
     return (sum);      return (sum);
Line 95  libnet_toggle_checksum(libnet_t *l, libnet_ptag_t ptag Line 128  libnet_toggle_checksum(libnet_t *l, libnet_ptag_t ptag
     }      }
 }  }
   
   static int check_ip_payload_size(libnet_t*l, const uint8_t *iphdr, int ip_hl, int h_len, const uint8_t * end, const char* func)
   {
       if((iphdr+ip_hl+h_len) > end)
       {
           snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                   "%s(): ip payload not inside packet (pktsz %d, iphsz %d, payloadsz %d)\n", func,
                   (int)(end - iphdr), ip_hl, h_len);
           return -1;
       }
   
       return 0;
   }
   
   
   /*
    * For backwards binary compatibility. The calculations done here can easily
    * result in buffer overreads and overwrites. You have been warned. And no, it
    * is not possible to fix, the API contains no information on the buffer's
    * boundary. libnet itself calls the safe function, libnet_inet_checksum(). So
    * should you.
    */
 int  int
libnet_do_checksum(libnet_t *l, u_int8_t *buf, int protocol, int len)libnet_do_checksum(libnet_t *l, uint8_t *iphdr, int protocol, int h_len)
 {  {
    /* will need to update this for ipv6 at some point */    uint16_t ip_len = 0;
    struct libnet_ipv4_hdr *iph_p;    struct libnet_ipv4_hdr* ip4 = (struct libnet_ipv4_hdr *)iphdr;
    struct libnet_ipv6_hdr *ip6h_p;    struct libnet_ipv6_hdr* ip6 = (struct libnet_ipv6_hdr *)iphdr;
    int is_ipv6; 
    int ip_hl; 
    int sum; 
   
    is_ipv6 = 0;    /* default to not using IPv6 */    if(ip4->ip_v == 6) {
    sum     = 0;        ip_len = ntohs(ip6->ip_len);
    iph_p   = NULL;    } else {
    ip6h_p  = NULL;        ip_len = ntohs(ip4->ip_len);
     }
   
    if (len == 0)    return libnet_inet_checksum(l, iphdr, protocol, h_len,
             iphdr, iphdr + ip_len
             );
 }
 
 
 #define CHECK_IP_PAYLOAD_SIZE() do { \
     int e=check_ip_payload_size(l,iphdr,ip_hl, h_len, end, __func__);\
     if(e) return e;\
 } while(0)
 
 
 /*
  * We are checksumming pblock "q"
  *
  * iphdr is the pointer to it's encapsulating IP header
  * protocol describes the type of "q", expressed as an IPPROTO_ value
  * h_len is the h_len from "q"
  */
 int
 libnet_inet_checksum(libnet_t *l, uint8_t *iphdr, int protocol, int h_len, const uint8_t *beg, const uint8_t * end)
 {
     /* will need to update this for ipv6 at some point */
     struct libnet_ipv4_hdr *iph_p = (struct libnet_ipv4_hdr *)iphdr;
     struct libnet_ipv6_hdr *ip6h_p = NULL; /* default to not using IPv6 */
     int ip_hl   = 0;
     int sum     = 0;
 
     /* Check for memory under/over reads/writes. */
     if(iphdr < beg || (iphdr+sizeof(*iph_p)) > end)
     {      {
         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,          snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
            "%s(): header length can't be zero\n", __func__);            "%s(): ipv4 hdr not inside packet (where %d, size %d)\n", __func__,
        return (-1);            (int)(iphdr-beg), (int)(end-beg));
         return -1;
     }      }
   
     /*      /*
      *  Figure out which IP version we're dealing with.  We'll assume v4       *  Figure out which IP version we're dealing with.  We'll assume v4
      *  and overlay a header structure to yank out the version.       *  and overlay a header structure to yank out the version.
      */       */
    iph_p = (struct libnet_ipv4_hdr *)buf;    if (iph_p->ip_v == 6)
    if (iph_p && iph_p->ip_v == 6) 
     {      {
        ip6h_p = (struct libnet_ipv6_hdr *)buf;        ip6h_p = (struct libnet_ipv6_hdr *)iph_p;
        is_ipv6 = 1;        iph_p = NULL;
         ip_hl   = 40;          ip_hl   = 40;
           if((uint8_t*)(ip6h_p+1) > end)
           {
               snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                       "%s(): ipv6 hdr not inside packet\n", __func__);
               return -1;
           }
     }      }
     else      else
     {      {
         is_ipv6 = 0;  
         ip_hl = iph_p->ip_hl << 2;          ip_hl = iph_p->ip_hl << 2;
     }      }
   
       if((iphdr+ip_hl) > end)
       {
           snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
               "%s(): ip hdr len not inside packet\n", __func__);
           return -1;
       }
   
     /*      /*
      *  Dug Song came up with this very cool checksuming implementation       *  Dug Song came up with this very cool checksuming implementation
      *  eliminating the need for explicit psuedoheader use.  Check it out.       *  eliminating the need for explicit psuedoheader use.  Check it out.
      */       */
     switch (protocol)      switch (protocol)
     {      {
         /*  
          *  Style note: normally I don't advocate declaring variables inside  
          *  blocks of control, but it makes good sense here. -- MDS  
          */  
         case IPPROTO_TCP:          case IPPROTO_TCP:
         {          {
             struct libnet_tcp_hdr *tcph_p =              struct libnet_tcp_hdr *tcph_p =
                (struct libnet_tcp_hdr *)(buf + ip_hl);                (struct libnet_tcp_hdr *)(iphdr + ip_hl);
   
               h_len = end - (uint8_t*) tcph_p; /* ignore h_len, sum the packet we've coalesced */
   
               CHECK_IP_PAYLOAD_SIZE();
   
 #if (STUPID_SOLARIS_CHECKSUM_BUG)  #if (STUPID_SOLARIS_CHECKSUM_BUG)
             tcph_p->th_sum = tcph_p->th_off << 2;              tcph_p->th_sum = tcph_p->th_off << 2;
             return (1);              return (1);
Line 162  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro Line 254  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
                  *  the size of the TCP payload (only for raw sockets).                   *  the size of the TCP payload (only for raw sockets).
                  */                   */
                 tcph_p->th_sum = (tcph_p->th_off << 2) +                  tcph_p->th_sum = (tcph_p->th_off << 2) +
                        (len - (tcph_p->th_off << 2));                        (h_len - (tcph_p->th_off << 2));
                 return (1);                   return (1); 
             }              }
 #endif  #endif
               /* TCP checksum is over the IP pseudo header:
                * ip src
                * ip dst
                * tcp protocol (IPPROTO_TCP)
                * tcp length, including the header
                * + the TCP header (with checksum set to zero) and data
                */
             tcph_p->th_sum = 0;              tcph_p->th_sum = 0;
            if (is_ipv6)            if (ip6h_p)
             {              {
                sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);                sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32);
             }              }
             else              else
             {              {
                sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);                /* 8 = src and dst */
                 sum = libnet_in_cksum((uint16_t *)&iph_p->ip_src, 8);
             }              }
            sum += ntohs(IPPROTO_TCP + len);            sum += ntohs(IPPROTO_TCP + h_len);
            sum += libnet_in_cksum((u_int16_t *)tcph_p, len);            sum += libnet_in_cksum((uint16_t *)tcph_p, h_len);
             tcph_p->th_sum = LIBNET_CKSUM_CARRY(sum);              tcph_p->th_sum = LIBNET_CKSUM_CARRY(sum);
   #if 0
               printf("tcp sum calculated: %#x/%d h_len %d\n",
                       ntohs(tcph_p->th_sum),
                       ntohs(tcph_p->th_sum),
                       h_len
                     );
   #endif
             break;              break;
         }          }
         case IPPROTO_UDP:          case IPPROTO_UDP:
         {          {
             struct libnet_udp_hdr *udph_p =              struct libnet_udp_hdr *udph_p =
                (struct libnet_udp_hdr *)(buf + ip_hl);                (struct libnet_udp_hdr *)(iphdr + ip_hl);
 
             h_len = end - (uint8_t*) udph_p; /* ignore h_len, sum the packet we've coalesced */
 
             CHECK_IP_PAYLOAD_SIZE();
 
             udph_p->uh_sum = 0;              udph_p->uh_sum = 0;
            if (is_ipv6)            if (ip6h_p)
             {              {
                sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);                sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32);
             }              }
             else              else
             {              {
                sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);                sum = libnet_in_cksum((uint16_t *)&iph_p->ip_src, 8);
             }              }
            sum += ntohs(IPPROTO_UDP + len);            sum += ntohs(IPPROTO_UDP + h_len);
            sum += libnet_in_cksum((u_int16_t *)udph_p, len);            sum += libnet_in_cksum((uint16_t *)udph_p, h_len);
             udph_p->uh_sum = LIBNET_CKSUM_CARRY(sum);              udph_p->uh_sum = LIBNET_CKSUM_CARRY(sum);
             break;              break;
         }          }
         case IPPROTO_ICMP:          case IPPROTO_ICMP:
         {          {
             struct libnet_icmpv4_hdr *icmph_p =              struct libnet_icmpv4_hdr *icmph_p =
                (struct libnet_icmpv4_hdr *)(buf + ip_hl);                (struct libnet_icmpv4_hdr *)(iphdr + ip_hl);
   
               h_len = end - (uint8_t*) icmph_p; /* ignore h_len, sum the packet we've coalesced */
   
               CHECK_IP_PAYLOAD_SIZE();
   
             icmph_p->icmp_sum = 0;              icmph_p->icmp_sum = 0;
            if (is_ipv6)            /* Hm, is this valid? Is the checksum algorithm for ICMPv6 encapsulated in IPv4
              * actually defined?
              */
             if (ip6h_p)
             {              {
                sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);                sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32);
                sum += ntohs(IPPROTO_ICMP6 + len);                sum += ntohs(IPPROTO_ICMP6 + h_len);
             }              }
            sum += libnet_in_cksum((u_int16_t *)icmph_p, len);            sum += libnet_in_cksum((uint16_t *)icmph_p, h_len);
             icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum);              icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum);
             break;              break;
         }          }
           case IPPROTO_ICMPV6:
           {
               struct libnet_icmpv6_hdr *icmph_p =
                   (struct libnet_icmpv6_hdr *)(iphdr + ip_hl);
   
               h_len = end - (uint8_t*) icmph_p; /* ignore h_len, sum the packet we've coalesced */
   
               CHECK_IP_PAYLOAD_SIZE();
   
               icmph_p->icmp_sum = 0;
               if (ip6h_p)
               {
                   sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32);
                   sum += ntohs(IPPROTO_ICMP6 + h_len);
               }
               sum += libnet_in_cksum((uint16_t *)icmph_p, h_len);
               icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum);
               break;
           }
         case IPPROTO_IGMP:          case IPPROTO_IGMP:
         {          {
             struct libnet_igmp_hdr *igmph_p =              struct libnet_igmp_hdr *igmph_p =
                (struct libnet_igmp_hdr *)(buf + ip_hl);                (struct libnet_igmp_hdr *)(iphdr + ip_hl);
   
               h_len = end - (uint8_t*) igmph_p; /* ignore h_len, sum the packet we've coalesced */
   
               CHECK_IP_PAYLOAD_SIZE();
   
             igmph_p->igmp_sum = 0;              igmph_p->igmp_sum = 0;
            sum = libnet_in_cksum((u_int16_t *)igmph_p, len);            sum = libnet_in_cksum((uint16_t *)igmph_p, h_len);
             igmph_p->igmp_sum = LIBNET_CKSUM_CARRY(sum);              igmph_p->igmp_sum = LIBNET_CKSUM_CARRY(sum);
             break;              break;
         }          }
Line 229  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro Line 371  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
              * in the multiple RFC version of the protocol ... ouf !!!               * in the multiple RFC version of the protocol ... ouf !!!
              */               */
             struct libnet_gre_hdr *greh_p =               struct libnet_gre_hdr *greh_p = 
                (struct libnet_gre_hdr *)(buf + ip_hl);                (struct libnet_gre_hdr *)(iphdr + ip_hl);
            u_int16_t fv = ntohs(greh_p->flags_ver);            uint16_t fv = ntohs(greh_p->flags_ver);
 
             CHECK_IP_PAYLOAD_SIZE();
 
             if (!(fv & (GRE_CSUM|GRE_ROUTING | GRE_VERSION_0)) ||              if (!(fv & (GRE_CSUM|GRE_ROUTING | GRE_VERSION_0)) ||
                 !(fv & (GRE_CSUM|GRE_VERSION_1)))                  !(fv & (GRE_CSUM|GRE_VERSION_1)))
             {              {
Line 238  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro Line 383  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
                 "%s(): can't compute GRE checksum (wrong flags_ver bits: 0x%x )\n",  __func__, fv);                  "%s(): can't compute GRE checksum (wrong flags_ver bits: 0x%x )\n",  __func__, fv);
                 return (-1);                  return (-1);
             }              }
            sum = libnet_in_cksum((u_int16_t *)greh_p, len);            sum = libnet_in_cksum((uint16_t *)greh_p, h_len);
             greh_p->gre_sum = LIBNET_CKSUM_CARRY(sum);              greh_p->gre_sum = LIBNET_CKSUM_CARRY(sum);
             break;              break;
         }          }
         case IPPROTO_OSPF:          case IPPROTO_OSPF:
         {          {
             struct libnet_ospf_hdr *oh_p =              struct libnet_ospf_hdr *oh_p =
                (struct libnet_ospf_hdr *)(buf + ip_hl);                (struct libnet_ospf_hdr *)(iphdr + ip_hl);
   
               CHECK_IP_PAYLOAD_SIZE();
   
             oh_p->ospf_sum = 0;              oh_p->ospf_sum = 0;
            sum += libnet_in_cksum((u_int16_t *)oh_p, len);            sum += libnet_in_cksum((uint16_t *)oh_p, h_len);
             oh_p->ospf_sum = LIBNET_CKSUM_CARRY(sum);              oh_p->ospf_sum = LIBNET_CKSUM_CARRY(sum);
             break;              break;
         }          }
         case IPPROTO_OSPF_LSA:          case IPPROTO_OSPF_LSA:
         {          {
             struct libnet_ospf_hdr *oh_p =              struct libnet_ospf_hdr *oh_p =
                (struct libnet_ospf_hdr *)(buf + ip_hl);                (struct libnet_ospf_hdr *)(iphdr + ip_hl);
             struct libnet_lsa_hdr *lsa_p =              struct libnet_lsa_hdr *lsa_p =
                (struct libnet_lsa_hdr *)(buf +                 (struct libnet_lsa_hdr *)(iphdr + 
                 ip_hl + oh_p->ospf_len);                  ip_hl + oh_p->ospf_len);
   
               /* FIXME need additional length check, to account for ospf_len */
             lsa_p->lsa_sum = 0;              lsa_p->lsa_sum = 0;
            sum += libnet_in_cksum((u_int16_t *)lsa_p, len);            sum += libnet_in_cksum((uint16_t *)lsa_p, h_len);
             lsa_p->lsa_sum = LIBNET_CKSUM_CARRY(sum);              lsa_p->lsa_sum = LIBNET_CKSUM_CARRY(sum);
             break;              break;
 #if 0  #if 0
Line 270  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro Line 418  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
              */               */
             int c0, c1;              int c0, c1;
             struct libnet_lsa_hdr *lsa_p = (struct libnet_lsa_hdr *)buf;              struct libnet_lsa_hdr *lsa_p = (struct libnet_lsa_hdr *)buf;
            u_int8_t *p, *p1, *p2, *p3;            uint8_t *p, *p1, *p2, *p3;
   
             c0 = 0;              c0 = 0;
             c1 = 0;              c1 = 0;
Line 319  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro Line 467  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
         }          }
         case IPPROTO_IP:          case IPPROTO_IP:
         {          {
            iph_p->ip_sum = 0;            if(!iph_p) {
            sum = libnet_in_cksum((u_int16_t *)iph_p, ip_hl);                /* IPv6 doesn't have a checksum */
            iph_p->ip_sum = LIBNET_CKSUM_CARRY(sum);            } else {
                 iph_p->ip_sum = 0;
                 sum = libnet_in_cksum((uint16_t *)iph_p, ip_hl);
                 iph_p->ip_sum = LIBNET_CKSUM_CARRY(sum);
             }
             break;              break;
         }          }
         case IPPROTO_VRRP:          case IPPROTO_VRRP:
         {          {
             struct libnet_vrrp_hdr *vrrph_p =              struct libnet_vrrp_hdr *vrrph_p =
                (struct libnet_vrrp_hdr *)(buf + ip_hl);                (struct libnet_vrrp_hdr *)(iphdr + ip_hl);
             CHECK_IP_PAYLOAD_SIZE();
   
             vrrph_p->vrrp_sum = 0;              vrrph_p->vrrp_sum = 0;
            sum = libnet_in_cksum((u_int16_t *)vrrph_p, len);            sum = libnet_in_cksum((uint16_t *)vrrph_p, h_len);
             vrrph_p->vrrp_sum = LIBNET_CKSUM_CARRY(sum);              vrrph_p->vrrp_sum = LIBNET_CKSUM_CARRY(sum);
             break;              break;
         }          }
         case LIBNET_PROTO_CDP:          case LIBNET_PROTO_CDP:
         {   /* XXX - Broken: how can we easily get the entire packet size? */          {   /* XXX - Broken: how can we easily get the entire packet size? */
               /* FIXME you can't, checksumming non-IP protocols was not supported by libnet */
             struct libnet_cdp_hdr *cdph_p =              struct libnet_cdp_hdr *cdph_p =
                (struct libnet_cdp_hdr *)buf;                (struct libnet_cdp_hdr *)iphdr;
   
               if((iphdr+h_len) > end)
               {
                   snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                           "%s(): cdp payload not inside packet\n", __func__);
                   return -1;
               }
   
             cdph_p->cdp_sum = 0;              cdph_p->cdp_sum = 0;
            sum = libnet_in_cksum((u_int16_t *)cdph_p, len);            sum = libnet_in_cksum((uint16_t *)cdph_p, h_len);
             cdph_p->cdp_sum = LIBNET_CKSUM_CARRY(sum);              cdph_p->cdp_sum = LIBNET_CKSUM_CARRY(sum);
             break;              break;
         }          }
         case LIBNET_PROTO_ISL:          case LIBNET_PROTO_ISL:
         {          {
           // struct libnet_isl_hdr *islh_p =#if 0
           //     (struct libnet_isl_hdr *)buf;            struct libnet_isl_hdr *islh_p =
                 (struct libnet_isl_hdr *)buf;
 #endif
             /*              /*
              *  Need to compute 4 byte CRC for the ethernet frame and for               *  Need to compute 4 byte CRC for the ethernet frame and for
              *  the ISL frame itself.  Use the libnet_crc function.               *  the ISL frame itself.  Use the libnet_crc function.
Line 356  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro Line 519  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
         default:          default:
         {          {
             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,              snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                "%s(): unsuported protocol %d\n", __func__, protocol);                "%s(): unsupported protocol %d\n", __func__, protocol);
             return (-1);              return (-1);
         }          }
     }      }
Line 364  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro Line 527  libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
 }  }
   
   
u_int16_tuint16_t
libnet_ip_check(u_int16_t *addr, int len)libnet_ip_check(uint16_t *addr, int len)
 {  {
     int sum;      int sum;
   

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>