GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/rebound/rebound.c Lines: 0 541 0.0 %
Date: 2017-11-13 Branches: 0 461 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: rebound.c,v 1.91 2017/08/22 15:47:13 deraadt Exp $ */
2
/*
3
 * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
#include <sys/types.h>
18
#include <sys/socket.h>
19
#include <arpa/inet.h>
20
#include <netinet/in.h>
21
#include <sys/queue.h>
22
#include <sys/tree.h>
23
#include <sys/event.h>
24
#include <sys/resource.h>
25
#include <sys/time.h>
26
#include <sys/wait.h>
27
#include <sys/sysctl.h>
28
29
#include <signal.h>
30
#include <syslog.h>
31
#include <stdlib.h>
32
#include <stdio.h>
33
#include <limits.h>
34
#include <string.h>
35
#include <ctype.h>
36
#include <err.h>
37
#include <unistd.h>
38
#include <fcntl.h>
39
#include <pwd.h>
40
#include <errno.h>
41
#include <getopt.h>
42
#include <stdarg.h>
43
#include <ctype.h>
44
45
#define MINIMUM(a,b) (((a)<(b))?(a):(b))
46
47
uint16_t randomid(void);
48
49
union sockun {
50
	struct sockaddr a;
51
	struct sockaddr_storage s;
52
	struct sockaddr_in i;
53
	struct sockaddr_in6 i6;
54
};
55
56
static struct timespec now;
57
static int debug;
58
static int daemonized;
59
60
struct dnspacket {
61
	uint16_t id;
62
	uint16_t flags;
63
	uint16_t qdcount;
64
	uint16_t ancount;
65
	uint16_t nscount;
66
	uint16_t arcount;
67
	char qname[];
68
	/* ... */
69
};
70
#define NAMELEN 256
71
72
/*
73
 * requests will point to cache entries until a response is received.
74
 * until then, the request owns the entry and must free it.
75
 * after the response is set, the request must not free it.
76
 */
77
struct dnscache {
78
	TAILQ_ENTRY(dnscache) fifo;
79
	RB_ENTRY(dnscache) cachenode;
80
	struct dnspacket *req;
81
	size_t reqlen;
82
	struct dnspacket *resp;
83
	size_t resplen;
84
	struct timespec ts;
85
	struct timespec basetime;
86
};
87
static TAILQ_HEAD(, dnscache) cachefifo;
88
static RB_HEAD(cachetree, dnscache) cachetree;
89
RB_PROTOTYPE_STATIC(cachetree, dnscache, cachenode, cachecmp)
90
91
static int cachecount;
92
static int cachemax;
93
static uint64_t cachehits;
94
95
/*
96
 * requests are kept on a fifo list, but only after socket s is set.
97
 */
98
struct request {
99
	int s;
100
	int client;
101
	int tcp;
102
	union sockun from;
103
	socklen_t fromlen;
104
	struct timespec ts;
105
	TAILQ_ENTRY(request) fifo;
106
	uint16_t clientid;
107
	uint16_t reqid;
108
	struct dnscache *cacheent;
109
	char origname[NAMELEN];
110
	char newname[NAMELEN];
111
};
112
static TAILQ_HEAD(, request) reqfifo;
113
114
static int conncount;
115
static int connmax;
116
static uint64_t conntotal;
117
static int stopaccepting;
118
119
static void
120
logmsg(int prio, const char *msg, ...)
121
{
122
	va_list ap;
123
124
	if (debug || !daemonized) {
125
		va_start(ap, msg);
126
		vfprintf(stdout, msg, ap);
127
		fprintf(stdout, "\n");
128
		va_end(ap);
129
	}
130
	if (!debug) {
131
		va_start(ap, msg);
132
		vsyslog(LOG_DAEMON | prio, msg, ap);
133
		va_end(ap);
134
	}
135
}
136
137
static void __dead
138
logerr(const char *msg, ...)
139
{
140
	va_list ap;
141
142
	if (debug || !daemonized) {
143
		va_start(ap, msg);
144
		fprintf(stderr, "rebound: ");
145
		vfprintf(stderr, msg, ap);
146
		fprintf(stderr, "\n");
147
		va_end(ap);
148
	}
149
	if (!debug) {
150
		va_start(ap, msg);
151
		vsyslog(LOG_DAEMON | LOG_ERR, msg, ap);
152
		va_end(ap);
153
	}
154
	exit(1);
155
}
156
157
static int
158
cachecmp(struct dnscache *c1, struct dnscache *c2)
159
{
160
	if (c1->reqlen == c2->reqlen)
161
		return memcmp(c1->req, c2->req, c1->reqlen);
162
	return c1->reqlen < c2->reqlen ? -1 : 1;
163
}
164
RB_GENERATE_STATIC(cachetree, dnscache, cachenode, cachecmp)
165
166
static void
167
lowercase(unsigned char *s, size_t len)
168
{
169
	while (len--) {
170
		*s = tolower(*s);
171
		s++;
172
	}
173
}
174
175
static void
176
randomcase(unsigned char *s, size_t len)
177
{
178
	unsigned char bits[NAMELEN / 8], *b;
179
	u_int i = 0;
180
181
	arc4random_buf(bits, (len + 7) / 8);
182
	b = bits;
183
	while (len--) {
184
		*s = (*b & (1 << i)) ? toupper(*s) : tolower(*s);
185
		s++;
186
		i++;
187
		if (i == 8) {
188
			b++;
189
			i = 0;
190
		}
191
	}
192
}
193
194
static void
195
freecacheent(struct dnscache *ent)
196
{
197
	cachecount -= 1;
198
	RB_REMOVE(cachetree, &cachetree, ent);
199
	TAILQ_REMOVE(&cachefifo, ent, fifo);
200
	free(ent->req);
201
	free(ent->resp);
202
	free(ent);
203
}
204
205
/*
206
 * names end with either a nul byte, or a two byte 0xc0 pointer
207
 */
208
static size_t
209
dnamelen(const unsigned char *p, size_t len)
210
{
211
	size_t n = 0;
212
213
	for (n = 0; n < len; n++) {
214
		if (p[n] == 0)
215
			return n + 1;
216
		if ((p[n] & 0xc0) == 0xc0)
217
			return n + 2;
218
	}
219
	return len + 1;
220
}
221
222
static int
223
adjustttl(struct dnscache *ent)
224
{
225
	struct dnspacket *resp = ent->resp;
226
	char *p = (char *)resp;
227
	u_int rlen = ent->resplen;
228
	u_int used = 0;
229
	uint32_t ttl, cnt, i;
230
	uint16_t len;
231
	time_t diff;
232
233
	diff = now.tv_sec - ent->basetime.tv_sec;
234
	if (diff <= 0)
235
		return 0;
236
237
	/* checks are redundant; checked when cacheent is created */
238
	/* skip past packet header */
239
	used += sizeof(struct dnspacket);
240
	if (used >= rlen)
241
		return -1;
242
	if (ntohs(resp->qdcount) != 1)
243
		return -1;
244
	/* skip past query name, type, and class */
245
	used += dnamelen(p + used, rlen - used);
246
	used += 2;
247
	used += 2;
248
	cnt = ntohs(resp->ancount);
249
	for (i = 0; i < cnt; i++) {
250
		if (used >= rlen)
251
			return -1;
252
		/* skip past answer name, type, and class */
253
		used += dnamelen(p + used, rlen - used);
254
		used += 2;
255
		used += 2;
256
		if (used + 4 >= rlen)
257
			return -1;
258
		memcpy(&ttl, p + used, 4);
259
		ttl = ntohl(ttl);
260
		/* expired */
261
		if (diff >= ttl)
262
			return -1;
263
		ttl -= diff;
264
		ttl = ntohl(ttl);
265
		memcpy(p + used, &ttl, 4);
266
		used += 4;
267
		if (used + 2 >= rlen)
268
			return -1;
269
		memcpy(&len, p + used, 2);
270
		used += 2;
271
		used += ntohs(len);
272
	}
273
	ent->basetime.tv_sec += diff;
274
	return 0;
275
}
276
277
static struct dnscache *
278
cachelookup(struct dnspacket *dnsreq, size_t reqlen, size_t namelen)
279
{
280
	struct dnscache *hit, key;
281
	unsigned char origname[NAMELEN];
282
	uint16_t origid;
283
284
	memcpy(origname, dnsreq->qname, namelen);
285
	lowercase(dnsreq->qname, namelen);
286
287
	origid = dnsreq->id;
288
	dnsreq->id = 0;
289
290
	key.reqlen = reqlen;
291
	key.req = dnsreq;
292
	hit = RB_FIND(cachetree, &cachetree, &key);
293
	if (hit) {
294
		if (adjustttl(hit) != 0) {
295
			freecacheent(hit);
296
			hit = NULL;
297
		} else
298
			cachehits += 1;
299
	}
300
301
	memcpy(dnsreq->qname, origname, namelen);
302
	dnsreq->id = origid;
303
	return hit;
304
}
305
306
static void
307
freerequest(struct request *req)
308
{
309
	struct dnscache *ent;
310
311
	if (req->tcp)
312
		conncount -= 2;
313
	else
314
		conncount -= 1;
315
	if (req->s != -1) {
316
		TAILQ_REMOVE(&reqfifo, req, fifo);
317
		close(req->s);
318
	}
319
	if (req->tcp && req->client != -1)
320
		close(req->client);
321
	if ((ent = req->cacheent) && !ent->resp) {
322
		free(ent->req);
323
		free(ent);
324
	}
325
	free(req);
326
}
327
328
static void
329
servfail(int ud, uint16_t id, struct sockaddr *fromaddr, socklen_t fromlen)
330
{
331
	struct dnspacket pkt;
332
333
	memset(&pkt, 0, sizeof(pkt));
334
	pkt.id = id;
335
	pkt.flags = htons(1 << 15 | 0x2);
336
	sendto(ud, &pkt, sizeof(pkt), 0, fromaddr, fromlen);
337
}
338
339
static struct request *
340
newrequest(int ud, struct sockaddr *remoteaddr)
341
{
342
	union sockun from;
343
	socklen_t fromlen;
344
	struct request *req;
345
	uint8_t buf[65536];
346
	struct dnspacket *dnsreq;
347
	struct dnscache *hit = NULL;
348
	size_t r;
349
	size_t namelen = 0;
350
351
	dnsreq = (struct dnspacket *)buf;
352
353
	fromlen = sizeof(from);
354
	r = recvfrom(ud, buf, sizeof(buf), 0, &from.a, &fromlen);
355
	if (r == 0 || r == -1 || r < sizeof(struct dnspacket))
356
		return NULL;
357
	if (ntohs(dnsreq->qdcount) == 1) {
358
		/* some more checking */
359
		namelen = dnamelen(dnsreq->qname, r - sizeof(struct dnspacket));
360
		if (namelen > r - sizeof(struct dnspacket))
361
			return NULL;
362
		if (namelen > NAMELEN)
363
			return NULL;
364
		hit = cachelookup(dnsreq, r, namelen);
365
	}
366
367
	conntotal += 1;
368
	if (hit) {
369
		hit->resp->id = dnsreq->id;
370
		memcpy(hit->resp->qname, dnsreq->qname, namelen);
371
		sendto(ud, hit->resp, hit->resplen, 0, &from.a, fromlen);
372
		return NULL;
373
	}
374
375
	if (!(req = calloc(1, sizeof(*req))))
376
		return NULL;
377
378
	conncount += 1;
379
	req->ts = now;
380
	req->ts.tv_sec += 30;
381
	req->s = -1;
382
383
	req->client = ud;
384
	memcpy(&req->from, &from, fromlen);
385
	req->fromlen = fromlen;
386
387
	req->clientid = dnsreq->id;
388
	req->reqid = randomid();
389
	dnsreq->id = req->reqid;
390
	if (ntohs(dnsreq->qdcount) == 1) {
391
		memcpy(req->origname, dnsreq->qname, namelen);
392
		randomcase(dnsreq->qname, namelen);
393
		memcpy(req->newname, dnsreq->qname, namelen);
394
395
		hit = calloc(1, sizeof(*hit));
396
		if (hit) {
397
			hit->req = malloc(r);
398
			if (hit->req) {
399
				memcpy(hit->req, dnsreq, r);
400
				hit->reqlen = r;
401
				hit->req->id = 0;
402
				lowercase(hit->req->qname, namelen);
403
			} else {
404
				free(hit);
405
				hit = NULL;
406
407
			}
408
		}
409
		req->cacheent = hit;
410
	}
411
412
	req->s = socket(remoteaddr->sa_family, SOCK_DGRAM, 0);
413
	if (req->s == -1)
414
		goto fail;
415
416
	TAILQ_INSERT_TAIL(&reqfifo, req, fifo);
417
418
	if (connect(req->s, remoteaddr, remoteaddr->sa_len) == -1) {
419
		logmsg(LOG_NOTICE, "failed to connect (%d)", errno);
420
		if (errno == EADDRNOTAVAIL)
421
			servfail(ud, req->clientid, &from.a, fromlen);
422
		goto fail;
423
	}
424
	if (send(req->s, buf, r, 0) != r) {
425
		logmsg(LOG_NOTICE, "failed to send (%d)", errno);
426
		goto fail;
427
	}
428
429
	return req;
430
431
fail:
432
	freerequest(req);
433
	return NULL;
434
}
435
436
static uint32_t
437
minttl(struct dnspacket *resp, u_int rlen)
438
{
439
	uint32_t minttl = -1, ttl, cnt, i;
440
	uint16_t len;
441
	char *p = (char *)resp;
442
	u_int used = 0;
443
444
	/* skip past packet header */
445
	used += sizeof(struct dnspacket);
446
	if (used >= rlen)
447
		return -1;
448
	if (ntohs(resp->qdcount) != 1)
449
		return -1;
450
	/* skip past query name, type, and class */
451
	used += dnamelen(p + used, rlen - used);
452
	used += 2;
453
	used += 2;
454
	cnt = ntohs(resp->ancount);
455
	for (i = 0; i < cnt; i++) {
456
		if (used >= rlen)
457
			return -1;
458
		/* skip past answer name, type, and class */
459
		used += dnamelen(p + used, rlen - used);
460
		used += 2;
461
		used += 2;
462
		if (used + 4 >= rlen)
463
			return -1;
464
		memcpy(&ttl, p + used, 4);
465
		used += 4;
466
		if (used + 2 >= rlen)
467
			return -1;
468
		ttl = ntohl(ttl);
469
		if (ttl < minttl)
470
			minttl = ttl;
471
		memcpy(&len, p + used, 2);
472
		used += 2;
473
		used += ntohs(len);
474
	}
475
	return minttl;
476
}
477
478
static void
479
sendreply(struct request *req)
480
{
481
	uint8_t buf[65536];
482
	struct dnspacket *resp;
483
	struct dnscache *ent;
484
	size_t r;
485
	uint32_t ttl;
486
487
	resp = (struct dnspacket *)buf;
488
489
	r = recv(req->s, buf, sizeof(buf), 0);
490
	if (r == 0 || r == -1 || r < sizeof(struct dnspacket))
491
		return;
492
	if (resp->id != req->reqid)
493
		return;
494
	resp->id = req->clientid;
495
	if (ntohs(resp->qdcount) == 1) {
496
		/* some more checking */
497
		size_t namelen = dnamelen(resp->qname, r - sizeof(struct dnspacket));
498
		if (namelen > r - sizeof(struct dnspacket))
499
			return;
500
		if (namelen > NAMELEN)
501
			return;
502
		if (memcmp(resp->qname, req->newname, namelen) != 0)
503
			return;
504
		memcpy(resp->qname, req->origname, namelen);
505
	}
506
	sendto(req->client, buf, r, 0, &req->from.a, req->fromlen);
507
	if ((ent = req->cacheent)) {
508
		/* check that the response is worth caching */
509
		ttl = minttl(resp, r);
510
		if (ttl == -1 || ttl == 0)
511
			return;
512
		/*
513
		 * we do this next, because there's a potential race against
514
		 * other requests made at the same time. if we lose, abort.
515
		 * if anything else goes wrong, though, we need to reverse.
516
		 */
517
		if (RB_INSERT(cachetree, &cachetree, ent))
518
			return;
519
		ent->ts = now;
520
		ent->ts.tv_sec += MINIMUM(ttl, 300);
521
		ent->basetime = now;
522
		ent->resp = malloc(r);
523
		if (!ent->resp) {
524
			RB_REMOVE(cachetree, &cachetree, ent);
525
			return;
526
		}
527
		memcpy(ent->resp, buf, r);
528
		ent->resplen = r;
529
		cachecount += 1;
530
		TAILQ_INSERT_TAIL(&cachefifo, ent, fifo);
531
	}
532
}
533
534
static struct request *
535
tcpphasetwo(struct request *req)
536
{
537
	int error;
538
	socklen_t len = sizeof(error);
539
540
	req->tcp = 2;
541
542
	if (getsockopt(req->s, SOL_SOCKET, SO_ERROR, &error, &len) == -1 ||
543
	    error != 0)
544
		goto fail;
545
	if (setsockopt(req->client, SOL_SOCKET, SO_SPLICE, &req->s,
546
	    sizeof(req->s)) == -1)
547
		goto fail;
548
	if (setsockopt(req->s, SOL_SOCKET, SO_SPLICE, &req->client,
549
	    sizeof(req->client)) == -1)
550
		goto fail;
551
552
	return req;
553
554
fail:
555
	freerequest(req);
556
	return NULL;
557
}
558
559
static struct request *
560
newtcprequest(int ld, struct sockaddr *remoteaddr)
561
{
562
	struct request *req;
563
	int client;
564
565
	client = accept(ld, NULL, 0);
566
	if (client == -1) {
567
		if (errno == ENFILE || errno == EMFILE)
568
			stopaccepting = 1;
569
		return NULL;
570
	}
571
572
	if (!(req = calloc(1, sizeof(*req)))) {
573
		close(client);
574
		return NULL;
575
	}
576
577
	conntotal += 1;
578
	conncount += 2;
579
	req->ts = now;
580
	req->ts.tv_sec += 30;
581
	req->tcp = 1;
582
	req->client = client;
583
584
	req->s = socket(remoteaddr->sa_family, SOCK_STREAM | SOCK_NONBLOCK, 0);
585
	if (req->s == -1)
586
		goto fail;
587
588
	TAILQ_INSERT_TAIL(&reqfifo, req, fifo);
589
590
	if (connect(req->s, remoteaddr, remoteaddr->sa_len) == -1) {
591
		if (errno != EINPROGRESS)
592
			goto fail;
593
	} else {
594
		return tcpphasetwo(req);
595
	}
596
597
	return req;
598
599
fail:
600
	freerequest(req);
601
	return NULL;
602
}
603
604
static int
605
readconfig(int conffd, union sockun *remoteaddr)
606
{
607
	const char ns[] = "nameserver";
608
	char buf[1024];
609
	char *p;
610
	struct sockaddr_in *sin = &remoteaddr->i;
611
	struct sockaddr_in6 *sin6 = &remoteaddr->i6;
612
	FILE *conf;
613
	int rv = -1;
614
615
	conf = fdopen(conffd, "r");
616
617
	while (fgets(buf, sizeof(buf), conf) != NULL) {
618
		buf[strcspn(buf, "\n")] = '\0';
619
620
		if (strncmp(buf, ns, strlen(ns)) != 0)
621
			continue;
622
		p = buf + strlen(ns) + 1;
623
		while (isspace((unsigned char)*p))
624
			p++;
625
626
		/* this will not end well */
627
		if (strcmp(p, "127.0.0.1") == 0)
628
			continue;
629
630
		memset(remoteaddr, 0, sizeof(*remoteaddr));
631
		if (inet_pton(AF_INET, p, &sin->sin_addr) == 1) {
632
			sin->sin_len = sizeof(*sin);
633
			sin->sin_family = AF_INET;
634
			sin->sin_port = htons(53);
635
			rv = AF_INET;
636
		} else if (inet_pton(AF_INET6, p, &sin6->sin6_addr) == 1) {
637
			sin6->sin6_len = sizeof(*sin6);
638
			sin6->sin6_family = AF_INET6;
639
			sin6->sin6_port = htons(53);
640
			rv = AF_INET6;
641
		}
642
		break;
643
	}
644
	fclose(conf);
645
	return rv;
646
}
647
648
static void
649
workerinit(void)
650
{
651
	struct rlimit rlim;
652
	struct passwd *pwd;
653
654
	if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
655
		logerr("getrlimit: %s", strerror(errno));
656
	rlim.rlim_cur = rlim.rlim_max;
657
	if (setrlimit(RLIMIT_NOFILE, &rlim) == -1)
658
		logerr("setrlimit: %s", strerror(errno));
659
	connmax = rlim.rlim_cur - 10;
660
	if (connmax > 512)
661
		connmax = 512;
662
663
	cachemax = 10000; /* something big, but not huge */
664
665
	TAILQ_INIT(&reqfifo);
666
	TAILQ_INIT(&cachefifo);
667
	RB_INIT(&cachetree);
668
669
	if (!(pwd = getpwnam("_rebound")))
670
		logerr("getpwnam failed");
671
672
	if (chroot(pwd->pw_dir) == -1)
673
		logerr("chroot: %s", strerror(errno));
674
	if (chdir("/") == -1)
675
		logerr("chdir: %s", strerror(errno));
676
677
	setproctitle("worker");
678
	if (setgroups(1, &pwd->pw_gid) ||
679
	    setresgid(pwd->pw_gid, pwd->pw_gid, pwd->pw_gid) ||
680
	    setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid))
681
		logerr("failed to privdrop");
682
683
	if (pledge("stdio inet flock rpath cpath wpath", NULL) == -1)
684
		logerr("pledge failed");
685
}
686
687
static int
688
workerloop(int conffd, int ud, int ld, int ud6, int ld6)
689
{
690
	union sockun remoteaddr;
691
	struct kevent ch[2], kev[4];
692
	struct timespec ts, *timeout = NULL;
693
	struct request *req;
694
	struct dnscache *ent;
695
	int i, r, af, kq;
696
697
	kq = kqueue();
698
699
	if (!debug) {
700
		pid_t parent = getppid();
701
		/* would need pledge(proc) to do this below */
702
		EV_SET(&kev[0], parent, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
703
		if (kevent(kq, kev, 1, NULL, 0, NULL) == -1)
704
			logerr("kevent1: %d", errno);
705
	}
706
707
	workerinit();
708
709
	af = readconfig(conffd, &remoteaddr);
710
	if (af == -1)
711
		logerr("parse error in config file");
712
713
	EV_SET(&kev[0], ud, EVFILT_READ, EV_ADD, 0, 0, NULL);
714
	EV_SET(&kev[1], ld, EVFILT_READ, EV_ADD, 0, 0, NULL);
715
	EV_SET(&kev[2], ud6, EVFILT_READ, EV_ADD, 0, 0, NULL);
716
	EV_SET(&kev[3], ld6, EVFILT_READ, EV_ADD, 0, 0, NULL);
717
	if (kevent(kq, kev, 4, NULL, 0, NULL) == -1)
718
		logerr("kevent4: %d", errno);
719
	EV_SET(&kev[0], SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
720
	EV_SET(&kev[1], SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
721
	if (kevent(kq, kev, 2, NULL, 0, NULL) == -1)
722
		logerr("kevent2: %d", errno);
723
	logmsg(LOG_INFO, "worker process going to work");
724
	while (1) {
725
		r = kevent(kq, NULL, 0, kev, 4, timeout);
726
		if (r == -1)
727
			logerr("kevent failed (%d)", errno);
728
729
		clock_gettime(CLOCK_MONOTONIC, &now);
730
731
		if (stopaccepting) {
732
			EV_SET(&ch[0], ld, EVFILT_READ, EV_ADD, 0, 0, NULL);
733
			kevent(kq, ch, 1, NULL, 0, NULL);
734
			stopaccepting = 0;
735
		}
736
737
		for (i = 0; i < r; i++) {
738
			struct kevent *ke = &kev[i];
739
			switch (ke->filter) {
740
			case EVFILT_SIGNAL:
741
				if (ke->ident == SIGHUP) {
742
					logmsg(LOG_INFO, "hupped, exiting");
743
					exit(0);
744
				} else {
745
					logmsg(LOG_INFO, "connection stats: "
746
					    "%d active, %llu total",
747
					    conncount, conntotal);
748
					logmsg(LOG_INFO, "cache stats: "
749
					    "%d active, %llu hits",
750
					    cachecount, cachehits);
751
				}
752
				break;
753
			case EVFILT_PROC:
754
				logmsg(LOG_INFO, "parent died");
755
				exit(0);
756
				break;
757
			case EVFILT_WRITE:
758
				req = ke->udata;
759
				req = tcpphasetwo(req);
760
				if (req) {
761
					EV_SET(&ch[0], req->s, EVFILT_WRITE,
762
					    EV_DELETE, 0, 0, NULL);
763
					EV_SET(&ch[1], req->s, EVFILT_READ,
764
					    EV_ADD, 0, 0, req);
765
					kevent(kq, ch, 2, NULL, 0, NULL);
766
				}
767
				break;
768
			case EVFILT_READ:
769
				if (ke->ident == ud || ke->ident == ud6) {
770
					if ((req = newrequest(ke->ident, &remoteaddr.a))) {
771
						EV_SET(&ch[0], req->s, EVFILT_READ,
772
						    EV_ADD, 0, 0, req);
773
						kevent(kq, ch, 1, NULL, 0, NULL);
774
					}
775
				} else if (ke->ident == ld || ke->ident == ld6) {
776
					if ((req = newtcprequest(ke->ident, &remoteaddr.a))) {
777
						EV_SET(&ch[0], req->s,
778
						    req->tcp == 1 ? EVFILT_WRITE :
779
						    EVFILT_READ, EV_ADD, 0, 0, req);
780
						kevent(kq, ch, 1, NULL, 0, NULL);
781
					}
782
				} else {
783
					req = ke->udata;
784
					if (req->tcp == 0)
785
						sendreply(req);
786
					freerequest(req);
787
				}
788
				break;
789
			default:
790
				logerr("don't know what happened");
791
				break;
792
			}
793
		}
794
795
		timeout = NULL;
796
797
		if (stopaccepting) {
798
			EV_SET(&ch[0], ld, EVFILT_READ, EV_DELETE, 0, 0, NULL);
799
			kevent(kq, ch, 1, NULL, 0, NULL);
800
			memset(&ts, 0, sizeof(ts));
801
			/* one second added below */
802
			timeout = &ts;
803
		}
804
805
		while (conncount > connmax)
806
			freerequest(TAILQ_FIRST(&reqfifo));
807
		while (cachecount > cachemax)
808
			freecacheent(TAILQ_FIRST(&cachefifo));
809
810
		/* burn old cache entries */
811
		while ((ent = TAILQ_FIRST(&cachefifo))) {
812
			if (timespeccmp(&ent->ts, &now, <=))
813
				freecacheent(ent);
814
			else
815
				break;
816
		}
817
		if (ent) {
818
			timespecsub(&ent->ts, &now, &ts);
819
			timeout = &ts;
820
		}
821
822
		/* burn stalled requests */
823
		while ((req = TAILQ_FIRST(&reqfifo))) {
824
			if (timespeccmp(&req->ts, &now, <=))
825
				freerequest(req);
826
			else
827
				break;
828
		}
829
		if (req && (!ent || timespeccmp(&req->ts, &ent->ts, <=))) {
830
			timespecsub(&req->ts, &now, &ts);
831
			timeout = &ts;
832
		}
833
		/* one second grace to avoid spinning */
834
		if (timeout)
835
			timeout->tv_sec += 1;
836
837
	}
838
	/* not reached */
839
	exit(1);
840
}
841
842
static int
843
openconfig(const char *confname, int kq)
844
{
845
	struct kevent kev;
846
	int conffd;
847
848
	conffd = open(confname, O_RDONLY);
849
	if (conffd == -1)
850
		logerr("failed to open config %s", confname);
851
	if (kq != -1) {
852
		EV_SET(&kev, conffd, EVFILT_VNODE, EV_ADD,
853
		    NOTE_DELETE | NOTE_ATTRIB, 0, NULL);
854
		kevent(kq, &kev, 1, NULL, 0, NULL);
855
	}
856
	return conffd;
857
}
858
859
static pid_t
860
reexec(int conffd, int ud, int ld, int ud6, int ld6)
861
{
862
	pid_t child;
863
864
	if (conffd != 8 || ud != 3 || ld != 4 || ud6 != 5 || ld6 != 6)
865
		logerr("can't re-exec, fds are wrong");
866
867
	switch ((child = fork())) {
868
	case -1:
869
		logerr("failed to fork");
870
		break;
871
	case 0:
872
		execl("/usr/sbin/rebound", "rebound", "-W", NULL);
873
		logerr("re-exec failed");
874
	default:
875
		break;
876
	}
877
	return child;
878
}
879
880
static int
881
monitorloop(int ud, int ld, int ud6, int ld6, const char *confname)
882
{
883
	pid_t child;
884
	struct kevent kev;
885
	int r, kq;
886
	int conffd = -1;
887
	struct timespec ts, *timeout = NULL;
888
889
	kq = kqueue();
890
891
	/* catch these signals with kevent */
892
	signal(SIGHUP, SIG_IGN);
893
	EV_SET(&kev, SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
894
	kevent(kq, &kev, 1, NULL, 0, NULL);
895
	signal(SIGTERM, SIG_IGN);
896
	EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
897
	kevent(kq, &kev, 1, NULL, 0, NULL);
898
	while (1) {
899
		int hupped = 0;
900
		int childdead = 0;
901
902
		if (conffd == -1)
903
			conffd = openconfig(confname, kq);
904
905
		child = reexec(conffd, ud, ld, ud6, ld6);
906
907
		/* monitor child */
908
		EV_SET(&kev, child, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
909
		kevent(kq, &kev, 1, NULL, 0, NULL);
910
911
		/* wait for something to happen: HUP or child exiting */
912
		timeout = NULL;
913
		while (1) {
914
			r = kevent(kq, NULL, 0, &kev, 1, timeout);
915
			if (r == -1)
916
				logerr("kevent failed (%d)", errno);
917
			if (r == 0) {
918
				/* timeout expired */
919
				logerr("child died without HUP");
920
			}
921
			switch (kev.filter) {
922
			case EVFILT_VNODE:
923
				/* config file changed */
924
				logmsg(LOG_INFO, "config changed, reloading");
925
				close(conffd);
926
				conffd = -1;
927
				sleep(1);
928
				raise(SIGHUP);
929
				break;
930
			case EVFILT_SIGNAL:
931
				if (kev.ident == SIGHUP) {
932
					/* signaled. kill child. */
933
					logmsg(LOG_INFO, "received HUP, restarting");
934
					hupped = 1;
935
					if (childdead)
936
						goto doublebreak;
937
					kill(child, SIGHUP);
938
				} else if (kev.ident == SIGTERM) {
939
					/* good bye */
940
					logmsg(LOG_INFO, "received TERM, quitting");
941
					kill(child, SIGTERM);
942
					exit(0);
943
				}
944
				break;
945
			case EVFILT_PROC:
946
				/* child died. wait for our own HUP. */
947
				logmsg(LOG_INFO, "observed child exit");
948
				childdead = 1;
949
				if (hupped)
950
					goto doublebreak;
951
				memset(&ts, 0, sizeof(ts));
952
				ts.tv_sec = 1;
953
				timeout = &ts;
954
				break;
955
			default:
956
				logerr("don't know what happened");
957
				break;
958
			}
959
		}
960
doublebreak:
961
		while (waitpid(child, NULL, 0) == -1) {
962
			if (errno != EINTR)
963
				break;
964
		}
965
	}
966
	return 1;
967
}
968
969
static void
970
resetport(void)
971
{
972
	int dnsjacking[2] = { CTL_KERN, KERN_DNSJACKPORT };
973
	int jackport = 0;
974
975
	sysctl(dnsjacking, 2, NULL, NULL, &jackport, sizeof(jackport));
976
}
977
978
static void __dead
979
usage(void)
980
{
981
	fprintf(stderr, "usage: rebound [-d] [-c config] [-l address]\n");
982
	exit(1);
983
}
984
985
int
986
main(int argc, char **argv)
987
{
988
	int dnsjacking[2] = { CTL_KERN, KERN_DNSJACKPORT };
989
	int jackport = 54;
990
	union sockun bindaddr;
991
	int ld, ld6, ud, ud6, ch;
992
	int one = 1;
993
	const char *confname = "/etc/resolv.conf";
994
	const char *bindname = "127.0.0.1";
995
996
	tzset();
997
	openlog("rebound", LOG_PID | LOG_NDELAY, LOG_DAEMON);
998
999
	signal(SIGPIPE, SIG_IGN);
1000
	signal(SIGUSR1, SIG_IGN);
1001
1002
	while ((ch = getopt(argc, argv, "c:dl:W")) != -1) {
1003
		switch (ch) {
1004
		case 'c':
1005
			confname = optarg;
1006
			break;
1007
		case 'd':
1008
			debug = 1;
1009
			break;
1010
		case 'l':
1011
			bindname = optarg;
1012
			jackport = 0;
1013
			break;
1014
		case 'W':
1015
			daemonized = 1;
1016
			/* parent responsible for setting up fds */
1017
			return workerloop(8, 3, 4, 5, 6);
1018
		default:
1019
			usage();
1020
			break;
1021
		}
1022
	}
1023
	argv += optind;
1024
	argc -= optind;
1025
1026
	if (argc)
1027
		usage();
1028
1029
	/* make sure we consistently open fds */
1030
	closefrom(3);
1031
1032
	memset(&bindaddr, 0, sizeof(bindaddr));
1033
	bindaddr.i.sin_len = sizeof(bindaddr.i);
1034
	bindaddr.i.sin_family = AF_INET;
1035
	bindaddr.i.sin_port = htons(jackport ? jackport : 53);
1036
	inet_aton(bindname, &bindaddr.i.sin_addr);
1037
1038
	ud = socket(AF_INET, SOCK_DGRAM, 0);
1039
	if (ud == -1)
1040
		logerr("socket: %s", strerror(errno));
1041
	if (bind(ud, &bindaddr.a, bindaddr.a.sa_len) == -1)
1042
		logerr("bind: %s", strerror(errno));
1043
1044
	ld = socket(AF_INET, SOCK_STREAM, 0);
1045
	if (ld == -1)
1046
		logerr("socket: %s", strerror(errno));
1047
	setsockopt(ld, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
1048
	if (bind(ld, &bindaddr.a, bindaddr.a.sa_len) == -1)
1049
		logerr("bind: %s", strerror(errno));
1050
	if (listen(ld, 10) == -1)
1051
		logerr("listen: %s", strerror(errno));
1052
1053
	memset(&bindaddr, 0, sizeof(bindaddr));
1054
	bindaddr.i6.sin6_len = sizeof(bindaddr.i6);
1055
	bindaddr.i6.sin6_family = AF_INET6;
1056
	bindaddr.i6.sin6_port = htons(jackport ? jackport : 53);
1057
	bindaddr.i6.sin6_addr = in6addr_loopback;
1058
1059
	ud6 = socket(AF_INET6, SOCK_DGRAM, 0);
1060
	if (ud6 == -1)
1061
		logerr("socket: %s", strerror(errno));
1062
	if (bind(ud6, &bindaddr.a, bindaddr.a.sa_len) == -1)
1063
		logerr("bind: %s", strerror(errno));
1064
1065
	ld6 = socket(AF_INET6, SOCK_STREAM, 0);
1066
	if (ld6 == -1)
1067
		logerr("socket: %s", strerror(errno));
1068
	setsockopt(ld6, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
1069
	if (bind(ld6, &bindaddr.a, bindaddr.a.sa_len) == -1)
1070
		logerr("bind: %s", strerror(errno));
1071
	if (listen(ld6, 10) == -1)
1072
		logerr("listen: %s", strerror(errno));
1073
1074
	if (jackport) {
1075
		atexit(resetport);
1076
		sysctl(dnsjacking, 2, NULL, NULL, &jackport, sizeof(jackport));
1077
	}
1078
1079
	if (debug) {
1080
		int conffd = openconfig(confname, -1);
1081
		return workerloop(conffd, ud, ld, ud6, ld6);
1082
	}
1083
1084
	if (daemon(0, 0) == -1)
1085
		logerr("daemon: %s", strerror(errno));
1086
	daemonized = 1;
1087
1088
	return monitorloop(ud, ld, ud6, ld6, confname);
1089
}