/src/tcpreplay/src/fragroute/mod_tcp_seg.c
Line | Count | Source |
1 | | /* |
2 | | * mod_tcp_seg.c |
3 | | * |
4 | | * Copyright (c) 2001 Dug Song <dugsong@monkey.org> |
5 | | * |
6 | | * $Id$ |
7 | | */ |
8 | | |
9 | | #include "defines.h" |
10 | | #include "config.h" |
11 | | #include "common.h" |
12 | | #include "iputil.h" |
13 | | #include "lib/queue.h" |
14 | | #include "mod.h" |
15 | | #include "pkt.h" |
16 | | #include "randutil.h" |
17 | | #include <stdio.h> |
18 | | #include <stdlib.h> |
19 | | #include <string.h> |
20 | | |
21 | | #ifndef MIN |
22 | | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) |
23 | | #endif |
24 | | |
25 | 0 | #define FAVOR_OLD 1 |
26 | 0 | #define FAVOR_NEW 2 |
27 | | |
28 | | static struct tcp_seg_data { |
29 | | rand_t *rnd; |
30 | | int size; |
31 | | int overlap; |
32 | | } tcp_seg_data; |
33 | | |
34 | | void * |
35 | | tcp_seg_close(_U_ void *d) |
36 | 0 | { |
37 | 0 | if (tcp_seg_data.rnd != NULL) |
38 | 0 | rand_close(tcp_seg_data.rnd); |
39 | 0 | tcp_seg_data.size = 0; |
40 | 0 | return (NULL); |
41 | 0 | } |
42 | | |
43 | | void * |
44 | | tcp_seg_open(int argc, char *argv[]) |
45 | 0 | { |
46 | 0 | if (argc < 2) { |
47 | 0 | warn("need segment <size> in bytes"); |
48 | 0 | return (NULL); |
49 | 0 | } |
50 | 0 | if (tcp_seg_data.rnd != NULL) |
51 | 0 | rand_close(tcp_seg_data.rnd); |
52 | 0 | tcp_seg_data.rnd = rand_open(); |
53 | | |
54 | | /* |
55 | | * A negative size survives as a negative int, then reaches memcpy() as a |
56 | | * huge implicitly-converted size_t (and walks the segment loop backwards). |
57 | | */ |
58 | 0 | tcp_seg_data.size = (int)strtol(argv[1], NULL, 10); |
59 | 0 | if (tcp_seg_data.size <= 0 || tcp_seg_data.size > IP_LEN_MAX) { |
60 | 0 | warnx("invalid segment size '%s' (must be between 1 and 65535 bytes)", argv[1]); |
61 | 0 | return (tcp_seg_close(&tcp_seg_data)); |
62 | 0 | } |
63 | 0 | if (argc == 3) { |
64 | 0 | if (strcmp(argv[2], "old") == 0 || strcmp(argv[2], "win32") == 0) |
65 | 0 | tcp_seg_data.overlap = FAVOR_OLD; |
66 | 0 | else if (strcmp(argv[2], "new") == 0 || strcmp(argv[2], "unix") == 0) |
67 | 0 | tcp_seg_data.overlap = FAVOR_NEW; |
68 | 0 | else |
69 | 0 | return (tcp_seg_close(&tcp_seg_data)); |
70 | 0 | } |
71 | 0 | return (&tcp_seg_data); |
72 | 0 | } |
73 | | |
74 | | int |
75 | | tcp_seg_apply(_U_ void *d, struct pktq *pktq) |
76 | 0 | { |
77 | 0 | struct pkt *pkt, *new, *next; |
78 | |
|
79 | 0 | for (pkt = TAILQ_FIRST(pktq); pkt != TAILQ_END(pktq); pkt = next) { |
80 | 0 | uint32_t seq; |
81 | 0 | int hl, tl, len; |
82 | 0 | u_char *p; |
83 | 0 | uint16_t eth_type; |
84 | 0 | uint8_t nxt; |
85 | |
|
86 | 0 | next = TAILQ_NEXT(pkt, pkt_next); |
87 | |
|
88 | 0 | eth_type = htons(pkt->pkt_eth->eth_type); |
89 | |
|
90 | 0 | if (pkt->pkt_ip == NULL) |
91 | 0 | continue; |
92 | | |
93 | 0 | if (eth_type == ETH_TYPE_IP) { |
94 | 0 | nxt = pkt->pkt_ip->ip_p; |
95 | 0 | } else if (eth_type == ETH_TYPE_IPV6) { |
96 | 0 | nxt = pkt->pkt_ip6->ip6_nxt; |
97 | 0 | } else { |
98 | 0 | continue; |
99 | 0 | } |
100 | | |
101 | 0 | if (nxt != IP_PROTO_TCP || pkt->pkt_tcp == NULL || pkt->pkt_tcp_data == NULL || |
102 | 0 | (pkt->pkt_tcp->th_flags & TH_ACK) == 0 || pkt->pkt_end - pkt->pkt_tcp_data <= tcp_seg_data.size) |
103 | 0 | continue; |
104 | | |
105 | 0 | if (eth_type == ETH_TYPE_IP) { |
106 | 0 | hl = pkt->pkt_ip->ip_hl << 2; |
107 | 0 | } else if (eth_type == ETH_TYPE_IPV6) { |
108 | 0 | hl = IP6_HDR_LEN; |
109 | 0 | } else { |
110 | 0 | continue; |
111 | 0 | } |
112 | | |
113 | 0 | tl = pkt->pkt_tcp->th_off << 2; |
114 | 0 | seq = ntohl(pkt->pkt_tcp->th_seq); |
115 | |
|
116 | 0 | for (p = pkt->pkt_tcp_data; p < pkt->pkt_end; p += len) { |
117 | 0 | u_char *p1, *p2; |
118 | |
|
119 | 0 | if ((new = pkt_new(pkt->pkt_buf_size)) == NULL) { |
120 | 0 | return -1; |
121 | 0 | } |
122 | | |
123 | 0 | memcpy(new->pkt_eth, pkt->pkt_eth, (u_char *)pkt->pkt_eth_data - (u_char *)pkt->pkt_eth); |
124 | 0 | p1 = p, p2 = NULL; |
125 | 0 | len = MIN(pkt->pkt_end - p, tcp_seg_data.size); |
126 | |
|
127 | 0 | if (tcp_seg_data.overlap != 0 && p + (len << 1) < pkt->pkt_end) { |
128 | 0 | struct pkt tmp; |
129 | 0 | u_char tmp_buf[pkt->pkt_buf_size]; |
130 | |
|
131 | 0 | tmp.pkt_buf = tmp_buf; |
132 | 0 | tmp.pkt_buf_size = pkt->pkt_buf_size; |
133 | 0 | rand_strset(tcp_seg_data.rnd, tmp.pkt_buf, len); |
134 | |
|
135 | 0 | if (tcp_seg_data.overlap == FAVOR_OLD) { |
136 | 0 | p1 = p + len; |
137 | 0 | p2 = tmp.pkt_buf; |
138 | 0 | } else if (tcp_seg_data.overlap == FAVOR_NEW) { |
139 | 0 | p1 = tmp.pkt_buf; |
140 | 0 | p2 = p + len; |
141 | 0 | } |
142 | 0 | len = tcp_seg_data.size; |
143 | 0 | seq += tcp_seg_data.size; |
144 | 0 | } |
145 | 0 | memcpy(new->pkt_ip, pkt->pkt_ip, hl + tl); |
146 | 0 | new->pkt_ip_data = new->pkt_eth_data + hl; |
147 | 0 | new->pkt_tcp_data = new->pkt_ip_data + tl; |
148 | 0 | memcpy(new->pkt_tcp_data, p1, len); |
149 | 0 | new->pkt_end = new->pkt_tcp_data + len; |
150 | |
|
151 | 0 | if (eth_type == ETH_TYPE_IP) { |
152 | 0 | new->pkt_ip->ip_id = rand_uint16(tcp_seg_data.rnd); |
153 | 0 | new->pkt_ip->ip_len = htons(hl + tl + len); |
154 | 0 | } else { |
155 | 0 | new->pkt_ip6->ip6_plen = htons(tl + len); |
156 | 0 | } |
157 | |
|
158 | 0 | new->pkt_tcp->th_seq = htonl(seq); |
159 | 0 | inet_checksum(eth_type, new->pkt_ip, hl + tl + len); |
160 | 0 | TAILQ_INSERT_BEFORE(pkt, new, pkt_next); |
161 | |
|
162 | 0 | if (p2 != NULL) { |
163 | 0 | if ((new = pkt_dup(new)) == NULL) { |
164 | 0 | return -1; |
165 | 0 | } |
166 | | |
167 | 0 | new->pkt_ts.tv_usec = 1; |
168 | 0 | if (eth_type == ETH_TYPE_IP) { |
169 | 0 | new->pkt_ip->ip_id = rand_uint16(tcp_seg_data.rnd); |
170 | 0 | new->pkt_ip->ip_len = htons(hl + tl + (len << 1)); |
171 | 0 | } else if (eth_type == ETH_TYPE_IPV6) { |
172 | 0 | new->pkt_ip6->ip6_plen = htons(tl + (len << 1)); |
173 | 0 | } |
174 | 0 | new->pkt_tcp->th_seq = htonl(seq - len); |
175 | |
|
176 | 0 | memcpy(new->pkt_tcp_data, p, len); |
177 | 0 | memcpy(new->pkt_tcp_data + len, p2, len); |
178 | 0 | new->pkt_end = new->pkt_tcp_data + (len << 1); |
179 | 0 | inet_checksum(eth_type, new->pkt_ip, hl + tl + (len << 1)); |
180 | 0 | TAILQ_INSERT_BEFORE(pkt, new, pkt_next); |
181 | 0 | p += len; |
182 | 0 | } |
183 | 0 | seq += len; |
184 | 0 | } |
185 | 0 | TAILQ_REMOVE(pktq, pkt, pkt_next); |
186 | 0 | pkt_free(pkt); |
187 | 0 | } |
188 | 0 | return (0); |
189 | 0 | } |
190 | | |
191 | | struct mod mod_tcp_seg = { |
192 | | "tcp_seg", /* name */ |
193 | | "tcp_seg <size> [old|new]", /* usage */ |
194 | | tcp_seg_open, /* open */ |
195 | | tcp_seg_apply, /* apply */ |
196 | | tcp_seg_close /* close */ |
197 | | }; |