bin/148686: ftp-proxy -T tag patch for FBSD

Mario Lobo lobo at bsd.com.br
Fri Jul 16 16:10:09 UTC 2010


>Number:         148686
>Category:       bin
>Synopsis:       ftp-proxy -T tag patch for FBSD
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jul 16 16:10:07 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator:     Mario Lobo
>Release:        8.1-PRERELEASE
>Organization:
>Environment:
FreeBSD Papi 8.1-PRERELEASE FreeBSD 8.1-PRERELEASE #0: Sat Jul  3 13:06:10 UTC 2010     root at Papi:/usr/src/sys/amd64/compile/LOBO  amd64
>Description:
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 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
>How-To-Repeat:
NA
>Fix:


Patch attached with submission follows:

--- 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 -T and -q are both 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 keyword can be implemented. The -q option is
+is automatically cancelled.
 .It Fl v
 Set the 'log' flag on pf rules committed by
 .Nm .


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list