Annotation of embedaddon/libnet/src/libnet_build_tcp.c, revision 1.1.1.2
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
1.1.1.2 ! misho 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)
1.1 misho 47: {
48: int n, offset;
1.1.1.2 ! misho 49: libnet_pblock_t *p = NULL;
! 50: libnet_ptag_t ptag_data = 0;
1.1 misho 51: struct libnet_tcp_hdr tcp_hdr;
52:
53: if (l == NULL)
1.1.1.2 ! misho 54: return -1;
1.1 misho 55:
1.1.1.2 ! misho 56: if (payload_s && !payload)
! 57: {
! 58: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
! 59: "%s(): payload inconsistency\n", __func__);
! 60: return -1;
! 61: }
1.1 misho 62:
63: p = libnet_pblock_probe(l, ptag, LIBNET_TCP_H, LIBNET_PBLOCK_TCP_H);
64: if (p == NULL)
1.1.1.2 ! misho 65: return -1;
1.1 misho 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 */
1.1.1.2 ! misho 77: if (p->prev && p->prev->type == LIBNET_PBLOCK_TCPO_H)
1.1 misho 78: {
1.1.1.2 ! misho 79: /* Note that the tcp options pblock is already padded */
! 80: tcp_hdr.th_off += (p->prev->b_len/4);
1.1 misho 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:
1.1.1.2 ! misho 87: n = libnet_pblock_append(l, p, (uint8_t *)&tcp_hdr, LIBNET_TCP_H);
1.1 misho 88: if (n == -1)
89: {
90: goto bad;
91: }
92:
93: if (ptag == LIBNET_PTAG_INITIALIZER)
94: {
1.1.1.2 ! misho 95: libnet_pblock_update(l, p, h_len, LIBNET_PBLOCK_TCP_H);
1.1 misho 96: }
97:
98: offset = payload_s;
1.1.1.2 ! misho 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)
1.1 misho 104: {
1.1.1.2 ! misho 105: libnet_pblock_t* datablock = p->prev;
1.1 misho 106:
1.1.1.2 ! misho 107: if (datablock && datablock->type == LIBNET_PBLOCK_TCPO_H)
! 108: datablock = datablock->prev;
1.1 misho 109:
1.1.1.2 ! misho 110: if (datablock && datablock->type == LIBNET_PBLOCK_TCPDATA)
1.1 misho 111: {
1.1.1.2 ! misho 112: ptag_data = datablock->ptag;
! 113: offset -= datablock->b_len;
1.1 misho 114: }
1.1.1.2 ! misho 115: p->h_len += offset;
1.1 misho 116: }
117:
1.1.1.2 ! misho 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)
1.1 misho 122: {
1.1.1.2 ! misho 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: }
1.1 misho 134: }
135:
136: /* if there is a payload, add it in the context */
1.1.1.2 ! misho 137: if (payload_s)
1.1 misho 138: {
139: /* update ptag_data with the new payload */
1.1.1.2 ! misho 140: libnet_pblock_t* p_data = libnet_pblock_probe(l, ptag_data, payload_s, LIBNET_PBLOCK_TCPDATA);
! 141: if (!p_data)
1.1 misho 142: {
1.1.1.2 ! misho 143: goto bad;
1.1 misho 144: }
145:
1.1.1.2 ! misho 146: n = libnet_pblock_append(l, p_data, payload, payload_s);
! 147: if (n == -1)
1.1 misho 148: {
149: goto bad;
150: }
151:
152: if (ptag_data == LIBNET_PTAG_INITIALIZER)
153: {
1.1.1.2 ! misho 154: int insertbefore = p->ptag;
1.1 misho 155:
1.1.1.2 ! misho 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);
1.1 misho 164: }
165: }
166: else
167: {
1.1.1.2 ! misho 168: libnet_pblock_t* p_data = libnet_pblock_find(l, ptag_data);
! 169: libnet_pblock_delete(l, p_data);
1.1 misho 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: }
1.1.1.2 ! misho 181: return (p->ptag);
1.1 misho 182: bad:
183: libnet_pblock_delete(l, p);
184: return (-1);
185: }
186:
187: libnet_ptag_t
1.1.1.2 ! misho 188: libnet_build_tcp_options(const uint8_t *options, uint32_t options_s, libnet_t *l,
1.1 misho 189: libnet_ptag_t ptag)
190: {
1.1.1.2 ! misho 191: static const uint8_t padding[] = { 0 };
! 192: int n, offset, underflow;
! 193: uint32_t i, j, adj_size;
1.1 misho 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: }
1.1.1.2 ! misho 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);
1.1 misho 256: if (n == -1)
257: {
258: goto bad;
259: }
1.1.1.2 ! misho 260:
1.1 misho 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>