mirror of
https://github.com/daeuniverse/dae.git
synced 2025-01-27 16:11:05 +07:00
120 lines
3.3 KiB
Go
120 lines
3.3 KiB
Go
|
/*
|
||
|
* 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)
|
||
|
}
|