From owner-svn-src-stable@FreeBSD.ORG Thu Jun 18 20:34:41 2015 Return-Path: Delivered-To: svn-src-stable@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 290A271C; Thu, 18 Jun 2015 20:34:41 +0000 (UTC) (envelope-from kp@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 163279A1; Thu, 18 Jun 2015 20:34:41 +0000 (UTC) (envelope-from kp@FreeBSD.org) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t5IKYeG1027347; Thu, 18 Jun 2015 20:34:40 GMT (envelope-from kp@FreeBSD.org) Received: (from kp@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t5IKYdBi027339; Thu, 18 Jun 2015 20:34:39 GMT (envelope-from kp@FreeBSD.org) Message-Id: <201506182034.t5IKYdBi027339@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: kp set sender to kp@FreeBSD.org using -f From: Kristof Provost Date: Thu, 18 Jun 2015 20:34:39 +0000 (UTC) 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 X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Jun 2015 20:34:41 -0000 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) {