//go:build linux package sdk import ( "fmt" "os/exec" "syscall" "unsafe" ) type tapInterface struct { Name string MTU int fd int } func openTap(name string, mtu int) (*tapInterface, error) { fd, err := syscall.Open("/dev/net/tun", syscall.O_RDWR, 0) if err != nil { return nil, fmt.Errorf("open /dev/net/tun: %w", err) } var ifr struct { name [16]byte flags uint16 } copy(ifr.name[:], []byte(name)) ifr.flags = 0x0002 | 0x1000 // IFF_TAP | IFF_NO_PI if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), 0x400454ca, uintptr(unsafe.Pointer(&ifr))); errno != 0 { syscall.Close(fd) return nil, fmt.Errorf("TUNSETIFF: %w", errno) } devName := string(ifr.name[:]) if idx := indexOfZero(devName); idx >= 0 { devName = devName[:idx] } ti := &tapInterface{Name: devName, MTU: mtu, fd: fd} s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0) if err == nil { defer syscall.Close(s) var mtuReq struct { name [16]byte mtu int32 } copy(mtuReq.name[:], []byte(devName)) mtuReq.mtu = int32(mtu) syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), 0x400c4a52, uintptr(unsafe.Pointer(&mtuReq))) } return ti, nil } func (ti *tapInterface) Read(buf []byte) (int, error) { return syscall.Read(ti.fd, buf) } func (ti *tapInterface) Write(buf []byte) error { _, err := syscall.Write(ti.fd, buf) return err } func (ti *tapInterface) Close() error { return syscall.Close(ti.fd) } func (ti *tapInterface) SetMAC(mac [6]byte) error { macStr := fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) return exec.Command("ip", "link", "set", ti.Name, "address", macStr).Run() } func (ti *tapInterface) SetIP(cidr string) error { if err := exec.Command("ip", "addr", "add", cidr, "dev", ti.Name).Run(); err != nil { return fmt.Errorf("add ip: %w", err) } if err := exec.Command("ip", "link", "set", ti.Name, "up").Run(); err != nil { return fmt.Errorf("link up: %w", err) } return nil } func indexOfZero(s string) int { for i, c := range []byte(s) { if c == 0 { return i } } return -1 }