Feature: add REDIRECT IPv6 support for FreeBSD. (#2768)

Upstream patch from FreeBSD ports which adds IPv6 support.
This commit is contained in:
Yonas Yanfa 2023-05-25 09:13:42 -04:00 committed by GitHub
parent ccd6d321cd
commit 2b6dd2a909
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 29 additions and 15 deletions

View File

@ -1,12 +1,16 @@
package redir package redir
import ( import (
"encoding/binary"
"errors" "errors"
"net" "net"
"net/netip"
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
"golang.org/x/sys/unix"
) )
const ( const (
@ -25,28 +29,38 @@ func parserPacket(conn net.Conn) (socks5.Addr, error) {
return nil, err return nil, err
} }
var addr socks5.Addr var addr netip.AddrPort
rc.Control(func(fd uintptr) { rc.Control(func(fd uintptr) {
addr, err = getorigdst(fd) if ip4 := c.LocalAddr().(*net.TCPAddr).IP.To4(); ip4 != nil {
addr, err = getorigdst(fd)
} else {
addr, err = getorigdst6(fd)
}
}) })
return addr, err return socks5.AddrFromStdAddrPort(addr), err
} }
// Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c // Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
func getorigdst(fd uintptr) (socks5.Addr, error) { func getorigdst(fd uintptr) (netip.AddrPort, error) {
raw := syscall.RawSockaddrInet4{} addr := unix.RawSockaddrInet4{}
siz := unsafe.Sizeof(raw) size := uint32(unsafe.Sizeof(addr))
_, _, err := syscall.Syscall6(syscall.SYS_GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0) _, _, err := syscall.Syscall6(syscall.SYS_GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(&size)), 0)
if err != 0 { if err != 0 {
return nil, err return netip.AddrPort{}, err
} }
port := binary.BigEndian.Uint16((*(*[2]byte)(unsafe.Pointer(&addr.Port)))[:])
addr := make([]byte, 1+net.IPv4len+2) return netip.AddrPortFrom(netip.AddrFrom4(addr.Addr), port), nil
addr[0] = socks5.AtypIPv4 }
copy(addr[1:1+net.IPv4len], raw.Addr[:])
port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian func getorigdst6(fd uintptr) (netip.AddrPort, error) {
addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1] addr := unix.RawSockaddrInet6{}
return addr, nil size := uint32(unsafe.Sizeof(addr))
_, _, err := syscall.Syscall6(syscall.SYS_GETSOCKOPT, fd, syscall.IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(&size)), 0);
if err != 0 {
return netip.AddrPort{}, err
}
port := binary.BigEndian.Uint16((*(*[2]byte)(unsafe.Pointer(&addr.Port)))[:])
return netip.AddrPortFrom(netip.AddrFrom16(addr.Addr), port), nil
} }