mirror of
https://github.com/SunBK201/UA3F.git
synced 2025-12-16 16:57:08 +00:00
62 lines
1.5 KiB
Go
62 lines
1.5 KiB
Go
//go:build linux
|
|
|
|
package base
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"syscall"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
const SO_MARK = 0xc9
|
|
|
|
// Connect dials the target address with SO_MARK set and returns the connection.
|
|
func Connect(addr string, mark int) (target net.Conn, err error) {
|
|
dialer := net.Dialer{
|
|
Control: func(network, address string, c syscall.RawConn) error {
|
|
return c.Control(func(fd uintptr) {
|
|
unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_MARK, mark)
|
|
})
|
|
},
|
|
}
|
|
|
|
conn, err := dialer.Dial("tcp", addr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Connect dialer.Dial SO_MARK(%d): %v", mark, err)
|
|
}
|
|
return conn, nil
|
|
}
|
|
|
|
// GetOriginalDstAddr retrieves the original destination address of the redirected connection.
|
|
func GetOriginalDstAddr(conn net.Conn) (addr string, err error) {
|
|
fd, err := GetConnFD(conn)
|
|
if err != nil {
|
|
return "", fmt.Errorf("GetConnFD: %v", err)
|
|
}
|
|
raw, err := unix.GetsockoptIPv6Mreq(fd, unix.SOL_IP, unix.SO_ORIGINAL_DST)
|
|
if err != nil {
|
|
return "", fmt.Errorf("unix.GetsockoptIPv6Mreq: %v", err)
|
|
}
|
|
|
|
ip := net.IPv4(raw.Multiaddr[4], raw.Multiaddr[5], raw.Multiaddr[6], raw.Multiaddr[7])
|
|
port := uint16(raw.Multiaddr[2])<<8 + uint16(raw.Multiaddr[3])
|
|
return fmt.Sprintf("%s:%d", ip.String(), port), nil
|
|
}
|
|
|
|
func GetConnFD(conn net.Conn) (fd int, err error) {
|
|
tcpConn, ok := conn.(*net.TCPConn)
|
|
if !ok {
|
|
return 0, errors.New("GetConnFD connection is not *net.TCPConn")
|
|
}
|
|
file, err := tcpConn.File()
|
|
if err != nil {
|
|
return 0, fmt.Errorf("tcpConn.File: %v", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
return int(file.Fd()), nil
|
|
}
|