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/D2188
Approved by:		gnn (mentor)
This commit is contained in:
Kristof Provost 2015-04-01 12:15:01 +00:00
parent 63f13cedca
commit 798318490e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=280955
3 changed files with 13 additions and 5 deletions

View File

@ -214,7 +214,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;
@ -222,7 +222,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 *);
@ -318,6 +317,7 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
int needfiblookup;
uint32_t fibnum;
struct m_tag *fwd_tag = NULL;
uint32_t id;
ip6 = mtod(m, struct ip6_hdr *);
if (ip6 == NULL) {
@ -1010,7 +1010,8 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
* 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

@ -388,7 +388,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;
@ -673,6 +674,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;
@ -715,6 +717,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 +
@ -751,6 +754,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 *);
@ -1094,6 +1098,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;
@ -1101,6 +1106,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;
@ -1130,7 +1136,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) {