diff options
author | bz <bz@FreeBSD.org> | 2011-06-28 11:57:25 +0000 |
---|---|---|
committer | bz <bz@FreeBSD.org> | 2011-06-28 11:57:25 +0000 |
commit | e15f804c7b67f7cac4a68d0f6b6d0418e9f7309a (patch) | |
tree | 6f90e30d66bc1d86e242d960993589e5a0ad8936 /contrib/pf/ftp-proxy | |
parent | a963cb97121e4c58292b7deaf2a9d08d4455b21b (diff) | |
download | FreeBSD-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.c | 18 | ||||
-rw-r--r-- | contrib/pf/ftp-proxy/filter.h | 4 | ||||
-rw-r--r-- | contrib/pf/ftp-proxy/ftp-proxy.8 | 29 | ||||
-rw-r--r-- | contrib/pf/ftp-proxy/ftp-proxy.c | 139 |
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); } |