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

1.1       misho       1: /*
                      2:  *  $Id: libnet_pblock.c,v 1.13 2004/03/16 18:40:59 mike Exp $
                      3:  *
                      4:  *  libnet
                      5:  *  libnet_pblock.c - Memory protocol block 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: 
                     42: libnet_pblock_t *
                     43: libnet_pblock_probe(libnet_t *l, libnet_ptag_t ptag, u_int32_t n, u_int8_t type)
                     44: {
                     45:     int offset;
                     46:     libnet_pblock_t *p;
                     47: 
                     48:     if (ptag == LIBNET_PTAG_INITIALIZER)
                     49:     {
                     50:         /*
                     51:          *  Create a new pblock and enough buffer space for the packet.
                     52:          */
                     53:         p = libnet_pblock_new(l, n);
                     54:         if (p == NULL)
                     55:         {
                     56:             /* err msg set in libnet_pblock_new() */
                     57:             return (NULL);
                     58:         }
                     59:     }
                     60:     else
                     61:     {
                     62:         /*
                     63:          *  Update this pblock, don't create a new one.  Note that if the
                     64:          *  new packet size is larger than the old one we will do a malloc.
                     65:          */
                     66:         p = libnet_pblock_find(l, ptag);
                     67: 
                     68:         if (p == NULL)
                     69:         {
                     70:             /* err msg set in libnet_pblock_find() */
                     71:             return (NULL);
                     72:         }
                     73:         if (p->type != type)
                     74:         {
                     75:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                     76:                "%s(): ptag refers to different type than expected (%d != %d)",
                     77:                __func__, p->type, type);
                     78:             return (NULL); 
                     79:         }
                     80:         /*
                     81:          *  If size is greater than the original block of memory, we need 
                     82:          *  to malloc more memory.  Should we use realloc?
                     83:          */
                     84:         if (n > p->b_len)
                     85:         {
                     86:             offset = n - p->b_len;  /* how many bytes larger new pblock is */
                     87:             free(p->buf);
                     88:             p->buf = malloc(n);
                     89:             if (p->buf == NULL)
                     90:             {
                     91:                 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                     92:                         "%s(): can't resize pblock buffer: %s\n", __func__,
                     93:                         strerror(errno));
                     94:                 return (NULL);
                     95:             }
                     96:             memset(p->buf, 0, n);
                     97:             p->h_len += offset; /* new length for checksums */
                     98:             p->b_len = n;       /* new buf len */
                     99:             l->total_size += offset;
                    100:         }
                    101:         else
                    102:         {
                    103:             offset = p->b_len - n;
                    104:             p->h_len -= offset; /* new length for checksums */
                    105:             p->b_len = n;       /* new buf len */
                    106:             l->total_size -= offset;
                    107:         }
                    108:         p->copied = 0;      /* reset copied counter */
                    109:     }
                    110:     return (p);
                    111: }
                    112: 
                    113: libnet_pblock_t *
                    114: libnet_pblock_new(libnet_t *l, u_int32_t size)
                    115: {
                    116:     libnet_pblock_t *p;
                    117:     /*
                    118:      *  Should we do error checking the size of the pblock here, or
                    119:      *  should we rely on the underlying operating system to complain when
                    120:      *  the user tries to write some ridiculously huge packet?
                    121:      */
                    122: 
                    123:     /* make the head node if it doesn't exist */
                    124:     if (l->protocol_blocks == NULL)
                    125:     {
                    126:         p = l->protocol_blocks = malloc(sizeof (libnet_pblock_t));
                    127:         if (p == NULL)
                    128:         {
                    129:             goto bad;
                    130:         }
                    131:         memset(p, 0, sizeof (libnet_pblock_t));
                    132:     }
                    133:     else
                    134:     {
                    135:         p = l->pblock_end;
                    136:         p->next = malloc(sizeof (libnet_pblock_t));
                    137: 
                    138:         if (p->next == NULL)
                    139:         {
                    140:             goto bad;
                    141:         }
                    142:         memset(p->next, 0, sizeof (libnet_pblock_t));
                    143:         p->next->prev = p;
                    144:         p = p->next;
                    145:     }
                    146: 
                    147:     p->buf = malloc(size);
                    148:     if (p->buf == NULL)
                    149:     {
                    150:         free(p);
                    151:         p = NULL;
                    152:         goto bad;
                    153:     }
                    154:     memset(p->buf, 0, size);
                    155:     p->b_len      = size;
                    156:     l->total_size += size;
                    157:     l->n_pblocks++;
                    158:     return (p);
                    159: 
                    160:     bad:
                    161:     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n", __func__, 
                    162:             strerror(errno));
                    163:     return (NULL);
                    164: }
                    165: 
                    166: int
                    167: libnet_pblock_swap(libnet_t *l, libnet_ptag_t ptag1, libnet_ptag_t ptag2)
                    168: {
                    169:     libnet_pblock_t *p1, *p2;
                    170: 
                    171:     p1 = libnet_pblock_find(l, ptag1);
                    172:     p2 = libnet_pblock_find(l, ptag2);
                    173:     if (p1 == NULL || p2 == NULL)
                    174:     {
                    175:         /* error set elsewhere */
                    176:         return (-1);
                    177:     }
                    178: 
                    179:     p2->prev = p1->prev;
                    180:     p1->next = p2->next;
                    181:     p2->next = p1;
                    182:     p1->prev = p2;
                    183: 
                    184:     if (p1->next)
                    185:     {
                    186:         p1->next->prev = p1;
                    187:     }
                    188: 
                    189:     if (p2->prev)
                    190:     {
                    191:         p2->prev->next = p2;
                    192:     }
                    193:     else
                    194:     {
                    195:         /* first node on the list */
                    196:         l->protocol_blocks = p2;
                    197:     }
                    198: 
                    199:     if (l->pblock_end == p2)
                    200:     {
                    201:         l->pblock_end = p1;
                    202:     }
                    203:     return (1);
                    204: }
                    205: 
                    206: int
                    207: libnet_pblock_insert_before(libnet_t *l, libnet_ptag_t ptag1,
                    208:         libnet_ptag_t ptag2)
                    209: {
                    210:     libnet_pblock_t *p1, *p2;
                    211: 
                    212:     p1 = libnet_pblock_find(l, ptag1);
                    213:     p2 = libnet_pblock_find(l, ptag2);
                    214:     if (p1 == NULL || p2 == NULL)
                    215:     {
                    216:         /* error set elsewhere */
                    217:         return (-1);
                    218:     }
                    219: 
                    220:     p2->prev = p1->prev;
                    221:     p2->next = p1;
                    222:     p1->prev = p2;
                    223: 
                    224:     if (p2->prev)  
                    225:     {
                    226:         p2->prev->next = p2;
                    227:     }
                    228:     else
                    229:     {
                    230:         /* first node on the list */
                    231:         l->protocol_blocks = p2;
                    232:     }
                    233:     
                    234:     return (1);
                    235: }
                    236: 
                    237: libnet_pblock_t *
                    238: libnet_pblock_find(libnet_t *l, libnet_ptag_t ptag)
                    239: {
                    240:     libnet_pblock_t *p;
                    241: 
                    242:     for (p = l->protocol_blocks; p; p = p->next)
                    243:     {
                    244:         if (p->ptag == ptag)
                    245:         {
                    246:             return (p); 
                    247:         }
                    248:     }
                    249:     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                    250:             "%s(): couldn't find protocol block\n", __func__);
                    251:     return (NULL);
                    252: }
                    253: 
                    254: int
                    255: libnet_pblock_append(libnet_t *l, libnet_pblock_t *p, u_int8_t *buf,
                    256:             u_int32_t len)
                    257: {
                    258:     if (p->copied + len > p->b_len)
                    259:     {
                    260:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                    261:                 "%s(): memcpy would overflow buffer\n", __func__);
                    262:         return (-1);
                    263:     }
                    264:     memcpy(p->buf + p->copied, buf, len);
                    265:     p->copied += len;
                    266:     return (1);
                    267: }
                    268: 
                    269: void
                    270: libnet_pblock_setflags(libnet_pblock_t *p, u_int8_t flags)
                    271: {
                    272:     p->flags = flags;
                    273: }
                    274: 
                    275: libnet_ptag_t
                    276: libnet_pblock_update(libnet_t *l, libnet_pblock_t *p, u_int32_t h,
                    277: u_int8_t type)
                    278: {
                    279:     p->type  =  type;
                    280:     p->ptag  =  ++(l->ptag_state);
                    281:     p->h_len = h;
                    282:     l->pblock_end = p;              /* point end of pblock list here */
                    283: 
                    284:     return (p->ptag);
                    285: }
                    286: 
                    287: int
                    288: libnet_pblock_coalesce(libnet_t *l, u_int8_t **packet, u_int32_t *size)
                    289: {
                    290:     libnet_pblock_t *p, *q;
                    291:     u_int32_t c, n;
                    292: 
                    293:     /*
                    294:      *  Determine the offset required to keep memory aligned (strict
                    295:      *  architectures like solaris enforce this, but's a good practice
                    296:      *  either way).  This is only required on the link layer with the
                    297:      *  14 byte ethernet offset (others are similarly unkind).
                    298:      */
                    299:     if (l->injection_type == LIBNET_LINK || 
                    300:         l->injection_type == LIBNET_LINK_ADV)
                    301:     {
                    302:         /* 8 byte alignment should work */
                    303:         l->aligner = 8 - (l->link_offset % 8);
                    304:     }
                    305:     else
                    306:     {
                    307:         l->aligner = 0;
                    308:     }
                    309: 
                    310:     *packet = malloc(l->aligner + l->total_size);
                    311:     if (*packet == NULL)
                    312:     {
                    313:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n",
                    314:                 __func__, strerror(errno));
                    315:         return (-1);
                    316:     }
                    317: 
                    318:     memset(*packet, 0, l->aligner + l->total_size);
                    319: 
                    320:     if (l->injection_type == LIBNET_RAW4 && 
                    321:         l->pblock_end->type == LIBNET_PBLOCK_IPV4_H)
                    322:     {
                    323:         libnet_pblock_setflags(l->pblock_end, LIBNET_PBLOCK_DO_CHECKSUM); 
                    324:     }
                    325:     
                    326:     /* additional sanity checks to perform if we're not in advanced mode */
                    327:     if (!(l->injection_type & LIBNET_ADV_MASK))
                    328:     {
                    329:        switch (l->injection_type)
                    330:        {
                    331:             case LIBNET_LINK:
                    332:                 if ((l->pblock_end->type != LIBNET_PBLOCK_TOKEN_RING_H) &&
                    333:                     (l->pblock_end->type != LIBNET_PBLOCK_FDDI_H)       &&
                    334:                     (l->pblock_end->type != LIBNET_PBLOCK_ETH_H)        &&
                    335:                     (l->pblock_end->type != LIBNET_PBLOCK_802_1Q_H)     &&
                    336:                     (l->pblock_end->type != LIBNET_PBLOCK_ISL_H)        &&
                    337:                     (l->pblock_end->type != LIBNET_PBLOCK_802_3_H))
                    338:                 {
                    339:                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
                    340:                     "%s(): packet assembly cannot find a layer 2 header\n",
                    341:                     __func__);
                    342:                     return (-1);
                    343:                 }
                    344:                 break;
                    345:             case LIBNET_RAW4:
                    346:                 if ((l->pblock_end->type != LIBNET_PBLOCK_IPV4_H))
                    347:                 {
                    348:                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
                    349:                     "%s(): packet assembly cannot find an IPv4 header\n",
                    350:                      __func__);
                    351:                     return (-1);
                    352:                 }
                    353:                 break;
                    354:             case LIBNET_RAW6:
                    355:                 if ((l->pblock_end->type != LIBNET_PBLOCK_IPV6_H))
                    356:                 {
                    357:                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
                    358:                     "%s(): packet assembly cannot find an IPv6 header\n",
                    359:                      __func__);
                    360:                     return (-1);
                    361:                 }
                    362:                 break;
                    363:             default:
                    364:                 /* we should not end up here ever */
                    365:                 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
                    366:                 "%s(): suddenly the dungeon collapses -- you die\n",
                    367:                  __func__);
                    368:                 return (-1);
                    369:             break;
                    370:         }
                    371:     }
                    372: 
                    373:     q = NULL; 
                    374:     for (n = l->aligner + l->total_size, p = l->protocol_blocks; p || q; )
                    375:     {
                    376:         if (q)
                    377:         {
                    378:             p = p->next;
                    379:         }
                    380:         if (p)
                    381:         {
                    382:             n -= p->b_len;
                    383:             /* copy over the packet chunk */
                    384:             memcpy(*packet + n, p->buf, p->b_len);
                    385:         }
                    386:         if (q)
                    387:         {
                    388:             if (p == NULL || ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM))
                    389:             {
                    390:                 if ((q->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
                    391:                 {
                    392:                     int offset = (l->total_size + l->aligner) - q->ip_offset;
                    393:                     c = libnet_do_checksum(l, *packet + offset,
                    394:                             libnet_pblock_p2p(q->type), q->h_len);
                    395:                     if (c == -1)
                    396:                     {
                    397:                         /* err msg set in libnet_do_checksum() */
                    398:                         return (-1);
                    399:                     }
                    400:                 }
                    401:                 q = p;
                    402:             }
                    403:         }
                    404:         else
                    405:         {
                    406:             q = p;
                    407:         }
                    408:     }
                    409:     *size = l->aligner + l->total_size;
                    410: 
                    411:     /*
                    412:      *  Set the packet pointer to the true beginning of the packet and set
                    413:      *  the size for transmission.
                    414:      */
                    415:     if ((l->injection_type == LIBNET_LINK ||
                    416:         l->injection_type == LIBNET_LINK_ADV) && l->aligner)
                    417:     {
                    418:         *packet += l->aligner;
                    419:         *size -= l->aligner;
                    420:     }
                    421:     return (1);
                    422: }
                    423: 
                    424: void
                    425: libnet_pblock_delete(libnet_t *l, libnet_pblock_t *p)
                    426: {
                    427:     if (p)
                    428:     {
                    429:         l->total_size -= p->b_len;
                    430:         l->n_pblocks--;
                    431:         if (p->prev) 
                    432:         {
                    433:             p->prev->next = p->next;
                    434:         }
                    435:         else
                    436:         {
                    437:             l->protocol_blocks = p->next;
                    438:         }
                    439: 
                    440:         if (p->next)
                    441:         {
                    442:             p->next->prev = p->prev;
                    443:         }
                    444:         else
                    445:         {
                    446:             l->pblock_end = p->prev;
                    447:         }
                    448: 
                    449:         if (p->buf)
                    450:         {
                    451:           free(p->buf);
                    452:         }
                    453: 
                    454:         free(p);
                    455:         p = NULL;
                    456:     }
                    457: }
                    458: 
                    459: int
                    460: libnet_pblock_p2p(u_int8_t type)
                    461: {
                    462:     /* for checksum; return the protocol number given a pblock type*/
                    463:     switch (type)
                    464:     {
                    465:         case LIBNET_PBLOCK_CDP_H:
                    466:             return (LIBNET_PROTO_CDP);
                    467:         case LIBNET_PBLOCK_ICMPV4_H:
                    468:         case LIBNET_PBLOCK_ICMPV4_ECHO_H:
                    469:         case LIBNET_PBLOCK_ICMPV4_MASK_H:
                    470:         case LIBNET_PBLOCK_ICMPV4_UNREACH_H:
                    471:         case LIBNET_PBLOCK_ICMPV4_TIMXCEED_H:
                    472:         case LIBNET_PBLOCK_ICMPV4_REDIRECT_H:
                    473:         case LIBNET_PBLOCK_ICMPV4_TS_H:
                    474:             return (IPPROTO_ICMP);
                    475:         case LIBNET_PBLOCK_IGMP_H:
                    476:             return (IPPROTO_IGMP);
                    477:         case LIBNET_PBLOCK_IPV4_H:
                    478:             return (IPPROTO_IP);
                    479:         case LIBNET_ISL_H:
                    480:             return (LIBNET_PROTO_ISL);
                    481:         case LIBNET_PBLOCK_OSPF_H:
                    482:             return (IPPROTO_OSPF);
                    483:         case LIBNET_PBLOCK_LS_RTR_H:
                    484:             return (IPPROTO_OSPF_LSA);
                    485:         case LIBNET_PBLOCK_TCP_H:
                    486:             return (IPPROTO_TCP);
                    487:         case LIBNET_PBLOCK_UDP_H:
                    488:             return (IPPROTO_UDP);
                    489:         case LIBNET_PBLOCK_VRRP_H:
                    490:             return (IPPROTO_VRRP);
                    491:         case LIBNET_PBLOCK_GRE_H:
                    492:             return (IPPROTO_GRE);
                    493:         default:
                    494:             return (-1);
                    495:     }
                    496: }
                    497: 
                    498: void
                    499: libnet_pblock_record_ip_offset(libnet_t *l, u_int32_t offset)
                    500: {
                    501:     libnet_pblock_t *p = l->pblock_end;
                    502: 
                    503:     do
                    504:     {
                    505:         p->ip_offset = offset;
                    506:         p = p->prev;
                    507:     } while (p && p->type != LIBNET_PBLOCK_IPV4_H);
                    508: }
                    509: 
                    510: 
                    511: /* EOF */

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