fix(redirect_tcp): client got reset under i386

it seems like syscall.Syscall6(SYS_SOCKETCALL, SYS_GETSOCKOPT, ...)
always failed with EFAULT.

so we call syscall.socketcall() instead.

close: #583
This commit is contained in:
Haruue Icymoon 2023-03-15 00:13:36 +08:00
parent 1b3b038728
commit 779e962d49
No known key found for this signature in database
GPG Key ID: F6083B28CBCBC148
5 changed files with 50 additions and 45 deletions

View File

@ -0,0 +1,17 @@
//go:build !386
// +build !386
package redirect
import (
"syscall"
"unsafe"
)
func getsockopt(s uintptr, level uintptr, name uintptr, val unsafe.Pointer, vallen *uint32) (err error) {
_, _, e := syscall.Syscall6(syscall.SYS_GETSOCKOPT, s, level, name, uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e != 0 {
err = e
}
return
}

View File

@ -0,0 +1,22 @@
package redirect
import (
"syscall"
"unsafe"
)
const (
SYS_GETSOCKOPT = 15
)
// we cannot call socketcall with syscall.Syscall6, it always fails with EFAULT.
// we have to call syscall.socketcall with this trick.
func syscall_socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno)
func getsockopt(s uintptr, level uintptr, name uintptr, val unsafe.Pointer, vallen *uint32) (err error) {
_, e := syscall_socketcall(SYS_GETSOCKOPT, s, level, name, uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e != 0 {
err = e
}
return
}

View File

@ -1,6 +1,3 @@
//go:build !386
// +build !386
package redirect
import (
@ -23,13 +20,11 @@ func getOrigDst(fd uintptr) (*sockAddr, error) {
var addr sockAddr
addrSize := uint32(unsafe.Sizeof(addr))
// try IPv6 first
_, _, err := syscall.Syscall6(syscall.SYS_GETSOCKOPT, fd, syscall.SOL_IPV6, IP6T_SO_ORIGINAL_DST,
uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(&addrSize)), 0)
if err != 0 {
err := getsockopt(fd, syscall.SOL_IPV6, IP6T_SO_ORIGINAL_DST, unsafe.Pointer(&addr), &addrSize)
if err != nil {
// try IPv4
_, _, err = syscall.Syscall6(syscall.SYS_GETSOCKOPT, fd, syscall.SOL_IP, SO_ORIGINAL_DST,
uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(&addrSize)), 0)
if err != 0 {
err = getsockopt(fd, syscall.SOL_IP, SO_ORIGINAL_DST, unsafe.Pointer(&addr), &addrSize)
if err != nil {
// failed
return nil, err
}

View File

@ -1,36 +0,0 @@
package redirect
import (
"syscall"
"unsafe"
)
const (
SYS_GETSOCKOPT = 15
SO_ORIGINAL_DST = 80
IP6T_SO_ORIGINAL_DST = 80
)
type sockAddr struct {
family uint16
port [2]byte // big endian regardless of host byte order
data [24]byte // check sockaddr_in or sockaddr_in6 for more information
}
func getOrigDst(fd uintptr) (*sockAddr, error) {
var addr sockAddr
addrSize := uint32(unsafe.Sizeof(addr))
// try IPv6 first
_, _, err := syscall.Syscall6(syscall.SYS_SOCKETCALL, SYS_GETSOCKOPT, fd, syscall.SOL_IPV6, IP6T_SO_ORIGINAL_DST,
uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(&addrSize)))
if err != 0 {
// try IPv4
_, _, err = syscall.Syscall6(syscall.SYS_SOCKETCALL, SYS_GETSOCKOPT, fd, syscall.SOL_IP, SO_ORIGINAL_DST,
uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(&addrSize)))
if err != 0 {
// failed
return nil, err
}
}
return &addr, nil
}

View File

@ -0,0 +1,7 @@
//go:build gc
// +build gc
#include "textflag.h"
TEXT ·syscall_socketcall(SB),NOSPLIT,$0-36
JMP syscall·socketcall(SB)