mirror of https://github.com/Dreamacro/clash.git
Feature: add REDIRECT IPv6 support for FreeBSD. (#2768)
Upstream patch from FreeBSD ports which adds IPv6 support.
This commit is contained in:
parent
ccd6d321cd
commit
2b6dd2a909
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue