Annotation of embedaddon/libnet/src/libnet_build_tcp.c, revision 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>