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>