@@ -640,3 +640,38 @@ func serializeAH(ah *layers.IPSecAH) []byte {
640640
641641 return buf .Bytes ()
642642}
643+
644+ // Test_newPacket_v6ExtHeaderOverflow is a regression test for the IPv6 extension-header
645+ // length uint8 overflow in parseV6. A Destination-Options header with HdrExtLen=255 spans
646+ // (255+1)*8 = 2048 bytes, so the real transport header sits at offset 2088. Before the fix
647+ // the advance was computed in uint8 and wrapped to 0 (then clamped to 8), so the firewall
648+ // read the transport header ~2KB too early from attacker-controlled option bytes while the
649+ // host OS parses the real header, a firewall port/proto bypass. The fix makes parseV6 land
650+ // on the same offset the host does.
651+ func Test_newPacket_v6ExtHeaderOverflow (t * testing.T ) {
652+ p := & firewall.Packet {}
653+
654+ const (
655+ hdrLen = 40 // IPv6 header
656+ extLen = 2048 // (255+1)*8, the true Destination-Options header size
657+ realTCPAt = hdrLen + extLen // 2088, where the host reads the transport header
658+ forgedTCPAt = hdrLen + 8 // 48, where the pre-fix wrapped+clamped walk landed
659+ )
660+
661+ pkt := make ([]byte , realTCPAt + 4 )
662+ pkt [0 ] = 0x60 // version 6
663+ pkt [6 ] = byte (layers .IPProtocolIPv6Destination ) // NextHeader -> Destination Options
664+ pkt [40 ] = byte (firewall .ProtoTCP ) // Dest-Options NextHeader -> TCP
665+ pkt [41 ] = 255 // HdrExtLen = 255
666+
667+ // Forged transport header at the pre-fix (wrong) offset: dst port 443.
668+ binary .BigEndian .PutUint16 (pkt [forgedTCPAt + 2 :forgedTCPAt + 4 ], 443 )
669+ // Real transport header at the offset the host actually uses: dst port 22.
670+ binary .BigEndian .PutUint16 (pkt [realTCPAt + 2 :realTCPAt + 4 ], 22 )
671+
672+ require .NoError (t , newPacket (pkt , true , p ))
673+ assert .Equal (t , uint8 (firewall .ProtoTCP ), p .Protocol )
674+ // LocalPort is the destination port for incoming traffic. It must be the real port (22)
675+ // the host delivers to, not the forged 443 at the overflowed offset.
676+ assert .Equal (t , uint16 (22 ), p .LocalPort , "firewall must parse the real transport header, not the overflowed offset" )
677+ }
0 commit comments