Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 13 Jul 2010 21:25:00 +0000
From:      Mario Lobo <lobo@bsd.com.br>
To:        freebsd-hackers@freebsd.org
Subject:   ftp-proxy -T tag patch for FBSD
Message-ID:  <201007132125.00541.lobo@bsd.com.br>

next in thread | raw e-mail | index | archive | help
--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--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007132125.00541.lobo>