1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <time.h>
8 
9 #include <winsock2.h>
10 #include <windows.h>
11 #include <iphlpapi.h>
12 
13 #include "inc.h"
14 #include "tcpcrypt_divert.h"
15 #include "tcpcryptd.h"
16 #include "tcpcrypt.h"
17 #include "checksum.h"
18 #include "util.h"
19 
20 #include <windivert.h>
21 
22 #define MAC_SIZE 14
23 
24 static int	  _s;
25 static divert_cb _cb;
26 
27 struct packet {
28 	unsigned char p_buf[2048];
29 	int	      p_len;
30 	struct packet *p_next;
31 } _outbound;
32 
33 enum {
34 	STATE_NONE = 0,
35 	STATE_REDIRECT,
36 	STATE_HANDSHAKE,
37 	STATE_CONNECTED
38 };
39 
40 #define CONN_TIMEOUT 15
41 
42 static struct conmap {
43 	struct sockaddr_in	src;
44 	struct sockaddr_in	dst;
45 	int			state;
46 	time_t			dead;
47 	struct conmap		*next;
48 } _cons;
49 
50 static struct in_addr _local_ip;
51 
52 extern int do_divert_open(void);
53 extern int do_divert_read(int s, void *buf, int len);
54 extern int do_divert_write(int s, void *buf, int len);
55 extern void do_divert_close(int s);
56 
divert_open(int port,divert_cb cb)57 static int divert_open(int port, divert_cb cb)
58 {
59 	int s;
60 	struct sockaddr_in s_in;
61 	socklen_t len = sizeof(s_in);
62 
63 	_s  = do_divert_open();
64 	_cb = cb;
65 
66 	/* figure out local IP */
67 	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
68 		err(1, "socket()");
69 
70 	memset(&s_in, 0, sizeof(&s_in));
71 	s_in.sin_family      = PF_INET;
72 	s_in.sin_addr.s_addr = inet_addr("8.8.8.8");
73 	s_in.sin_port        = htons(666);
74 
75 	if (connect(s, (struct sockaddr*) &s_in, sizeof(s_in)) == -1)
76 		err(1, "connect()");
77 
78 	if (getsockname(s, (struct sockaddr*) &s_in, &len) == -1)
79 		err(1, "getsockname()");
80 
81 	_local_ip.s_addr = s_in.sin_addr.s_addr;
82 
83 	xprintf(XP_ALWAYS, "Local IP is %s\n", inet_ntoa(_local_ip));
84 
85 	close(s);
86 
87 	return _s;
88 }
89 
divert_close(void)90 static void divert_close(void)
91 {
92 	do_divert_close(_s);
93 }
94 
do_redirect(struct conmap * c,struct ip * ip,struct tcphdr * tcp,struct in_addr * fromip,uint32_t toip,uint16_t * fromport,uint16_t toport)95 static void do_redirect(struct conmap *c,
96 			struct ip *ip, struct tcphdr *tcp,
97 			struct in_addr *fromip, uint32_t toip,
98 			uint16_t *fromport, uint16_t toport)
99 {
100 #if 0
101 	xprintf(XP_NOISY, "rdr %s:%d->",
102 		inet_ntoa(*fromip), ntohs(*fromport));
103 #endif
104 	fromip->s_addr = toip;
105 	*fromport      = htons(toport);
106 
107 	checksum_packet(NULL, ip, tcp);
108 #if 0
109 	xprintf(XP_NOISY,"%s:%d\n",
110 		inet_ntoa(*fromip), ntohs(*fromport));
111 #endif
112 
113 	if (tcp->th_flags & (TH_RST | TH_FIN)) {
114 		c->dead = time(NULL);
115 	}
116 }
117 
find_conmap_prev(int sport)118 static struct conmap *find_conmap_prev(int sport)
119 {
120 	struct conmap *c = &_cons;
121 
122 	while (c->next) {
123 		if (c->next->src.sin_port == sport)
124 			return c;
125 
126 		c = c->next;
127 	}
128 
129 	return NULL;
130 }
131 
find_conmap(int sport)132 static struct conmap *find_conmap(int sport)
133 {
134 	struct conmap *c = find_conmap_prev(sport);
135 
136 	if (!c)
137 		return NULL;
138 
139 	return c->next;
140 }
141 
redirect(struct ip * ip,int len,int flags)142 static struct conmap *redirect(struct ip *ip, int len, int flags)
143 {
144 	struct tcphdr *tcp = get_tcp(ip);
145 
146 	if (ntohs(tcp->th_dport) == 80) {
147 		struct conmap *c = find_conmap(tcp->th_sport);
148 
149 		if (!c && (tcp->th_flags == TH_SYN)) {
150 			c = xmalloc(sizeof(*c));
151 			memset(c, 0, sizeof(*c));
152 
153 			c->src.sin_port = tcp->th_sport;
154 			c->state        = STATE_REDIRECT;
155 
156 			c->next     = _cons.next;
157 			_cons.next  = c;
158 		}
159 
160 		/* not redirecting */
161 		if (!c)
162 			return NULL;
163 
164 		/* don't redirect outbound handshake but divert it */
165 		if (c->state == STATE_HANDSHAKE)
166 			return c;
167 
168 		if (c->state != STATE_REDIRECT)
169 			return NULL;
170 
171 		if (tcp->th_flags == TH_SYN)
172 			c->dead = 0;
173 
174 		c->dst.sin_addr.s_addr = ip->ip_dst.s_addr;
175 
176 		do_redirect(c, ip, tcp,
177 			    &ip->ip_dst, _local_ip.s_addr,
178 			    &tcp->th_dport, REDIRECT_PORT);
179 
180 	} else if (ntohs(tcp->th_sport) == REDIRECT_PORT) {
181 		struct conmap *c = find_conmap(tcp->th_dport);
182 
183 		if (!c || c->state != STATE_REDIRECT)
184 			return NULL;
185 
186 		do_redirect(c, ip, tcp,
187 			    &ip->ip_src, c->dst.sin_addr.s_addr,
188 			    &tcp->th_sport, 80);
189 	}
190 
191 	return NULL;
192 }
193 
print_con(void)194 static void print_con(void)
195 {
196 	struct conmap *c = &_cons;
197 
198 	printf("Dumping con\n");
199 
200 	while ((c = c->next)) {
201 		printf("con %s:%d ",
202 		       inet_ntoa(c->src.sin_addr),
203 		       ntohs(c->src.sin_port));
204 
205 		printf("->%s:%d %d [dead %u]\n",
206 		       inet_ntoa(c->dst.sin_addr),
207 		       ntohs(c->dst.sin_port),
208 		       c->state,
209 		       c->dead);
210 	}
211 }
212 
kill_dead(void)213 static void kill_dead(void)
214 {
215 	time_t now = time(NULL);
216 	struct conmap *prev = &_cons, *cur;
217 
218 	while ((cur = prev->next)) {
219 		if (cur->dead && (now - cur->dead) >= CONN_TIMEOUT) {
220 			prev->next = cur->next;
221 			free(cur);
222 			continue;
223 		}
224 
225 		prev = cur;
226 	}
227 }
228 
firewall_divert(struct ip * ip,int len,int flags)229 static int firewall_divert(struct ip *ip, int len, int flags)
230 {
231 	struct tcphdr *tcp = get_tcp(ip);
232 	struct conmap *c;
233 
234 	kill_dead();
235 //	print_con();
236 
237 	c = redirect(ip, len, flags);
238 
239 	/* don't firewall our injections */
240 	if (ip->ip_tos == INJECT_TOS) {
241 		ip->ip_tos = 0;
242 		checksum_ip(ip);
243 		return 0;
244 	}
245 
246 	/* stuff we didn't redirect, so it's going to the outside world */
247 	if (c) {
248 		/* divert syns */
249 		if (tcp->th_flags == TH_SYN)
250 			c->state = STATE_HANDSHAKE;
251 
252 		/* XXX assume it's ACK of 3 way handshake.  Won't work with
253 		 * retransmits */
254 		if (!(tcp->th_flags & TH_SYN)) {
255 			if (c->state == STATE_HANDSHAKE) {
256 //				c->state = STATE_CONNECTED;
257 				return 1;
258 			}
259 		}
260 	}
261 
262 	/* divert handshake */
263 	if (tcp->th_flags & TH_SYN)
264 		return 1;
265 
266 	return 0;
267 }
268 
do_divert_next_packet(unsigned char * buf,int rc)269 static void do_divert_next_packet(unsigned char *buf, int rc)
270 {
271 	int verdict = DIVERT_MODIFY;
272 	int flags = 0;
273 	struct ip *iph = (struct ip*) &buf[MAC_SIZE];
274 	int len;
275 	PDIVERT_ADDRESS addr = (PDIVERT_ADDRESS)buf;
276 
277 	if (rc < MAC_SIZE)
278 		errx(1, "short read %d", rc);
279 
280 	if (addr->Direction == WINDIVERT_DIRECTION_INBOUND)
281 		flags |= DF_IN;
282 
283 	// XXX ethernet padding on short packets?  (46 byte minimum)
284 	len = rc - MAC_SIZE;
285 	if (len > ntohs(iph->ip_len)) {
286 		xprintf(XP_ALWAYS, "Trimming from %d to %d\n",
287 			len, ntohs(iph->ip_len));
288 
289 		len = ntohs(iph->ip_len);
290 	}
291 
292 	if (firewall_divert(iph, len, flags))
293 		verdict = _cb(iph, len, flags);
294 
295 	switch (verdict) {
296 	case DIVERT_MODIFY:
297 		rc = ntohs(iph->ip_len) + MAC_SIZE;
298 		/* fallthrough */
299 	case DIVERT_ACCEPT:
300 		flags = do_divert_write(_s, buf, rc);
301 		if (flags == -1)
302 			err(1, "write()");
303 
304 		if (flags != rc)
305 			errx(1, "wrote %d/%d", flags, rc);
306 		break;
307 
308 	case DIVERT_DROP:
309 		break;
310 
311 	default:
312 		abort();
313 		break;
314 	}
315 }
316 
divert_next_packet(int s)317 static void divert_next_packet(int s)
318 {
319 	unsigned char buf[2048];
320 	int rc;
321 
322 	rc = do_divert_read(_s, buf, sizeof(buf));
323 	if (rc == -1)
324 		err(1, "read()");
325 
326 	if (rc == 0)
327 		errx(1, "EOF");
328 
329 	do_divert_next_packet(buf, rc);
330 }
331 
divert_inject(void * data,int len)332 static void divert_inject(void *data, int len)
333 {
334 	struct packet *p, *p2;
335 	struct ip *ip;
336 
337 	p = malloc(sizeof(*p));
338 	if (!p)
339 		err(1, "malloc()");
340 
341 	memset(p, 0, sizeof(*p));
342 
343 	// XXX: for divert, we can just zero the ethhdr, which contains the
344 	//      DIVERT_ADDRESS.  A zeroed address usually gives the desired
345 	//      result.
346 
347 	/* payload */
348 	p->p_len = len + MAC_SIZE;
349 
350 	if (p->p_len > sizeof(p->p_buf))
351 		errx(1, "too big (divert_inject)");
352 
353 	memcpy(&p->p_buf[MAC_SIZE], data, len);
354 
355 	/* Keep TOS signaling consistent */
356 	ip = (struct ip*) &p->p_buf[MAC_SIZE];
357 	ip->ip_tos = INJECT_TOS;
358 	checksum_ip(ip);
359 
360 	/* add to list */
361 	p2 = &_outbound;
362 
363 	if (p2->p_next)
364 		p2 = p2->p_next;
365 
366 	p2->p_next = p;
367 }
368 
divert_cycle(void)369 static void divert_cycle(void)
370 {
371 	struct packet *p = _outbound.p_next;
372 
373 	while (p) {
374 		struct packet *next = p->p_next;
375 
376 		do_divert_next_packet(p->p_buf, p->p_len);
377 
378 		free(p);
379 
380 		p = next;
381 	}
382 
383 	_outbound.p_next = NULL;
384 }
385 
divert_orig_dest(struct sockaddr_in * out,struct ip * ip,int * flags)386 static int divert_orig_dest(struct sockaddr_in *out, struct ip *ip, int *flags)
387 {
388 	struct tcphdr *tcp = get_tcp(ip);
389 	struct conmap *c = find_conmap(tcp->th_sport);
390 
391 	if (!c || c->state != STATE_REDIRECT)
392 		return -1;
393 
394 	memset(out, 0, sizeof(*out));
395 
396 	out->sin_family      = PF_INET;
397 	out->sin_addr.s_addr = c->dst.sin_addr.s_addr;
398 	out->sin_port        = htons(80);
399 
400 	return 0;
401 }
402 
win_dont_rdr(int s)403 void win_dont_rdr(int s)
404 {
405 	struct sockaddr_in s_in;
406 	struct conmap *c;
407 	socklen_t len = sizeof(s_in);
408 
409 	if (getsockname(s, (struct sockaddr*) &s_in, &len) == -1)
410 		err(1, "getsockname()");
411 
412 	c = find_conmap(s_in.sin_port);
413 	if (c) {
414 		printf("XXX TODO\n");
415 		return;
416 	}
417 
418 	c = xmalloc(sizeof(*c));
419 	memset(c, 0, sizeof(*c));
420 
421 	c->src.sin_port = s_in.sin_port;
422 	c->state        = STATE_HANDSHAKE;
423 
424 	c->next      = _cons.next;
425 	_cons.next = c;
426 
427 	xprintf(XP_NOISY, "No RDR on %d\n", ntohs(c->src.sin_port));
428 }
429 
win_handshake_complete(int s)430 void win_handshake_complete(int s)
431 {
432 	struct sockaddr_in s_in;
433 	struct conmap *c, *con;
434 	socklen_t len = sizeof(s_in);
435 
436 	if (getsockname(s, (struct sockaddr*) &s_in, &len) == -1)
437 		err(1, "getsockname()");
438 
439 	if (!(c = find_conmap_prev(s_in.sin_port))) {
440 		printf("XXX TODO 222\n");
441 		return;
442 	}
443 	con = c->next;
444 
445 	if (con->state != STATE_HANDSHAKE) {
446 		printf("DDDD TODO\n");
447 		return;
448 	}
449 
450 	c->next = con->next;
451 	free(con);
452 }
453 
win_local_ip(void)454 uint32_t win_local_ip(void)
455 {
456 	return _local_ip.s_addr;
457 }
458 
divert_get(void)459 struct divert *divert_get(void)
460 {
461         static struct divert _divert_win = {
462                 .open           = divert_open,
463                 .next_packet    = divert_next_packet,
464                 .close          = divert_close,
465                 .inject         = divert_inject,
466 		.cycle		= divert_cycle,
467 		.orig_dest      = divert_orig_dest,
468         };
469 
470         return &_divert_win;
471 }
472