Annotation of embedaddon/libnet/src/libnet_build_tcp.c, revision 1.1.1.3

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

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