dae/component/outbound/dialer/sockopt.go
2023-02-07 21:11:37 +08:00

128 lines
3.5 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
addr := addrPort.Addr()
switch {
case addr.Is4() || addr.Is4In6():
a4 := &syscall.SockaddrInet4{
Port: int(addrPort.Port()),
}
a4.Addr = addr.As4()
sockAddr = a4
case addr.Is6():
a6 := &syscall.SockaddrInet6{
Port: int(addrPort.Port()),
}
zone := addrPort.Addr().Zone()
if zone != "" {
//if link, e := netlink.LinkByName(zone); e == nil {
// a6.ZoneId = uint32(link.Attrs().Index)
//}
return fmt.Errorf("unsupported ipv6 zone")
}
a6.Addr = addr.As16()
sockAddr = a6
default:
return fmt.Errorf("unexpected length of ip")
}
return syscall.Bind(int(fd), sockAddr)
}