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