fix(redirect): add IPv6 TPROXY support for TCP redirect listener
Add missing IPV6_TRANSPARENT socket option to the TCP redirect listener Control callback, matching what the UDP redirect listener already sets. Without this, the kernel silently drops IPv6 TPROXY-redirected connections. Also clean up handler_linux.go getOriginalDstAddr: - Remove encoding/binary import and heap allocation for port conversion - Replace with zero-allocation ntohs (native-to-network byte order swap) - Document the struct layout hack where GetsockoptIPv6Mreq and GetsockoptIPv6MTUInfo are used to read sockaddr_in/sockaddr_in6 from SO_ORIGINAL_DST (kernel returns smaller structs than the getter functions expect, but only the first N bytes are populated) Fixes go-gost/gost#126
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package redirect
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net"
|
||||
"syscall"
|
||||
@@ -30,6 +29,10 @@ func (h *redirectHandler) getOriginalDstAddr(conn net.Conn) (addr net.Addr, err
|
||||
var cerr error
|
||||
err = rc.Control(func(fd uintptr) {
|
||||
if tcpAddr.IP.To4() != nil {
|
||||
// SO_ORIGINAL_DST returns a struct sockaddr_in (16 bytes).
|
||||
// GetsockoptIPv6Mreq reads into a 20-byte ipv6_mreq; only the
|
||||
// first 16 bytes (the Multiaddr field) are populated.
|
||||
// Layout: [0:2]=sin_family, [2:4]=sin_port (BE), [4:8]=sin_addr.
|
||||
mreq, err := unix.GetsockoptIPv6Mreq(int(fd), unix.IPPROTO_IP, unix.SO_ORIGINAL_DST)
|
||||
if err != nil {
|
||||
cerr = err
|
||||
@@ -41,17 +44,19 @@ func (h *redirectHandler) getOriginalDstAddr(conn net.Conn) (addr net.Addr, err
|
||||
Port: int(mreq.Multiaddr[2])<<8 + int(mreq.Multiaddr[3]),
|
||||
}
|
||||
} else {
|
||||
// SO_ORIGINAL_DST returns a struct sockaddr_in6 (28 bytes).
|
||||
// GetsockoptIPv6MTUInfo reads into a 32-byte ipv6_mtuinfo; only
|
||||
// the first 28 bytes (the Addr field) are populated.
|
||||
info, err := unix.GetsockoptIPv6MTUInfo(int(fd), unix.IPPROTO_IPV6, unix.SO_ORIGINAL_DST)
|
||||
if err != nil {
|
||||
cerr = err
|
||||
return
|
||||
}
|
||||
|
||||
var buf = make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(buf, info.Addr.Port)
|
||||
// info.Addr.Port is in network byte order (big-endian).
|
||||
addr = &net.TCPAddr{
|
||||
IP: net.IP(info.Addr.Addr[:]),
|
||||
Port: int(binary.NativeEndian.Uint16(buf)),
|
||||
Port: int(uint16(info.Addr.Port>>8 | info.Addr.Port<<8)),
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user