File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_build_tcp.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 11:54:42 2013 UTC (10 years, 11 months ago) by misho
Branches: libnet, MAIN
CVS tags: v1_1_6p5, v1_1_6p4, v1_1_6p0, v1_1_6, HEAD
1.1.6

    1: /*
    2:  *  $Id: libnet_build_tcp.c,v 1.1.1.2 2013/07/22 11:54:42 misho Exp $
    3:  *
    4:  *  libnet
    5:  *  libnet_build_tcp.c - TCP packet assembler
    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_ptag_t
   43: libnet_build_tcp(
   44:             uint16_t sp, uint16_t dp, uint32_t seq, uint32_t ack,
   45:             uint8_t control, uint16_t win, uint16_t sum, uint16_t urg, uint16_t h_len,
   46:             const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
   47: {
   48:     int n, offset;
   49:     libnet_pblock_t *p = NULL;
   50:     libnet_ptag_t ptag_data = 0;
   51:     struct libnet_tcp_hdr tcp_hdr;
   52: 
   53:     if (l == NULL)
   54:         return -1;
   55: 
   56:     if (payload_s && !payload)
   57:     {
   58:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
   59: 			    "%s(): payload inconsistency\n", __func__);
   60:         return -1;
   61:     }
   62: 
   63:     p = libnet_pblock_probe(l, ptag, LIBNET_TCP_H, LIBNET_PBLOCK_TCP_H);
   64:     if (p == NULL)
   65:         return -1;
   66: 
   67:     memset(&tcp_hdr, 0, sizeof(tcp_hdr));
   68:     tcp_hdr.th_sport   = htons(sp);    /* source port */
   69:     tcp_hdr.th_dport   = htons(dp);    /* destination port */
   70:     tcp_hdr.th_seq     = htonl(seq);   /* sequence number */
   71:     tcp_hdr.th_ack     = htonl(ack);   /* acknowledgement number */
   72:     tcp_hdr.th_flags   = control;      /* control flags */
   73:     tcp_hdr.th_x2      = 0;            /* UNUSED */
   74:     tcp_hdr.th_off     = 5;            /* 20 byte header */
   75: 
   76:     /* check to see if there are TCP options to include */
   77:     if (p->prev && p->prev->type == LIBNET_PBLOCK_TCPO_H)
   78:     {
   79:         /* Note that the tcp options pblock is already padded */
   80:         tcp_hdr.th_off += (p->prev->b_len/4);
   81:     }
   82: 
   83:     tcp_hdr.th_win     = htons(win);   /* window size */
   84:     tcp_hdr.th_sum     = (sum ? htons(sum) : 0);   /* checksum */ 
   85:     tcp_hdr.th_urp     = htons(urg);          /* urgent pointer */
   86: 
   87:     n = libnet_pblock_append(l, p, (uint8_t *)&tcp_hdr, LIBNET_TCP_H);
   88:     if (n == -1)
   89:     {
   90:         goto bad;
   91:     }
   92: 
   93:     if (ptag == LIBNET_PTAG_INITIALIZER)
   94:     {
   95:         libnet_pblock_update(l, p, h_len, LIBNET_PBLOCK_TCP_H);
   96:     }
   97: 
   98:     offset = payload_s;
   99: 
  100:     /* If we are going to modify a TCP data block, find it, and figure out the
  101:      * "offset", the possibly negative amount by which we are increasing the ip
  102:      * data length. */
  103:     if (ptag)
  104:     {
  105:         libnet_pblock_t* datablock = p->prev;
  106: 
  107:         if (datablock && datablock->type == LIBNET_PBLOCK_TCPO_H)
  108:             datablock = datablock->prev;
  109: 
  110:         if (datablock && datablock->type == LIBNET_PBLOCK_TCPDATA)
  111:         {
  112:             ptag_data = datablock->ptag;
  113:             offset -=  datablock->b_len;
  114:         }
  115:         p->h_len += offset;
  116:     }
  117: 
  118:     /* If we are modifying a TCP block, we should look forward and apply the offset
  119:      * to our IPv4 header, if we have one.
  120:      */
  121:     if (p->next)
  122:     {
  123:         libnet_pblock_t* ipblock = p->next;
  124: 
  125:         if(ipblock->type == LIBNET_PBLOCK_IPO_H)
  126:             ipblock = ipblock->next;
  127: 
  128:         if(ipblock && ipblock->type == LIBNET_PBLOCK_IPV4_H)
  129:         {
  130:             struct libnet_ipv4_hdr * ip_hdr = (struct libnet_ipv4_hdr *)ipblock->buf;
  131:             int ip_len = ntohs(ip_hdr->ip_len) + offset;
  132:             ip_hdr->ip_len = htons(ip_len);
  133:         }
  134:     }
  135: 
  136:     /* if there is a payload, add it in the context */
  137:     if (payload_s)
  138:     {
  139:         /* update ptag_data with the new payload */
  140:         libnet_pblock_t* p_data = libnet_pblock_probe(l, ptag_data, payload_s, LIBNET_PBLOCK_TCPDATA);
  141:         if (!p_data)
  142:         {
  143:             goto bad;
  144:         }
  145: 
  146:         n = libnet_pblock_append(l, p_data, payload, payload_s);
  147:         if (n == -1)
  148:         {
  149:             goto bad;
  150:         }
  151: 
  152:         if (ptag_data == LIBNET_PTAG_INITIALIZER)
  153:         {
  154:             int insertbefore = p->ptag;
  155: 
  156:             /* Then we created it, and we need to shuffle it back until it's before
  157:              * the tcp header and options. */
  158:             libnet_pblock_update(l, p_data, payload_s, LIBNET_PBLOCK_TCPDATA);
  159: 
  160:             if(p->prev && p->prev->type == LIBNET_PBLOCK_TCPO_H)
  161:                 insertbefore = p->prev->ptag;
  162: 
  163:             libnet_pblock_insert_before(l, insertbefore, p_data->ptag);
  164:         }
  165:     }
  166:     else
  167:     {
  168:         libnet_pblock_t* p_data = libnet_pblock_find(l, ptag_data);
  169:         libnet_pblock_delete(l, p_data);
  170:     }
  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 (p->ptag);
  182: bad:
  183:     libnet_pblock_delete(l, p);
  184:     return (-1);
  185: }
  186: 
  187: libnet_ptag_t
  188: libnet_build_tcp_options(const uint8_t *options, uint32_t options_s, libnet_t *l, 
  189: libnet_ptag_t ptag)
  190: {
  191:     static const uint8_t padding[] = { 0 };
  192:     int n, offset, underflow;
  193:     uint32_t i, j, adj_size;
  194:     libnet_pblock_t *p, *p_temp;
  195:     struct libnet_ipv4_hdr *ip_hdr;
  196:     struct libnet_tcp_hdr *tcp_hdr;
  197: 
  198:     if (l == NULL)
  199:     { 
  200:         return (-1);
  201:     }
  202: 
  203:     underflow = 0;
  204:     offset = 0;
  205: 
  206:     /* check options list size */
  207:     if (options_s > LIBNET_MAXOPTION_SIZE)
  208:     {
  209:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  210:             "%s(): options list is too large %d\n", __func__, options_s);
  211:         return (-1);
  212:     }
  213: 
  214:     adj_size = options_s;
  215:     if (adj_size % 4)
  216:     {
  217:         /* size of memory block with padding */
  218:         adj_size += 4 - (options_s % 4);
  219:     }
  220: 
  221:     /* if this pblock already exists, determine if there is a size diff */
  222:     if (ptag)
  223:     {
  224:         p_temp = libnet_pblock_find(l, ptag);
  225:         if (p_temp)
  226:         {
  227:             if (adj_size >= p_temp->b_len)
  228:             {
  229:                 offset = adj_size - p_temp->b_len;
  230:             }
  231:             else
  232:             {
  233:                 offset = p_temp->b_len - adj_size;
  234:                 underflow = 1;
  235:             }
  236:         }
  237:     }
  238: 
  239:     /*
  240:      *  Find the existing protocol block if a ptag is specified, or create
  241:      *  a new one.
  242:      */
  243:     p = libnet_pblock_probe(l, ptag, adj_size, LIBNET_PBLOCK_TCPO_H);
  244:     if (p == NULL)
  245:     {
  246:         return (-1);
  247:     }
  248: 
  249:     n = libnet_pblock_append(l, p, options, options_s);
  250:     if (n == -1)
  251:     {
  252:         goto bad;
  253:     }
  254: 
  255:     n = libnet_pblock_append(l, p, padding, adj_size - options_s);
  256:     if (n == -1)
  257:     {
  258:         goto bad;
  259:     }
  260: 
  261:     if (ptag && p->next)
  262:     {
  263:         p_temp = p->next;
  264:         while ((p_temp->next) && (p_temp->type != LIBNET_PBLOCK_TCP_H))
  265:         {
  266:            p_temp = p_temp->next;
  267:         }
  268:         if (p_temp->type == LIBNET_PBLOCK_TCP_H)
  269:         {
  270:             /*
  271:              *  Count up number of 32-bit words in options list, padding if
  272:              *  neccessary.
  273:              */
  274:             for (i = 0, j = 0; i < p->b_len; i++)
  275:             {
  276:                 (i % 4) ? j : j++;
  277:             }
  278:             tcp_hdr = (struct libnet_tcp_hdr *)p_temp->buf;
  279:             tcp_hdr->th_off = j + 5;
  280:             if (!underflow)
  281:             {
  282:                 p_temp->h_len += offset;
  283:             }
  284:             else
  285:             {
  286:                 p_temp->h_len -= offset;
  287:             }
  288:         }
  289:         while ((p_temp->next) && (p_temp->type != LIBNET_PBLOCK_IPV4_H))
  290:         {
  291:             p_temp = p_temp->next;
  292:         }
  293:         if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
  294:         {
  295:             ip_hdr = (struct libnet_ipv4_hdr *)p_temp->buf;
  296:             if (!underflow)
  297:             {
  298:                 ip_hdr->ip_len += htons(offset);
  299:             }
  300:             else
  301:             {
  302:                 ip_hdr->ip_len -= htons(offset);
  303:             }
  304:         }
  305:     }
  306: 
  307:     return (ptag ? ptag : libnet_pblock_update(l, p, adj_size,
  308:             LIBNET_PBLOCK_TCPO_H));
  309: bad:
  310:     libnet_pblock_delete(l, p);
  311:     return (-1);
  312: }
  313: 
  314: /* EOF */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>