Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf_lb.c
Show First 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
#define V_pf_rdr_srcport_rewrite_tries VNET(pf_rdr_srcport_rewrite_tries) | #define V_pf_rdr_srcport_rewrite_tries VNET(pf_rdr_srcport_rewrite_tries) | ||||
VNET_DEFINE_STATIC(int, pf_rdr_srcport_rewrite_tries) = 16; | VNET_DEFINE_STATIC(int, pf_rdr_srcport_rewrite_tries) = 16; | ||||
#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x | #define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x | ||||
static uint64_t pf_hash(struct pf_addr *, struct pf_addr *, | static uint64_t 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 pf_krule *pf_match_translation(struct pf_pdesc *, | ||||
int, struct pf_kanchor_stackframe *); | int, struct pf_kanchor_stackframe *); | ||||
static int pf_get_sport(struct pf_pdesc *, struct pf_krule *, | static int pf_get_sport(struct pf_pdesc *, struct pf_krule *, | ||||
struct pf_addr *, uint16_t *, uint16_t, uint16_t, | struct pf_addr *, uint16_t *, uint16_t, uint16_t, | ||||
struct pf_ksrc_node **, struct pf_srchash **, | struct pf_ksrc_node **, struct pf_srchash **, | ||||
struct pf_kpool *, struct pf_udp_mapping **, | struct pf_kpool *, struct pf_udp_mapping **, | ||||
pf_sn_types_t); | pf_sn_types_t); | ||||
static bool pf_islinklocal(const sa_family_t, const struct pf_addr *); | static bool pf_islinklocal(const sa_family_t, const struct pf_addr *); | ||||
Show All 36 Lines | case AF_INET6: | ||||
break; | break; | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
default: | default: | ||||
unhandled_af(af); | unhandled_af(af); | ||||
} | } | ||||
return (res); | return (res); | ||||
} | } | ||||
static struct pf_krule * | struct pf_krule * | ||||
pf_match_translation(struct pf_pdesc *pd, | pf_match_translation(struct pf_pdesc *pd, | ||||
int rs_num, struct pf_kanchor_stackframe *anchor_stack) | int rs_num, struct pf_kanchor_stackframe *anchor_stack) | ||||
{ | { | ||||
struct pf_krule *r, *rm = NULL; | struct pf_krule *r, *rm = NULL; | ||||
struct pf_kruleset *ruleset = NULL; | struct pf_kruleset *ruleset = NULL; | ||||
int tag = -1; | int tag = -1; | ||||
int rtableid = -1; | int rtableid = -1; | ||||
int asd = 0; | int asd = 0; | ||||
▲ Show 20 Lines • Show All 283 Lines • ▼ Show 20 Lines | if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&addr->v6)) | ||||
return (true); | return (true); | ||||
return (false); | return (false); | ||||
} | } | ||||
static int | static int | ||||
pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r, | pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r, | ||||
struct pf_addr *naddr, uint16_t *nport, | struct pf_addr *naddr, uint16_t *nport, | ||||
struct pf_ksrc_node **sn, struct pf_srchash **sh, | struct pf_ksrc_node **sn, struct pf_srchash **sh, | ||||
struct pf_udp_mapping **udp_mapping) | struct pf_udp_mapping **udp_mapping, struct pf_kpool *rpool) | ||||
{ | { | ||||
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->rdr.mape.offset; | ashift = 16 - rpool->mape.offset; | ||||
psidshift = ashift - r->rdr.mape.psidlen; | psidshift = ashift - rpool->mape.psidlen; | ||||
psmask = r->rdr.mape.psid & ((1U << r->rdr.mape.psidlen) - 1); | psmask = rpool->mape.psid & ((1U << rpool->mape.psidlen) - 1); | ||||
psmask = psmask << psidshift; | psmask = psmask << psidshift; | ||||
highmask = (1U << psidshift) - 1; | highmask = (1U << psidshift) - 1; | ||||
ahigh = (1U << r->rdr.mape.offset) - 1; | ahigh = (1U << 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(pd, r, | if (!pf_get_sport(pd, r, | ||||
naddr, nport, low, low | highmask, sn, sh, &r->rdr, | naddr, nport, low, low | highmask, sn, sh, rpool, | ||||
udp_mapping, PF_SN_NAT)) | udp_mapping, PF_SN_NAT)) | ||||
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(pd, r, | if (!pf_get_sport(pd, r, | ||||
naddr, nport, low, low | highmask, sn, sh, &r->rdr, | naddr, nport, low, low | highmask, sn, sh, rpool, | ||||
udp_mapping, PF_SN_NAT)) | udp_mapping, PF_SN_NAT)) | ||||
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, | ||||
▲ Show 20 Lines • Show All 304 Lines • ▼ Show 20 Lines | |||||
u_short | u_short | ||||
pf_get_translation(struct pf_pdesc *pd, int off, | pf_get_translation(struct pf_pdesc *pd, int off, | ||||
struct pf_state_key **skp, struct pf_state_key **nkp, | struct pf_state_key **skp, struct pf_state_key **nkp, | ||||
struct pf_kanchor_stackframe *anchor_stack, struct pf_krule **rp, | struct pf_kanchor_stackframe *anchor_stack, struct pf_krule **rp, | ||||
struct pf_udp_mapping **udp_mapping) | struct pf_udp_mapping **udp_mapping) | ||||
{ | { | ||||
struct pf_krule *r = NULL; | struct pf_krule *r = NULL; | ||||
struct pf_addr *naddr; | u_short transerror; | ||||
struct pf_ksrc_node *sn = NULL; | |||||
struct pf_srchash *sh = NULL; | |||||
uint16_t *nportp; | |||||
uint16_t low, high; | |||||
u_short reason; | |||||
PF_RULES_RASSERT(); | PF_RULES_RASSERT(); | ||||
KASSERT(*skp == NULL, ("*skp not NULL")); | KASSERT(*skp == NULL, ("*skp not NULL")); | ||||
KASSERT(*nkp == NULL, ("*nkp not NULL")); | KASSERT(*nkp == NULL, ("*nkp not NULL")); | ||||
*rp = NULL; | *rp = NULL; | ||||
if (pd->dir == PF_OUT) { | if (pd->dir == PF_OUT) { | ||||
Show All 11 Lines | pf_get_translation(struct pf_pdesc *pd, int off, | ||||
switch (r->action) { | switch (r->action) { | ||||
case PF_NONAT: | case PF_NONAT: | ||||
case PF_NOBINAT: | case PF_NOBINAT: | ||||
case PF_NORDR: | case PF_NORDR: | ||||
return (PFRES_MAX); | return (PFRES_MAX); | ||||
} | } | ||||
transerror = pf_get_transaddr(pd, skp, nkp, r, udp_mapping, r->action, &(r->rdr)); | |||||
if (transerror == PFRES_MATCH) | |||||
*rp = r; | |||||
return (transerror); | |||||
} | |||||
u_short | |||||
pf_get_transaddr(struct pf_pdesc *pd, struct pf_state_key **skp, | |||||
struct pf_state_key **nkp, struct pf_krule *r, | |||||
struct pf_udp_mapping **udp_mapping, uint8_t nat_action, | |||||
kp: uint8_t in new code. | |||||
struct pf_kpool *rpool) | |||||
{ | |||||
struct pf_addr *naddr; | |||||
struct pf_ksrc_node *sn = NULL; | |||||
struct pf_srchash *sh = NULL; | |||||
uint16_t *nportp; | |||||
uint16_t low, high; | |||||
u_short reason; | |||||
PF_RULES_RASSERT(); | |||||
KASSERT(r != NULL, ("r is NULL")); | |||||
KASSERT(!(r->rule_flag & PFRULE_AFTO), ("AFTO rule")); | |||||
if (*skp == NULL && *nkp == NULL) { | |||||
if (pf_state_key_setup(pd, pd->nsport, pd->ndport, skp, nkp)) | if (pf_state_key_setup(pd, pd->nsport, pd->ndport, skp, nkp)) | ||||
return (PFRES_MEMORY); | return (PFRES_MEMORY); | ||||
} | |||||
naddr = &(*nkp)->addr[1]; | naddr = &(*nkp)->addr[1]; | ||||
nportp = &(*nkp)->port[1]; | nportp = &(*nkp)->port[1]; | ||||
switch (r->action) { | switch (nat_action) { | ||||
case PF_NAT: | case PF_NAT: | ||||
if (pd->proto == IPPROTO_ICMP) { | if (pd->proto == IPPROTO_ICMP) { | ||||
low = 1; | low = 1; | ||||
high = 65535; | high = 65535; | ||||
} else { | } else { | ||||
low = r->rdr.proxy_port[0]; | low = rpool->proxy_port[0]; | ||||
high = r->rdr.proxy_port[1]; | high = rpool->proxy_port[1]; | ||||
} | } | ||||
if (r->rdr.mape.offset > 0) { | if (rpool->mape.offset > 0) { | ||||
if (pf_get_mape_sport(pd, r, naddr, nportp, &sn, | if (pf_get_mape_sport(pd, r, naddr, nportp, &sn, | ||||
&sh, udp_mapping)) { | &sh, udp_mapping, rpool)) { | ||||
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->rdr.mape.offset, | rpool->mape.offset, | ||||
r->rdr.mape.psidlen, | rpool->mape.psidlen, | ||||
r->rdr.mape.psid)); | rpool->mape.psid)); | ||||
reason = PFRES_MAPFAILED; | reason = PFRES_MAPFAILED; | ||||
goto notrans; | goto notrans; | ||||
} | } | ||||
} else if (pf_get_sport(pd, r, naddr, nportp, low, high, &sn, | } else if (pf_get_sport(pd, r, naddr, nportp, low, high, &sn, | ||||
&sh, &r->rdr, udp_mapping, PF_SN_NAT)) { | &sh, rpool, udp_mapping, PF_SN_NAT)) { | ||||
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->rdr.proxy_port[0], r->rdr.proxy_port[1])); | rpool->proxy_port[0], rpool->proxy_port[1])); | ||||
reason = PFRES_MAPFAILED; | reason = PFRES_MAPFAILED; | ||||
goto notrans; | goto notrans; | ||||
} | } | ||||
break; | break; | ||||
case PF_BINAT: | case PF_BINAT: | ||||
switch (pd->dir) { | switch (pd->dir) { | ||||
case PF_OUT: | case PF_OUT: | ||||
if (r->rdr.cur->addr.type == PF_ADDR_DYNIFTL){ | if (rpool->cur->addr.type == PF_ADDR_DYNIFTL){ | ||||
switch (pd->af) { | switch (pd->af) { | ||||
#ifdef INET | #ifdef INET | ||||
case AF_INET: | case AF_INET: | ||||
if (r->rdr.cur->addr.p.dyn-> | if (rpool->cur->addr.p.dyn-> | ||||
pfid_acnt4 < 1) { | pfid_acnt4 < 1) { | ||||
reason = PFRES_MAPFAILED; | reason = PFRES_MAPFAILED; | ||||
goto notrans; | goto notrans; | ||||
} | } | ||||
PF_POOLMASK(naddr, | PF_POOLMASK(naddr, | ||||
&r->rdr.cur->addr.p.dyn-> | &rpool->cur->addr.p.dyn->pfid_addr4, | ||||
pfid_addr4, | &rpool->cur->addr.p.dyn->pfid_mask4, | ||||
&r->rdr.cur->addr.p.dyn-> | &pd->nsaddr, AF_INET); | ||||
pfid_mask4, &pd->nsaddr, AF_INET); | |||||
break; | break; | ||||
#endif /* INET */ | #endif /* INET */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
case AF_INET6: | case AF_INET6: | ||||
if (r->rdr.cur->addr.p.dyn-> | if (rpool->cur->addr.p.dyn-> | ||||
pfid_acnt6 < 1) { | pfid_acnt6 < 1) { | ||||
reason = PFRES_MAPFAILED; | reason = PFRES_MAPFAILED; | ||||
goto notrans; | goto notrans; | ||||
} | } | ||||
PF_POOLMASK(naddr, | PF_POOLMASK(naddr, | ||||
&r->rdr.cur->addr.p.dyn-> | &rpool->cur->addr.p.dyn->pfid_addr6, | ||||
pfid_addr6, | &rpool->cur->addr.p.dyn->pfid_mask6, | ||||
&r->rdr.cur->addr.p.dyn-> | &pd->nsaddr, AF_INET6); | ||||
pfid_mask6, &pd->nsaddr, AF_INET6); | |||||
break; | break; | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
} | } | ||||
} else | } else | ||||
PF_POOLMASK(naddr, | PF_POOLMASK(naddr, | ||||
&r->rdr.cur->addr.v.a.addr, | &rpool->cur->addr.v.a.addr, | ||||
&r->rdr.cur->addr.v.a.mask, &pd->nsaddr, | &rpool->cur->addr.v.a.mask, &pd->nsaddr, | ||||
pd->af); | pd->af); | ||||
break; | break; | ||||
case PF_IN: | case PF_IN: | ||||
if (r->src.addr.type == PF_ADDR_DYNIFTL) { | if (r->src.addr.type == PF_ADDR_DYNIFTL) { | ||||
switch (pd->af) { | switch (pd->af) { | ||||
#ifdef INET | #ifdef INET | ||||
case AF_INET: | case AF_INET: | ||||
if (r->src.addr.p.dyn->pfid_acnt4 < 1) { | if (r->src.addr.p.dyn->pfid_acnt4 < 1) { | ||||
Show All 26 Lines | #endif /* INET6 */ | ||||
} | } | ||||
break; | break; | ||||
case PF_RDR: { | case PF_RDR: { | ||||
struct pf_state_key_cmp key; | struct pf_state_key_cmp key; | ||||
int tries; | int tries; | ||||
uint16_t cut, low, high, nport; | uint16_t cut, low, high, nport; | ||||
reason = pf_map_addr_sn(pd->af, r, &pd->nsaddr, naddr, NULL, | reason = pf_map_addr_sn(pd->af, r, &pd->nsaddr, naddr, NULL, | ||||
NULL, &sn, &sh, &r->rdr, PF_SN_NAT); | NULL, &sn, &sh, rpool, PF_SN_NAT); | ||||
if (reason != 0) | if (reason != 0) | ||||
goto notrans; | goto notrans; | ||||
if ((r->rdr.opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK) | if ((rpool->opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK) | ||||
PF_POOLMASK(naddr, naddr, &r->rdr.cur->addr.v.a.mask, | PF_POOLMASK(naddr, naddr, &rpool->cur->addr.v.a.mask, | ||||
&pd->ndaddr, pd->af); | &pd->ndaddr, pd->af); | ||||
/* Do not change SCTP ports. */ | /* Do not change SCTP ports. */ | ||||
if (pd->proto == IPPROTO_SCTP) | if (pd->proto == IPPROTO_SCTP) | ||||
break; | break; | ||||
if (r->rdr.proxy_port[1]) { | if (rpool->proxy_port[1]) { | ||||
uint32_t tmp_nport; | uint32_t tmp_nport; | ||||
tmp_nport = ((ntohs(pd->ndport) - ntohs(r->dst.port[0])) % | tmp_nport = ((ntohs(pd->ndport) - ntohs(r->dst.port[0])) % | ||||
(r->rdr.proxy_port[1] - r->rdr.proxy_port[0] + | (rpool->proxy_port[1] - rpool->proxy_port[0] + | ||||
1)) + r->rdr.proxy_port[0]; | 1)) + rpool->proxy_port[0]; | ||||
/* Wrap around if necessary. */ | /* Wrap around if necessary. */ | ||||
if (tmp_nport > 65535) | if (tmp_nport > 65535) | ||||
tmp_nport -= 65535; | tmp_nport -= 65535; | ||||
nport = htons((uint16_t)tmp_nport); | nport = htons((uint16_t)tmp_nport); | ||||
} else if (r->rdr.proxy_port[0]) | } else if (rpool->proxy_port[0]) | ||||
nport = htons(r->rdr.proxy_port[0]); | nport = htons(rpool->proxy_port[0]); | ||||
else | else | ||||
nport = pd->ndport; | nport = pd->ndport; | ||||
/* | /* | ||||
* Update the destination port. | * Update the destination port. | ||||
*/ | */ | ||||
*nportp = nport; | *nportp = nport; | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | out: | ||||
break; | break; | ||||
} | } | ||||
default: | default: | ||||
panic("%s: unknown action %u", __func__, r->action); | panic("%s: unknown action %u", __func__, r->action); | ||||
} | } | ||||
/* Return success only if translation really happened. */ | /* Return success only if translation really happened. */ | ||||
if (bcmp(*skp, *nkp, sizeof(struct pf_state_key_cmp))) { | if (bcmp(*skp, *nkp, sizeof(struct pf_state_key_cmp))) { | ||||
*rp = r; | |||||
return (PFRES_MATCH); | return (PFRES_MATCH); | ||||
} | } | ||||
reason = PFRES_MAX; | reason = PFRES_MAX; | ||||
notrans: | notrans: | ||||
uma_zfree(V_pf_state_key_z, *nkp); | uma_zfree(V_pf_state_key_z, *nkp); | ||||
uma_zfree(V_pf_state_key_z, *skp); | uma_zfree(V_pf_state_key_z, *skp); | ||||
*skp = *nkp = NULL; | *skp = *nkp = NULL; | ||||
▲ Show 20 Lines • Show All 118 Lines • Show Last 20 Lines |
uint8_t in new code.