diff options
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/net/pfvar.h | 1 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf.c | 64 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_nv.c | 30 |
3 files changed, 87 insertions, 8 deletions
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 57acab788b20..a61feb07334f 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -646,6 +646,7 @@ struct pf_keth_rule { uint8_t direction; uint16_t proto; struct pf_keth_rule_addr src, dst; + struct pf_rule_addr ipsrc, ipdst; /* Stats */ counter_u64_t evaluations; diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index fb0abc8cd035..a900da0b8bd1 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -279,7 +279,7 @@ static u_int32_t pf_tcp_iss(struct pf_pdesc *); void pf_rule_to_actions(struct pf_krule *, struct pf_rule_actions *); static int pf_test_eth_rule(int, struct pfi_kkif *, - struct mbuf *); + struct mbuf **); static int pf_test_rule(struct pf_krule **, struct pf_kstate **, int, struct pfi_kkif *, struct mbuf *, int, struct pf_pdesc *, struct pf_krule **, @@ -3826,31 +3826,67 @@ pf_match_eth_addr(const uint8_t *a, const struct pf_keth_rule_addr *r) } static int -pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf *m) +pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0) { + struct mbuf *m = *m0; struct ether_header *e; struct pf_keth_rule *r, *rm, *a = NULL; struct pf_keth_ruleset *ruleset = NULL; struct pf_mtag *mtag; struct pf_keth_ruleq *rules; + struct pf_addr *src, *dst; + sa_family_t af = 0; + uint16_t proto; int asd = 0, match = 0; uint8_t action; struct pf_keth_anchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE]; - NET_EPOCH_ASSERT(); - MPASS(kif->pfik_ifp->if_vnet == curvnet); NET_EPOCH_ASSERT(); SDT_PROBE3(pf, eth, test_rule, entry, dir, kif->pfik_ifp, m); - e = mtod(m, struct ether_header *); - ruleset = V_pf_keth; rules = ck_pr_load_ptr(&ruleset->active.rules); r = TAILQ_FIRST(rules); rm = NULL; + e = mtod(m, struct ether_header *); + proto = ntohs(e->ether_type); + + switch (proto) { + case ETHERTYPE_IP: { + struct ip *ip; + m = m_pullup(m, sizeof(struct ether_header) + + sizeof(struct ip)); + if (m == NULL) { + *m0 = NULL; + return (PF_DROP); + } + af = AF_INET; + ip = mtodo(m, sizeof(struct ether_header)); + src = (struct pf_addr *)&ip->ip_src; + dst = (struct pf_addr *)&ip->ip_dst; + break; + } + case ETHERTYPE_IPV6: { + struct ip6_hdr *ip6; + m = m_pullup(m, sizeof(struct ether_header) + + sizeof(struct ip6_hdr)); + if (m == NULL) { + *m0 = NULL; + return (PF_DROP); + } + af = AF_INET6; + ip6 = mtodo(m, sizeof(struct ether_header)); + src = (struct pf_addr *)&ip6->ip6_src; + dst = (struct pf_addr *)&ip6->ip6_dst; + break; + } + } + e = mtod(m, struct ether_header *); + *m0 = m; + while (r != NULL) { counter_u64_add(r->evaluations, 1); SDT_PROBE2(pf, eth, test_rule, test, r->nr, r); @@ -3865,7 +3901,7 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf *m) "dir"); r = r->skip[PFE_SKIP_DIR].ptr; } - else if (r->proto && r->proto != ntohs(e->ether_type)) { + else if (r->proto && r->proto != proto) { SDT_PROBE3(pf, eth, test_rule, mismatch, r->nr, r, "proto"); r = r->skip[PFE_SKIP_PROTO].ptr; @@ -3880,6 +3916,18 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf *m) "dst"); r = TAILQ_NEXT(r, entries); } + else if (af != 0 && PF_MISMATCHAW(&r->ipsrc.addr, src, af, + r->ipsrc.neg, kif, M_GETFIB(m))) { + SDT_PROBE3(pf, eth, test_rule, mismatch, r->nr, r, + "ip_src"); + r = TAILQ_NEXT(r, entries); + } + else if (af != 0 && PF_MISMATCHAW(&r->ipdst.addr, dst, af, + r->ipdst.neg, kif, M_GETFIB(m))) { + SDT_PROBE3(pf, eth, test_rule, mismatch, r->nr, r, + "ip_dst"); + r = TAILQ_NEXT(r, entries); + } else { if (r->anchor == NULL) { /* Rule matches */ @@ -6737,7 +6785,7 @@ pf_test_eth(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, return (PF_PASS); /* Stateless! */ - return (pf_test_eth_rule(dir, kif, m)); + return (pf_test_eth_rule(dir, kif, m0)); } #ifdef INET diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c index 42434dabf565..3b0d92cc5d20 100644 --- a/sys/netpfil/pf/pf_nv.c +++ b/sys/netpfil/pf/pf_nv.c @@ -1071,6 +1071,22 @@ pf_keth_rule_to_nveth_rule(const struct pf_keth_rule *krule) } nvlist_add_nvlist(nvl, "dst", addr); + addr = pf_rule_addr_to_nvrule_addr(&krule->ipsrc); + if (addr == NULL) { + nvlist_destroy(nvl); + return (NULL); + } + nvlist_add_nvlist(nvl, "ipsrc", addr); + nvlist_destroy(addr); + + addr = pf_rule_addr_to_nvrule_addr(&krule->ipdst); + if (addr == NULL) { + nvlist_destroy(nvl); + return (NULL); + } + nvlist_add_nvlist(nvl, "ipdst", addr); + nvlist_destroy(addr); + nvlist_add_number(nvl, "evaluations", counter_u64_fetch(krule->evaluations)); nvlist_add_number(nvl, "packets-in", @@ -1125,6 +1141,20 @@ pf_nveth_rule_to_keth_rule(const nvlist_t *nvl, return (error); } + if (nvlist_exists_nvlist(nvl, "ipsrc")) { + error = pf_nvrule_addr_to_rule_addr( + nvlist_get_nvlist(nvl, "ipsrc"), &krule->ipsrc); + if (error != 0) + return (error); + } + + if (nvlist_exists_nvlist(nvl, "ipdst")) { + error = pf_nvrule_addr_to_rule_addr( + nvlist_get_nvlist(nvl, "ipdst"), &krule->ipdst); + if (error != 0) + return (error); + } + PFNV_CHK(pf_nvstring(nvl, "qname", krule->qname, sizeof(krule->qname))); PFNV_CHK(pf_nvstring(nvl, "tagname", krule->tagname, sizeof(krule->tagname))); |
