mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-08 17:40:31 +00:00
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: silby, rpaulo, mlaier MFC after: 2 months
This commit is contained in:
parent
5ce33ccf10
commit
dc3c09c89f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=184096
|
@ -449,6 +449,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 *);
|
||||
|
|
|
@ -95,6 +95,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, struct inpcb *inp, struct ucred *cred)
|
|||
INIT_VNET_INET(curvnet);
|
||||
struct socket *so = inp->inp_socket;
|
||||
u_int16_t lport = 0, first, last, *lastport;
|
||||
int count, error = 0, wild = 0;
|
||||
int count, error = 0, wild = 0, dorandom;
|
||||
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(pcbinfo);
|
||||
|
@ -802,57 +805,59 @@ in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct ucred *cred)
|
|||
last = V_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 (V_ipport_randomized &&
|
||||
(!V_ipport_stoprandom || pcbinfo == &V_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 != &V_udbinfo)
|
||||
V_ipport_tcpallocs++;
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
/*
|
||||
* counting down
|
||||
*/
|
||||
count = 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));
|
||||
} else {
|
||||
/*
|
||||
* counting up
|
||||
*/
|
||||
count = last - first;
|
||||
|
||||
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) {
|
||||
inp->in6p_laddr = in6addr_any;
|
||||
|
|
Loading…
Reference in a new issue