Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf_lb.c
Show First 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
static void pf_hash(struct pf_addr *, struct pf_addr *, | static void pf_hash(struct pf_addr *, struct pf_addr *, | ||||
struct pf_poolhashkey *, sa_family_t); | struct pf_poolhashkey *, sa_family_t); | ||||
static struct pf_krule *pf_match_translation(struct pf_pdesc *, struct mbuf *, | static struct pf_krule *pf_match_translation(struct pf_pdesc *, struct mbuf *, | ||||
int, struct pfi_kkif *, | int, struct pfi_kkif *, | ||||
struct pf_addr *, u_int16_t, struct pf_addr *, | struct pf_addr *, u_int16_t, struct pf_addr *, | ||||
uint16_t, int, struct pf_kanchor_stackframe *); | uint16_t, int, struct pf_kanchor_stackframe *); | ||||
static int pf_get_sport(sa_family_t, uint8_t, struct pf_krule *, | static int pf_get_sport(sa_family_t, uint8_t, struct pf_krule *, | ||||
struct pf_addr *, uint16_t, struct pf_addr *, uint16_t, struct pf_addr *, | struct pf_addr *, uint16_t, struct pf_addr *, uint16_t, struct pf_addr *, | ||||
uint16_t *, uint16_t, uint16_t, struct pf_ksrc_node **); | uint16_t *, uint16_t, uint16_t, struct pf_ksrc_node **, struct pf_udp_mapping **); | ||||
kp: Line length. | |||||
#define mix(a,b,c) \ | #define mix(a,b,c) \ | ||||
do { \ | do { \ | ||||
a -= b; a -= c; a ^= (c >> 13); \ | a -= b; a -= c; a ^= (c >> 13); \ | ||||
b -= c; b -= a; b ^= (a << 8); \ | b -= c; b -= a; b ^= (a << 8); \ | ||||
c -= a; c -= b; c ^= (b >> 13); \ | c -= a; c -= b; c ^= (b >> 13); \ | ||||
a -= b; a -= c; a ^= (c >> 12); \ | a -= b; a -= c; a ^= (c >> 12); \ | ||||
b -= c; b -= a; b ^= (a << 16); \ | b -= c; b -= a; b ^= (a << 16); \ | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, | ||||
return (rm); | return (rm); | ||||
} | } | ||||
static int | static int | ||||
pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r, | pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r, | ||||
struct pf_addr *saddr, uint16_t sport, struct pf_addr *daddr, | struct pf_addr *saddr, uint16_t sport, struct pf_addr *daddr, | ||||
uint16_t dport, struct pf_addr *naddr, uint16_t *nport, uint16_t low, | uint16_t dport, struct pf_addr *naddr, uint16_t *nport, uint16_t low, | ||||
uint16_t high, struct pf_ksrc_node **sn) | uint16_t high, struct pf_ksrc_node **sn, struct pf_udp_mapping **udp_mapping) | ||||
kpUnsubmitted Done Inline ActionsLine length. kp: Line length. | |||||
{ | { | ||||
struct pf_state_key_cmp key; | struct pf_state_key_cmp key; | ||||
struct pf_addr init_addr; | struct pf_addr init_addr; | ||||
struct pf_srchash *sh = NULL; | |||||
bzero(&init_addr, sizeof(init_addr)); | bzero(&init_addr, sizeof(init_addr)); | ||||
if (pf_map_addr(af, r, saddr, naddr, NULL, &init_addr, sn)) | |||||
Not Done Inline ActionsEmpty line below. glebius: Empty line below. | |||||
Done Inline ActionsI'd MPASS(*udp_mapping == NULL) here. kp: I'd MPASS(*udp_mapping == NULL) here. | |||||
MPASS(*udp_mapping == NULL); | |||||
/* | |||||
* If we are UDP and have an existing mapping we can get source port | |||||
* from the mapping. In this case we have to look up the src_node as | |||||
* pf_map_addr would. | |||||
*/ | |||||
if (proto == IPPROTO_UDP && (r->rpool.opts & PF_POOL_ENDPI)) { | |||||
struct pf_udp_endpoint_cmp udp_source; | |||||
bzero(&udp_source, sizeof(udp_source)); | |||||
udp_source.af = af; | |||||
PF_ACPY(&udp_source.addr, saddr, af); | |||||
Not Done Inline ActionsDo we not need to release the mapping when we're done with it? kp: Do we not need to release the mapping when we're done with it? | |||||
Not Done Inline ActionsThe mapping is cleaned up in pf_unlink_state, or do you mean something else I'm missing? thj: The mapping is cleaned up in pf_unlink_state, or do you mean something else I'm missing? | |||||
Not Done Inline ActionsI meant that pf_udp_mapping_find() increments the reference counter for the mapping, and I didn't see where we decrement it again. I suspect I missed that we return it to the caller, and rely on it to release the reference for us. Have you tried unloading pf after a test run? If we forget to clean things up uma ought to warn. kp: I meant that pf_udp_mapping_find() increments the reference counter for the mapping, and I… | |||||
udp_source.port = sport; | |||||
*udp_mapping = pf_udp_mapping_find(&udp_source); | |||||
if (*udp_mapping) { | |||||
PF_ACPY(naddr, &(*udp_mapping)->endpoints[1].addr, af); | |||||
*nport = (*udp_mapping)->endpoints[1].port; | |||||
/* Try to find a src_node as per pf_map_addr(). */ | |||||
if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR && | |||||
(r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) | |||||
*sn = pf_find_src_node(saddr, r, af, &sh, 0); | |||||
return (0); | |||||
} else { | |||||
kpUnsubmitted Done Inline ActionsAccidentally indented with spaces, not tabs. kp: Accidentally indented with spaces, not tabs. | |||||
*udp_mapping = pf_udp_mapping_create(af, saddr, sport, &init_addr, 0); | |||||
if (*udp_mapping == NULL) | |||||
return (1); | return (1); | ||||
} | |||||
} | |||||
if (pf_map_addr(af, r, saddr, naddr, NULL, &init_addr, sn)) | |||||
goto failed; | |||||
if (proto == IPPROTO_ICMP) { | if (proto == IPPROTO_ICMP) { | ||||
if (*nport == htons(ICMP_ECHO)) { | if (*nport == htons(ICMP_ECHO)) { | ||||
low = 1; | low = 1; | ||||
high = 65535; | high = 65535; | ||||
} else | } else | ||||
return (0); /* Don't try to modify non-echo ICMP */ | return (0); /* Don't try to modify non-echo ICMP */ | ||||
} | } | ||||
#ifdef INET6 | #ifdef INET6 | ||||
Show All 9 Lines | #endif /* INET6 */ | ||||
bzero(&key, sizeof(key)); | bzero(&key, sizeof(key)); | ||||
key.af = af; | key.af = af; | ||||
key.proto = proto; | key.proto = proto; | ||||
key.port[0] = dport; | key.port[0] = dport; | ||||
PF_ACPY(&key.addr[0], daddr, key.af); | PF_ACPY(&key.addr[0], daddr, key.af); | ||||
do { | do { | ||||
PF_ACPY(&key.addr[1], naddr, key.af); | PF_ACPY(&key.addr[1], naddr, key.af); | ||||
if (*udp_mapping) | |||||
PF_ACPY(&(*udp_mapping)->endpoints[1].addr, naddr, af); | |||||
/* | /* | ||||
* port search; start random, step; | * port search; start random, step; | ||||
* similar 2 portloop in in_pcbbind | * similar 2 portloop in in_pcbbind | ||||
*/ | */ | ||||
if (proto == IPPROTO_SCTP) { | if (proto == IPPROTO_SCTP) { | ||||
key.port[1] = sport; | key.port[1] = sport; | ||||
if (!pf_find_state_all_exists(&key, PF_IN)) { | if (!pf_find_state_all_exists(&key, PF_IN)) { | ||||
Show All 11 Lines | if (proto == IPPROTO_SCTP) { | ||||
key.port[1] = sport; | key.port[1] = sport; | ||||
if (!pf_find_state_all_exists(&key, PF_IN)) { | if (!pf_find_state_all_exists(&key, PF_IN)) { | ||||
*nport = sport; | *nport = sport; | ||||
return (0); | return (0); | ||||
} | } | ||||
} else if (low == high) { | } else if (low == high) { | ||||
key.port[1] = htons(low); | key.port[1] = htons(low); | ||||
if (!pf_find_state_all_exists(&key, PF_IN)) { | if (!pf_find_state_all_exists(&key, PF_IN)) { | ||||
if (*udp_mapping != NULL) { | |||||
(*udp_mapping)->endpoints[1].port = htons(low); | |||||
if (pf_udp_mapping_insert(*udp_mapping) == 0) { | |||||
*nport = htons(low); | *nport = htons(low); | ||||
return (0); | return (0); | ||||
} | } | ||||
} else { | } else { | ||||
*nport = htons(low); | |||||
return (0); | |||||
} | |||||
Done Inline ActionsCan we not just if (*udp_mapping != NULL) here? kp: Can we not just `if (*udp_mapping != NULL)` here? | |||||
} | |||||
} else { | |||||
uint32_t tmp; | uint32_t tmp; | ||||
uint16_t cut; | uint16_t cut; | ||||
if (low > high) { | if (low > high) { | ||||
tmp = low; | tmp = low; | ||||
low = high; | low = high; | ||||
high = tmp; | high = tmp; | ||||
} | } | ||||
/* low < high */ | /* low < high */ | ||||
cut = arc4random() % (1 + high - low) + low; | cut = arc4random() % (1 + high - low) + low; | ||||
/* low <= cut <= high */ | /* low <= cut <= high */ | ||||
for (tmp = cut; tmp <= high && tmp <= 0xffff; ++tmp) { | for (tmp = cut; tmp <= high && tmp <= 0xffff; ++tmp) { | ||||
if (*udp_mapping != NULL) { | |||||
(*udp_mapping)->endpoints[1].port = htons(tmp); | |||||
if (pf_udp_mapping_insert(*udp_mapping) == 0) { | |||||
*nport = htons(tmp); | |||||
return (0); | |||||
} | |||||
} else { | |||||
key.port[1] = htons(tmp); | key.port[1] = htons(tmp); | ||||
if (!pf_find_state_all_exists(&key, PF_IN)) { | if (!pf_find_state_all_exists(&key, PF_IN)) { | ||||
*nport = htons(tmp); | *nport = htons(tmp); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
} | |||||
tmp = cut; | tmp = cut; | ||||
for (tmp -= 1; tmp >= low && tmp <= 0xffff; --tmp) { | for (tmp -= 1; tmp >= low && tmp <= 0xffff; --tmp) { | ||||
if (proto == IPPROTO_UDP && | |||||
(r->rpool.opts & PF_POOL_ENDPI)) { | |||||
(*udp_mapping)->endpoints[1].port = htons(tmp); | |||||
if (pf_udp_mapping_insert(*udp_mapping) == 0) { | |||||
*nport = htons(tmp); | |||||
return (0); | |||||
} | |||||
} else { | |||||
key.port[1] = htons(tmp); | key.port[1] = htons(tmp); | ||||
if (!pf_find_state_all_exists(&key, PF_IN)) { | if (!pf_find_state_all_exists(&key, PF_IN)) { | ||||
*nport = htons(tmp); | *nport = htons(tmp); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | |||||
switch (r->rpool.opts & PF_POOL_TYPEMASK) { | switch (r->rpool.opts & PF_POOL_TYPEMASK) { | ||||
case PF_POOL_RANDOM: | case PF_POOL_RANDOM: | ||||
case PF_POOL_ROUNDROBIN: | case PF_POOL_ROUNDROBIN: | ||||
/* | /* | ||||
* pick a different source address since we're out | * pick a different source address since we're out | ||||
* of free port choices for the current one. | * of free port choices for the current one. | ||||
*/ | */ | ||||
if (pf_map_addr(af, r, saddr, naddr, NULL, &init_addr, sn)) | if (pf_map_addr(af, r, saddr, naddr, NULL, &init_addr, sn)) | ||||
return (1); | return (1); | ||||
break; | break; | ||||
case PF_POOL_NONE: | case PF_POOL_NONE: | ||||
case PF_POOL_SRCHASH: | case PF_POOL_SRCHASH: | ||||
case PF_POOL_BITMASK: | case PF_POOL_BITMASK: | ||||
default: | default: | ||||
return (1); | return (1); | ||||
} | } | ||||
} while (! PF_AEQ(&init_addr, naddr, af) ); | } while (! PF_AEQ(&init_addr, naddr, af) ); | ||||
failed: | |||||
if (*udp_mapping) { | |||||
Not Done Inline ActionsThat doesn't need the NULL check. ima_zfree_pcpu(..., NULL) is safe. kp: That doesn't need the NULL check. ima_zfree_pcpu(..., NULL) is safe. | |||||
uma_zfree(V_pf_udp_mapping_z, *udp_mapping); | |||||
*udp_mapping = NULL; | |||||
} | |||||
return (1); /* none available */ | return (1); /* none available */ | ||||
} | } | ||||
static int | static int | ||||
pf_get_mape_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r, | pf_get_mape_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r, | ||||
struct pf_addr *saddr, uint16_t sport, struct pf_addr *daddr, | struct pf_addr *saddr, uint16_t sport, struct pf_addr *daddr, | ||||
uint16_t dport, struct pf_addr *naddr, uint16_t *nport, | uint16_t dport, struct pf_addr *naddr, uint16_t *nport, | ||||
struct pf_ksrc_node **sn) | struct pf_ksrc_node **sn, struct pf_udp_mapping **udp_mapping) | ||||
{ | { | ||||
uint16_t psmask, low, highmask; | uint16_t psmask, low, highmask; | ||||
uint16_t i, ahigh, cut; | uint16_t i, ahigh, cut; | ||||
int ashift, psidshift; | int ashift, psidshift; | ||||
ashift = 16 - r->rpool.mape.offset; | ashift = 16 - r->rpool.mape.offset; | ||||
psidshift = ashift - r->rpool.mape.psidlen; | psidshift = ashift - r->rpool.mape.psidlen; | ||||
psmask = r->rpool.mape.psid & ((1U << r->rpool.mape.psidlen) - 1); | psmask = r->rpool.mape.psid & ((1U << r->rpool.mape.psidlen) - 1); | ||||
psmask = psmask << psidshift; | psmask = psmask << psidshift; | ||||
highmask = (1U << psidshift) - 1; | highmask = (1U << psidshift) - 1; | ||||
ahigh = (1U << r->rpool.mape.offset) - 1; | ahigh = (1U << r->rpool.mape.offset) - 1; | ||||
cut = arc4random() & ahigh; | cut = arc4random() & ahigh; | ||||
if (cut == 0) | if (cut == 0) | ||||
cut = 1; | cut = 1; | ||||
for (i = cut; i <= ahigh; i++) { | for (i = cut; i <= ahigh; i++) { | ||||
low = (i << ashift) | psmask; | low = (i << ashift) | psmask; | ||||
if (!pf_get_sport(af, proto, r, saddr, sport, daddr, dport, | if (!pf_get_sport(af, proto, r, saddr, sport, daddr, dport, | ||||
naddr, nport, low, low | highmask, sn)) | naddr, nport, low, low | highmask, sn, udp_mapping)) | ||||
return (0); | return (0); | ||||
} | } | ||||
for (i = cut - 1; i > 0; i--) { | for (i = cut - 1; i > 0; i--) { | ||||
low = (i << ashift) | psmask; | low = (i << ashift) | psmask; | ||||
if (!pf_get_sport(af, proto, r, saddr, sport, daddr, dport, | if (!pf_get_sport(af, proto, r, saddr, sport, daddr, dport, | ||||
naddr, nport, low, low | highmask, sn)) | naddr, nport, low, low | highmask, sn, udp_mapping)) | ||||
return (0); | return (0); | ||||
} | } | ||||
return (1); | return (1); | ||||
} | } | ||||
u_short | u_short | ||||
pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, | pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, | ||||
struct pf_addr *naddr, struct pfi_kkif **nkif, struct pf_addr *init_addr, | struct pf_addr *naddr, struct pfi_kkif **nkif, struct pf_addr *init_addr, | ||||
▲ Show 20 Lines • Show All 221 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
u_short | u_short | ||||
pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, | pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, | ||||
struct pfi_kkif *kif, struct pf_ksrc_node **sn, | struct pfi_kkif *kif, struct pf_ksrc_node **sn, | ||||
struct pf_state_key **skp, struct pf_state_key **nkp, | struct pf_state_key **skp, struct pf_state_key **nkp, | ||||
struct pf_addr *saddr, struct pf_addr *daddr, | struct pf_addr *saddr, struct pf_addr *daddr, | ||||
uint16_t sport, uint16_t dport, struct pf_kanchor_stackframe *anchor_stack, | uint16_t sport, uint16_t dport, struct pf_kanchor_stackframe *anchor_stack, | ||||
struct pf_krule **rp) | struct pf_krule **rp, | ||||
struct pf_udp_mapping **udp_mapping) | |||||
{ | { | ||||
struct pf_krule *r = NULL; | struct pf_krule *r = NULL; | ||||
struct pf_addr *naddr; | struct pf_addr *naddr; | ||||
uint16_t *nportp; | uint16_t *nportp; | ||||
uint16_t low, high; | uint16_t low, high; | ||||
u_short reason; | u_short reason; | ||||
PF_RULES_RASSERT(); | PF_RULES_RASSERT(); | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | if (pd->proto == IPPROTO_ICMP) { | ||||
low = 1; | low = 1; | ||||
high = 65535; | high = 65535; | ||||
} else { | } else { | ||||
low = r->rpool.proxy_port[0]; | low = r->rpool.proxy_port[0]; | ||||
high = r->rpool.proxy_port[1]; | high = r->rpool.proxy_port[1]; | ||||
} | } | ||||
if (r->rpool.mape.offset > 0) { | if (r->rpool.mape.offset > 0) { | ||||
if (pf_get_mape_sport(pd->af, pd->proto, r, saddr, | if (pf_get_mape_sport(pd->af, pd->proto, r, saddr, | ||||
sport, daddr, dport, naddr, nportp, sn)) { | sport, daddr, dport, naddr, nportp, sn, udp_mapping)) { | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: MAP-E port allocation (%u/%u/%u)" | ("pf: MAP-E port allocation (%u/%u/%u)" | ||||
" failed\n", | " failed\n", | ||||
r->rpool.mape.offset, | r->rpool.mape.offset, | ||||
r->rpool.mape.psidlen, | r->rpool.mape.psidlen, | ||||
r->rpool.mape.psid)); | r->rpool.mape.psid)); | ||||
reason = PFRES_MAPFAILED; | reason = PFRES_MAPFAILED; | ||||
goto notrans; | goto notrans; | ||||
} | } | ||||
} else if (pf_get_sport(pd->af, pd->proto, r, saddr, sport, | } else if (pf_get_sport(pd->af, pd->proto, r, saddr, sport, | ||||
daddr, dport, naddr, nportp, low, high, sn)) { | daddr, dport, naddr, nportp, low, high, sn, udp_mapping)) { | ||||
DPFPRINTF(PF_DEBUG_MISC, | DPFPRINTF(PF_DEBUG_MISC, | ||||
("pf: NAT proxy port allocation (%u-%u) failed\n", | ("pf: NAT proxy port allocation (%u-%u) failed\n", | ||||
r->rpool.proxy_port[0], r->rpool.proxy_port[1])); | r->rpool.proxy_port[0], r->rpool.proxy_port[1])); | ||||
reason = PFRES_MAPFAILED; | reason = PFRES_MAPFAILED; | ||||
goto notrans; | goto notrans; | ||||
} | } | ||||
break; | break; | ||||
case PF_BINAT: | case PF_BINAT: | ||||
▲ Show 20 Lines • Show All 177 Lines • Show Last 20 Lines |
Line length.