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;