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