Clash.Meta/proxy/redir/tcp_linux.go

52 lines
1.2 KiB
Go
Raw Normal View History

2018-08-12 04:00:34 +08:00
package redir
import (
"errors"
"net"
"syscall"
"unsafe"
2019-04-25 13:48:47 +08:00
"github.com/Dreamacro/clash/component/socks5"
2018-08-12 04:00:34 +08:00
)
const (
SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv4.h
IP6T_SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv6/ip6_tables.h
)
2019-04-25 13:48:47 +08:00
func parserPacket(conn net.Conn) (socks5.Addr, error) {
2018-08-12 04:00:34 +08:00
c, ok := conn.(*net.TCPConn)
if !ok {
return nil, errors.New("only work with TCP connection")
}
rc, err := c.SyscallConn()
if err != nil {
return nil, err
}
2019-04-25 13:48:47 +08:00
var addr socks5.Addr
2018-08-12 04:00:34 +08:00
rc.Control(func(fd uintptr) {
addr, err = getorigdst(fd)
})
return addr, err
}
// Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
2019-04-25 13:48:47 +08:00
func getorigdst(fd uintptr) (socks5.Addr, error) {
2018-08-12 04:00:34 +08:00
raw := syscall.RawSockaddrInet4{}
siz := unsafe.Sizeof(raw)
if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil {
return nil, err
}
addr := make([]byte, 1+net.IPv4len+2)
2019-04-25 13:48:47 +08:00
addr[0] = socks5.AtypIPv4
2018-08-12 04:00:34 +08:00
copy(addr[1:1+net.IPv4len], raw.Addr[:])
port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian
addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1]
return addr, nil
}