mirror of
https://github.com/yggdrasil-network/water.git
synced 2025-05-19 16:35:10 +03:00
122 lines
2.4 KiB
Go
122 lines
2.4 KiB
Go
// +build linux
|
|
|
|
package water
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
cIFFTUN = 0x0001
|
|
cIFFTAP = 0x0002
|
|
cIFFNOPI = 0x1000
|
|
cIFFMULTIQUEUE = 0x0100
|
|
)
|
|
|
|
type ifReq struct {
|
|
Name [0x10]byte
|
|
Flags uint16
|
|
pad [0x28 - 0x10 - 2]byte
|
|
}
|
|
|
|
func ioctl(fd uintptr, request uintptr, argp uintptr) error {
|
|
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(request), argp)
|
|
if errno != 0 {
|
|
return os.NewSyscallError("ioctl", errno)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func newTAP(config Config) (ifce *Interface, err error) {
|
|
file, err := openTun()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var flags uint16
|
|
flags = cIFFTAP | cIFFNOPI
|
|
if config.PlatformSpecificParams.MultiQueue {
|
|
flags |= cIFFMULTIQUEUE
|
|
}
|
|
name, err := createInterface(file.Fd(), config.Name, flags)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err = setDeviceOptions(file.Fd(), config); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ifce = &Interface{isTAP: true, ReadWriteCloser: file, name: name}
|
|
return
|
|
}
|
|
|
|
func newTUN(config Config) (ifce *Interface, err error) {
|
|
file, err := openTun()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var flags uint16
|
|
flags = cIFFTUN | cIFFNOPI
|
|
if config.PlatformSpecificParams.MultiQueue {
|
|
flags |= cIFFMULTIQUEUE
|
|
}
|
|
name, err := createInterface(file.Fd(), config.Name, flags)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err = setDeviceOptions(file.Fd(), config); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ifce = &Interface{isTAP: false, ReadWriteCloser: file, name: name}
|
|
return
|
|
}
|
|
|
|
func createInterface(fd uintptr, ifName string, flags uint16) (createdIFName string, err error) {
|
|
var req ifReq
|
|
req.Flags = flags
|
|
copy(req.Name[:], ifName)
|
|
|
|
err = ioctl(fd, syscall.TUNSETIFF, uintptr(unsafe.Pointer(&req)))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
createdIFName = strings.Trim(string(req.Name[:]), "\x00")
|
|
return
|
|
}
|
|
|
|
func setDeviceOptions(fd uintptr, config Config) (err error) {
|
|
if config.Permissions != nil {
|
|
if err = ioctl(fd, syscall.TUNSETOWNER, uintptr(config.Permissions.Owner)); err != nil {
|
|
return
|
|
}
|
|
if err = ioctl(fd, syscall.TUNSETGROUP, uintptr(config.Permissions.Group)); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
// set clear the persist flag
|
|
value := 0
|
|
if config.Persist {
|
|
value = 1
|
|
}
|
|
|
|
return ioctl(fd, syscall.TUNSETPERSIST, uintptr(value))
|
|
}
|
|
|
|
func openTun() (*os.File, error) {
|
|
tunFile := "/dev/net/tun"
|
|
bfile, err := os.OpenFile(tunFile, os.O_RDWR, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return os.NewFile(bfile.Fd(), tunFile), nil
|
|
}
|