Annotation of embedaddon/libnet/src/libnet_pblock.c, revision 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>