Files
zeromesh/internal/tap/tap_linux.go

72 lines
1.5 KiB
Go

//go:build linux
package tap
import (
"fmt"
"os"
"syscall"
"unsafe"
)
const (
cIFF_TAP = 0x0002
cIFF_NO_PI = 0x1000
cTUNSETIFF = 0x400454ca
cSIOCSIFMTU = 0x8922
)
func openTap(name string, mtu int) (*Interface, error) {
fd, err := syscall.Open("/dev/net/tun", syscall.O_RDWR, 0)
if err != nil {
return nil, fmt.Errorf("open /dev/net/tun: %w (is TUN/TAP supported?)", err)
}
ifr := make([]byte, 40)
copy(ifr, []byte(name))
*(*uint16)(unsafe.Pointer(&ifr[16])) = uint16(cIFF_TAP | cIFF_NO_PI)
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), cTUNSETIFF, uintptr(unsafe.Pointer(&ifr[0])))
if errno != 0 {
syscall.Close(fd)
return nil, fmt.Errorf("ioctl TUNSETIFF: %w", errno)
}
if mtu > 0 {
mtuIfr := make([]byte, 40)
copy(mtuIfr, ifr[:16])
*(*int32)(unsafe.Pointer(&mtuIfr[16])) = int32(mtu)
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), cSIOCSIFMTU, uintptr(unsafe.Pointer(&mtuIfr[0])))
if errno != 0 {
syscall.Close(fd)
return nil, fmt.Errorf("ioctl SIOCSIFMTU: %w", errno)
}
}
return &Interface{
Name: name,
MTU: mtu,
fd: fd,
}, nil
}
func readBuf(fd int, buf []byte) (int, error) {
n, err := syscall.Read(fd, buf)
if err != nil {
return 0, os.NewSyscallError("read", err)
}
return n, nil
}
func writeBuf(fd int, buf []byte) (int, error) {
n, err := syscall.Write(fd, buf)
if err != nil {
return 0, os.NewSyscallError("write", err)
}
return n, nil
}
func closeFD(fd int) error {
return syscall.Close(fd)
}