72 lines
1.5 KiB
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)
|
|
}
|