From owner-freebsd-hackers@FreeBSD.ORG Wed Jul 14 00:25:29 2010 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 581D01065670 for ; Wed, 14 Jul 2010 00:25:29 +0000 (UTC) (envelope-from lobo@bsd.com.br) Received: from mail-gx0-f182.google.com (mail-gx0-f182.google.com [209.85.161.182]) by mx1.freebsd.org (Postfix) with ESMTP id 08B0A8FC12 for ; Wed, 14 Jul 2010 00:25:28 +0000 (UTC) Received: by gxk24 with SMTP id 24so4436746gxk.13 for ; Tue, 13 Jul 2010 17:25:28 -0700 (PDT) Received: by 10.101.75.17 with SMTP id c17mr17457563anl.128.1279067126594; Tue, 13 Jul 2010 17:25:26 -0700 (PDT) Received: from papi.localnet ([189.70.227.74]) by mx.google.com with ESMTPS id a12sm71899064and.16.2010.07.13.17.25.23 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 13 Jul 2010 17:25:25 -0700 (PDT) From: Mario Lobo To: freebsd-hackers@freebsd.org Date: Tue, 13 Jul 2010 21:25:00 +0000 User-Agent: KMail/1.13.3 (FreeBSD/8.1-PRERELEASE; KDE/4.4.4; amd64; ; ) MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_smNPMippf34UdyY" Message-Id: <201007132125.00541.lobo@bsd.com.br> Subject: ftp-proxy -T tag patch for FBSD X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 14 Jul 2010 00:25:29 -0000 --Boundary-00=_smNPMippf34UdyY Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Hello; First, forgive me if that's not the right list to post this but I picked the most akin list to the subject I was subscribed to. After all, ftp-proxy is part of the base system now. If any of you is subscribed to a better list for this, please forward it to it. I felt sorry the -T tag option was present in Linux and not on FBSD because I got to a situation where it would really be useful for me. So I decided to stuff my hands on the grease can. What this does is to give the option to put a tag (instead of a queue to the dynamic rules that ftp-proxy creates on the fly. The option to put a queue is nice but it confines the rule to THAT queue only, and you cannot create queues with the same name on different interfaces. You could specify 2 interfaces on the same altq rule, but then again, both interfaces will be confined to the same queue tunings. The -T "tag" option however, besides tagging the packets for the rule, takes the "quick" keyword out of it, so rule processing can continue, to later find a rule that has the keyword "tagged tag" and be sent to any queue you want. A really welcomed flexibility. The application of nat-anchor "ftp-proxy/*" and rdr-anchor "ftp-proxy/*" are still as per man pages. Just make sure you put anchor "ftp-proxy/*" right before the first pass rule rc.conf example --------------------------------------------------- ftpproxy_enable="YES" ftpproxy_flags="-r -v -T ftp_proxy" pf.conf example --------------------------------------------------- # Ftp (it inserts its rules here, like bellow, taken from `pfctl -vv -a ftp-proxy/15780.1 -sr`) anchor "ftp-proxy/*" @0 pass in log inet proto tcp from 172.16.3.145 to 129.128.5.191 port = 61076 flags S/SA keep state (max 1) tag ftp_proxy rtable 0 @1 pass out log inet proto tcp from 189.23.180.30 to 129.128.5.191 port = 61076 flags S/SA keep state (max 1) tag ftp_proxy rtable 0 # first pass rule of pf.conf pass in log quick on $ext_if inet proto icmp from any to ($ext_if) icmp- type 8 code 0 keep state queue (icmp) --------- then way down there... --------- pass out log quick on $int_if inet proto tcp tagged ftp_proxy keep state queue (ether) --------- even further down, a different match ... --------- pass out log quick on $ext_if inet proto tcp tagged ftp_proxy keep state queue (ftp) ------------------------------------------------------------------- The lines bellow were taken during an ftp session to ftp.openbsd.com from a LAN client station. ================================ # Server [20:14:03] [~]>pfctl -vv -sA ftp-proxy ftp-proxy/15780.1 # Server [20:15:01] [~]> pfctl -vv -a ftp-proxy/15780.1 -sr @0 pass in log inet proto tcp from 172.16.3.145 to 129.128.5.191 port = 61076 flags S/SA keep state (max 1) tag ftp_proxy rtable 0 [ Evaluations: 4 Packets: 0 Bytes: 0 States: 0 ] [ Inserted: uid 62 pid 15780 ] @1 pass out log inet proto tcp from 189.12.120.67 to 129.128.5.191 port = 61076 flags S/SA keep state (max 1) tag ftp_proxy rtable 0 [ Evaluations: 4 Packets: 0 Bytes: 0 States: 0 ] [ Inserted: uid 62 pid 15780 ] # Server [20:15:11] [~]>pfctl -vv -sA ftp-proxy ftp-proxy/15780.1 # Server [20:15:16] [~]> pfctl -vv -a ftp-proxy/15780.1 -sn @0 nat inet proto tcp from 172.16.3.145 to 129.128.5.191 port = 61076 rtable 0 -> 189.12.120.67 [ Evaluations: 1 Packets: 0 Bytes: 0 States: 0 ] [ Inserted: uid 62 pid 15780 ] @0 rdr inet proto tcp from 172.16.3.145 to 129.128.5.191 port = 51973 rtable 0 -> 129.128.5.191 port 61076 [ Evaluations: 6 Packets: 8 Bytes: 1485 States: 0 ] [ Inserted: uid 62 pid 15780 ] # Server [20:15:23] [~]> pfctl -vv -a ftp-proxy/15780.1 -sn pfctl: DIOCGETRULES: Invalid argument # Server [20:16:12] [~]>pfctl -vv -sA ftp-proxy ================================ The nat, rdr and pass rules are correctly created and tagged. Observe the times to see that ftp-proxy removes the rule really fast. To apply the patch, copy it to /usr/src/contrib/pf/ftp-proxy/ then, cd /usr/src/usr.sbin/ftp-proxy/ftp-proxy make [clean] make install Wisdom demands to test it for while before putting into production, but it has been working for me for a couple of weeks. I hope this is useful, because ftp-proxy is really simple. But a great program. -- Mario Lobo http://www.mallavoodoo.com.br FreeBSD since 2.2.8 [not Pro-Audio.... YET!!] (99% winfoes FREE) --Boundary-00=_smNPMippf34UdyY Content-Type: text/x-patch; charset="ISO-8859-1"; name="ftp-proxy.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ftp-proxy.patch" --- ftp-proxy.c.orig 2009-08-03 08:13:06.000000000 +0000 +++ ftp-proxy.c 2010-07-13 12:56:07.000000000 +0000 @@ -116,7 +116,7 @@ struct sockaddr_storage fixed_server_ss, fixed_proxy_ss; char *fixed_server, *fixed_server_port, *fixed_proxy, *listen_ip, *listen_port, - *qname; + *qname, *tname; int anonymous_only, daemonize, id_count, ipv6_mode, loglevel, max_sessions, rfc_mode, session_count, timeout, verbose; extern char *__progname; @@ -601,6 +601,7 @@ loglevel = LOG_NOTICE; max_sessions = 100; qname = NULL; + tname = NULL; rfc_mode = 0; timeout = 24 * 3600; verbose = 0; @@ -609,7 +610,7 @@ 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; @@ -647,8 +648,9 @@ if (strlen(optarg) >= PF_QNAME_SIZE) errx(1, "queuename too long"); qname = optarg; + tname = NULL; break; - case 'R': + case 'R': fixed_server = optarg; break; case 'r': @@ -659,6 +661,12 @@ if (errstr) errx(1, "timeout %s", errstr); break; + case 'T': + if (strlen(optarg) >= PF_TAG_NAME_SIZE) + errx(1, "tagname too long"); + tname = optarg; + qname = NULL; + break; case 'v': verbose++; if (verbose > 2) @@ -734,7 +742,8 @@ freeaddrinfo(res); /* Initialize pf. */ - init_filter(qname, verbose); + init_filter_q(qname, verbose); + init_filter_t(tname, verbose); if (daemonize) { if (daemon(0, 0) == -1) @@ -1102,6 +1111,6 @@ { 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 timeout] [-T tag]\n", __progname); exit(1); } --- filter.c.orig 2007-07-03 12:21:51.000000000 +0000 +++ filter.c 2010-07-13 05:57:20.000000000 +0000 @@ -54,6 +54,7 @@ static struct pfioc_trans_e pfte[TRANS_SIZE]; static int dev, rule_log; static char *qname; +static char *tname; int add_filter(u_int32_t id, u_int8_t dir, struct sockaddr *src, @@ -159,7 +160,7 @@ } void -init_filter(char *opt_qname, int opt_verbose) +init_filter_q(char *opt_qname, int opt_verbose) { struct pf_status status; @@ -179,6 +180,28 @@ errx(1, "pf is disabled"); } +void +init_filter_t(char *opt_tname, int opt_verbose) +{ + struct pf_status status; + + tname = opt_tname; + + if (opt_verbose == 1) + rule_log = PF_LOG; + else if (opt_verbose == 2) + rule_log = PF_LOG_ALL; + + dev = open("/dev/pf", O_RDWR); + if (dev == -1) + err(1, "/dev/pf"); + if (ioctl(dev, DIOCGETSTATUS, &status) == -1) + err(1, "DIOCGETSTATUS"); + if (!status.running) + errx(1, "pf is disabled"); +} + + int prepare_commit(u_int32_t id) { @@ -279,20 +302,29 @@ switch (rs_num) { case PF_RULESET_FILTER: - /* - * pass quick [log] inet[6] proto tcp \ - * from $src to $dst port = $d_port flags S/SA keep state - * (max 1) [queue qname] - */ - pfr.rule.action = PF_PASS; - pfr.rule.quick = 1; - pfr.rule.log = rule_log; - pfr.rule.keep_state = 1; - pfr.rule.flags = TH_SYN; - pfr.rule.flagset = (TH_SYN|TH_ACK); - pfr.rule.max_states = 1; - if (qname != NULL) - strlcpy(pfr.rule.qname, qname, sizeof pfr.rule.qname); + + /* + * pass quick [log] inet[6] proto tcp \ + * from $src to $dst port = $d_port flags S/SA keep state + * (max 1) [queue qname] + */ + + pfr.rule.action = PF_PASS; + pfr.rule.log = rule_log; + pfr.rule.keep_state = 1; + pfr.rule.flags = TH_SYN; + pfr.rule.flagset = (TH_SYN|TH_ACK); + pfr.rule.max_states = 1; + pfr.rule.quick = 1; + + if (qname != NULL) { + strlcpy(pfr.rule.qname, qname, sizeof pfr.rule.qname); + } else { + if (tname != NULL) { + pfr.rule.quick = 0; + strlcpy(pfr.rule.tagname, tname, sizeof pfr.rule.tagname); + } + } break; case PF_RULESET_NAT: /* --- filter.h.orig 2007-07-03 12:21:50.000000000 +0000 +++ filter.h 2010-07-13 05:25:52.000000000 +0000 @@ -26,6 +26,7 @@ struct sockaddr *, u_int16_t); int do_commit(void); int do_rollback(void); -void init_filter(char *, int); +void init_filter_q(char *, int); +void init_filter_t(char *, int); int prepare_commit(u_int32_t); int server_lookup(struct sockaddr *, struct sockaddr *, struct sockaddr *); --- ftp-proxy.8.orig 2009-08-03 08:13:06.000000000 +0000 +++ ftp-proxy.8 2010-07-13 13:22:58.000000000 +0000 @@ -120,7 +120,9 @@ .It Fl q Ar queue Create rules with queue .Ar queue -appended, so that data connections can be queued. +appended, so that data connections can be queued. The -T option +is automatically cancelled. If both are present, the last on the +command line prevails. .It Fl R Ar address Fixed server address, also known as reverse mode. The proxy will always connect to the same server, regardless of @@ -136,6 +138,12 @@ The maximum is 86400 seconds, which is also the default. Do not set this too low, because the control connection is usually idle when large data transfers are taking place. +.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 tagged key-word can be implemented following the ftp-proxy +anchor that ftp-proxy does not implement itself. .It Fl v Set the 'log' flag on pf rules committed by .Nm . --Boundary-00=_smNPMippf34UdyY--