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