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>