Hello,

I attach the latest version of the port randomization code as a patch
against RELENG_8.

Changelog:
1) sysctl variable names are changed to:
- 'net.inet.ip.portrange.randomalg.version' - representing the
algorithm of choice.
- 'net.inet.ip.portrange.randomalg.alg5_tradeoff' - representing the
Algorithm 5 computational tradeoff value (the 'N' value in the
Algorithm 5 description in the RFC 6056).
2) Code comments are synchronized with the current variable names.

Ivo Vachkov

On Sat, Jan 29, 2011 at 4:27 AM, Doug Barton <do...@freebsd.org> wrote:
> On 01/28/2011 11:57, Ivo Vachkov wrote:
>>
>> On Fri, Jan 28, 2011 at 9:00 PM, Doug Barton<do...@freebsd.org>  wrote:
>
>>> How does net.inet.ip.portrange.randomalg sound? I would also suggest that
>>> the second sysctl be named net.inet.ip.portrange.randomalg.alg5_tradeoff
>>> so
>>> that one could do 'sysctl net.inet.ip.portrange.randomalg' and see both
>>> values. But I won't quibble on that. :)
>>>
>>
>> I have no objections with this. Since this is my first attempt to
>> contribute something back to the community I decided to see how it's
>> done before. So I found:
>> net.inet.tcp.rfc1323
>> net.inet.tcp.rfc3465
>> net.inet.tcp.rfc3390
>> net.inet.tcp.rfc3042
>> which probably led me in a wrong direction :)
>
> Yeah, I had actually intended to say something to the effect of "there are
> plenty of unfortunate examples in the tree already so your doing it that way
> is totally understandable" but I trimmed it.
>
>> I understand your point and agree with it. However, my somewhat
>> limited understanding of the sysctl internal organization is telling
>> me that tree node does not support values. Am I wrong?
>
> You are likely correct. :)  It's an inconvenient fact that often forget
> because that's not the sandbox that I usually play in.
>
>> If my reasoning
>> is correct, maybe I can create the sysctl variables with the following
>> names:
>> - net.inet.ip.portrange.randomalg (Tree Node)
>> - net.inet.ip.portrange.randomalg.alg[orithm] (Leaf Node, to store the
>> selected algorithm)
>
> I would go with "version" to increase the visual distinctiveness. I searched
> the current tree and there doesn't seem to be a clear winner for how to
> portray "this is the current N/M that is in use" but "version" seems to have
> the most representatives.
>
>> - net.inet.ip.portrange.randomalg.alg5_tradeoff (Leaf Node, to store
>> the Algorithm 5 trade-off value)
>
> I'm assuming this is the "N" value mentioned in the RFC. If so, I commend
> you on your choice of "tradeoff" to represent it. :)
>
>
> hth,
>
> Doug
>
> --
>
>        Nothin' ever doesn't change, but nothin' changes much.
>                        -- OK Go
>
>        Breadth of IT experience, and depth of knowledge in the DNS.
>        Yours for the right price.  :)  http://SupersetSolutions.com/
>
>



-- 
"UNIX is basically a simple operating system, but you have to be a
genius to understand the simplicity." Dennis Ritchie
diff -r 0d67f9c982f7 src/sys/netinet/in_pcb.c
--- a/src/sys/netinet/in_pcb.c	Mon Jan 31 11:35:24 2011 +0200
+++ b/src/sys/netinet/in_pcb.c	Mon Jan 31 14:29:52 2011 +0200
@@ -81,6 +81,8 @@
 #include <netipsec/key.h>
 #endif /* IPSEC */
 
+#include <sys/md5.h>	
+
 #include <security/mac/mac_framework.h>
 
 /*
@@ -109,6 +111,8 @@
 VNET_DEFINE(int, ipport_stoprandom);		/* toggled by ipport_tick */
 VNET_DEFINE(int, ipport_tcpallocs);
 static VNET_DEFINE(int, ipport_tcplastcount);
+VNET_DEFINE(u_int, ipport_randomalg_ver) = 1;	/* user controlled via sysctl */
+VNET_DEFINE(u_int, ipport_randomalg_alg5_tradeoff) = 500;	/* user controlled via sysctl */
 
 #define	V_ipport_tcplastcount		VNET(ipport_tcplastcount)
 
@@ -141,7 +145,68 @@
 
 #undef RANGECHK
 
+/*
+ * Updates V_ipport_randomalg_ver to the provided value
+ * and ensures it is in the supported range (1 - 5)
+ */
+static int
+sysctl_net_randomalg_version_check(SYSCTL_HANDLER_ARGS)
+{
+	u_int algorithm = *(u_int *)arg1;
+	int error;
+
+#ifdef VIMAGE
+	error = vnet_sysctl_handle_uint(oidp, &algorithm, 0, req);
+#else
+	error = sysctl_handle_int(oidp, &algorithm, 0, req);
+#endif
+
+	if (error == 0) {
+		switch (algorithm) {
+		case INP_RFC6056_ALG_1:
+		case INP_RFC6056_ALG_2:
+		case INP_RFC6056_ALG_3:
+		case INP_RFC6056_ALG_4:
+		case INP_RFC6056_ALG_5:
+			V_ipport_randomalg_ver = algorithm;
+			break;
+		default:
+			return (EINVAL);
+		}
+	} 	
+
+	return (error);
+}
+
+/*
+ * Updates V_ipport_randomalg_alg5_tradeoff to provided value
+ * and ensures it is in the supported range (1 - 65536)
+ */
+static int
+sysctl_net_randomalg_alg5_tradeoff_check(SYSCTL_HANDLER_ARGS)
+{
+	u_int tradeoff = *(u_int *)arg1;
+	int error;
+
+#ifdef VIMAGE
+	error = vnet_sysctl_handle_uint(oidp, &tradeoff, 0, req);
+#else
+	error = sysctl_handle_int(oidp, &tradeoff, 0, req);
+#endif
+
+	if (error == 0) {
+		if (tradeoff < 1 || tradeoff > 65536)
+			return (EINVAL);
+		else
+			V_ipport_randomalg_alg5_tradeoff = tradeoff;
+	}
+
+	return (error);
+}
+
 SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports");
+SYSCTL_NODE(_net_inet_ip_portrange, IPPROTO_IP, randomalg, CTLFLAG_RW, 0, 
+	"Port Randomization Algorithms");
 
 SYSCTL_VNET_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst,
 	CTLTYPE_INT|CTLFLAG_RW, &VNET_NAME(ipport_lowfirstauto), 0,
@@ -174,6 +239,15 @@
 	&VNET_NAME(ipport_randomtime), 0,
 	"Minimum time to keep sequental port "
 	"allocation before switching to a random one");
+SYSCTL_VNET_PROC(_net_inet_ip_portrange_randomalg, OID_AUTO, version,
+	CTLTYPE_UINT|CTLFLAG_RW, &VNET_NAME(ipport_randomalg_ver), 0,
+	&sysctl_net_randomalg_version_check, "IU", 
+	"RFC 6056 Port randomization algorithm");
+SYSCTL_VNET_PROC(_net_inet_ip_portrange_randomalg, OID_AUTO,
+	alg5_tradeoff, CTLTYPE_UINT|CTLFLAG_RW,
+	&VNET_NAME(ipport_randomalg_alg5_tradeoff), 0,
+	&sysctl_net_randomalg_alg5_tradeoff_check, "IU",
+	"RFC 6056 Algorithm 5 computational trade-off");
 
 /*
  * in_pcb.c: manage the Protocol Control Blocks.
@@ -468,21 +542,177 @@
 			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 RFC 6056 there are 5 (five) possible algorithms
+		 * for random port allocation. Usage of a particular algorithm
+		 * is specified with the 'net.inet.ip.portrange.randomalg.version'
+		 * sysctl variable. Default value is 1, which represents the
+		 * legacy random port allocation algorithm in FreeBSD.
+		 */
+		if (dorandom) {
+			switch (V_ipport_randomalg_ver) {
+			case INP_RFC6056_ALG_5:	/* Random-Increments Port Selection */
+				do {
+					if (count-- < 0)	/* completely used? */
+						return (EADDRNOTAVAIL);
+
+					*lastport = first + ((arc4random() % 65536) + 
+					    (arc4random() % V_ipport_randomalg_alg5_tradeoff) + 1);
+
+					if (*lastport < first || *lastport > last)
+						*lastport = first;
+					lport = htons(*lastport);
+				} while (in_pcblookup_local(pcbinfo, laddr,
+				    lport, wild, cred));
+				break;
+			case INP_RFC6056_ALG_4:	/* Double-Hash Port Selection Algorithm */
+				{
+					MD5_CTX f_ctx;
+					MD5_CTX g_ctx;
+					u_int32_t F[4] = { 0, 0, 0, 0 };
+					u_int32_t G[4] = { 0, 0, 0, 0 };
+					u_int32_t secret_f[4] = { 0, 0, 0, 0 };
+					u_int32_t secret_g[4] = { 0, 0, 0, 0 };
+					u_int16_t table[16]; 
+					u_int32_t index = 0;
+					u_int32_t offset = 0;
+
+					secret_f[0] = arc4random();
+					secret_f[1] = arc4random();
+					secret_f[2] = arc4random();
+					secret_f[3] = arc4random();
+
+					secret_g[0] = arc4random();
+					secret_g[1] = arc4random();
+					secret_g[2] = arc4random();
+					secret_g[3] = arc4random();
+
+					for (index = 0; index < sizeof(table); index++)
+						table[index] = arc4random() % 65536;
+
+					MD5Init(&f_ctx);
+					MD5Update(&f_ctx, (u_char *)&inp->inp_laddr,
+					    sizeof(inp->inp_laddr));
+					MD5Update(&f_ctx, (u_char *)&inp->inp_faddr,
+					    sizeof(inp->inp_faddr));
+					MD5Update(&f_ctx, (u_char *)&inp->inp_fport,
+					    sizeof(inp->inp_fport));
+					MD5Update(&f_ctx, (u_char *)secret_f,
+					    sizeof(secret_f));
+					MD5Final((u_char *)&F, &f_ctx);
+
+					offset = ((F[0] ^ F[1]) ^ (F[2] ^ F[3]));
+
+					MD5Init(&g_ctx);
+					MD5Update(&g_ctx, (u_char *)&inp->inp_laddr,
+					    sizeof(inp->inp_laddr));
+					MD5Update(&g_ctx, (u_char *)&inp->inp_faddr,
+					    sizeof(inp->inp_faddr));
+					MD5Update(&g_ctx, (u_char *)&inp->inp_fport,
+					    sizeof(inp->inp_fport));
+					MD5Update(&g_ctx, (u_char *)secret_g,
+					    sizeof(secret_g));
+					MD5Final((u_char *)&G, &g_ctx);
+
+					index = ((G[0] ^ G[1]) ^ (G[2] ^ G[3])) % sizeof(table);
+
+					do {
+						if (count-- < 0)	/* completely used? */
+							return (EADDRNOTAVAIL);
+
+						*lastport = first + 
+						    (offset + table[index]++) % count;
+
+						if (*lastport < first || *lastport > last)
+							*lastport = first;
+						lport = htons(*lastport);
+					} while (in_pcblookup_local(pcbinfo, laddr,
+					    lport, wild, cred));
+				}
+				break;
+			case INP_RFC6056_ALG_3:	/* Simple Hash-Based Port Selection Algorithm */
+				{
+					MD5_CTX f_ctx;
+					u_int32_t F[4] = { 0, 0, 0, 0 };
+					u_int32_t secret_f[4] = { 0, 0, 0, 0 };
+					u_int32_t offset = 0;
+
+					secret_f[0] = arc4random();
+					secret_f[1] = arc4random();
+					secret_f[2] = arc4random();
+					secret_f[3] = arc4random();
+
+					MD5Init(&f_ctx);
+					MD5Update(&f_ctx, (u_char *)&inp->inp_laddr,
+					    sizeof(inp->inp_laddr));
+					MD5Update(&f_ctx, (u_char *)&inp->inp_faddr,
+					    sizeof(inp->inp_faddr));
+					MD5Update(&f_ctx, (u_char *)&inp->inp_fport,
+					    sizeof(inp->inp_fport));
+					MD5Update(&f_ctx, (u_char *)secret_f,
+					    sizeof(secret_f));
+					MD5Final((u_char *)&F, &f_ctx);
+
+					offset = ((F[0] ^ F[1]) ^ (F[2] ^ F[3]));
+
+					do {
+						if (count-- < 0)	/* completely used? */
+							return (EADDRNOTAVAIL);
+
+						*lastport = first + ((arc4random() % 65536) + 
+						    (offset % 65536)) % count;
+
+						if (*lastport < first || *lastport > last)
+							*lastport = first;
+						lport = htons(*lastport);
+					} while (in_pcblookup_local(pcbinfo, laddr,
+					    lport, wild, cred));				
+				}
+				break;
+			case INP_RFC6056_ALG_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 INP_RFC6056_ALG_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 0d67f9c982f7 src/sys/netinet/in_pcb.h
--- a/src/sys/netinet/in_pcb.h	Mon Jan 31 11:35:24 2011 +0200
+++ b/src/sys/netinet/in_pcb.h	Mon Jan 31 14:29:52 2011 +0200
@@ -452,6 +452,15 @@
 
 #define	INP_CHECK_SOCKAF(so, af)	(INP_SOCKAF(so) == af)
 
+/*
+ * RFC6056 Port Randomization Algorithms
+ */
+#define	INP_RFC6056_ALG_1	1	/* Simple Port Randomization Algorithm I */
+#define	INP_RFC6056_ALG_2	2	/* Simple Port Randomization Algorithm II */
+#define	INP_RFC6056_ALG_3	3	/* Simple Hash-Based Port Selection Algorithm */
+#define	INP_RFC6056_ALG_4	4	/* Double-Hash Port Selection Algorithm */
+#define	INP_RFC6056_ALG_5	5	/* Random-Increments Port Selection Algorithm */
+
 #ifdef _KERNEL
 VNET_DECLARE(int, ipport_reservedhigh);
 VNET_DECLARE(int, ipport_reservedlow);
@@ -466,6 +475,8 @@
 VNET_DECLARE(int, ipport_randomtime);
 VNET_DECLARE(int, ipport_stoprandom);
 VNET_DECLARE(int, ipport_tcpallocs);
+VNET_DECLARE(u_int, ipport_randomalg_ver);
+VNET_DECLARE(u_int, ipport_randomalg_alg5_tradeoff);
 
 #define	V_ipport_reservedhigh	VNET(ipport_reservedhigh)
 #define	V_ipport_reservedlow	VNET(ipport_reservedlow)
@@ -480,6 +491,8 @@
 #define	V_ipport_randomtime	VNET(ipport_randomtime)
 #define	V_ipport_stoprandom	VNET(ipport_stoprandom)
 #define	V_ipport_tcpallocs	VNET(ipport_tcpallocs)
+#define V_ipport_randomalg_ver	VNET(ipport_randomalg_ver)
+#define V_ipport_randomalg_alg5_tradeoff	VNET(ipport_randomalg_alg5_tradeoff)
 
 extern struct callout ipport_tick_callout;
 
diff -r 0d67f9c982f7 src/sys/netinet6/in6_src.c
--- a/src/sys/netinet6/in6_src.c	Mon Jan 31 11:35:24 2011 +0200
+++ b/src/sys/netinet6/in6_src.c	Mon Jan 31 14:29:52 2011 +0200
@@ -108,6 +108,8 @@
 #include <netinet6/scope6_var.h>
 #include <netinet6/nd6.h>
 
+#include <sys/md5.h>
+
 static struct mtx addrsel_lock;
 #define	ADDRSEL_LOCK_INIT()	mtx_init(&addrsel_lock, "addrsel_lock", NULL, MTX_DEF)
 #define	ADDRSEL_LOCK()		mtx_lock(&addrsel_lock)
@@ -919,23 +921,195 @@
 		last = aux;
 	}
 
-	if (dorandom)
-		*lastport = first + (arc4random() % (last - first));
-
 	count = last - first;
 
-	do {
-		if (count-- < 0) {	/* completely used? */
-			/* Undo an address bind that may have occurred. */
-			inp->in6p_laddr = in6addr_any;
-			return (EADDRNOTAVAIL);
+	/*
+	 * According to RFC 6056 there are 5 (five) possible algorithms
+	 * for random port allocation. Usage of a particular algorithm
+	 * is specified with the 'net.inet.ip.portrange.randomalg.version'
+	 * sysctl variable. Default value is 1, which represents the
+	 * legacy random port allocation algorithm in FreeBSD.
+	 */
+	if (dorandom) {
+		switch (V_ipport_randomalg_ver) {
+		case INP_RFC6056_ALG_5:	/* Random-Increments Port Selection */
+			do {
+				if (count-- < 0) {	/* completely used? */
+					/* Undo an address bind that may have occurred. */
+					inp->in6p_laddr = in6addr_any;
+					return (EADDRNOTAVAIL);
+				}
+
+				*lastport = first + ((arc4random() % 65536) +
+				    (arc4random() % V_ipport_randomalg_alg5_tradeoff) + 1);
+
+				if (*lastport < first || *lastport > last)
+					*lastport = first;
+				lport = htons(*lastport);
+			} while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
+			    lport, wild, cred));
+			break;
+		case INP_RFC6056_ALG_4: /* Double-Hash Port Selection Algorithm */
+			{
+				MD5_CTX f_ctx;
+				MD5_CTX g_ctx;
+				u_int32_t F[4] = { 0, 0, 0, 0 };
+				u_int32_t G[4] = { 0, 0, 0, 0 };
+				u_int32_t secret_f[4] = { 0, 0, 0, 0 };
+				u_int32_t secret_g[4] = { 0, 0, 0, 0 };
+				u_int16_t table[16];
+				u_int32_t index = 0;
+				u_int32_t offset = 0;
+
+				secret_f[0] = arc4random();
+				secret_f[1] = arc4random();
+				secret_f[2] = arc4random();
+				secret_f[3] = arc4random();
+
+				secret_g[0] = arc4random();
+				secret_g[1] = arc4random();
+				secret_g[2] = arc4random();
+				secret_g[3] = arc4random();
+
+				for (index = 0; index < sizeof(table); index++)
+					table[index] = arc4random() % 65536;
+
+				MD5Init(&f_ctx);
+				MD5Update(&f_ctx, (u_char *)&inp->in6p_laddr,
+				    sizeof(inp->in6p_laddr));
+				MD5Update(&f_ctx, (u_char *)&inp->in6p_faddr,
+				    sizeof(inp->in6p_faddr));
+				MD5Update(&f_ctx, (u_char *)&inp->inp_fport,
+				    sizeof(inp->inp_fport));
+				MD5Update(&f_ctx, (u_char *)secret_f,
+				    sizeof(secret_f));
+				MD5Final((u_char *)&F, &f_ctx);
+
+				offset = ((F[0] ^ F[1]) ^ (F[2] ^ F[3]));
+
+				MD5Init(&g_ctx);
+				MD5Update(&g_ctx, (u_char *)&inp->in6p_laddr,
+				    sizeof(inp->in6p_laddr));
+				MD5Update(&g_ctx, (u_char *)&inp->in6p_faddr,
+				    sizeof(inp->in6p_faddr));
+				MD5Update(&g_ctx, (u_char *)&inp->inp_fport,
+				    sizeof(inp->inp_fport));
+				MD5Update(&g_ctx, (u_char *)secret_g,
+				    sizeof(secret_g));
+				MD5Final((u_char *)&G, &g_ctx);
+
+				index = ((G[0] ^ G[1]) ^ (G[2] ^ G[3])) % sizeof(table);
+
+				do {
+					if (count-- < 0) {	/* completely used? */
+						/* Undo an address bind that may have occurred. */
+						inp->in6p_laddr = in6addr_any;
+						return (EADDRNOTAVAIL);
+					}
+
+					*lastport = first +
+					    (offset + table[index]++) % count;
+
+					if (*lastport < first || *lastport > last)
+						*lastport = first;
+					lport = htons(*lastport);
+				} while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
+				    lport, wild, cred));
+			}
+			break;
+		case INP_RFC6056_ALG_3: /* Simple Hash-Based Port Selection Algorithm */
+			{
+				MD5_CTX f_ctx;
+				u_int32_t F[4] = { 0, 0, 0, 0 };
+				u_int32_t secret_f[4] = { 0, 0, 0, 0 };
+				u_int32_t offset = 0;
+
+				secret_f[0] = arc4random();
+				secret_f[1] = arc4random();
+				secret_f[2] = arc4random();
+				secret_f[3] = arc4random();
+
+				MD5Init(&f_ctx);
+				MD5Update(&f_ctx, (u_char *)&inp->in6p_laddr,
+				    sizeof(inp->in6p_laddr));
+				MD5Update(&f_ctx, (u_char *)&inp->in6p_faddr,
+				    sizeof(inp->in6p_faddr));
+				MD5Update(&f_ctx, (u_char *)&inp->inp_fport,
+				    sizeof(inp->inp_fport));
+				MD5Update(&f_ctx, (u_char *)secret_f,
+				    sizeof(secret_f));
+				MD5Final((u_char *)&F, &f_ctx);
+
+				offset = ((F[0] ^ F[1]) ^ (F[2] ^ F[3]));
+
+				do {
+					if (count-- < 0) {	/* completely used? */
+						/* Undo an address bind that may have occurred. */
+						inp->in6p_laddr = in6addr_any;
+						return (EADDRNOTAVAIL);
+					}
+
+					*lastport = first + ((arc4random() % 65536) +
+					    (offset % 65536)) % count;
+
+					if (*lastport < first || *lastport > last)
+						*lastport = first;
+					lport = htons(*lastport);
+				} while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
+				    lport, wild, cred));
+			}
+			break;
+		case INP_RFC6056_ALG_2:	/* Simple Port Randomization Algorithm II */
+			do {
+				if (count-- < 0) {	/* completely used? */
+					/* Undo an address bind that may have occurred. */
+					inp->in6p_laddr = in6addr_any;
+					return (EADDRNOTAVAIL);
+				}
+
+				*lastport = first + (arc4random() % (last - first));
+
+				if (*lastport < first || *lastport > last)
+					*lastport = first;
+				lport = htons(*lastport);
+			} while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
+			    lport, wild, cred));
+			break;
+		case INP_RFC6056_ALG_1:	/* Simple Port Randomization Algorithm I */
+		default:
+			*lastport = first + (arc4random() % (last - first));
+
+			do {
+				if (count-- < 0) {	/* completely used? */
+					/* Undo an address bind that may have occurred. */
+					inp->in6p_laddr = in6addr_any;
+					return (EADDRNOTAVAIL);
+				}
+
+				++*lastport;
+
+				if (*lastport < first || *lastport > last)
+					*lastport = first;
+				lport = htons(*lastport);
+			} while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
+			    lport, wild, cred));
 		}
-		++*lastport;
-		if (*lastport < first || *lastport > last)
-			*lastport = first;
-		lport = htons(*lastport);
-	} while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
-	    lport, wild, cred));
+	} else {
+		do {
+			if (count-- < 0) {	/* completely used? */
+				/* Undo an address bind that may have occurred. */
+				inp->in6p_laddr = in6addr_any;
+				return (EADDRNOTAVAIL);
+			}
+
+			++*lastport;
+
+			if (*lastport < first || *lastport > last)
+				*lastport = first;
+			lport = htons(*lastport);
+		} while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
+		    lport, wild, cred));
+	}
 
 	inp->inp_lport = lport;
 	if (in_pcbinshash(inp) != 0) {
_______________________________________________
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