diff options
Diffstat (limited to 'sys/netpfil/pf/pf_lb.c')
| -rw-r--r-- | sys/netpfil/pf/pf_lb.c | 117 |
1 files changed, 113 insertions, 4 deletions
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c index 5d85e16f18e3..7aeb8266ca8c 100644 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -535,6 +535,63 @@ pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r, return (1); } +static __inline u_short +pf_check_src_node_valid(struct pf_ksrc_node *sn, struct pf_kpool *rpool) +{ + struct pf_addr *raddr, *rmask; + struct pf_addr *caddr; /* cached redirection address */ + struct pf_kpooladdr *pa; + sa_family_t raf; + sa_family_t caf; /* cached redirection AF */ + u_short valid = 0; + + KASSERT(sn != NULL, ("sn is NULL")); + KASSERT(rpool != NULL, ("rpool is NULL")); + + /* check if the cached entry is still valid */ + + if (sn->type == PF_SN_LIMIT) { + /* Always valid as it does not store redirection address */ + return (1); + } + + mtx_lock(&rpool->mtx); + caddr = &(sn->raddr); + caf = sn->raf; + + TAILQ_FOREACH(pa, &rpool->list, entries) { + if (PF_AZERO(caddr, caf)) { + valid = 1; + goto done; + } else if (pa->addr.type == PF_ADDR_DYNIFTL) { + if (pfr_kentry_byaddr(pa->addr.p.dyn->pfid_kt, caddr, caf, 0)) { + valid = 1; + goto done; + } + } else if (pa->addr.type == PF_ADDR_TABLE) { + if (pfr_kentry_byaddr(pa->addr.p.tbl, caddr, caf, 0)) { + valid = 1; + goto done; + } + } else if (pa->addr.type != PF_ADDR_NOROUTE) { + /* PF_ADDR_URPFFAILED, PF_ADDR_RANGE, PF_ADDR_ADDRMASK */ + raddr = &(pa->addr.v.a.addr); + rmask = &(pa->addr.v.a.mask); + raf = pa->af; + if (raf == caf && pf_match_addr(0, raddr, rmask, caddr, caf)) { + valid = 1; + goto done; + } + } + /* else PF_ADDR_NOROUTE */ + } + +done: + mtx_unlock(&rpool->mtx); + + return (valid); +} + u_short pf_map_addr(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr, struct pf_addr *naddr, struct pfi_kkif **nkif, sa_family_t *naf, @@ -874,6 +931,45 @@ pf_map_addr_sn(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr, if (sn != NULL) { PF_SRC_NODE_LOCK_ASSERT(sn); + /* + * Check if source node's redirection address still exists + * in pool from which the SN was created. If not, delete it. + * Similar to pf_kill_srcnodes(). Unlink the source node + * from tree, unlink it from states, then free it. Do not + * overlap source node and state locks to avoid LOR. + */ + if (!pf_check_src_node_valid(sn, rpool)) { + pf_unlink_src_node(sn); + PF_SRC_NODE_UNLOCK(sn); + if (V_pf_status.debug >= PF_DEBUG_NOISY) { + printf("%s: stale src tracking (%d) ", + __func__, sn_type); + pf_print_host(saddr, 0, saf); + printf(" to "); + pf_print_host(&(sn->raddr), 0, sn->raf); + if (nkif) + printf("@%s", sn->rkif->pfik_name); + printf("\n"); + } + + for (int i = 0; i <= V_pf_hashmask; i++) { + struct pf_idhash *ih = &V_pf_idhash[i]; + struct pf_kstate *st; + + PF_HASHROW_LOCK(ih); + LIST_FOREACH(st, &ih->states, entry) { + if (st->sns[sn->type] == sn) { + st->sns[sn->type] = NULL; + } + } + PF_HASHROW_UNLOCK(ih); + } + pf_free_src_node(sn); + counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS], 1); + sn = NULL; + goto map_addr; + } + (*naf) = sn->raf; /* If the supplied address is the same as the current one we've @@ -902,9 +998,10 @@ pf_map_addr_sn(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr, goto done; } +map_addr: /* - * Source node has not been found. Find a new address and store it - * in variables given by the caller. + * Source node has not been found or is invalid. Find a new address + * and store it in variables given by the caller. */ if ((reason = pf_map_addr(saf, r, saddr, naddr, nkif, naf, init_addr, rpool)) != 0) { @@ -974,6 +1071,7 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r, { struct pf_pdesc *pd = ctx->pd; struct pf_addr *naddr; + int idx; uint16_t *nportp; uint16_t low, high; u_short reason; @@ -988,8 +1086,19 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r, return (PFRES_MEMORY); } - naddr = &ctx->nk->addr[1]; - nportp = &ctx->nk->port[1]; + switch (nat_action) { + case PF_NAT: + idx = pd->sidx; + break; + case PF_BINAT: + idx = 1; + break; + case PF_RDR: + idx = pd->didx; + break; + } + naddr = &ctx->nk->addr[idx]; + nportp = &ctx->nk->port[idx]; switch (nat_action) { case PF_NAT: |
