On Fri, Oct 30, 2015 at 11:30:56AM +0100, Alexander Bluhm wrote:
> On Fri, Oct 30, 2015 at 10:43:21AM +0100, Reyk Floeter wrote:
> > Question:
> > > How does pair(4) interact with pf? If a packet crosses a pair
> > > does it create a new state or does pf track the original state?
> > >
> >
> > Answer:
> > It does create a new state, you can filter between pair(4) without
> > problems and all features including nat work.
> > But it currently does not clear some of the extended packet settings -
> > like flags, tags, qid etc. - so you can filter on the tag, eg.
> >
> > # Assuming pair1 is patched to pair0
> > pass out on pair1 tag FOO
> > pass in on pair0 tagged FOO
> >
> > The attached diff _removes_ that and resets all pf settings, so the pf
> > rules above will not work anymore. I think it is better to assume
> > crossing barriers and receiving packets with pair(4) works like a
> > "normal" Ethernet packet. The following will still work:
> >
> > # Received packets on pair0 don't carry any existing pf states
> > pass out on pair1
> > pass in on pair0
> >
> > OK?
>
> The new semantics is better.
>
> > +void
> > +pf_pkt_reset(struct mbuf *m)
> > +{
> > + if (m->m_flags & M_PKTHDR)
> > + m_tag_delete_chain(m);
> > +
> > + /* resets state key, pcb reference, qid, tag, and all flags */
> > + memset(&m->m_pkthdr.pf, 0, sizeof(m->m_pkthdr.pf));
> > +}
>
> You need a packet header mbuf to access m->m_pkthdr. So either
> assume that M_PKTHDR is set and don't check. Or put both actions
> into the if block.
>
> As pf_pkt_addr_changed() accesses the m->m_pkthdr without check, I
> would recomend to remove the "if (m->m_flags & M_PKTHDR)" here,
> too. You may also put an assert into both functions.
>
> The default for m->m_pkthdr.pf.prio is IFQ_DEFPRIO, not 0.
> Look at m_inithdr().
>
Thanks.
Adding asserts in in both functions makes sense, but I'll try it
separately - no caller of pf_pkt_addr_changed() checks for the pkthdr
at the moment and I fear potential fallout. Maybe it would also make
sense to rename both functions to pf_pkthdr_* to make it clear, but
this can also be done separately.
Here is the updated diff, OK?
Reyk
Index: sys/net/if_pair.c
===================================================================
RCS file: /cvs/src/sys/net/if_pair.c,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 if_pair.c
--- sys/net/if_pair.c 25 Oct 2015 12:59:57 -0000 1.4
+++ sys/net/if_pair.c 30 Oct 2015 10:57:10 -0000
@@ -30,6 +30,11 @@
#include <netinet/in.h>
#include <netinet/if_ether.h>
+#include "pf.h"
+#if NPF > 0
+#include <net/pfvar.h>
+#endif
+
#include "bpfilter.h"
#if NBPFILTER > 0
#include <net/bpf.h>
@@ -182,9 +187,13 @@ pairstart(struct ifnet *ifp)
#endif /* NBPFILTER > 0 */
ifp->if_opackets++;
- if (pairedifp != NULL)
+ if (pairedifp != NULL) {
+#if NPF > 0
+ if (m->m_flags & M_PKTHDR)
+ pf_pkt_reset(m);
+#endif
ml_enqueue(&ml, m);
- else
+ } else
m_freem(m);
}
Index: sys/net/pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.948
diff -u -p -u -p -r1.948 pf.c
--- sys/net/pf.c 27 Oct 2015 10:52:17 -0000 1.948
+++ sys/net/pf.c 30 Oct 2015 10:57:11 -0000
@@ -6701,6 +6701,19 @@ pf_pkt_addr_changed(struct mbuf *m)
m->m_pkthdr.pf.inp = NULL;
}
+/*
+ * should be called when reinjecting the packet with a clean state
+ */
+void
+pf_pkt_reset(struct mbuf *m)
+{
+ m_tag_delete_chain(m);
+
+ /* resets pf state key, pcb, qid, tag, and flags like m_inithdr() */
+ memset(&m->m_pkthdr.pf, 0, sizeof(m->m_pkthdr.pf));
+ m->m_pkthdr.pf.prio = IFQ_DEFPRIO;
+}
+
#if NPFLOG > 0
void
pf_log_matches(struct pf_pdesc *pd, struct pf_rule *rm, struct pf_rule *am,
Index: sys/net/pfvar.h
===================================================================
RCS file: /cvs/src/sys/net/pfvar.h,v
retrieving revision 1.421
diff -u -p -u -p -r1.421 pfvar.h
--- sys/net/pfvar.h 13 Oct 2015 19:32:32 -0000 1.421
+++ sys/net/pfvar.h 30 Oct 2015 10:57:11 -0000
@@ -1756,6 +1756,7 @@ int pf_rtlabel_match(struct pf_addr *, s
int pf_socket_lookup(struct pf_pdesc *);
struct pf_state_key *pf_alloc_state_key(int);
void pf_pkt_addr_changed(struct mbuf *);
+void pf_pkt_reset(struct mbuf *);
int pf_state_key_attach(struct pf_state_key *, struct pf_state *, int);
int pf_translate(struct pf_pdesc *, struct pf_addr *, u_int16_t,
struct pf_addr *, u_int16_t, u_int16_t, int);