FreeBSD Bugzilla – Attachment 201346 Details for
Bug 229092
[pf] [pfsync] States created by route-to rules pfsynced without interface
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Reconstruct interface route by standard fib lookup
reconstruct_rt_kif_from_route.diff (text/plain), 12.99 KB, created by
Kajetan Staszkiewicz
on 2019-01-22 22:56:15 UTC
(
hide
)
Description:
Reconstruct interface route by standard fib lookup
Filename:
MIME Type:
Creator:
Kajetan Staszkiewicz
Created:
2019-01-22 22:56:15 UTC
Size:
12.99 KB
patch
obsolete
>diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h >index ea0d55f9010..5bf5640cb6e 100644 >--- a/sys/net/pfvar.h >+++ b/sys/net/pfvar.h >@@ -743,21 +743,22 @@ struct pf_state { > /* was PFSTATE_PFLOW 0x04 */ > #define PFSTATE_NOSYNC 0x08 > #define PFSTATE_ACK 0x10 > #define PFSTATE_SETPRIO 0x0200 > #define PFSTATE_SETMASK (PFSTATE_SETPRIO) > u_int8_t timeout; > u_int8_t sync_state; /* PFSYNC_S_x */ > > /* XXX */ > u_int8_t sync_updates; >- u_int8_t _tail[3]; >+ u_int8_t rt; >+ u_int8_t _tail[2]; > }; > > /* > * Unified state structures for pulling states out of the kernel > * used by pfsync(4) and the pf(4) ioctl. > */ > struct pfsync_state_scrub { > u_int16_t pfss_flags; > u_int8_t pfss_ttl; /* stashed TTL */ > #define PFSYNC_SCRUB_FLAG_VALID 0x01 >@@ -793,21 +794,22 @@ struct pfsync_state { > u_int32_t anchor; > u_int32_t nat_rule; > u_int32_t creation; > u_int32_t expire; > u_int32_t packets[2][2]; > u_int32_t bytes[2][2]; > u_int32_t creatorid; > sa_family_t af; > u_int8_t proto; > u_int8_t direction; >- u_int8_t __spare[2]; >+ u_int8_t rt; >+ u_int8_t __spare[1]; > u_int8_t log; > u_int8_t state_flags; > u_int8_t timeout; > u_int8_t sync_flags; > u_int8_t updates; > } __packed; > > #ifdef _KERNEL > /* pfsync */ > typedef int pfsync_state_import_t(struct pfsync_state *, u_int8_t); >diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c >index c46688217d4..9e23fbd17b2 100644 >--- a/sys/netpfil/pf/if_pfsync.c >+++ b/sys/netpfil/pf/if_pfsync.c >@@ -92,20 +92,27 @@ __FBSDID("$FreeBSD$"); > #include <netinet/if_ether.h> > #include <netinet/in.h> > #include <netinet/in_var.h> > #include <netinet/ip.h> > #include <netinet/ip_carp.h> > #include <netinet/ip_var.h> > #include <netinet/tcp.h> > #include <netinet/tcp_fsm.h> > #include <netinet/tcp_seq.h> > >+#ifdef INET >+#include <netinet/in_fib.h> >+#endif >+#ifdef INET6 >+#include <netinet6/in6_fib.h> >+#endif >+ > #define PFSYNC_MINPKT ( \ > sizeof(struct ip) + \ > sizeof(struct pfsync_header) + \ > sizeof(struct pfsync_subheader) ) > > struct pfsync_pkt { > struct ip *ip; > struct in_addr src; > u_int8_t flags; > }; >@@ -405,20 +412,26 @@ pfsync_state_import(struct pfsync_state *sp, u_int8_t flags) > struct pfsync_softc *sc = V_pfsyncif; > #ifndef __NO_STRICT_ALIGNMENT > struct pfsync_state_key key[2]; > #endif > struct pfsync_state_key *kw, *ks; > struct pf_state *st = NULL; > struct pf_state_key *skw = NULL, *sks = NULL; > struct pf_rule *r = NULL; > struct pfi_kif *kif; > int error; >+#ifdef INET >+ struct nhop4_basic nh4; >+#endif >+#ifdef INET6 >+ struct nhop6_basic nh6; >+#endif > > PF_RULES_RASSERT(); > > if (sp->creatorid == 0) { > if (V_pf_status.debug >= PF_DEBUG_MISC) > printf("%s: invalid creator id: %08x\n", __func__, > ntohl(sp->creatorid)); > return (EINVAL); > } > >@@ -508,31 +521,50 @@ pfsync_state_import(struct pfsync_state *sp, u_int8_t flags) > timeout = V_pf_default_rule.timeout[sp->timeout]; > > /* sp->expire may have been adaptively scaled by export. */ > st->expire -= timeout - ntohl(sp->expire); > } > > st->direction = sp->direction; > st->log = sp->log; > st->timeout = sp->timeout; > st->state_flags = sp->state_flags; >+ st->rt = sp->rt; > > st->id = sp->id; > st->creatorid = sp->creatorid; > pf_state_peer_ntoh(&sp->src, &st->src); > pf_state_peer_ntoh(&sp->dst, &st->dst); > > st->rule.ptr = r; > st->nat_rule.ptr = NULL; > st->anchor.ptr = NULL; > st->rt_kif = NULL; > >+ if (st->rt) { >+ /* Do our best to reconstruct original route-to interface. */ >+ switch (sp->af) { >+#ifdef INET >+ case AF_INET: >+ fib4_lookup_nh_basic(0, st->rt_addr.v4, 0, 0, &nh4); >+ st->rt_kif = pfi_kif_find(nh4.nh_ifp->if_xname); >+ break; >+#endif >+#ifdef INET6 >+ case AF_INET6: >+ fib6_lookup_nh_basic(0, &(st->rt_addr.v6), 0, 0, 0, &nh6); >+ st->rt_kif = pfi_kif_find(nh6.nh_ifp->if_xname); >+ break; >+#endif >+ } >+ } >+ > st->pfsync_time = time_uptime; > st->sync_state = PFSYNC_S_NONE; > > if (!(flags & PFSYNC_SI_IOCTL)) > st->state_flags |= PFSTATE_NOSYNC; > > if ((error = pf_state_insert(kif, skw, sks, st)) != 0) > goto cleanup_state; > > /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ >diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c >index b7dbd1e8685..97f8f1665b2 100644 >--- a/sys/netpfil/pf/pf.c >+++ b/sys/netpfil/pf/pf.c >@@ -3704,20 +3704,21 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, > > if (r->rt) { > if (pf_map_addr(pd->af, r, pd->src, &s->rt_addr, NULL, &sn)) { > REASON_SET(&reason, PFRES_MAPFAILED); > pf_src_tree_remove_state(s); > STATE_DEC_COUNTERS(s); > uma_zfree(V_pf_state_z, s); > goto csfailed; > } > s->rt_kif = r->rpool.cur->kif; >+ s->rt = r->rt; > } > > s->creation = time_uptime; > s->expire = time_uptime; > > if (sn != NULL) > s->src_node = sn; > if (nsn != NULL) { > /* XXX We only modify one side for now. */ > PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af); >@@ -5456,74 +5457,85 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif, > return (0); > > /* Perform uRPF check if passed input interface */ > if (kif->pfik_ifp == ifp) > return (1); > return (0); > } > > #ifdef INET > static void >-pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, >+pf_route(struct mbuf **m, struct pf_rule * r, int p_dir, struct ifnet *oifp, > struct pf_state *s, struct pf_pdesc *pd, struct inpcb *inp) > { > struct mbuf *m0, *m1; > struct sockaddr_in dst; > struct ip *ip; > struct ifnet *ifp = NULL; > struct pf_addr naddr; > struct pf_src_node *sn = NULL; > int error = 0; > uint16_t ip_len, ip_off; >+ int r_rt, r_dir; > > KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__)); >- KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: invalid direction", >+ >+ if (s) { >+ r_rt = s->rt; >+ r_dir = s->direction; >+ } else { >+ r_rt = r->rt; >+ r_dir = r->direction; >+ } >+ >+ KASSERT(p_dir == PF_IN || p_dir == PF_OUT || >+ r_dir = PF_IN || r_dir == PF_OUT, ("%s: invalid direction", > __func__)); > > if ((pd->pf_mtag == NULL && > ((pd->pf_mtag = pf_get_mtag(*m)) == NULL)) || > pd->pf_mtag->routed++ > 3) { > m0 = *m; > *m = NULL; > goto bad_locked; > } > >- if (r->rt == PF_DUPTO) { >+ if (r_rt == PF_DUPTO) { > if ((m0 = m_dup(*m, M_NOWAIT)) == NULL) { > if (s) > PF_STATE_UNLOCK(s); > return; > } > } else { >- if ((r->rt == PF_REPLYTO) == (r->direction == dir)) { >+ if ((r_rt == PF_REPLYTO) == (r_dir == p_dir)) { > if (s) > PF_STATE_UNLOCK(s); > return; > } > m0 = *m; > } > > ip = mtod(m0, struct ip *); > > bzero(&dst, sizeof(dst)); > dst.sin_family = AF_INET; > dst.sin_len = sizeof(dst); > dst.sin_addr = ip->ip_dst; > > bzero(&naddr, sizeof(naddr)); > >- if (TAILQ_EMPTY(&r->rpool.list)) { >- DPFPRINTF(PF_DEBUG_URGENT, >- ("%s: TAILQ_EMPTY(&r->rpool.list)\n", __func__)); >- goto bad_locked; >- } > if (s == NULL) { >+ if (TAILQ_EMPTY(&r->rpool.list)) { >+ DPFPRINTF(PF_DEBUG_URGENT, >+ ("%s: TAILQ_EMPTY(&r->rpool.list)\n", __func__)); >+ goto bad_locked; >+ } > pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src, > &naddr, NULL, &sn); > if (!PF_AZERO(&naddr, AF_INET)) > dst.sin_addr.s_addr = naddr.v4.s_addr; > ifp = r->rpool.cur->kif ? > r->rpool.cur->kif->pfik_ifp : NULL; > } else { > if (!PF_AZERO(&s->rt_addr, AF_INET)) > dst.sin_addr.s_addr = > s->rt_addr.v4.s_addr; >@@ -5578,21 +5590,21 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, > } > m_clrprotoflags(m0); /* Avoid confusing lower layers. */ > error = (*ifp->if_output)(ifp, m0, sintosa(&dst), NULL); > goto done; > } > > /* Balk when DF bit is set or the interface didn't support TSO. */ > if ((ip_off & IP_DF) || (m0->m_pkthdr.csum_flags & CSUM_TSO)) { > error = EMSGSIZE; > KMOD_IPSTAT_INC(ips_cantfrag); >- if (r->rt != PF_DUPTO) { >+ if (r_rt != PF_DUPTO) { > icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, > ifp->if_mtu); > goto done; > } else > goto bad; > } > > error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist); > if (error) > goto bad; >@@ -5604,87 +5616,98 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, > m_clrprotoflags(m0); > error = (*ifp->if_output)(ifp, m0, sintosa(&dst), NULL); > } else > m_freem(m0); > } > > if (error == 0) > KMOD_IPSTAT_INC(ips_fragmented); > > done: >- if (r->rt != PF_DUPTO) >+ if (r_rt != PF_DUPTO) > *m = NULL; > return; > > bad_locked: > if (s) > PF_STATE_UNLOCK(s); > bad: > m_freem(m0); > goto done; > } > #endif /* INET */ > > #ifdef INET6 > static void >-pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, >+pf_route6(struct mbuf **m, struct pf_rule * r, int p_dir, struct ifnet *oifp, > struct pf_state *s, struct pf_pdesc *pd, struct inpcb *inp) > { > struct mbuf *m0; > struct sockaddr_in6 dst; > struct ip6_hdr *ip6; > struct ifnet *ifp = NULL; > struct pf_addr naddr; > struct pf_src_node *sn = NULL; >+ int r_rt, r_dir; > > KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__)); >- KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: invalid direction", >+ >+ if (s) { >+ r_rt = s->rt; >+ r_dir = s->direction; >+ } else { >+ r_rt = r->rt; >+ r_dir = r->direction; >+ } >+ >+ KASSERT(p_dir == PF_IN || p_dir == PF_OUT || >+ r_dir == PF_IN || r_dir == PF_OUT, ("%s: invalid direction", > __func__)); > > if ((pd->pf_mtag == NULL && > ((pd->pf_mtag = pf_get_mtag(*m)) == NULL)) || > pd->pf_mtag->routed++ > 3) { > m0 = *m; > *m = NULL; > goto bad_locked; > } > >- if (r->rt == PF_DUPTO) { >+ if (r_rt == PF_DUPTO) { > if ((m0 = m_dup(*m, M_NOWAIT)) == NULL) { > if (s) > PF_STATE_UNLOCK(s); > return; > } > } else { >- if ((r->rt == PF_REPLYTO) == (r->direction == dir)) { >+ if ((r_rt == PF_REPLYTO) == (r_dir == p_dir)) { > if (s) > PF_STATE_UNLOCK(s); > return; > } > m0 = *m; > } > > ip6 = mtod(m0, struct ip6_hdr *); > > bzero(&dst, sizeof(dst)); > dst.sin6_family = AF_INET6; > dst.sin6_len = sizeof(dst); > dst.sin6_addr = ip6->ip6_dst; > > bzero(&naddr, sizeof(naddr)); > >- if (TAILQ_EMPTY(&r->rpool.list)) { >- DPFPRINTF(PF_DEBUG_URGENT, >- ("%s: TAILQ_EMPTY(&r->rpool.list)\n", __func__)); >- goto bad_locked; >- } > if (s == NULL) { >+ if (TAILQ_EMPTY(&r->rpool.list)) { >+ DPFPRINTF(PF_DEBUG_URGENT, >+ ("%s: TAILQ_EMPTY(&r->rpool.list)\n", __func__)); >+ goto bad_locked; >+ } > pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src, > &naddr, NULL, &sn); > if (!PF_AZERO(&naddr, AF_INET6)) > PF_ACPY((struct pf_addr *)&dst.sin6_addr, > &naddr, AF_INET6); > ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL; > } else { > if (!PF_AZERO(&s->rt_addr, AF_INET6)) > PF_ACPY((struct pf_addr *)&dst.sin6_addr, > &s->rt_addr, AF_INET6); >@@ -5724,28 +5747,28 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, > /* > * If the packet is too large for the outgoing interface, > * send back an icmp6 error. > */ > if (IN6_IS_SCOPE_EMBED(&dst.sin6_addr)) > dst.sin6_addr.s6_addr16[1] = htons(ifp->if_index); > if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) > nd6_output_ifp(ifp, ifp, m0, &dst, NULL); > else { > in6_ifstat_inc(ifp, ifs6_in_toobig); >- if (r->rt != PF_DUPTO) >+ if (r_rt != PF_DUPTO) > icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); > else > goto bad; > } > > done: >- if (r->rt != PF_DUPTO) >+ if (r_rt != PF_DUPTO) > *m = NULL; > return; > > bad_locked: > if (s) > PF_STATE_UNLOCK(s); > bad: > m_freem(m0); > goto done; > } >@@ -6253,21 +6276,21 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb * > case PF_DEFER: > *m0 = NULL; > action = PF_PASS; > break; > case PF_DROP: > m_freem(*m0); > *m0 = NULL; > break; > default: > /* pf_route() returns unlocked. */ >- if (r->rt) { >+ if (r->rt || (s != NULL && s->rt)) { > pf_route(m0, r, dir, kif->pfik_ifp, s, &pd, inp); > return (action); > } > break; > } > if (s) > PF_STATE_UNLOCK(s); > > return (action); > } >@@ -6649,21 +6672,21 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb > case PF_DEFER: > *m0 = NULL; > action = PF_PASS; > break; > case PF_DROP: > m_freem(*m0); > *m0 = NULL; > break; > default: > /* pf_route6() returns unlocked. */ >- if (r->rt) { >+ if (r->rt || (s != NULL && s->rt)) { > pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd, inp); > return (action); > } > break; > } > > if (s) > PF_STATE_UNLOCK(s); > > /* If reassembled packet passed, create new fragments. */ >diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c >index bd0bfd91e79..b09e7822b4d 100644 >--- a/sys/netpfil/pf/pf_ioctl.c >+++ b/sys/netpfil/pf/pf_ioctl.c >@@ -3488,20 +3488,21 @@ pfsync_state_export(struct pfsync_state *sp, struct pf_state *st) > sp->expire = pf_state_expires(st); > if (sp->expire <= time_uptime) > sp->expire = htonl(0); > else > sp->expire = htonl(sp->expire - time_uptime); > > sp->direction = st->direction; > sp->log = st->log; > sp->timeout = st->timeout; > sp->state_flags = st->state_flags; >+ sp->rt = st->rt; > if (st->src_node) > sp->sync_flags |= PFSYNC_FLAG_SRCNODE; > if (st->nat_src_node) > sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; > > sp->id = st->id; > sp->creatorid = st->creatorid; > pf_state_peer_hton(&st->src, &sp->src); > pf_state_peer_hton(&st->dst, &sp->dst); >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 229092
:
194342
| 201346