svn commit: r221085 - projects/pf/pf45/contrib/pf/ftp-proxy

Ermal Luçi eri at FreeBSD.org
Tue Apr 26 21:06:57 UTC 2011


Author: eri
Date: Tue Apr 26 21:06:56 2011
New Revision: 221085
URL: http://svn.freebsd.org/changeset/base/221085

Log:
  Bring ftp-proxy up to date with OpenBSD 4.5.
  Also make it compile with WARNS= 6

Modified:
  projects/pf/pf45/contrib/pf/ftp-proxy/filter.c
  projects/pf/pf45/contrib/pf/ftp-proxy/filter.h
  projects/pf/pf45/contrib/pf/ftp-proxy/ftp-proxy.8
  projects/pf/pf45/contrib/pf/ftp-proxy/ftp-proxy.c

Modified: projects/pf/pf45/contrib/pf/ftp-proxy/filter.c
==============================================================================
--- projects/pf/pf45/contrib/pf/ftp-proxy/filter.c	Tue Apr 26 21:06:05 2011	(r221084)
+++ projects/pf/pf45/contrib/pf/ftp-proxy/filter.c	Tue Apr 26 21:06:56 2011	(r221085)
@@ -1,4 +1,4 @@
-/*	$OpenBSD: filter.c,v 1.5 2006/12/01 07:31:21 camield Exp $ */
+/*	$OpenBSD: filter.c,v 1.8 2008/06/13 07:25:26 claudio Exp $ */
 
 /*
  * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd at sentia.nl>
@@ -53,7 +53,7 @@ static struct pfioc_rule	pfr;
 static struct pfioc_trans	pft;
 static struct pfioc_trans_e	pfte[TRANS_SIZE];
 static int dev, rule_log;
-static char *qname;
+static const char *qname, *tagname;
 
 int
 add_filter(u_int32_t id, u_int8_t dir, struct sockaddr *src,
@@ -159,11 +159,12 @@ do_rollback(void)
 }
 
 void
-init_filter(char *opt_qname, int opt_verbose)
+init_filter(const char *opt_qname, const char *opt_tagname, int opt_verbose)
 {
 	struct pf_status status;
 
 	qname = opt_qname;
+	tagname = opt_tagname;
 
 	if (opt_verbose == 1)
 		rule_log = PF_LOG;
@@ -172,7 +173,7 @@ init_filter(char *opt_qname, int opt_ver
 
 	dev = open("/dev/pf", O_RDWR);	
 	if (dev == -1)
-		err(1, "/dev/pf");
+		err(1, "open /dev/pf");
 	if (ioctl(dev, DIOCGETSTATUS, &status) == -1)
 		err(1, "DIOCGETSTATUS");
 	if (!status.running)
@@ -280,9 +281,9 @@ prepare_rule(u_int32_t id, int rs_num, s
 	switch (rs_num) {
 	case PF_RULESET_FILTER:
 		/*
-		 * pass quick [log] inet[6] proto tcp \
+		 * pass [quick] [log] inet[6] proto tcp \
 		 *     from $src to $dst port = $d_port flags S/SA keep state
-		 *     (max 1) [queue qname]
+		 *     (max 1) [queue qname] [tag tagname]
 		 */
 		pfr.rule.action = PF_PASS;
 		pfr.rule.quick = 1;
@@ -293,6 +294,11 @@ prepare_rule(u_int32_t id, int rs_num, s
 		pfr.rule.max_states = 1;
 		if (qname != NULL)
 			strlcpy(pfr.rule.qname, qname, sizeof pfr.rule.qname);
+		if (tagname != NULL) {
+			pfr.rule.quick = 0;
+			strlcpy(pfr.rule.tagname, tagname,
+                                sizeof pfr.rule.tagname);
+		}
 		break;
 	case PF_RULESET_NAT:
 		/*

Modified: projects/pf/pf45/contrib/pf/ftp-proxy/filter.h
==============================================================================
--- projects/pf/pf45/contrib/pf/ftp-proxy/filter.h	Tue Apr 26 21:06:05 2011	(r221084)
+++ projects/pf/pf45/contrib/pf/ftp-proxy/filter.h	Tue Apr 26 21:06:56 2011	(r221085)
@@ -1,4 +1,4 @@
-/*	$OpenBSD: filter.h,v 1.3 2005/06/07 14:12:07 camield Exp $ */
+/*	$OpenBSD: filter.h,v 1.4 2007/08/01 09:31:41 henning Exp $ */
 
 /*
  * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd at sentia.nl>
@@ -26,6 +26,6 @@ int add_rdr(u_int32_t, struct sockaddr *
     struct sockaddr *, u_int16_t);
 int do_commit(void);
 int do_rollback(void);
-void init_filter(char *, int);
+void init_filter(const char *, const char *, int);
 int prepare_commit(u_int32_t);
 int server_lookup(struct sockaddr *, struct sockaddr *, struct sockaddr *);

Modified: projects/pf/pf45/contrib/pf/ftp-proxy/ftp-proxy.8
==============================================================================
--- projects/pf/pf45/contrib/pf/ftp-proxy/ftp-proxy.8	Tue Apr 26 21:06:05 2011	(r221084)
+++ projects/pf/pf45/contrib/pf/ftp-proxy/ftp-proxy.8	Tue Apr 26 21:06:56 2011	(r221085)
@@ -1,4 +1,4 @@
-.\"	$OpenBSD: ftp-proxy.8,v 1.7 2006/12/30 13:01:54 camield Exp $
+.\"	$OpenBSD: ftp-proxy.8,v 1.11 2008/02/26 18:52:53 henning Exp $
 .\"
 .\" Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd at sentia.nl>
 .\"
@@ -14,16 +14,15 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.\" $FreeBSD$
-.\"
-.Dd November 28, 2004
+.Dd $Mdocdate: February 26 2008 $
 .Dt FTP-PROXY 8
 .Os
 .Sh NAME
 .Nm ftp-proxy
 .Nd Internet File Transfer Protocol proxy daemon
 .Sh SYNOPSIS
-.Nm ftp-proxy
+.Nm
+.Bk -words
 .Op Fl 6Adrv
 .Op Fl a Ar address
 .Op Fl b Ar address
@@ -33,7 +32,9 @@
 .Op Fl p Ar port
 .Op Fl q Ar queue
 .Op Fl R Ar address
+.Op Fl T Ar tag
 .Op Fl t Ar timeout
+.Ek
 .Sh DESCRIPTION
 .Nm
 is a proxy for the Internet File Transfer Protocol.
@@ -58,7 +59,7 @@ facility for this.
 Assuming the FTP control connection is from $client to $server, the
 proxy connected to the server using the $proxy source address, and
 $port is negotiated, then
-.Nm ftp-proxy
+.Nm
 adds the following rules to the various anchors.
 (These example rules use inet, but the proxy also supports inet6.)
 .Pp
@@ -130,6 +131,20 @@ connections to another proxy.
 .It Fl r
 Rewrite sourceport to 20 in active mode to suit ancient clients that insist
 on this RFC property.
+.It Fl T Ar tag
+The filter rules will add tag
+.Ar tag
+to data connections, and not match quick.
+This way alternative rules that use the
+.Ar tagged
+keyword can be implemented following the
+.Nm
+anchor.
+These rules can use special
+.Xr pf 4
+features like route-to, reply-to, label, rtable, overload, etc. that
+.Nm
+does not implement itself.
 .It Fl t Ar timeout
 Number of seconds that the control connection can be idle, before the
 proxy will disconnect.
@@ -172,7 +187,7 @@ does not allow the ruleset to be modifie
 .Xr securelevel 7
 higher than 1.
 At that level
-.Nm ftp-proxy
+.Nm
 cannot add rules to the anchors and FTP data connections may get blocked.
 .Pp
 Negotiated data connection ports below 1024 are not allowed.
@@ -181,5 +196,5 @@ The negotiated IP address for active mod
 reasons.
 This makes third party file transfers impossible.
 .Pp
-.Nm ftp-proxy
+.Nm
 chroots to "/var/empty" and changes to user "proxy" to drop privileges.

Modified: projects/pf/pf45/contrib/pf/ftp-proxy/ftp-proxy.c
==============================================================================
--- projects/pf/pf45/contrib/pf/ftp-proxy/ftp-proxy.c	Tue Apr 26 21:06:05 2011	(r221084)
+++ projects/pf/pf45/contrib/pf/ftp-proxy/ftp-proxy.c	Tue Apr 26 21:06:56 2011	(r221085)
@@ -1,4 +1,4 @@
-/*	$OpenBSD: ftp-proxy.c,v 1.13 2006/12/30 13:24:00 camield Exp $ */
+/*	$OpenBSD: ftp-proxy.c,v 1.19 2008/06/13 07:25:26 claudio Exp $ */
 
 /*
  * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd at sentia.nl>
@@ -16,9 +16,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
 #include <sys/queue.h>
 #include <sys/types.h>
 #include <sys/time.h>
@@ -61,6 +58,14 @@ __FBSDID("$FreeBSD$");
 #define PF_NAT_PROXY_PORT_LOW	50001
 #define PF_NAT_PROXY_PORT_HIGH	65535
 
+#ifndef LIST_END
+#define LIST_END(a)     NULL
+#endif
+
+#ifndef getrtable
+#define getrtable(a)    0
+#endif
+
 #define	sstosa(ss)	((struct sockaddr *)(ss))
 
 enum { CMD_NONE = 0, CMD_PORT, CMD_EPRT, CMD_PASV, CMD_EPSV };
@@ -94,7 +99,7 @@ int	client_parse_cmd(struct session *s);
 void	client_read(struct bufferevent *, void *);
 int	drop_privs(void);
 void	end_session(struct session *);
-int	exit_daemon(void);
+void	exit_daemon(void);
 int	getline(char *, size_t *);
 void	handle_connection(const int, short, void *);
 void	handle_signal(int, short, void *);
@@ -105,6 +110,7 @@ u_int16_t pick_proxy_port(void);
 void	proxy_reply(int, struct sockaddr *, u_int16_t);
 void	server_error(struct bufferevent *, short, void *);
 int	server_parse(struct session *s);
+int	allow_data_connection(struct session *s);
 void	server_read(struct bufferevent *, void *);
 const char *sock_ntop(struct sockaddr *);
 void	usage(void);
@@ -115,14 +121,14 @@ size_t linelen;
 char ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN];
 
 struct sockaddr_storage fixed_server_ss, fixed_proxy_ss;
-char *fixed_server, *fixed_server_port, *fixed_proxy, *listen_ip, *listen_port,
-    *qname;
+const char *fixed_server, *fixed_server_port, *fixed_proxy, *listen_ip, *listen_port,
+    *qname, *tagname;
 int anonymous_only, daemonize, id_count, ipv6_mode, loglevel, max_sessions,
     rfc_mode, session_count, timeout, verbose;
 extern char *__progname;
 
 void
-client_error(struct bufferevent *bufev, short what, void *arg)
+client_error(struct bufferevent *bufev __unused, short what, void *arg)
 {
 	struct session *s = arg;
 
@@ -152,8 +158,19 @@ client_parse(struct session *s)
 		return (1);
 
 	if (linebuf[0] == 'P' || linebuf[0] == 'p' ||
-	    linebuf[0] == 'E' || linebuf[0] == 'e')
-		return (client_parse_cmd(s));
+	    linebuf[0] == 'E' || linebuf[0] == 'e') {
+		if (!client_parse_cmd(s))
+			return (0);
+
+		/*
+		 * Allow active mode connections immediately, instead of
+		 * waiting for a positive reply from the server.  Some
+		 * rare servers/proxies try to probe or setup the data
+		 * connection before an actual transfer request.
+		 */
+		if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT)
+			return (allow_data_connection(s));
+	}
 	
 	if (anonymous_only && (linebuf[0] == 'U' || linebuf[0] == 'u'))
 		return (client_parse_anon(s));
@@ -220,14 +237,14 @@ void
 client_read(struct bufferevent *bufev, void *arg)
 {
 	struct session	*s = arg;
-	size_t		 buf_avail, read;
+	size_t		 buf_avail, clientread;
 	int		 n;
 
 	do {
 		buf_avail = sizeof s->cbuf - s->cbuf_valid;
-		read = bufferevent_read(bufev, s->cbuf + s->cbuf_valid,
+		clientread = bufferevent_read(bufev, s->cbuf + s->cbuf_valid,
 		    buf_avail);
-		s->cbuf_valid += read;
+		s->cbuf_valid += clientread;
 
 		while ((n = getline(s->cbuf, &s->cbuf_valid)) > 0) {
 			logmsg(LOG_DEBUG, "#%d client: %s", s->id, linebuf);
@@ -244,7 +261,7 @@ client_read(struct bufferevent *bufev, v
 			end_session(s);
 			return;
 		}
-	} while (read == buf_avail);
+	} while (clientread == buf_avail);
 }
 
 int
@@ -269,10 +286,16 @@ drop_privs(void)
 void
 end_session(struct session *s)
 {
-	int err;
+	int serr;
 
 	logmsg(LOG_INFO, "#%d ending session", s->id);
 
+	/* Flush output buffers. */
+	if (s->client_bufev && s->client_fd != -1)
+		evbuffer_write(s->client_bufev->output, s->client_fd);
+	if (s->server_bufev && s->server_fd != -1)
+		evbuffer_write(s->server_bufev->output, s->server_fd);
+
 	if (s->client_fd != -1)
 		close(s->client_fd);
 	if (s->server_fd != -1)
@@ -284,33 +307,29 @@ end_session(struct session *s)
 		bufferevent_free(s->server_bufev);
 
 	/* Remove rulesets by commiting empty ones. */
-	err = 0;
+	serr = 0;
 	if (prepare_commit(s->id) == -1)
-		err = errno;
+		serr = errno;
 	else if (do_commit() == -1) {
-		err = errno;
+		serr = errno;
 		do_rollback();
 	}
-	if (err)
+	if (serr)
 		logmsg(LOG_ERR, "#%d pf rule removal failed: %s", s->id,
-		    strerror(err));
+		    strerror(serr));
 
 	LIST_REMOVE(s, entry);
 	free(s);
 	session_count--;
 }
 
-int
+void
 exit_daemon(void)
 {
 	struct session *s, *next;
 
-#ifdef __FreeBSD__
-	LIST_FOREACH_SAFE(s, &sessions, entry, next) {
-#else
 	for (s = LIST_FIRST(&sessions); s != LIST_END(&sessions); s = next) {
 		next = LIST_NEXT(s, entry);
-#endif
 		end_session(s);
 	}
 
@@ -318,9 +337,6 @@ exit_daemon(void)
 		closelog();
 
 	exit(0);
-
-	/* NOTREACHED */
-	return (-1);
 }
 
 int
@@ -361,7 +377,7 @@ getline(char *buf, size_t *valid)
 }
 
 void
-handle_connection(const int listen_fd, short event, void *ev)
+handle_connection(const int listen_fd, short event __unused, void *ev __unused)
 {
 	struct sockaddr_storage tmp_ss;
 	struct sockaddr *client_sa, *server_sa, *fixed_server_sa;
@@ -508,13 +524,13 @@ handle_connection(const int listen_fd, s
 }
 
 void
-handle_signal(int sig, short event, void *arg)
+handle_signal(int sig, short event __unused, void *arg __unused)
 {
 	/*
 	 * Signal handler rules don't apply, libevent decouples for us.
 	 */
 
-	logmsg(LOG_ERR, "%s exiting on signal %d", __progname, sig);
+	logmsg(LOG_ERR, "exiting on signal %d", sig);
 
 	exit_daemon();
 }
@@ -567,10 +583,7 @@ logmsg(int pri, const char *message, ...
 		/* We don't care about truncation. */
 		vsnprintf(buf, sizeof buf, message, ap);
 #ifdef __FreeBSD__
-		/* XXX: strnvis might be nice to have */
-		strvisx(visbuf, buf,
-		    MIN((sizeof(visbuf) / 4) - 1, strlen(buf)),
-		    VIS_CSTYLE | VIS_NL);
+		strvis(visbuf, buf, VIS_CSTYLE | VIS_NL);
 #else
 		strnvis(visbuf, buf, sizeof visbuf, VIS_CSTYLE | VIS_NL);
 #endif
@@ -602,6 +615,7 @@ main(int argc, char *argv[])
 	max_sessions	= 100;
 	qname		= NULL;
 	rfc_mode	= 0;
+	tagname		= NULL;
 	timeout		= 24 * 3600;
 	verbose		= 0;
 
@@ -609,7 +623,7 @@ main(int argc, char *argv[])
 	id_count	= 1;
 	session_count	= 0;
 
-	while ((ch = getopt(argc, argv, "6Aa:b:D:dm:P:p:q:R:rt:v")) != -1) {
+	while ((ch = getopt(argc, argv, "6Aa:b:D:dm:P:p:q:R:rT:t:v")) != -1) {
 		switch (ch) {
 		case '6':
 			ipv6_mode = 1;
@@ -654,6 +668,11 @@ main(int argc, char *argv[])
 		case 'r':
 			rfc_mode = 1;
 			break;
+		case 'T':
+			if (strlen(optarg) >= PF_TAG_NAME_SIZE)
+				errx(1, "tagname too long");
+			tagname = optarg;
+			break;
 		case 't':
 			timeout = strtonum(optarg, 0, 86400, &errstr);
 			if (errstr)
@@ -734,7 +753,7 @@ main(int argc, char *argv[])
 	freeaddrinfo(res);
 
 	/* Initialize pf. */
-	init_filter(qname, verbose);
+	init_filter(qname, tagname, verbose);
 
 	if (daemonize) {
 		if (daemon(0, 0) == -1)
@@ -830,14 +849,15 @@ u_int16_t
 pick_proxy_port(void)
 {
 	/* Random should be good enough for avoiding port collisions. */
-	return (IPPORT_HIFIRSTAUTO + (arc4random() %
-	    (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)));
+	return (IPPORT_HIFIRSTAUTO +
+	    arc4random_uniform(IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO));
 }
 
 void
 proxy_reply(int cmd, struct sockaddr *sa, u_int16_t port)
 {
-	int i, r;
+	u_int i;
+	int r = 0;
 
 	switch (cmd) {
 	case CMD_PORT:
@@ -864,7 +884,7 @@ proxy_reply(int cmd, struct sockaddr *sa
 		break;
 	}
 
-	if (r < 0 || r >= sizeof linebuf) {
+	if (r < 0 || ((u_int)r) >= sizeof linebuf) {
 		logmsg(LOG_ERR, "proxy_reply failed: %d", r);
 		linebuf[0] = '\0';
 		linelen = 0;
@@ -881,7 +901,7 @@ proxy_reply(int cmd, struct sockaddr *sa
 }
 
 void
-server_error(struct bufferevent *bufev, short what, void *arg)
+server_error(struct bufferevent *bufev __unused, short what, void *arg)
 {
 	struct session *s = arg;
 
@@ -902,12 +922,26 @@ server_error(struct bufferevent *bufev, 
 int
 server_parse(struct session *s)
 {
-	struct sockaddr *client_sa, *orig_sa, *proxy_sa, *server_sa;
-	int prepared = 0;
-
 	if (s->cmd == CMD_NONE || linelen < 4 || linebuf[0] != '2')
 		goto out;
 
+	if ((s->cmd == CMD_PASV && strncmp("227 ", linebuf, 4) == 0) ||
+	    (s->cmd == CMD_EPSV && strncmp("229 ", linebuf, 4) == 0))
+		return (allow_data_connection(s));
+
+ out:
+	s->cmd = CMD_NONE;
+	s->port = 0;
+
+	return (1);
+}
+
+int
+allow_data_connection(struct session *s)
+{
+	struct sockaddr *client_sa, *orig_sa, *proxy_sa, *server_sa;
+	int prepared = 0;
+
 	/*
 	 * The pf rules below do quite some NAT rewriting, to keep up
 	 * appearances.  Points to keep in mind:
@@ -932,8 +966,7 @@ server_parse(struct session *s)
 		orig_sa = sstosa(&s->server_ss);
 
 	/* Passive modes. */
-	if ((s->cmd == CMD_PASV && strncmp("227 ", linebuf, 4) == 0) ||
-	    (s->cmd == CMD_EPSV && strncmp("229 ", linebuf, 4) == 0)) {
+	if (s->cmd == CMD_PASV || s->cmd == CMD_EPSV) {
 		s->port = parse_port(s->cmd);
 		if (s->port < MIN_PORT) {
 			logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id,
@@ -974,8 +1007,7 @@ server_parse(struct session *s)
 	}
 
 	/* Active modes. */
-	if ((s->cmd == CMD_PORT || s->cmd == CMD_EPRT) &&
-	    strncmp("200 ", linebuf, 4) == 0) {
+	if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT) {
 		logmsg(LOG_INFO, "#%d active: server to client port %d"
 		    " via port %d", s->id, s->port, s->proxy_port);
 
@@ -1025,7 +1057,6 @@ server_parse(struct session *s)
 			goto fail;
 	}
 
- out:
 	s->cmd = CMD_NONE;
 	s->port = 0;
 
@@ -1042,16 +1073,16 @@ void
 server_read(struct bufferevent *bufev, void *arg)
 {
 	struct session	*s = arg;
-	size_t		 buf_avail, read;
+	size_t		 buf_avail, srvread;
 	int		 n;
 
 	bufferevent_settimeout(bufev, timeout, 0);
 
 	do {
 		buf_avail = sizeof s->sbuf - s->sbuf_valid;
-		read = bufferevent_read(bufev, s->sbuf + s->sbuf_valid,
+		srvread = bufferevent_read(bufev, s->sbuf + s->sbuf_valid,
 		    buf_avail);
-		s->sbuf_valid += read;
+		s->sbuf_valid += srvread;
 
 		while ((n = getline(s->sbuf, &s->sbuf_valid)) > 0) {
 			logmsg(LOG_DEBUG, "#%d server: %s", s->id, linebuf);
@@ -1068,7 +1099,7 @@ server_read(struct bufferevent *bufev, v
 			end_session(s);
 			return;
 		}
-	} while (read == buf_avail);
+	} while (srvread == buf_avail);
 }
 
 const char *
@@ -1102,6 +1133,7 @@ usage(void)
 {
 	fprintf(stderr, "usage: %s [-6Adrv] [-a address] [-b address]"
 	    " [-D level] [-m maxsessions]\n                 [-P port]"
-	    " [-p port] [-q queue] [-R address] [-t timeout]\n", __progname);
+	    " [-p port] [-q queue] [-R address] [-T tag]\n"
+            "                 [-t timeout]\n", __progname);
 	exit(1);
 }


More information about the svn-src-projects mailing list