1 /*
2 * mod_tcp_chaff.c
3 *
4 * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
5 *
6 * $Id: mod_tcp_chaff.c,v 1.11 2002/04/07 22:55:20 dugsong Exp $
7 */
8
9 #include "config.h"
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "pkt.h"
16 #include "mod.h"
17 #include "randutil.h"
18
19 #define CHAFF_TYPE_CKSUM 1
20 #define CHAFF_TYPE_NULL 2
21 #define CHAFF_TYPE_PAWS 3
22 #define CHAFF_TYPE_REXMIT 4
23 #define CHAFF_TYPE_SEQ 5
24 #define CHAFF_TYPE_SYN 6
25 #define CHAFF_TYPE_TTL 7
26
27 struct tcp_chaff_data {
28 rand_t *rnd;
29 int type;
30 int ttl;
31 };
32
33 void *
tcp_chaff_close(void * d)34 tcp_chaff_close(void *d)
35 {
36 struct tcp_chaff_data *data = (struct tcp_chaff_data *)d;
37
38 if (data != NULL) {
39 rand_close(data->rnd);
40 free(data);
41 }
42 return (NULL);
43 }
44
45 void *
tcp_chaff_open(int argc,char * argv[])46 tcp_chaff_open(int argc, char *argv[])
47 {
48 struct tcp_chaff_data *data;
49
50 if (argc < 2)
51 return (NULL);
52
53 if ((data = calloc(1, sizeof(*data))) == NULL)
54 return (NULL);
55
56 data->rnd = rand_open();
57
58 if (strcasecmp(argv[1], "cksum") == 0)
59 data->type = CHAFF_TYPE_CKSUM;
60 else if (strcasecmp(argv[1], "null") == 0)
61 data->type = CHAFF_TYPE_NULL;
62 else if (strcasecmp(argv[1], "paws") == 0)
63 data->type = CHAFF_TYPE_PAWS;
64 else if (strcasecmp(argv[1], "rexmit") == 0)
65 data->type = CHAFF_TYPE_REXMIT;
66 else if (strcasecmp(argv[1], "seq") == 0)
67 data->type = CHAFF_TYPE_SEQ;
68 else if (strcasecmp(argv[1], "syn") == 0)
69 data->type = CHAFF_TYPE_SYN;
70 else if ((data->ttl = atoi(argv[1])) > 0 && data->ttl < 256)
71 data->type = CHAFF_TYPE_TTL;
72 else
73 return (tcp_chaff_close(data));
74
75 return (data);
76 }
77
78 int
tcp_chaff_apply(void * d,struct pktq * pktq)79 tcp_chaff_apply(void *d, struct pktq *pktq)
80 {
81 struct tcp_chaff_data *data = (struct tcp_chaff_data *)d;
82 struct pkt *pkt, *new, *next;
83 struct tcp_opt opt;
84 int i;
85
86 for (pkt = TAILQ_FIRST(pktq); pkt != TAILQ_END(pktq); pkt = next) {
87 next = TAILQ_NEXT(pkt, pkt_next);
88
89 if (pkt->pkt_ip == NULL || pkt->pkt_ip->ip_p != IP_PROTO_TCP ||
90 pkt->pkt_tcp == NULL || pkt->pkt_tcp_data == NULL ||
91 (pkt->pkt_tcp->th_flags & TH_ACK) == 0)
92 continue;
93
94 new = pkt_dup(pkt);
95 rand_strset(data->rnd, new->pkt_tcp_data, new->pkt_end -
96 new->pkt_tcp_data + 1);
97
98 switch (data->type) {
99 case CHAFF_TYPE_CKSUM:
100 ip_checksum(new->pkt_ip,
101 new->pkt_ip_data - new->pkt_eth_data);
102 new->pkt_tcp->th_sum = rand_uint16(data->rnd);
103 break;
104 case CHAFF_TYPE_NULL:
105 new->pkt_tcp->th_flags = 0;
106 ip_checksum(new->pkt_ip, new->pkt_end -
107 new->pkt_eth_data);
108 break;
109 case CHAFF_TYPE_PAWS:
110 /* Delete any existing TCP options. */
111 i = (new->pkt_tcp->th_off << 2) - TCP_HDR_LEN;
112 new->pkt_tcp->th_off = 5;
113 new->pkt_end -= i;
114 new->pkt_ip->ip_len = htons(new->pkt_end -
115 new->pkt_eth_data);
116
117 /* Insert initial timestamp, for PAWS elimination. */
118 opt.opt_type = TCP_OPT_TIMESTAMP;
119 opt.opt_len = TCP_OPT_LEN + 8;
120 opt.opt_data.timestamp[0] = 0;
121 opt.opt_data.timestamp[1] = 0;
122 if ((i = ip_add_option(new->pkt_ip,
123 PKT_BUF_LEN - ETH_HDR_LEN,
124 IP_PROTO_TCP, &opt, opt.opt_len)) < 0) {
125 pkt_free(new);
126 continue;
127 }
128 new->pkt_end += i;
129 ip_checksum(new->pkt_ip, new->pkt_end -
130 new->pkt_eth_data);
131 pkt_decorate(new);
132 break;
133 case CHAFF_TYPE_REXMIT:
134 new->pkt_ts.tv_usec = 1;
135 ip_checksum(new->pkt_ip, new->pkt_end -
136 new->pkt_eth_data);
137 break;
138 case CHAFF_TYPE_SEQ:
139 /* XXX - dunno recv window? */
140 new->pkt_tcp->th_seq = htonl(666);
141 new->pkt_tcp->th_ack = htonl(666);
142 ip_checksum(new->pkt_ip, new->pkt_end -
143 new->pkt_eth_data);
144 break;
145 case CHAFF_TYPE_SYN:
146 new->pkt_tcp->th_flags = TH_SYN;
147 new->pkt_tcp->th_seq = rand_uint32(data->rnd);
148 new->pkt_tcp->th_ack = 0;
149 new->pkt_end = new->pkt_tcp_data;
150 new->pkt_tcp_data = NULL;
151 new->pkt_ip->ip_len = htons(new->pkt_end -
152 new->pkt_eth_data);
153 ip_checksum(new->pkt_ip, new->pkt_end -
154 new->pkt_eth_data);
155 break;
156 case CHAFF_TYPE_TTL:
157 new->pkt_ip->ip_ttl = data->ttl;
158 ip_checksum(new->pkt_ip, new->pkt_end -
159 new->pkt_eth_data);
160 break;
161 }
162 /* Minimal random reordering. */
163 if ((new->pkt_tcp->th_sum & 1) == 0)
164 TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
165 else
166 TAILQ_INSERT_AFTER(pktq, pkt, new, pkt_next);
167 }
168 return (0);
169 }
170
171 struct mod mod_tcp_chaff = {
172 "tcp_chaff", /* name */
173 "tcp_chaff cksum|null|paws|rexmit|seq|syn|<ttl>", /* usage */
174 tcp_chaff_open, /* open */
175 tcp_chaff_apply, /* apply */
176 tcp_chaff_close /* close */
177 };
178