mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-15 04:53:00 +08:00
55 lines
1.2 KiB
Go
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
|
|
}
|