diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1602,7 +1602,6 @@ char any[0]; } hdr; - struct pf_krule *nat_rule; /* nat/rdr rule applied to packet */ struct pf_addr *src; /* src address */ struct pf_addr *dst; /* dst address */ u_int16_t *sport; @@ -2632,7 +2631,8 @@ struct pf_addr *, struct pf_addr *, uint16_t, uint16_t, struct pf_kanchor_stackframe *, struct pf_krule **, - struct pf_udp_mapping **udp_mapping); + struct pf_udp_mapping **udp_mapping, + struct pf_krule_slist *match_rules); struct pf_state_key *pf_state_key_setup(struct pf_pdesc *, struct mbuf *, int, struct pf_addr *, struct pf_addr *, u_int16_t, u_int16_t); 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 @@ -322,14 +322,16 @@ static int pf_test_rule(struct pf_krule **, struct pf_kstate **, struct pfi_kkif *, struct mbuf *, int, struct pf_pdesc *, struct pf_krule **, - struct pf_kruleset **, struct inpcb *, int); + struct pf_kruleset **, struct inpcb *, int, + struct pf_krule_slist *); static int pf_create_state(struct pf_krule *, struct pf_krule *, struct pf_krule *, struct pf_pdesc *, struct pf_ksrc_node *, struct pf_state_key *, struct pf_state_key *, struct mbuf *, int, u_int16_t, u_int16_t, int *, struct pfi_kkif *, struct pf_kstate **, int, u_int16_t, u_int16_t, - int, struct pf_krule_slist *, struct pf_udp_mapping *); + int, struct pf_udp_mapping *, + struct pf_krule_slist *); static int pf_state_key_addr_setup(struct pf_pdesc *, struct mbuf *, int, struct pf_state_key_cmp *, int, struct pf_addr *, int, struct pf_addr *, int); @@ -371,10 +373,9 @@ const struct pf_state_key_cmp *, u_int); static int pf_src_connlimit(struct pf_kstate **); static int pf_match_rcvif(struct mbuf *, struct pf_krule *); -static void pf_counters_inc(int, - struct pf_pdesc *, struct pfi_kkif *, - struct pf_kstate *, struct pf_krule *, - struct pf_krule *); +static void pf_counters_inc(int, struct pf_pdesc *, + struct pfi_kkif *, struct pf_kstate *, + struct pf_krule_slist *match_rules); static void pf_overload_task(void *v, int pending); static u_short pf_insert_src_node(struct pf_ksrc_node **, struct pf_krule *, struct pf_addr *, sa_family_t); @@ -4885,7 +4886,8 @@ static int pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif, struct mbuf *m, int off, struct pf_pdesc *pd, struct pf_krule **am, - struct pf_kruleset **rsm, struct inpcb *inp, int hdrlen) + struct pf_kruleset **rsm, struct inpcb *inp, int hdrlen, + struct pf_krule_slist *match_rules) { struct pf_krule *nr = NULL; struct pf_addr * const saddr = pd->src; @@ -4893,7 +4895,6 @@ sa_family_t af = pd->af; struct pf_krule *r, *a = NULL; struct pf_kruleset *ruleset = NULL; - struct pf_krule_slist match_rules; struct pf_krule_item *ri; struct pf_ksrc_node *nsn = NULL; struct tcphdr *th = &pd->hdr.tcp; @@ -4912,8 +4913,6 @@ PF_RULES_RASSERT(); - SLIST_INIT(&match_rules); - if (inp != NULL) { INP_LOCK_ASSERT(inp); pd->lookup.uid = inp->inp_cred->cr_uid; @@ -4976,7 +4975,8 @@ /* check packet for BINAT/NAT/RDR */ transerror = pf_get_translation(pd, m, off, kif, &nsn, &sk, - &nk, saddr, daddr, sport, dport, anchor_stack, &nr, &udp_mapping); + &nk, saddr, daddr, sport, dport, anchor_stack, &nr, &udp_mapping, + match_rules); switch (transerror) { default: /* A translation error occurred. */ @@ -5131,7 +5131,6 @@ } if (nr->natpass) r = NULL; - pd->nat_rule = nr; } while (r != NULL) { @@ -5228,21 +5227,20 @@ r->os_fingerprint)), TAILQ_NEXT(r, entries)); /* FALLTHROUGH */ + + ri = malloc(sizeof(struct pf_krule_item), M_PF_RULE_ITEM, M_NOWAIT | M_ZERO); + if (ri == NULL) { + REASON_SET(&reason, PFRES_MEMORY); + goto cleanup; + } + ri->r = r; + SLIST_INSERT_HEAD(match_rules, ri, entry); + + if (r->tag) tag = r->tag; if (r->anchor == NULL) { if (r->action == PF_MATCH) { - ri = malloc(sizeof(struct pf_krule_item), M_PF_RULE_ITEM, M_NOWAIT | M_ZERO); - if (ri == NULL) { - REASON_SET(&reason, PFRES_MEMORY); - goto cleanup; - } - ri->r = r; - SLIST_INSERT_HEAD(&match_rules, ri, entry); - pf_counter_u64_critical_enter(); - pf_counter_u64_add_protected(&r->packets[pd->dir == PF_OUT], 1); - pf_counter_u64_add_protected(&r->bytes[pd->dir == PF_OUT], pd->tot_len); - pf_counter_u64_critical_exit(); pf_rule_to_actions(r, &pd->act); if (r->log || pd->act.log & PF_LOG_MATCHES) PFLOG_PACKET(kif, m, @@ -5310,7 +5308,7 @@ int action; action = pf_create_state(r, nr, a, pd, nsn, nk, sk, m, off, sport, dport, &rewrite, kif, sm, tag, bproto_sum, bip_sum, - hdrlen, &match_rules, udp_mapping); + hdrlen, udp_mapping, match_rules); if (action != PF_PASS) { pf_udp_mapping_release(udp_mapping); if (action == PF_DROP && @@ -5321,11 +5319,6 @@ return (action); } } else { - while ((ri = SLIST_FIRST(&match_rules))) { - SLIST_REMOVE_HEAD(&match_rules, entry); - free(ri, M_PF_RULE_ITEM); - } - uma_zfree(V_pf_state_key_z, sk); uma_zfree(V_pf_state_key_z, nk); pf_udp_mapping_release(udp_mapping); @@ -5349,11 +5342,6 @@ return (PF_PASS); cleanup: - while ((ri = SLIST_FIRST(&match_rules))) { - SLIST_REMOVE_HEAD(&match_rules, entry); - free(ri, M_PF_RULE_ITEM); - } - uma_zfree(V_pf_state_key_z, sk); uma_zfree(V_pf_state_key_z, nk); pf_udp_mapping_release(udp_mapping); @@ -5367,14 +5355,13 @@ struct pf_state_key *sk, struct mbuf *m, int off, u_int16_t sport, u_int16_t dport, int *rewrite, struct pfi_kkif *kif, struct pf_kstate **sm, int tag, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen, - struct pf_krule_slist *match_rules, struct pf_udp_mapping *udp_mapping) + struct pf_udp_mapping *udp_mapping, struct pf_krule_slist *match_rules) { struct pf_kstate *s = NULL; struct pf_ksrc_node *sn = NULL; struct tcphdr *th = &pd->hdr.tcp; u_int16_t mss = V_tcp_mssdflt; u_short reason, sn_reason; - struct pf_krule_item *ri; /* check maximums */ if (r->max_states && @@ -5589,11 +5576,6 @@ return (PF_PASS); csfailed: - while ((ri = SLIST_FIRST(match_rules))) { - SLIST_REMOVE_HEAD(match_rules, entry); - free(ri, M_PF_RULE_ITEM); - } - uma_zfree(V_pf_state_key_z, sk); uma_zfree(V_pf_state_key_z, nk); @@ -6583,7 +6565,7 @@ */ ret = pf_test_rule(&r, &sm, V_pfi_all, j->m, off, &j->pd, &ra, &rs, NULL, - sizeof(j->pd.hdr.sctp)); + sizeof(j->pd.hdr.sctp), NULL); PF_RULES_RUNLOCK(); SDT_PROBE4(pf, sctp, multihome, test, kif, r, j->m, ret); if (ret != PF_DROP && sm != NULL) { @@ -7709,6 +7691,7 @@ struct pfi_kkif *nkif = NULL; struct ifnet *ifp = NULL; struct pf_addr naddr; + struct pf_krule_item *ri; int error = 0; uint16_t ip_len, ip_off; uint16_t tmp; @@ -7900,10 +7883,17 @@ error = EMSGSIZE; KMOD_IPSTAT_INC(ips_cantfrag); if (r_rt != PF_DUPTO) { - if (s && pd->nat_rule != NULL) - PACKET_UNDO_NAT(m0, pd, - (ip->ip_hl << 2) + (ip_off & IP_OFFMASK), - s); + if (s) { + while ((ri = SLIST_FIRST(&(s->match_rules)))) { + if (ri->r->action == PF_NAT || + ri->r->action == PF_RDR) { + PACKET_UNDO_NAT(m0, pd, + (ip->ip_hl << 2) + + (ip_off & IP_OFFMASK), + s); + } + } + } icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, ifp->if_mtu); @@ -7959,6 +7949,7 @@ struct ip6_hdr *ip6; struct pfi_kkif *nkif = NULL; struct ifnet *ifp = NULL; + struct pf_krule_item *ri; struct pf_addr naddr; int r_rt, r_dir; @@ -8113,10 +8104,18 @@ else { in6_ifstat_inc(ifp, ifs6_in_toobig); if (r_rt != PF_DUPTO) { - if (s && pd->nat_rule != NULL) - PACKET_UNDO_NAT(m0, pd, - ((caddr_t)ip6 - m0->m_data) + - sizeof(struct ip6_hdr), s); + if (s) { + while ((ri = SLIST_FIRST(&(s->match_rules)))) { + if (ri->r->action == PF_NAT || + ri->r->action == PF_RDR) { + PACKET_UNDO_NAT(m0, pd, + ((caddr_t)ip6 - + m0->m_data) + + sizeof(struct ip6_hdr), + s); + } + } + } icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); } else @@ -8466,17 +8465,16 @@ u_short *action, u_short *reason, struct pfi_kkif *kif, struct pf_krule **a, struct pf_krule **r, struct pf_kstate **s, struct pf_kruleset **ruleset, int *off, int *hdrlen, struct inpcb *inp, - struct pf_rule_actions *default_actions) + struct pf_rule_actions *default_actions, struct pf_krule_slist *match_rules) { struct mbuf *m = *m0; - memset(pd, 0, sizeof(*pd)); + SLIST_INIT(match_rules); pd->dir = dir; TAILQ_INIT(&pd->sctp_multihome_jobs); if (default_actions != NULL) memcpy(&pd->act, default_actions, sizeof(pd->act)); - pd->pf_mtag = pf_find_mtag(m); if (pd->pf_mtag && pd->pf_mtag->dnpipe) { pd->act.dnpipe = pd->pf_mtag->dnpipe; @@ -8539,7 +8537,7 @@ *action = PF_DROP; else *action = pf_test_rule(r, s, kif, m, *off, - pd, a, ruleset, inp, *hdrlen); + pd, a, ruleset, inp, *hdrlen, match_rules); if (*action != PF_PASS) REASON_SET(reason, PFRES_FRAG); return (-1); @@ -8594,7 +8592,7 @@ else *action = pf_test_rule(r, s, kif, m, *off, pd, a, ruleset, inp, - *hdrlen); + *hdrlen, match_rules); if (*action == PF_DROP) REASON_SET(reason, PFRES_FRAG); return (-1); @@ -8767,11 +8765,11 @@ } static void -pf_counters_inc(int action, struct pf_pdesc *pd, - struct pfi_kkif *kif, struct pf_kstate *s, - struct pf_krule *r, struct pf_krule *a) +pf_counters_inc(int action, struct pf_pdesc *pd, struct pfi_kkif *kif, + struct pf_kstate *s, struct pf_krule_slist *match_rules) { - struct pf_krule *tr, *nr; + struct pf_krule_item *ri; + struct pf_addr *src, *dst; int dir = pd->dir; int dirndx; @@ -8783,65 +8781,58 @@ &kif->pfik_packets[pd->af == AF_INET6][dir == PF_OUT][action != PF_PASS], 1); - if (action == PF_PASS || r->action == PF_DROP) { - dirndx = (dir == PF_OUT); - pf_counter_u64_add_protected(&r->packets[dirndx], 1); - pf_counter_u64_add_protected(&r->bytes[dirndx], pd->tot_len); - pf_update_timestamp(r); - - if (a != NULL) { - pf_counter_u64_add_protected(&a->packets[dirndx], 1); - pf_counter_u64_add_protected(&a->bytes[dirndx], pd->tot_len); - } - if (s != NULL) { - struct pf_krule_item *ri; - - if (s->nat_rule.ptr != NULL) { - pf_counter_u64_add_protected(&s->nat_rule.ptr->packets[dirndx], - 1); - pf_counter_u64_add_protected(&s->nat_rule.ptr->bytes[dirndx], - pd->tot_len); - } - if (s->src_node != NULL) { - counter_u64_add(s->src_node->packets[dirndx], - 1); - counter_u64_add(s->src_node->bytes[dirndx], - pd->tot_len); - } - if (s->nat_src_node != NULL) { - counter_u64_add(s->nat_src_node->packets[dirndx], - 1); - counter_u64_add(s->nat_src_node->bytes[dirndx], - pd->tot_len); - } - dirndx = (dir == s->direction) ? 0 : 1; - s->packets[dirndx]++; - s->bytes[dirndx] += pd->tot_len; - - SLIST_FOREACH(ri, &s->match_rules, entry) { - pf_counter_u64_add_protected(&ri->r->packets[dirndx], 1); - pf_counter_u64_add_protected(&ri->r->bytes[dirndx], pd->tot_len); - } - } - tr = r; - nr = (s != NULL) ? s->nat_rule.ptr : pd->nat_rule; - if (nr != NULL && r == &V_pf_default_rule) - tr = nr; - if (tr->src.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->src.addr.p.tbl, - (s == NULL) ? pd->src : - &s->key[(s->direction == PF_IN)]-> - addr[(s->direction == PF_OUT)], - pd->af, pd->tot_len, dir == PF_OUT, - r->action == PF_PASS, tr->src.neg); - if (tr->dst.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->dst.addr.p.tbl, - (s == NULL) ? pd->dst : - &s->key[(s->direction == PF_IN)]-> - addr[(s->direction == PF_IN)], - pd->af, pd->tot_len, dir == PF_OUT, - r->action == PF_PASS, tr->dst.neg); + if (s == NULL) { + src = pd->src; + dst = pd->dst; + } else { + src = &s->key[(s->direction == PF_IN)]->addr[(s->direction == PF_OUT)]; + dst = &s->key[(s->direction == PF_IN)]->addr[(s->direction == PF_IN)]; } + + dirndx = (dir == PF_OUT); + + SLIST_FOREACH(ri, match_rules, entry) { + if (action == PF_PASS || ri->r->action == PF_DROP) { + pf_counter_u64_add_protected(&ri->r->packets[dirndx], 1); + pf_counter_u64_add_protected(&ri->r->bytes[dirndx], pd->tot_len); + pf_update_timestamp(ri->r); + } + + if (ri->r->src.addr.type == PF_ADDR_TABLE) + pfr_update_stats(ri->r->src.addr.p.tbl, + src, pd->af, pd->tot_len, dirndx, + ri->r->action == PF_PASS, ri->r->src.neg); + if (ri->r->dst.addr.type == PF_ADDR_TABLE) + pfr_update_stats(ri->r->dst.addr.p.tbl, + dst, pd->af, pd->tot_len, dirndx, + ri->r->action == PF_PASS, ri->r->dst.neg); + } + + if (s != NULL) { + if (s->src_node != NULL) { + counter_u64_add(s->src_node->packets[dirndx], 1); + counter_u64_add(s->src_node->bytes[dirndx], pd->tot_len); + } + if (s->nat_src_node != NULL) { + counter_u64_add(s->nat_src_node->packets[dirndx], 1); + counter_u64_add(s->nat_src_node->bytes[dirndx], pd->tot_len); + } + dirndx = (dir == s->direction) ? 0 : 1; + s->packets[dirndx]++; + s->bytes[dirndx] += pd->tot_len; + + printf("Counters:"); + printf(" 00: "); + pf_print_host(&s->key[0]->addr[0], 0, pd->af); + printf(" 01: "); + pf_print_host(&s->key[0]->addr[1], 0, pd->af); + printf(" 10: "); + pf_print_host(&s->key[1]->addr[0], 0, pd->af); + printf(" 11: "); + pf_print_host(&s->key[1]->addr[1], 0, pd->af); + printf("\n"); + } + pf_counter_u64_critical_exit(); } @@ -8850,6 +8841,8 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp, struct pf_rule_actions *default_actions) { + struct pf_krule_slist match_rules; + struct pf_krule_item *ri; struct pfi_kkif *kif; u_short action, reason = 0; struct mbuf *m = *m0; @@ -8913,30 +8906,8 @@ return (PF_DROP); } - if (pf_setup_pdesc(af, dir, &pd, m0, &action, &reason, kif, &a, &r, - &s, &ruleset, &off, &hdrlen, inp, default_actions) == -1) { - if (action != PF_PASS) - pd.act.log |= PF_LOG_FORCE; - goto done; - } - m = *m0; - - switch (af) { -#ifdef INET - case AF_INET: - h = mtod(m, struct ip *); - ttl = h->ip_ttl; - break; -#endif -#ifdef INET6 - case AF_INET6: - h6 = mtod(m, struct ip6_hdr *); - ttl = h6->ip6_hlim; - break; -#endif - default: - panic("Unknown af %d", af); - } + memset(&pd, 0, sizeof(pd)); + pd.pf_mtag = pf_find_mtag(*m0); if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_MTAG_FLAG_ROUTE_TO)) { pd.pf_mtag->flags &= ~PF_MTAG_FLAG_ROUTE_TO; @@ -8969,6 +8940,15 @@ return (PF_PASS); } + if (pf_setup_pdesc(af, dir, &pd, m0, &action, &reason, kif, &a, &r, + &s, &ruleset, &off, &hdrlen, inp, default_actions, + &match_rules) == -1) { + if (action != PF_PASS) + pd.act.log |= PF_LOG_FORCE; + goto done; + } + m = *m0; + if (__predict_false(ip_divert_ptr != NULL) && ((mtag = m_tag_locate(m, MTAG_PF_DIVERT, 0, NULL)) != NULL)) { struct pf_divert_mtag *dt = (struct pf_divert_mtag *)(mtag+1); @@ -8992,6 +8972,23 @@ m_tag_delete(m, mtag); } + switch (af) { +#ifdef INET + case AF_INET: + h = mtod(m, struct ip *); + ttl = h->ip_ttl; + break; +#endif +#ifdef INET6 + case AF_INET6: + h6 = mtod(m, struct ip6_hdr *); + ttl = h6->ip6_hlim; + break; +#endif + default: + panic("Unknown af %d", af); + } + #ifdef INET6 /* * we do not support jumbogram. if we keep going, zero ip6_plen @@ -9060,7 +9057,7 @@ break; } else { action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp, hdrlen); + &a, &ruleset, inp, hdrlen, &match_rules); } } break; @@ -9075,7 +9072,7 @@ a = s->anchor.ptr; } else if (s == NULL) action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp, hdrlen); + &a, &ruleset, inp, hdrlen, &match_rules); break; } @@ -9092,7 +9089,7 @@ a = s->anchor.ptr; } else if (s == NULL) { action = pf_test_rule(&r, &s, kif, m, off, - &pd, &a, &ruleset, inp, hdrlen); + &pd, &a, &ruleset, inp, hdrlen, &match_rules); } break; } @@ -9112,7 +9109,7 @@ a = s->anchor.ptr; } else if (s == NULL) action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp, hdrlen); + &a, &ruleset, inp, hdrlen, &match_rules); break; } @@ -9131,7 +9128,7 @@ a = s->anchor.ptr; } else if (s == NULL) action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp, hdrlen); + &a, &ruleset, inp, hdrlen, &match_rules); break; } @@ -9144,7 +9141,7 @@ a = s->anchor.ptr; } else if (s == NULL) action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp, hdrlen); + &a, &ruleset, inp, hdrlen, &match_rules); break; } @@ -9261,6 +9258,11 @@ ip_divert_ptr(*m0, dir == PF_IN); *m0 = NULL; + while ((ri = SLIST_FIRST(&match_rules))) { + SLIST_REMOVE_HEAD(&match_rules, entry); + free(ri, M_PF_RULE_ITEM); + } + return (action); } else { /* XXX: ipfw has the same behaviour! */ @@ -9294,13 +9296,15 @@ ruleset, &pd, (s == NULL)); if (s) { SLIST_FOREACH(ri, &s->match_rules, entry) - if (ri->r->log & PF_LOG_ALL) + if (ri->r->action == PF_MATCH && + ri->r->log & PF_LOG_ALL) PFLOG_PACKET(kif, m, action, reason, ri->r, a, ruleset, &pd, 0); } } - pf_counters_inc(action, &pd, kif, s, r, a); + pf_counters_inc(action, &pd, kif, s, + (s != NULL) ? &(s->match_rules) : &match_rules); switch (action) { case PF_SYNPROXY_DROP: @@ -9349,8 +9353,14 @@ s->if_index_out = ifp->if_index; } - if (s) + if (s) { PF_STATE_UNLOCK(s); + } else { + while ((ri = SLIST_FIRST(&match_rules))) { + SLIST_REMOVE_HEAD(&match_rules, entry); + free(ri, M_PF_RULE_ITEM); + } + } #ifdef INET6 /* If reassembled packet passed, create new fragments. */ 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 @@ -64,9 +64,10 @@ static void pf_hash(struct pf_addr *, struct pf_addr *, struct pf_poolhashkey *, sa_family_t); static struct pf_krule *pf_match_translation(struct pf_pdesc *, struct mbuf *, - int, struct pfi_kkif *, - struct pf_addr *, u_int16_t, struct pf_addr *, - uint16_t, int, struct pf_kanchor_stackframe *); + int, struct pfi_kkif *, struct pf_addr *, u_int16_t, + struct pf_addr *, uint16_t, int, + struct pf_kanchor_stackframe *, + struct pf_krule_slist *); static int pf_get_sport(sa_family_t, uint8_t, struct pf_krule *, struct pf_addr *, uint16_t, struct pf_addr *, uint16_t, struct pf_addr *, uint16_t *, uint16_t, uint16_t, struct pf_ksrc_node **, @@ -134,10 +135,12 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, struct pfi_kkif *kif, struct pf_addr *saddr, u_int16_t sport, struct pf_addr *daddr, uint16_t dport, int rs_num, - struct pf_kanchor_stackframe *anchor_stack) + struct pf_kanchor_stackframe *anchor_stack, + struct pf_krule_slist *match_rules) { struct pf_krule *r, *rm = NULL; struct pf_kruleset *ruleset = NULL; + struct pf_krule_item *ri; int tag = -1; int rtableid = -1; int asd = 0; @@ -192,6 +195,15 @@ off, &pd->hdr.tcp), r->os_fingerprint))) r = TAILQ_NEXT(r, entries); else { + ri = malloc(sizeof(struct pf_krule_item), M_PF_RULE_ITEM, M_NOWAIT | M_ZERO); + /* + * XXX KS: There's no error handling for the NAT + * ruleset. It needs to be added before we can add + * malloc failure check. + */ + ri->r = r; + SLIST_INSERT_HEAD(match_rules, ri, entry); + if (r->tag) tag = r->tag; if (r->rtableid >= 0) @@ -697,12 +709,11 @@ u_short pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, - struct pfi_kkif *kif, struct pf_ksrc_node **sn, - struct pf_state_key **skp, struct pf_state_key **nkp, - struct pf_addr *saddr, struct pf_addr *daddr, + struct pfi_kkif *kif, struct pf_ksrc_node **sn, struct pf_state_key **skp, + struct pf_state_key **nkp, struct pf_addr *saddr, struct pf_addr *daddr, uint16_t sport, uint16_t dport, struct pf_kanchor_stackframe *anchor_stack, - struct pf_krule **rp, - struct pf_udp_mapping **udp_mapping) + struct pf_krule **rp, struct pf_udp_mapping **udp_mapping, + struct pf_krule_slist *match_rules) { struct pf_krule *r = NULL; struct pf_addr *naddr; @@ -717,19 +728,19 @@ *rp = NULL; if (pd->dir == PF_OUT) { - r = pf_match_translation(pd, m, off, kif, saddr, - sport, daddr, dport, PF_RULESET_BINAT, anchor_stack); + r = pf_match_translation(pd, m, off, kif, saddr, sport, daddr, + dport, PF_RULESET_BINAT, anchor_stack, match_rules); if (r == NULL) - r = pf_match_translation(pd, m, off, kif, - saddr, sport, daddr, dport, PF_RULESET_NAT, - anchor_stack); + r = pf_match_translation(pd, m, off, kif, saddr, sport, + daddr, dport, PF_RULESET_NAT, anchor_stack, + match_rules); } else { - r = pf_match_translation(pd, m, off, kif, saddr, - sport, daddr, dport, PF_RULESET_RDR, anchor_stack); + r = pf_match_translation(pd, m, off, kif, saddr, sport, daddr, + dport, PF_RULESET_RDR, anchor_stack, match_rules); if (r == NULL) - r = pf_match_translation(pd, m, off, kif, - saddr, sport, daddr, dport, PF_RULESET_BINAT, - anchor_stack); + r = pf_match_translation(pd, m, off, kif, saddr, sport, + daddr, dport, PF_RULESET_BINAT, anchor_stack, + match_rules); } if (r == NULL) diff --git a/tests/sys/netpfil/pf/Makefile b/tests/sys/netpfil/pf/Makefile --- a/tests/sys/netpfil/pf/Makefile +++ b/tests/sys/netpfil/pf/Makefile @@ -6,6 +6,7 @@ ATF_TESTS_SH+= altq \ anchor \ + counters \ debug \ divert-to \ dup \ diff --git a/tests/sys/netpfil/pf/counters.sh b/tests/sys/netpfil/pf/counters.sh new file mode 100755 --- /dev/null +++ b/tests/sys/netpfil/pf/counters.sh @@ -0,0 +1,99 @@ +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2024 Kajetan Staszkiewicz +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +. $(atf_get_srcdir)/utils.subr + +atf_test_case "source_track" "cleanup" + +counters_head() +{ + atf_set descr 'Rule and table counters' + atf_set require.user root +} + +counters_body() +{ + setup_router_server_ipv6 + + # Clients will connect from another network behind the router. + # This allows for using multiple source addresses and for tester jail + # to not respond with RST packets for SYN+ACKs. + jexec router route add -6 2001:db8:44::0/64 2001:db8:42::2 + jexec server route add -6 2001:db8:44::0/64 2001:db8:43::1 + + pft_set_rules router \ + "table counters { 2001:db8:44::0/64 }" \ + "table counters { 2001:db8:44::0/64 }" \ + "table counters { 2001:db8:44::0/64 }" \ + "table counters { 2001:db8:44::0/64 }" \ + "nat on ${epair_server}a inet6 from to any -> ${epair_server}a" \ + "block" \ + "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ + "anchor anchor1 in on ${epair_tester}b inet6 proto tcp from {"\ + "match from " \ + "pass from keep state" \ + "}" \ + "pass out on ${epair_server}a inet6 proto tcp keep state" + + # Use the 3-way testing so that more than 1 packet is sent. + ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201 --fromaddr 2001:db8:44::1 + + nat_rules=$(mktemp) || exit 1 + jexec router pfctl -qvvsn > ${nat_rules} + echo === NAT rules === + cat $nat_rules + + pass_rules=$(mktemp) || exit 1 + jexec router pfctl -qvvsr -a '*' > ${pass_rules} + echo === pass_rules === + cat $pass_rules + + states=$(mktemp) || exit 1 + jexec router pfctl -qvss > ${states} + echo === states === + cat $states + + nodes=$(mktemp) || exit 1 + jexec router pfctl -qvsS > ${nodes} + echo === nodes === + cat $nodes + + tables=$(mktemp) || exit 1 + jexec router pfctl -qvvsT > ${tables} + echo === tables === + cat $tables +} + +counters_cleanup() +{ + pft_cleanup +} + + +atf_init_test_cases() +{ + atf_add_test_case "counters" +}