diff options
| author | David Lönnhager <david.l@mullvad.net> | 2025-01-10 11:08:40 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2025-01-24 17:34:45 +0100 |
| commit | 696c60680a7e4a2c4c6f4778d2d63c135e4469d8 (patch) | |
| tree | 97a7de7bec4fa7fe6a60b80d5a2f5c0e20449291 | |
| parent | ff88a777e7c73dd1b6ea995df517d37bb26cc7e0 (diff) | |
| download | mullvadvpn-696c60680a7e4a2c4c6f4778d2d63c135e4469d8.tar.xz mullvadvpn-696c60680a7e4a2c4c6f4778d2d63c135e4469d8.zip | |
Add Windows support to libwg
| -rw-r--r-- | wireguard-go-rs/libwg/README.md | 3 | ||||
| -rw-r--r-- | wireguard-go-rs/libwg/libwg_windows.go | 138 |
2 files changed, 141 insertions, 0 deletions
diff --git a/wireguard-go-rs/libwg/README.md b/wireguard-go-rs/libwg/README.md index 39ad48e3e0..e5b96928f7 100644 --- a/wireguard-go-rs/libwg/README.md +++ b/wireguard-go-rs/libwg/README.md @@ -7,6 +7,7 @@ It currently offers support for the following platforms: - Linux - macOS - Android +- Windows # Organization @@ -16,6 +17,8 @@ It currently offers support for the following platforms: `libwg_android.go` has code specifically for Android. +`libwg_windows.go` has code specifically for Windows. + # Usage Call `wgTurnOn` to create and activate a tunnel. The prototype is different on different platforms, see the code for details. diff --git a/wireguard-go-rs/libwg/libwg_windows.go b/wireguard-go-rs/libwg/libwg_windows.go new file mode 100644 index 0000000000..f4ad7faa6d --- /dev/null +++ b/wireguard-go-rs/libwg/libwg_windows.go @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: Apache-2.0 + * + * Copyright (C) 2017-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + * Copyright (C) 2024 Mullvad VPN AB. All Rights Reserved. + */ + +package main + +// #include <stdlib.h> +// #include <stdint.h> +import "C" + +import ( + "bufio" + "strings" + "unsafe" + + "golang.org/x/sys/windows" + + "golang.zx2c4.com/wireguard/conn" + "golang.zx2c4.com/wireguard/device" + "golang.zx2c4.com/wireguard/tun" + + "github.com/mullvad/mullvadvpn-app/wireguard/libwg/logging" + "github.com/mullvad/mullvadvpn-app/wireguard/libwg/tunnelcontainer" +) + +// Redefined here because otherwise the compiler doesn't realize it's a type alias for a type that's safe to export. +// Taken from the contained logging package. +type LogSink = unsafe.Pointer +type LogContext = C.uint64_t + +//export wgTurnOn +func wgTurnOn(cIfaceName *C.char, cIfaceNameOut **C.char, cLuidOut *C.uint64_t, mtu C.uint16_t, cSettings *C.char, logSink LogSink, logContext LogContext) C.int32_t { + logger := logging.NewLogger(logSink, logging.LogContext(logContext)) + if cIfaceNameOut != nil { + *cIfaceNameOut = nil + } + + if cIfaceName == nil { + logger.Errorf("cIfaceName is null\n") + return ERROR_GENERAL_FAILURE + } + + if cSettings == nil { + logger.Errorf("cSettings is null\n") + return ERROR_GENERAL_FAILURE + } + + settings := C.GoString(cSettings) + ifaceName := C.GoString(cIfaceName) + + // {AFE43773-E1F8-4EBB-8536-576AB86AFE9A} + networkId := windows.GUID{ + Data1: 0xafe43773, + Data2: 0xe1f8, + Data3: 0x4ebb, + Data4: [8]byte{0x85, 0x36, 0x57, 0x6a, 0xb8, 0x6a, 0xfe, 0x9a}, + } + + tun.WintunTunnelType = "Mullvad" + + wintun, err := tun.CreateTUNWithRequestedGUID(ifaceName, &networkId, mtu) + if err != nil { + logger.Errorf("Failed to create tunnel\n") + logger.Errorf("%s\n", err) + return ERROR_INTERMITTENT_FAILURE + } + + nativeTun := wintun.(*tun.NativeTun) + + actualInterfaceName, err := nativeTun.Name() + if err != nil { + nativeTun.Close() + logger.Errorf("Failed to determine name of wintun adapter\n") + return ERROR_GENERAL_FAILURE + } + if actualInterfaceName != ifaceName { + // WireGuard picked a different name for the adapter than the one we expected. + // This indicates there is already an adapter with the name we intended to use. + logger.Verbosef("Failed to create adapter with specific name\n") + } + + device := device.NewDevice(wintun, conn.NewDefaultBind(), logger) + + setError := device.IpcSetOperation(bufio.NewReader(strings.NewReader(settings))) + if setError != nil { + logger.Errorf("Failed to set device configuration\n") + logger.Errorf("%s\n", setError) + device.Close() + return ERROR_GENERAL_FAILURE + } + + device.Up() + + context := tunnelcontainer.Context{ + Device: device, + Logger: logger, + } + + handle, err := tunnels.Insert(context) + if err != nil { + logger.Errorf("%s\n", err) + device.Close() + return ERROR_GENERAL_FAILURE + } + + if cIfaceNameOut != nil { + *cIfaceNameOut = C.CString(actualInterfaceName) + } + if cLuidOut != nil { + *cLuidOut = nativeTun.LUID() + } + + return C.int32_t(handle) +} + +//export wgRebindTunnelSocket +func wgRebindTunnelSocket(family uint16, interfaceIndex uint32) { + tunnels.ForEach(func(tunnel tunnelcontainer.Context) { + blackhole := (interfaceIndex == 0) + bind := tunnel.Device.Bind().(conn.BindSocketToInterface) + + if family == windows.AF_INET { + tunnel.Logger.Verbosef("Binding v4 socket to interface %d (blackhole=%v)\n", interfaceIndex, blackhole) + err := bind.BindSocketToInterface4(interfaceIndex, blackhole) + if err != nil { + tunnel.Logger.Verbosef("%s\n", err) + } + } else if family == windows.AF_INET6 { + tunnel.Logger.Verbosef("Binding v6 socket to interface %d (blackhole=%v)\n", interfaceIndex, blackhole) + err := bind.BindSocketToInterface6(interfaceIndex, blackhole) + if err != nil { + tunnel.Logger.Verbosef("%s\n", err) + } + } + }) +} |
