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>