1 /* $OpenBSD: ftp-proxy.c,v 1.15 2007/08/15 15:18:02 camield Exp $ */ 2 3 /* 4 * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #define _KERNEL_STRUCTURES 20 #include <sys/queue.h> 21 #include <sys/types.h> 22 #include <sys/event.h> 23 #include <sys/time.h> 24 #include <sys/resource.h> 25 #include <sys/socket.h> 26 27 #include <net/if.h> 28 #include <net/pf/pfvar.h> 29 #include <netinet/in.h> 30 #include <arpa/inet.h> 31 32 #include <err.h> 33 #include <errno.h> 34 #include <fcntl.h> 35 #include <netdb.h> 36 #include <pwd.h> 37 #include <signal.h> 38 #include <stdarg.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <syslog.h> 43 #include <unistd.h> 44 #include <vis.h> 45 46 #include "filter.h" 47 48 #define CONNECT_TIMEOUT 30 49 #define MIN_PORT 1024 50 #define MAX_LINE 500 51 #define MAX_LOGLINE 300 52 #define NTOP_BUFS 3 53 #define TCP_BACKLOG 10 54 55 #define CHROOT_DIR "/var/empty" 56 #define NOPRIV_USER "proxy" 57 58 /* pfctl standard NAT range. */ 59 #define PF_NAT_PROXY_PORT_LOW 50001 60 #define PF_NAT_PROXY_PORT_HIGH 65535 61 62 #define sstosa(ss) ((struct sockaddr *)(ss)) 63 64 enum { CMD_NONE = 0, CMD_PORT, CMD_EPRT, CMD_PASV, CMD_EPSV }; 65 66 struct cbuf { 67 char *buffer; 68 size_t buffer_size; 69 size_t buffer_offset; 70 }; 71 72 struct session { 73 u_int32_t id; 74 struct sockaddr_storage client_ss; 75 struct sockaddr_storage proxy_ss; 76 struct sockaddr_storage server_ss; 77 struct sockaddr_storage orig_server_ss; 78 struct cbuf client; 79 struct cbuf server; 80 int client_fd; 81 int server_fd; 82 char cbuf[MAX_LINE]; 83 size_t cbuf_valid; 84 char sbuf[MAX_LINE]; 85 size_t sbuf_valid; 86 int cmd; 87 u_int16_t port; 88 u_int16_t proxy_port; 89 LIST_ENTRY(session) entry; 90 }; 91 92 LIST_HEAD(, session) sessions = LIST_HEAD_INITIALIZER(sessions); 93 94 void buffer_data(struct session *, struct cbuf *, char *, size_t); 95 int client_parse(struct session *); 96 int client_parse_anon(struct session *); 97 int client_parse_cmd(struct session *); 98 void client_read(struct session *); 99 void client_write(struct session *); 100 int drop_privs(void); 101 void end_session(struct session *); 102 int exit_daemon(void); 103 int getline(char *, size_t *); 104 void handle_connection(const int); 105 void handle_signal(int); 106 struct session * init_session(void); 107 void logmsg(int, const char *, ...) __printflike(2, 3); 108 u_int16_t parse_port(int); 109 u_int16_t pick_proxy_port(void); 110 void proxy_reply(int, struct sockaddr *, u_int16_t); 111 int server_parse(struct session *); 112 void server_read(struct session *); 113 void server_write(struct session *); 114 int allow_data_connection(struct session *s); 115 const char *sock_ntop(struct sockaddr *); 116 void usage(void); 117 118 char linebuf[MAX_LINE + 1]; 119 size_t linelen; 120 121 char ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN]; 122 123 #define KQ_NEVENTS 64 124 struct kevent changes[KQ_NEVENTS]; 125 int nchanges; 126 127 struct sockaddr_storage fixed_server_ss, fixed_proxy_ss; 128 char *fixed_server, *fixed_server_port, *fixed_proxy, *listen_ip, *listen_port, 129 *qname, *tagname; 130 int anonymous_only, daemonize, id_count, ipv6_mode, loglevel, max_sessions, 131 rfc_mode, session_count, timeout, verbose; 132 extern char *__progname; 133 134 void 135 buffer_data(struct session *s, struct cbuf *cb, char *buf, size_t len) 136 { 137 if (len < 1) 138 return; 139 140 if (cb->buffer == NULL) 141 if ((cb->buffer = malloc(MAX_LINE)) == NULL) 142 goto error; 143 144 memcpy(cb->buffer, buf, len); 145 cb->buffer_size = len; 146 return; 147 148 error: 149 logmsg(LOG_ERR, "#%d could not allocate memory for buffer", s->id); 150 end_session(s); 151 } 152 153 int 154 client_parse(struct session *s) 155 { 156 /* Reset any previous command. */ 157 s->cmd = CMD_NONE; 158 s->port = 0; 159 160 /* Commands we are looking for are at least 4 chars long. */ 161 if (linelen < 4) 162 return (1); 163 164 if (linebuf[0] == 'P' || linebuf[0] == 'p' || 165 linebuf[0] == 'E' || linebuf[0] == 'e') { 166 if (!client_parse_cmd(s)) 167 return (0); 168 169 /* 170 * Allow active mode connections immediately, instead of 171 * waiting for a positive reply from the server. Some 172 * rare servers/proxies try to probe or setup the data 173 * connection before an actual transfer request. 174 */ 175 if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT) 176 return (allow_data_connection(s)); 177 } 178 179 if (anonymous_only && (linebuf[0] == 'U' || linebuf[0] == 'u')) 180 return (client_parse_anon(s)); 181 182 return (1); 183 } 184 185 int 186 client_parse_anon(struct session *s) 187 { 188 size_t written; 189 190 if (strcasecmp("USER ftp\r\n", linebuf) != 0 && 191 strcasecmp("USER anonymous\r\n", linebuf) != 0) { 192 snprintf(linebuf, sizeof linebuf, 193 "500 Only anonymous FTP allowed\r\n"); 194 logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf); 195 196 /* Talk back to the client ourself. */ 197 linelen = strlen(linebuf); 198 written = write(s->client_fd, linebuf, linelen); 199 if (written == -1) { 200 logmsg(LOG_ERR, "#%d write failed", s->id); 201 return (0); /* Session will be ended for us */ 202 } else if (written < linelen) { 203 EV_SET(&changes[nchanges++], s->server_fd, 204 EVFILT_READ, EV_DISABLE, 0, 0, s); 205 EV_SET(&changes[nchanges++], s->client_fd, 206 EVFILT_WRITE, EV_ADD, 0, 0, s); 207 buffer_data(s, &s->client, linebuf + written, 208 linelen - written); 209 return (1); 210 } 211 212 /* Clear buffer so it's not sent to the server. */ 213 linebuf[0] = '\0'; 214 linelen = 0; 215 } 216 217 return (1); 218 } 219 220 int 221 client_parse_cmd(struct session *s) 222 { 223 if (strncasecmp("PASV", linebuf, 4) == 0) 224 s->cmd = CMD_PASV; 225 else if (strncasecmp("PORT ", linebuf, 5) == 0) 226 s->cmd = CMD_PORT; 227 else if (strncasecmp("EPSV", linebuf, 4) == 0) 228 s->cmd = CMD_EPSV; 229 else if (strncasecmp("EPRT ", linebuf, 5) == 0) 230 s->cmd = CMD_EPRT; 231 else 232 return (1); 233 234 if (ipv6_mode && (s->cmd == CMD_PASV || s->cmd == CMD_PORT)) { 235 logmsg(LOG_CRIT, "PASV and PORT not allowed with IPv6"); 236 return (0); 237 } 238 239 if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT) { 240 s->port = parse_port(s->cmd); 241 if (s->port < MIN_PORT) { 242 logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id, 243 linebuf); 244 return (0); 245 } 246 s->proxy_port = pick_proxy_port(); 247 proxy_reply(s->cmd, sstosa(&s->proxy_ss), s->proxy_port); 248 logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf); 249 } 250 251 return (1); 252 } 253 254 void 255 client_read(struct session *s) 256 { 257 size_t buf_avail, bread, bwritten; 258 int n; 259 260 do { 261 buf_avail = sizeof s->cbuf - s->cbuf_valid; 262 bread = read(s->client_fd, s->cbuf + s->cbuf_valid, buf_avail); 263 s->cbuf_valid += bread; 264 265 while ((n = getline(s->cbuf, &s->cbuf_valid)) > 0) { 266 logmsg(LOG_DEBUG, "#%d client: %s", s->id, linebuf); 267 if (!client_parse(s)) { 268 end_session(s); 269 return; 270 } 271 bwritten = write(s->server_fd, linebuf, linelen); 272 if (bwritten == -1) { 273 } else if (bwritten < linelen) { 274 EV_SET(&changes[nchanges++], s->client_fd, 275 EVFILT_READ, EV_DISABLE, 0, 0, s); 276 EV_SET(&changes[nchanges++], s->server_fd, 277 EVFILT_WRITE, EV_ADD, 0, 0, s); 278 buffer_data(s, &s->server, linebuf + bwritten, 279 linelen - bwritten); 280 return; 281 } 282 } 283 284 if (n == -1) { 285 logmsg(LOG_ERR, "#%d client command too long or not" 286 " clean", s->id); 287 end_session(s); 288 return; 289 } 290 } while (bread == buf_avail); 291 } 292 293 void 294 client_write(struct session *s) 295 { 296 size_t written; 297 298 written = write(s->client_fd, s->client.buffer + s->client.buffer_offset, 299 s->client.buffer_size - s->client.buffer_offset); 300 if (written == -1) { 301 logmsg(LOG_ERR, "#%d write failed", s->id); 302 end_session(s); 303 } else if (written == (s->client.buffer_size - s->client.buffer_offset)) { 304 free(s->client.buffer); 305 s->client.buffer = NULL; 306 s->client.buffer_size = 0; 307 s->client.buffer_offset = 0; 308 EV_SET(&changes[nchanges++], s->server_fd, 309 EVFILT_READ, EV_ENABLE, 0, 0, s); 310 } else { 311 s->client.buffer_offset += written; 312 } 313 } 314 315 int 316 drop_privs(void) 317 { 318 struct passwd *pw; 319 320 pw = getpwnam(NOPRIV_USER); 321 if (pw == NULL) 322 return (0); 323 324 tzset(); 325 if (chroot(CHROOT_DIR) != 0 || chdir("/") != 0 || 326 setgroups(1, &pw->pw_gid) != 0 || 327 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0 || 328 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) 329 return (0); 330 331 return (1); 332 } 333 334 void 335 end_session(struct session *s) 336 { 337 int err; 338 339 logmsg(LOG_INFO, "#%d ending session", s->id); 340 341 if (s->client_fd != -1) 342 close(s->client_fd); 343 if (s->server_fd != -1) 344 close(s->server_fd); 345 346 if (s->client.buffer) 347 free(s->client.buffer); 348 if (s->server.buffer) 349 free(s->server.buffer); 350 351 /* Remove rulesets by commiting empty ones. */ 352 err = 0; 353 if (prepare_commit(s->id) == -1) 354 err = errno; 355 else if (do_commit() == -1) { 356 err = errno; 357 do_rollback(); 358 } 359 if (err) 360 logmsg(LOG_ERR, "#%d pf rule removal failed: %s", s->id, 361 strerror(err)); 362 363 LIST_REMOVE(s, entry); 364 free(s); 365 session_count--; 366 } 367 368 int 369 exit_daemon(void) 370 { 371 struct session *s, *tmp; 372 373 LIST_FOREACH_MUTABLE(s, &sessions, entry, tmp) { 374 end_session(s); 375 } 376 377 if (daemonize) 378 closelog(); 379 380 exit(0); 381 382 /* NOTREACHED */ 383 return (-1); 384 } 385 386 int 387 getline(char *buf, size_t *valid) 388 { 389 size_t i; 390 391 if (*valid > MAX_LINE) 392 return (-1); 393 394 /* Copy to linebuf while searching for a newline. */ 395 for (i = 0; i < *valid; i++) { 396 linebuf[i] = buf[i]; 397 if (buf[i] == '\0') 398 return (-1); 399 if (buf[i] == '\n') 400 break; 401 } 402 403 if (i == *valid) { 404 /* No newline found. */ 405 linebuf[0] = '\0'; 406 linelen = 0; 407 if (i < MAX_LINE) 408 return (0); 409 return (-1); 410 } 411 412 linelen = i + 1; 413 linebuf[linelen] = '\0'; 414 *valid -= linelen; 415 416 /* Move leftovers to the start. */ 417 if (*valid != 0) 418 bcopy(buf + linelen, buf, *valid); 419 420 return ((int)linelen); 421 } 422 423 void 424 handle_connection(const int listen_fd) 425 { 426 struct sockaddr_storage tmp_ss; 427 struct sockaddr *client_sa, *server_sa, *fixed_server_sa; 428 struct sockaddr *client_to_proxy_sa, *proxy_to_server_sa; 429 struct session *s; 430 socklen_t len; 431 int client_fd, fc, on; 432 433 /* 434 * We _must_ accept the connection, otherwise libevent will keep 435 * coming back, and we will chew up all CPU. 436 */ 437 client_sa = sstosa(&tmp_ss); 438 len = sizeof(struct sockaddr_storage); 439 if ((client_fd = accept(listen_fd, client_sa, &len)) < 0) { 440 logmsg(LOG_CRIT, "accept failed: %s", strerror(errno)); 441 return; 442 } 443 444 /* Refuse connection if the maximum is reached. */ 445 if (session_count >= max_sessions) { 446 logmsg(LOG_ERR, "client limit (%d) reached, refusing " 447 "connection from %s", max_sessions, sock_ntop(client_sa)); 448 close(client_fd); 449 return; 450 } 451 452 /* Allocate session and copy back the info from the accept(). */ 453 s = init_session(); 454 if (s == NULL) { 455 logmsg(LOG_CRIT, "init_session failed"); 456 close(client_fd); 457 return; 458 } 459 s->client_fd = client_fd; 460 memcpy(sstosa(&s->client_ss), client_sa, client_sa->sa_len); 461 462 /* Cast it once, and be done with it. */ 463 client_sa = sstosa(&s->client_ss); 464 server_sa = sstosa(&s->server_ss); 465 client_to_proxy_sa = sstosa(&tmp_ss); 466 proxy_to_server_sa = sstosa(&s->proxy_ss); 467 fixed_server_sa = sstosa(&fixed_server_ss); 468 469 /* Log id/client early to ease debugging. */ 470 logmsg(LOG_DEBUG, "#%d accepted connection from %s", s->id, 471 sock_ntop(client_sa)); 472 473 /* 474 * Find out the real server and port that the client wanted. 475 */ 476 len = sizeof(struct sockaddr_storage); 477 if ((getsockname(s->client_fd, client_to_proxy_sa, &len)) < 0) { 478 logmsg(LOG_CRIT, "#%d getsockname failed: %s", s->id, 479 strerror(errno)); 480 goto fail; 481 } 482 if (server_lookup(client_sa, client_to_proxy_sa, server_sa) != 0) { 483 logmsg(LOG_CRIT, "#%d server lookup failed (no rdr?)", s->id); 484 goto fail; 485 } 486 if (fixed_server) { 487 memcpy(sstosa(&s->orig_server_ss), server_sa, 488 server_sa->sa_len); 489 memcpy(server_sa, fixed_server_sa, fixed_server_sa->sa_len); 490 } 491 492 /* XXX: check we are not connecting to ourself. */ 493 494 /* 495 * Setup socket and connect to server. 496 */ 497 if ((s->server_fd = socket(server_sa->sa_family, SOCK_STREAM, 498 IPPROTO_TCP)) < 0) { 499 logmsg(LOG_CRIT, "#%d server socket failed: %s", s->id, 500 strerror(errno)); 501 goto fail; 502 } 503 if (fixed_proxy && bind(s->server_fd, sstosa(&fixed_proxy_ss), 504 fixed_proxy_ss.ss_len) != 0) { 505 logmsg(LOG_CRIT, "#%d cannot bind fixed proxy address: %s", 506 s->id, strerror(errno)); 507 goto fail; 508 } 509 510 /* Use non-blocking connect(), see CONNECT_TIMEOUT below. */ 511 if ((fc = fcntl(s->server_fd, F_GETFL)) == -1 || 512 fcntl(s->server_fd, F_SETFL, fc | O_NONBLOCK) == -1) { 513 logmsg(LOG_CRIT, "#%d cannot mark socket non-blocking: %s", 514 s->id, strerror(errno)); 515 goto fail; 516 } 517 if (connect(s->server_fd, server_sa, server_sa->sa_len) < 0 && 518 errno != EINPROGRESS) { 519 logmsg(LOG_CRIT, "#%d proxy cannot connect to server %s: %s", 520 s->id, sock_ntop(server_sa), strerror(errno)); 521 goto fail; 522 } 523 524 len = sizeof(struct sockaddr_storage); 525 if ((getsockname(s->server_fd, proxy_to_server_sa, &len)) < 0) { 526 logmsg(LOG_CRIT, "#%d getsockname failed: %s", s->id, 527 strerror(errno)); 528 goto fail; 529 } 530 531 logmsg(LOG_INFO, "#%d FTP session %d/%d started: client %s to server " 532 "%s via proxy %s ", s->id, session_count, max_sessions, 533 sock_ntop(client_sa), sock_ntop(server_sa), 534 sock_ntop(proxy_to_server_sa)); 535 536 /* Keepalive is nice, but don't care if it fails. */ 537 on = 1; 538 setsockopt(s->client_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, 539 sizeof on); 540 setsockopt(s->server_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, 541 sizeof on); 542 543 EV_SET(&changes[nchanges++], s->client_fd, EVFILT_READ, EV_ADD, 0, 0, s); 544 EV_SET(&changes[nchanges++], s->server_fd, EVFILT_READ, EV_ADD, 0, 0, s); 545 546 return; 547 548 fail: 549 end_session(s); 550 } 551 552 void 553 handle_signal(int sig) 554 { 555 /* 556 * Signal handler rules don't apply. 557 */ 558 559 logmsg(LOG_ERR, "%s exiting on signal %d", __progname, sig); 560 561 exit_daemon(); 562 } 563 564 565 struct session * 566 init_session(void) 567 { 568 struct session *s; 569 570 s = calloc(1, sizeof(struct session)); 571 if (s == NULL) 572 return (NULL); 573 574 s->id = id_count++; 575 s->client_fd = -1; 576 s->server_fd = -1; 577 s->cbuf[0] = '\0'; 578 s->cbuf_valid = 0; 579 s->sbuf[0] = '\0'; 580 s->sbuf_valid = 0; 581 s->client.buffer = NULL; 582 s->client.buffer_size = 0; 583 s->client.buffer_offset = 0; 584 s->server.buffer = NULL; 585 s->server.buffer_size = 0; 586 s->server.buffer_offset = 0; 587 s->cmd = CMD_NONE; 588 s->port = 0; 589 590 LIST_INSERT_HEAD(&sessions, s, entry); 591 session_count++; 592 593 return (s); 594 } 595 596 void 597 logmsg(int pri, const char *message, ...) 598 { 599 va_list ap; 600 601 if (pri > loglevel) 602 return; 603 604 va_start(ap, message); 605 606 if (daemonize) 607 /* syslog does its own vissing. */ 608 vsyslog(pri, message, ap); 609 else { 610 char buf[MAX_LOGLINE]; 611 char visbuf[2 * MAX_LOGLINE]; 612 613 /* We don't care about truncation. */ 614 vsnprintf(buf, sizeof buf, message, ap); 615 strnvis(visbuf, buf, sizeof visbuf, VIS_CSTYLE | VIS_NL); 616 fprintf(stderr, "%s\n", visbuf); 617 } 618 619 va_end(ap); 620 } 621 622 int 623 main(int argc, char *argv[]) 624 { 625 struct rlimit rlp; 626 struct addrinfo hints, *res; 627 int kq, ch, error, listenfd, on; 628 const char *errstr; 629 630 /* Defaults. */ 631 anonymous_only = 0; 632 daemonize = 1; 633 fixed_proxy = NULL; 634 fixed_server = NULL; 635 fixed_server_port = "21"; 636 ipv6_mode = 0; 637 listen_ip = NULL; 638 listen_port = "8021"; 639 loglevel = LOG_NOTICE; 640 max_sessions = 100; 641 qname = NULL; 642 rfc_mode = 0; 643 tagname = NULL; 644 timeout = 24 * 3600; 645 verbose = 0; 646 647 /* Other initialization. */ 648 id_count = 1; 649 session_count = 0; 650 nchanges = 0; 651 652 while ((ch = getopt(argc, argv, "6Aa:b:D:dm:P:p:q:R:rT:t:v")) != -1) { 653 switch (ch) { 654 case '6': 655 ipv6_mode = 1; 656 break; 657 case 'A': 658 anonymous_only = 1; 659 break; 660 case 'a': 661 fixed_proxy = optarg; 662 break; 663 case 'b': 664 listen_ip = optarg; 665 break; 666 case 'D': 667 loglevel = strtonum(optarg, LOG_EMERG, LOG_DEBUG, 668 &errstr); 669 if (errstr) 670 errx(1, "loglevel %s", errstr); 671 break; 672 case 'd': 673 daemonize = 0; 674 break; 675 case 'm': 676 max_sessions = strtonum(optarg, 1, 500, &errstr); 677 if (errstr) 678 errx(1, "max sessions %s", errstr); 679 break; 680 case 'P': 681 fixed_server_port = optarg; 682 break; 683 case 'p': 684 listen_port = optarg; 685 break; 686 case 'q': 687 if (strlen(optarg) >= PF_QNAME_SIZE) 688 errx(1, "queuename too long"); 689 qname = optarg; 690 break; 691 case 'R': 692 fixed_server = optarg; 693 break; 694 case 'r': 695 rfc_mode = 1; 696 break; 697 case 'T': 698 if (strlen(optarg) >= PF_TAG_NAME_SIZE) 699 errx(1, "tagname too long"); 700 tagname = optarg; 701 break; 702 case 't': 703 timeout = strtonum(optarg, 0, 86400, &errstr); 704 if (errstr) 705 errx(1, "timeout %s", errstr); 706 break; 707 case 'v': 708 verbose++; 709 if (verbose > 2) 710 usage(); 711 break; 712 default: 713 usage(); 714 } 715 } 716 717 if (listen_ip == NULL) 718 listen_ip = ipv6_mode ? "::1" : "127.0.0.1"; 719 720 /* Check for root to save the user from cryptic failure messages. */ 721 if (getuid() != 0) 722 errx(1, "needs to start as root"); 723 724 /* Raise max. open files limit to satisfy max. sessions. */ 725 rlp.rlim_cur = rlp.rlim_max = (2 * max_sessions) + 10; 726 if (setrlimit(RLIMIT_NOFILE, &rlp) == -1) 727 err(1, "setrlimit"); 728 729 if (fixed_proxy) { 730 memset(&hints, 0, sizeof hints); 731 hints.ai_flags = AI_NUMERICHOST; 732 hints.ai_family = ipv6_mode ? AF_INET6 : AF_INET; 733 hints.ai_socktype = SOCK_STREAM; 734 error = getaddrinfo(fixed_proxy, NULL, &hints, &res); 735 if (error) 736 errx(1, "getaddrinfo fixed proxy address failed: %s", 737 gai_strerror(error)); 738 memcpy(&fixed_proxy_ss, res->ai_addr, res->ai_addrlen); 739 logmsg(LOG_INFO, "using %s to connect to servers", 740 sock_ntop(sstosa(&fixed_proxy_ss))); 741 freeaddrinfo(res); 742 } 743 744 if (fixed_server) { 745 memset(&hints, 0, sizeof hints); 746 hints.ai_family = ipv6_mode ? AF_INET6 : AF_INET; 747 hints.ai_socktype = SOCK_STREAM; 748 error = getaddrinfo(fixed_server, fixed_server_port, &hints, 749 &res); 750 if (error) 751 errx(1, "getaddrinfo fixed server address failed: %s", 752 gai_strerror(error)); 753 memcpy(&fixed_server_ss, res->ai_addr, res->ai_addrlen); 754 logmsg(LOG_INFO, "using fixed server %s", 755 sock_ntop(sstosa(&fixed_server_ss))); 756 freeaddrinfo(res); 757 } 758 759 /* Setup listener. */ 760 memset(&hints, 0, sizeof hints); 761 hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; 762 hints.ai_family = ipv6_mode ? AF_INET6 : AF_INET; 763 hints.ai_socktype = SOCK_STREAM; 764 error = getaddrinfo(listen_ip, listen_port, &hints, &res); 765 if (error) 766 errx(1, "getaddrinfo listen address failed: %s", 767 gai_strerror(error)); 768 if ((listenfd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP)) == -1) 769 errx(1, "socket failed"); 770 on = 1; 771 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, 772 sizeof on) != 0) 773 err(1, "setsockopt failed"); 774 if (bind(listenfd, (struct sockaddr *)res->ai_addr, 775 (socklen_t)res->ai_addrlen) != 0) 776 err(1, "bind failed"); 777 if (listen(listenfd, TCP_BACKLOG) != 0) 778 err(1, "listen failed"); 779 freeaddrinfo(res); 780 781 /* Initialize pf. */ 782 init_filter(qname, tagname, verbose); 783 784 if (daemonize) { 785 if (daemon(0, 0) == -1) 786 err(1, "cannot daemonize"); 787 openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); 788 } 789 790 /* Use logmsg for output from here on. */ 791 792 if (!drop_privs()) { 793 logmsg(LOG_ERR, "cannot drop privileges: %s", strerror(errno)); 794 exit(1); 795 } 796 797 if ((kq = kqueue()) == -1) { 798 logmsg(LOG_ERR, "cannot create new kqueue(2): %s", strerror(errno)); 799 exit(1); 800 } 801 802 /* Setup signal handler. */ 803 signal(SIGPIPE, SIG_IGN); 804 EV_SET(&changes[nchanges++], SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 805 EV_SET(&changes[nchanges++], SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 806 EV_SET(&changes[nchanges++], SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 807 808 EV_SET(&changes[nchanges++], listenfd, EVFILT_READ, EV_ADD, 0, 0, NULL); 809 810 logmsg(LOG_NOTICE, "listening on %s port %s", listen_ip, listen_port); 811 812 /* Vroom, vroom. */ 813 for ( ; ; ) { 814 int i, nevents; 815 struct kevent events[KQ_NEVENTS], *event; 816 struct session *s; 817 818 nevents = kevent(kq, &changes[0], nchanges, &events[0], 819 KQ_NEVENTS, NULL); 820 if (nevents == -1) { 821 logmsg(LOG_ERR, "cannot create new kqueue(2): %s", strerror(errno)); 822 exit(1); 823 } 824 nchanges = 0; 825 826 for (i = 0; i < nevents; ++i) { 827 event = &events[i]; 828 829 if (event->filter == EVFILT_SIGNAL) { 830 handle_signal(event->ident); 831 continue; 832 } 833 834 if (event->ident == listenfd) { 835 /* Handle new connection */ 836 handle_connection(event->ident); 837 } else { 838 /* Process existing connection */ 839 s = (struct session *)event->udata; 840 841 if (event->ident == s->client_fd) { 842 if (event->filter == EVFILT_READ) 843 client_read(s); 844 else 845 client_write(s); 846 } else { 847 if (event->filter == EVFILT_READ) 848 server_read(s); 849 else 850 server_write(s); 851 } 852 } 853 854 /* The next loop might overflow changes */ 855 if (nchanges > KQ_NEVENTS - 4) 856 break; 857 } 858 } 859 860 exit_daemon(); 861 862 /* NOTREACHED */ 863 return (1); 864 } 865 866 u_int16_t 867 parse_port(int mode) 868 { 869 unsigned int port, v[6]; 870 int n; 871 char *p; 872 873 /* Find the last space or left-parenthesis. */ 874 for (p = linebuf + linelen; p > linebuf; p--) 875 if (*p == ' ' || *p == '(') 876 break; 877 if (p == linebuf) 878 return (0); 879 880 switch (mode) { 881 case CMD_PORT: 882 n = sscanf(p, " %u,%u,%u,%u,%u,%u", &v[0], &v[1], &v[2], 883 &v[3], &v[4], &v[5]); 884 if (n == 6 && v[0] < 256 && v[1] < 256 && v[2] < 256 && 885 v[3] < 256 && v[4] < 256 && v[5] < 256) 886 return ((v[4] << 8) | v[5]); 887 break; 888 case CMD_PASV: 889 n = sscanf(p, "(%u,%u,%u,%u,%u,%u)", &v[0], &v[1], &v[2], 890 &v[3], &v[4], &v[5]); 891 if (n == 6 && v[0] < 256 && v[1] < 256 && v[2] < 256 && 892 v[3] < 256 && v[4] < 256 && v[5] < 256) 893 return ((v[4] << 8) | v[5]); 894 break; 895 case CMD_EPSV: 896 n = sscanf(p, "(|||%u|)", &port); 897 if (n == 1 && port < 65536) 898 return (port); 899 break; 900 case CMD_EPRT: 901 n = sscanf(p, " |1|%u.%u.%u.%u|%u|", &v[0], &v[1], &v[2], 902 &v[3], &port); 903 if (n == 5 && v[0] < 256 && v[1] < 256 && v[2] < 256 && 904 v[3] < 256 && port < 65536) 905 return (port); 906 n = sscanf(p, " |2|%*[a-fA-F0-9:]|%u|", &port); 907 if (n == 1 && port < 65536) 908 return (port); 909 break; 910 default: 911 return (0); 912 } 913 914 return (0); 915 } 916 917 u_int16_t 918 pick_proxy_port(void) 919 { 920 /* Random should be good enough for avoiding port collisions. */ 921 return (IPPORT_HIFIRSTAUTO + (arc4random() % 922 (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO))); 923 } 924 925 void 926 proxy_reply(int cmd, struct sockaddr *sa, u_int16_t port) 927 { 928 int i, r; 929 930 switch (cmd) { 931 case CMD_PORT: 932 r = snprintf(linebuf, sizeof linebuf, 933 "PORT %s,%u,%u\r\n", sock_ntop(sa), port / 256, 934 port % 256); 935 break; 936 case CMD_PASV: 937 r = snprintf(linebuf, sizeof linebuf, 938 "227 Entering Passive Mode (%s,%u,%u)\r\n", sock_ntop(sa), 939 port / 256, port % 256); 940 break; 941 case CMD_EPRT: 942 if (sa->sa_family == AF_INET) 943 r = snprintf(linebuf, sizeof linebuf, 944 "EPRT |1|%s|%u|\r\n", sock_ntop(sa), port); 945 else if (sa->sa_family == AF_INET6) 946 r = snprintf(linebuf, sizeof linebuf, 947 "EPRT |2|%s|%u|\r\n", sock_ntop(sa), port); 948 break; 949 case CMD_EPSV: 950 r = snprintf(linebuf, sizeof linebuf, 951 "229 Entering Extended Passive Mode (|||%u|)\r\n", port); 952 break; 953 } 954 955 if (r < 0 || r >= sizeof linebuf) { 956 logmsg(LOG_ERR, "proxy_reply failed: %d", r); 957 linebuf[0] = '\0'; 958 linelen = 0; 959 return; 960 } 961 linelen = (size_t)r; 962 963 if (cmd == CMD_PORT || cmd == CMD_PASV) { 964 /* Replace dots in IP address with commas. */ 965 for (i = 0; i < linelen; i++) 966 if (linebuf[i] == '.') 967 linebuf[i] = ','; 968 } 969 } 970 971 int 972 server_parse(struct session *s) 973 { 974 if (s->cmd == CMD_NONE || linelen < 4 || linebuf[0] != '2') 975 goto out; 976 977 if ((s->cmd == CMD_PASV && strncmp("227 ", linebuf, 4) == 0) || 978 (s->cmd == CMD_EPSV && strncmp("229 ", linebuf, 4) == 0)) 979 return (allow_data_connection(s)); 980 981 out: 982 s->cmd = CMD_NONE; 983 s->port = 0; 984 985 return (1); 986 } 987 988 int 989 allow_data_connection(struct session *s) 990 { 991 struct sockaddr *client_sa, *orig_sa, *proxy_sa, *server_sa; 992 int prepared = 0; 993 994 if (s->cmd == CMD_NONE || linelen < 4 || linebuf[0] != '2') 995 goto out; 996 997 /* 998 * The pf rules below do quite some NAT rewriting, to keep up 999 * appearances. Points to keep in mind: 1000 * 1) The client must think it's talking to the real server, 1001 * for both control and data connections. Transparently. 1002 * 2) The server must think that the proxy is the client. 1003 * 3) Source and destination ports are rewritten to minimize 1004 * port collisions, to aid security (some systems pick weak 1005 * ports) or to satisfy RFC requirements (source port 20). 1006 */ 1007 1008 /* Cast this once, to make code below it more readable. */ 1009 client_sa = sstosa(&s->client_ss); 1010 server_sa = sstosa(&s->server_ss); 1011 proxy_sa = sstosa(&s->proxy_ss); 1012 if (fixed_server) 1013 /* Fixed server: data connections must appear to come 1014 from / go to the original server, not the fixed one. */ 1015 orig_sa = sstosa(&s->orig_server_ss); 1016 else 1017 /* Server not fixed: orig_server == server. */ 1018 orig_sa = sstosa(&s->server_ss); 1019 1020 /* Passive modes. */ 1021 if (s->cmd == CMD_PASV || s->cmd == CMD_EPSV) { 1022 s->port = parse_port(s->cmd); 1023 if (s->port < MIN_PORT) { 1024 logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id, 1025 linebuf); 1026 return (0); 1027 } 1028 s->proxy_port = pick_proxy_port(); 1029 logmsg(LOG_INFO, "#%d passive: client to server port %d" 1030 " via port %d", s->id, s->port, s->proxy_port); 1031 1032 if (prepare_commit(s->id) == -1) 1033 goto fail; 1034 prepared = 1; 1035 1036 proxy_reply(s->cmd, orig_sa, s->proxy_port); 1037 logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf); 1038 1039 /* rdr from $client to $orig_server port $proxy_port -> $server 1040 port $port */ 1041 if (add_rdr(s->id, client_sa, orig_sa, s->proxy_port, 1042 server_sa, s->port) == -1) 1043 goto fail; 1044 1045 /* nat from $client to $server port $port -> $proxy */ 1046 if (add_nat(s->id, client_sa, server_sa, s->port, proxy_sa, 1047 PF_NAT_PROXY_PORT_LOW, PF_NAT_PROXY_PORT_HIGH) == -1) 1048 goto fail; 1049 1050 /* pass in from $client to $server port $port */ 1051 if (add_filter(s->id, PF_IN, client_sa, server_sa, 1052 s->port) == -1) 1053 goto fail; 1054 1055 /* pass out from $proxy to $server port $port */ 1056 if (add_filter(s->id, PF_OUT, proxy_sa, server_sa, 1057 s->port) == -1) 1058 goto fail; 1059 } 1060 1061 /* Active modes. */ 1062 if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT) { 1063 logmsg(LOG_INFO, "#%d active: server to client port %d" 1064 " via port %d", s->id, s->port, s->proxy_port); 1065 1066 if (prepare_commit(s->id) == -1) 1067 goto fail; 1068 prepared = 1; 1069 1070 /* rdr from $server to $proxy port $proxy_port -> $client port 1071 $port */ 1072 if (add_rdr(s->id, server_sa, proxy_sa, s->proxy_port, 1073 client_sa, s->port) == -1) 1074 goto fail; 1075 1076 /* nat from $server to $client port $port -> $orig_server port 1077 $natport */ 1078 if (rfc_mode && s->cmd == CMD_PORT) { 1079 /* Rewrite sourceport to RFC mandated 20. */ 1080 if (add_nat(s->id, server_sa, client_sa, s->port, 1081 orig_sa, 20, 20) == -1) 1082 goto fail; 1083 } else { 1084 /* Let pf pick a source port from the standard range. */ 1085 if (add_nat(s->id, server_sa, client_sa, s->port, 1086 orig_sa, PF_NAT_PROXY_PORT_LOW, 1087 PF_NAT_PROXY_PORT_HIGH) == -1) 1088 goto fail; 1089 } 1090 1091 /* pass in from $server to $client port $port */ 1092 if (add_filter(s->id, PF_IN, server_sa, client_sa, s->port) == 1093 -1) 1094 goto fail; 1095 1096 /* pass out from $orig_server to $client port $port */ 1097 if (add_filter(s->id, PF_OUT, orig_sa, client_sa, s->port) == 1098 -1) 1099 goto fail; 1100 } 1101 1102 /* Commit rules if they were prepared. */ 1103 if (prepared && (do_commit() == -1)) { 1104 if (errno != EBUSY) 1105 goto fail; 1106 /* One more try if busy. */ 1107 usleep(5000); 1108 if (do_commit() == -1) 1109 goto fail; 1110 } 1111 1112 out: 1113 s->cmd = CMD_NONE; 1114 s->port = 0; 1115 1116 return (1); 1117 1118 fail: 1119 logmsg(LOG_CRIT, "#%d pf operation failed: %s", s->id, strerror(errno)); 1120 if (prepared) 1121 do_rollback(); 1122 return (0); 1123 } 1124 1125 void 1126 server_read(struct session *s) 1127 { 1128 size_t buf_avail, bread, bwritten; 1129 int n; 1130 1131 do { 1132 buf_avail = sizeof s->sbuf - s->sbuf_valid; 1133 bread = read(s->server_fd, s->sbuf + s->sbuf_valid, buf_avail); 1134 s->sbuf_valid += bread; 1135 1136 while ((n = getline(s->sbuf, &s->sbuf_valid)) > 0) { 1137 logmsg(LOG_DEBUG, "#%d server: %s", s->id, linebuf); 1138 if (!server_parse(s)) { 1139 end_session(s); 1140 return; 1141 } 1142 bwritten = write(s->client_fd, linebuf, linelen); 1143 if (bwritten == -1) { 1144 logmsg(LOG_ERR, "#%d write failed", s->id); 1145 end_session(s); 1146 return; 1147 } else if (bwritten < linelen) { 1148 EV_SET(&changes[nchanges++], s->server_fd, 1149 EVFILT_READ, EV_DISABLE, 0, 0, s); 1150 EV_SET(&changes[nchanges++], s->client_fd, 1151 EVFILT_WRITE, EV_ADD, 0, 0, s); 1152 buffer_data(s, &s->client, linebuf + bwritten, 1153 linelen - bwritten); 1154 return; 1155 } 1156 } 1157 1158 if (n == -1) { 1159 logmsg(LOG_ERR, "#%d server reply too long or not" 1160 " clean", s->id); 1161 end_session(s); 1162 return; 1163 } 1164 } while (bread == buf_avail); 1165 } 1166 1167 void 1168 server_write(struct session *s) 1169 { 1170 size_t written; 1171 1172 written = write(s->server_fd, s->server.buffer + s->server.buffer_offset, 1173 s->server.buffer_size - s->server.buffer_offset); 1174 if (written == -1) { 1175 logmsg(LOG_ERR, "#%d write failed", s->id); 1176 end_session(s); 1177 } else if (written == (s->server.buffer_size - s->server.buffer_offset)) { 1178 free(s->server.buffer); 1179 s->server.buffer = NULL; 1180 s->server.buffer_size = 0; 1181 s->server.buffer_offset = 0; 1182 EV_SET(&changes[nchanges++], s->client_fd, 1183 EVFILT_READ, EV_ENABLE, 0, 0, s); 1184 } else { 1185 s->server.buffer_offset += written; 1186 } 1187 } 1188 1189 const char * 1190 sock_ntop(struct sockaddr *sa) 1191 { 1192 static int n = 0; 1193 1194 /* Cycle to next buffer. */ 1195 n = (n + 1) % NTOP_BUFS; 1196 ntop_buf[n][0] = '\0'; 1197 1198 if (sa->sa_family == AF_INET) { 1199 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 1200 1201 return (inet_ntop(AF_INET, &sin->sin_addr, ntop_buf[n], 1202 sizeof ntop_buf[0])); 1203 } 1204 1205 if (sa->sa_family == AF_INET6) { 1206 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 1207 1208 return (inet_ntop(AF_INET6, &sin6->sin6_addr, ntop_buf[n], 1209 sizeof ntop_buf[0])); 1210 } 1211 1212 return (NULL); 1213 } 1214 1215 void 1216 usage(void) 1217 { 1218 fprintf(stderr, "usage: %s [-6Adrv] [-a address] [-b address]" 1219 " [-D level] [-m maxsessions]\n [-P port]" 1220 " [-p port] [-q queue] [-R address] [-T tag] [-t timeout]\n", __progname); 1221 exit(1); 1222 } 1223