github.com/metacubex/sing-tun@v0.2.7-0.20240512075008-89e7c6208eec/tun_linux_flags.go (about)

     1  //go:build linux
     2  
     3  package tun
     4  
     5  import (
     6  	"os"
     7  	"syscall"
     8  	"unsafe"
     9  
    10  	E "github.com/sagernet/sing/common/exceptions"
    11  
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  func checkVNETHDREnabled(fd int, name string) (bool, error) {
    16  	ifr, err := unix.NewIfreq(name)
    17  	if err != nil {
    18  		return false, err
    19  	}
    20  	err = unix.IoctlIfreq(fd, unix.TUNGETIFF, ifr)
    21  	if err != nil {
    22  		return false, os.NewSyscallError("TUNGETIFF", err)
    23  	}
    24  	return ifr.Uint16()&unix.IFF_VNET_HDR != 0, nil
    25  }
    26  
    27  func setTCPOffload(fd int) error {
    28  	const (
    29  		// TODO: support TSO with ECN bits
    30  		tunOffloads = unix.TUN_F_CSUM | unix.TUN_F_TSO4 | unix.TUN_F_TSO6
    31  	)
    32  	err := unix.IoctlSetInt(fd, unix.TUNSETOFFLOAD, tunOffloads)
    33  	if err != nil {
    34  		return E.Cause(os.NewSyscallError("TUNSETOFFLOAD", err), "enable offload")
    35  	}
    36  	return nil
    37  }
    38  
    39  type ifreqData struct {
    40  	ifrName [unix.IFNAMSIZ]byte
    41  	ifrData uintptr
    42  }
    43  
    44  type ethtoolValue struct {
    45  	cmd  uint32
    46  	data uint32
    47  }
    48  
    49  //go:linkname ioctlPtr golang.org/x/sys/unix.ioctlPtr
    50  func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error)
    51  
    52  func checkChecksumOffload(name string, cmd uint32) (bool, error) {
    53  	fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
    54  	if err != nil {
    55  		return false, err
    56  	}
    57  	defer syscall.Close(fd)
    58  	ifr := ifreqData{}
    59  	copy(ifr.ifrName[:], name)
    60  	data := ethtoolValue{cmd: cmd}
    61  	ifr.ifrData = uintptr(unsafe.Pointer(&data))
    62  	err = ioctlPtr(fd, unix.SIOCETHTOOL, unsafe.Pointer(&ifr))
    63  	if err != nil {
    64  		return false, os.NewSyscallError("SIOCETHTOOL ETHTOOL_GTXCSUM", err)
    65  	}
    66  	return data.data == 0, nil
    67  }
    68  
    69  func setChecksumOffload(name string, cmd uint32) error {
    70  	fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
    71  	if err != nil {
    72  		return err
    73  	}
    74  	defer syscall.Close(fd)
    75  	ifr := ifreqData{}
    76  	copy(ifr.ifrName[:], name)
    77  	data := ethtoolValue{cmd: cmd, data: 0}
    78  	ifr.ifrData = uintptr(unsafe.Pointer(&data))
    79  	err = ioctlPtr(fd, unix.SIOCETHTOOL, unsafe.Pointer(&ifr))
    80  	if err != nil {
    81  		return os.NewSyscallError("SIOCETHTOOL ETHTOOL_STXCSUM", err)
    82  	}
    83  	return nil
    84  }