Hello,

I would like to propose a patch (against FreeBSD RELENG_8) to extend
the port randomization support in FreeBSD, according to RFC6056
(https://www.rfc-editor.org/rfc/rfc6056.txt)

Currently the patch implements:
- Algorithm 1 (default in FreeBSD 8)
- Algorithm 2
- Algorithm 5
from the aforementioned RFC6056.

Any of those algorithms can be chosen with the sysctl variable
net.inet.ip.portrange.rfc6056_algorithm.

I deliberately skipped Algorithm 3 and Algorithm 4, because I believe
usage of cryptographic hash functions will introduce unnecessary
latency in vital network operations. However, in case of expressed
interest, I will be glad to add those too.

I would like to ask what is the proper way to validate the sysctl
input in order to accept only a specific values? In my case only '1',
'2' and '5'.

Thank you very much.

Ivo Vachkov
diff -r fbf1313362d7 src/sys/netinet/in_pcb.c
--- a/src/sys/netinet/in_pcb.c	Tue Jan 25 14:03:37 2011 +0200
+++ b/src/sys/netinet/in_pcb.c	Wed Jan 26 12:58:05 2011 +0200
@@ -109,6 +109,7 @@
 VNET_DEFINE(int, ipport_stoprandom);		/* toggled by ipport_tick */
 VNET_DEFINE(int, ipport_tcpallocs);
 static VNET_DEFINE(int, ipport_tcplastcount);
+VNET_DEFINE(int, ipport_rfc6056alg) = 1;	/* user controlled via sysctl */
 
 #define	V_ipport_tcplastcount		VNET(ipport_tcplastcount)
 
@@ -174,6 +175,8 @@
 	&VNET_NAME(ipport_randomtime), 0,
 	"Minimum time to keep sequental port "
 	"allocation before switching to a random one");
+SYSCTL_VNET_INT(_net_inet_ip_portrange, OID_AUTO, rfc6056_algorithm, CTLFLAG_RW,
+	&VNET_NAME(ipport_rfc6056alg), 0, "RFC 6056 Port randomization algorithm");
 
 /*
  * in_pcb.c: manage the Protocol Control Blocks.
@@ -468,21 +471,75 @@
 			last = aux;
 		}
 
-		if (dorandom)
-			*lastport = first +
-				    (arc4random() % (last - first));
-
 		count = last - first;
 
-		do {
-			if (count-- < 0)	/* completely used? */
-				return (EADDRNOTAVAIL);
-			++*lastport;
-			if (*lastport < first || *lastport > last)
-				*lastport = first;
-			lport = htons(*lastport);
-		} while (in_pcblookup_local(pcbinfo, laddr,
-		    lport, wild, cred));
+		/* 
+		 * According to RFC6056 there are 5 (five) possible algorithms
+		 * for random port allocation. Usage of a particular algorithm
+		 * is specified with the 'net.inet.ip.portrange.rfc6056_algorithm'
+		 * sysctl variable. Default value is 1, which represents the
+		 * legacy random port allocation algorithm in FreeBSD.
+		 */
+		if (dorandom) {
+			switch (V_ipport_rfc6056alg) {
+			case 5:		/* Random-Increments Port Selection */
+				do {
+					if (count-- < 0)	/* completely used? */
+						return (EADDRNOTAVAIL);
+
+					*lastport = first + ((arc4random() % 65536) + 
+					    (arc4random() % 500) + 1);
+
+					if (*lastport < first || *lastport > last)
+						*lastport = first;
+					lport = htons(*lastport);
+				} while (in_pcblookup_local(pcbinfo, laddr,
+				    lport, wild, cred));
+
+				break;
+			case 2:		/* Simple Port Randomization Algorithm II */
+				do {
+					if (count-- < 0)	/* completely used? */
+						return (EADDRNOTAVAIL);
+
+					*lastport = first + (arc4random() % (last - first));
+
+					if (*lastport < first || *lastport > last)
+						*lastport = first;
+					lport = htons(*lastport);
+				} while (in_pcblookup_local(pcbinfo, laddr,
+				    lport, wild, cred));
+
+				break;
+			case 1:		/* Simple Port Randomization Algorithm I */
+			default:
+				*lastport = first + (arc4random() % (last - first));
+
+				do {
+					if (count-- < 0)	/* completely used? */
+						return (EADDRNOTAVAIL);
+
+					++*lastport;
+
+					if (*lastport < first || *lastport > last)
+						*lastport = first;
+					lport = htons(*lastport);
+				} while (in_pcblookup_local(pcbinfo, laddr,
+				    lport, wild, cred));
+			}
+		} else {
+			do {
+				if (count-- < 0)        /* completely used? */
+					return (EADDRNOTAVAIL);
+	
+				++*lastport;
+
+				if (*lastport < first || *lastport > last)
+					*lastport = first;
+				lport = htons(*lastport);
+			} while (in_pcblookup_local(pcbinfo, laddr,
+			    lport, wild, cred));
+		}
 	}
 	*laddrp = laddr.s_addr;
 	*lportp = lport;
diff -r fbf1313362d7 src/sys/netinet/in_pcb.h
--- a/src/sys/netinet/in_pcb.h	Tue Jan 25 14:03:37 2011 +0200
+++ b/src/sys/netinet/in_pcb.h	Wed Jan 26 12:58:05 2011 +0200
@@ -466,6 +466,7 @@
 VNET_DECLARE(int, ipport_randomtime);
 VNET_DECLARE(int, ipport_stoprandom);
 VNET_DECLARE(int, ipport_tcpallocs);
+VNET_DECLARE(int, ipport_rfc6056alg);
 
 #define	V_ipport_reservedhigh	VNET(ipport_reservedhigh)
 #define	V_ipport_reservedlow	VNET(ipport_reservedlow)
@@ -480,6 +481,7 @@
 #define	V_ipport_randomtime	VNET(ipport_randomtime)
 #define	V_ipport_stoprandom	VNET(ipport_stoprandom)
 #define	V_ipport_tcpallocs	VNET(ipport_tcpallocs)
+#define V_ipport_rfc6056alg	VNET(ipport_rfc6056alg)
 
 extern struct callout ipport_tick_callout;
 
_______________________________________________
freebsd-net@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"

Reply via email to