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