1 /*
2  * Copyright 2001 Niels Provos <provos@citi.umich.edu>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Niels Provos.
16  * 4. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/types.h>
32 #include <sys/queue.h>
33 #include <sys/socket.h>
34 #include <sys/time.h>
35 #include <netdb.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <signal.h>
40 #include <unistd.h>
41 #include <err.h>
42 
43 #include <event.h>
44 
45 #include "config.h"
46 #include "tree.h"
47 #include "http.h"
48 #include "dns.h"
49 
50 ssize_t atomicio(ssize_t (*f)(), int, void *, size_t);
51 
52 extern int debug;
53 #define DFPRINTF(x,y)   if (debug >= x) fprintf y
54 
55 #define DNS_MAXLRUSIZE	65536
56 
57 struct dns_child {
58 	pid_t pid;
59 	struct dns_entry *current;
60 
61 	int waits;
62 
63 	struct event ev_read;
64 	struct event ev_write;
65 	int cmd_write;
66 	int res_read;
67 
68 	struct dns_list waitqueue;
69 };
70 
71 struct dns_child children[DNS_MAX_CHILDREN];
72 int childnr = 0;
73 
74 struct stats {
75 	int hits;
76 	int replacements;
77 	int iterations;
78 	int calls;
79 } dns_stats;
80 
81 SPLAY_HEAD(tree, dns_entry) root;
82 
83 static int
compare(struct dns_entry * a,struct dns_entry * b)84 compare(struct dns_entry *a, struct dns_entry *b)
85 {
86 	dns_stats.iterations++;
87 	return (strcasecmp(a->name, b->name));
88 }
89 
90 SPLAY_PROTOTYPE(tree, dns_entry, splay_next, compare);
91 
92 SPLAY_GENERATE(tree, dns_entry, splay_next, compare);
93 
94 struct dns_transport {
95 	struct addrinfo ai;
96 	struct sockaddr_storage dns_addr;
97 };
98 
99 void dns_child(int, int);
100 void dns_remove(struct dns_entry *);
101 
102 struct dns_list dnsqueue;
103 
104 int entries;
105 
106 void
dns_makeaddrinfo(struct addrinfo ** pai,struct dns_transport * dt)107 dns_makeaddrinfo(struct addrinfo **pai, struct dns_transport *dt)
108 {
109 	struct addrinfo *ai;
110 
111 	ai = calloc(1, sizeof(struct addrinfo) + dt->ai.ai_addrlen);
112 	if (ai == NULL)
113 		err(1, "%s: malloc", __func__);
114 
115 	*ai = dt->ai;
116 	ai->ai_addr = (struct sockaddr *)(ai + 1);
117 	memcpy(ai->ai_addr, &dt->dns_addr, ai->ai_addrlen);
118 
119 	ai->ai_next = *pai;
120 	*pai = ai;
121 }
122 
123 void
dns_read(int fd,short why,void * arg)124 dns_read(int fd, short why, void *arg)
125 {
126 	struct dns_child *child = arg;
127 	struct dns_entry *dns;
128 	struct addrinfo *ai = NULL;
129 	struct timeval tv;
130 	u_char *buf;
131 	int size;
132 
133 	dns = TAILQ_FIRST(&child->waitqueue);
134 	TAILQ_REMOVE(&child->waitqueue, dns, wait_next);
135 
136 	/* Reschedule writes */
137 	child->waits--;
138 	if (child->waits)
139 		event_add(&child->ev_write, NULL);
140 
141 	if (atomicio(read, fd, &size, sizeof(size)) != sizeof(size))
142 		err(1, "%s: read(%d)", __func__, sizeof(size));
143 
144 	if (size == -1)
145 		goto fail;
146 
147 	if (size > 0) {
148 		char *p;
149 
150 		if ((buf = malloc(size)) == NULL)
151 			err(1, "%s: malloc", __func__);
152 		if (atomicio(read, fd, buf, size) != size)
153 			err(1, "%s: read(%d)", __func__, size);
154 
155 		p = buf;
156 		while (size) {
157 			dns_makeaddrinfo(&ai, (struct dns_transport *)p);
158 
159 			p += sizeof(struct dns_transport);
160 			size -= sizeof(struct dns_transport);
161 		}
162 		free(buf);
163 	} else
164 		ai = NULL;
165 
166 	DFPRINTF(2, (stderr, "%s: return for %s: %p\n", __func__,
167 		     dns->name, ai));
168 
169 	/* Remove pending or temporary status */
170 	dns->ai = ai;
171 	dns->flags = ai != NULL ? DNS_POSITIVE : 0;
172 
173 	(*dns->cb)(ai, dns, dns->cbarg);
174 
175 	return;
176  fail:
177 	DFPRINTF(2, (stderr, "%s: error for %s\n", __func__, dns->name));
178 
179 	dns->ai = NULL;
180 
181 	dns->retries++;
182 	if (dns->retries > DNS_MAX_RETRY) {
183 		/* This is a negative cache entry, causes uri dequeue */
184 		dns->flags = 0;
185 	} else {
186 		dns->flags = DNS_TEMPORARY;
187 
188 		/* Make them retry */
189 		gettimeofday(&dns->access, NULL);
190 		timerclear(&tv);
191 		tv.tv_sec = DNS_RETRY_TIME;
192 		timeradd(&tv, &dns->access, &dns->access);
193 	}
194 
195 	(*dns->cb)(NULL, dns, dns->cbarg);
196 }
197 
198 void
dns_write(int fd,short why,void * arg)199 dns_write(int fd, short why, void *arg)
200 {
201 	struct dns_child *child = arg;
202 	struct dns_entry *dns;
203 	int size;
204 
205 	dns = TAILQ_FIRST(&child->waitqueue);
206 	size = strlen(dns->name) + 1;
207 
208 	if (atomicio(write, fd, &size, sizeof(size)) != sizeof(size))
209 		err(1, "write");
210 	if (atomicio(write, fd, dns->name, size) != size)
211 		err(1, "write");
212 
213 	event_add(&child->ev_read, NULL);
214 }
215 
216 int
dns_set_child(struct dns_child * child)217 dns_set_child(struct dns_child *child)
218 {
219 	int cmd[2];
220 	int res[2];
221 
222 	memset(child, 0, sizeof(struct dns_child));
223 
224 	if (pipe(cmd) == -1)
225 		err(1, "pipe");
226 	if (pipe(res) == -1)
227 		err(1, "pipe");
228 
229 	if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
230 		err(1, "signal");
231 
232 	child->pid = fork();
233 	if (child->pid == 0) {
234 		close(cmd[1]);
235 		close(res[0]);
236 		dns_child(cmd[0], res[1]);
237 		exit(0);
238 	} else if (child->pid == -1)
239 		err(1, "fork");
240 
241 	close(cmd[0]);
242 	close(res[1]);
243 
244 	child->cmd_write = cmd[1];
245 	child->res_read = res[0];
246 
247 	child->waits = 0;
248 
249 	TAILQ_INIT(&child->waitqueue);
250 
251 	event_set(&child->ev_read, child->res_read, EV_READ, dns_read, child);
252 	event_set(&child->ev_write, child->cmd_write, EV_WRITE, dns_write, child);
253 
254 	return (0);
255 }
256 
257 void
dns_init(void)258 dns_init(void)
259 {
260 	int i;
261 
262 	TAILQ_INIT(&dnsqueue);
263 	SPLAY_INIT(&root);
264 
265 	memset(&dns_stats, 0, sizeof(dns_stats));
266 
267 	for (i = 0; i < DNS_MAX_CHILDREN; i++)
268 		dns_set_child(&children[i]);
269 
270 	entries = 0;
271 }
272 
273 void
dns_end(void)274 dns_end(void)
275 {
276 	int i;
277 
278 	for (i = 0; i < DNS_MAX_CHILDREN; i++)
279 		kill(children[i].pid, SIGTERM);
280 }
281 
282 void
dns_print_stats(void)283 dns_print_stats(void)
284 {
285 	fprintf(stdout, "DNS queries: %d, entries: %d\n",
286 	    dns_stats.calls, entries);
287 	fprintf(stdout, "DNS cache hits: %d, replacements: %d\n",
288 		dns_stats.hits, dns_stats.replacements);
289 	fprintf(stdout, "DNS average list search: %f\n",
290 		(float)dns_stats.iterations/dns_stats.calls);
291 }
292 
293 /* Reference counting on host names */
294 
295 void
dns_unref(struct dns_entry * dns)296 dns_unref(struct dns_entry *dns)
297 {
298 	if (dns->ref == 0) {
299 		fprintf(stderr, "%s: %s(%p) already unref\n", __func__,
300 		    dns->name, dns);
301 		return;
302 	}
303 
304 	dns->ref--;
305 }
306 
307 void
dns_ref(struct dns_entry * dns)308 dns_ref(struct dns_entry *dns)
309 {
310 	dns->ref++;
311 }
312 
313 void
dns_remove(struct dns_entry * dns)314 dns_remove(struct dns_entry *dns)
315 {
316 	TAILQ_REMOVE(&dnsqueue, dns, next);
317 	SPLAY_REMOVE(tree, &root, dns);
318 
319 	if (dns->name)
320 		free(dns->name);
321 	if (dns->ai)
322 		freeaddrinfo(dns->ai);
323 	memset(dns, 0, sizeof (struct dns_entry));
324 }
325 
326 void
dns_set(struct dns_entry * dns,char * name,void (* cb)(struct addrinfo *,struct dns_entry *,void *),void * arg)327 dns_set(struct dns_entry *dns, char *name,
328     void (*cb)(struct addrinfo *, struct dns_entry *, void *), void *arg)
329 {
330 	/* Record creation and access time */
331 	gettimeofday(&dns->creat, NULL);
332 	dns->access = dns->creat;
333 
334 	dns->name = name;
335 	dns->flags = DNS_PENDING;
336 
337 	dns->cb = cb;
338 	dns->cbarg = arg;
339 }
340 
341 struct addrinfo *
dns_roundrobin(struct dns_entry * dns)342 dns_roundrobin(struct dns_entry *dns)
343 {
344 	struct addrinfo *first = dns->ai;
345 	struct addrinfo *tmp;
346 
347 	if (first == NULL || first->ai_next == NULL)
348 		return (first);
349 
350 	tmp = first->ai_next;
351 	dns->ai = tmp;
352 
353 	/* Detach at the beginning and put at the end */
354 	first->ai_next = NULL;
355 	while (tmp->ai_next != NULL)
356 		tmp = tmp->ai_next;
357 
358 	tmp->ai_next = first;
359 
360 	return (first);
361 }
362 
363 void
dns_setdepth(struct dns_entry * dns,int depth)364 dns_setdepth(struct dns_entry *dns, int depth)
365 {
366 	struct dns_entry *tmp;
367 
368 	/* Fast path */
369 	if (depth == 0) {
370 		TAILQ_REMOVE(&dnsqueue, dns, next);
371 		TAILQ_INSERT_TAIL(&dnsqueue, dns, next);
372 		return;
373 	}
374 
375 	while ((tmp = TAILQ_PREV(dns, dns_list, next))) {
376 		if (tmp->depth >= dns->depth)
377 			break;
378 	}
379 
380 	if (tmp == NULL)
381 		return;
382 	if (tmp == TAILQ_PREV(dns, dns_list, next)) {
383 		while ((tmp = TAILQ_NEXT(dns, next))) {
384 			if (tmp->depth <= dns->depth)
385 				break;
386 		}
387 
388 		if (tmp == NULL || tmp == TAILQ_NEXT(dns, next))
389 			return;
390 	}
391 
392 	TAILQ_REMOVE(&dnsqueue, dns, next);
393 	TAILQ_INSERT_AFTER(&dnsqueue, tmp, dns, next);
394 	return;
395 }
396 
397 struct dns_entry *
dns_find(char * host)398 dns_find(char *host)
399 {
400 	struct dns_entry *dns, tmp;
401 
402 	tmp.name = host;
403 
404 	dns_stats.calls++;
405 	dns = SPLAY_FIND(tree, &root, &tmp);
406 	if (dns != NULL)
407 		dns_stats.hits++;
408 
409 	return (dns);
410 }
411 
412 struct dns_entry *
dns_get(void)413 dns_get(void)
414 {
415 	struct dns_entry *dns = NULL;
416 
417 	if (entries >= DNS_MAXLRUSIZE) {
418 		dns_stats.replacements++;
419 
420 		/* Recycle an old entry */
421 		dns = TAILQ_LAST(&dnsqueue, dns_list);
422 		while (dns != NULL && DNS_UNUSED(dns))
423 			dns = TAILQ_PREV(dns, dns_list, next);
424 		if (dns != NULL)
425 			dns_remove(dns);
426 		/*
427 		 * If there is no old unused entry, we fall through and
428 		 * allocate a new one.
429 		 */
430 	}
431 
432 	if (dns == NULL) {
433 		dns = calloc(1, sizeof(struct dns_entry));
434 		entries++;
435 	}
436 
437 	/* Initalize queues */
438 	TAILQ_INIT(&dns->uriqueue);
439 	TAILQ_INIT(&dns->mediaqueue);
440 
441 	return (dns);
442 }
443 
444 int
dns_ready(struct dns_entry * dns,struct timeval * tv,struct timeval * ready,int max)445 dns_ready(struct dns_entry *dns, struct timeval *tv, struct timeval *ready,
446     int max)
447 {
448 	int res;
449 
450 	timerclear(ready);
451 
452 	if (dns->flags & DNS_PENDING)
453 		return (0);
454 
455 	/* Limit number of parallel connections */
456 	if (max && dns->ref >= max)
457 		return (0);
458 
459 	/* See if we may access this host yet */
460 	res = timercmp(&dns->access, tv, <=);
461 
462 	if (!res)
463 		*ready = dns->access;
464 
465 	return (res);
466 }
467 
468 void
dns_send(struct dns_entry * dns)469 dns_send(struct dns_entry *dns)
470 {
471 	struct dns_child *child;
472 
473 	/* Round robin on the children */
474 	child = &children[++childnr % DNS_MAX_CHILDREN];
475 
476 	TAILQ_INSERT_TAIL(&child->waitqueue, dns, wait_next);
477 
478 	if (child->waits == 0)
479 		event_add(&child->ev_write, NULL);
480 
481 	child->waits++;
482 }
483 
484 /*
485  * If tv != NULL, it records the gap between access times.
486  */
487 
488 int
dns_resolve_cb(char * ip,u_short port,void (* cb)(struct addrinfo *,struct dns_entry *,void *),void * arg)489 dns_resolve_cb(char *ip, u_short port,
490     void (*cb)(struct addrinfo *, struct dns_entry *, void *), void *arg)
491 {
492 	char *name;
493 	struct dns_entry *dns;
494 	struct addrinfo *ai = NULL;
495 	int positive;
496 
497 	dns = dns_find(ip);
498 
499 	if (dns != NULL) {
500 		/*
501 		 * Return an error if we have a pending access for this
502 		 * host already.
503 		 */
504 		if (dns->flags & DNS_PENDING)
505 			return (-1);
506 
507 		if (dns->flags & DNS_TEMPORARY) {
508 			/* XXX - need to have retry limit */
509 			dns->cb = cb;
510 			dns->cbarg = arg;
511 			dns->flags |= DNS_PENDING;
512 			dns_send(dns);
513 			return (0);
514 		}
515 
516 		if (dns->flags & DNS_POSITIVE)
517 			ai = dns_roundrobin(dns);
518 		else
519 			ai = NULL;
520 
521 		(*cb)(ai, dns, arg);
522 
523 		return (0);
524 	}
525 
526 	name = strdup(ip);
527 	if (name == NULL) {
528 		warn("%s: strdup", __func__);
529 		return (-1);
530 	}
531 
532 	/* Only use IP addresses with this interface, otherwise we
533 	 * will block on DNS.
534 	 */
535 	positive = 0;
536 
537 	/* Get a slot for a dns entry */
538 	if ((dns = dns_get()) == NULL) {
539 		free(name);
540 
541 		return (-1);
542 	}
543 
544 	dns_set(dns, name, cb, arg);
545 	TAILQ_INSERT_TAIL(&dnsqueue, dns, next);
546 	SPLAY_INSERT(tree, &root, dns);
547 
548 	dns_send(dns);
549 	return (0);
550 }
551 
552 int
dns_resolve(char * ip,struct addrinfo ** pai)553 dns_resolve(char *ip, struct addrinfo **pai)
554 {
555 	struct addrinfo hints, *ai;
556 	int res;
557 
558         memset(&hints, 0, sizeof(hints));
559         hints.ai_family = AF_INET;
560         hints.ai_socktype = SOCK_STREAM;
561 	res = getaddrinfo(ip, NULL, &hints, &ai);
562         if (res != 0) {
563                 fprintf(stderr, "%s: getaddrinfo(%s): %s\n", __func__,
564 		    ip, gai_strerror(res));
565 #ifdef EAI_NODATA
566 		if (res != EAI_NODATA)
567 			return (-1);
568 #else
569 		if (res != EAI_NONAME)
570 			return (-1);
571 #endif
572 
573 		/* Negative caching */
574 		ai = NULL;
575         }
576 
577 	*pai = ai;
578 
579 	return (0);
580 }
581 
582 void
dns_child_error(int fd)583 dns_child_error(int fd)
584 {
585 	int size = -1;
586 
587 	if (atomicio(write, fd, &size, sizeof(size)) != sizeof(size))
588 		exit(1);
589 }
590 
591 void
dns_child_success(int fd,struct addrinfo * ai)592 dns_child_success(int fd, struct addrinfo *ai)
593 {
594 	int size = 0;
595 	char *buf = NULL, *p;
596 	struct dns_transport *dt;
597 
598 	while (ai != NULL) {
599 		size += sizeof(struct dns_transport);
600 
601 		if ((p = realloc(buf, size)) == NULL)
602 			break;
603 		buf = p;
604 
605 		dt = (struct dns_transport *)(buf + size - sizeof(struct dns_transport));
606 		dt->ai = *ai;
607 		dt->ai.ai_canonname = NULL;
608 		dt->ai.ai_next = NULL;
609 		dt->ai.ai_addr = NULL;
610 		memcpy(&dt->dns_addr, ai->ai_addr, ai->ai_addrlen);
611 
612 		ai = ai->ai_next;
613 	}
614 
615 	if (atomicio(write, fd, &size, sizeof(size)) != sizeof(size))
616 		exit(1);
617 	if (size > 0 && atomicio(write, fd, buf, size) != size)
618 		exit(1);
619 	free(buf);
620 }
621 
622 void
dns_child(int rfd,int wfd)623 dns_child(int rfd, int wfd)
624 {
625 	struct addrinfo *ai;
626 	char line[1024];
627 	int i, size;
628 
629 	/* Clean up file descriptors */
630 	for (i = 0; i < DNS_MAX_CHILDREN && children[i].pid; i++) {
631 		close(children[i].cmd_write);
632 		close(children[i].res_read);
633 	}
634 
635 	/* Setup signal handler */
636 	if (signal(SIGINT, SIG_IGN) == SIG_ERR)
637 		err(1, "signal");
638 
639 	while (atomicio(read, rfd, &size, sizeof(size)) == sizeof(size)) {
640 		/* Error - no handling */
641 		if (size > sizeof(line) || size < 0)
642 			break;
643 
644 		if (atomicio(read, rfd, line, size) != size)
645 			exit(1);
646 		if (dns_resolve(line, &ai) == -1)
647 			dns_child_error(wfd);
648 		else {
649 			dns_child_success(wfd, ai);
650 			if (ai != NULL)
651 				freeaddrinfo(ai);
652 		}
653 	}
654 
655 	exit(1);
656 }
657