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