summaryrefslogtreecommitdiffstats
path: root/sys/netinet/in_pcb.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/in_pcb.c')
-rw-r--r--sys/netinet/in_pcb.c56
1 files changed, 52 insertions, 4 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 11e5b0d..20a9465 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -59,6 +59,8 @@
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
#include <netinet/tcp_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
@@ -97,8 +99,13 @@ int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */
int ipport_reservedhigh = IPPORT_RESERVED - 1; /* 1023 */
int ipport_reservedlow = 0;
-/* Shall we allocate ephemeral ports in random order? */
-int ipport_randomized = 1;
+/* Variables dealing with random ephemeral port allocation. */
+int ipport_randomized = 1; /* user controlled via sysctl */
+int ipport_randomcps = 10; /* user controlled via sysctl */
+int ipport_randomtime = 45; /* user controlled via sysctl */
+int ipport_stoprandom = 0; /* toggled by ipport_tick */
+int ipport_tcpallocs;
+int ipport_tcplastcount;
#define RANGECHK(var, min, max) \
if ((var) < (min)) { (var) = (min); } \
@@ -143,6 +150,10 @@ SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, reservedlow,
CTLFLAG_RW|CTLFLAG_SECURE, &ipport_reservedlow, 0, "");
SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, randomized,
CTLFLAG_RW, &ipport_randomized, 0, "");
+SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, randomcps,
+ CTLFLAG_RW, &ipport_randomcps, 0, "");
+SYSCTL_INT(_net_inet_ip_portrange, OID_AUTO, randomtime,
+ CTLFLAG_RW, &ipport_randomtime, 0, "");
/*
* in_pcb.c: manage the Protocol Control Blocks.
@@ -266,6 +277,7 @@ in_pcbbind_setup(inp, nam, laddrp, lportp, cred)
u_short lport = 0;
int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
int error, prison = 0;
+ int dorandom;
INP_INFO_WLOCK_ASSERT(pcbinfo);
INP_LOCK_ASSERT(inp);
@@ -394,6 +406,20 @@ in_pcbbind_setup(inp, nam, laddrp, lportp, cred)
lastport = &pcbinfo->lastport;
}
/*
+ * 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 (ipport_randomized &&
+ (!ipport_stoprandom || pcbinfo == &udbinfo))
+ dorandom = 1;
+ else
+ dorandom = 0;
+ /* Make sure to not include UDP packets in the count. */
+ if (pcbinfo != &udbinfo)
+ ipport_tcpallocs++;
+ /*
* Simple check to ensure all ports are not used up causing
* a deadlock here.
*
@@ -404,7 +430,7 @@ in_pcbbind_setup(inp, nam, laddrp, lportp, cred)
/*
* counting down
*/
- if (ipport_randomized)
+ if (dorandom)
*lastport = first -
(arc4random() % (first - last));
count = first - last;
@@ -422,7 +448,7 @@ in_pcbbind_setup(inp, nam, laddrp, lportp, cred)
/*
* counting up
*/
- if (ipport_randomized)
+ if (dorandom)
*lastport = first +
(arc4random() % (last - first));
count = last - first;
@@ -1181,3 +1207,25 @@ in_pcbsosetlabel(so)
INP_UNLOCK(inp);
#endif
}
+
+/*
+ * ipport_tick runs once per second, determining if random port
+ * allocation should be continued. If more than ipport_randomcps
+ * ports have been allocated in the last second, then we return to
+ * sequential port allocation. We return to random allocation only
+ * once we drop below ipport_randomcps for at least 5 seconds.
+ */
+
+void
+ipport_tick(xtp)
+ void *xtp;
+{
+ if (ipport_tcpallocs > ipport_tcplastcount + ipport_randomcps) {
+ ipport_stoprandom = ipport_randomtime;
+ } else {
+ if (ipport_stoprandom > 0)
+ ipport_stoprandom--;
+ }
+ ipport_tcplastcount = ipport_tcpallocs;
+ callout_reset(&ipport_tick_callout, hz, ipport_tick, NULL);
+}
OpenPOWER on IntegriCloud