diff --git a/src/yggdrasil/tun.go b/src/yggdrasil/tun.go index 49acff6..b22a341 100644 --- a/src/yggdrasil/tun.go +++ b/src/yggdrasil/tun.go @@ -2,6 +2,7 @@ package yggdrasil // This manages the tun driver to send/recv packets to/from applications +import "os" import ethernet "github.com/songgao/packets/ethernet" const IPv6_HEADER_LENGTH = 40 @@ -14,6 +15,7 @@ type tunInterface interface { Read(to []byte) (int, error) Write(from []byte) (int, error) Close() error + FD() *os.File } type tunDevice struct { diff --git a/src/yggdrasil/tun_bsd.go b/src/yggdrasil/tun_bsd.go index 67e3b6f..a6a5adc 100644 --- a/src/yggdrasil/tun_bsd.go +++ b/src/yggdrasil/tun_bsd.go @@ -2,16 +2,18 @@ package yggdrasil -import "fmt" import "os/exec" import "strings" +import "unsafe" +import "syscall" +import "golang.org/x/sys/unix" import water "github.com/neilalexander/water" // This is to catch BSD platforms -const TUNSIFINFO = (0x80000000) | ((4 & 0x1fff) << 16) | uint32(byte('t'))<<8 | 91 -const TUNGIFINFO = (0x40000000) | ((4 & 0x1fff) << 16) | uint32(byte('t'))<<8 | 92 +const TUNSIFINFO = (0x80000000) | ((12 & 0x1fff) << 16) | uint32(byte('t'))<<8 | 91 +const TUNGIFINFO = (0x40000000) | ((12 & 0x1fff) << 16) | uint32(byte('t'))<<8 | 92 const SIOCAIFADDR_IN6 = (0x80000000) | ((4 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 27 type in6_addrlifetime struct { @@ -40,10 +42,10 @@ type in6_aliasreq struct { } type tuninfo struct { - tun_baudrate int - tun_mtu int16 - tun_type uint8 - tun_dummy uint8 + tun_mtu uint16 + tun_type uint32 + tun_flags uint32 + tun_dummy uint16 } func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) error { @@ -67,23 +69,46 @@ func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) } func (tun *tunDevice) setupAddress(addr string) error { + fd := tun.iface.FD().Fd() + var err error + var ti tuninfo + + // Get the existing interface flags + if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(TUNGIFINFO), uintptr(unsafe.Pointer(&ti))); errno != 0 { + err = errno + tun.core.log.Printf("Error in TUNGIFINFO: %v", errno) + return err + } + tun.core.log.Printf("TUNGIFINFO: %+v", ti) + + // Set the new MTU + ti.tun_mtu = uint16(tun.mtu) + + // Set the new interface flags + ti.tun_flags |= syscall.IFF_UP + switch { + case tun.iface.IsTAP(): + ti.tun_flags |= syscall.IFF_MULTICAST + ti.tun_flags |= syscall.IFF_BROADCAST + case tun.iface.IsTUN(): + ti.tun_flags |= syscall.IFF_POINTOPOINT + } + + // Set the new interface flags + tun.core.log.Printf("TUNSIFINFO: %+v", ti) + if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(TUNSIFINFO), uintptr(unsafe.Pointer(&ti))); errno != 0 { + err = errno + tun.core.log.Printf("Error in TUNSIFINFO: %v", errno) + return err + } + // Set address cmd := exec.Command("ifconfig", tun.iface.Name(), "inet6", addr) tun.core.log.Printf("ifconfig command: %v", strings.Join(cmd.Args, " ")) output, err := cmd.CombinedOutput() if err != nil { - tun.core.log.Printf("ipconfig failed: %v.", err) + tun.core.log.Printf("ifconfig failed: %v.", err) tun.core.log.Println(string(output)) - return err - } - // Set MTU and bring device up - cmd = exec.Command("ifconfig", tun.iface.Name(), "mtu", fmt.Sprintf("%d", tun.mtu), "up") - tun.core.log.Printf("ifconfig command: %v", strings.Join(cmd.Args, " ")) - output, err = cmd.CombinedOutput() - if err != nil { - tun.core.log.Printf("ipconfig failed: %v.", err) - tun.core.log.Println(string(output)) - return err } return nil