aboutsummaryrefslogtreecommitdiff
path: root/sys/netpfil/pf/pf_lb.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netpfil/pf/pf_lb.c')
-rw-r--r--sys/netpfil/pf/pf_lb.c117
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: