Annotation of embedaddon/libnet/src/libnet_build_icmp.c, revision 1.1.1.3
1.1 misho 1: /*
1.1.1.2 misho 2: * $Id: libnet_build_icmp.c,v 1.17 2004/04/13 17:32:28 mike Exp $
1.1 misho 3: *
4: * libnet
5: * libnet_build_icmp.c - ICMP packet assemblers
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 misho 34:
1.1.1.2 misho 35: #include <assert.h>
36:
1.1 misho 37: /* some common cruft for completing ICMP error packets */
38: #define LIBNET_BUILD_ICMP_ERR_FINISH(len) \
39: do \
40: { \
1.1.1.2 misho 41: n = libnet_pblock_append(l, p, (uint8_t *)&icmp_hdr, len); \
1.1 misho 42: if (n == -1) \
43: { \
44: goto bad; \
45: } \
46: \
1.1.1.2 misho 47: if (payload_s && !payload) \
1.1 misho 48: { \
49: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, \
1.1.1.3 ! misho 50: "%s(): payload inconsistency", __func__); \
1.1 misho 51: goto bad; \
52: } \
53: \
1.1.1.2 misho 54: if (payload_s) \
1.1 misho 55: { \
56: n = libnet_pblock_append(l, p, payload, payload_s); \
57: if (n == -1) \
58: { \
59: goto bad; \
60: } \
61: } \
62: \
63: if (sum == 0) \
64: { \
65: libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM); \
66: } \
67: } while (0)
68:
69: libnet_ptag_t
1.1.1.2 misho 70: libnet_build_icmpv4_echo(uint8_t type, uint8_t code, uint16_t sum,
71: uint16_t id, uint16_t seq, const uint8_t *payload, uint32_t payload_s,
1.1 misho 72: libnet_t *l, libnet_ptag_t ptag)
73: {
1.1.1.2 misho 74: uint32_t n, h;
1.1 misho 75: libnet_pblock_t *p;
76: struct libnet_icmpv4_hdr icmp_hdr;
77:
78: if (l == NULL)
79: {
80: return (-1);
81: }
82:
83: n = LIBNET_ICMPV4_ECHO_H + payload_s; /* size of memory block */
84: h = LIBNET_ICMPV4_ECHO_H + payload_s; /* hl for checksum */
85:
86: /*
87: * Find the existing protocol block if a ptag is specified, or create
88: * a new one.
89: */
90: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV4_ECHO_H);
91: if (p == NULL)
92: {
93: return (-1);
94: }
95:
96: memset(&icmp_hdr, 0, sizeof(icmp_hdr));
97: icmp_hdr.icmp_type = type; /* packet type */
98: icmp_hdr.icmp_code = code; /* packet code */
99: icmp_hdr.icmp_sum = (sum ? htons(sum) : 0); /* checksum */
100: icmp_hdr.icmp_id = htons(id); /* packet id */
101: icmp_hdr.icmp_seq = htons(seq); /* packet seq */
102:
1.1.1.2 misho 103: n = libnet_pblock_append(l, p, (uint8_t *)&icmp_hdr, LIBNET_ICMPV4_ECHO_H);
1.1 misho 104: if (n == -1)
105: {
106: goto bad;
107: }
108:
1.1.1.2 misho 109: /* boilerplate payload sanity check / append macro */
110: LIBNET_DO_PAYLOAD(l, p);
1.1 misho 111:
112: if (sum == 0)
113: {
114: /*
115: * If checksum is zero, by default libnet will compute a checksum
116: * for the user. The programmer can override this by calling
117: * libnet_toggle_checksum(l, ptag, 1);
118: */
119: libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
120: }
121: return (ptag ? ptag : libnet_pblock_update(l, p, h,
122: LIBNET_PBLOCK_ICMPV4_ECHO_H));
123: bad:
124: libnet_pblock_delete(l, p);
125: return (-1);
126: }
127:
128: libnet_ptag_t
1.1.1.2 misho 129: libnet_build_icmpv4_mask(uint8_t type, uint8_t code, uint16_t sum,
130: uint16_t id, uint16_t seq, uint32_t mask, const uint8_t *payload,
131: uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
1.1 misho 132: {
1.1.1.2 misho 133: uint32_t n, h;
1.1 misho 134: libnet_pblock_t *p;
135: struct libnet_icmpv4_hdr icmp_hdr;
136:
137: if (l == NULL)
138: {
139: return (-1);
140: }
141:
142: n = LIBNET_ICMPV4_MASK_H + payload_s; /* size of memory block */
143: h = LIBNET_ICMPV4_MASK_H + payload_s; /* hl for checksum */
144:
145: /*
146: * Find the existing protocol block if a ptag is specified, or create
147: * a new one.
148: */
149: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV4_MASK_H);
150: if (p == NULL)
151: {
152: return (-1);
153: }
154:
155: memset(&icmp_hdr, 0, sizeof(icmp_hdr));
156: icmp_hdr.icmp_type = type; /* packet type */
157: icmp_hdr.icmp_code = code; /* packet code */
158: icmp_hdr.icmp_sum = (sum ? htons(sum) : 0); /* checksum */
159: icmp_hdr.icmp_id = htons(id); /* packet id */
160: icmp_hdr.icmp_seq = htons(seq); /* packet seq */
161: icmp_hdr.icmp_mask = htonl(mask); /* address mask */
162:
1.1.1.2 misho 163: n = libnet_pblock_append(l, p, (uint8_t *)&icmp_hdr, LIBNET_ICMPV4_MASK_H);
1.1 misho 164: if (n == -1)
165: {
166: goto bad;
167: }
168:
1.1.1.2 misho 169: /* boilerplate payload sanity check / append macro */
170: LIBNET_DO_PAYLOAD(l, p);
1.1 misho 171:
172: if (sum == 0)
173: {
174: /*
175: * If checksum is zero, by default libnet will compute a checksum
176: * for the user. The programmer can override this by calling
177: * libnet_toggle_checksum(l, ptag, 1);
178: */
179: libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
180: }
181: return (ptag ? ptag : libnet_pblock_update(l, p, h,
182: LIBNET_PBLOCK_ICMPV4_MASK_H));
183: bad:
184: libnet_pblock_delete(l, p);
185: return (-1);
186: }
187:
188: libnet_ptag_t
1.1.1.2 misho 189: libnet_build_icmpv4_timestamp(uint8_t type, uint8_t code, uint16_t sum,
190: uint16_t id, uint16_t seq, uint32_t otime, uint32_t rtime, uint32_t ttime,
191: const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
1.1 misho 192: {
1.1.1.2 misho 193: uint32_t n, h;
1.1 misho 194: libnet_pblock_t *p;
195: struct libnet_icmpv4_hdr icmp_hdr;
196:
197: if (l == NULL)
198: {
199: return (-1);
200: }
201:
202: n = LIBNET_ICMPV4_TS_H + payload_s; /* size of memory block */
203: h = LIBNET_ICMPV4_TS_H + payload_s; /* hl for checksum */
204:
205: /*
206: * Find the existing protocol block if a ptag is specified, or create
207: * a new one.
208: */
209: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV4_TS_H);
210: if (p == NULL)
211: {
212: return (-1);
213: }
214:
215: memset(&icmp_hdr, 0, sizeof(icmp_hdr));
216: icmp_hdr.icmp_type = type; /* packet type */
217: icmp_hdr.icmp_code = code; /* packet code */
218: icmp_hdr.icmp_sum = (sum ? htons(sum) : 0); /* checksum */
219: icmp_hdr.icmp_id = htons(id); /* packet id */
220: icmp_hdr.icmp_seq = htons(seq); /* packet seq */
221: icmp_hdr.icmp_otime = htonl(otime); /* original timestamp */
222: icmp_hdr.icmp_rtime = htonl(rtime); /* receive timestamp */
223: icmp_hdr.icmp_ttime = htonl(ttime); /* transmit timestamp */
224:
1.1.1.2 misho 225: n = libnet_pblock_append(l, p, (uint8_t *)&icmp_hdr, LIBNET_ICMPV4_TS_H);
1.1 misho 226: if (n == -1)
227: {
228: goto bad;
229: }
230:
1.1.1.2 misho 231: /* boilerplate payload sanity check / append macro */
232: LIBNET_DO_PAYLOAD(l, p);
1.1 misho 233:
234: if (sum == 0)
235: {
236: /*
237: * If checksum is zero, by default libnet will compute a checksum
238: * for the user. The programmer can override this by calling
239: * libnet_toggle_checksum(l, ptag, 1);
240: */
241: libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
242: }
243: return (ptag ? ptag : libnet_pblock_update(l, p, h,
244: LIBNET_PBLOCK_ICMPV4_TS_H));
245: bad:
246: libnet_pblock_delete(l, p);
247: return (-1);
248: }
249:
250: libnet_ptag_t
1.1.1.2 misho 251: libnet_build_icmpv4_unreach(uint8_t type, uint8_t code, uint16_t sum,
252: const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
1.1 misho 253: {
1.1.1.2 misho 254: uint32_t n, h;
1.1 misho 255: libnet_pblock_t *p;
256: struct libnet_icmpv4_hdr icmp_hdr;
257:
258: if (l == NULL)
259: {
260: return (-1);
261: }
262: n = LIBNET_ICMPV4_UNREACH_H + payload_s; /* size of memory block */
263:
264: /*
265: * FREDRAYNAL: as ICMP checksum includes what is embedded in
266: * the payload, and what is after the ICMP header, we need to include
267: * those 2 sizes.
268: */
269: h = LIBNET_ICMPV4_UNREACH_H + payload_s + l->total_size;
270:
271: /*
272: * Find the existing protocol block if a ptag is specified, or create
273: * a new one.
274: */
275: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV4_UNREACH_H);
276: if (p == NULL)
277: {
278: return (-1);
279: }
280:
281: memset(&icmp_hdr, 0, sizeof(icmp_hdr));
282: icmp_hdr.icmp_type = type; /* packet type */
283: icmp_hdr.icmp_code = code; /* packet code */
284: icmp_hdr.icmp_sum = (sum ? htons(sum) : 0); /* checksum */
285: icmp_hdr.icmp_id = 0; /* must be 0 */
286: icmp_hdr.icmp_seq = 0; /* must be 0 */
287:
288: LIBNET_BUILD_ICMP_ERR_FINISH(LIBNET_ICMPV4_UNREACH_H);
289:
290: return (ptag ? ptag : libnet_pblock_update(l, p, h,
291: LIBNET_PBLOCK_ICMPV4_UNREACH_H));
292: bad:
293: libnet_pblock_delete(l, p);
294: return (-1);
295: }
296:
297: libnet_ptag_t
1.1.1.2 misho 298: libnet_build_icmpv4_timeexceed(uint8_t type, uint8_t code, uint16_t sum,
299: const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
1.1 misho 300: {
1.1.1.2 misho 301: uint32_t n, h;
1.1 misho 302: libnet_pblock_t *p;
303: struct libnet_icmpv4_hdr icmp_hdr;
304:
305: if (l == NULL)
306: {
307: return (-1);
308: }
309:
310: /* size of memory block */
1.1.1.2 misho 311: n = LIBNET_ICMPV4_TIMXCEED_H + payload_s;
1.1 misho 312: /*
313: * FREDRAYNAL: as ICMP checksum includes what is embedded in
314: * the payload, and what is after the ICMP header, we need to include
315: * those 2 sizes.
316: */
317: h = LIBNET_ICMPV4_TIMXCEED_H + payload_s + l->total_size;
318:
319: /*
320: * Find the existing protocol block if a ptag is specified, or create
321: * a new one.
322: */
323: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV4_TIMXCEED_H);
324: if (p == NULL)
325: {
326: return (-1);
327: }
328:
329: memset(&icmp_hdr, 0, sizeof(icmp_hdr));
330: icmp_hdr.icmp_type = type; /* packet type */
331: icmp_hdr.icmp_code = code; /* packet code */
332: icmp_hdr.icmp_sum = (sum ? htons(sum) : 0); /* checksum */
333: icmp_hdr.icmp_id = 0; /* must be 0 */
334: icmp_hdr.icmp_seq = 0; /* must be 0 */
335:
336: LIBNET_BUILD_ICMP_ERR_FINISH(LIBNET_ICMPV4_TIMXCEED_H);
337:
338: return (ptag ? ptag : libnet_pblock_update(l, p, h,
339: LIBNET_PBLOCK_ICMPV4_TIMXCEED_H));
340: bad:
341: libnet_pblock_delete(l, p);
342: return (-1);
343: }
344:
345: libnet_ptag_t
1.1.1.2 misho 346: libnet_build_icmpv4_redirect(uint8_t type, uint8_t code, uint16_t sum,
347: uint32_t gateway, const uint8_t *payload, uint32_t payload_s, libnet_t *l,
1.1 misho 348: libnet_ptag_t ptag)
349:
350: {
1.1.1.2 misho 351: uint32_t n, h;
1.1 misho 352: libnet_pblock_t *p;
353: struct libnet_icmpv4_hdr icmp_hdr;
354:
355: if (l == NULL)
356: {
357: return (-1);
358: }
359:
1.1.1.2 misho 360: n = LIBNET_ICMPV4_REDIRECT_H + payload_s; /* size of memory block */
1.1 misho 361: /*
362: * FREDRAYNAL: as ICMP checksum includes what is embedded in
363: * the payload, and what is after the ICMP header, we need to include
364: * those 2 sizes.
365: */
366: h = LIBNET_ICMPV4_REDIRECT_H + payload_s + l->total_size;
367:
368: /*
369: * Find the existing protocol block if a ptag is specified, or create
370: * a new one.
371: */
372: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV4_REDIRECT_H);
373: if (p == NULL)
374: {
375: return (-1);
376: }
377:
378: memset(&icmp_hdr, 0, sizeof(icmp_hdr));
379: icmp_hdr.icmp_type = type; /* packet type */
380: icmp_hdr.icmp_code = code; /* packet code */
381: icmp_hdr.icmp_sum = (sum ? htons(sum) : 0); /* checksum */
382: icmp_hdr.hun.gateway = gateway;
383:
384: LIBNET_BUILD_ICMP_ERR_FINISH(LIBNET_ICMPV4_REDIRECT_H);
385:
386: return (ptag ? ptag : libnet_pblock_update(l, p, h,
387: LIBNET_PBLOCK_ICMPV4_REDIRECT_H));
388: bad:
389: libnet_pblock_delete(l, p);
390: return (-1);
391: }
392:
1.1.1.2 misho 393:
394: libnet_ptag_t
395: libnet_build_icmpv6_common(
396: uint8_t type, uint8_t code, uint16_t sum,
397: const void* specific, uint32_t specific_s, uint8_t pblock_type,
398: uint8_t *payload, uint32_t payload_s,
399: libnet_t *l, libnet_ptag_t ptag
400: )
401: {
402: uint32_t n;
403: libnet_pblock_t *p;
404: struct libnet_icmpv6_hdr icmp_hdr;
405:
406: if (l == NULL)
407: {
408: return (-1);
409: }
410:
411: n = LIBNET_ICMPV6_COMMON_H + specific_s + payload_s;
412:
413: p = libnet_pblock_probe(l, ptag, n, pblock_type);
414:
415: if (p == NULL)
416: {
417: return (-1);
418: }
419:
420: memset(&icmp_hdr, 0, sizeof(icmp_hdr));
421: icmp_hdr.icmp_type = type;
422: icmp_hdr.icmp_code = code;
423: icmp_hdr.icmp_sum = htons(sum);
424:
425: if (libnet_pblock_append(l, p, (uint8_t *)&icmp_hdr, LIBNET_ICMPV6_COMMON_H) < 0)
426: {
427: goto bad;
428: }
429:
430: if (libnet_pblock_append(l, p, specific, specific_s) < 0)
431: {
432: goto bad;
433: }
434:
435: if (libnet_pblock_append(l, p, payload, payload_s) < 0)
436: {
437: goto bad;
438: }
439:
440: if (sum == 0)
441: {
442: libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
443: }
444:
445: return ptag ? ptag : libnet_pblock_update(l, p, 0, pblock_type);
446:
447: bad:
448: libnet_pblock_delete(l, p);
449:
450: return -1;
451: }
452:
453: libnet_ptag_t libnet_build_icmpv6(uint8_t type, uint8_t code, uint16_t sum,
454: uint8_t* payload, uint32_t payload_s,
455: libnet_t* l, libnet_ptag_t ptag)
456: {
457: return libnet_build_icmpv6_common(
458: type, code, sum,
459: NULL, 0, LIBNET_PBLOCK_ICMPV6_UNREACH_H,
460: payload, payload_s,
461: l, ptag);
462: }
463:
464: libnet_ptag_t
465: libnet_build_icmpv6_unreach(
466: uint8_t type, uint8_t code, uint16_t sum,
467: uint8_t *payload, uint32_t payload_s,
468: libnet_t *l, libnet_ptag_t ptag
469: )
470: {
471: struct libnet_icmpv6_unreach specific;
472:
473: memset(&specific, 0, sizeof(specific));
474:
475: return libnet_build_icmpv6_common(
476: type, code, sum,
477: &specific, sizeof(specific), LIBNET_PBLOCK_ICMPV6_UNREACH_H,
478: payload, payload_s,
479: l, ptag);
480: }
481:
482: libnet_ptag_t
483: libnet_build_icmpv6_echo(
484: uint8_t type, uint8_t code, uint16_t sum,
485: uint16_t id, uint16_t seq,
486: uint8_t *payload, uint32_t payload_s,
487: libnet_t *l, libnet_ptag_t ptag
488: )
489: {
490: struct libnet_icmpv6_echo specific;
491:
492: memset(&specific, 0, sizeof(specific));
493: specific.id = htons(id);
494: specific.seq = htons(seq);
495:
496: return libnet_build_icmpv6_common(
497: type, code, sum,
498: &specific, sizeof(specific), LIBNET_PBLOCK_ICMPV6_ECHO_H,
499: payload, payload_s,
500: l, ptag);
501: }
502:
503:
504: libnet_ptag_t libnet_build_icmpv6_ndp_nsol(
505: uint8_t type, uint8_t code, uint16_t sum,
506: struct libnet_in6_addr target,
507: uint8_t *payload, uint32_t payload_s,
508: libnet_t* l, libnet_ptag_t ptag)
509: {
510: struct libnet_icmpv6_ndp_nsol specific;
511:
512: memset(&specific, 0, sizeof(specific));
513: specific.reserved = 0;
514: specific.target_addr = target;
515:
516: return libnet_build_icmpv6_common(
517: type, code, sum,
518: &specific, sizeof(specific), LIBNET_PBLOCK_ICMPV6_NDP_NSOL_H,
519: payload, payload_s,
520: l, ptag);
521: }
522:
523:
524: libnet_ptag_t libnet_build_icmpv6_ndp_nadv(
525: uint8_t type, uint8_t code, uint16_t sum,
526: uint32_t flags, struct libnet_in6_addr target,
527: uint8_t *payload, uint32_t payload_s,
528: libnet_t* l, libnet_ptag_t ptag)
529: {
530:
531: struct libnet_icmpv6_ndp_nadv specific;
532:
533: memset(&specific, 0, sizeof(specific));
534: specific.flags = htonl(flags);
535: specific.target_addr = target;
536:
537: return libnet_build_icmpv6_common(
538: type, code, sum,
539: &specific, sizeof(specific), LIBNET_PBLOCK_ICMPV6_NDP_NADV_H,
540: payload, payload_s,
541: l, ptag);
542: }
543:
544: libnet_ptag_t libnet_build_icmpv6_ndp_opt(
545: uint8_t type, uint8_t* option, uint32_t option_s,
546: libnet_t* l, libnet_ptag_t ptag)
547: {
548: struct libnet_icmpv6_ndp_opt opt;
549: uint32_t n;
550: static uint8_t pad[8] = { 0 };
551: uint32_t pad_s = 0;
552: libnet_pblock_t* p;
553:
554: if(l == NULL)
555: return -1;
556:
557: if(!option)
558: option_s = 0;
559:
560: /* options need to be padded to a multiple of 8-bytes, and opts.len is in units of 8-bytes */
561: n = sizeof(opt) + option_s;
562:
563: if(n % 8)
564: {
565: n += 8 - (n % 8);
566: }
567:
568: if(n > (0xff * 8))
569: {
570: return -1;
571: }
572:
573: pad_s = n - option_s - sizeof(opt);
574:
575: assert((n % 8) == 0);
576: assert(pad_s < sizeof(pad));
577:
578: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_ICMPV6_NDP_OPT_H);
579: if(p == NULL)
580: return -1;
581:
582: memset(&opt, 0, sizeof(opt));
583: opt.type = type;
584: opt.len = n / 8;
585:
586: if(libnet_pblock_append(l, p, &opt, sizeof(opt)) == -1)
587: goto bad;
588:
589: if(libnet_pblock_append(l, p, option, option_s) == -1)
590: goto bad;
591:
592: if(libnet_pblock_append(l, p, pad, pad_s) == -1)
593: goto bad;
594:
595: return ptag ? ptag : libnet_pblock_update(l, p, n, LIBNET_PBLOCK_ICMPV6_NDP_OPT_H);
596:
597: bad:
598: libnet_pblock_delete(l, p);
599: return -1;
600: }
601:
1.1.1.3 ! misho 602: /**
! 603: * Local Variables:
! 604: * indent-tabs-mode: nil
! 605: * c-file-style: "stroustrup"
! 606: * End:
! 607: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>