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) {
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to