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