xref: /openbsd-src/usr.sbin/tftp-proxy/tftp-proxy.c (revision 6cc41355f0ce9ffe14778aa82c08f18d2797da1c)
1 /* $OpenBSD: tftp-proxy.c,v 1.13 2015/11/12 19:13:47 deraadt Exp $
2  *
3  * Copyright (c) 2005 DLS Internet Services
4  * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <sys/uio.h>
34 
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <arpa/tftp.h>
38 #include <net/if.h>
39 #include <net/pfvar.h>
40 #include <netdb.h>
41 
42 #include <unistd.h>
43 #include <errno.h>
44 #include <err.h>
45 #include <pwd.h>
46 #include <stdio.h>
47 #include <syslog.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <event.h>
51 
52 #include "filter.h"
53 
54 #define CHROOT_DIR	"/var/empty"
55 #define NOPRIV_USER	"proxy"
56 
57 #define DEFTRANSWAIT	2
58 #define NTOP_BUFS	4
59 #define PKTSIZE		SEGSIZE+4
60 
61 const char *opcode(int);
62 const char *sock_ntop(struct sockaddr *);
63 static void usage(void);
64 
65 struct proxy_listener {
66 	struct event ev;
67 	TAILQ_ENTRY(proxy_listener) entry;
68 	int (*cmsg2dst)(struct cmsghdr *, struct sockaddr_storage *);
69 	int s;
70 };
71 
72 void	proxy_listen(const char *, const char *, int);
73 void	proxy_listener_events(void);
74 int	proxy_dst4(struct cmsghdr *, struct sockaddr_storage *);
75 int	proxy_dst6(struct cmsghdr *, struct sockaddr_storage *);
76 void	proxy_recv(int, short, void *);
77 
78 struct fd_reply {
79 	TAILQ_ENTRY(fd_reply) entry;
80 	int fd;
81 };
82 
83 struct privproc {
84 	struct event pop_ev;
85 	struct event push_ev;
86 	TAILQ_HEAD(, fd_reply) replies;
87 	struct evbuffer *buf;
88 };
89 
90 void	proxy_privproc(int, struct passwd *);
91 void	privproc_push(int, short, void *);
92 void	privproc_pop(int, short, void *);
93 
94 void	unprivproc_push(int, short, void *);
95 void	unprivproc_pop(int, short, void *);
96 void	unprivproc_timeout(int, short, void *);
97 
98 char	ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN];
99 
100 struct loggers {
101 	void (*err)(int, const char *, ...);
102 	void (*errx)(int, const char *, ...);
103 	void (*warn)(const char *, ...);
104 	void (*warnx)(const char *, ...);
105 	void (*info)(const char *, ...);
106 };
107 
108 const struct loggers conslogger = {
109 	err,
110 	errx,
111 	warn,
112 	warnx,
113 	warnx
114 };
115 
116 void	syslog_err(int, const char *, ...);
117 void	syslog_errx(int, const char *, ...);
118 void	syslog_warn(const char *, ...);
119 void	syslog_warnx(const char *, ...);
120 void	syslog_info(const char *, ...);
121 void	syslog_vstrerror(int, int, const char *, va_list);
122 
123 const struct loggers syslogger = {
124 	syslog_err,
125 	syslog_errx,
126 	syslog_warn,
127 	syslog_warnx,
128 	syslog_info,
129 };
130 
131 const struct loggers *logger = &conslogger;
132 
133 #define lerr(_e, _f...) logger->err((_e), _f)
134 #define lerrx(_e, _f...) logger->errx((_e), _f)
135 #define lwarn(_f...) logger->warn(_f)
136 #define lwarnx(_f...) logger->warnx(_f)
137 #define linfo(_f...) logger->info(_f)
138 
139 __dead void
140 usage(void)
141 {
142 	extern char *__progname;
143 	fprintf(stderr, "usage: %s [-46dv] [-a address] [-l address] [-p port]"
144 	    " [-w transwait]\n", __progname);
145 	exit(1);
146 }
147 
148 int	debug = 0;
149 int	verbose = 0;
150 struct timeval transwait = { DEFTRANSWAIT, 0 };
151 
152 int on = 1;
153 
154 struct addr_pair {
155 	struct sockaddr_storage src;
156 	struct sockaddr_storage dst;
157 };
158 
159 struct proxy_request {
160 	char buf[SEGSIZE_MAX + 4];
161 	size_t buflen;
162 
163 	struct addr_pair addrs;
164 
165 	struct event ev;
166 	TAILQ_ENTRY(proxy_request) entry;
167 	u_int32_t id;
168 };
169 
170 struct proxy_child {
171 	TAILQ_HEAD(, proxy_request) fdrequests;
172 	TAILQ_HEAD(, proxy_request) tmrequests;
173 	struct event push_ev;
174 	struct event pop_ev;
175 	struct evbuffer *buf;
176 };
177 
178 struct proxy_child *child = NULL;
179 TAILQ_HEAD(, proxy_listener) proxy_listeners;
180 
181 struct src_addr {
182 	TAILQ_ENTRY(src_addr)	entry;
183 	struct sockaddr_storage	addr;
184 	socklen_t		addrlen;
185 };
186 TAILQ_HEAD(, src_addr) src_addrs;
187 
188 void	source_addresses(const char*, int);
189 
190 int
191 main(int argc, char *argv[])
192 {
193 	extern char *__progname;
194 
195 	int c;
196 	const char *errstr;
197 
198 	struct src_addr *saddr, *saddr2;
199 	struct passwd *pw;
200 
201 	char *addr = "localhost";
202 	char *port = "6969";
203 	int family = AF_UNSPEC;
204 
205 	int pair[2];
206 
207 	TAILQ_INIT(&src_addrs);
208 
209 	while ((c = getopt(argc, argv, "46a:dvl:p:w:")) != -1) {
210 		switch (c) {
211 		case '4':
212 			family = AF_INET;
213 			break;
214 		case '6':
215 			family = AF_INET6;
216 			break;
217 		case 'a':
218 			source_addresses(optarg, family);
219 			break;
220 		case 'd':
221 			verbose = debug = 1;
222 			break;
223 		case 'l':
224 			addr = optarg;
225 			break;
226 		case 'p':
227 			port = optarg;
228 			break;
229 		case 'v':
230 			verbose = 1;
231 			break;
232 		case 'w':
233 			transwait.tv_sec = strtonum(optarg, 1, 30, &errstr);
234 			if (errstr)
235 				errx(1, "wait is %s", errstr);
236 			break;
237 		default:
238 			usage();
239 			/* NOTREACHED */
240 		}
241 	}
242 
243 	if (geteuid() != 0)
244 		errx(1, "need root privileges");
245 
246 	if (!debug && daemon(1, 0) == -1)
247 		err(1, "daemon");
248 
249 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC, pair)
250 	    == -1)
251 		lerr(1, "socketpair");
252 
253 	pw = getpwnam(NOPRIV_USER);
254 	if (pw == NULL)
255 		lerrx(1, "no %s user", NOPRIV_USER);
256 
257 	/* Family option may have been specified late. */
258 	if (family != AF_UNSPEC)
259 		TAILQ_FOREACH_SAFE(saddr, &src_addrs, entry, saddr2)
260 			if (saddr->addr.ss_family != family) {
261 				TAILQ_REMOVE(&src_addrs, saddr, entry);
262 				free(saddr);
263 			}
264 
265 	switch (fork()) {
266 	case -1:
267 		lerr(1, "fork");
268 
269 	case 0:
270 		setproctitle("privproc");
271 		close(pair[1]);
272 		proxy_privproc(pair[0], pw);
273 		/* this never returns */
274 
275 	default:
276 		setproctitle("unprivproc");
277 		close(pair[0]);
278 		break;
279 	}
280 
281 	child = calloc(1, sizeof(*child));
282 	if (child == NULL)
283 		lerr(1, "alloc(child)");
284 
285 	child->buf = evbuffer_new();
286 	if (child->buf == NULL)
287 		lerr(1, "child evbuffer");
288 
289 	TAILQ_INIT(&child->fdrequests);
290 	TAILQ_INIT(&child->tmrequests);
291 
292 	if (!debug) {
293 		openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
294 		tzset();
295 		logger = &syslogger;
296 	}
297 
298 	proxy_listen(addr, port, family);
299 
300 	/* open /dev/pf */
301 	init_filter(NULL, verbose);
302 
303 	/* revoke privs */
304 	pw = getpwnam(NOPRIV_USER);
305 	if (!pw)
306 		lerrx(1, "no such user %s", NOPRIV_USER);
307 
308 	if (chroot(CHROOT_DIR) == -1)
309 		lerr(1, "chroot %s", CHROOT_DIR);
310 
311 	if (chdir("/") == -1)
312 		lerr(1, "chdir %s", CHROOT_DIR);
313 
314 	if (setgroups(1, &pw->pw_gid) ||
315 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
316 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
317 		err(1, "unable to revoke privs");
318 
319 	event_init();
320 
321 	proxy_listener_events();
322 
323 	event_set(&child->pop_ev, pair[1], EV_READ | EV_PERSIST,
324 	    unprivproc_pop, NULL);
325 	event_set(&child->push_ev, pair[1], EV_WRITE,
326 	    unprivproc_push, NULL);
327 
328 	event_add(&child->pop_ev, NULL);
329 
330 	event_dispatch();
331 
332 	return(0);
333 }
334 
335 void
336 source_addresses(const char* name, int family)
337 {
338 	struct addrinfo hints, *res, *res0;
339 	struct src_addr *saddr;
340 	int error;
341 
342 	memset(&hints, 0, sizeof(hints));
343 	hints.ai_family = family;
344 	hints.ai_socktype = SOCK_DGRAM;
345 	hints.ai_flags = AI_PASSIVE;
346 	error = getaddrinfo(name, NULL, &hints, &res0);
347 	if (error)
348 		lerrx(1, "%s: %s", name, gai_strerror(error));
349 	for (res = res0; res != NULL; res = res->ai_next) {
350 		if ((saddr = calloc(1, sizeof(struct src_addr))) == NULL)
351 			lerrx(1, "calloc");
352 		memcpy(&(saddr->addr), res->ai_addr, res->ai_addrlen);
353 		saddr->addrlen = res->ai_addrlen;
354 		TAILQ_INSERT_TAIL(&src_addrs, saddr, entry);
355 	}
356 	freeaddrinfo(res0);
357 }
358 
359 void
360 proxy_privproc(int s, struct passwd *pw)
361 {
362 	extern char *__progname;
363 	struct privproc p;
364 
365 	if (!debug) {
366 		openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
367 		tzset();
368 		logger = &syslogger;
369 	}
370 
371 	if (chroot(CHROOT_DIR) == -1)
372 		lerr(1, "chroot to %s", CHROOT_DIR);
373 
374 	if (chdir("/") == -1)
375 		lerr(1, "chdir to %s", CHROOT_DIR);
376 
377 	if (setgroups(1, &pw->pw_gid) ||
378 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid))
379 		lerr(1, "unable to set group ids");
380 
381 	TAILQ_INIT(&p.replies);
382 
383 	p.buf = evbuffer_new();
384 	if (p.buf == NULL)
385 		err(1, "pop evbuffer_new");
386 
387 	event_init();
388 
389 	event_set(&p.pop_ev, s, EV_READ | EV_PERSIST, privproc_pop, &p);
390 	event_set(&p.push_ev, s, EV_WRITE, privproc_push, &p);
391 
392 	event_add(&p.pop_ev, NULL);
393 
394 	event_dispatch();
395 }
396 
397 void
398 privproc_pop(int fd, short events, void *arg)
399 {
400 	struct addr_pair req;
401 	struct privproc *p = arg;
402 	struct fd_reply *rep;
403 	struct src_addr *saddr;
404 	int add = 0;
405 
406 	switch (evbuffer_read(p->buf, fd, sizeof(req))) {
407 	case 0:
408 		lerrx(1, "unprivproc has gone");
409 	case -1:
410 		switch (errno) {
411 		case EAGAIN:
412 		case EINTR:
413 			return;
414 		default:
415 			lerr(1, "privproc_pop read");
416 		}
417 	default:
418 		break;
419 	}
420 
421 	while (EVBUFFER_LENGTH(p->buf) >= sizeof(req)) {
422 		evbuffer_remove(p->buf, &req, sizeof(req));
423 
424 		/* do i really need to check this? */
425 		if (req.src.ss_family != req.dst.ss_family)
426 			lerrx(1, "family mismatch");
427 
428 		rep = calloc(1, sizeof(*rep));
429 		if (rep == NULL)
430 			lerr(1, "reply calloc");
431 
432 		rep->fd = socket(req.src.ss_family, SOCK_DGRAM | SOCK_NONBLOCK,
433 		    IPPROTO_UDP);
434 		if (rep->fd == -1)
435 			lerr(1, "privproc socket");
436 
437 		if (setsockopt(rep->fd, SOL_SOCKET, SO_BINDANY,
438 		    &on, sizeof(on)) == -1)
439 			lerr(1, "privproc setsockopt(BINDANY)");
440 
441 		if (setsockopt(rep->fd, SOL_SOCKET, SO_REUSEADDR,
442 		    &on, sizeof(on)) == -1)
443 			lerr(1, "privproc setsockopt(REUSEADDR)");
444 
445 		if (setsockopt(rep->fd, SOL_SOCKET, SO_REUSEPORT,
446 		    &on, sizeof(on)) == -1)
447 			lerr(1, "privproc setsockopt(REUSEPORT)");
448 
449 		TAILQ_FOREACH(saddr, &src_addrs, entry)
450 			if (saddr->addr.ss_family == req.src.ss_family)
451 				break;
452 		if (saddr == NULL) {
453 			if (bind(rep->fd, (struct sockaddr *)&req.src,
454 			    req.src.ss_len) == -1)
455 				lerr(1, "privproc bind");
456 		} else {
457 			if (bind(rep->fd, (struct sockaddr*)&saddr->addr,
458 			    saddr->addrlen) == -1)
459 				lerr(1, "privproc bind");
460 		}
461 
462 		if (TAILQ_EMPTY(&p->replies))
463 			add = 1;
464 
465 		TAILQ_INSERT_TAIL(&p->replies, rep, entry);
466 	}
467 
468 	if (add)
469 		event_add(&p->push_ev, NULL);
470 }
471 
472 void
473 privproc_push(int fd, short events, void *arg)
474 {
475 	struct privproc *p = arg;
476 	struct fd_reply *rep;
477 
478 	struct msghdr msg;
479 	union {
480 		struct cmsghdr hdr;
481 		char buf[CMSG_SPACE(sizeof(int))];
482 	} cmsgbuf;
483 	struct cmsghdr *cmsg;
484 	struct iovec iov;
485 	int result = 0;
486 
487 	while ((rep = TAILQ_FIRST(&p->replies)) != NULL) {
488 		memset(&msg, 0, sizeof(msg));
489 
490 		msg.msg_control = (caddr_t)&cmsgbuf.buf;
491 		msg.msg_controllen = sizeof(cmsgbuf.buf);
492 		cmsg = CMSG_FIRSTHDR(&msg);
493 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
494 		cmsg->cmsg_level = SOL_SOCKET;
495 		cmsg->cmsg_type = SCM_RIGHTS;
496 		*(int *)CMSG_DATA(cmsg) = rep->fd;
497 
498 		iov.iov_base = &result;
499 		iov.iov_len = sizeof(int);
500 		msg.msg_iov = &iov;
501 		msg.msg_iovlen = 1;
502 
503 		switch (sendmsg(fd, &msg, 0)) {
504 		case sizeof(int):
505 			break;
506 
507 		case -1:
508 			if (errno == EAGAIN)
509 				goto again;
510 
511 			lerr(1, "privproc sendmsg");
512 			/* NOTREACHED */
513 
514 		default:
515 			lerrx(1, "privproc sendmsg weird len");
516 		}
517 
518 		TAILQ_REMOVE(&p->replies, rep, entry);
519 		close(rep->fd);
520 		free(rep);
521 	}
522 
523 	if (TAILQ_EMPTY(&p->replies))
524 		return;
525 
526 again:
527 	event_add(&p->push_ev, NULL);
528 }
529 
530 void
531 proxy_listen(const char *addr, const char *port, int family)
532 {
533 	struct proxy_listener *l;
534 
535 	struct addrinfo hints, *res, *res0;
536 	int error;
537 	int s, on = 1;
538 	int serrno;
539 	const char *cause = NULL;
540 
541 	memset(&hints, 0, sizeof(hints));
542 	hints.ai_family = family;
543 	hints.ai_socktype = SOCK_DGRAM;
544 	hints.ai_flags = AI_PASSIVE;
545 
546 	TAILQ_INIT(&proxy_listeners);
547 
548 	error = getaddrinfo(addr, port, &hints, &res0);
549 	if (error)
550 		errx(1, "%s:%s: %s", addr, port, gai_strerror(error));
551 
552 	for (res = res0; res != NULL; res = res->ai_next) {
553 		s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
554 		    res->ai_protocol);
555 		if (s == -1) {
556 			cause = "socket";
557 			continue;
558 		}
559 
560 		if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
561 			cause = "bind";
562 			serrno = errno;
563 			close(s);
564 			errno = serrno;
565 			continue;
566 		}
567 
568 		l = calloc(1, sizeof(*l));
569 		if (l == NULL)
570 			err(1, "listener alloc");
571 
572 		switch (res->ai_family) {
573 		case AF_INET:
574 			l->cmsg2dst = proxy_dst4;
575 
576 			if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR,
577 			    &on, sizeof(on)) == -1)
578 				errx(1, "setsockopt(IP_RECVDSTADDR)");
579 			if (setsockopt(s, IPPROTO_IP, IP_RECVDSTPORT,
580 			    &on, sizeof(on)) == -1)
581 				errx(1, "setsockopt(IP_RECVDSTPORT)");
582 			break;
583 		case AF_INET6:
584 			l->cmsg2dst = proxy_dst6;
585 
586 			if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
587 			    &on, sizeof(on)) == -1)
588 				errx(1, "setsockopt(IPV6_RECVPKTINFO)");
589 			if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTPORT,
590 			    &on, sizeof(on)) == -1)
591 				errx(1, "setsockopt(IPV6_RECVDSTPORT)");
592 			break;
593 		}
594 		l->s = s;
595 
596 		TAILQ_INSERT_TAIL(&proxy_listeners, l, entry);
597 	}
598 	freeaddrinfo(res0);
599 
600 	if (TAILQ_EMPTY(&proxy_listeners))
601 		err(1, "%s", cause);
602 }
603 
604 void
605 proxy_listener_events(void)
606 {
607 	struct proxy_listener *l;
608 
609 	TAILQ_FOREACH(l, &proxy_listeners, entry) {
610 		event_set(&l->ev, l->s, EV_READ | EV_PERSIST, proxy_recv, l);
611 		event_add(&l->ev, NULL);
612 	}
613 }
614 
615 char safety[SEGSIZE_MAX + 4];
616 
617 int
618 proxy_dst4(struct cmsghdr *cmsg, struct sockaddr_storage *ss)
619 {
620 	struct sockaddr_in *sin = (struct sockaddr_in *)ss;
621 
622 	if (cmsg->cmsg_level != IPPROTO_IP)
623 		return (0);
624 
625 	switch (cmsg->cmsg_type) {
626 	case IP_RECVDSTADDR:
627 		memcpy(&sin->sin_addr, CMSG_DATA(cmsg), sizeof(sin->sin_addr));
628 		if (sin->sin_addr.s_addr == INADDR_BROADCAST)
629 			return (-1);
630 		break;
631 
632 	case IP_RECVDSTPORT:
633 		memcpy(&sin->sin_port, CMSG_DATA(cmsg), sizeof(sin->sin_port));
634 		break;
635 	}
636 
637 	return (0);
638 }
639 
640 int
641 proxy_dst6(struct cmsghdr *cmsg, struct sockaddr_storage *ss)
642 {
643 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;
644 	struct in6_pktinfo *ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg);
645 
646 	if (cmsg->cmsg_level != IPPROTO_IPV6)
647 		return (0);
648 
649 	switch (cmsg->cmsg_type) {
650 	case IPV6_PKTINFO:
651 		memcpy(&sin6->sin6_addr, &ipi->ipi6_addr,
652 		    sizeof(sin6->sin6_addr));
653 #ifdef __KAME__
654 		if (IN6_IS_ADDR_LINKLOCAL(&ipi->ipi6_addr))
655 		    sin6->sin6_scope_id = ipi->ipi6_ifindex;
656 #endif
657 		break;
658 	case IPV6_RECVDSTPORT:
659 		memcpy(&sin6->sin6_port, CMSG_DATA(cmsg),
660 		    sizeof(sin6->sin6_port));
661 		break;
662 	}
663 
664 	return (0);
665 }
666 
667 void
668 proxy_recv(int fd, short events, void *arg)
669 {
670 	struct proxy_listener *l = arg;
671 
672 	union {
673 		struct cmsghdr hdr;
674 		char buf[CMSG_SPACE(sizeof(struct sockaddr_storage)) +
675 		    CMSG_SPACE(sizeof(in_port_t))];
676 	} cmsgbuf;
677 	struct cmsghdr *cmsg;
678 	struct msghdr msg;
679 	struct iovec iov;
680 	ssize_t n;
681 
682 	struct proxy_request *r;
683 	struct tftphdr *tp;
684 
685 	r = calloc(1, sizeof(*r));
686 	if (r == NULL) {
687 		recv(fd, safety, sizeof(safety), 0);
688 		return;
689 	}
690 	r->id = arc4random(); /* XXX unique? */
691 
692 	bzero(&msg, sizeof(msg));
693 	iov.iov_base = r->buf;
694 	iov.iov_len = sizeof(r->buf);
695 	msg.msg_name = &r->addrs.src;
696 	msg.msg_namelen = sizeof(r->addrs.src);
697 	msg.msg_iov = &iov;
698 	msg.msg_iovlen = 1;
699 	msg.msg_control = &cmsgbuf.buf;
700 	msg.msg_controllen = sizeof(cmsgbuf.buf);
701 
702 	n = recvmsg(fd, &msg, 0);
703 	if (n == -1) {
704 		switch (errno) {
705 		case EAGAIN:
706 		case EINTR:
707 			goto err;
708 		default:
709 			lerr(1, "recvmsg");
710 			/* NOTREACHED */
711 		}
712 	}
713 	r->buflen = n;
714 
715 	/* check the packet */
716 	if (n < 5) {
717 		/* not enough to be a real packet */
718 		goto err;
719 	}
720 	tp = (struct tftphdr *)r->buf;
721 	switch (ntohs(tp->th_opcode)) {
722 	case RRQ:
723 	case WRQ:
724 		break;
725 	default:
726 		goto err;
727 	}
728 
729 	r->addrs.dst.ss_family = r->addrs.src.ss_family;
730 	r->addrs.dst.ss_len = r->addrs.src.ss_len;
731 
732 	/* get local address if possible */
733 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
734 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
735 		if (l->cmsg2dst(cmsg, &r->addrs.dst) == -1)
736 			goto err;
737 	}
738 
739 	if (verbose) {
740 		linfo("%s:%d -> %s:%d \"%s %s\"",
741 		    sock_ntop((struct sockaddr *)&r->addrs.src),
742 		    ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port),
743 		    sock_ntop((struct sockaddr *)&r->addrs.dst),
744 		    ntohs(((struct sockaddr_in *)&r->addrs.dst)->sin_port),
745 		    opcode(ntohs(tp->th_opcode)), tp->th_stuff);
746 		/* XXX tp->th_stuff could be garbage */
747 	}
748 
749 	TAILQ_INSERT_TAIL(&child->fdrequests, r, entry);
750 	evbuffer_add(child->buf, &r->addrs, sizeof(r->addrs));
751 	event_add(&child->push_ev, NULL);
752 
753 	return;
754 
755 err:
756 	free(r);
757 }
758 
759 void
760 unprivproc_push(int fd, short events, void *arg)
761 {
762 	if (evbuffer_write(child->buf, fd) == -1)
763 		lerr(1, "child evbuffer_write");
764 
765 	if (EVBUFFER_LENGTH(child->buf))
766 		event_add(&child->push_ev, NULL);
767 }
768 
769 void
770 unprivproc_pop(int fd, short events, void *arg)
771 {
772 	struct proxy_request *r;
773 
774 	struct msghdr msg;
775 	union {
776 		struct cmsghdr hdr;
777 		char buf[CMSG_SPACE(sizeof(int))];
778 	} cmsgbuf;
779 	struct cmsghdr *cmsg;
780 	struct iovec iov;
781 	struct src_addr *src_addr;
782 	struct sockaddr_storage saddr;
783 	socklen_t len;
784 	int result;
785 	int s;
786 
787 	len = sizeof(saddr);
788 
789 	do {
790 		memset(&msg, 0, sizeof(msg));
791 		iov.iov_base = &result;
792 		iov.iov_len = sizeof(int);
793 		msg.msg_iov = &iov;
794 		msg.msg_iovlen = 1;
795 		msg.msg_control = &cmsgbuf.buf;
796 		msg.msg_controllen = sizeof(cmsgbuf.buf);
797 
798 		switch (recvmsg(fd, &msg, 0)) {
799 		case sizeof(int):
800 			break;
801 
802 		case -1:
803 			switch (errno) {
804 			case EAGAIN:
805 			case EINTR:
806 				return;
807 			default:
808 				lerr(1, "child recvmsg");
809 			}
810 			/* NOTREACHED */
811 
812 		case 0:
813 			lerrx(1, "privproc closed connection");
814 
815 		default:
816 			lerrx(1, "child recvmsg was weird");
817 			/* NOTREACHED */
818 		}
819 
820 		if (result != 0) {
821 			errno = result;
822 			lerr(1, "child fdpass fail");
823 		}
824 
825 		cmsg = CMSG_FIRSTHDR(&msg);
826 		if (cmsg == NULL)
827 			lerrx(1, "%s: no message header", __func__);
828 
829 		if (cmsg->cmsg_type != SCM_RIGHTS) {
830 			lerrx(1, "%s: expected type %d got %d", __func__,
831 			    SCM_RIGHTS, cmsg->cmsg_type);
832 		}
833 
834 		s = (*(int *)CMSG_DATA(cmsg));
835 
836 		r = TAILQ_FIRST(&child->fdrequests);
837 		if (r == NULL)
838 			lerrx(1, "got fd without a pending request");
839 
840 		TAILQ_REMOVE(&child->fdrequests, r, entry);
841 
842 		/* get ready to add rules */
843 		if (prepare_commit(r->id) == -1)
844 			lerr(1, "%s: prepare_commit", __func__);
845 
846 		TAILQ_FOREACH(src_addr, &src_addrs, entry)
847 			if (src_addr->addr.ss_family == r->addrs.dst.ss_family)
848 				break;
849 		if (src_addr == NULL) {
850 			if (add_filter(r->id, PF_IN, (struct sockaddr *)
851 			    &r->addrs.dst, (struct sockaddr *)&r->addrs.src,
852 			    ntohs(((struct sockaddr_in *)&r->addrs.src)
853 			    ->sin_port), IPPROTO_UDP) == -1)
854 				lerr(1, "%s: couldn't add pass in", __func__);
855 		} else {
856 			if (getsockname(s, (struct sockaddr*)&saddr, &len) == -1)
857 				lerr(1, "%s: getsockname", __func__);
858 			if (add_rdr(r->id, (struct sockaddr *)&r->addrs.dst,
859 			    (struct sockaddr*)&saddr,
860 			    ntohs(((struct sockaddr_in *)&saddr)->sin_port),
861 			    (struct sockaddr *)&r->addrs.src,
862 			    ntohs(((struct sockaddr_in *)&r->addrs.src)->
863 			    sin_port), IPPROTO_UDP ) == -1)
864 				lerr(1, "%s: couldn't add rdr rule", __func__);
865 		}
866 
867 		if (add_filter(r->id, PF_OUT, (struct sockaddr *)&r->addrs.dst,
868 		    (struct sockaddr *)&r->addrs.src,
869 		    ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port),
870 		    IPPROTO_UDP) == -1)
871 			lerr(1, "%s: couldn't add pass out", __func__);
872 
873 		if (do_commit() == -1)
874 			lerr(1, "%s: couldn't commit rules", __func__);
875 
876 		/* forward the initial tftp request and start the insanity */
877 		if (sendto(s, r->buf, r->buflen, 0,
878 		    (struct sockaddr *)&r->addrs.dst,
879 		    r->addrs.dst.ss_len) == -1)
880 			lerr(1, "%s: unable to send", __func__);
881 
882 		close(s);
883 
884 		evtimer_set(&r->ev, unprivproc_timeout, r);
885 		evtimer_add(&r->ev, &transwait);
886 
887 		TAILQ_INSERT_TAIL(&child->tmrequests, r, entry);
888 	} while (!TAILQ_EMPTY(&child->fdrequests));
889 }
890 
891 void
892 unprivproc_timeout(int fd, short events, void *arg)
893 {
894 	struct proxy_request *r = arg;
895 
896 	TAILQ_REMOVE(&child->tmrequests, r, entry);
897 
898 	/* delete our rdr rule and clean up */
899 	prepare_commit(r->id);
900 	do_commit();
901 
902 	free(r);
903 }
904 
905 
906 const char *
907 opcode(int code)
908 {
909 	static char str[6];
910 
911 	switch (code) {
912 	case 1:
913 		(void)snprintf(str, sizeof(str), "RRQ");
914 		break;
915 	case 2:
916 		(void)snprintf(str, sizeof(str), "WRQ");
917 		break;
918 	default:
919 		(void)snprintf(str, sizeof(str), "(%d)", code);
920 		break;
921 	}
922 
923 	return (str);
924 }
925 
926 const char *
927 sock_ntop(struct sockaddr *sa)
928 {
929 	static int n = 0;
930 
931 	/* Cycle to next buffer. */
932 	n = (n + 1) % NTOP_BUFS;
933 	ntop_buf[n][0] = '\0';
934 
935 	if (sa->sa_family == AF_INET) {
936 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
937 
938 		return (inet_ntop(AF_INET, &sin->sin_addr, ntop_buf[n],
939 		    sizeof ntop_buf[0]));
940 	}
941 
942 	if (sa->sa_family == AF_INET6) {
943 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
944 
945 		return (inet_ntop(AF_INET6, &sin6->sin6_addr, ntop_buf[n],
946 		    sizeof ntop_buf[0]));
947 	}
948 
949 	return (NULL);
950 }
951 
952 void
953 syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
954 {
955 	char *s;
956 
957 	if (vasprintf(&s, fmt, ap) == -1) {
958 		syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror");
959 		exit(1);
960 	}
961 
962 	syslog(priority, "%s: %s", s, strerror(e));
963 
964 	free(s);
965 }
966 
967 void
968 syslog_err(int ecode, const char *fmt, ...)
969 {
970 	va_list ap;
971 
972 	va_start(ap, fmt);
973 	syslog_vstrerror(errno, LOG_EMERG, fmt, ap);
974 	va_end(ap);
975 
976 	exit(ecode);
977 }
978 
979 void
980 syslog_errx(int ecode, const char *fmt, ...)
981 {
982 	va_list ap;
983 
984 	va_start(ap, fmt);
985 	vsyslog(LOG_WARNING, fmt, ap);
986 	va_end(ap);
987 
988 	exit(ecode);
989 }
990 
991 void
992 syslog_warn(const char *fmt, ...)
993 {
994 	va_list ap;
995 
996 	va_start(ap, fmt);
997 	syslog_vstrerror(errno, LOG_WARNING, fmt, ap);
998 	va_end(ap);
999 }
1000 
1001 void
1002 syslog_warnx(const char *fmt, ...)
1003 {
1004 	va_list ap;
1005 
1006 	va_start(ap, fmt);
1007 	vsyslog(LOG_WARNING, fmt, ap);
1008 	va_end(ap);
1009 }
1010 
1011 void
1012 syslog_info(const char *fmt, ...)
1013 {
1014 	va_list ap;
1015 
1016 	va_start(ap, fmt);
1017 	vsyslog(LOG_INFO, fmt, ap);
1018 	va_end(ap);
1019 }
1020 
1021