File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_pblock.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:11:38 2023 UTC (9 months, 1 week ago) by misho
Branches: libnet, MAIN
CVS tags: v1_2p1, HEAD
Version 1.2p1

    1: /*
    2:  *  $Id: libnet_pblock.c,v 1.1.1.3 2023/09/27 11:11:38 misho 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: #include "common.h"
   34: #include <assert.h>
   35: 
   36: libnet_pblock_t *
   37: libnet_pblock_probe(libnet_t *l, libnet_ptag_t ptag, uint32_t b_len, uint8_t type)
   38: {
   39:     int offset;
   40:     libnet_pblock_t *p;
   41: 
   42:     if (ptag == LIBNET_PTAG_INITIALIZER)
   43:     {
   44:         return libnet_pblock_new(l, b_len);
   45:     }
   46: 
   47:     /*
   48:      *  Update this pblock, don't create a new one.  Note that if the
   49:      *  new packet size is larger than the old one we will do a malloc.
   50:      */
   51:     p = libnet_pblock_find(l, ptag);
   52: 
   53:     if (p == NULL)
   54:     {
   55:         /* err msg set in libnet_pblock_find() */
   56:         return (NULL);
   57:     }
   58:     if (p->type != type)
   59:     {
   60:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
   61:                 "%s(): ptag refers to different type than expected (0x%x != 0x%x)",
   62:                 __func__, p->type, type);
   63:         return (NULL); 
   64:     }
   65:     /*
   66:      *  If size is greater than the original block of memory, we need 
   67:      *  to malloc more memory.  Should we use realloc?
   68:      */
   69:     if (b_len > p->b_len)
   70:     {
   71:         offset = b_len - p->b_len;  /* how many bytes larger new pblock is */
   72:         free(p->buf);
   73:         p->buf = malloc(b_len);
   74:         if (p->buf == NULL)
   75:         {
   76:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
   77:                     "%s(): can't resize pblock buffer: %s", __func__,
   78:                     strerror(errno));
   79:             return (NULL);
   80:         }
   81:         memset(p->buf, 0, b_len);
   82:         p->h_len += offset; /* new length for checksums */
   83:         p->b_len = b_len;       /* new buf len */
   84:         l->total_size += offset;
   85:     }
   86:     else
   87:     {
   88:         offset = p->b_len - b_len;
   89:         p->h_len -= offset; /* new length for checksums */
   90:         p->b_len = b_len;       /* new buf len */
   91:         l->total_size -= offset;
   92:     }
   93:     p->copied = 0;      /* reset copied counter */
   94: 
   95:     return (p);
   96: }
   97: 
   98: static void* zmalloc(libnet_t* l, uint32_t size, const char* func)
   99: {
  100:     void* v = malloc(size);
  101:     if(v)
  102:         memset(v, 0, size);
  103:     else
  104:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s", func, 
  105:                 strerror(errno));
  106:     return v;
  107: }
  108: 
  109: libnet_pblock_t *
  110: libnet_pblock_new(libnet_t *l, uint32_t b_len)
  111: {
  112:     libnet_pblock_t *p = zmalloc(l, sizeof(libnet_pblock_t), __func__);
  113:     if(!p)
  114:         return NULL;
  115: 
  116:     p->buf = zmalloc(l, b_len, __func__);
  117: 
  118:     if(!p->buf)
  119:     {
  120:         free(p);
  121:         return NULL;
  122:     }
  123: 
  124:     p->b_len = b_len;
  125: 
  126:     l->total_size += b_len;
  127:     l->n_pblocks++;
  128: 
  129:     /* make the head node if it doesn't exist */
  130:     if (l->protocol_blocks == NULL)
  131:     {
  132:         l->protocol_blocks = p;
  133:         l->pblock_end = p;
  134:     }
  135:     else
  136:     {
  137:         l->pblock_end->next = p;
  138:         p->prev = l->pblock_end;
  139:         l->pblock_end = p;
  140:     }
  141: 
  142:     return p;
  143: }
  144: 
  145: int
  146: libnet_pblock_swap(libnet_t *l, libnet_ptag_t ptag1, libnet_ptag_t ptag2)
  147: {
  148:     libnet_pblock_t *p1, *p2;
  149: 
  150:     p1 = libnet_pblock_find(l, ptag1);
  151:     p2 = libnet_pblock_find(l, ptag2);
  152:     if (p1 == NULL || p2 == NULL)
  153:     {
  154:         /* error set elsewhere */
  155:         return (-1);
  156:     }
  157: 
  158:     p2->prev = p1->prev;
  159:     p1->next = p2->next;
  160:     p2->next = p1;
  161:     p1->prev = p2;
  162: 
  163:     if (p1->next)
  164:     {
  165:         p1->next->prev = p1;
  166:     }
  167: 
  168:     if (p2->prev)
  169:     {
  170:         p2->prev->next = p2;
  171:     }
  172:     else
  173:     {
  174:         /* first node on the list */
  175:         l->protocol_blocks = p2;
  176:     }
  177: 
  178:     if (l->pblock_end == p2)
  179:     {
  180:         l->pblock_end = p1;
  181:     }
  182:     return (1);
  183: }
  184: 
  185: static void libnet_pblock_remove_from_list(libnet_t *l, libnet_pblock_t *p)
  186: {
  187:     if (p->prev) 
  188:     {
  189:         p->prev->next = p->next;
  190:     }
  191:     else
  192:     {
  193:         l->protocol_blocks = p->next;
  194:     }
  195: 
  196:     if (p->next)
  197:     {
  198:         p->next->prev = p->prev;
  199:     }
  200:     else
  201:     {
  202:         l->pblock_end = p->prev;
  203:     }
  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:     /* check for already present before */
  221:     if(p2->next == p1)
  222:         return 1;
  223: 
  224:     libnet_pblock_remove_from_list(l, p2);
  225: 
  226:     /* insert p2 into list */
  227:     p2->prev = p1->prev;
  228:     p2->next = p1;
  229:     p1->prev = p2;
  230: 
  231:     if (p2->prev)  
  232:     {
  233:         p2->prev->next = p2;
  234:     }
  235:     else
  236:     {
  237:         /* first node on the list */
  238:         l->protocol_blocks = p2;
  239:     }
  240:     
  241:     return (1);
  242: }
  243: 
  244: libnet_pblock_t *
  245: libnet_pblock_find(libnet_t *l, libnet_ptag_t ptag)
  246: {
  247:     libnet_pblock_t *p;
  248: 
  249:     for (p = l->protocol_blocks; p; p = p->next)
  250:     {
  251:         if (p->ptag == ptag)
  252:         {
  253:             return (p); 
  254:         }
  255:     }
  256:     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  257:             "%s(): couldn't find protocol block", __func__);
  258:     return (NULL);
  259: }
  260: 
  261: int
  262: libnet_pblock_append(libnet_t *l, libnet_pblock_t *p, const void *buf, uint32_t len)
  263: {
  264:     if (len && !buf)
  265:     {
  266:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  267: 			    "%s(): payload inconsistency", __func__);
  268:         return -1;
  269:     }
  270: 
  271:     if (p->copied + len > p->b_len)
  272:     {
  273:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  274:                 "%s(): memcpy would overflow buffer", __func__);
  275:         return (-1);
  276:     }
  277:     memcpy(p->buf + p->copied, buf, len);
  278:     p->copied += len;
  279:     return (1);
  280: }
  281: 
  282: void
  283: libnet_pblock_setflags(libnet_pblock_t *p, uint8_t flags)
  284: {
  285:     p->flags = flags;
  286: }
  287: 
  288: /* FIXME both ptag setting and end setting should be done in pblock new and/or pblock probe. */
  289: libnet_ptag_t
  290: libnet_pblock_update(libnet_t *l, libnet_pblock_t *p, uint32_t h_len, uint8_t type)
  291: {
  292:     p->type  =  type;
  293:     p->ptag  =  ++(l->ptag_state);
  294:     p->h_len = h_len;
  295:     l->pblock_end = p;              /* point end of pblock list here */
  296: 
  297:     return (p->ptag);
  298: }
  299: 
  300: static int pblock_is_ip(libnet_pblock_t* p)
  301: {
  302:     return p->type == LIBNET_PBLOCK_IPV4_H || p->type == LIBNET_PBLOCK_IPV6_H;
  303: }
  304: 
  305: /* q is either an ip hdr, or is followed  by an ip hdr. return the offset
  306:  * from end of packet. if there is no offset, we'll return the total size,
  307:  * and things will break later
  308:  */
  309: static int calculate_ip_offset(libnet_t* l, libnet_pblock_t* q)
  310: {
  311:     int ip_offset = 0;
  312:     libnet_pblock_t* p = l->protocol_blocks;
  313:     for(; p && p != q; p = p->next) {
  314: 	ip_offset += p->b_len;
  315:     }
  316:     assert(p == q); /* if not true, then q is not a pblock! */
  317: 
  318:     for(; p; p = p->next) {
  319: 	ip_offset += p->b_len;
  320: 	if(pblock_is_ip(p))
  321: 	    break;
  322:     }
  323: 
  324:     return ip_offset;
  325: }
  326: 
  327: int
  328: libnet_pblock_coalesce(libnet_t *l, uint8_t **packet, uint32_t *size)
  329: {
  330:     /*
  331:      *  Determine the offset required to keep memory aligned (strict
  332:      *  architectures like solaris enforce this, but's a good practice
  333:      *  either way).  This is only required on the link layer with the
  334:      *  14 byte ethernet offset (others are similarly unkind).
  335:      */
  336:     if (l->injection_type == LIBNET_LINK || 
  337:         l->injection_type == LIBNET_LINK_ADV)
  338:     {
  339:         /* 8 byte alignment should work */
  340:         l->aligner = 8 - (l->link_offset % 8);
  341:     }
  342:     else
  343:     {
  344:         l->aligner = 0;
  345:     }
  346: 
  347:     if(!l->total_size && !l->aligner) {
  348:         /* Avoid allocating zero bytes of memory, it perturbs electric fence. */
  349:         *packet = malloc(1);
  350:         **packet =1;
  351:     } else {
  352:         *packet = malloc(l->aligner + l->total_size);
  353:     }
  354:     if (*packet == NULL)
  355:     {
  356:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s",
  357:                 __func__, strerror(errno));
  358:         return (-1);
  359:     }
  360: 
  361:     memset(*packet, 0, l->aligner + l->total_size);
  362: 
  363:     if (l->injection_type == LIBNET_RAW4 && 
  364:         l->pblock_end->type == LIBNET_PBLOCK_IPV4_H)
  365:     {
  366:         libnet_pblock_setflags(l->pblock_end, LIBNET_PBLOCK_DO_CHECKSUM); 
  367:     }
  368:     
  369:     /* additional sanity checks to perform if we're not in advanced mode */
  370:     if (!(l->injection_type & LIBNET_ADV_MASK))
  371:     {
  372:     	switch (l->injection_type)
  373:     	{
  374:             case LIBNET_LINK:
  375:                 if ((l->pblock_end->type != LIBNET_PBLOCK_TOKEN_RING_H) &&
  376:                     (l->pblock_end->type != LIBNET_PBLOCK_FDDI_H)       &&
  377:                     (l->pblock_end->type != LIBNET_PBLOCK_ETH_H)        &&
  378:                     (l->pblock_end->type != LIBNET_PBLOCK_802_1Q_H)     &&
  379:                     (l->pblock_end->type != LIBNET_PBLOCK_ISL_H)        &&
  380:                     (l->pblock_end->type != LIBNET_PBLOCK_802_3_H))
  381:                 {
  382:                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
  383:                     "%s(): packet assembly cannot find a layer 2 header",
  384:                     __func__);
  385:                     goto err;
  386:                 }
  387:                 break;
  388:             case LIBNET_RAW4:
  389:                 if ((l->pblock_end->type != LIBNET_PBLOCK_IPV4_H))
  390:                 {
  391:                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
  392:                     "%s(): packet assembly cannot find an IPv4 header",
  393:                      __func__);
  394:                     goto err;
  395:                 }
  396:                 break;
  397:             case LIBNET_RAW6:
  398:                 if ((l->pblock_end->type != LIBNET_PBLOCK_IPV6_H))
  399:                 {
  400:                     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
  401:                     "%s(): packet assembly cannot find an IPv6 header",
  402:                      __func__);
  403:                     goto err;
  404:                 }
  405:                 break;
  406:             default:
  407:                 /* we should not end up here ever */
  408:                 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, 
  409:                 "%s(): suddenly the dungeon collapses -- you die",
  410:                  __func__);
  411:                 goto err;
  412:             break;
  413:         }
  414:     }
  415: 
  416:     /* Build packet from end to start. */
  417:     {
  418:         /*
  419:            From top to bottom, go through pblocks pairwise:
  420: 
  421:            p   is the currently being copied pblock, and steps through every block
  422:            q   is the prev pblock to p that needs checksumming, it will
  423:                not step through every block as p does, it will skip any that do not
  424:                need checksumming.
  425:            n   offset from start of packet to beginning of block we are writing
  426: 
  427:            q is NULL on first iteration
  428:            p is NULL on last iteration
  429: 
  430:            Checksums are done on q, to give p a chance to be copied over, since
  431:            checksumming q can require a lower-level header to be encoded, in the
  432:            case of IP protocols (which are the only kinds handled by libnet's
  433:            checksum implementation).
  434: 
  435:            This is very obscure, or would be much more clear if it was done in
  436:            two loops.
  437:            */
  438:         libnet_pblock_t *q = NULL;
  439:         libnet_pblock_t *p = NULL;
  440:         uint32_t n;
  441: 
  442:         for (n = l->aligner + l->total_size, p = l->protocol_blocks; p || q; )
  443:         {
  444:             if (q)
  445:             {
  446:                 p = p->next;
  447:             }
  448:             if (p)
  449:             {
  450:                 n -= p->b_len;
  451:                 /* copy over the packet chunk */
  452:                 memcpy(*packet + n, p->buf, p->b_len);
  453:             }
  454: #if 0
  455:             printf("-- n %d/%d cksum? %d\n", n, l->aligner + l->total_size,
  456:                     q &&
  457:                     (p == NULL || (p->flags & LIBNET_PBLOCK_DO_CHECKSUM)) &&
  458:                     (q->flags & LIBNET_PBLOCK_DO_CHECKSUM));
  459:             if(q)
  460:             {
  461:                 printf(" iph %d/%d offset -%d\n",
  462:                         (l->total_size + l->aligner) - q->ip_offset,
  463:                         l->total_size + l->aligner,
  464:                         q->ip_offset
  465:                       );
  466:             }
  467:             if (p)
  468:             {
  469:                 printf("p %p ptag %d b_len %d h_len %d cksum? %d type %s\n",
  470:                         p, p->ptag,
  471:                         p->b_len, p->h_len,
  472:                         p->flags & LIBNET_PBLOCK_DO_CHECKSUM,
  473:                         libnet_diag_dump_pblock_type(p->type)
  474:                       );
  475:             }
  476:             if (q)
  477:             {
  478:                 printf("q %p ptag %d b_len %d h_len %d cksum? %d type %s\n",
  479:                         q, q->ptag,
  480:                         q->b_len, q->h_len,
  481:                         q->flags & LIBNET_PBLOCK_DO_CHECKSUM,
  482:                         libnet_diag_dump_pblock_type(q->type)
  483:                       );
  484:             }
  485: #endif
  486:             if (q)
  487:             {
  488:                 if (p == NULL || (p->flags & LIBNET_PBLOCK_DO_CHECKSUM))
  489:                 {
  490:                     if (q->flags & LIBNET_PBLOCK_DO_CHECKSUM)
  491:                     {
  492:                         uint32_t c;
  493:                         uint8_t* end = *packet + l->aligner + l->total_size;
  494:                         uint8_t* beg = *packet + n;
  495:                         int ip_offset = calculate_ip_offset(l, q);
  496:                         uint8_t* iph = end - ip_offset;
  497: #if 0
  498: 			printf("p %d/%s q %d/%s offset calculated %d\n",
  499: 				p ? p->ptag : -1, p ? libnet_diag_dump_pblock_type(p->type) : "nil",
  500: 				q->ptag, libnet_diag_dump_pblock_type(q->type),
  501: 				ip_offset);
  502: #endif
  503:                         c = libnet_inet_checksum(l, iph,
  504:                                 libnet_pblock_p2p(q->type), q->h_len,
  505:                                 beg, end);
  506:                         if (c == -1)
  507:                         {
  508:                             /* err msg set in libnet_do_checksum() */
  509:                             goto err;
  510:                         }
  511:                     }
  512:                     q = p;
  513:                 }
  514:             }
  515:             else
  516:             {
  517:                 q = p;
  518:             }
  519:         }
  520:     }
  521:     *size = l->aligner + l->total_size;
  522: 
  523:     /*
  524:      *  Set the packet pointer to the true beginning of the packet and set
  525:      *  the size for transmission.
  526:      */
  527:     if ((l->injection_type == LIBNET_LINK ||
  528:         l->injection_type == LIBNET_LINK_ADV) && l->aligner)
  529:     {
  530:         *packet += l->aligner;
  531:         *size -= l->aligner;
  532:     }
  533:     return (1);
  534: 
  535: err:
  536:     free(*packet);
  537:     *packet = NULL;
  538:     return (-1);
  539: }
  540: 
  541: void
  542: libnet_pblock_delete(libnet_t *l, libnet_pblock_t *p)
  543: {
  544:     if (p)
  545:     {
  546:         l->total_size -= p->b_len;
  547:         l->n_pblocks--;
  548: 
  549:         libnet_pblock_remove_from_list(l, p);
  550: 
  551:         if (p->buf)
  552:         {
  553:             free(p->buf);
  554:             p->buf = NULL;
  555:         }
  556: 
  557:         free(p);
  558:     }
  559: }
  560: 
  561: int
  562: libnet_pblock_p2p(uint8_t type)
  563: {
  564:     /* for checksum; return the protocol number given a pblock type*/
  565:     switch (type)
  566:     {
  567:         case LIBNET_PBLOCK_CDP_H:
  568:             return (LIBNET_PROTO_CDP);
  569:         case LIBNET_PBLOCK_ICMPV4_H:
  570:         case LIBNET_PBLOCK_ICMPV4_ECHO_H:
  571:         case LIBNET_PBLOCK_ICMPV4_MASK_H:
  572:         case LIBNET_PBLOCK_ICMPV4_UNREACH_H:
  573:         case LIBNET_PBLOCK_ICMPV4_TIMXCEED_H:
  574:         case LIBNET_PBLOCK_ICMPV4_REDIRECT_H:
  575:         case LIBNET_PBLOCK_ICMPV4_TS_H:
  576:             return (IPPROTO_ICMP);
  577:         case LIBNET_PBLOCK_ICMPV6_H:
  578:         case LIBNET_PBLOCK_ICMPV6_ECHO_H:
  579:         case LIBNET_PBLOCK_ICMPV6_UNREACH_H:
  580:         case LIBNET_PBLOCK_ICMPV6_NDP_NSOL_H:
  581:         case LIBNET_PBLOCK_ICMPV6_NDP_NADV_H:
  582:             return (IPPROTO_ICMPV6);
  583:         case LIBNET_PBLOCK_IGMP_H:
  584:             return (IPPROTO_IGMP);
  585:         case LIBNET_PBLOCK_IPV4_H:
  586:             return (IPPROTO_IP);
  587:         case LIBNET_PBLOCK_IPV6_H:
  588:             return (IPPROTO_IPV6);
  589:         case LIBNET_ISL_H:
  590:             return (LIBNET_PROTO_ISL);
  591:         case LIBNET_PBLOCK_OSPF_H:
  592:             return (IPPROTO_OSPF);
  593:         case LIBNET_PBLOCK_LS_RTR_H:
  594:             return (IPPROTO_OSPF_LSA);
  595:         case LIBNET_PBLOCK_TCP_H:
  596:             return (IPPROTO_TCP);
  597:         case LIBNET_PBLOCK_UDP_H:
  598:             return (IPPROTO_UDP);
  599:         case LIBNET_PBLOCK_VRRP_H:
  600:             return (IPPROTO_VRRP);
  601:         case LIBNET_PBLOCK_GRE_H:
  602:             return (IPPROTO_GRE);
  603:         default:
  604:             return (-1);
  605:     }
  606: }
  607: 
  608: void
  609: libnet_pblock_record_ip_offset(libnet_t *l, libnet_pblock_t *p)
  610: {
  611:     (void) l;
  612:     (void) p;
  613:     /* For backwards compatibility, libnet_pblock_t no longer includes
  614:        an ip_offset, so calling this is unnecessary.
  615:        */
  616: }
  617: 
  618: /**
  619:  * Local Variables:
  620:  *  indent-tabs-mode: nil
  621:  *  c-file-style: "stroustrup"
  622:  * End:
  623:  */

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