Annotation of embedaddon/libnet/src/libnet_checksum.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *  $Id: libnet_checksum.c,v 1.13 2004/03/01 20:26:12 mike Exp $
                      3:  *
                      4:  *  libnet
                      5:  *  libnet_checksum.c - checksum routines
                      6:  *
                      7:  *  Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
                      8:  *  All rights reserved.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     29:  * SUCH DAMAGE.
                     30:  *
                     31:  */
                     32: 
                     33: #if (HAVE_CONFIG_H)
                     34: #include "../include/config.h"
                     35: #endif
                     36: #if (!(_WIN32) || (__CYGWIN__)) 
                     37: #include "../include/libnet.h"
                     38: #else
                     39: #include "../include/win32/libnet.h"
                     40: #endif
                     41: int
                     42: libnet_in_cksum(u_int16_t *addr, int len)
                     43: {
                     44:     int sum;
                     45: 
                     46:     sum = 0;
                     47: 
                     48:     while (len > 1)
                     49:     {
                     50:         sum += *addr++;
                     51:         len -= 2;
                     52:     }
                     53:     if (len == 1)
                     54:     {
                     55:         sum += *(u_int16_t *)addr;
                     56:     }
                     57: 
                     58:     return (sum);
                     59: }
                     60: 
                     61: int
                     62: libnet_toggle_checksum(libnet_t *l, libnet_ptag_t ptag, int mode)
                     63: {
                     64:     libnet_pblock_t *p;
                     65: 
                     66:     p = libnet_pblock_find(l, ptag);
                     67:     if (p == NULL)
                     68:     {
                     69:         /* err msg set in libnet_pblock_find() */
                     70:         return (-1);
                     71:     }
                     72:     if (mode == LIBNET_ON)
                     73:     {
                     74:         if ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
                     75:         {
                     76:             return (1);
                     77:         }
                     78:         else
                     79:         {
                     80:             (p->flags) |= LIBNET_PBLOCK_DO_CHECKSUM;
                     81:             return (1);
                     82:         }
                     83:     }
                     84:     else
                     85:     {
                     86:         if ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
                     87:         {
                     88:             (p->flags) &= ~LIBNET_PBLOCK_DO_CHECKSUM;
                     89:             return (1);
                     90:         }
                     91:         else
                     92:         {
                     93:             return (1);
                     94:         }
                     95:     }
                     96: }
                     97: 
                     98: 
                     99: int
                    100: libnet_do_checksum(libnet_t *l, u_int8_t *buf, int protocol, int len)
                    101: {
                    102:     /* will need to update this for ipv6 at some point */
                    103:     struct libnet_ipv4_hdr *iph_p;
                    104:     struct libnet_ipv6_hdr *ip6h_p;
                    105:     int is_ipv6;
                    106:     int ip_hl;
                    107:     int sum;
                    108: 
                    109:     is_ipv6 = 0;    /* default to not using IPv6 */
                    110:     sum     = 0;
                    111:     iph_p   = NULL;
                    112:     ip6h_p  = NULL;
                    113: 
                    114:     if (len == 0)
                    115:     {
                    116:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                    117:             "%s(): header length can't be zero\n", __func__);
                    118:         return (-1);
                    119:     }
                    120: 
                    121:     /*
                    122:      *  Figure out which IP version we're dealing with.  We'll assume v4
                    123:      *  and overlay a header structure to yank out the version.
                    124:      */
                    125:     iph_p = (struct libnet_ipv4_hdr *)buf;
                    126:     if (iph_p && iph_p->ip_v == 6)
                    127:     {
                    128:         ip6h_p = (struct libnet_ipv6_hdr *)buf;
                    129:         is_ipv6 = 1;
                    130:         ip_hl   = 40;
                    131:     }
                    132:     else
                    133:     {
                    134:         is_ipv6 = 0;
                    135:         ip_hl = iph_p->ip_hl << 2;
                    136:     }
                    137: 
                    138:     /*
                    139:      *  Dug Song came up with this very cool checksuming implementation
                    140:      *  eliminating the need for explicit psuedoheader use.  Check it out.
                    141:      */
                    142:     switch (protocol)
                    143:     {
                    144:         /*
                    145:          *  Style note: normally I don't advocate declaring variables inside
                    146:          *  blocks of control, but it makes good sense here. -- MDS
                    147:          */
                    148:         case IPPROTO_TCP:
                    149:         {
                    150:             struct libnet_tcp_hdr *tcph_p =
                    151:                 (struct libnet_tcp_hdr *)(buf + ip_hl);
                    152: 
                    153: #if (STUPID_SOLARIS_CHECKSUM_BUG)
                    154:             tcph_p->th_sum = tcph_p->th_off << 2;
                    155:             return (1);
                    156: #endif /* STUPID_SOLARIS_CHECKSUM_BUG */
                    157: #if (HAVE_HPUX11)   
                    158:             if (l->injection_type != LIBNET_LINK)
                    159:             {
                    160:                 /*
                    161:                  *  Similiar to the Solaris Checksum bug - but need to add
                    162:                  *  the size of the TCP payload (only for raw sockets).
                    163:                  */
                    164:                 tcph_p->th_sum = (tcph_p->th_off << 2) +
                    165:                         (len - (tcph_p->th_off << 2));
                    166:                 return (1); 
                    167:             }
                    168: #endif
                    169:             tcph_p->th_sum = 0;
                    170:             if (is_ipv6)
                    171:             {
                    172:                 sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
                    173:             }
                    174:             else
                    175:             {
                    176:                 sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);
                    177:             }
                    178:             sum += ntohs(IPPROTO_TCP + len);
                    179:             sum += libnet_in_cksum((u_int16_t *)tcph_p, len);
                    180:             tcph_p->th_sum = LIBNET_CKSUM_CARRY(sum);
                    181:             break;
                    182:         }
                    183:         case IPPROTO_UDP:
                    184:         {
                    185:             struct libnet_udp_hdr *udph_p =
                    186:                 (struct libnet_udp_hdr *)(buf + ip_hl);
                    187:             udph_p->uh_sum = 0;
                    188:             if (is_ipv6)
                    189:             {
                    190:                 sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
                    191:             }
                    192:             else
                    193:             {
                    194:                 sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);
                    195:             }
                    196:             sum += ntohs(IPPROTO_UDP + len);
                    197:             sum += libnet_in_cksum((u_int16_t *)udph_p, len);
                    198:             udph_p->uh_sum = LIBNET_CKSUM_CARRY(sum);
                    199:             break;
                    200:         }
                    201:         case IPPROTO_ICMP:
                    202:         {
                    203:             struct libnet_icmpv4_hdr *icmph_p =
                    204:                 (struct libnet_icmpv4_hdr *)(buf + ip_hl);
                    205: 
                    206:             icmph_p->icmp_sum = 0;
                    207:             if (is_ipv6)
                    208:             {
                    209:                 sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
                    210:                 sum += ntohs(IPPROTO_ICMP6 + len);
                    211:             }
                    212:             sum += libnet_in_cksum((u_int16_t *)icmph_p, len);
                    213:             icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum);
                    214:             break;
                    215:         }
                    216:         case IPPROTO_IGMP:
                    217:         {
                    218:             struct libnet_igmp_hdr *igmph_p =
                    219:                 (struct libnet_igmp_hdr *)(buf + ip_hl);
                    220: 
                    221:             igmph_p->igmp_sum = 0;
                    222:             sum = libnet_in_cksum((u_int16_t *)igmph_p, len);
                    223:             igmph_p->igmp_sum = LIBNET_CKSUM_CARRY(sum);
                    224:             break;
                    225:         }
                    226:        case IPPROTO_GRE:
                    227:        {
                    228:             /* checksum is always at the same place in GRE header
                    229:              * in the multiple RFC version of the protocol ... ouf !!!
                    230:              */
                    231:            struct libnet_gre_hdr *greh_p = 
                    232:                (struct libnet_gre_hdr *)(buf + ip_hl);
                    233:            u_int16_t fv = ntohs(greh_p->flags_ver);
                    234:            if (!(fv & (GRE_CSUM|GRE_ROUTING | GRE_VERSION_0)) ||
                    235:                 !(fv & (GRE_CSUM|GRE_VERSION_1)))
                    236:            {
                    237:                snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                    238:                 "%s(): can't compute GRE checksum (wrong flags_ver bits: 0x%x )\n",  __func__, fv);
                    239:                return (-1);
                    240:            }
                    241:            sum = libnet_in_cksum((u_int16_t *)greh_p, len);
                    242:            greh_p->gre_sum = LIBNET_CKSUM_CARRY(sum);
                    243:            break;
                    244:        }
                    245:         case IPPROTO_OSPF:
                    246:         {
                    247:             struct libnet_ospf_hdr *oh_p =
                    248:                 (struct libnet_ospf_hdr *)(buf + ip_hl);
                    249: 
                    250:             oh_p->ospf_sum = 0;
                    251:             sum += libnet_in_cksum((u_int16_t *)oh_p, len);
                    252:             oh_p->ospf_sum = LIBNET_CKSUM_CARRY(sum);
                    253:             break;
                    254:         }
                    255:         case IPPROTO_OSPF_LSA:
                    256:         {
                    257:             struct libnet_ospf_hdr *oh_p =
                    258:                 (struct libnet_ospf_hdr *)(buf + ip_hl);
                    259:             struct libnet_lsa_hdr *lsa_p =
                    260:                 (struct libnet_lsa_hdr *)(buf + 
                    261:                 ip_hl + oh_p->ospf_len);
                    262: 
                    263:             lsa_p->lsa_sum = 0;
                    264:             sum += libnet_in_cksum((u_int16_t *)lsa_p, len);
                    265:             lsa_p->lsa_sum = LIBNET_CKSUM_CARRY(sum);
                    266:             break;
                    267: #if 0
                    268:             /*
                    269:              *  Reworked fletcher checksum taken from RFC 1008.
                    270:              */
                    271:             int c0, c1;
                    272:             struct libnet_lsa_hdr *lsa_p = (struct libnet_lsa_hdr *)buf;
                    273:             u_int8_t *p, *p1, *p2, *p3;
                    274: 
                    275:             c0 = 0;
                    276:             c1 = 0;
                    277: 
                    278:             lsa_p->lsa_cksum = 0;
                    279: 
                    280:             p = buf;
                    281:             p1 = buf;
                    282:             p3 = buf + len;             /* beginning and end of buf */
                    283: 
                    284:             while (p1 < p3)
                    285:             {
                    286:                 p2 = p1 + LIBNET_MODX;
                    287:                 if (p2 > p3)
                    288:                 {
                    289:                     p2 = p3;
                    290:                 }
                    291:   
                    292:                 for (p = p1; p < p2; p++)
                    293:                 {
                    294:                     c0 += (*p);
                    295:                     c1 += c0;
                    296:                 }
                    297: 
                    298:                 c0 %= 255;
                    299:                 c1 %= 255;      /* modular 255 */
                    300:  
                    301:                 p1 = p2;
                    302:             }
                    303: 
                    304: #if AWR_PLEASE_REWORK_THIS
                    305:             lsa_p->lsa_cksum[0] = (((len - 17) * c0 - c1) % 255);
                    306:             if (lsa_p->lsa_cksum[0] <= 0)
                    307:             {
                    308:                 lsa_p->lsa_cksum[0] += 255;
                    309:             }
                    310: 
                    311:             lsa_p->lsa_cksum[1] = (510 - c0 - lsa_p->lsa_cksum[0]);
                    312:             if (lsa_p->lsa_cksum[1] > 255)
                    313:             {
                    314:                 lsa_p->lsa_cksum[1] -= 255;
                    315:             }
                    316: #endif
                    317:             break;
                    318: #endif
                    319:         }
                    320:         case IPPROTO_IP:
                    321:         {
                    322:             iph_p->ip_sum = 0;
                    323:             sum = libnet_in_cksum((u_int16_t *)iph_p, ip_hl);
                    324:             iph_p->ip_sum = LIBNET_CKSUM_CARRY(sum);
                    325:             break;
                    326:         }
                    327:         case IPPROTO_VRRP:
                    328:         {
                    329:             struct libnet_vrrp_hdr *vrrph_p =
                    330:                 (struct libnet_vrrp_hdr *)(buf + ip_hl);
                    331: 
                    332:             vrrph_p->vrrp_sum = 0;
                    333:             sum = libnet_in_cksum((u_int16_t *)vrrph_p, len);
                    334:             vrrph_p->vrrp_sum = LIBNET_CKSUM_CARRY(sum);
                    335:             break;
                    336:         }
                    337:         case LIBNET_PROTO_CDP:
                    338:         {   /* XXX - Broken: how can we easily get the entire packet size? */
                    339:             struct libnet_cdp_hdr *cdph_p =
                    340:                 (struct libnet_cdp_hdr *)buf;
                    341: 
                    342:             cdph_p->cdp_sum = 0;
                    343:             sum = libnet_in_cksum((u_int16_t *)cdph_p, len);
                    344:             cdph_p->cdp_sum = LIBNET_CKSUM_CARRY(sum);
                    345:             break;
                    346:         }
                    347:         case LIBNET_PROTO_ISL:
                    348:         {
                    349:            // struct libnet_isl_hdr *islh_p =
                    350:            //     (struct libnet_isl_hdr *)buf;
                    351:             /*
                    352:              *  Need to compute 4 byte CRC for the ethernet frame and for
                    353:              *  the ISL frame itself.  Use the libnet_crc function.
                    354:              */
                    355:         }
                    356:         default:
                    357:         {
                    358:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                    359:                 "%s(): unsuported protocol %d\n", __func__, protocol);
                    360:             return (-1);
                    361:         }
                    362:     }
                    363:     return (1);
                    364: }
                    365: 
                    366: 
                    367: u_int16_t
                    368: libnet_ip_check(u_int16_t *addr, int len)
                    369: {
                    370:     int sum;
                    371: 
                    372:     sum = libnet_in_cksum(addr, len);
                    373:     return (LIBNET_CKSUM_CARRY(sum));
                    374: }
                    375: 
                    376: /* EOF */

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