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