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