Merge r280955

Preserve IPv6 fragment IDs accross reassembly and refragmentation

When forwarding fragmented IPv6 packets and filtering with PF we
reassemble and refragment. That means we generate new fragment headers
and a new fragment ID.

We already save the fragment IDs so we can do the reassembly so it's
straightforward to apply the incoming fragment ID on the refragmented
packets.

Differential Revision:	https://reviews.freebsd.org/D2817
Reviewed by:	gnn
This commit is contained in:
kp 2015-06-18 20:40:36 +00:00
parent 83b6287db4
commit ad9eb0c77b
3 changed files with 13 additions and 5 deletions

View File

@ -210,7 +210,7 @@ in6_delayed_cksum(struct mbuf *m, uint32_t plen, u_short offset)
int
ip6_fragment(struct ifnet *ifp, struct mbuf *m0, int hlen, u_char nextproto,
int mtu)
int mtu, uint32_t id)
{
struct mbuf *m, **mnext, *m_frgpart;
struct ip6_hdr *ip6, *mhip6;
@ -218,7 +218,6 @@ ip6_fragment(struct ifnet *ifp, struct mbuf *m0, int hlen, u_char nextproto,
int off;
int error;
int tlen = m0->m_pkthdr.len;
uint32_t id = htonl(ip6_randomid());
m = m0;
ip6 = mtod(m, struct ip6_hdr *);
@ -309,6 +308,7 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
int hdrsplit = 0;
int sw_csum, tso;
struct m_tag *fwd_tag = NULL;
uint32_t id;
ip6 = mtod(m, struct ip6_hdr *);
if (ip6 == NULL) {
@ -996,7 +996,8 @@ passout:
* chain.
*/
m0 = m;
if ((error = ip6_fragment(ifp, m, hlen, nextproto, len)))
id = htonl(ip6_randomid());
if ((error = ip6_fragment(ifp, m, hlen, nextproto, len, id)))
goto sendorfree;
in6_ifstat_inc(ifp, ifs6_out_fragok);

View File

@ -426,7 +426,8 @@ void ip6_clearpktopts(struct ip6_pktopts *, int);
struct ip6_pktopts *ip6_copypktopts(struct ip6_pktopts *, int);
int ip6_optlen(struct inpcb *);
int ip6_deletefraghdr(struct mbuf *, int, int);
int ip6_fragment(struct ifnet *, struct mbuf *, int, u_char, int);
int ip6_fragment(struct ifnet *, struct mbuf *, int, u_char, int,
uint32_t);
int route6_input(struct mbuf **, int *, int);

View File

@ -104,6 +104,7 @@ struct pf_fragment_tag {
uint16_t ft_hdrlen; /* header length of reassembled pkt */
uint16_t ft_extoff; /* last extension header offset or 0 */
uint16_t ft_maxlen; /* maximum fragment payload length */
uint32_t ft_id; /* fragment id */
};
static struct mtx pf_frag_mtx;
@ -681,6 +682,7 @@ pf_reassemble6(struct mbuf **m0, struct ip6_hdr *ip6, struct ip6_frag *fraghdr,
struct m_tag *mtag;
struct pf_fragment_tag *ftag;
int off;
uint32_t frag_id;
uint16_t total, maxlen;
uint8_t proto;
@ -723,6 +725,7 @@ pf_reassemble6(struct mbuf **m0, struct ip6_hdr *ip6, struct ip6_frag *fraghdr,
/* We have all the data. */
extoff = frent->fe_extoff;
maxlen = frag->fr_maxlen;
frag_id = frag->fr_id;
frent = TAILQ_FIRST(&frag->fr_queue);
KASSERT(frent != NULL, ("frent != NULL"));
total = TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_off +
@ -759,6 +762,7 @@ pf_reassemble6(struct mbuf **m0, struct ip6_hdr *ip6, struct ip6_frag *fraghdr,
ftag->ft_hdrlen = hdrlen;
ftag->ft_extoff = extoff;
ftag->ft_maxlen = maxlen;
ftag->ft_id = frag_id;
m_tag_prepend(m, mtag);
ip6 = mtod(m, struct ip6_hdr *);
@ -1100,6 +1104,7 @@ 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;
uint32_t frag_id;
uint16_t hdrlen, extoff, maxlen;
uint8_t proto;
int error, action;
@ -1107,6 +1112,7 @@ pf_refragment6(struct ifnet *ifp, struct mbuf **m0, struct m_tag *mtag)
hdrlen = ftag->ft_hdrlen;
extoff = ftag->ft_extoff;
maxlen = ftag->ft_maxlen;
frag_id = ftag->ft_id;
m_tag_delete(m, mtag);
mtag = NULL;
ftag = NULL;
@ -1136,7 +1142,7 @@ pf_refragment6(struct ifnet *ifp, struct mbuf **m0, struct m_tag *mtag)
* is less than 8, ip6_fragment() will return EMSGSIZE and
* we drop the packet.
*/
error = ip6_fragment(ifp, m, hdrlen, proto, maxlen);
error = ip6_fragment(ifp, m, hdrlen, proto, maxlen, frag_id);
m = (*m0)->m_nextpkt;
(*m0)->m_nextpkt = NULL;
if (error == 0) {