diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -2403,7 +2403,7 @@ 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 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -329,7 +329,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ (*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 @@ 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 @@ /* 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 @@ } 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 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -342,10 +342,11 @@ 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 @@ /* 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_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 @@ 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 @@ 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 @@ } } 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 @@ /* 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 @@ /* 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 @@ 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 @@ 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 *