Annotation of embedaddon/libnet/src/libnet_build_gre.c, revision 1.1
1.1 ! misho 1: /*
! 2: * libnet
! 3: * libnet_build_gre.c - GRE packet assembler
! 4: *
! 5: * Copyright (c) 2003 Frédéric Raynal <pappy@security-labs.org>
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: *
! 29: */
! 30:
! 31: #if (HAVE_CONFIG_H)
! 32: #include "../include/config.h"
! 33: #endif
! 34: #if (!(_WIN32) || (__CYGWIN__))
! 35: #include "../include/libnet.h"
! 36: #else
! 37: #include "../include/win32/libnet.h"
! 38: #endif
! 39:
! 40: /*
! 41: * Overall packet
! 42: *
! 43: * The entire encapsulated packet would then have the form:
! 44: *
! 45: * ---------------------------------
! 46: * | |
! 47: * | Delivery Header |
! 48: * | |
! 49: * ---------------------------------
! 50: * | |
! 51: * | GRE Header |
! 52: * | |
! 53: * ---------------------------------
! 54: * | |
! 55: * | Payload packet |
! 56: * | |
! 57: * ---------------------------------
! 58: *
! 59: * RFC 1701 defines a header.
! 60: * A new RFC (2784) has changed the header and proposed to remove the key
! 61: * and seqnum.
! 62: * A newer RFC (2890) has changed the header proposed in RFC 2784 by putting
! 63: * back key and seqnum.
! 64: * These will be supported the day IETF'guys stop this mess !
! 65: *
! 66: * FR
! 67: */
! 68:
! 69:
! 70: /*
! 71: * Generic Routing Encapsulation (GRE)
! 72: * RFC 1701 http://www.faqs.org/rfcs/rfc1701.html
! 73: *
! 74: *
! 75: * Packet header
! 76: *
! 77: * The GRE packet header has the form:
! 78: *
! 79: * 0 1 2 3
! 80: * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
! 81: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 82: * |C|R|K|S|s|Recur| Flags | Ver | Protocol Type |
! 83: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 84: * | Checksum (optional) | Offset (optional) |
! 85: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 86: * | Key (optional) |
! 87: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 88: * | Sequence Number (optional) |
! 89: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 90: * | Routing (optional) |
! 91: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 92: *
! 93: * Enhanced GRE header
! 94: *
! 95: * See rfc 2637 for details. It is used for PPTP tunneling.
! 96: *
! 97: * 0 1 2 3
! 98: * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
! 99: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 100: * |C|R|K|S|s|Recur|A| Flags | Ver | Protocol Type |
! 101: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 102: * | Key (HW) Payload Length | Key (LW) Call ID |
! 103: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 104: * | Sequence Number (Optional) |
! 105: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 106: * | Acknowledgment Number (Optional) |
! 107: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 108: *
! 109: */
! 110:
! 111: static inline void
! 112: __libnet_print_gre_flags_ver(u_int16_t fv)
! 113: {
! 114: printf("version = %d (%d) -> ",
! 115: fv & GRE_VERSION_MASK, libnet_getgre_length(fv));
! 116: if (fv & GRE_CSUM)
! 117: {
! 118: printf("CSUM ");
! 119: }
! 120: if (fv & GRE_ROUTING)
! 121: {
! 122: printf("ROUTING ");
! 123: }
! 124: if (fv & GRE_KEY)
! 125: {
! 126: printf("KEY ");
! 127: }
! 128: if (fv & GRE_SEQ)
! 129: {
! 130: printf("SEQ ");
! 131: }
! 132: if (fv & GRE_ACK)
! 133: {
! 134: printf("ACK ");
! 135: }
! 136: printf("\n");
! 137: }
! 138:
! 139:
! 140: /* FIXME: what is the portability of the "((struct libnet_gre_hdr*)0)->" ? */
! 141: inline u_int32_t
! 142: libnet_getgre_length(u_int16_t fv)
! 143: {
! 144:
! 145: u_int32_t n = LIBNET_GRE_H;
! 146: /*
! 147: * If either the Checksum Present bit or the Routing Present bit are
! 148: * set, BOTH the Checksum and Offset fields are present in the GRE
! 149: * packet.
! 150: */
! 151:
! 152: if ((!(fv & GRE_VERSION_MASK) && (fv & (GRE_CSUM|GRE_ROUTING))) || /* v0 */
! 153: (fv & GRE_VERSION_MASK) ) /* v1 */
! 154: {
! 155: n += sizeof( ((struct libnet_gre_hdr *)0)->gre_sum) +
! 156: sizeof( ((struct libnet_gre_hdr *)0)->gre_offset);
! 157: }
! 158:
! 159: if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_KEY)) || /* v0 */
! 160: ( (fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) ) /* v1 */
! 161: {
! 162: n += sizeof( ((struct libnet_gre_hdr *)0)->gre_key);
! 163: }
! 164:
! 165: if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) || /* v0 */
! 166: ( (fv & GRE_VERSION_MASK) && (fv & GRE_ACK)) ) /* v1 */
! 167: {
! 168: n += sizeof( ((struct libnet_gre_hdr *)0)->gre_seq );
! 169: }
! 170:
! 171: return (n);
! 172: }
! 173:
! 174: libnet_ptag_t
! 175: libnet_build_gre(u_int16_t fv, u_int16_t type, u_int16_t sum,
! 176: u_int16_t offset, u_int32_t key, u_int32_t seq, u_int16_t len,
! 177: u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
! 178: {
! 179: u_int32_t n;
! 180: libnet_pblock_t *p;
! 181: struct libnet_gre_hdr gre_hdr;
! 182:
! 183: if (l == NULL)
! 184: {
! 185: return (-1);
! 186: }
! 187:
! 188: n = libnet_getgre_length(fv) + payload_s;
! 189:
! 190: /*
! 191: * Find the existing protocol block if a ptag is specified, or create
! 192: * a new one.
! 193: */
! 194: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_GRE_H);
! 195: if (p == NULL)
! 196: {
! 197: return (-1);
! 198: }
! 199:
! 200: gre_hdr.flags_ver = htons(fv);
! 201: gre_hdr.type = htons(type);
! 202: n = libnet_pblock_append(l, p, (u_int8_t *)&gre_hdr, LIBNET_GRE_H);
! 203: if (n == -1)
! 204: {
! 205: /* err msg set in libnet_pblock_append() */
! 206: goto bad;
! 207: }
! 208:
! 209: if ((!(fv & GRE_VERSION_MASK) && (fv & (GRE_CSUM|GRE_ROUTING))) || /* v0 */
! 210: (fv & GRE_VERSION_MASK)) /* v1 */
! 211: {
! 212: sum = htons(sum);
! 213: n = libnet_pblock_append(l, p, (u_int8_t*)&sum,
! 214: sizeof(gre_hdr.gre_sum));
! 215: if (n == -1)
! 216: {
! 217: /* err msg set in libnet_pblock_append() */
! 218: goto bad;
! 219: }
! 220: offset = htons(offset);
! 221: n = libnet_pblock_append(l, p, (u_int8_t*)&offset,
! 222: sizeof(gre_hdr.gre_offset));
! 223: if (n == -1)
! 224: {
! 225: /* err msg set in libnet_pblock_append() */
! 226: goto bad;
! 227: }
! 228: }
! 229:
! 230: if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_KEY)) || /* v0 */
! 231: ( (fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) ) /* v1 */
! 232: {
! 233: key = htonl(key);
! 234: n = libnet_pblock_append(l, p, (u_int8_t*)&key,
! 235: sizeof(gre_hdr.gre_key));
! 236: if (n == -1)
! 237: {
! 238: /* err msg set in libnet_pblock_append() */
! 239: goto bad;
! 240: }
! 241: }
! 242:
! 243: if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) || /* v0 */
! 244: ( (fv & GRE_VERSION_MASK) && (fv & GRE_ACK)) ) /* v1 */
! 245: {
! 246: seq = htonl(seq);
! 247: n = libnet_pblock_append(l, p, (u_int8_t*)&seq,
! 248: sizeof(gre_hdr.gre_seq));
! 249: if (n == -1)
! 250: {
! 251: /* err msg set in libnet_pblock_append() */
! 252: goto bad;
! 253: }
! 254: }
! 255:
! 256: if ((payload && !payload_s) || (!payload && payload_s))
! 257: {
! 258: sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
! 259: goto bad;
! 260: }
! 261:
! 262: if (payload && payload_s)
! 263: {
! 264: n = libnet_pblock_append(l, p, payload, payload_s);
! 265: if (n == -1)
! 266: {
! 267: /* err msg set in libnet_pblock_append() */
! 268: goto bad;
! 269: }
! 270: }
! 271:
! 272: if ( (fv & GRE_CSUM) && (!sum) )
! 273: {
! 274: libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
! 275: }
! 276:
! 277: return (ptag ? ptag : libnet_pblock_update(l, p, len, LIBNET_PBLOCK_GRE_H));
! 278:
! 279: bad:
! 280: libnet_pblock_delete(l, p);
! 281: return (-1);
! 282: }
! 283:
! 284: libnet_ptag_t
! 285: libnet_build_egre(u_int16_t fv, u_int16_t type, u_int16_t sum,
! 286: u_int16_t offset, u_int32_t key, u_int32_t seq, u_int16_t len,
! 287: u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
! 288: {
! 289: return (libnet_build_gre(fv, type, sum, offset, key, seq, len,
! 290: payload, payload_s, l, ptag));
! 291: }
! 292:
! 293: /*
! 294: * Routing (variable)
! 295: *
! 296: * The Routing field is optional and is present only if the Routing
! 297: * Present bit is set to 1.
! 298: *
! 299: * The Routing field is a list of Source Route Entries (SREs). Each
! 300: * SRE has the form:
! 301: *
! 302: * 0 1 2 3
! 303: * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
! 304: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 305: * | Address Family | SRE Offset | SRE Length |
! 306: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 307: * | Routing Information ...
! 308: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 309: *
! 310: */
! 311: libnet_ptag_t
! 312: libnet_build_gre_sre(u_int16_t af, u_int8_t offset, u_int8_t length,
! 313: u_int8_t *routing, u_int8_t *payload, u_int32_t payload_s, libnet_t *l,
! 314: libnet_ptag_t ptag)
! 315: {
! 316: u_int32_t n;
! 317: libnet_pblock_t *p;
! 318: struct libnet_gre_sre_hdr sre_hdr;
! 319:
! 320: if (l == NULL)
! 321: {
! 322: return (-1);
! 323: }
! 324:
! 325: n = LIBNET_GRE_SRE_H + length + payload_s;
! 326:
! 327: /*
! 328: * Find the existing protocol block if a ptag is specified, or create
! 329: * a new one.
! 330: */
! 331: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_GRE_SRE_H);
! 332: if (p == NULL)
! 333: {
! 334: return (-1);
! 335: }
! 336: sre_hdr.af = htons(af);
! 337: sre_hdr.sre_offset = offset;
! 338: sre_hdr.sre_length = length;
! 339: n = libnet_pblock_append(l, p, (u_int8_t *)&sre_hdr, LIBNET_GRE_SRE_H);
! 340: if (n == -1)
! 341: {
! 342: /* err msg set in libnet_pblock_append() */
! 343: goto bad;
! 344: }
! 345:
! 346: if ((routing && !length) || (!routing && length))
! 347: {
! 348: sprintf(l->err_buf, "%s(): routing inconsistency\n", __func__);
! 349: goto bad;
! 350: }
! 351:
! 352: if (routing && length)
! 353: {
! 354: n = libnet_pblock_append(l, p, routing, length);
! 355: if (n == -1)
! 356: {
! 357: /* err msg set in libnet_pblock_append() */
! 358: goto bad;
! 359: }
! 360: }
! 361:
! 362: if ((payload && !payload_s) || (!payload && payload_s))
! 363: {
! 364: sprintf(l->err_buf, "%s(): payload inconsistency\n", __func__);
! 365: goto bad;
! 366: }
! 367:
! 368: if (payload && payload_s)
! 369: {
! 370: n = libnet_pblock_append(l, p, payload, payload_s);
! 371: if (n == -1)
! 372: {
! 373: /* err msg set in libnet_pblock_append() */
! 374: goto bad;
! 375: }
! 376: }
! 377:
! 378: return (ptag ? ptag : libnet_pblock_update(l, p, 0,
! 379: LIBNET_PBLOCK_GRE_SRE_H));
! 380:
! 381: bad:
! 382: libnet_pblock_delete(l, p);
! 383: return (-1);
! 384:
! 385: }
! 386:
! 387: libnet_ptag_t
! 388: libnet_build_gre_last_sre(libnet_t *l, libnet_ptag_t ptag)
! 389: {
! 390: u_int32_t n, zero = 0;
! 391: libnet_pblock_t *p;
! 392:
! 393: if (l == NULL)
! 394: {
! 395: return (-1);
! 396: }
! 397:
! 398: n = LIBNET_GRE_SRE_H;
! 399:
! 400: /*
! 401: * Find the existing protocol block if a ptag is specified, or create
! 402: * a new one.
! 403: */
! 404: p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_GRE_H);
! 405: if (p == NULL)
! 406: {
! 407: return (-1);
! 408: }
! 409:
! 410: n = libnet_pblock_append(l, p, (u_int8_t *)&zero, LIBNET_GRE_SRE_H);
! 411: if (n == -1)
! 412: {
! 413: /* err msg set in libnet_pblock_append() */
! 414: goto bad;
! 415: }
! 416:
! 417: return (ptag ? ptag : libnet_pblock_update(l, p, 0,
! 418: LIBNET_PBLOCK_GRE_SRE_H));
! 419:
! 420: bad:
! 421: libnet_pblock_delete(l, p);
! 422: return (-1);
! 423:
! 424: }
! 425:
! 426:
! 427: /* EOF */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>