svn commit: r189956 - in stable/7: . sys sys/contrib/pf
sys/dev/ath/ath_hal sys/dev/cxgb sys/netinet sys/netinet6
Bjoern A. Zeeb
bz at FreeBSD.org
Wed Mar 18 04:30:48 PDT 2009
Author: bz
Date: Wed Mar 18 11:30:47 2009
New Revision: 189956
URL: http://svn.freebsd.org/changeset/base/189956
Log:
MFC r184096:
Bring over the change switching from using sequential to random
ephemeral port allocation as implemented in netinet/in_pcb.c rev. 1.143
(initially from OpenBSD) and follow-up commits during the last four and
a half years including rev. 1.157, 1.162 and 1.199.
This now is relying on the same infrastructure as has been implemented
in in_pcb.c since rev. 1.199.
Reviewed by: rwatson (UPDATING)
Modified:
stable/7/UPDATING
stable/7/sys/ (props changed)
stable/7/sys/contrib/pf/ (props changed)
stable/7/sys/dev/ath/ath_hal/ (props changed)
stable/7/sys/dev/cxgb/ (props changed)
stable/7/sys/netinet/in_pcb.h
stable/7/sys/netinet6/in6_src.c
Modified: stable/7/UPDATING
==============================================================================
--- stable/7/UPDATING Wed Mar 18 03:56:26 2009 (r189955)
+++ stable/7/UPDATING Wed Mar 18 11:30:47 2009 (r189956)
@@ -8,6 +8,13 @@ Items affecting the ports and packages s
/usr/ports/UPDATING. Please read that file before running
portupgrade.
+20090318:
+ Change IPv6 ephemeral port allocation from sequential to
+ random allocation, like IPv4 has done for more than four years.
+ The implementation shares infrastructure with IPv4. This
+ means that there is only one set of sysctls to control both
+ IPv4 and IPv6. See ip(4) man page for details.
+
20090312:
A workaround is committed to allow the creation of System V shared
memory segment of size > 2 GB on the 64-bit architectures.
Modified: stable/7/sys/netinet/in_pcb.h
==============================================================================
--- stable/7/sys/netinet/in_pcb.h Wed Mar 18 03:56:26 2009 (r189955)
+++ stable/7/sys/netinet/in_pcb.h Wed Mar 18 11:30:47 2009 (r189956)
@@ -483,6 +483,9 @@ extern int ipport_firstauto;
extern int ipport_lastauto;
extern int ipport_hifirstauto;
extern int ipport_hilastauto;
+extern int ipport_randomized;
+extern int ipport_stoprandom;
+extern int ipport_tcpallocs;
extern struct callout ipport_tick_callout;
void in_pcbpurgeif0(struct inpcbinfo *, struct ifnet *);
Modified: stable/7/sys/netinet6/in6_src.c
==============================================================================
--- stable/7/sys/netinet6/in6_src.c Wed Mar 18 03:56:26 2009 (r189955)
+++ stable/7/sys/netinet6/in6_src.c Wed Mar 18 11:30:47 2009 (r189956)
@@ -91,6 +91,9 @@ __FBSDID("$FreeBSD$");
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
#include <netinet6/in6_var.h>
#include <netinet/ip6.h>
#include <netinet6/in6_pcb.h>
@@ -774,7 +777,7 @@ in6_pcbsetport(struct in6_addr *laddr, s
{
struct socket *so = inp->inp_socket;
u_int16_t lport = 0, first, last, *lastport;
- int count, error, wild = 0;
+ int count, error, wild = 0, dorandom;
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
INP_INFO_WLOCK_ASSERT(pcbinfo);
@@ -807,56 +810,58 @@ in6_pcbsetport(struct in6_addr *laddr, s
last = ipport_lastauto;
lastport = &pcbinfo->ipi_lastport;
}
+
/*
- * Simple check to ensure all ports are not used up causing
- * a deadlock here.
- *
- * We split the two cases (up and down) so that the direction
- * is not being tested on each round of the loop.
+ * For UDP, use random port allocation as long as the user
+ * allows it. For TCP (and as of yet unknown) connections,
+ * use random port allocation only if the user allows it AND
+ * ipport_tick() allows it.
*/
- if (first > last) {
- /*
- * counting down
- */
- count = first - last;
+ if (ipport_randomized &&
+ (!ipport_stoprandom || pcbinfo == &udbinfo))
+ dorandom = 1;
+ else
+ dorandom = 0;
+ /*
+ * It makes no sense to do random port allocation if
+ * we have the only port available.
+ */
+ if (first == last)
+ dorandom = 0;
+ /* Make sure to not include UDP packets in the count. */
+ if (pcbinfo != &udbinfo)
+ ipport_tcpallocs++;
- do {
- if (count-- < 0) { /* completely used? */
- /*
- * Undo any address bind that may have
- * occurred above.
- */
- inp->in6p_laddr = in6addr_any;
- return (EAGAIN);
- }
- --*lastport;
- if (*lastport > first || *lastport < last)
- *lastport = first;
- lport = htons(*lastport);
- } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
- lport, wild, cred));
- } else {
- /*
- * counting up
- */
- count = last - first;
+ /*
+ * Instead of having two loops further down counting up or down
+ * make sure that first is always <= last and go with only one
+ * code path implementing all logic.
+ */
+ if (first > last) {
+ u_int16_t aux;
- do {
- if (count-- < 0) { /* completely used? */
- /*
- * Undo any address bind that may have
- * occurred above.
- */
- inp->in6p_laddr = in6addr_any;
- return (EAGAIN);
- }
- ++*lastport;
- if (*lastport < first || *lastport > last)
- *lastport = first;
- lport = htons(*lastport);
- } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
- lport, wild, cred));
- }
+ aux = first;
+ first = last;
+ 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);
+ }
+ ++*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) {
More information about the svn-src-stable
mailing list