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