diff --git a/contrib/mobile/build b/contrib/mobile/build index 3c7b1d11..3f6b9bfc 100755 --- a/contrib/mobile/build +++ b/contrib/mobile/build @@ -37,7 +37,7 @@ if [ $IOS ]; then echo "Building framework for iOS" go get golang.org/x/mobile/bind gomobile bind \ - -target ios -tags mobile -o Yggdrasil.xcframework \ + -target ios,macos -tags mobile -o Yggdrasil.xcframework \ -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" \ ./contrib/mobile ./src/config; fi diff --git a/contrib/mobile/mobile.go b/contrib/mobile/mobile.go index 6b036094..4c1a8ef9 100644 --- a/contrib/mobile/mobile.go +++ b/contrib/mobile/mobile.go @@ -5,6 +5,7 @@ import ( "encoding/json" "net" "regexp" + "runtime/debug" "github.com/gologme/log" @@ -13,6 +14,7 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/core" "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" "github.com/yggdrasil-network/yggdrasil-go/src/multicast" + "github.com/yggdrasil-network/yggdrasil-go/src/tun" "github.com/yggdrasil-network/yggdrasil-go/src/version" _ "golang.org/x/mobile/bind" @@ -28,7 +30,9 @@ type Yggdrasil struct { iprwc *ipv6rwc.ReadWriteCloser config *config.NodeConfig multicast *multicast.Multicast + tun *tun.TunAdapter // optional log MobileLogger + logger *log.Logger } // StartAutoconfigure starts a node with a randomly generated config @@ -39,6 +43,8 @@ func (m *Yggdrasil) StartAutoconfigure() error { // StartJSON starts a node with the given JSON config. You can get JSON config // (rather than HJSON) by using the GenerateConfigJSON() function func (m *Yggdrasil) StartJSON(configjson []byte) error { + debug.SetMemoryLimit(1024 * 1024 * 40) + logger := log.New(m.log, "", 0) logger.EnableLevel("error") logger.EnableLevel("warn") @@ -88,9 +94,9 @@ func (m *Yggdrasil) StartJSON(configjson []byte) error { Priority: uint8(intf.Priority), }) } - m.multicast, err = multicast.New(m.core, logger, options...) + m.multicast, err = multicast.New(m.core, m.logger, options...) if err != nil { - logger.Errorln("An error occurred starting multicast:", err) + m.logger.Errorln("An error occurred starting multicast:", err) } } @@ -153,6 +159,11 @@ func (m *Yggdrasil) Stop() error { if err := m.multicast.Stop(); err != nil { return err } + if m.tun != nil { + if err := m.tun.Stop(); err != nil { + return err + } + } m.core.Stop() return nil } diff --git a/contrib/mobile/mobile_ios.go b/contrib/mobile/mobile_ios.go index fedee2db..c7747ea3 100644 --- a/contrib/mobile/mobile_ios.go +++ b/contrib/mobile/mobile_ios.go @@ -15,6 +15,8 @@ void Log(const char *text) { import "C" import ( "unsafe" + + "github.com/yggdrasil-network/yggdrasil-go/src/tun" ) type MobileLogger struct { @@ -26,3 +28,13 @@ func (nsl MobileLogger) Write(p []byte) (n int, err error) { C.Log(cstr) return len(p), nil } + +func (m *Yggdrasil) TakeOverTUN(fd int32) error { + options := []tun.SetupOption{ + tun.FileDescriptor(fd), + tun.InterfaceMTU(m.iprwc.MTU()), + } + var err error + m.tun, err = tun.New(m.iprwc, m.logger, options...) + return err +} diff --git a/src/tun/options.go b/src/tun/options.go index 7be79211..58d3d80c 100644 --- a/src/tun/options.go +++ b/src/tun/options.go @@ -6,6 +6,8 @@ func (m *TunAdapter) _applyOption(opt SetupOption) { m.config.name = v case InterfaceMTU: m.config.mtu = v + case FileDescriptor: + m.config.fd = int32(v) } } @@ -15,6 +17,8 @@ type SetupOption interface { type InterfaceName string type InterfaceMTU uint64 +type FileDescriptor int32 -func (a InterfaceName) isSetupOption() {} -func (a InterfaceMTU) isSetupOption() {} +func (a InterfaceName) isSetupOption() {} +func (a InterfaceMTU) isSetupOption() {} +func (a FileDescriptor) isSetupOption() {} diff --git a/src/tun/tun.go b/src/tun/tun.go index 7964ab9d..cca3af5b 100644 --- a/src/tun/tun.go +++ b/src/tun/tun.go @@ -44,6 +44,7 @@ type TunAdapter struct { isOpen bool isEnabled bool // Used by the writer to drop sessionTraffic if not enabled config struct { + fd int32 name InterfaceName mtu InterfaceMTU } @@ -126,7 +127,13 @@ func (tun *TunAdapter) _start() error { if tun.rwc.MaxMTU() < mtu { mtu = tun.rwc.MaxMTU() } - if err := tun.setup(string(tun.config.name), addr, mtu); err != nil { + var err error + if tun.config.fd > 0 { + err = tun.setupFD(tun.config.fd, addr, mtu) + } else { + err = tun.setup(string(tun.config.name), addr, mtu) + } + if err != nil { return err } if tun.MTU() != mtu { diff --git a/src/tun/tun_bsd.go b/src/tun/tun_bsd.go index 9a8f70ce..3910ccef 100644 --- a/src/tun/tun_bsd.go +++ b/src/tun/tun_bsd.go @@ -5,6 +5,7 @@ package tun import ( "encoding/binary" + "fmt" "os/exec" "strconv" "strings" @@ -88,6 +89,11 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error { return tun.setupAddress(addr) } +// Configures the "utun" adapter from an existing file descriptor. +func (tun *TunAdapter) setupFD(fd int32, addr string, mtu uint64) error { + return fmt.Errorf("setup via FD not supported on this platform") +} + func (tun *TunAdapter) setupAddress(addr string) error { var sfd int var err error diff --git a/src/tun/tun_darwin.go b/src/tun/tun_darwin.go index 29cfe959..b8e32a2f 100644 --- a/src/tun/tun_darwin.go +++ b/src/tun/tun_darwin.go @@ -1,5 +1,5 @@ -//go:build !mobile -// +build !mobile +//go:build darwin || ios +// +build darwin ios package tun @@ -7,6 +7,7 @@ package tun import ( "encoding/binary" + "os" "strconv" "strings" "unsafe" @@ -34,6 +35,31 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error { return tun.setupAddress(addr) } +// Configures the "utun" adapter from an existing file descriptor. +func (tun *TunAdapter) setupFD(fd int32, addr string, mtu uint64) error { + dfd, err := unix.Dup(int(fd)) + if err != nil { + return err + } + err = unix.SetNonblock(dfd, true) + if err != nil { + unix.Close(dfd) + return err + } + iface, err := wgtun.CreateTUNFromFile(os.NewFile(uintptr(dfd), "/dev/tun"), 0) + if err != nil { + unix.Close(dfd) + return err + } + tun.iface = iface + if m, err := iface.MTU(); err == nil { + tun.mtu = getSupportedMTU(uint64(m)) + } else { + tun.mtu = 0 + } + return nil // tun.setupAddress(addr) +} + const ( darwin_SIOCAIFADDR_IN6 = 2155899162 // netinet6/in6_var.h darwin_IN6_IFF_NODAD = 0x0020 // netinet6/in6_var.h diff --git a/src/tun/tun_linux.go b/src/tun/tun_linux.go index 1e42b7b8..16deb8e5 100644 --- a/src/tun/tun_linux.go +++ b/src/tun/tun_linux.go @@ -6,6 +6,8 @@ package tun // The linux platform specific tun parts import ( + "fmt" + "github.com/vishvananda/netlink" wgtun "golang.zx2c4.com/wireguard/tun" ) @@ -28,6 +30,11 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error { return tun.setupAddress(addr) } +// Configures the "utun" adapter from an existing file descriptor. +func (tun *TunAdapter) setupFD(fd int32, addr string, mtu uint64) error { + return fmt.Errorf("setup via FD not supported on this platform") +} + // Configures the TUN adapter with the correct IPv6 address and MTU. Netlink // is used to do this, so there is not a hard requirement on "ip" or "ifconfig" // to exist on the system, but this will fail if Netlink is not present in the diff --git a/src/tun/tun_other.go b/src/tun/tun_other.go index c618d837..dd33708e 100644 --- a/src/tun/tun_other.go +++ b/src/tun/tun_other.go @@ -7,6 +7,8 @@ package tun // If your platform supports tun devices, you could try configuring it manually import ( + "fmt" + wgtun "golang.zx2c4.com/wireguard/tun" ) @@ -25,6 +27,11 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error { return tun.setupAddress(addr) } +// Configures the "utun" adapter from an existing file descriptor. +func (tun *TunAdapter) setupFD(fd int32, addr string, mtu uint64) error { + return fmt.Errorf("setup via FD not supported on this platform") +} + // We don't know how to set the IPv6 address on an unknown platform, therefore // write about it to stdout and don't try to do anything further. func (tun *TunAdapter) setupAddress(addr string) error { diff --git a/src/tun/tun_windows.go b/src/tun/tun_windows.go index 1a8aa1f3..b3bb0c78 100644 --- a/src/tun/tun_windows.go +++ b/src/tun/tun_windows.go @@ -6,6 +6,7 @@ package tun import ( "bytes" "errors" + "fmt" "log" "net" @@ -50,6 +51,11 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error { }) } +// Configures the "utun" adapter from an existing file descriptor. +func (tun *TunAdapter) setupFD(fd int32, addr string, mtu uint64) error { + return fmt.Errorf("setup via FD not supported on this platform") +} + // Sets the MTU of the TUN adapter. func (tun *TunAdapter) setupMTU(mtu uint64) error { if tun.iface == nil || tun.Name() == "" {