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