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>