1 /*
2 tcp_seg.c
3
4 Dug Song <dugsong@anzen.com>
5
6 Copyright (c) 1999 Anzen Computing. All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17 3. All advertising materials mentioning features or use of this software
18 must display the following acknowledgement:
19 This product includes software developed by Anzen Computing.
20 4. Neither the name of Anzen Computing nor the names of its
21 contributors may be used to endorse or promote products derived
22 from this software without specific prior written permission.
23
24 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
28 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
30 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
36 $Id: tcp_seg.c,v 1.8 1999/05/28 14:23:43 dugsong Exp $
37 */
38
39 #include "config.h"
40
41 #include <libnet.h>
42 #include "list.h"
43 #include "tcp_seg.h"
44
45 #ifndef MIN
46 #define MIN(a,b) (((a)<(b))?(a):(b))
47 #endif
48
49 ELEM *
tcp_seg_make(u_char * pkt,int pktlen,int segsize)50 tcp_seg_make(u_char *pkt, int pktlen, int segsize)
51 {
52 ELEM *new, *list = NULL;
53 struct ip *iph = (struct ip *)pkt;
54 int len, ip_hl = iph->ip_hl * 4;
55 struct tcphdr *tcph = (struct tcphdr *)(pkt + ip_hl);
56 int tcp_hl = tcph->th_off * 4;
57 u_char *tcp_blob = pkt + ip_hl + tcp_hl;
58 int tcp_bloblen = ntohs(iph->ip_len) - ip_hl - tcp_hl;
59 u_char *tcp_end = tcp_blob + tcp_bloblen;
60 u_long tcp_newseq = ntohl(tcph->th_seq);
61 u_char *p, *data;
62
63 if (iph->ip_p != IPPROTO_TCP || tcp_bloblen <= segsize ||
64 (tcph->th_flags & TH_ACK) == 0)
65 return NULL;
66
67 for (p = tcp_blob ; p < tcp_end ; p += len) {
68 len = MIN(tcp_end - p, segsize);
69
70 if (!(data = malloc(ip_hl + tcp_hl + len)))
71 return NULL;
72
73 /* Copy in headers and data. */
74 memcpy(data, pkt, ip_hl + tcp_hl);
75 memcpy(data + ip_hl + tcp_hl, p, len);
76
77 /* Correct IP len, TCP seqnum, and TCP checksum. */
78 ((struct ip *)data)->ip_len = htons(ip_hl + tcp_hl + len);
79 ((struct tcphdr *)(data + ip_hl))->th_seq = htonl(tcp_newseq);
80 libnet_do_checksum(data, IPPROTO_TCP, tcp_hl + len);
81
82 tcp_newseq += len;
83
84 /* Add it to our list of TCP packets. */
85 new = list_elem(data, ip_hl + tcp_hl + len);
86 free(data);
87
88 if (!(list = list_add(list, new)))
89 return NULL;
90 }
91 return (list->head);
92 }
93
94 ELEM *
tcp_seg_null_payload(ELEM * seg)95 tcp_seg_null_payload(ELEM *seg)
96 {
97 struct ip *iph = (struct ip *)seg->data;
98 int ip_hl = iph->ip_hl * 4;
99 struct tcphdr *tcph = (struct tcphdr *)(seg->data + ip_hl);
100 int tcp_hl = tcph->th_off * 4;
101 int newlen = ntohs(iph->ip_len) - (ip_hl + tcp_hl);
102 u_char *newdata;
103
104 if (!(newdata = malloc(ip_hl + TCP_H + newlen)))
105 return NULL;
106
107 /* Whack the payload (including TCP options to elude PAWS). */
108 memcpy(newdata, seg->data, ip_hl + TCP_H);
109 memset(newdata + ip_hl + TCP_H, 0, newlen);
110
111 /* Correct IP length, TCP header length, TCP checksum, segment length. */
112 ((struct ip *)newdata)->ip_len = htons(ip_hl + TCP_H + newlen);
113 ((struct tcphdr *)(newdata + ip_hl))->th_off = TCP_H / 4;
114 libnet_do_checksum(newdata, IPPROTO_TCP, TCP_H + newlen);
115 seg->len = ip_hl + TCP_H + newlen;
116
117 free(seg->data);
118 seg->data = newdata;
119
120 return (seg);
121 }
122
123 ELEM *
tcp_seg_whack_checksums(ELEM * seg)124 tcp_seg_whack_checksums(ELEM *seg)
125 {
126 ELEM *s;
127 struct ip *iph;
128 struct tcphdr *tcph;
129
130 for (s = seg ; s != NULL ; s = s->next) {
131 iph = (struct ip *)s->data;
132 tcph = (struct tcphdr *)(s->data + (iph->ip_hl * 4));
133 tcph->th_sum = htons(666);
134 }
135 return (seg);
136 }
137
138 ELEM *
tcp_seg_whack_acks(ELEM * seg)139 tcp_seg_whack_acks(ELEM *seg)
140 {
141 ELEM *s;
142 struct ip *iph;
143 struct tcphdr *tcph;
144
145 for (s = seg ; s != NULL ; s = s->next) {
146 iph = (struct ip *)s->data;
147 tcph = (struct tcphdr *)(s->data + (iph->ip_hl * 4));
148 tcph->th_flags &= ~TH_ACK;
149 }
150 return (seg);
151 }
152
153 ELEM *
tcp_seg_interleave_nulls(ELEM * seg)154 tcp_seg_interleave_nulls(ELEM *seg)
155 {
156 ELEM *s;
157 struct ip *iph;
158 int ip_hl;
159
160 if (!seg) return NULL;
161
162 for (s = seg ; s != NULL ; s = s->next) {
163 s = list_dup(s);
164
165 iph = (struct ip *)s->data;
166 ip_hl = iph->ip_hl * 4;
167
168 /* Whack the sequence number with something bogus. */
169 ((struct tcphdr *)(s->data + ip_hl))->th_seq =
170 htonl(((struct tcphdr *)(s->data + ip_hl))->th_seq);
171
172 /* Whack the payload. */
173 tcp_seg_null_payload(s);
174 }
175 return (seg);
176 }
177
178 ELEM *
tcp_seg_interleave_syns(ELEM * seg)179 tcp_seg_interleave_syns(ELEM *seg)
180 {
181 ELEM *s, *new;
182 u_char *data;
183
184 if (!seg) return NULL;
185
186 for (s = seg ; s && s->next ; s = s->next) {
187 struct ip *iph = (struct ip *)s->data;
188 int ip_hl = iph->ip_hl * 4;
189 struct tcphdr *tcph = (struct tcphdr *)(s->data + ip_hl);
190
191 if (!(data = malloc(ip_hl + TCP_H)))
192 return NULL;
193
194 /* Copy in IP header. */
195 memcpy(data, s->data, ip_hl);
196
197 /* Correct IP length, trash IP ID, TCP sequence number. */
198 ((struct ip *)data)->ip_len = htons(ip_hl + TCP_H);
199 ((struct ip *)data)->ip_id = htons(iph->ip_id) * 2; /* intentional! */
200 libnet_build_tcp(ntohs(tcph->th_sport), ntohs(tcph->th_dport),
201 htonl(tcph->th_seq * 2), 0, TH_SYN, ntohs(tcph->th_win),
202 ntohs(tcph->th_urp), NULL, 0, data + ip_hl);
203
204 libnet_do_checksum(data, IPPROTO_TCP, TCP_H);
205
206 /* Add it to our list of TCP packets. */
207 new = list_elem(data, ip_hl + TCP_H);
208 free(data);
209
210 if (!(s = list_add(s, new)))
211 return NULL;
212 }
213 return (seg);
214 }
215
216 ELEM *
tcp_seg_prepend_fakeclose(u_char * pkt,int pktlen)217 tcp_seg_prepend_fakeclose(u_char *pkt, int pktlen)
218 {
219 ELEM *new, *list = NULL;
220 struct ip *iph = (struct ip *)pkt;
221 int ip_hl = iph->ip_hl * 4;
222 struct tcphdr *tcph = (struct tcphdr *)(pkt + ip_hl);
223 u_char *data;
224
225 if ((tcph->th_flags & TH_SYN) == 0)
226 return NULL;
227
228 /* Add our real SYN packet to list. */
229 new = list_elem(pkt, pktlen);
230 if (!(list = list_add(list, new)))
231 return NULL;
232
233 /* Add our fake FIN packet. */
234 if (!(data = malloc(ip_hl + TCP_H)))
235 return NULL;
236
237 memcpy(data, pkt, ip_hl);
238 ((struct ip *)data)->ip_len = htons(ip_hl + TCP_H);
239 ((struct ip *)data)->ip_id = htons(iph->ip_id) * 2; /* intentional! */
240 libnet_build_tcp(ntohs(tcph->th_sport), ntohs(tcph->th_dport),
241 ntohl(tcph->th_seq) + 1, ntohl(tcph->th_ack),
242 TH_FIN, 0, ntohs(tcph->th_urp), NULL, 0, data + ip_hl);
243
244 new = list_elem(data, ip_hl + TCP_H);
245 free(data);
246
247 if (!(list = list_add(list, new)))
248 return NULL;
249
250 /* Add our fake RST packet. */
251 if (!(data = malloc(ip_hl + TCP_H)))
252 return NULL;
253
254 memcpy(data, pkt, ip_hl);
255 ((struct ip *)data)->ip_len = htons(ip_hl + TCP_H);
256 ((struct ip *)data)->ip_id = htons(iph->ip_id) * 2 + 1; /* intentional! */
257 libnet_build_tcp(ntohs(tcph->th_sport), ntohs(tcph->th_dport),
258 ntohl(tcph->th_seq) + 2, ntohl(tcph->th_ack),
259 TH_RST, 0, ntohs(tcph->th_urp), NULL, 0, data + ip_hl);
260
261 new = list_elem(data, ip_hl + TCP_H);
262 free(data);
263
264 if (!(list = list_add(list, new)))
265 return NULL;
266
267 return (list->head);
268 }
269
270 ELEM *
tcp_seg_prepend_connection(u_char * pkt,int pktlen)271 tcp_seg_prepend_connection(u_char *pkt, int pktlen)
272 {
273 ELEM *new, *list = NULL;
274 struct ip *iph = (struct ip *)pkt;
275 int ip_hl = iph->ip_hl * 4;
276 struct tcphdr *tcph = (struct tcphdr *)(pkt + ip_hl);
277 u_char *data;
278
279 if ((tcph->th_flags & TH_SYN) == 0)
280 return NULL;
281
282 /* Add our decoy SYN packet. */
283 if (!(data = malloc(ip_hl + TCP_H)))
284 return NULL;
285
286 memcpy(data, pkt, ip_hl);
287 ((struct ip *)data)->ip_len = htons(ip_hl + TCP_H);
288 ((struct ip *)data)->ip_id = htons(iph->ip_id) * 2; /* intentional! */
289 libnet_build_tcp(ntohs(tcph->th_sport), ntohs(tcph->th_dport),
290 ntohl(tcph->th_seq) * 2, 0, TH_SYN, ntohs(tcph->th_win),
291 0, NULL, 0, data + ip_hl);
292 libnet_do_checksum(data, IPPROTO_TCP, TCP_H);
293 new = list_elem(data, ip_hl + TCP_H);
294 free(data);
295
296 if (!(list = list_add(list, new)))
297 return NULL;
298
299 /* Add our decoy RST packet, in case the attacker is filtering hers. */
300 if (!(data = malloc(ip_hl + TCP_H)))
301 return NULL;
302
303 memcpy(data, pkt, ip_hl);
304 ((struct ip *)data)->ip_len = htons(ip_hl + TCP_H);
305 ((struct ip *)data)->ip_id = htons(iph->ip_id) * 2 + 1; /* intentional! */
306 libnet_build_tcp(ntohs(tcph->th_sport), ntohs(tcph->th_dport),
307 ntohl(tcph->th_seq) * 2 + 1, 0, TH_RST, ntohs(tcph->th_win),
308 0, NULL, 0, data + ip_hl);
309 libnet_do_checksum(data, IPPROTO_TCP, TCP_H);
310 new = list_elem(data, ip_hl + TCP_H);
311 free(data);
312
313 if (!(list = list_add(list, new)))
314 return NULL;
315
316 /* Add our real SYN packet to list. */
317 new = list_elem(pkt, pktlen);
318 if (!(list = list_add(list, new)))
319 return NULL;
320
321 return (list->head);
322 }
323
324 ELEM *
tcp_seg_prepend_junk(u_char * pkt,int pktlen)325 tcp_seg_prepend_junk(u_char *pkt, int pktlen)
326 {
327 ELEM *new, *list = NULL;
328 struct ip *iph = (struct ip *)pkt;
329 int ip_hl = iph->ip_hl * 4;
330 struct tcphdr *tcph = (struct tcphdr *)(pkt + ip_hl);
331 u_char *data;
332 int i;
333
334 if ((tcph->th_flags & TH_SYN) == 0)
335 return NULL;
336
337 for (i = 0; i < 500 ; i++) {
338 if (!(data = malloc(ip_hl + TCP_H + PACKET)))
339 return NULL;
340
341 /* Copy over IP header. */
342 memcpy(data, pkt, ip_hl);
343
344 /* Correct IP length, IP ID. */
345 ((struct ip *)data)->ip_len = htons(ip_hl + TCP_H + PACKET);
346 ((struct ip *)data)->ip_id = htons(iph->ip_id + i); /* intentional! */
347
348 /* Add TCP header, null payload, and fix checksum. */
349 libnet_build_tcp(ntohs(tcph->th_sport), ntohs(tcph->th_dport),
350 i, 666, TH_ACK, ntohs(tcph->th_win),
351 ntohs(tcph->th_urp), NULL, 0, data + ip_hl);
352 memset(data + ip_hl + TCP_H, 0, PACKET);
353 libnet_do_checksum(data, IPPROTO_TCP, TCP_H);
354
355 new = list_elem(data, ip_hl + TCP_H + PACKET);
356 free(data);
357
358 if (!(list = list_add(list, new)))
359 return NULL;
360 }
361 /* Add our real SYN packet. */
362 new = list_elem(pkt, pktlen);
363 if (!(list = list_add(list, new)))
364 return NULL;
365
366 return (list->head);
367 }
368
369 ELEM *
tcp_seg_interleave_overwrites(ELEM * seg)370 tcp_seg_interleave_overwrites(ELEM *seg)
371 {
372 ELEM *s, *new;
373 u_char nulls[PACKET], *newdata;
374 u_long newseq;
375 int newlen;
376
377 memset(nulls, 0, sizeof(nulls));
378
379 for (s = seg ; s && s->next ; s = s->next) {
380 struct ip *iph = (struct ip *)s->data;
381 int ip_hl = iph->ip_hl * 4;
382 struct tcphdr *tcph = (struct tcphdr *)(s->data + ip_hl);
383 int tcp_hl = tcph->th_off * 4;
384
385 /* Build new null data segment, half the length of the current segment
386 and overlapping its latter half. */
387 newlen = (ntohs(iph->ip_len) - (ip_hl + tcp_hl)) / 2;
388 newseq = ntohl(tcph->th_seq) + newlen;
389
390 if (!(newdata = malloc(ip_hl + TCP_H + newlen)))
391 return NULL;
392
393 /* Copy in IP, TCP headers and data. */
394 memcpy(newdata, s->data, ip_hl + TCP_H);
395 memcpy(newdata + ip_hl + TCP_H, nulls, newlen);
396
397 /* Correct IP length, TCP header length, TCP seqnum, TCP checksum. */
398 ((struct ip *)newdata)->ip_len = htons(ip_hl + TCP_H + newlen);
399 ((struct tcphdr *)(newdata + ip_hl))->th_seq = htonl(newseq);
400 ((struct tcphdr *)(newdata + ip_hl))->th_off = TCP_H / 4; /* XXX - PAWS! */
401 libnet_do_checksum(newdata, IPPROTO_TCP, TCP_H + newlen);
402
403 /* Add null fragment after current fragment. */
404 new = list_elem(newdata, ip_hl + TCP_H + newlen);
405 free(newdata);
406
407 if (!list_add(s, new))
408 return NULL;
409
410 /* Swap them. */
411 if (!list_swap(s))
412 return NULL;
413 }
414 return (seg);
415 }
416