1 /* $OpenBSD: tftp-proxy.c,v 1.22 2021/01/17 13:38:52 claudio 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
usage(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
main(int argc,char * argv[])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
source_addresses(const char * name,int family)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
proxy_privproc(int s,struct passwd * pw)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
privproc_pop(int fd,short events,void * arg)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
privproc_push(int fd,short events,void * arg)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
proxy_listen(const char * addr,const char * port,int family)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
proxy_listener_events(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
proxy_dst4(struct cmsghdr * cmsg,struct sockaddr_storage * ss)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
proxy_dst6(struct cmsghdr * cmsg,struct sockaddr_storage * ss)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 if (IN6_IS_ADDR_LINKLOCAL(&ipi->ipi6_addr))
665 sin6->sin6_scope_id = ipi->ipi6_ifindex;
666 break;
667 case IPV6_RECVDSTPORT:
668 memcpy(&sin6->sin6_port, CMSG_DATA(cmsg),
669 sizeof(sin6->sin6_port));
670 break;
671 }
672
673 return (0);
674 }
675
676 void
proxy_recv(int fd,short events,void * arg)677 proxy_recv(int fd, short events, void *arg)
678 {
679 struct proxy_listener *l = arg;
680
681 union {
682 struct cmsghdr hdr;
683 char buf[CMSG_SPACE(sizeof(struct sockaddr_storage)) +
684 CMSG_SPACE(sizeof(in_port_t))];
685 } cmsgbuf;
686 struct cmsghdr *cmsg;
687 struct msghdr msg;
688 struct iovec iov;
689 ssize_t n;
690
691 struct proxy_request *r;
692 struct tftphdr *tp;
693
694 r = calloc(1, sizeof(*r));
695 if (r == NULL) {
696 recv(fd, safety, sizeof(safety), 0);
697 return;
698 }
699 r->id = arc4random(); /* XXX unique? */
700
701 bzero(&msg, sizeof(msg));
702 iov.iov_base = r->buf;
703 iov.iov_len = sizeof(r->buf);
704 msg.msg_name = &r->addrs.src;
705 msg.msg_namelen = sizeof(r->addrs.src);
706 msg.msg_iov = &iov;
707 msg.msg_iovlen = 1;
708 msg.msg_control = &cmsgbuf.buf;
709 msg.msg_controllen = sizeof(cmsgbuf.buf);
710
711 n = recvmsg(fd, &msg, 0);
712 if (n == -1) {
713 switch (errno) {
714 case EAGAIN:
715 case EINTR:
716 goto err;
717 default:
718 lerr(1, "recvmsg");
719 /* NOTREACHED */
720 }
721 }
722 r->buflen = n;
723
724 /* check the packet */
725 if (n < 5) {
726 /* not enough to be a real packet */
727 goto err;
728 }
729 tp = (struct tftphdr *)r->buf;
730 switch (ntohs(tp->th_opcode)) {
731 case RRQ:
732 case WRQ:
733 break;
734 default:
735 goto err;
736 }
737
738 r->addrs.dst.ss_family = r->addrs.src.ss_family;
739 r->addrs.dst.ss_len = r->addrs.src.ss_len;
740
741 /* get local address if possible */
742 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
743 cmsg = CMSG_NXTHDR(&msg, cmsg)) {
744 if (l->cmsg2dst(cmsg, &r->addrs.dst) == -1)
745 goto err;
746 }
747
748 if (verbose) {
749 linfo("%s:%d -> %s:%d \"%s %s\"",
750 sock_ntop((struct sockaddr *)&r->addrs.src),
751 ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port),
752 sock_ntop((struct sockaddr *)&r->addrs.dst),
753 ntohs(((struct sockaddr_in *)&r->addrs.dst)->sin_port),
754 opcode(ntohs(tp->th_opcode)), tp->th_stuff);
755 /* XXX tp->th_stuff could be garbage */
756 }
757
758 TAILQ_INSERT_TAIL(&child->fdrequests, r, entry);
759 evbuffer_add(child->buf, &r->addrs, sizeof(r->addrs));
760 event_add(&child->push_ev, NULL);
761
762 return;
763
764 err:
765 free(r);
766 }
767
768 void
unprivproc_push(int fd,short events,void * arg)769 unprivproc_push(int fd, short events, void *arg)
770 {
771 if (evbuffer_write(child->buf, fd) == -1)
772 lerr(1, "child evbuffer_write");
773
774 if (EVBUFFER_LENGTH(child->buf))
775 event_add(&child->push_ev, NULL);
776 }
777
778 void
unprivproc_pop(int fd,short events,void * arg)779 unprivproc_pop(int fd, short events, void *arg)
780 {
781 struct proxy_request *r;
782
783 struct msghdr msg;
784 union {
785 struct cmsghdr hdr;
786 char buf[CMSG_SPACE(sizeof(int))];
787 } cmsgbuf;
788 struct cmsghdr *cmsg;
789 struct iovec iov;
790 struct src_addr *src_addr;
791 struct sockaddr_storage saddr;
792 socklen_t len;
793 int result;
794 int s;
795
796 len = sizeof(saddr);
797
798 do {
799 memset(&msg, 0, sizeof(msg));
800 iov.iov_base = &result;
801 iov.iov_len = sizeof(int);
802 msg.msg_iov = &iov;
803 msg.msg_iovlen = 1;
804 msg.msg_control = &cmsgbuf.buf;
805 msg.msg_controllen = sizeof(cmsgbuf.buf);
806
807 switch (recvmsg(fd, &msg, 0)) {
808 case sizeof(int):
809 break;
810
811 case -1:
812 switch (errno) {
813 case EAGAIN:
814 case EINTR:
815 return;
816 default:
817 lerr(1, "child recvmsg");
818 }
819 /* NOTREACHED */
820
821 case 0:
822 lerrx(1, "privproc closed connection");
823
824 default:
825 lerrx(1, "child recvmsg was weird");
826 /* NOTREACHED */
827 }
828
829 if (result != 0) {
830 errno = result;
831 lerr(1, "child fdpass fail");
832 }
833
834 cmsg = CMSG_FIRSTHDR(&msg);
835 if (cmsg == NULL)
836 lerrx(1, "%s: no message header", __func__);
837
838 if (cmsg->cmsg_type != SCM_RIGHTS) {
839 lerrx(1, "%s: expected type %d got %d", __func__,
840 SCM_RIGHTS, cmsg->cmsg_type);
841 }
842
843 s = (*(int *)CMSG_DATA(cmsg));
844
845 r = TAILQ_FIRST(&child->fdrequests);
846 if (r == NULL)
847 lerrx(1, "got fd without a pending request");
848
849 TAILQ_REMOVE(&child->fdrequests, r, entry);
850
851 /* get ready to add rules */
852 if (prepare_commit(r->id) == -1)
853 lerr(1, "%s: prepare_commit", __func__);
854
855 TAILQ_FOREACH(src_addr, &src_addrs, entry)
856 if (src_addr->addr.ss_family == r->addrs.dst.ss_family)
857 break;
858 if (src_addr == NULL) {
859 if (add_filter(r->id, PF_IN, (struct sockaddr *)
860 &r->addrs.dst, (struct sockaddr *)&r->addrs.src,
861 ntohs(((struct sockaddr_in *)&r->addrs.src)
862 ->sin_port), IPPROTO_UDP) == -1)
863 lerr(1, "%s: couldn't add pass in", __func__);
864 } else {
865 if (getsockname(s, (struct sockaddr*)&saddr, &len) == -1)
866 lerr(1, "%s: getsockname", __func__);
867 if (add_rdr(r->id, (struct sockaddr *)&r->addrs.dst,
868 (struct sockaddr*)&saddr,
869 ntohs(((struct sockaddr_in *)&saddr)->sin_port),
870 (struct sockaddr *)&r->addrs.src,
871 ntohs(((struct sockaddr_in *)&r->addrs.src)->
872 sin_port), IPPROTO_UDP ) == -1)
873 lerr(1, "%s: couldn't add rdr rule", __func__);
874 }
875
876 if (add_filter(r->id, PF_OUT, (struct sockaddr *)&r->addrs.dst,
877 (struct sockaddr *)&r->addrs.src,
878 ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port),
879 IPPROTO_UDP) == -1)
880 lerr(1, "%s: couldn't add pass out", __func__);
881
882 if (do_commit() == -1)
883 lerr(1, "%s: couldn't commit rules", __func__);
884
885 /* forward the initial tftp request and start the insanity */
886 if (sendto(s, r->buf, r->buflen, 0,
887 (struct sockaddr *)&r->addrs.dst,
888 r->addrs.dst.ss_len) == -1)
889 lerr(1, "%s: unable to send", __func__);
890
891 close(s);
892
893 evtimer_set(&r->ev, unprivproc_timeout, r);
894 evtimer_add(&r->ev, &transwait);
895
896 TAILQ_INSERT_TAIL(&child->tmrequests, r, entry);
897 } while (!TAILQ_EMPTY(&child->fdrequests));
898 }
899
900 void
unprivproc_timeout(int fd,short events,void * arg)901 unprivproc_timeout(int fd, short events, void *arg)
902 {
903 struct proxy_request *r = arg;
904
905 TAILQ_REMOVE(&child->tmrequests, r, entry);
906
907 /* delete our rdr rule and clean up */
908 prepare_commit(r->id);
909 do_commit();
910
911 free(r);
912 }
913
914
915 const char *
opcode(int code)916 opcode(int code)
917 {
918 static char str[6];
919
920 switch (code) {
921 case 1:
922 (void)snprintf(str, sizeof(str), "RRQ");
923 break;
924 case 2:
925 (void)snprintf(str, sizeof(str), "WRQ");
926 break;
927 default:
928 (void)snprintf(str, sizeof(str), "(%d)", code);
929 break;
930 }
931
932 return (str);
933 }
934
935 const char *
sock_ntop(struct sockaddr * sa)936 sock_ntop(struct sockaddr *sa)
937 {
938 static int n = 0;
939
940 /* Cycle to next buffer. */
941 n = (n + 1) % NTOP_BUFS;
942 ntop_buf[n][0] = '\0';
943
944 if (sa->sa_family == AF_INET) {
945 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
946
947 return (inet_ntop(AF_INET, &sin->sin_addr, ntop_buf[n],
948 sizeof ntop_buf[0]));
949 }
950
951 if (sa->sa_family == AF_INET6) {
952 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
953
954 return (inet_ntop(AF_INET6, &sin6->sin6_addr, ntop_buf[n],
955 sizeof ntop_buf[0]));
956 }
957
958 return (NULL);
959 }
960
961 void
syslog_vstrerror(int e,int priority,const char * fmt,va_list ap)962 syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
963 {
964 char *s;
965
966 if (vasprintf(&s, fmt, ap) == -1) {
967 syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror");
968 exit(1);
969 }
970
971 syslog(priority, "%s: %s", s, strerror(e));
972
973 free(s);
974 }
975
976 void
syslog_err(int ecode,const char * fmt,...)977 syslog_err(int ecode, const char *fmt, ...)
978 {
979 va_list ap;
980
981 va_start(ap, fmt);
982 syslog_vstrerror(errno, LOG_CRIT, fmt, ap);
983 va_end(ap);
984
985 exit(ecode);
986 }
987
988 void
syslog_errx(int ecode,const char * fmt,...)989 syslog_errx(int ecode, const char *fmt, ...)
990 {
991 va_list ap;
992
993 va_start(ap, fmt);
994 vsyslog(LOG_CRIT, fmt, ap);
995 va_end(ap);
996
997 exit(ecode);
998 }
999
1000 void
syslog_warn(const char * fmt,...)1001 syslog_warn(const char *fmt, ...)
1002 {
1003 va_list ap;
1004
1005 va_start(ap, fmt);
1006 syslog_vstrerror(errno, LOG_ERR, fmt, ap);
1007 va_end(ap);
1008 }
1009
1010 void
syslog_warnx(const char * fmt,...)1011 syslog_warnx(const char *fmt, ...)
1012 {
1013 va_list ap;
1014
1015 va_start(ap, fmt);
1016 vsyslog(LOG_ERR, fmt, ap);
1017 va_end(ap);
1018 }
1019
1020 void
syslog_info(const char * fmt,...)1021 syslog_info(const char *fmt, ...)
1022 {
1023 va_list ap;
1024
1025 va_start(ap, fmt);
1026 vsyslog(LOG_INFO, fmt, ap);
1027 va_end(ap);
1028 }
1029
1030 void
syslog_debug(const char * fmt,...)1031 syslog_debug(const char *fmt, ...)
1032 {
1033 va_list ap;
1034
1035 if (!debug)
1036 return;
1037
1038 va_start(ap, fmt);
1039 vsyslog(LOG_DEBUG, fmt, ap);
1040 va_end(ap);
1041 }
1042