Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 18 Jun 2015 20:34:39 +0000 (UTC)
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r284571 - in stable/10/sys: net netpfil/pf
Message-ID:  <201506182034.t5IKYdBi027339@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kp
Date: Thu Jun 18 20:34:39 2015
New Revision: 284571
URL: https://svnweb.freebsd.org/changeset/base/284571

Log:
  Merge r278843, r278858
  
  In the forwarding case refragment the reassembled packets with the same
  size as they arrived in. This allows the sender to determine the optimal
  fragment size by Path MTU Discovery.
  
  Roughly based on the OpenBSD work by Alexander Bluhm.
  
  Differential Revision:	https://reviews.freebsd.org/D2816
  Reviewed by:	gnn

Modified:
  stable/10/sys/net/pfvar.h
  stable/10/sys/netpfil/pf/pf.c
  stable/10/sys/netpfil/pf/pf.h
  stable/10/sys/netpfil/pf/pf_mtag.h
  stable/10/sys/netpfil/pf/pf_norm.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/net/pfvar.h
==============================================================================
--- stable/10/sys/net/pfvar.h	Thu Jun 18 20:32:53 2015	(r284570)
+++ stable/10/sys/net/pfvar.h	Thu Jun 18 20:34:39 2015	(r284571)
@@ -1573,6 +1573,7 @@ int	pf_test6(int, struct ifnet *, struct
 void	pf_poolmask(struct pf_addr *, struct pf_addr*,
 	    struct pf_addr *, struct pf_addr *, u_int8_t);
 void	pf_addr_inc(struct pf_addr *, sa_family_t);
+int	pf_refragment6(struct ifnet *ifp, struct mbuf **m0, struct m_tag *mtag);
 #endif /* INET6 */
 
 u_int32_t	pf_new_isn(struct pf_state *);

Modified: stable/10/sys/netpfil/pf/pf.c
==============================================================================
--- stable/10/sys/netpfil/pf/pf.c	Thu Jun 18 20:32:53 2015	(r284570)
+++ stable/10/sys/netpfil/pf/pf.c	Thu Jun 18 20:34:39 2015	(r284571)
@@ -5509,7 +5509,7 @@ pf_route6(struct mbuf **m, struct pf_rul
 		goto bad;
 
 	if (oifp != ifp) {
-		if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
+		if (pf_test6(PF_FWD, ifp, &m0, NULL) != PF_PASS)
 			goto bad;
 		else if (m0 == NULL)
 			goto done;
@@ -6067,15 +6067,20 @@ pf_test6(int dir, struct ifnet *ifp, str
 	struct pfi_kif		*kif;
 	u_short			 action, reason = 0, log = 0;
 	struct mbuf		*m = *m0, *n = NULL;
+	struct m_tag		*mtag;
 	struct ip6_hdr		*h = NULL;
 	struct pf_rule		*a = NULL, *r = &V_pf_default_rule, *tr, *nr;
 	struct pf_state		*s = NULL;
 	struct pf_ruleset	*ruleset = NULL;
 	struct pf_pdesc		 pd;
 	int			 off, terminal = 0, dirndx, rh_cnt = 0;
+	int			 fwdir = dir;
 
 	M_ASSERTPKTHDR(m);
 
+	if (ifp != m->m_pkthdr.rcvif)
+		fwdir = PF_FWD;
+
 	if (!V_pf_status.running)
 		return (PF_PASS);
 
@@ -6437,6 +6442,11 @@ done:
 	if (s)
 		PF_STATE_UNLOCK(s);
 
+	/* If reassembled packet passed, create new fragments. */
+	if (action == PF_PASS && *m0 && fwdir == PF_FWD &&
+	    (mtag = m_tag_find(m, PF_REASSEMBLED, NULL)) != NULL)
+		action = pf_refragment6(ifp, m0, mtag);
+
 	return (action);
 }
 #endif /* INET6 */

Modified: stable/10/sys/netpfil/pf/pf.h
==============================================================================
--- stable/10/sys/netpfil/pf/pf.h	Thu Jun 18 20:32:53 2015	(r284570)
+++ stable/10/sys/netpfil/pf/pf.h	Thu Jun 18 20:34:39 2015	(r284571)
@@ -43,7 +43,7 @@
 #endif
 #endif
 
-enum	{ PF_INOUT, PF_IN, PF_OUT };
+enum	{ PF_INOUT, PF_IN, PF_OUT, PF_FWD };
 enum	{ PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT,
 	  PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER };
 enum	{ PF_RULESET_SCRUB, PF_RULESET_FILTER, PF_RULESET_NAT,

Modified: stable/10/sys/netpfil/pf/pf_mtag.h
==============================================================================
--- stable/10/sys/netpfil/pf/pf_mtag.h	Thu Jun 18 20:32:53 2015	(r284570)
+++ stable/10/sys/netpfil/pf/pf_mtag.h	Thu Jun 18 20:34:39 2015	(r284571)
@@ -39,6 +39,7 @@
 #define	PF_TAG_TRANSLATE_LOCALHOST	0x04
 #define	PF_PACKET_LOOPED		0x08
 #define	PF_FASTFWD_OURS_PRESENT		0x10
+#define	PF_REASSEMBLED			0x20
 
 struct pf_mtag {
 	void		*hdr;		/* saved hdr pos in mbuf, for ECN */

Modified: stable/10/sys/netpfil/pf/pf_norm.c
==============================================================================
--- stable/10/sys/netpfil/pf/pf_norm.c	Thu Jun 18 20:32:53 2015	(r284570)
+++ stable/10/sys/netpfil/pf/pf_norm.c	Thu Jun 18 20:34:39 2015	(r284571)
@@ -678,6 +678,8 @@ pf_reassemble6(struct mbuf **m0, struct 
 	struct pf_frent		*frent;
 	struct pf_fragment	*frag;
 	struct pf_fragment_cmp	 key;
+	struct m_tag		*mtag;
+	struct pf_fragment_tag	*ftag;
 	int			 off;
 	uint16_t		 total, maxlen;
 	uint8_t			 proto;
@@ -750,6 +752,15 @@ pf_reassemble6(struct mbuf **m0, struct 
 		m->m_pkthdr.len = plen;
 	}
 
+	if ((mtag = m_tag_get(PF_REASSEMBLED, sizeof(struct pf_fragment_tag),
+	    M_NOWAIT)) == NULL)
+		goto fail;
+	ftag = (struct pf_fragment_tag *)(mtag + 1);
+	ftag->ft_hdrlen = hdrlen;
+	ftag->ft_extoff = extoff;
+	ftag->ft_maxlen = maxlen;
+	m_tag_prepend(m, mtag);
+
 	ip6 = mtod(m, struct ip6_hdr *);
 	ip6->ip6_plen = htons(hdrlen - sizeof(struct ip6_hdr) + total);
 	if (extoff) {
@@ -1084,6 +1095,75 @@ pf_fragcache(struct mbuf **m0, struct ip
 }
 
 int
+pf_refragment6(struct ifnet *ifp, struct mbuf **m0, struct m_tag *mtag)
+{
+	struct mbuf		*m = *m0, *t;
+	struct pf_fragment_tag	*ftag = (struct pf_fragment_tag *)(mtag + 1);
+	struct pf_pdesc		 pd;
+	uint16_t		 hdrlen, extoff, maxlen;
+	uint8_t			 proto;
+	int			 error, action;
+
+	hdrlen = ftag->ft_hdrlen;
+	extoff = ftag->ft_extoff;
+	maxlen = ftag->ft_maxlen;
+	m_tag_delete(m, mtag);
+	mtag = NULL;
+	ftag = NULL;
+
+	if (extoff) {
+		int off;
+
+		/* Use protocol from next field of last extension header */
+		m = m_getptr(m, extoff + offsetof(struct ip6_ext, ip6e_nxt),
+		    &off);
+		KASSERT((m != NULL), ("pf_refragment6: short mbuf chain"));
+		proto = *(mtod(m, caddr_t) + off);
+		*(mtod(m, char *) + off) = IPPROTO_FRAGMENT;
+		m = *m0;
+	} else {
+		struct ip6_hdr *hdr;
+
+		hdr = mtod(m, struct ip6_hdr *);
+		proto = hdr->ip6_nxt;
+		hdr->ip6_nxt = IPPROTO_FRAGMENT;
+	}
+
+	/*
+	 * Maxlen may be less than 8 if there was only a single
+	 * fragment.  As it was fragmented before, add a fragment
+	 * header also for a single fragment.  If total or maxlen
+	 * is less than 8, ip6_fragment() will return EMSGSIZE and
+	 * we drop the packet.
+	 */
+	error = ip6_fragment(ifp, m, hdrlen, proto, maxlen);
+	m = (*m0)->m_nextpkt;
+	(*m0)->m_nextpkt = NULL;
+	if (error == 0) {
+		/* The first mbuf contains the unfragmented packet. */
+		m_freem(*m0);
+		*m0 = NULL;
+		action = PF_PASS;
+	} else {
+		/* Drop expects an mbuf to free. */
+		DPFPRINTF(("refragment error %d", error));
+		action = PF_DROP;
+	}
+	for (t = m; m; m = t) {
+		t = m->m_nextpkt;
+		m->m_nextpkt = NULL;
+		memset(&pd, 0, sizeof(pd));
+		pd.pf_mtag = pf_find_mtag(m);
+		if (error == 0)
+			ip6_forward(m, 0);
+		else
+			m_freem(m);
+	}
+
+	return (action);
+}
+
+int
 pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
     struct pf_pdesc *pd)
 {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201506182034.t5IKYdBi027339>