github.com/labulakalia/water@v0.0.5-0.20231118024244-f351ca6784b6/syscalls_linux.go (about)

     1  package water
     2  
     3  import (
     4  	"os"
     5  	"strings"
     6  	"syscall"
     7  	"unsafe"
     8  )
     9  
    10  const (
    11  	cIFFTUN        = 0x0001
    12  	cIFFTAP        = 0x0002
    13  	cIFFNOPI       = 0x1000
    14  	cIFFMULTIQUEUE = 0x0100
    15  )
    16  
    17  type ifReq struct {
    18  	Name  [0x10]byte
    19  	Flags uint16
    20  	pad   [0x28 - 0x10 - 2]byte
    21  }
    22  
    23  func ioctl(fd uintptr, request uintptr, argp uintptr) error {
    24  	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(request), argp)
    25  	if errno != 0 {
    26  		return os.NewSyscallError("ioctl", errno)
    27  	}
    28  	return nil
    29  }
    30  
    31  func setupFd(config Config, fd uintptr) (name string, err error) {
    32  	var flags uint16 = cIFFNOPI
    33  	if config.DeviceType == TUN {
    34  		flags |= cIFFTUN
    35  	} else {
    36  		flags |= cIFFTAP
    37  	}
    38  	if config.PlatformSpecificParams.MultiQueue {
    39  		flags |= cIFFMULTIQUEUE
    40  	}
    41  
    42  	if name, err = createInterface(fd, config.Name, flags); err != nil {
    43  		return "", err
    44  	}
    45  
    46  	if err = setDeviceOptions(fd, config); err != nil {
    47  		return "", err
    48  	}
    49  
    50  	return name, nil
    51  }
    52  
    53  func createInterface(fd uintptr, ifName string, flags uint16) (createdIFName string, err error) {
    54  	var req ifReq
    55  	req.Flags = flags
    56  	copy(req.Name[:], ifName)
    57  
    58  	err = ioctl(fd, syscall.TUNSETIFF, uintptr(unsafe.Pointer(&req)))
    59  	if err != nil {
    60  		return
    61  	}
    62  
    63  	createdIFName = strings.Trim(string(req.Name[:]), "\x00")
    64  	return
    65  }
    66  
    67  func setDeviceOptions(fd uintptr, config Config) (err error) {
    68  	if config.Permissions != nil {
    69  		if err = ioctl(fd, syscall.TUNSETOWNER, uintptr(config.Permissions.Owner)); err != nil {
    70  			return
    71  		}
    72  		if err = ioctl(fd, syscall.TUNSETGROUP, uintptr(config.Permissions.Group)); err != nil {
    73  			return
    74  		}
    75  	}
    76  
    77  	// set clear the persist flag
    78  	value := 0
    79  	if config.Persist {
    80  		value = 1
    81  	}
    82  	return ioctl(fd, syscall.TUNSETPERSIST, uintptr(value))
    83  }