76e01f06ff
Fixes the P001 review finding. The previous ipv6_transport_offset walker returned only the offset, but the caller passed the INITIAL next_header (which is usually a Hop-by-Hop / Routing / Destination / Fragment number, not a transport protocol) to parse_ports() and to PacketContext.protocol. Any IPv6 packet with extension headers silently failed firewall port rules. Two changes: 1. ipv6_transport_offset now returns (final_protocol, offset) tuple. Continues to return None for malformed/encrypted/too-deep chains so we never fall through to wrong-offset parse. 2. The IPv6 dispatch in infer_context() uses the returned final protocol: parse_ports() gets the right IpProtocol (TCP/UDP/ICMPv6) and PacketContext.protocol is set to the discovered final protocol. Also corrects the AH header length formula: RFC 8200 §4 says AH length is in 4-octet units over the 8-octet fixed part, so total = (len+2)*8, not the generic (len+1)*8 used for Hop-by-Hop / Routing / Destination.