> >I think that a patch like the one you propose is very useful (for > >ipv4 as well) but it requires a sysctl or other mechanism to make > >sure that when it is enabled we don't pass fragments through the > >firewall. > > i've looked further into this and I now wonder if is a byproduct of my > use of ipfw. the problem seems to be that offset will always be > non-zero with any packet with a v6 fragment header, so a rule requiring > offset to be zero is never run. i'll spend a bit more time on this > tomorrow, and come back with a patch for ipfw.
Here's a patch to ipfw. We keep a copy of the MF bit for IPv6 fragments so it can be passed to ipfw_log. Otherwise, the offset field no longer has the MF bit embedded in it as before. Note that apart from the various transport-layer checks that require offset to be zero, the O_FRAG opcode now has a different behaviour. Only subsequent fragments will match this rule. If you want the exact same behaviour as before, then case O_FRAG: match = (offset != 0); break; should become case O_FRAG: match = (offset != 0 || ext_hd & EXT_FRAGMENT); break; If you are generally happy with this patch, let me know and I'll file a PR so it doesn't get lost. --- ip_fw2.c.orig 2008-11-25 15:59:29.000000000 +1300 +++ ip_fw2.c 2010-04-14 10:05:46.000000000 +1200 @@ -758,6 +758,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, st char *action; int limit_reached = 0; char action2[40], proto[128], fragment[32]; + u_short mf = 0; fragment[0] = '\0'; proto[0] = '\0'; @@ -903,6 +904,8 @@ ipfw_log(struct ip_fw *f, u_int hlen, st snprintf(dst, sizeof(dst), "[%s]", ip6_sprintf(ip6buf, &args->f_id.dst_ip6)); + mf = offset & IP6F_MORE_FRAG; + offset &= IP6F_OFF_MASK; ip6 = (struct ip6_hdr *)ip; tcp = (struct tcphdr *)(((char *)ip) + hlen); udp = (struct udphdr *)(((char *)ip) + hlen); @@ -972,13 +975,13 @@ ipfw_log(struct ip_fw *f, u_int hlen, st #ifdef INET6 if (IS_IP6_FLOW_ID(&(args->f_id))) { - if (offset & (IP6F_OFF_MASK | IP6F_MORE_FRAG)) + if (offset || mf) snprintf(SNPARGS(fragment, 0), " (frag %08x:%...@%d%s)", args->f_id.frag_id6, ntohs(ip6->ip6_plen) - hlen, - ntohs(offset & IP6F_OFF_MASK) << 3, - (offset & IP6F_MORE_FRAG) ? "+" : ""); + ntohs(offset) << 3, + mf ? "+" : ""); } else #endif { @@ -2151,16 +2154,13 @@ ipfw_chk(struct ip_fw_args *args) /* * offset The offset of a fragment. offset != 0 means that - * we have a fragment at this offset of an IPv4 packet. - * offset == 0 means that (if this is an IPv4 packet) - * this is the first or only fragment. - * For IPv6 offset == 0 means there is no Fragment Header. - * If offset != 0 for IPv6 always use correct mask to - * get the correct offset because we add IP6F_MORE_FRAG - * to be able to dectect the first fragment which would - * otherwise have offset = 0. + * we have a fragment at this offset. + * offset == 0 means that this is the first or only fragment. + * + * mf The MF bit masked out of IPv6 packets. */ u_short offset = 0; + u_short mf = 0; /* * Local copies of addresses. They are only valid if we have @@ -2311,17 +2311,8 @@ do { \ proto = ((struct ip6_frag *)ulp)->ip6f_nxt; offset = ((struct ip6_frag *)ulp)->ip6f_offlg & IP6F_OFF_MASK; - /* Add IP6F_MORE_FRAG for offset of first - * fragment to be != 0. */ - offset |= ((struct ip6_frag *)ulp)->ip6f_offlg & + mf = ((struct ip6_frag *)ulp)->ip6f_offlg & IP6F_MORE_FRAG; - if (offset == 0) { - printf("IPFW2: IPV6 - Invalid Fragment " - "Header\n"); - if (fw_deny_unknown_exthdrs) - return (IP_FW_DENY); - break; - } args->f_id.frag_id6 = ntohl(((struct ip6_frag *)ulp)->ip6f_ident); ulp = NULL; @@ -2904,7 +2895,7 @@ check_body: case O_LOG: if (fw_verbose) ipfw_log(f, hlen, args, m, - oif, offset, tablearg, ip); + oif, offset|mf, tablearg, ip); match = 1; break; _______________________________________________ freebsd-net@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-net To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"