mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-25 07:49:18 +00:00
in_pcb: use jenkins hash over the entire IPv6 (or IPv4) address
The intent is to provide more entropy than can be provided by just the 32-bits of the IPv6 address which overlaps with 6to4 tunnels. This is needed to mitigate potential algorithmic complexity attacks from attackers who can control large numbers of IPv6 addresses. Together with: gallatin Reviewed by: dwmalone, rscheff Differential revision: https://reviews.freebsd.org/D33254
This commit is contained in:
parent
eb8dcdeac2
commit
a057769205
@ -49,7 +49,9 @@ __FBSDID("$FreeBSD$");
|
||||
#include "opt_rss.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/hash.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/libkern.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
@ -246,6 +248,16 @@ SYSCTL_COUNTER_U64(_net_inet_ip_rl, OID_AUTO, chgrl, CTLFLAG_RD,
|
||||
|
||||
#endif /* INET */
|
||||
|
||||
VNET_DEFINE(uint32_t, in_pcbhashseed);
|
||||
static void
|
||||
in_pcbhashseed_init(void)
|
||||
{
|
||||
|
||||
V_in_pcbhashseed = arc4random();
|
||||
}
|
||||
VNET_SYSINIT(in_pcbhashseed_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST,
|
||||
in_pcbhashseed_init, 0);
|
||||
|
||||
/*
|
||||
* in_pcb.c: manage the Protocol Control Blocks.
|
||||
*
|
||||
@ -2085,8 +2097,8 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr,
|
||||
* Look for an unconnected (wildcard foreign addr) PCB that
|
||||
* matches the local address and port we're looking for.
|
||||
*/
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport,
|
||||
0, pcbinfo->ipi_hashmask)];
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH_WILD(lport,
|
||||
pcbinfo->ipi_hashmask)];
|
||||
CK_LIST_FOREACH(inp, head, inp_hash) {
|
||||
#ifdef INET6
|
||||
/* XXX inp locking */
|
||||
@ -2214,7 +2226,7 @@ in_pcblookup_lbgroup(const struct inpcbinfo *pcbinfo,
|
||||
if (grp->il_lport != lport)
|
||||
continue;
|
||||
|
||||
idx = INP_PCBLBGROUP_PKTHASH(faddr->s_addr, lport, fport) %
|
||||
idx = INP_PCBLBGROUP_PKTHASH(faddr, lport, fport) %
|
||||
grp->il_inpcnt;
|
||||
if (grp->il_laddr.s_addr == laddr->s_addr) {
|
||||
if (numa_domain == M_NODOM ||
|
||||
@ -2260,7 +2272,7 @@ in_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in_addr faddr,
|
||||
* First look for an exact match.
|
||||
*/
|
||||
tmpinp = NULL;
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport,
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(&faddr, lport, fport,
|
||||
pcbinfo->ipi_hashmask)];
|
||||
CK_LIST_FOREACH(inp, head, inp_hash) {
|
||||
#ifdef INET6
|
||||
@ -2315,8 +2327,8 @@ in_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in_addr faddr,
|
||||
* 4. non-jailed, wild.
|
||||
*/
|
||||
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport,
|
||||
0, pcbinfo->ipi_hashmask)];
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH_WILD(lport,
|
||||
pcbinfo->ipi_hashmask)];
|
||||
CK_LIST_FOREACH(inp, head, inp_hash) {
|
||||
#ifdef INET6
|
||||
/* XXX inp locking */
|
||||
@ -2439,7 +2451,6 @@ in_pcbinshash(struct inpcb *inp)
|
||||
struct inpcbporthead *pcbporthash;
|
||||
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
|
||||
struct inpcbport *phd;
|
||||
u_int32_t hashkey_faddr;
|
||||
int so_options;
|
||||
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
@ -2450,13 +2461,12 @@ in_pcbinshash(struct inpcb *inp)
|
||||
|
||||
#ifdef INET6
|
||||
if (inp->inp_vflag & INP_IPV6)
|
||||
hashkey_faddr = INP6_PCBHASHKEY(&inp->in6p_faddr);
|
||||
pcbhash = &pcbinfo->ipi_hashbase[INP6_PCBHASH(&inp->in6p_faddr,
|
||||
inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
|
||||
else
|
||||
#endif
|
||||
hashkey_faddr = inp->inp_faddr.s_addr;
|
||||
|
||||
pcbhash = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr,
|
||||
inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
|
||||
pcbhash = &pcbinfo->ipi_hashbase[INP_PCBHASH(&inp->inp_faddr,
|
||||
inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
|
||||
|
||||
pcbporthash = &pcbinfo->ipi_porthashbase[
|
||||
INP_PCBPORTHASH(inp->inp_lport, pcbinfo->ipi_porthashmask)];
|
||||
@ -2516,7 +2526,6 @@ in_pcbrehash(struct inpcb *inp)
|
||||
{
|
||||
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
|
||||
struct inpcbhead *head;
|
||||
u_int32_t hashkey_faddr;
|
||||
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(pcbinfo);
|
||||
@ -2526,13 +2535,12 @@ in_pcbrehash(struct inpcb *inp)
|
||||
|
||||
#ifdef INET6
|
||||
if (inp->inp_vflag & INP_IPV6)
|
||||
hashkey_faddr = INP6_PCBHASHKEY(&inp->in6p_faddr);
|
||||
head = &pcbinfo->ipi_hashbase[INP6_PCBHASH(&inp->in6p_faddr,
|
||||
inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
|
||||
else
|
||||
#endif
|
||||
hashkey_faddr = inp->inp_faddr.s_addr;
|
||||
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr,
|
||||
inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(&inp->inp_faddr,
|
||||
inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
|
||||
|
||||
CK_LIST_REMOVE(inp, inp_hash);
|
||||
CK_LIST_INSERT_HEAD(head, inp, inp_hash);
|
||||
|
@ -73,7 +73,8 @@ typedef uint64_t inp_gen_t;
|
||||
/*
|
||||
* PCB with AF_INET6 null bind'ed laddr can receive AF_INET input packet.
|
||||
* So, AF_INET6 null laddr is also used as AF_INET null laddr, by utilizing
|
||||
* the following structure.
|
||||
* the following structure. This requires padding always be zeroed out,
|
||||
* which is done right after inpcb allocation and stays through its lifetime.
|
||||
*/
|
||||
struct in_addr_4in6 {
|
||||
u_int32_t ia46_pad32[3];
|
||||
@ -530,13 +531,36 @@ int inp_so_options(const struct inpcb *inp);
|
||||
#define INP_HASH_WLOCK_ASSERT(ipi) mtx_assert(&(ipi)->ipi_hash_lock, \
|
||||
MA_OWNED)
|
||||
|
||||
#define INP_PCBHASH(faddr, lport, fport, mask) \
|
||||
(((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport))) & (mask))
|
||||
#define INP_PCBPORTHASH(lport, mask) \
|
||||
(ntohs((lport)) & (mask))
|
||||
#define INP_PCBLBGROUP_PKTHASH(faddr, lport, fport) \
|
||||
((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport)))
|
||||
#define INP6_PCBHASHKEY(faddr) ((faddr)->s6_addr32[3])
|
||||
/*
|
||||
* Wildcard matching hash is not just a microoptimisation! The hash for
|
||||
* wildcard IPv4 and wildcard IPv6 must be the same, otherwise AF_INET6
|
||||
* wildcard bound pcb won't be able to receive AF_INET connections, while:
|
||||
* jenkins_hash(&zeroes, 1, s) != jenkins_hash(&zeroes, 4, s)
|
||||
* See also comment above struct in_addr_4in6.
|
||||
*/
|
||||
#define IN_ADDR_JHASH32(addr) \
|
||||
((addr)->s_addr == INADDR_ANY ? V_in_pcbhashseed : \
|
||||
jenkins_hash32((&(addr)->s_addr), 1, V_in_pcbhashseed))
|
||||
#define IN6_ADDR_JHASH32(addr) \
|
||||
(memcmp((addr), &in6addr_any, sizeof(in6addr_any)) == 0 ? \
|
||||
V_in_pcbhashseed : \
|
||||
jenkins_hash32((addr)->__u6_addr.__u6_addr32, \
|
||||
nitems((addr)->__u6_addr.__u6_addr32), V_in_pcbhashseed))
|
||||
|
||||
#define INP_PCBHASH(faddr, lport, fport, mask) \
|
||||
((IN_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport))) & (mask))
|
||||
#define INP6_PCBHASH(faddr, lport, fport, mask) \
|
||||
((IN6_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport))) & (mask))
|
||||
|
||||
#define INP_PCBHASH_WILD(lport, mask) \
|
||||
((V_in_pcbhashseed ^ ntohs(lport)) & (mask))
|
||||
|
||||
#define INP_PCBLBGROUP_PKTHASH(faddr, lport, fport) \
|
||||
(IN_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport)))
|
||||
#define INP6_PCBLBGROUP_PKTHASH(faddr, lport, fport) \
|
||||
(IN6_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport)))
|
||||
|
||||
#define INP_PCBPORTHASH(lport, mask) (ntohs((lport)) & (mask))
|
||||
|
||||
/*
|
||||
* Flags for inp_vflags -- historically version flags only
|
||||
|
@ -44,6 +44,9 @@
|
||||
* Definitions shared between netinet/in_pcb.c and netinet6/in6_pcb.c
|
||||
*/
|
||||
|
||||
VNET_DECLARE(uint32_t, in_pcbhashseed);
|
||||
#define V_in_pcbhashseed VNET(in_pcbhashseed)
|
||||
|
||||
bool inp_smr_lock(struct inpcb *, const inp_lookup_t);
|
||||
int in_pcb_lport(struct inpcb *, struct in_addr *, u_short *,
|
||||
struct ucred *, int);
|
||||
|
@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include "opt_route.h"
|
||||
#include "opt_rss.h"
|
||||
|
||||
#include <sys/hash.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
@ -787,8 +788,7 @@ in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr,
|
||||
* Look for an unconnected (wildcard foreign addr) PCB that
|
||||
* matches the local address and port we're looking for.
|
||||
*/
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(
|
||||
INP6_PCBHASHKEY(&in6addr_any), lport, 0,
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH_WILD(lport,
|
||||
pcbinfo->ipi_hashmask)];
|
||||
CK_LIST_FOREACH(inp, head, inp_hash) {
|
||||
/* XXX inp locking */
|
||||
@ -972,8 +972,8 @@ in6_pcblookup_lbgroup(const struct inpcbinfo *pcbinfo,
|
||||
if (grp->il_lport != lport)
|
||||
continue;
|
||||
|
||||
idx = INP_PCBLBGROUP_PKTHASH(INP6_PCBHASHKEY(faddr), lport,
|
||||
fport) % grp->il_inpcnt;
|
||||
idx = INP6_PCBLBGROUP_PKTHASH(faddr, lport, fport) %
|
||||
grp->il_inpcnt;
|
||||
if (IN6_ARE_ADDR_EQUAL(&grp->il6_laddr, laddr)) {
|
||||
if (numa_domain == M_NODOM ||
|
||||
grp->il_numa_domain == numa_domain) {
|
||||
@ -1015,8 +1015,8 @@ in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
|
||||
* First look for an exact match.
|
||||
*/
|
||||
tmpinp = NULL;
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(
|
||||
INP6_PCBHASHKEY(faddr), lport, fport, pcbinfo->ipi_hashmask)];
|
||||
head = &pcbinfo->ipi_hashbase[INP6_PCBHASH(faddr, lport, fport,
|
||||
pcbinfo->ipi_hashmask)];
|
||||
CK_LIST_FOREACH(inp, head, inp_hash) {
|
||||
/* XXX inp locking */
|
||||
if ((inp->inp_vflag & INP_IPV6) == 0)
|
||||
@ -1064,8 +1064,7 @@ in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
|
||||
* 3. non-jailed, non-wild.
|
||||
* 4. non-jailed, wild.
|
||||
*/
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(
|
||||
INP6_PCBHASHKEY(&in6addr_any), lport, 0,
|
||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH_WILD(lport,
|
||||
pcbinfo->ipi_hashmask)];
|
||||
CK_LIST_FOREACH(inp, head, inp_hash) {
|
||||
/* XXX inp locking */
|
||||
|
Loading…
Reference in New Issue
Block a user