//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) }