mirror of
https://github.com/daeuniverse/dae.git
synced 2025-07-31 15:19:45 +07:00
refactor: refactor lan tproxy using sk_assign
This commit is contained in:
119
component/outbound/dialer/sockopt.go
Normal file
119
component/outbound/dialer/sockopt.go
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
*/
|
||||
|
||||
package dialer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/sys/unix"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var fwmarkIoctl int
|
||||
|
||||
func init() {
|
||||
switch runtime.GOOS {
|
||||
case "linux", "android":
|
||||
fwmarkIoctl = 36 /* unix.SO_MARK */
|
||||
case "freebsd":
|
||||
fwmarkIoctl = 0x1015 /* unix.SO_USER_COOKIE */
|
||||
case "openbsd":
|
||||
fwmarkIoctl = 0x1021 /* unix.SO_RTABLE */
|
||||
}
|
||||
}
|
||||
|
||||
func SoMarkControl(c syscall.RawConn, mark int) error {
|
||||
var sockOptErr error
|
||||
controlErr := c.Control(func(fd uintptr) {
|
||||
err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, fwmarkIoctl, mark)
|
||||
if err != nil {
|
||||
sockOptErr = fmt.Errorf("error setting SO_MARK socket option: %w", err)
|
||||
}
|
||||
})
|
||||
if controlErr != nil {
|
||||
return fmt.Errorf("error invoking socket control function: %w", controlErr)
|
||||
}
|
||||
return sockOptErr
|
||||
}
|
||||
|
||||
func TproxyControl(c syscall.RawConn) error {
|
||||
var sockOptErr error
|
||||
controlErr := c.Control(func(fd uintptr) {
|
||||
// - https://www.kernel.org/doc/Documentation/networking/tproxy.txt
|
||||
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_TRANSPARENT, 1); err != nil {
|
||||
sockOptErr = fmt.Errorf("error setting IP_TRANSPARENT socket option: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
|
||||
sockOptErr = fmt.Errorf("error setting SO_REUSEADDR socket option: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
e4 := unix.SetsockoptInt(int(fd), syscall.SOL_IP, unix.IP_RECVORIGDSTADDR, 1)
|
||||
e6 := unix.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1)
|
||||
if e4 != nil && e6 != nil {
|
||||
if e4 != nil {
|
||||
sockOptErr = fmt.Errorf("error setting IP_RECVORIGDSTADDR socket option: %w", e4)
|
||||
} else {
|
||||
sockOptErr = fmt.Errorf("error setting IPV6_RECVORIGDSTADDR socket option: %w", e6)
|
||||
}
|
||||
return
|
||||
}
|
||||
})
|
||||
if controlErr != nil {
|
||||
return fmt.Errorf("error invoking socket control function: %w", controlErr)
|
||||
}
|
||||
return sockOptErr
|
||||
}
|
||||
|
||||
func BindControl(c syscall.RawConn, lAddrPort netip.AddrPort) error {
|
||||
var sockOptErr error
|
||||
controlErr := c.Control(func(fd uintptr) {
|
||||
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
|
||||
sockOptErr = fmt.Errorf("error setting IP_TRANSPARENT socket option: %w", err)
|
||||
}
|
||||
if err := bindAddr(fd, lAddrPort); err != nil {
|
||||
sockOptErr = fmt.Errorf("error bindAddr: %w", err)
|
||||
}
|
||||
})
|
||||
if controlErr != nil {
|
||||
return fmt.Errorf("error invoking socket control function: %w", controlErr)
|
||||
}
|
||||
return sockOptErr
|
||||
}
|
||||
|
||||
func bindAddr(fd uintptr, addrPort netip.AddrPort) error {
|
||||
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
|
||||
return fmt.Errorf("error setting SO_REUSEADDR socket option: %w", err)
|
||||
}
|
||||
|
||||
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
|
||||
return fmt.Errorf("error setting SO_REUSEPORT socket option: %w", err)
|
||||
}
|
||||
|
||||
var sockAddr syscall.Sockaddr
|
||||
|
||||
switch addr := addrPort.Addr().AsSlice(); len(addr) {
|
||||
case 4:
|
||||
a4 := &syscall.SockaddrInet4{
|
||||
Port: int(addrPort.Port()),
|
||||
}
|
||||
copy(a4.Addr[:], addr)
|
||||
sockAddr = a4
|
||||
case 16:
|
||||
a6 := &syscall.SockaddrInet6{
|
||||
Port: int(addrPort.Port()),
|
||||
}
|
||||
copy(a6.Addr[:], addr)
|
||||
sockAddr = a6
|
||||
default:
|
||||
return fmt.Errorf("unexpected length of ip")
|
||||
}
|
||||
|
||||
return syscall.Bind(int(fd), sockAddr)
|
||||
}
|
Reference in New Issue
Block a user