File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_build_gre.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:14:23 2012 UTC (12 years, 4 months ago) by misho
Branches: libnet, MAIN
CVS tags: v1_1_2_1, HEAD
libnet

    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>