diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-08-22 14:59:50 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-09-21 10:29:41 +0200 |
commit | 3489e3b6396ee9944a6a2e19e675ca54c36993b4 (patch) | |
tree | cd55cfac1c96ff4b888a9606fd6a0d8eb65bb446 /freebsd/sys/netpfil/pf | |
parent | ck: Define CK_MD_PPC32_LWSYNC if available (diff) | |
download | rtems-libbsd-3489e3b6396ee9944a6a2e19e675ca54c36993b4.tar.bz2 |
Update to FreeBSD head 2018-09-17
Git mirror commit 6c2192b1ef8c50788c751f878552526800b1e319.
Update #3472.
Diffstat (limited to 'freebsd/sys/netpfil/pf')
-rw-r--r-- | freebsd/sys/netpfil/pf/if_pflog.c | 2 | ||||
-rw-r--r-- | freebsd/sys/netpfil/pf/if_pfsync.c | 10 | ||||
-rw-r--r-- | freebsd/sys/netpfil/pf/pf.c | 206 | ||||
-rw-r--r-- | freebsd/sys/netpfil/pf/pf_altq.h | 145 | ||||
-rw-r--r-- | freebsd/sys/netpfil/pf/pf_if.c | 41 | ||||
-rw-r--r-- | freebsd/sys/netpfil/pf/pf_ioctl.c | 310 | ||||
-rw-r--r-- | freebsd/sys/netpfil/pf/pf_norm.c | 16 | ||||
-rw-r--r-- | freebsd/sys/netpfil/pf/pf_osfp.c | 2 | ||||
-rw-r--r-- | freebsd/sys/netpfil/pf/pf_table.c | 10 |
9 files changed, 586 insertions, 156 deletions
diff --git a/freebsd/sys/netpfil/pf/if_pflog.c b/freebsd/sys/netpfil/pf/if_pflog.c index 53cf94c8..3da5d8c0 100644 --- a/freebsd/sys/netpfil/pf/if_pflog.c +++ b/freebsd/sys/netpfil/pf/if_pflog.c @@ -98,7 +98,7 @@ static void pflog_clone_destroy(struct ifnet *); static const char pflogname[] = "pflog"; -static VNET_DEFINE(struct if_clone *, pflog_cloner); +VNET_DEFINE_STATIC(struct if_clone *, pflog_cloner); #define V_pflog_cloner VNET(pflog_cloner) VNET_DEFINE(struct ifnet *, pflogifs[PFLOGIFS_MAX]); /* for fast access */ diff --git a/freebsd/sys/netpfil/pf/if_pfsync.c b/freebsd/sys/netpfil/pf/if_pfsync.c index 9b457818..dae091db 100644 --- a/freebsd/sys/netpfil/pf/if_pfsync.c +++ b/freebsd/sys/netpfil/pf/if_pfsync.c @@ -231,13 +231,13 @@ struct pfsync_softc { static const char pfsyncname[] = "pfsync"; static MALLOC_DEFINE(M_PFSYNC, pfsyncname, "pfsync(4) data"); -static VNET_DEFINE(struct pfsync_softc *, pfsyncif) = NULL; +VNET_DEFINE_STATIC(struct pfsync_softc *, pfsyncif) = NULL; #define V_pfsyncif VNET(pfsyncif) -static VNET_DEFINE(void *, pfsync_swi_cookie) = NULL; +VNET_DEFINE_STATIC(void *, pfsync_swi_cookie) = NULL; #define V_pfsync_swi_cookie VNET(pfsync_swi_cookie) -static VNET_DEFINE(struct pfsyncstats, pfsyncstats); +VNET_DEFINE_STATIC(struct pfsyncstats, pfsyncstats); #define V_pfsyncstats VNET(pfsyncstats) -static VNET_DEFINE(int, pfsync_carp_adj) = CARP_MAXSKEW; +VNET_DEFINE_STATIC(int, pfsync_carp_adj) = CARP_MAXSKEW; #define V_pfsync_carp_adj VNET(pfsync_carp_adj) static void pfsync_timeout(void *); @@ -871,7 +871,7 @@ pfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) st = pf_find_state_byid(sp->id, sp->creatorid); if (st == NULL) { /* insert the update */ - if (pfsync_state_import(sp, 0)) + if (pfsync_state_import(sp, pkt->flags)) V_pfsyncstats.pfsyncs_badstate++; continue; } diff --git a/freebsd/sys/netpfil/pf/pf.c b/freebsd/sys/netpfil/pf/pf.c index 3cc4ff11..f765350d 100644 --- a/freebsd/sys/netpfil/pf/pf.c +++ b/freebsd/sys/netpfil/pf/pf.c @@ -137,7 +137,7 @@ VNET_DEFINE(int, pf_tcp_iss_off); VNET_DECLARE(int, pf_vnet_active); #define V_pf_vnet_active VNET(pf_vnet_active) -static VNET_DEFINE(uint32_t, pf_purge_idx); +VNET_DEFINE_STATIC(uint32_t, pf_purge_idx); #define V_pf_purge_idx VNET(pf_purge_idx) /* @@ -161,7 +161,7 @@ struct pf_send_entry { }; STAILQ_HEAD(pf_send_head, pf_send_entry); -static VNET_DEFINE(struct pf_send_head, pf_sendqueue); +VNET_DEFINE_STATIC(struct pf_send_head, pf_sendqueue); #define V_pf_sendqueue VNET(pf_sendqueue) static struct mtx pf_sendqueue_mtx; @@ -181,9 +181,9 @@ struct pf_overload_entry { }; SLIST_HEAD(pf_overload_head, pf_overload_entry); -static VNET_DEFINE(struct pf_overload_head, pf_overloadqueue); +VNET_DEFINE_STATIC(struct pf_overload_head, pf_overloadqueue); #define V_pf_overloadqueue VNET(pf_overloadqueue) -static VNET_DEFINE(struct task, pf_overloadtask); +VNET_DEFINE_STATIC(struct task, pf_overloadtask); #define V_pf_overloadtask VNET(pf_overloadtask) static struct mtx pf_overloadqueue_mtx; @@ -197,7 +197,7 @@ struct mtx pf_unlnkdrules_mtx; MTX_SYSINIT(pf_unlnkdrules_mtx, &pf_unlnkdrules_mtx, "pf unlinked rules", MTX_DEF); -static VNET_DEFINE(uma_zone_t, pf_sources_z); +VNET_DEFINE_STATIC(uma_zone_t, pf_sources_z); #define V_pf_sources_z VNET(pf_sources_z) uma_zone_t pf_mtag_z; VNET_DEFINE(uma_zone_t, pf_state_z); @@ -297,14 +297,14 @@ static void pf_mtag_free(struct m_tag *); #ifdef INET static void pf_route(struct mbuf **, struct pf_rule *, int, struct ifnet *, struct pf_state *, - struct pf_pdesc *); + struct pf_pdesc *, struct inpcb *); #endif /* INET */ #ifdef INET6 static void pf_change_a6(struct pf_addr *, u_int16_t *, struct pf_addr *, u_int8_t); static void pf_route6(struct mbuf **, struct pf_rule *, int, struct ifnet *, struct pf_state *, - struct pf_pdesc *); + struct pf_pdesc *, struct inpcb *); #endif /* INET6 */ int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len); @@ -1721,24 +1721,28 @@ pf_purge_expired_states(u_int i, int maxcheck) while (maxcheck > 0) { ih = &V_pf_idhash[i]; + + /* only take the lock if we expect to do work */ + if (!LIST_EMPTY(&ih->states)) { relock: - PF_HASHROW_LOCK(ih); - LIST_FOREACH(s, &ih->states, entry) { - if (pf_state_expires(s) <= time_uptime) { - V_pf_status.states -= - pf_unlink_state(s, PF_ENTER_LOCKED); - goto relock; + PF_HASHROW_LOCK(ih); + LIST_FOREACH(s, &ih->states, entry) { + if (pf_state_expires(s) <= time_uptime) { + V_pf_status.states -= + pf_unlink_state(s, PF_ENTER_LOCKED); + goto relock; + } + s->rule.ptr->rule_flag |= PFRULE_REFS; + if (s->nat_rule.ptr != NULL) + s->nat_rule.ptr->rule_flag |= PFRULE_REFS; + if (s->anchor.ptr != NULL) + s->anchor.ptr->rule_flag |= PFRULE_REFS; + s->kif->pfik_flags |= PFI_IFLAG_REFS; + if (s->rt_kif) + s->rt_kif->pfik_flags |= PFI_IFLAG_REFS; } - s->rule.ptr->rule_flag |= PFRULE_REFS; - if (s->nat_rule.ptr != NULL) - s->nat_rule.ptr->rule_flag |= PFRULE_REFS; - if (s->anchor.ptr != NULL) - s->anchor.ptr->rule_flag |= PFRULE_REFS; - s->kif->pfik_flags |= PFI_IFLAG_REFS; - if (s->rt_kif) - s->rt_kif->pfik_flags |= PFI_IFLAG_REFS; + PF_HASHROW_UNLOCK(ih); } - PF_HASHROW_UNLOCK(ih); /* Return when we hit end of hash. */ if (++i > pf_hashmask) { @@ -2501,6 +2505,81 @@ pf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af, pf_send(pfse); } +static void +pf_return(struct pf_rule *r, struct pf_rule *nr, struct pf_pdesc *pd, + struct pf_state_key *sk, int off, struct mbuf *m, struct tcphdr *th, + struct pfi_kif *kif, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen, + u_short *reason) +{ + struct pf_addr * const saddr = pd->src; + struct pf_addr * const daddr = pd->dst; + sa_family_t af = pd->af; + + /* undo NAT changes, if they have taken place */ + if (nr != NULL) { + PF_ACPY(saddr, &sk->addr[pd->sidx], af); + PF_ACPY(daddr, &sk->addr[pd->didx], af); + if (pd->sport) + *pd->sport = sk->port[pd->sidx]; + if (pd->dport) + *pd->dport = sk->port[pd->didx]; + if (pd->proto_sum) + *pd->proto_sum = bproto_sum; + if (pd->ip_sum) + *pd->ip_sum = bip_sum; + m_copyback(m, off, hdrlen, pd->hdr.any); + } + if (pd->proto == IPPROTO_TCP && + ((r->rule_flag & PFRULE_RETURNRST) || + (r->rule_flag & PFRULE_RETURN)) && + !(th->th_flags & TH_RST)) { + u_int32_t ack = ntohl(th->th_seq) + pd->p_len; + int len = 0; +#ifdef INET + struct ip *h4; +#endif +#ifdef INET6 + struct ip6_hdr *h6; +#endif + + switch (af) { +#ifdef INET + case AF_INET: + h4 = mtod(m, struct ip *); + len = ntohs(h4->ip_len) - off; + break; +#endif +#ifdef INET6 + case AF_INET6: + h6 = mtod(m, struct ip6_hdr *); + len = ntohs(h6->ip6_plen) - (off - sizeof(*h6)); + break; +#endif + } + + if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, af)) + REASON_SET(reason, PFRES_PROTCKSUM); + else { + if (th->th_flags & TH_SYN) + ack++; + if (th->th_flags & TH_FIN) + ack++; + pf_send_tcp(m, r, af, pd->dst, + pd->src, th->th_dport, th->th_sport, + ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, + r->return_ttl, 1, 0, kif->pfik_ifp); + } + } else if (pd->proto != IPPROTO_ICMP && af == AF_INET && + r->return_icmp) + pf_send_icmp(m, r->return_icmp >> 8, + r->return_icmp & 255, af, r); + else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 && + r->return_icmp6) + pf_send_icmp(m, r->return_icmp6 >> 8, + r->return_icmp6 & 255, af, r); +} + + static int pf_ieee8021q_setpcp(struct mbuf *m, u_int8_t prio) { @@ -3475,68 +3554,8 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, ((r->rule_flag & PFRULE_RETURNRST) || (r->rule_flag & PFRULE_RETURNICMP) || (r->rule_flag & PFRULE_RETURN))) { - /* undo NAT changes, if they have taken place */ - if (nr != NULL) { - PF_ACPY(saddr, &sk->addr[pd->sidx], af); - PF_ACPY(daddr, &sk->addr[pd->didx], af); - if (pd->sport) - *pd->sport = sk->port[pd->sidx]; - if (pd->dport) - *pd->dport = sk->port[pd->didx]; - if (pd->proto_sum) - *pd->proto_sum = bproto_sum; - if (pd->ip_sum) - *pd->ip_sum = bip_sum; - m_copyback(m, off, hdrlen, pd->hdr.any); - } - if (pd->proto == IPPROTO_TCP && - ((r->rule_flag & PFRULE_RETURNRST) || - (r->rule_flag & PFRULE_RETURN)) && - !(th->th_flags & TH_RST)) { - u_int32_t ack = ntohl(th->th_seq) + pd->p_len; - int len = 0; -#ifdef INET - struct ip *h4; -#endif -#ifdef INET6 - struct ip6_hdr *h6; -#endif - - switch (af) { -#ifdef INET - case AF_INET: - h4 = mtod(m, struct ip *); - len = ntohs(h4->ip_len) - off; - break; -#endif -#ifdef INET6 - case AF_INET6: - h6 = mtod(m, struct ip6_hdr *); - len = ntohs(h6->ip6_plen) - (off - sizeof(*h6)); - break; -#endif - } - - if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, af)) - REASON_SET(&reason, PFRES_PROTCKSUM); - else { - if (th->th_flags & TH_SYN) - ack++; - if (th->th_flags & TH_FIN) - ack++; - pf_send_tcp(m, r, af, pd->dst, - pd->src, th->th_dport, th->th_sport, - ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, - r->return_ttl, 1, 0, kif->pfik_ifp); - } - } else if (pd->proto != IPPROTO_ICMP && af == AF_INET && - r->return_icmp) - pf_send_icmp(m, r->return_icmp >> 8, - r->return_icmp & 255, af, r); - else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 && - r->return_icmp6) - pf_send_icmp(m, r->return_icmp6 >> 8, - r->return_icmp6 & 255, af, r); + pf_return(r, nr, pd, sk, off, m, th, kif, bproto_sum, + bip_sum, hdrlen, &reason); } if (r->action == PF_DROP) @@ -3555,8 +3574,13 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, action = pf_create_state(r, nr, a, pd, nsn, nk, sk, m, off, sport, dport, &rewrite, kif, sm, tag, bproto_sum, bip_sum, hdrlen); - if (action != PF_PASS) + if (action != PF_PASS) { + if (action == PF_DROP && + (r->rule_flag & PFRULE_RETURN)) + pf_return(r, nr, pd, sk, off, m, th, kif, + bproto_sum, bip_sum, hdrlen, &reason); return (action); + } } else { if (sk != NULL) uma_zfree(V_pf_state_key_z, sk); @@ -5454,7 +5478,7 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif, #ifdef INET static void pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, - struct pf_state *s, struct pf_pdesc *pd) + struct pf_state *s, struct pf_pdesc *pd, struct inpcb *inp) { struct mbuf *m0, *m1; struct sockaddr_in dst; @@ -5522,7 +5546,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, goto bad; if (oifp != ifp) { - if (pf_test(PF_OUT, 0, ifp, &m0, NULL) != PF_PASS) + if (pf_test(PF_OUT, 0, ifp, &m0, inp) != PF_PASS) goto bad; else if (m0 == NULL) goto done; @@ -5615,7 +5639,7 @@ bad: #ifdef INET6 static void pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, - struct pf_state *s, struct pf_pdesc *pd) + struct pf_state *s, struct pf_pdesc *pd, struct inpcb *inp) { struct mbuf *m0; struct sockaddr_in6 dst; @@ -5684,7 +5708,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, goto bad; if (oifp != ifp) { - if (pf_test6(PF_OUT, PFIL_FWD, ifp, &m0, NULL) != PF_PASS) + if (pf_test6(PF_OUT, PFIL_FWD, ifp, &m0, inp) != PF_PASS) goto bad; else if (m0 == NULL) goto done; @@ -6248,7 +6272,7 @@ done: default: /* pf_route() returns unlocked. */ if (r->rt) { - pf_route(m0, r, dir, kif->pfik_ifp, s, &pd); + pf_route(m0, r, dir, kif->pfik_ifp, s, &pd, inp); return (action); } break; @@ -6645,7 +6669,7 @@ done: default: /* pf_route6() returns unlocked. */ if (r->rt) { - pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd); + pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd, inp); return (action); } break; diff --git a/freebsd/sys/netpfil/pf/pf_altq.h b/freebsd/sys/netpfil/pf/pf_altq.h index f6d578d3..35d2d5cb 100644 --- a/freebsd/sys/netpfil/pf/pf_altq.h +++ b/freebsd/sys/netpfil/pf/pf_altq.h @@ -57,7 +57,7 @@ struct priq_opts { int flags; }; -struct hfsc_opts { +struct hfsc_opts_v0 { /* real-time service curve */ u_int rtsc_m1; /* slope of the 1st segment in bps */ u_int rtsc_d; /* the x-projection of m1 in msec */ @@ -73,6 +73,31 @@ struct hfsc_opts { int flags; }; +struct hfsc_opts_v1 { + /* real-time service curve */ + u_int64_t rtsc_m1; /* slope of the 1st segment in bps */ + u_int rtsc_d; /* the x-projection of m1 in msec */ + u_int64_t rtsc_m2; /* slope of the 2nd segment in bps */ + /* link-sharing service curve */ + u_int64_t lssc_m1; + u_int lssc_d; + u_int64_t lssc_m2; + /* upper-limit service curve */ + u_int64_t ulsc_m1; + u_int ulsc_d; + u_int64_t ulsc_m2; + int flags; +}; + +/* + * struct hfsc_opts doesn't have a version indicator macro or + * backwards-compat and convenience macros because both in the kernel and + * the pfctl parser, there are struct hfsc_opts instances named 'hfsc_opts'. + * It is believed that only in-tree code uses struct hfsc_opts, so + * backwards-compat macros are not necessary. The few in-tree uses can just + * be updated to the latest versioned struct tag. + */ + /* * XXX this needs some work */ @@ -87,11 +112,22 @@ struct fairq_opts { u_int lssc_m2; }; -struct pf_altq { +/* + * struct pf_altq_v0, struct pf_altq_v1, etc. are the ioctl argument + * structures corresponding to struct pfioc_altq_v0, struct pfioc_altq_v1, + * etc. + * + */ +struct pf_altq_v0 { char ifname[IFNAMSIZ]; - void *altq_disc; /* discipline-specific state */ - TAILQ_ENTRY(pf_altq) entries; + /* + * This member is a holdover from when the kernel state structure + * was reused as the ioctl argument structure, and remains to + * preserve the size and layout of this struct for backwards compat. + */ + void *unused1; + TAILQ_ENTRY(pf_altq_v0) entries; /* scheduler spec */ uint8_t scheduler; /* scheduler type */ @@ -113,11 +149,110 @@ struct pf_altq { struct cbq_opts cbq_opts; struct codel_opts codel_opts; struct priq_opts priq_opts; - struct hfsc_opts hfsc_opts; + struct hfsc_opts_v0 hfsc_opts; + struct fairq_opts fairq_opts; + } pq_u; + + uint32_t qid; /* return value */ +}; + +struct pf_altq_v1 { + char ifname[IFNAMSIZ]; + + TAILQ_ENTRY(pf_altq_v1) entries; + + /* scheduler spec */ + uint8_t scheduler; /* scheduler type */ + uint32_t tbrsize; /* tokenbucket regulator size */ + uint64_t ifbandwidth; /* interface bandwidth */ + + /* queue spec */ + char qname[PF_QNAME_SIZE]; /* queue name */ + char parent[PF_QNAME_SIZE]; /* parent name */ + uint32_t parent_qid; /* parent queue id */ + uint64_t bandwidth; /* queue bandwidth */ + uint8_t priority; /* priority */ + uint8_t local_flags; /* dynamic interface, see _v0 */ + + uint16_t qlimit; /* queue size limit */ + uint16_t flags; /* misc flags */ + union { + struct cbq_opts cbq_opts; + struct codel_opts codel_opts; + struct priq_opts priq_opts; + struct hfsc_opts_v1 hfsc_opts; struct fairq_opts fairq_opts; } pq_u; uint32_t qid; /* return value */ }; +/* Latest version of struct pf_altq_vX */ +#define PF_ALTQ_VERSION 1 + +#ifdef _KERNEL +struct pf_kaltq { + char ifname[IFNAMSIZ]; + + void *altq_disc; /* discipline-specific state */ + TAILQ_ENTRY(pf_kaltq) entries; + + /* scheduler spec */ + uint8_t scheduler; /* scheduler type */ + uint32_t tbrsize; /* tokenbucket regulator size */ + uint64_t ifbandwidth; /* interface bandwidth */ + + /* queue spec */ + char qname[PF_QNAME_SIZE]; /* queue name */ + char parent[PF_QNAME_SIZE]; /* parent name */ + uint32_t parent_qid; /* parent queue id */ + uint64_t bandwidth; /* queue bandwidth */ + uint8_t priority; /* priority */ + uint8_t local_flags; /* dynamic interface, see _v0 */ + + uint16_t qlimit; /* queue size limit */ + uint16_t flags; /* misc flags */ + union { + struct cbq_opts cbq_opts; + struct codel_opts codel_opts; + struct priq_opts priq_opts; + struct hfsc_opts_v1 hfsc_opts; + struct fairq_opts fairq_opts; + } pq_u; + + uint32_t qid; /* return value */ +}; +#endif /* _KERNEL */ + +/* + * Compatibility and convenience macros + */ +#ifdef _KERNEL +/* + * Avoid a patch with 100+ lines of name substitution. + */ +#define pf_altq pf_kaltq + +#else /* _KERNEL */ + +#ifdef PFIOC_USE_LATEST +/* + * Maintaining in-tree consumers of the ioctl interface is easier when that + * code can be written in terms old names that refer to the latest interface + * version as that reduces the required changes in the consumers to those + * that are functionally necessary to accommodate a new interface version. + */ +#define pf_altq __CONCAT(pf_altq_v, PF_ALTQ_VERSION) + +#else /* PFIOC_USE_LATEST */ +/* + * When building out-of-tree code that is written for the old interface, + * such as may exist in ports for example, resolve the old pf_altq struct + * tag to the v0 version. + */ +#define pf_altq __CONCAT(pf_altq_v, 0) + +#endif /* PFIOC_USE_LATEST */ +#endif /* _KERNEL */ + #endif /* _NET_PF_ALTQ_H_ */ diff --git a/freebsd/sys/netpfil/pf/pf_if.c b/freebsd/sys/netpfil/pf/pf_if.c index 2ac76ff2..2c321118 100644 --- a/freebsd/sys/netpfil/pf/pf_if.c +++ b/freebsd/sys/netpfil/pf/pf_if.c @@ -57,16 +57,16 @@ __FBSDID("$FreeBSD$"); #include <net/route.h> VNET_DEFINE(struct pfi_kif *, pfi_all); -static VNET_DEFINE(long, pfi_update); +VNET_DEFINE_STATIC(long, pfi_update); #define V_pfi_update VNET(pfi_update) #define PFI_BUFFER_MAX 0x10000 VNET_DECLARE(int, pf_vnet_active); #define V_pf_vnet_active VNET(pf_vnet_active) -static VNET_DEFINE(struct pfr_addr *, pfi_buffer); -static VNET_DEFINE(int, pfi_buffer_cnt); -static VNET_DEFINE(int, pfi_buffer_max); +VNET_DEFINE_STATIC(struct pfr_addr *, pfi_buffer); +VNET_DEFINE_STATIC(int, pfi_buffer_cnt); +VNET_DEFINE_STATIC(int, pfi_buffer_max); #define V_pfi_buffer VNET(pfi_buffer) #define V_pfi_buffer_cnt VNET(pfi_buffer_cnt) #define V_pfi_buffer_max VNET(pfi_buffer_max) @@ -100,14 +100,14 @@ static void pfi_ifaddr_event(void * __unused, struct ifnet *); RB_HEAD(pfi_ifhead, pfi_kif); static RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); static RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); -static VNET_DEFINE(struct pfi_ifhead, pfi_ifs); +VNET_DEFINE_STATIC(struct pfi_ifhead, pfi_ifs); #define V_pfi_ifs VNET(pfi_ifs) #define PFI_BUFFER_MAX 0x10000 MALLOC_DEFINE(PFI_MTYPE, "pf_ifnet", "pf(4) interface database"); LIST_HEAD(pfi_list, pfi_kif); -static VNET_DEFINE(struct pfi_list, pfi_unlinked_kifs); +VNET_DEFINE_STATIC(struct pfi_list, pfi_unlinked_kifs); #define V_pfi_unlinked_kifs VNET(pfi_unlinked_kifs) static struct mtx pfi_unlnkdkifs_mtx; MTX_SYSINIT(pfi_unlnkdkifs_mtx, &pfi_unlnkdkifs_mtx, "pf unlinked interfaces", @@ -299,11 +299,16 @@ pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif) if (rule_kif == NULL || rule_kif == packet_kif) return (1); - if (rule_kif->pfik_group != NULL) - /* XXXGL: locking? */ + if (rule_kif->pfik_group != NULL) { + IF_ADDR_RLOCK(packet_kif->pfik_ifp); CK_STAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next) - if (p->ifgl_group == rule_kif->pfik_group) + if (p->ifgl_group == rule_kif->pfik_group) { + IF_ADDR_RUNLOCK(packet_kif->pfik_ifp); return (1); + } + IF_ADDR_RUNLOCK(packet_kif->pfik_ifp); + } + return (0); } @@ -737,6 +742,7 @@ pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) static int pfi_skip_if(const char *filter, struct pfi_kif *p) { + struct ifg_list *i; int n; if (filter == NULL || !*filter) @@ -747,10 +753,19 @@ pfi_skip_if(const char *filter, struct pfi_kif *p) if (n < 1 || n >= IFNAMSIZ) return (1); /* sanity check */ if (filter[n-1] >= '0' && filter[n-1] <= '9') - return (1); /* only do exact match in that case */ - if (strncmp(p->pfik_name, filter, n)) - return (1); /* prefix doesn't match */ - return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9'); + return (1); /* group names may not end in a digit */ + if (p->pfik_ifp != NULL) { + IF_ADDR_RLOCK(p->pfik_ifp); + CK_STAILQ_FOREACH(i, &p->pfik_ifp->if_groups, ifgl_next) { + if (!strncmp(i->ifgl_group->ifg_group, filter, + IFNAMSIZ)) { + IF_ADDR_RUNLOCK(p->pfik_ifp); + return (0); /* iface is in group "filter" */ + } + } + IF_ADDR_RUNLOCK(p->pfik_ifp); + } + return (1); } int diff --git a/freebsd/sys/netpfil/pf/pf_ioctl.c b/freebsd/sys/netpfil/pf/pf_ioctl.c index 837ad31c..9ca15a41 100644 --- a/freebsd/sys/netpfil/pf/pf_ioctl.c +++ b/freebsd/sys/netpfil/pf/pf_ioctl.c @@ -115,11 +115,17 @@ static int pf_commit_rules(u_int32_t, int, char *); static int pf_addr_setup(struct pf_ruleset *, struct pf_addr_wrap *, sa_family_t); static void pf_addr_copyout(struct pf_addr_wrap *); +#ifdef ALTQ +static int pf_export_kaltq(struct pf_altq *, + struct pfioc_altq_v1 *, size_t); +static int pf_import_kaltq(struct pfioc_altq_v1 *, + struct pf_altq *, size_t); +#endif /* ALTQ */ VNET_DEFINE(struct pf_rule, pf_default_rule); #ifdef ALTQ -static VNET_DEFINE(int, pf_altq_running); +VNET_DEFINE_STATIC(int, pf_altq_running); #define V_pf_altq_running VNET(pf_altq_running) #endif @@ -189,7 +195,7 @@ static struct cdevsw pf_cdevsw = { .d_version = D_VERSION, }; -static volatile VNET_DEFINE(int, pf_pfil_hooked); +volatile VNET_DEFINE_STATIC(int, pf_pfil_hooked); #define V_pf_pfil_hooked VNET(pf_pfil_hooked) /* @@ -992,6 +998,222 @@ pf_addr_copyout(struct pf_addr_wrap *addr) } } +#ifdef ALTQ +/* + * Handle export of struct pf_kaltq to user binaries that may be using any + * version of struct pf_altq. + */ +static int +pf_export_kaltq(struct pf_altq *q, struct pfioc_altq_v1 *pa, size_t ioc_size) +{ + u_int32_t version; + + if (ioc_size == sizeof(struct pfioc_altq_v0)) + version = 0; + else + version = pa->version; + + if (version > PFIOC_ALTQ_VERSION) + return (EINVAL); + +#define ASSIGN(x) exported_q->x = q->x +#define COPY(x) \ + bcopy(&q->x, &exported_q->x, min(sizeof(q->x), sizeof(exported_q->x))) +#define SATU16(x) (u_int32_t)uqmin((x), USHRT_MAX) +#define SATU32(x) (u_int32_t)uqmin((x), UINT_MAX) + + switch (version) { + case 0: { + struct pf_altq_v0 *exported_q = + &((struct pfioc_altq_v0 *)pa)->altq; + + COPY(ifname); + + ASSIGN(scheduler); + ASSIGN(tbrsize); + exported_q->tbrsize = SATU16(q->tbrsize); + exported_q->ifbandwidth = SATU32(q->ifbandwidth); + + COPY(qname); + COPY(parent); + ASSIGN(parent_qid); + exported_q->bandwidth = SATU32(q->bandwidth); + ASSIGN(priority); + ASSIGN(local_flags); + + ASSIGN(qlimit); + ASSIGN(flags); + + if (q->scheduler == ALTQT_HFSC) { +#define ASSIGN_OPT(x) exported_q->pq_u.hfsc_opts.x = q->pq_u.hfsc_opts.x +#define ASSIGN_OPT_SATU32(x) exported_q->pq_u.hfsc_opts.x = \ + SATU32(q->pq_u.hfsc_opts.x) + + ASSIGN_OPT_SATU32(rtsc_m1); + ASSIGN_OPT(rtsc_d); + ASSIGN_OPT_SATU32(rtsc_m2); + + ASSIGN_OPT_SATU32(lssc_m1); + ASSIGN_OPT(lssc_d); + ASSIGN_OPT_SATU32(lssc_m2); + + ASSIGN_OPT_SATU32(ulsc_m1); + ASSIGN_OPT(ulsc_d); + ASSIGN_OPT_SATU32(ulsc_m2); + + ASSIGN_OPT(flags); + +#undef ASSIGN_OPT +#undef ASSIGN_OPT_SATU32 + } else + COPY(pq_u); + + ASSIGN(qid); + break; + } + case 1: { + struct pf_altq_v1 *exported_q = + &((struct pfioc_altq_v1 *)pa)->altq; + + COPY(ifname); + + ASSIGN(scheduler); + ASSIGN(tbrsize); + ASSIGN(ifbandwidth); + + COPY(qname); + COPY(parent); + ASSIGN(parent_qid); + ASSIGN(bandwidth); + ASSIGN(priority); + ASSIGN(local_flags); + + ASSIGN(qlimit); + ASSIGN(flags); + COPY(pq_u); + + ASSIGN(qid); + break; + } + default: + panic("%s: unhandled struct pfioc_altq version", __func__); + break; + } + +#undef ASSIGN +#undef COPY +#undef SATU16 +#undef SATU32 + + return (0); +} + +/* + * Handle import to struct pf_kaltq of struct pf_altq from user binaries + * that may be using any version of it. + */ +static int +pf_import_kaltq(struct pfioc_altq_v1 *pa, struct pf_altq *q, size_t ioc_size) +{ + u_int32_t version; + + if (ioc_size == sizeof(struct pfioc_altq_v0)) + version = 0; + else + version = pa->version; + + if (version > PFIOC_ALTQ_VERSION) + return (EINVAL); + +#define ASSIGN(x) q->x = imported_q->x +#define COPY(x) \ + bcopy(&imported_q->x, &q->x, min(sizeof(imported_q->x), sizeof(q->x))) + + switch (version) { + case 0: { + struct pf_altq_v0 *imported_q = + &((struct pfioc_altq_v0 *)pa)->altq; + + COPY(ifname); + + ASSIGN(scheduler); + ASSIGN(tbrsize); /* 16-bit -> 32-bit */ + ASSIGN(ifbandwidth); /* 32-bit -> 64-bit */ + + COPY(qname); + COPY(parent); + ASSIGN(parent_qid); + ASSIGN(bandwidth); /* 32-bit -> 64-bit */ + ASSIGN(priority); + ASSIGN(local_flags); + + ASSIGN(qlimit); + ASSIGN(flags); + + if (imported_q->scheduler == ALTQT_HFSC) { +#define ASSIGN_OPT(x) q->pq_u.hfsc_opts.x = imported_q->pq_u.hfsc_opts.x + + /* + * The m1 and m2 parameters are being copied from + * 32-bit to 64-bit. + */ + ASSIGN_OPT(rtsc_m1); + ASSIGN_OPT(rtsc_d); + ASSIGN_OPT(rtsc_m2); + + ASSIGN_OPT(lssc_m1); + ASSIGN_OPT(lssc_d); + ASSIGN_OPT(lssc_m2); + + ASSIGN_OPT(ulsc_m1); + ASSIGN_OPT(ulsc_d); + ASSIGN_OPT(ulsc_m2); + + ASSIGN_OPT(flags); + +#undef ASSIGN_OPT + } else + COPY(pq_u); + + ASSIGN(qid); + break; + } + case 1: { + struct pf_altq_v1 *imported_q = + &((struct pfioc_altq_v1 *)pa)->altq; + + COPY(ifname); + + ASSIGN(scheduler); + ASSIGN(tbrsize); + ASSIGN(ifbandwidth); + + COPY(qname); + COPY(parent); + ASSIGN(parent_qid); + ASSIGN(bandwidth); + ASSIGN(priority); + ASSIGN(local_flags); + + ASSIGN(qlimit); + ASSIGN(flags); + COPY(pq_u); + + ASSIGN(qid); + break; + } + default: + panic("%s: unhandled struct pfioc_altq version", __func__); + break; + } + +#undef ASSIGN +#undef COPY + + return (0); +} +#endif /* ALTQ */ + static int pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) { @@ -1015,9 +1237,12 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td case DIOCGETTIMEOUT: case DIOCCLRRULECTRS: case DIOCGETLIMIT: - case DIOCGETALTQS: - case DIOCGETALTQ: - case DIOCGETQSTATS: + case DIOCGETALTQSV0: + case DIOCGETALTQSV1: + case DIOCGETALTQV0: + case DIOCGETALTQV1: + case DIOCGETQSTATSV0: + case DIOCGETQSTATSV1: case DIOCGETRULESETS: case DIOCGETRULESET: case DIOCRGETTABLES: @@ -1035,7 +1260,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td case DIOCGETSRCNODES: case DIOCCLRSRCNODES: case DIOCIGETIFACES: - case DIOCGIFSPEED: + case DIOCGIFSPEEDV0: + case DIOCGIFSPEEDV1: case DIOCSETIFFLAG: case DIOCCLRIFFLAG: break; @@ -1061,9 +1287,12 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td case DIOCGETSTATES: case DIOCGETTIMEOUT: case DIOCGETLIMIT: - case DIOCGETALTQS: - case DIOCGETALTQ: - case DIOCGETQSTATS: + case DIOCGETALTQSV0: + case DIOCGETALTQSV1: + case DIOCGETALTQV0: + case DIOCGETALTQV1: + case DIOCGETQSTATSV0: + case DIOCGETQSTATSV1: case DIOCGETRULESETS: case DIOCGETRULESET: case DIOCNATLOOK: @@ -1075,7 +1304,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td case DIOCOSFPGET: case DIOCGETSRCNODES: case DIOCIGETIFACES: - case DIOCGIFSPEED: + case DIOCGIFSPEEDV1: + case DIOCGIFSPEEDV0: break; case DIOCRCLRTABLES: case DIOCRADDTABLES: @@ -2013,18 +2243,22 @@ DIOCGETSTATES_full: break; } - case DIOCGIFSPEED: { - struct pf_ifspeed *psp = (struct pf_ifspeed *)addr; - struct pf_ifspeed ps; + case DIOCGIFSPEEDV0: + case DIOCGIFSPEEDV1: { + struct pf_ifspeed_v1 *psp = (struct pf_ifspeed_v1 *)addr; + struct pf_ifspeed_v1 ps; struct ifnet *ifp; if (psp->ifname[0] != 0) { /* Can we completely trust user-land? */ strlcpy(ps.ifname, psp->ifname, IFNAMSIZ); ifp = ifunit(ps.ifname); - if (ifp != NULL) - psp->baudrate = ifp->if_baudrate; - else + if (ifp != NULL) { + psp->baudrate32 = + (u_int32_t)uqmin(ifp->if_baudrate, UINT_MAX); + if (cmd == DIOCGIFSPEEDV1) + psp->baudrate = ifp->if_baudrate; + } else error = EINVAL; } else error = EINVAL; @@ -2072,13 +2306,16 @@ DIOCGETSTATES_full: break; } - case DIOCADDALTQ: { - struct pfioc_altq *pa = (struct pfioc_altq *)addr; + case DIOCADDALTQV0: + case DIOCADDALTQV1: { + struct pfioc_altq_v1 *pa = (struct pfioc_altq_v1 *)addr; struct pf_altq *altq, *a; struct ifnet *ifp; - altq = malloc(sizeof(*altq), M_PFALTQ, M_WAITOK); - bcopy(&pa->altq, altq, sizeof(struct pf_altq)); + altq = malloc(sizeof(*altq), M_PFALTQ, M_WAITOK | M_ZERO); + error = pf_import_kaltq(pa, altq, IOCPARM_LEN(cmd)); + if (error) + break; altq->local_flags = 0; PF_RULES_WLOCK(); @@ -2122,13 +2359,15 @@ DIOCGETSTATES_full: } TAILQ_INSERT_TAIL(V_pf_altqs_inactive, altq, entries); - bcopy(altq, &pa->altq, sizeof(struct pf_altq)); + /* version error check done on import above */ + pf_export_kaltq(altq, pa, IOCPARM_LEN(cmd)); PF_RULES_WUNLOCK(); break; } - case DIOCGETALTQS: { - struct pfioc_altq *pa = (struct pfioc_altq *)addr; + case DIOCGETALTQSV0: + case DIOCGETALTQSV1: { + struct pfioc_altq_v1 *pa = (struct pfioc_altq_v1 *)addr; struct pf_altq *altq; PF_RULES_RLOCK(); @@ -2140,8 +2379,9 @@ DIOCGETSTATES_full: break; } - case DIOCGETALTQ: { - struct pfioc_altq *pa = (struct pfioc_altq *)addr; + case DIOCGETALTQV0: + case DIOCGETALTQV1: { + struct pfioc_altq_v1 *pa = (struct pfioc_altq_v1 *)addr; struct pf_altq *altq; u_int32_t nr; @@ -2162,21 +2402,24 @@ DIOCGETSTATES_full: error = EBUSY; break; } - bcopy(altq, &pa->altq, sizeof(struct pf_altq)); + pf_export_kaltq(altq, pa, IOCPARM_LEN(cmd)); PF_RULES_RUNLOCK(); break; } - case DIOCCHANGEALTQ: + case DIOCCHANGEALTQV0: + case DIOCCHANGEALTQV1: /* CHANGEALTQ not supported yet! */ error = ENODEV; break; - case DIOCGETQSTATS: { - struct pfioc_qstats *pq = (struct pfioc_qstats *)addr; + case DIOCGETQSTATSV0: + case DIOCGETQSTATSV1: { + struct pfioc_qstats_v1 *pq = (struct pfioc_qstats_v1 *)addr; struct pf_altq *altq; u_int32_t nr; int nbytes; + u_int32_t version; PF_RULES_RLOCK(); if (pq->ticket != V_ticket_altqs_active) { @@ -2203,7 +2446,11 @@ DIOCGETSTATES_full: break; } PF_RULES_RUNLOCK(); - error = altq_getqstats(altq, pq->buf, &nbytes); + if (cmd == DIOCGETQSTATSV0) + version = 0; /* DIOCGETQSTATSV0 means stats struct v0 */ + else + version = pq->version; + error = altq_getqstats(altq, pq->buf, &nbytes, version); if (error == 0) { pq->scheduler = altq->scheduler; pq->nbytes = nbytes; @@ -3963,7 +4210,6 @@ pf_unload_vnet(void) V_pf_vnet_active = 0; V_pf_status.running = 0; - swi_remove(V_pf_swi_cookie); error = dehook_pf(); if (error) { /* @@ -3979,6 +4225,8 @@ pf_unload_vnet(void) shutdown_pf(); PF_RULES_WUNLOCK(); + swi_remove(V_pf_swi_cookie); + pf_unload_vnet_purge(); pf_normalize_cleanup(); diff --git a/freebsd/sys/netpfil/pf/pf_norm.c b/freebsd/sys/netpfil/pf/pf_norm.c index 61da5e4f..0f98c669 100644 --- a/freebsd/sys/netpfil/pf/pf_norm.c +++ b/freebsd/sys/netpfil/pf/pf_norm.c @@ -93,8 +93,10 @@ struct pf_fragment { TAILQ_ENTRY(pf_fragment) frag_next; uint32_t fr_timeout; uint16_t fr_maxlen; /* maximum length of single fragment */ + uint16_t fr_entries; /* Total number of pf_fragment entries */ TAILQ_HEAD(pf_fragq, pf_frent) fr_queue; }; +#define PF_MAX_FRENT_PER_FRAGMENT 64 struct pf_fragment_tag { uint16_t ft_hdrlen; /* header length of reassembled pkt */ @@ -111,17 +113,17 @@ MTX_SYSINIT(pf_frag_mtx, &pf_frag_mtx, "pf fragments", MTX_DEF); VNET_DEFINE(uma_zone_t, pf_state_scrub_z); /* XXX: shared with pfsync */ -static VNET_DEFINE(uma_zone_t, pf_frent_z); +VNET_DEFINE_STATIC(uma_zone_t, pf_frent_z); #define V_pf_frent_z VNET(pf_frent_z) -static VNET_DEFINE(uma_zone_t, pf_frag_z); +VNET_DEFINE_STATIC(uma_zone_t, pf_frag_z); #define V_pf_frag_z VNET(pf_frag_z) TAILQ_HEAD(pf_fragqueue, pf_fragment); TAILQ_HEAD(pf_cachequeue, pf_fragment); -static VNET_DEFINE(struct pf_fragqueue, pf_fragqueue); +VNET_DEFINE_STATIC(struct pf_fragqueue, pf_fragqueue); #define V_pf_fragqueue VNET(pf_fragqueue) RB_HEAD(pf_frag_tree, pf_fragment); -static VNET_DEFINE(struct pf_frag_tree, pf_frag_tree); +VNET_DEFINE_STATIC(struct pf_frag_tree, pf_frag_tree); #define V_pf_frag_tree VNET(pf_frag_tree) static int pf_frag_compare(struct pf_fragment *, struct pf_fragment *); @@ -386,6 +388,7 @@ pf_fillup_fragment(struct pf_fragment_cmp *key, struct pf_frent *frent, *(struct pf_fragment_cmp *)frag = *key; frag->fr_timeout = time_uptime; frag->fr_maxlen = frent->fe_len; + frag->fr_entries = 0; TAILQ_INIT(&frag->fr_queue); RB_INSERT(pf_frag_tree, &V_pf_frag_tree, frag); @@ -397,6 +400,9 @@ pf_fillup_fragment(struct pf_fragment_cmp *key, struct pf_frent *frent, return (frag); } + if (frag->fr_entries >= PF_MAX_FRENT_PER_FRAGMENT) + goto bad_fragment; + KASSERT(!TAILQ_EMPTY(&frag->fr_queue), ("!TAILQ_EMPTY()->fr_queue")); /* Remember maximum fragment len for refragmentation. */ @@ -469,6 +475,8 @@ pf_fillup_fragment(struct pf_fragment_cmp *key, struct pf_frent *frent, else TAILQ_INSERT_AFTER(&frag->fr_queue, prev, frent, fr_next); + frag->fr_entries++; + return (frag); bad_fragment: diff --git a/freebsd/sys/netpfil/pf/pf_osfp.c b/freebsd/sys/netpfil/pf/pf_osfp.c index b87d39bd..8723830c 100644 --- a/freebsd/sys/netpfil/pf/pf_osfp.c +++ b/freebsd/sys/netpfil/pf/pf_osfp.c @@ -49,7 +49,7 @@ static MALLOC_DEFINE(M_PFOSFP, "pf_osfp", "pf(4) operating system fingerprints") printf(format , ##x) SLIST_HEAD(pf_osfp_list, pf_os_fingerprint); -static VNET_DEFINE(struct pf_osfp_list, pf_osfp_list) = +VNET_DEFINE_STATIC(struct pf_osfp_list, pf_osfp_list) = SLIST_HEAD_INITIALIZER(); #define V_pf_osfp_list VNET(pf_osfp_list) diff --git a/freebsd/sys/netpfil/pf/pf_table.c b/freebsd/sys/netpfil/pf/pf_table.c index 04a275d9..1fadd38c 100644 --- a/freebsd/sys/netpfil/pf/pf_table.c +++ b/freebsd/sys/netpfil/pf/pf_table.c @@ -124,9 +124,9 @@ struct pfr_walktree { #define senderr(e) do { rv = (e); goto _bad; } while (0) static MALLOC_DEFINE(M_PFTABLE, "pf_table", "pf(4) tables structures"); -static VNET_DEFINE(uma_zone_t, pfr_kentry_z); +VNET_DEFINE_STATIC(uma_zone_t, pfr_kentry_z); #define V_pfr_kentry_z VNET(pfr_kentry_z) -static VNET_DEFINE(uma_zone_t, pfr_kcounters_z); +VNET_DEFINE_STATIC(uma_zone_t, pfr_kcounters_z); #define V_pfr_kcounters_z VNET(pfr_kcounters_z) static struct pf_addr pfr_ffaddr = { @@ -186,13 +186,13 @@ static struct pfr_kentry static RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); static RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare); -static VNET_DEFINE(struct pfr_ktablehead, pfr_ktables); +VNET_DEFINE_STATIC(struct pfr_ktablehead, pfr_ktables); #define V_pfr_ktables VNET(pfr_ktables) -static VNET_DEFINE(struct pfr_table, pfr_nulltable); +VNET_DEFINE_STATIC(struct pfr_table, pfr_nulltable); #define V_pfr_nulltable VNET(pfr_nulltable) -static VNET_DEFINE(int, pfr_ktable_cnt); +VNET_DEFINE_STATIC(int, pfr_ktable_cnt); #define V_pfr_ktable_cnt VNET(pfr_ktable_cnt) void |