From 680434b58689c022540c2dc2a23d4739fc983e8f Mon Sep 17 00:00:00 2001 From: Andrew Bulhak Date: Tue, 30 Jul 2024 18:18:07 +0200 Subject: [PATCH] Rationalise wgTurnOn(,Multihop,IAN), deduplicating repeated code --- Sources/WireGuardKitGo/api-apple.go | 227 ++++++++++++---------------- 1 file changed, 94 insertions(+), 133 deletions(-) diff --git a/Sources/WireGuardKitGo/api-apple.go b/Sources/WireGuardKitGo/api-apple.go index f543bb88d..55617fa2f 100644 --- a/Sources/WireGuardKitGo/api-apple.go +++ b/Sources/WireGuardKitGo/api-apple.go @@ -102,43 +102,56 @@ func wgSetLogger(context, loggerFn uintptr) { loggerFunc = unsafe.Pointer(loggerFn) } -func wgTurnOnMultihopInner(tun tun.Device, exitSettings *C.char, entrySettings *C.char, privateIp *C.char, exitMtu int, logger *device.Logger) int32 { - ip, err := netip.ParseAddr(C.GoString(privateIp)) +func openTUNFromSocket(tunFd int32, logger *device.Logger) (tun.Device, int32) { + + dupTunFd, err := unix.Dup(int(tunFd)) if err != nil { - logger.Errorf("Failed to parse private IP: %v", err) - tun.Close() - return errBadIPString + logger.Errorf("Unable to dup tun fd: %v", err) + return nil, errDup } - exitConfigString := C.GoString(exitSettings) - exitEndpoint := parseEndpointFromGoConfig(exitConfigString) - if exitEndpoint == nil { - tun.Close() - return errNoEndpointInConfig + err = unix.SetNonblock(dupTunFd, true) + if err != nil { + logger.Errorf("Unable to set tun fd as non blocking: %v", err) + unix.Close(dupTunFd) + return nil, errSetNonblock + } + tun, err := tun.CreateTUNFromFile(os.NewFile(uintptr(dupTunFd), "/dev/tun"), 0) + if err != nil { + logger.Errorf("Unable to create new tun device from fd: %v", err) + unix.Close(dupTunFd) + return nil, errCreateTun } - singletun := multihoptun.NewMultihopTun(ip, exitEndpoint.Addr(), exitEndpoint.Port(), exitMtu+80) - - exitDev := device.NewDevice(tun, singletun.Binder(), logger) - entryDev := device.NewDevice(&singletun, conn.NewStdNetBind(), logger) + return tun, 0 +} - err = entryDev.IpcSet(C.GoString(entrySettings)) +func bringUpDevice(dev *device.Device, settings string, logger *device.Logger) error { + err := dev.IpcSet(settings) if err != nil { - logger.Errorf("Unable to set IPC settings for entry: %v", err) - tun.Close() - return errBadWgConfig + logger.Errorf("Unable to set IPC settings: %v", err) + dev.Close() + return err } - err = exitDev.IpcSet(exitConfigString) + dev.Up() + logger.Verbosef("Device started") + return nil +} + +func addTunnelFromDevice(dev *device.Device, entryDev *device.Device, settings string, entrySettings string, virtualNet *netstack.Net, logger *device.Logger) int32 { + err := bringUpDevice(dev, settings, logger) if err != nil { - logger.Errorf("Unable to set IPC settings for exit: %v", err) - tun.Close() return errBadWgConfig } - exitDev.Up() - entryDev.Up() - logger.Verbosef("Device started") + if entryDev != nil { + err = bringUpDevice(entryDev, entrySettings, logger) + if err != nil { + dev.Close() + return errBadWgConfig + } + } var i int32 for i = 0; i < math.MaxInt32; i++ { @@ -147,135 +160,83 @@ func wgTurnOnMultihopInner(tun tun.Device, exitSettings *C.char, entrySettings * } } if i == math.MaxInt32 { - tun.Close() + dev.Close() return errDeviceLimitHit } - tunnelHandles[i] = tunnelHandle{exitDev, entryDev, logger, nil} + tunnelHandles[i] = tunnelHandle{dev, entryDev, logger, virtualNet} return i } -//export wgTurnOnMultihop -func wgTurnOnMultihop(exitSettings *C.char, entrySettings *C.char, privateIp *C.char, tunFd int32) int32 { +//export wgTurnOn +func wgTurnOn(settings *C.char, tunFd int32) int32 { logger := &device.Logger{ Verbosef: CLogger(0).Printf, Errorf: CLogger(1).Printf, } - - dupTunFd, err := unix.Dup(int(tunFd)) - if err != nil { - logger.Errorf("Unable to dup tun fd: %v", err) - return errDup + tun, errCode := openTUNFromSocket(tunFd, logger) + if tun == nil { + return errCode } - err = unix.SetNonblock(dupTunFd, true) - if err != nil { - logger.Errorf("Unable to set tun fd as non blocking: %v", err) - unix.Close(dupTunFd) - return errSetNonblock - } - tun, err := tun.CreateTUNFromFile(os.NewFile(uintptr(dupTunFd), "/dev/tun"), 0) + logger.Verbosef("Attaching to interface") + dev := device.NewDevice(tun, conn.NewStdNetBind(), logger) + + return addTunnelFromDevice(dev, nil, C.GoString(settings), "", nil, logger) +} + +func wgTurnOnMultihopInner(tun tun.Device, exitSettings *C.char, entrySettings *C.char, privateIp *C.char, exitMtu int, logger *device.Logger) int32 { + ip, err := netip.ParseAddr(C.GoString(privateIp)) if err != nil { - logger.Errorf("Unable to create new tun device from fd: %v", err) - unix.Close(dupTunFd) - return errCreateTun + logger.Errorf("Failed to parse private IP: %v", err) + tun.Close() + return errBadIPString } - exitMtu, err := tun.MTU() - if err != nil { + exitConfigString := C.GoString(exitSettings) + entryConfigString := C.GoString(entrySettings) + exitEndpoint := parseEndpointFromGoConfig(exitConfigString) + if exitEndpoint == nil { tun.Close() - return errGetMtu + return errNoEndpointInConfig } - return wgTurnOnMultihopInner(tun, exitSettings, entrySettings, privateIp, exitMtu, logger) + singletun := multihoptun.NewMultihopTun(ip, exitEndpoint.Addr(), exitEndpoint.Port(), exitMtu+80) + exitDev := device.NewDevice(tun, singletun.Binder(), logger) + entryDev := device.NewDevice(&singletun, conn.NewStdNetBind(), logger) + + return addTunnelFromDevice(exitDev, entryDev, exitConfigString, entryConfigString, nil, logger) } -//export wgTurnOn -func wgTurnOn(settings *C.char, tunFd int32) int32 { +//export wgTurnOnMultihop +func wgTurnOnMultihop(exitSettings *C.char, entrySettings *C.char, privateIp *C.char, tunFd int32) int32 { logger := &device.Logger{ Verbosef: CLogger(0).Printf, Errorf: CLogger(1).Printf, } - dupTunFd, err := unix.Dup(int(tunFd)) - if err != nil { - logger.Errorf("Unable to dup tun fd: %v", err) - return -1 - } - err = unix.SetNonblock(dupTunFd, true) - if err != nil { - logger.Errorf("Unable to set tun fd as non blocking: %v", err) - unix.Close(dupTunFd) - return -1 - } - tun, err := tun.CreateTUNFromFile(os.NewFile(uintptr(dupTunFd), "/dev/tun"), 0) - if err != nil { - logger.Errorf("Unable to create new tun device from fd: %v", err) - unix.Close(dupTunFd) - return -1 + tun, errCode := openTUNFromSocket(tunFd, logger) + if tun == nil { + return errCode } - logger.Verbosef("Attaching to interface") - dev := device.NewDevice(tun, conn.NewStdNetBind(), logger) - err = dev.IpcSet(C.GoString(settings)) + exitMtu, err := tun.MTU() if err != nil { - logger.Errorf("Unable to set IPC settings: %v", err) - unix.Close(dupTunFd) - return -1 + tun.Close() + return errGetMtu } - dev.Up() - logger.Verbosef("Device started") - - var i int32 - for i = 1; i < math.MaxInt32; i++ { - if _, exists := tunnelHandles[i]; !exists { - break - } - } - if i == math.MaxInt32 { - unix.Close(dupTunFd) - return -1 - } - tunnelHandles[i] = tunnelHandle{dev, nil, logger, nil} - return i + return wgTurnOnMultihopInner(tun, exitSettings, entrySettings, privateIp, exitMtu, logger) } -//export wgTurnOnIAN -func wgTurnOnIAN(settings *C.char, tunFd int32, privateIP *C.char) int32 { +func wgTurnOnIANFromExistingTunnel(tun tun.Device, settings string, privateAddr netip.Addr) int32 { logger := &device.Logger{ Verbosef: CLogger(0).Printf, Errorf: CLogger(1).Printf, } - privateAddrStr := C.GoString(privateIP) - privateAddr, err := netip.ParseAddr(privateAddrStr) - if err != nil { - logger.Errorf("Invalid address: %s", privateAddrStr) - return errBadIPString - } - - dupTunFd, err := unix.Dup(int(tunFd)) - if err != nil { - logger.Errorf("Unable to dup tun fd: %v", err) - return errDup - } - - err = unix.SetNonblock(dupTunFd, true) - if err != nil { - logger.Errorf("Unable to set tun fd as non blocking: %v", err) - unix.Close(dupTunFd) - return errSetNonblock - } - tun, err := tun.CreateTUNFromFile(os.NewFile(uintptr(dupTunFd), "/dev/tun"), 0) - if err != nil { - logger.Errorf("Unable to create new tun device from fd: %v", err) - unix.Close(dupTunFd) - return errCreateTun - } /// assign the same private IPs associated with your key vtun, virtualNet, err := netstack.CreateNetTUN([]netip.Addr{privateAddr}, []netip.Addr{}, 1280) - if err != nil { logger.Errorf("Failed to initialize virtual tunnel device: %v", err) tun.Close() @@ -292,29 +253,29 @@ func wgTurnOnIAN(settings *C.char, tunFd int32, privateIP *C.char) int32 { logger.Verbosef("Attaching to interface") dev := device.NewDevice(&wrapper, conn.NewStdNetBind(), logger) - err = dev.IpcSet(C.GoString(settings)) - if err != nil { - logger.Errorf("Unable to set IPC settings: %v", err) - dev.Close() - return errBadWgConfig - } + return addTunnelFromDevice(dev, nil, settings, "", virtualNet, logger) +} - dev.Up() - logger.Verbosef("Device started") +//export wgTurnOnIAN +func wgTurnOnIAN(settings *C.char, tunFd int32, privateIP *C.char) int32 { + logger := &device.Logger{ + Verbosef: CLogger(0).Printf, + Errorf: CLogger(1).Printf, + } - var i int32 - for i = 0; i < math.MaxInt32; i++ { - if _, exists := tunnelHandles[i]; !exists { - break - } + privateAddrStr := C.GoString(privateIP) + privateAddr, err := netip.ParseAddr(privateAddrStr) + if err != nil { + logger.Errorf("Invalid address: %s", privateAddrStr) + return errBadIPString } - if i == math.MaxInt32 { - dev.Close() - return errDeviceLimitHit + + tun, errCode := openTUNFromSocket(tunFd, logger) + if tun == nil { + return errCode } - tunnelHandles[i] = tunnelHandle{dev, nil, logger, virtualNet} - // TODO: add a tunnel handle, or otherwise make sure we can create connections in the tunnel - return i + + return wgTurnOnIANFromExistingTunnel(tun, C.GoString(settings), privateAddr) } //export wgTurnOff