git: 16303d2ba6b0 - main - pf: improve source node error handling
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 03 May 2023 09:59:27 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=16303d2ba6b099afa8ec8f2e97deca2785caa082 commit 16303d2ba6b099afa8ec8f2e97deca2785caa082 Author: Kajetan Staszkiewicz <vegeta@tuxpowered.net> AuthorDate: 2023-05-03 08:31:05 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2023-05-03 08:31:05 +0000 pf: improve source node error handling Functions manipulating source nodes can fail due to various reasons like memory allocation errors, hitting configured limits or lack of redirection targets. Ensure those errors are properly caught and propagated in the code. Increase the error counters not only when parsing the main ruleset but the NAT ruleset too. Cherry-picked from development of D39880 Reviewed by: kp Sponsored by: InnoGames GmbH Differential Revision: https://reviews.freebsd.org/D39940 --- sys/net/pfvar.h | 2 +- sys/netpfil/pf/pf.c | 50 ++++++++++++++++++++++++++++++-------------------- sys/netpfil/pf/pf_lb.c | 47 ++++++++++++++++++++++++++++------------------- 3 files changed, 59 insertions(+), 40 deletions(-) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 412453f8dd25..f72c3980438d 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -2403,7 +2403,7 @@ int pf_step_out_of_keth_anchor(struct pf_keth_anchor_stackframe *, struct pf_keth_rule **, struct pf_keth_rule **, int *); -int pf_map_addr(u_int8_t, struct pf_krule *, +u_short pf_map_addr(u_int8_t, struct pf_krule *, struct pf_addr *, struct pf_addr *, struct pf_addr *, struct pf_ksrc_node **); struct pf_krule *pf_get_translation(struct pf_pdesc *, struct mbuf *, diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index e5f2a5ea57a0..ee17df0c866f 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -329,7 +329,7 @@ static struct pf_kstate *pf_find_state(struct pfi_kkif *, struct pf_state_key_cmp *, u_int); static int pf_src_connlimit(struct pf_kstate **); static void pf_overload_task(void *v, int pending); -static int pf_insert_src_node(struct pf_ksrc_node **, +static u_short pf_insert_src_node(struct pf_ksrc_node **, struct pf_krule *, struct pf_addr *, sa_family_t); static u_int pf_purge_expired_states(u_int, int); static void pf_purge_unlinked_rules(void); @@ -865,11 +865,12 @@ pf_free_src_node(struct pf_ksrc_node *sn) uma_zfree(V_pf_sources_z, sn); } -static int +static u_short pf_insert_src_node(struct pf_ksrc_node **sn, struct pf_krule *rule, struct pf_addr *src, sa_family_t af) { - struct pf_srchash *sh = NULL; + u_short reason = 0; + struct pf_srchash *sh = NULL; KASSERT((rule->rule_flag & PFRULE_SRCTRACK || rule->rpool.opts & PF_POOL_STICKYADDR), @@ -881,15 +882,19 @@ pf_insert_src_node(struct pf_ksrc_node **sn, struct pf_krule *rule, if (*sn == NULL) { PF_HASHROW_ASSERT(sh); - if (!rule->max_src_nodes || - counter_u64_fetch(rule->src_nodes) < rule->max_src_nodes) - (*sn) = uma_zalloc(V_pf_sources_z, M_NOWAIT | M_ZERO); - else - counter_u64_add(V_pf_status.lcounters[LCNT_SRCNODES], - 1); + if (rule->max_src_nodes && + counter_u64_fetch(rule->src_nodes) >= rule->max_src_nodes) { + counter_u64_add(V_pf_status.lcounters[LCNT_SRCNODES], 1); + PF_HASHROW_UNLOCK(sh); + reason = PFRES_SRCLIMIT; + goto done; + } + + (*sn) = uma_zalloc(V_pf_sources_z, M_NOWAIT | M_ZERO); if ((*sn) == NULL) { PF_HASHROW_UNLOCK(sh); - return (-1); + reason = PFRES_MEMORY; + goto done; } for (int i = 0; i < 2; i++) { @@ -899,7 +904,8 @@ pf_insert_src_node(struct pf_ksrc_node **sn, struct pf_krule *rule, if ((*sn)->bytes[i] == NULL || (*sn)->packets[i] == NULL) { pf_free_src_node(*sn); PF_HASHROW_UNLOCK(sh); - return (-1); + reason = PFRES_MEMORY; + goto done; } } @@ -926,10 +932,12 @@ pf_insert_src_node(struct pf_ksrc_node **sn, struct pf_krule *rule, (*sn)->states >= rule->max_src_states) { counter_u64_add(V_pf_status.lcounters[LCNT_SRCSTATES], 1); - return (-1); + reason = PFRES_SRCLIMIT; + goto done; } } - return (0); +done: + return (reason); } void @@ -4581,7 +4589,7 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a, struct pf_ksrc_node *sn = NULL; struct tcphdr *th = &pd->hdr.tcp; u_int16_t mss = V_tcp_mssdflt; - u_short reason; + u_short reason, sn_reason; /* check maximums */ if (r->max_states && @@ -4593,14 +4601,15 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a, /* src node for filter rule */ if ((r->rule_flag & PFRULE_SRCTRACK || r->rpool.opts & PF_POOL_STICKYADDR) && - pf_insert_src_node(&sn, r, pd->src, pd->af) != 0) { - REASON_SET(&reason, PFRES_SRCLIMIT); + (sn_reason = pf_insert_src_node(&sn, r, pd->src, pd->af)) != 0) { + REASON_SET(&reason, sn_reason); goto csfailed; } /* src node for translation rule */ if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && - pf_insert_src_node(&nsn, nr, &sk->addr[pd->sidx], pd->af)) { - REASON_SET(&reason, PFRES_SRCLIMIT); + (sn_reason = pf_insert_src_node(&nsn, nr, &sk->addr[pd->sidx], + pd->af)) != 0 ) { + REASON_SET(&reason, sn_reason); goto csfailed; } s = pf_alloc_state(M_NOWAIT); @@ -4689,8 +4698,9 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a, } if (r->rt) { - if (pf_map_addr(pd->af, r, pd->src, &s->rt_addr, NULL, &sn)) { - REASON_SET(&reason, PFRES_MAPFAILED); + /* pf_map_addr increases the reason counters */ + if ((reason = pf_map_addr(pd->af, r, pd->src, &s->rt_addr, NULL, + &sn)) != 0) { pf_src_tree_remove_state(s); s->timeout = PFTM_UNLINKED; STATE_DEC_COUNTERS(s); diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c index ca8593a1c37d..a2f0224f842c 100644 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -342,10 +342,11 @@ pf_get_mape_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r, return (1); } -int +u_short pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_ksrc_node **sn) { + u_short reason = 0; struct pf_kpool *rpool = &r->rpool; struct pf_addr *raddr = NULL, *rmask = NULL; struct pf_srchash *sh = NULL; @@ -364,8 +365,10 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, /* If the supplied address is the same as the current one we've * been asked before, so tell the caller that there's no other * address to be had. */ - if (PF_AEQ(naddr, &(*sn)->raddr, af)) - return (1); + if (PF_AEQ(naddr, &(*sn)->raddr, af)) { + reason = PFRES_MAPFAILED; + goto done; + } PF_ACPY(naddr, &(*sn)->raddr, af); if (V_pf_status.debug >= PF_DEBUG_NOISY) { @@ -375,15 +378,15 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, pf_print_host(naddr, 0, af); printf("\n"); } - return (0); + goto done; } mtx_lock(&rpool->mtx); /* Find the route using chosen algorithm. Store the found route in src_node if it was given or found. */ if (rpool->cur->addr.type == PF_ADDR_NOROUTE) { - mtx_unlock(&rpool->mtx); - return (1); + reason = PFRES_MAPFAILED; + goto done_pool_mtx; } if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { switch (af) { @@ -392,8 +395,8 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 && (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) { - mtx_unlock(&rpool->mtx); - return (1); + reason = PFRES_MAPFAILED; + goto done_pool_mtx; } raddr = &rpool->cur->addr.p.dyn->pfid_addr4; rmask = &rpool->cur->addr.p.dyn->pfid_mask4; @@ -404,8 +407,8 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 && (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) { - mtx_unlock(&rpool->mtx); - return (1); + reason = PFRES_MAPFAILED; + goto done_pool_mtx; } raddr = &rpool->cur->addr.p.dyn->pfid_addr6; rmask = &rpool->cur->addr.p.dyn->pfid_mask6; @@ -414,8 +417,8 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, } } else if (rpool->cur->addr.type == PF_ADDR_TABLE) { if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) { - mtx_unlock(&rpool->mtx); - return (1); /* unsupported */ + reason = PFRES_MAPFAILED; + goto done_pool_mtx; /* unsupported */ } } else { raddr = &rpool->cur->addr.v.a.addr; @@ -503,8 +506,8 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, /* table contains no address of type 'af' */ if (rpool->cur != acur) goto try_next; - mtx_unlock(&rpool->mtx); - return (1); + reason = PFRES_MAPFAILED; + goto done_pool_mtx; } } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { rpool->tblidx = -1; @@ -513,8 +516,8 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, /* table contains no address of type 'af' */ if (rpool->cur != acur) goto try_next; - mtx_unlock(&rpool->mtx); - return (1); + reason = PFRES_MAPFAILED; + goto done_pool_mtx; } } else { raddr = &rpool->cur->addr.v.a.addr; @@ -533,8 +536,6 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, if (*sn != NULL) PF_ACPY(&(*sn)->raddr, naddr, af); - mtx_unlock(&rpool->mtx); - if (V_pf_status.debug >= PF_DEBUG_NOISY && (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) { printf("pf_map_addr: selected address "); @@ -542,7 +543,15 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, printf("\n"); } - return (0); +done_pool_mtx: + mtx_unlock(&rpool->mtx); + +done: + if (reason) { + counter_u64_add(V_pf_status.counters[reason], 1); + } + + return (reason); } struct pf_krule *