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