Annotation of embedaddon/libnet/src/libnet_pblock.c, revision 1.1.1.3
1.1 misho 1: /*
1.1.1.2 misho 2: * $Id: libnet_pblock.c,v 1.14 2004/11/09 07:05:07 mike Exp $
1.1 misho 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:
1.1.1.3 ! misho 33: #include "common.h"
1.1.1.2 misho 34: #include <assert.h>
1.1 misho 35:
36: libnet_pblock_t *
1.1.1.2 misho 37: libnet_pblock_probe(libnet_t *l, libnet_ptag_t ptag, uint32_t b_len, uint8_t type)
1.1 misho 38: {
39: int offset;
40: libnet_pblock_t *p;
41:
42: if (ptag == LIBNET_PTAG_INITIALIZER)
43: {
1.1.1.2 misho 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)
1.1 misho 75: {
1.1.1.2 misho 76: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
1.1.1.3 ! misho 77: "%s(): can't resize pblock buffer: %s", __func__,
1.1.1.2 misho 78: strerror(errno));
1.1 misho 79: return (NULL);
80: }
1.1.1.2 misho 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;
1.1 misho 85: }
86: else
87: {
1.1.1.2 misho 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;
1.1 misho 92: }
1.1.1.2 misho 93: p->copied = 0; /* reset copied counter */
94:
1.1 misho 95: return (p);
96: }
97:
1.1.1.2 misho 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
1.1.1.3 ! misho 104: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s", func,
1.1.1.2 misho 105: strerror(errno));
106: return v;
107: }
108:
1.1 misho 109: libnet_pblock_t *
1.1.1.2 misho 110: libnet_pblock_new(libnet_t *l, uint32_t b_len)
1.1 misho 111: {
1.1.1.2 misho 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++;
1.1 misho 128:
129: /* make the head node if it doesn't exist */
130: if (l->protocol_blocks == NULL)
131: {
1.1.1.2 misho 132: l->protocol_blocks = p;
133: l->pblock_end = p;
1.1 misho 134: }
135: else
136: {
1.1.1.2 misho 137: l->pblock_end->next = p;
138: p->prev = l->pblock_end;
139: l->pblock_end = p;
1.1 misho 140: }
141:
1.1.1.2 misho 142: return p;
1.1 misho 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:
1.1.1.2 misho 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:
1.1 misho 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:
1.1.1.2 misho 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 */
1.1 misho 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,
1.1.1.3 ! misho 257: "%s(): couldn't find protocol block", __func__);
1.1 misho 258: return (NULL);
259: }
260:
261: int
1.1.1.2 misho 262: libnet_pblock_append(libnet_t *l, libnet_pblock_t *p, const void *buf, uint32_t len)
1.1 misho 263: {
1.1.1.2 misho 264: if (len && !buf)
265: {
266: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
1.1.1.3 ! misho 267: "%s(): payload inconsistency", __func__);
1.1.1.2 misho 268: return -1;
269: }
270:
1.1 misho 271: if (p->copied + len > p->b_len)
272: {
273: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
1.1.1.3 ! misho 274: "%s(): memcpy would overflow buffer", __func__);
1.1 misho 275: return (-1);
276: }
277: memcpy(p->buf + p->copied, buf, len);
278: p->copied += len;
279: return (1);
280: }
281:
282: void
1.1.1.2 misho 283: libnet_pblock_setflags(libnet_pblock_t *p, uint8_t flags)
1.1 misho 284: {
285: p->flags = flags;
286: }
287:
1.1.1.2 misho 288: /* FIXME both ptag setting and end setting should be done in pblock new and/or pblock probe. */
1.1 misho 289: libnet_ptag_t
1.1.1.2 misho 290: libnet_pblock_update(libnet_t *l, libnet_pblock_t *p, uint32_t h_len, uint8_t type)
1.1 misho 291: {
292: p->type = type;
293: p->ptag = ++(l->ptag_state);
1.1.1.2 misho 294: p->h_len = h_len;
1.1 misho 295: l->pblock_end = p; /* point end of pblock list here */
296:
297: return (p->ptag);
298: }
299:
1.1.1.2 misho 300: static int pblock_is_ip(libnet_pblock_t* p)
1.1 misho 301: {
1.1.1.2 misho 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: }
1.1 misho 326:
1.1.1.2 misho 327: int
328: libnet_pblock_coalesce(libnet_t *l, uint8_t **packet, uint32_t *size)
329: {
1.1 misho 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:
1.1.1.2 misho 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: }
1.1 misho 354: if (*packet == NULL)
355: {
1.1.1.3 ! misho 356: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s",
1.1 misho 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,
1.1.1.3 ! misho 383: "%s(): packet assembly cannot find a layer 2 header",
1.1 misho 384: __func__);
1.1.1.2 misho 385: goto err;
1.1 misho 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,
1.1.1.3 ! misho 392: "%s(): packet assembly cannot find an IPv4 header",
1.1 misho 393: __func__);
1.1.1.2 misho 394: goto err;
1.1 misho 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,
1.1.1.3 ! misho 401: "%s(): packet assembly cannot find an IPv6 header",
1.1 misho 402: __func__);
1.1.1.2 misho 403: goto err;
1.1 misho 404: }
405: break;
406: default:
407: /* we should not end up here ever */
408: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
1.1.1.3 ! misho 409: "%s(): suddenly the dungeon collapses -- you die",
1.1 misho 410: __func__);
1.1.1.2 misho 411: goto err;
1.1 misho 412: break;
413: }
414: }
415:
1.1.1.2 misho 416: /* Build packet from end to start. */
1.1 misho 417: {
1.1.1.2 misho 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; )
1.1 misho 443: {
1.1.1.2 misho 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)
1.1 misho 487: {
1.1.1.2 misho 488: if (p == NULL || (p->flags & LIBNET_PBLOCK_DO_CHECKSUM))
1.1 misho 489: {
1.1.1.2 misho 490: if (q->flags & LIBNET_PBLOCK_DO_CHECKSUM)
1.1 misho 491: {
1.1.1.2 misho 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: }
1.1 misho 511: }
1.1.1.2 misho 512: q = p;
1.1 misho 513: }
1.1.1.2 misho 514: }
515: else
516: {
1.1 misho 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);
1.1.1.2 misho 534:
535: err:
536: free(*packet);
537: *packet = NULL;
538: return (-1);
1.1 misho 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:
1.1.1.2 misho 549: libnet_pblock_remove_from_list(l, p);
1.1 misho 550:
551: if (p->buf)
552: {
1.1.1.2 misho 553: free(p->buf);
554: p->buf = NULL;
1.1 misho 555: }
556:
557: free(p);
558: }
559: }
560:
561: int
1.1.1.2 misho 562: libnet_pblock_p2p(uint8_t type)
1.1 misho 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);
1.1.1.2 misho 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);
1.1 misho 583: case LIBNET_PBLOCK_IGMP_H:
584: return (IPPROTO_IGMP);
585: case LIBNET_PBLOCK_IPV4_H:
586: return (IPPROTO_IP);
1.1.1.2 misho 587: case LIBNET_PBLOCK_IPV6_H:
588: return (IPPROTO_IPV6);
1.1 misho 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
1.1.1.2 misho 609: libnet_pblock_record_ip_offset(libnet_t *l, libnet_pblock_t *p)
1.1 misho 610: {
1.1.1.2 misho 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: */
1.1 misho 616: }
617:
1.1.1.3 ! misho 618: /**
! 619: * Local Variables:
! 620: * indent-tabs-mode: nil
! 621: * c-file-style: "stroustrup"
! 622: * End:
! 623: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>