Hi,

IPv6 atomic fragments must not go the reassembly queue.  I have
implemented this for the stack, but somehow forgot it for pf.  With
this diff, pf steps over an atomic fragment header and handles the
packet like an unfragmented.

ok?

bluhm

Index: net/pf.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/pf.c,v
retrieving revision 1.839
diff -u -p -u -p -r1.839 pf.c
--- net/pf.c    19 Aug 2013 09:16:25 -0000      1.839
+++ net/pf.c    6 Sep 2013 21:01:24 -0000
@@ -6000,7 +6000,7 @@ pf_walk_header6(struct pf_pdesc *pd, str
        struct ip6_ext           ext;
        struct ip6_rthdr         rthdr;
        u_int32_t                end;
-       int                      rthdr_cnt = 0;
+       int                      fraghdr_cnt = 0, rthdr_cnt = 0;
 
        pd->off += sizeof(struct ip6_hdr);
        end = pd->off + ntohs(h->ip6_plen);
@@ -6009,7 +6009,7 @@ pf_walk_header6(struct pf_pdesc *pd, str
        for (;;) {
                switch (pd->proto) {
                case IPPROTO_FRAGMENT:
-                       if (pd->fragoff != 0) {
+                       if (fraghdr_cnt++) {
                                DPFPRINTF(LOG_NOTICE, "IPv6 multiple fragment");
                                REASON_SET(reason, PFRES_FRAG);
                                return (PF_DROP);
@@ -6025,10 +6025,14 @@ pf_walk_header6(struct pf_pdesc *pd, str
                                DPFPRINTF(LOG_NOTICE, "IPv6 short fragment");
                                return (PF_DROP);
                        }
-                       pd->fragoff = pd->off;
                        /* stop walking over non initial fragments */
-                       if (ntohs((frag.ip6f_offlg & IP6F_OFF_MASK)) != 0)
+                       if (ntohs((frag.ip6f_offlg & IP6F_OFF_MASK)) != 0) {
+                               pd->fragoff = pd->off;
                                return (PF_PASS);
+                       }
+                       /* RFC6946:  reassemble only non atomic fragments */
+                       if (frag.ip6f_offlg & IP6F_MORE_FRAG)
+                               pd->fragoff = pd->off;
                        pd->off += sizeof(frag);
                        pd->proto = frag.ip6f_nxt;
                        break;

Reply via email to