github.com/chwjbn/xclash@v0.2.0/listener/redir/tcp_linux.go (about) 1 package redir 2 3 import ( 4 "errors" 5 "net" 6 "syscall" 7 "unsafe" 8 9 "github.com/chwjbn/xclash/transport/socks5" 10 ) 11 12 const ( 13 SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv4.h 14 IP6T_SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv6/ip6_tables.h 15 ) 16 17 func parserPacket(conn net.Conn) (socks5.Addr, error) { 18 c, ok := conn.(*net.TCPConn) 19 if !ok { 20 return nil, errors.New("only work with TCP connection") 21 } 22 23 rc, err := c.SyscallConn() 24 if err != nil { 25 return nil, err 26 } 27 28 var addr socks5.Addr 29 30 rc.Control(func(fd uintptr) { 31 addr, err = getorigdst(fd) 32 }) 33 34 return addr, err 35 } 36 37 // Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 38 func getorigdst(fd uintptr) (socks5.Addr, error) { 39 raw := syscall.RawSockaddrInet4{} 40 siz := unsafe.Sizeof(raw) 41 if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { 42 return nil, err 43 } 44 45 addr := make([]byte, 1+net.IPv4len+2) 46 addr[0] = socks5.AtypIPv4 47 copy(addr[1:1+net.IPv4len], raw.Addr[:]) 48 port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian 49 addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1] 50 return addr, nil 51 }