1 /*
2  * mod_tcp_seg.c
3  *
4  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
5  *
6  * $Id: mod_tcp_seg.c,v 1.12 2002/04/07 22:55:20 dugsong Exp $
7  */
8 
9 #include "config.h"
10 
11 #include <err.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include "mod.h"
17 #include "pkt.h"
18 #include "randutil.h"
19 
20 #ifndef MIN
21 #define MIN(a,b)	(((a)<(b))?(a):(b))
22 #endif
23 
24 #define FAVOR_OLD	1
25 #define FAVOR_NEW	2
26 
27 static struct tcp_seg_data {
28 	rand_t	*rnd;
29 	int	 size;
30 	int	 overlap;
31 } tcp_seg_data;
32 
33 void *
tcp_seg_close(void * d)34 tcp_seg_close(void *d)
35 {
36 	if (tcp_seg_data.rnd != NULL)
37 		rand_close(tcp_seg_data.rnd);
38 	tcp_seg_data.size = 0;
39 	return (NULL);
40 }
41 
42 void *
tcp_seg_open(int argc,char * argv[])43 tcp_seg_open(int argc, char *argv[])
44 {
45 	if (argc < 2) {
46 		warnx("need segment <size> in bytes");
47 		return (NULL);
48 	}
49 	tcp_seg_data.rnd = rand_open();
50 
51 	if ((tcp_seg_data.size = atoi(argv[1])) == 0) {
52 		warnx("invalid segment size '%s'", argv[1]);
53 		return (tcp_seg_close(&tcp_seg_data));
54 	}
55 	if (argc == 3) {
56 		if (strcmp(argv[2], "old") == 0 ||
57 		    strcmp(argv[2], "win32") == 0)
58 			tcp_seg_data.overlap = FAVOR_OLD;
59 		else if (strcmp(argv[2], "new") == 0 ||
60 		    strcmp(argv[2], "unix") == 0)
61 			tcp_seg_data.overlap = FAVOR_NEW;
62 		else
63 			return (tcp_seg_close(&tcp_seg_data));
64 	}
65 	return (&tcp_seg_data);
66 }
67 
68 int
tcp_seg_apply(void * d,struct pktq * pktq)69 tcp_seg_apply(void *d, struct pktq *pktq)
70 {
71 	struct pkt *pkt, *new, *next, tmp;
72 	uint32_t seq;
73 	int hl, tl, len;
74 	u_char *p, *p1, *p2;
75 
76 	for (pkt = TAILQ_FIRST(pktq); pkt != TAILQ_END(pktq); pkt = next) {
77 		next = TAILQ_NEXT(pkt, pkt_next);
78 
79 		if (pkt->pkt_ip == NULL || pkt->pkt_ip->ip_p != IP_PROTO_TCP ||
80 		    pkt->pkt_tcp == NULL || pkt->pkt_tcp_data == NULL ||
81 		    (pkt->pkt_tcp->th_flags & TH_ACK) == 0 ||
82 		    pkt->pkt_end - pkt->pkt_tcp_data <= tcp_seg_data.size)
83 			continue;
84 
85 		hl = pkt->pkt_ip->ip_hl << 2;
86 		tl = pkt->pkt_tcp->th_off << 2;
87 		seq = ntohl(pkt->pkt_tcp->th_seq);
88 
89 		for (p = pkt->pkt_tcp_data; p < pkt->pkt_end; p += len) {
90 			new = pkt_new();
91 			p1 = p, p2 = NULL;
92 			len = MIN(pkt->pkt_end - p, tcp_seg_data.size);
93 
94 			if (tcp_seg_data.overlap != 0 &&
95 			    p + (len << 1) < pkt->pkt_end) {
96 				rand_strset(tcp_seg_data.rnd, tmp.pkt_buf,len);
97 
98 				if (tcp_seg_data.overlap == FAVOR_OLD) {
99 					p1 = p + len;
100 					p2 = tmp.pkt_buf;
101 				} else if (tcp_seg_data.overlap == FAVOR_NEW) {
102 					p1 = tmp.pkt_buf;
103 					p2 = p + len;
104 				}
105 				len = tcp_seg_data.size;
106 				seq += tcp_seg_data.size;
107 			}
108 			memcpy(new->pkt_ip, pkt->pkt_ip, hl + tl);
109 			new->pkt_ip_data = new->pkt_eth_data + hl;
110 			new->pkt_tcp_data = new->pkt_ip_data + tl;
111 			memcpy(new->pkt_tcp_data, p1, len);
112 			new->pkt_end = new->pkt_tcp_data + len;
113 
114 			new->pkt_ip->ip_id = rand_uint16(tcp_seg_data.rnd);
115 			new->pkt_ip->ip_len = htons(hl + tl + len);
116 			new->pkt_tcp->th_seq = htonl(seq);
117 			ip_checksum(new->pkt_ip, hl + tl + len);
118 			TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
119 
120 			if (p2 != NULL) {
121 				new = pkt_dup(new);
122 				new->pkt_ts.tv_usec = 1;
123 				new->pkt_ip->ip_id =
124 				    rand_uint16(tcp_seg_data.rnd);
125 				new->pkt_ip->ip_len = htons(hl + tl +
126 				    (len << 1));
127 				new->pkt_tcp->th_seq = htonl(seq - len);
128 
129 				memcpy(new->pkt_tcp_data, p, len);
130 				memcpy(new->pkt_tcp_data + len, p2, len);
131 				new->pkt_end = new->pkt_tcp_data + (len << 1);
132 				ip_checksum(new->pkt_ip, hl + tl + (len << 1));
133 				TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
134 				p += len;
135 			}
136 			seq += len;
137 		}
138 		TAILQ_REMOVE(pktq, pkt, pkt_next);
139 		pkt_free(pkt);
140 	}
141 	return (0);
142 }
143 
144 struct mod mod_tcp_seg = {
145 	"tcp_seg",				/* name */
146 	"tcp_seg <size> [old|new]",		/* usage */
147 	tcp_seg_open,				/* open */
148 	tcp_seg_apply,				/* apply */
149 	tcp_seg_close				/* close */
150 };
151