Files
op-packages/UA-Mask/core/internal/proxy/tproxy_linux.go
T

55 lines
1.2 KiB
Go

//go:build linux
// +build linux
package proxy
import (
"fmt"
"net"
"unsafe"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
// getOriginalDst 获取被 REDIRECT 规则重定向前的原始目标地址
// 使用 SO_ORIGINAL_DST socket 选项,这是 iptables REDIRECT 目标填充的
func getOriginalDst(conn *net.TCPConn) (*net.TCPAddr, error) {
file, err := conn.File()
if err != nil {
return nil, fmt.Errorf("failed to get file descriptor: %w", err)
}
defer file.Close()
fd := int(file.Fd())
// SO_ORIGINAL_DST = 80
const SO_ORIGINAL_DST = 80
// 使用 sockaddr 结构获取原始目标地址
var addr unix.RawSockaddrInet4
addrLen := uint32(unsafe.Sizeof(addr))
_, _, errno := unix.Syscall6(
unix.SYS_GETSOCKOPT,
uintptr(fd),
uintptr(unix.SOL_IP),
uintptr(SO_ORIGINAL_DST),
uintptr(unsafe.Pointer(&addr)),
uintptr(unsafe.Pointer(&addrLen)),
0,
)
if errno != 0 {
return nil, fmt.Errorf("getsockopt SO_ORIGINAL_DST failed: %v", errno)
}
ip := net.IPv4(addr.Addr[0], addr.Addr[1], addr.Addr[2], addr.Addr[3])
port := int(addr.Port>>8 | addr.Port<<8)
logrus.Debugf("[Tproxy] getOriginalDst raw value: %d, parsed port: %d", addr.Port, port)
return &net.TCPAddr{
IP: ip,
Port: port,
}, nil
}