Index: head/sys/netpfil/ipfw/ip_fw2.c =================================================================== --- head/sys/netpfil/ipfw/ip_fw2.c (revision 280909) +++ head/sys/netpfil/ipfw/ip_fw2.c (working copy) @@ -232,6 +232,7 @@ SYSEND #define UDP(p) ((struct udphdr *)(p)) #define ICMP(p) ((struct icmphdr *)(p)) #define ICMP6(p) ((struct icmp6_hdr *)(p)) +#define IP6F(p) ((struct ip6_frag *)(p)) static __inline int icmptype_match(struct icmphdr *icmp, ipfw_insn_u32 *cmd) @@ -972,9 +973,11 @@ ipfw_chk(struct ip_fw_args *args) * without needed). We will treat a single packet fragment as if * there was no fragment header (or log/block depending on the * V_fw_permit_single_frag6 sysctl setting). + * ip6fh_off The offset of an ip6_frag header. */ u_short offset = 0; u_short ip6f_mf = 0; + int ip6fh_off = 0; /* * Local copies of addresses. They are only valid if we have @@ -1132,11 +1135,11 @@ do { \ case IPPROTO_FRAGMENT: /* RFC 2460 */ PULLUP_TO(hlen, ulp, struct ip6_frag); ext_hd |= EXT_FRAGMENT; + ip6fh_off = hlen; hlen += sizeof (struct ip6_frag); - proto = ((struct ip6_frag *)ulp)->ip6f_nxt; - offset = ((struct ip6_frag *)ulp)->ip6f_offlg & - IP6F_OFF_MASK; - ip6f_mf = ((struct ip6_frag *)ulp)->ip6f_offlg & + proto = IP6F(ulp)->ip6f_nxt; + offset = IP6F(ulp)->ip6f_offlg & IP6F_OFF_MASK; + ip6f_mf = IP6F(ulp)->ip6f_offlg & IP6F_MORE_FRAG; if (V_fw_permit_single_frag6 == 0 && offset == 0 && ip6f_mf == 0) { @@ -2538,40 +2541,51 @@ do { \ retval = ipfw_nat_ptr(args, t, m); break; - case O_REASS: { - int ip_off; - + case O_REASS: IPFW_INC_RULE_COUNTER(f, pktlen); l = 0; /* in any case exit inner loop */ - ip_off = ntohs(ip->ip_off); +#ifdef INET6 + if (is_ipv6) { + if ((ext_hd & EXT_FRAGMENT) == 0) + break; + if (frag6_input(&m, &ip6fh_off, 0) == + IPPROTO_DONE) + retval = IP_FW_DENY; + else { + retval = IP_FW_REASS; + set_match(args, f_pos, chain); + } + args->m = m; + } else +#endif /* INET6 */ + { + /* if not fragmented, go to next rule */ + if ((ip->ip_off & + ntohs(IP_MF | IP_OFFMASK)) == 0) + break; + args->m = m = ip_reass(m); + /* do IP header checksum fixup. */ + if (m == NULL) { + /* fragment got swallowed */ + retval = IP_FW_DENY; + } else { /* good, packet complete */ + int hlen; - /* if not fragmented, go to next rule */ - if ((ip_off & (IP_MF | IP_OFFMASK)) == 0) - break; - - args->m = m = ip_reass(m); - - /* - * do IP header checksum fixup. - */ - if (m == NULL) { /* fragment got swallowed */ - retval = IP_FW_DENY; - } else { /* good, packet complete */ - int hlen; - - ip = mtod(m, struct ip *); - hlen = ip->ip_hl << 2; - ip->ip_sum = 0; - if (hlen == sizeof(struct ip)) - ip->ip_sum = in_cksum_hdr(ip); - else - ip->ip_sum = in_cksum(m, hlen); - retval = IP_FW_REASS; - set_match(args, f_pos, chain); + ip = mtod(m, struct ip *); + hlen = ip->ip_hl << 2; + ip->ip_sum = 0; + if (hlen == sizeof(struct ip)) + ip->ip_sum = + in_cksum_hdr(ip); + else + ip->ip_sum = + in_cksum(m, hlen); + retval = IP_FW_REASS; + set_match(args, f_pos, chain); + } } done = 1; /* exit outer loop */ break; - } default: panic("-- unknown opcode %d\n", cmd->opcode);