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