summaryrefslogtreecommitdiffstats
path: root/contrib/pf/ftp-proxy
diff options
context:
space:
mode:
authorbz <bz@FreeBSD.org>2011-06-28 11:57:25 +0000
committerbz <bz@FreeBSD.org>2011-06-28 11:57:25 +0000
commite15f804c7b67f7cac4a68d0f6b6d0418e9f7309a (patch)
tree6f90e30d66bc1d86e242d960993589e5a0ad8936 /contrib/pf/ftp-proxy
parenta963cb97121e4c58292b7deaf2a9d08d4455b21b (diff)
downloadFreeBSD-src-e15f804c7b67f7cac4a68d0f6b6d0418e9f7309a.zip
FreeBSD-src-e15f804c7b67f7cac4a68d0f6b6d0418e9f7309a.tar.gz
Update packet filter (pf) code to OpenBSD 4.5.
You need to update userland (world and ports) tools to be in sync with the kernel. Submitted by: mlaier Submitted by: eri
Diffstat (limited to 'contrib/pf/ftp-proxy')
-rw-r--r--contrib/pf/ftp-proxy/filter.c18
-rw-r--r--contrib/pf/ftp-proxy/filter.h4
-rw-r--r--contrib/pf/ftp-proxy/ftp-proxy.829
-rw-r--r--contrib/pf/ftp-proxy/ftp-proxy.c139
4 files changed, 124 insertions, 66 deletions
diff --git a/contrib/pf/ftp-proxy/filter.c b/contrib/pf/ftp-proxy/filter.c
index f86429d..f575db1 100644
--- a/contrib/pf/ftp-proxy/filter.c
+++ b/contrib/pf/ftp-proxy/filter.c
@@ -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@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_verbose)
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, struct sockaddr *src,
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, struct sockaddr *src,
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:
/*
diff --git a/contrib/pf/ftp-proxy/filter.h b/contrib/pf/ftp-proxy/filter.h
index 6779c59..3b48898 100644
--- a/contrib/pf/ftp-proxy/filter.h
+++ b/contrib/pf/ftp-proxy/filter.h
@@ -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@sentia.nl>
@@ -26,6 +26,6 @@ int add_rdr(u_int32_t, struct sockaddr *, struct sockaddr *, u_int16_t,
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 *);
diff --git a/contrib/pf/ftp-proxy/ftp-proxy.8 b/contrib/pf/ftp-proxy/ftp-proxy.8
index 69c848e..d4dd030 100644
--- a/contrib/pf/ftp-proxy/ftp-proxy.8
+++ b/contrib/pf/ftp-proxy/ftp-proxy.8
@@ -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@sentia.nl>
.\"
@@ -16,14 +16,15 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 28, 2004
+.Dd 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 +34,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 +61,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 +133,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 +189,7 @@ does not allow the ruleset to be modified if the system is running at a
.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 +198,5 @@ The negotiated IP address for active modes is ignored for security
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.
diff --git a/contrib/pf/ftp-proxy/ftp-proxy.c b/contrib/pf/ftp-proxy/ftp-proxy.c
index 06c8487..26de75a 100644
--- a/contrib/pf/ftp-proxy/ftp-proxy.c
+++ b/contrib/pf/ftp-proxy/ftp-proxy.c
@@ -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@sentia.nl>
@@ -61,6 +61,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 +102,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 +113,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 +124,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 +161,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 +240,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 +264,7 @@ client_read(struct bufferevent *bufev, void *arg)
end_session(s);
return;
}
- } while (read == buf_avail);
+ } while (clientread == buf_avail);
}
int
@@ -269,10 +289,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 +310,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 +340,6 @@ exit_daemon(void)
closelog();
exit(0);
-
- /* NOTREACHED */
- return (-1);
}
int
@@ -361,7 +380,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 +527,13 @@ handle_connection(const int listen_fd, short event, void *ev)
}
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 +586,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 +618,7 @@ main(int argc, char *argv[])
max_sessions = 100;
qname = NULL;
rfc_mode = 0;
+ tagname = NULL;
timeout = 24 * 3600;
verbose = 0;
@@ -609,7 +626,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 +671,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 +756,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 +852,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 +887,7 @@ proxy_reply(int cmd, struct sockaddr *sa, u_int16_t port)
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 +904,7 @@ proxy_reply(int cmd, struct sockaddr *sa, u_int16_t port)
}
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 +925,26 @@ server_error(struct bufferevent *bufev, short what, void *arg)
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 +969,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 +1010,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 +1060,6 @@ server_parse(struct session *s)
goto fail;
}
- out:
s->cmd = CMD_NONE;
s->port = 0;
@@ -1042,16 +1076,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 +1102,7 @@ server_read(struct bufferevent *bufev, void *arg)
end_session(s);
return;
}
- } while (read == buf_avail);
+ } while (srvread == buf_avail);
}
const char *
@@ -1102,6 +1136,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);
}
OpenPOWER on IntegriCloud