On 09.02.21, 17:33, "Pablo Neira Ayuso" <pablo@xxxxxxxxxxxxx> wrote: Thanks for looking into this. > Note: nfq_ip6_set_transport_header() is very much similar to > ipv6_skip_exthdr() in the Linux kernel, see net/ipv6/exthdrs_core.c I submitted a revised version that uses similar logic as in the kernel to exit the loop once extension headers are fully processed. > > uint32_t hdrlen; > > > > /* No more extensions, we're done. */ > > - if (nexthdr == IPPROTO_NONE) { > > + if (nexthdr == IPPROTO_TCP || nexthdr == IPPROTO_UDP || nexthdr == IPPROTO_ESP || > > + nexthdr == IPPROTO_ICMPV6 || nexthdr == IPPROTO_NONE) { > > cur = NULL; > > break; > > } > > @@ -107,7 +108,7 @@ int nfq_ip6_set_transport_header(struct pkt_buff *pktb, struct ip6_hdr *ip6h, > > } else if (nexthdr == IPPROTO_AH) > > hdrlen = (ip6_ext->ip6e_len + 2) << 2; > > else > > - hdrlen = ip6_ext->ip6e_len; > > + hdrlen = (ip6_ext->ip6e_len + 1) << 3; > > This looks correct, IPv6 optlen is miscalculated. > > The chunk above to stop the iteration, so I think the chunk that fixes > optlen is sufficient to fix the bug. The optlen fix is not sufficient when a non-existent 'target' is given. For example, if a UDP packet is passed with 'target' IPPROTO_TCP, the loop will go on and attempt to interpret the UDP packet body as another IP extension header. Instead, by exiting the loop also when all extension headers are processed, the function will now return 0 in that case, as documented in the header file. Thanks Etan