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

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: 
                     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(u_int16_t sp, u_int16_t dp, u_int32_t seq, u_int32_t ack,
                     44: u_int8_t control, u_int16_t win, u_int16_t sum, u_int16_t urg, u_int16_t len,
                     45: u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
                     46: {
                     47:     int n, offset;
                     48:     u_int32_t i, j;
                     49:     libnet_pblock_t *p, *p_data, *p_temp;
                     50:     libnet_ptag_t ptag_hold, ptag_data;
                     51:     struct libnet_tcp_hdr tcp_hdr;
                     52:     struct libnet_ipv4_hdr *ip_hdr;
                     53: 
                     54:     if (l == NULL)
                     55:     { 
                     56:         return (-1);
                     57:     } 
                     58: 
                     59:     ptag_data = 0;                      /* for possible options */
                     60: 
                     61:     /*
                     62:      *  Find the existing protocol block if a ptag is specified, or create
                     63:      *  a new one.
                     64:      */
                     65:     p = libnet_pblock_probe(l, ptag, LIBNET_TCP_H, LIBNET_PBLOCK_TCP_H);
                     66:     if (p == NULL)
                     67:     {
                     68:         return (-1);
                     69:     }
                     70: 
                     71:     memset(&tcp_hdr, 0, sizeof(tcp_hdr));
                     72:     tcp_hdr.th_sport   = htons(sp);    /* source port */
                     73:     tcp_hdr.th_dport   = htons(dp);    /* destination port */
                     74:     tcp_hdr.th_seq     = htonl(seq);   /* sequence number */
                     75:     tcp_hdr.th_ack     = htonl(ack);   /* acknowledgement number */
                     76:     tcp_hdr.th_flags   = control;      /* control flags */
                     77:     tcp_hdr.th_x2      = 0;            /* UNUSED */
                     78:     tcp_hdr.th_off     = 5;            /* 20 byte header */
                     79: 
                     80:     /* check to see if there are TCP options to include */
                     81:     if (p->prev)
                     82:     {
                     83:         p_temp = p->prev;
                     84:         while ((p_temp->prev) && (p_temp->type != LIBNET_PBLOCK_TCPO_H))
                     85:         {
                     86:             p_temp = p_temp->prev;
                     87:         }
                     88:         if (p_temp->type == LIBNET_PBLOCK_TCPO_H)
                     89:         {
                     90:             /*
                     91:              *  Count up number of 32-bit words in options list, padding if
                     92:              *  neccessary.
                     93:              */
                     94:             for (i = 0, j = 0; i < p_temp->b_len; i++)
                     95:             {
                     96:                 (i % 4) ? j : j++;
                     97:             }
                     98:             tcp_hdr.th_off += j;
                     99:         }
                    100:     }
                    101: 
                    102:     tcp_hdr.th_win     = htons(win);   /* window size */
                    103:     tcp_hdr.th_sum     = (sum ? htons(sum) : 0);   /* checksum */ 
                    104:     tcp_hdr.th_urp     = htons(urg);          /* urgent pointer */
                    105: 
                    106:     n = libnet_pblock_append(l, p, (u_int8_t *)&tcp_hdr, LIBNET_TCP_H);
                    107:     if (n == -1)
                    108:     {
                    109:         goto bad;
                    110:     }
                    111: 
                    112:     ptag_hold = ptag;
                    113:     if (ptag == LIBNET_PTAG_INITIALIZER)
                    114:     {
                    115:         ptag = libnet_pblock_update(l, p, len, LIBNET_PBLOCK_TCP_H);
                    116:     }
                    117: 
                    118:     /* find and set the appropriate ptag, or else use the default of 0 */
                    119:     offset = payload_s;
                    120:     if (ptag_hold && p->prev)
                    121:     {
                    122:         p_temp = p->prev;
                    123:         while (p_temp->prev &&
                    124:               (p_temp->type != LIBNET_PBLOCK_TCPDATA) &&
                    125:               (p_temp->type != LIBNET_PBLOCK_TCP_H))
                    126:         {
                    127:            p_temp = p_temp->prev;
                    128:         }
                    129: 
                    130:         if (p_temp->type == LIBNET_PBLOCK_TCPDATA)
                    131:         {
                    132:             ptag_data = p_temp->ptag;
                    133:             offset -=  p_temp->b_len;
                    134:             p->h_len += offset;
                    135:         }
                    136:         else
                    137:         {
                    138:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                    139:                                    "%s(): TCP data pblock not found\n", __func__);
                    140:         }
                    141:      }
                    142: 
                    143:     /* update ip_len if present */
                    144:     if (ptag_hold && p->next)
                    145:     {
                    146:         p_temp = p->next;
                    147:         while (p_temp->next && (p_temp->type != LIBNET_PBLOCK_IPV4_H))
                    148:         {
                    149:             p_temp = p_temp->next;
                    150:         }
                    151:         if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
                    152:         {
                    153:             ip_hdr = (struct libnet_ipv4_hdr *)p_temp->buf;
                    154:             n = ntohs(ip_hdr->ip_len) + offset;
                    155:             ip_hdr->ip_len = htons(n);
                    156:         }
                    157:     }
                    158: 
                    159:     if ((payload && !payload_s) || (!payload && payload_s))
                    160:     {
                    161:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                    162:                            "%s(): payload inconsistency\n", __func__);
                    163:         goto bad;
                    164:     }
                    165: 
                    166:     /* if there is a payload, add it in the context */
                    167:     if (payload && payload_s)
                    168:     {
                    169:         /* update ptag_data with the new payload */
                    170:         p_data = libnet_pblock_probe(l, ptag_data, payload_s,
                    171:                 LIBNET_PBLOCK_TCPDATA);
                    172:         if (p_data == NULL) 
                    173:         {
                    174:             return (-1);
                    175:         }
                    176: 
                    177:         if (libnet_pblock_append(l, p_data, payload, payload_s) == -1)
                    178:         {
                    179:             goto bad;
                    180:         }
                    181: 
                    182:         if (ptag_data == LIBNET_PTAG_INITIALIZER)
                    183:         {
                    184:             if (p_data->prev->type == LIBNET_PBLOCK_TCP_H)
                    185:             {
                    186:                 libnet_pblock_update(l, p_data, payload_s,
                    187:                         LIBNET_PBLOCK_TCPDATA);
                    188:                 /* swap pblocks to correct the protocol order */
                    189:                 libnet_pblock_swap(l, p->ptag, p_data->ptag);
                    190:             }
                    191:             else
                    192:             {
                    193:                 /* update without setting this as the final pblock */
                    194:                 p_data->type  =  LIBNET_PBLOCK_TCPDATA;
                    195:                 p_data->ptag  =  ++(l->ptag_state);
                    196:                 p_data->h_len =  payload_s;
                    197: 
                    198:                 /* Adjust h_len for checksum. */
                    199:                 p->h_len += payload_s;
                    200: 
                    201:                 /* data was added after the initial construction */
                    202:                 for (p_temp = l->protocol_blocks;
                    203:                         p_temp->type == LIBNET_PBLOCK_TCP_H ||
                    204:                         p_temp->type == LIBNET_PBLOCK_TCPO_H;
                    205:                         p_temp = p_temp->next)
                    206:                 {
                    207:                     libnet_pblock_insert_before(l, p_temp->ptag, p_data->ptag);
                    208:                     break;
                    209:                 }
                    210:                 /* The end block needs to have its next pointer cleared. */
                    211:                 l->pblock_end->next = NULL;
                    212:             }
                    213: 
                    214:             if (p_data->prev && p_data->prev->type == LIBNET_PBLOCK_TCPO_H)
                    215:             {
                    216:                 libnet_pblock_swap(l, p_data->prev->ptag, p_data->ptag);
                    217:             }
                    218:         }
                    219:     }
                    220:     else
                    221:     {
                    222:         p_data = libnet_pblock_find(l, ptag_data);
                    223:         if (p_data) 
                    224:         {
                    225:             libnet_pblock_delete(l, p_data);
                    226:         }
                    227:     }
                    228: 
                    229:     if (sum == 0)
                    230:     {
                    231:         /*
                    232:          *  If checksum is zero, by default libnet will compute a checksum
                    233:          *  for the user.  The programmer can override this by calling
                    234:          *  libnet_toggle_checksum(l, ptag, 1);
                    235:          */
                    236:         libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
                    237:     }
                    238:     return (ptag);
                    239: bad:
                    240:     libnet_pblock_delete(l, p);
                    241:     return (-1);
                    242: }
                    243: 
                    244: 
                    245: libnet_ptag_t
                    246: libnet_build_tcp_options(u_int8_t *options, u_int32_t options_s, libnet_t *l, 
                    247: libnet_ptag_t ptag)
                    248: {
                    249:     int offset, underflow;
                    250:     u_int32_t i, j, n, adj_size;
                    251:     libnet_pblock_t *p, *p_temp;
                    252:     struct libnet_ipv4_hdr *ip_hdr;
                    253:     struct libnet_tcp_hdr *tcp_hdr;
                    254: 
                    255:     if (l == NULL)
                    256:     { 
                    257:         return (-1);
                    258:     }
                    259: 
                    260:     underflow = 0;
                    261:     offset = 0;
                    262: 
                    263:     /* check options list size */
                    264:     if (options_s > LIBNET_MAXOPTION_SIZE)
                    265:     {
                    266:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
                    267:             "%s(): options list is too large %d\n", __func__, options_s);
                    268:         return (-1);
                    269:     }
                    270: 
                    271:     adj_size = options_s;
                    272:     if (adj_size % 4)
                    273:     {
                    274:         /* size of memory block with padding */
                    275:         adj_size += 4 - (options_s % 4);
                    276:     }
                    277: 
                    278:     /* if this pblock already exists, determine if there is a size diff */
                    279:     if (ptag)
                    280:     {
                    281:         p_temp = libnet_pblock_find(l, ptag);
                    282:         if (p_temp)
                    283:         {
                    284:             if (adj_size >= p_temp->b_len)
                    285:             {
                    286:                 offset = adj_size - p_temp->b_len;
                    287:             }
                    288:             else
                    289:             {
                    290:                 offset = p_temp->b_len - adj_size;
                    291:                 underflow = 1;
                    292:             }
                    293:         }
                    294:     }
                    295: 
                    296:     /*
                    297:      *  Find the existing protocol block if a ptag is specified, or create
                    298:      *  a new one.
                    299:      */
                    300:     p = libnet_pblock_probe(l, ptag, adj_size, LIBNET_PBLOCK_TCPO_H);
                    301:     if (p == NULL)
                    302:     {
                    303:         return (-1);
                    304:     }
                    305:        
                    306:     n = libnet_pblock_append(l, p, options, adj_size);
                    307:     if (n == -1)
                    308:     {
                    309:         goto bad;
                    310:     }
                    311:        
                    312:     if (ptag && p->next)
                    313:     {
                    314:         p_temp = p->next;
                    315:         while ((p_temp->next) && (p_temp->type != LIBNET_PBLOCK_TCP_H))
                    316:         {
                    317:            p_temp = p_temp->next;
                    318:         }
                    319:         if (p_temp->type == LIBNET_PBLOCK_TCP_H)
                    320:         {
                    321:             /*
                    322:              *  Count up number of 32-bit words in options list, padding if
                    323:              *  neccessary.
                    324:              */
                    325:             for (i = 0, j = 0; i < p->b_len; i++)
                    326:             {
                    327:                 (i % 4) ? j : j++;
                    328:             }
                    329:             tcp_hdr = (struct libnet_tcp_hdr *)p_temp->buf;
                    330:             tcp_hdr->th_off = j + 5;
                    331:             if (!underflow)
                    332:             {
                    333:                 p_temp->h_len += offset;
                    334:             }
                    335:             else
                    336:             {
                    337:                 p_temp->h_len -= offset;
                    338:             }
                    339:         }
                    340:         while ((p_temp->next) && (p_temp->type != LIBNET_PBLOCK_IPV4_H))
                    341:         {
                    342:             p_temp = p_temp->next;
                    343:         }
                    344:         if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
                    345:         {
                    346:             ip_hdr = (struct libnet_ipv4_hdr *)p_temp->buf;
                    347:             if (!underflow)
                    348:             {
                    349:                 ip_hdr->ip_len += htons(offset);
                    350:             }
                    351:             else
                    352:             {
                    353:                 ip_hdr->ip_len -= htons(offset);
                    354:             }
                    355:         }
                    356:     }
                    357: 
                    358:     return (ptag ? ptag : libnet_pblock_update(l, p, adj_size,
                    359:             LIBNET_PBLOCK_TCPO_H));
                    360: bad:
                    361:     libnet_pblock_delete(l, p);
                    362:     return (-1);
                    363: }
                    364: 
                    365: /* EOF */

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