AmneziaWG Windows Library

repository·master·Indexed 41 days ago

https://github.com/amnezia-vpn/amneziawg-windows

An embeddable WireGuard tunnel library for Windows that allows developers to integrate tunneling capabilities into applications via a DLL. It includes functionality for managing network interface changes via interfaceWatcher, generating Curve25519 keypairs, and running the tunnel as a Windows service with support for Wintun interfaces and UAPI listeners.

Tokens
2.2K
Snippets
9
Records
11
Agent score
53%

What's inside AmneziaWG Windows

  1. Overview of the Embeddable WireGuard Tunnel Library

    master
    This project provides an embeddable WireGuard tunnel library for Windows. It is based on the embeddable-dll-service and tunnel modules from the upstream wireguard-windows repository, allowing developers to leverage existing WireGuard functionality within their own applications.
  2. Watch and manage network interface changes with interfaceWatcher

    master

    The interfaceWatcher struct is used to monitor Windows network interface changes and automatically reconfigure the tunnel's IP addresses when relevant changes occur.

    Lifecycle and Usage

    1. Initialization: Call watchInterface() to start monitoring. This registers a callback via winipcfg.RegisterInterfaceChangeCallback that listens for winipcfg.MibAddInstance notifications.
    2. Configuration: Once the watcher is initialized, call Configure(binder, conf, tun) to provide the necessary dependencies. This method also processes any interface change events that occurred while the watcher was running but before the tunnel was ready.
    3. Cleanup: Call Destroy() to unregister all callbacks, disable the firewall, and flush routes, IP addresses, and DNS settings associated with the tunnel's LUID to ensure a clean teardown of the Windows networking stack.

    Error Handling

    Errors encountered during interface setup are sent to the errors channel of the interfaceWatcher instance as interfaceWatcherError objects, which wrap a services.Error and the underlying error.

    iw, err := watchInterface()
    if err != nil {
        log.Fatal(err)
    }
    
    // ... later, once tunnel and config are ready ...
    
    iw.Configure(binder, config, tun)
    
    // ... on shutdown ...
    
    iw.Destroy()
  3. Run the AmneziaWG Windows service

    master

    To start the AmneziaWG tunnel as a Windows service, use the Run function. This function wraps the standard Windows service execution logic, handling interface creation (Wintun), privilege dropping, firewall configuration, and UAPI listening.

    Parameters

    • confString: A string containing the WireGuard configuration (compatible with wg-quick format).
    • tunnelName: The name of the service to be registered in the Windows Service Control Manager (SCM).

    Behavior

    • Configuration: Parses the confString using conf.FromWgQuickWithUnknownEncoding and deduplicates network entries.
    • Interface: Attempts to create a Wintun interface using a deterministic GUID based on the configuration.
    • Lifecycle Hooks: Executes PreUp, PostUp, PreDown, and PostDown script commands defined in the configuration.
    • Privileges: Automatically drops all privileges after setting up the network interface and firewall to enhance security.
    • UAPI: Starts a listener for User API requests to allow external control of the tunnel.
    • Error Handling: Maps internal errors to specific service error codes via services.DetermineErrorCode for better visibility in Windows Service logs.
    import "github.com/amnezia-vpn/amneziawg-windows/v3"
    
    func main() {
        confString := `[Interface]
    PrivateKey = <key>
    Address = 10.0.0.1/24`
        tunnelName := "amneziawg-tunnel"
    
        err := amneziawg.Run(confString, tunnelName)
        if err != nil {
            log.Fatalf("Service failed: %v", err)
        }
    }
  4. Cleanup resources with Destroy()

    master

    The Destroy() method performs a comprehensive cleanup of the interface watcher and the associated network state. It:

    • Unregisters the main interface change callback.
    • Unregisters all family-specific (v4/v6) change callbacks.
    • Disables the firewall via firewall.DisableFirewall().
    • Flushes routes, IP addresses, and DNS settings for the tunnel's LUID for both windows.AF_INET and windows.AF_INET6 to prevent Windows networking stack issues.
    iw.Destroy()
  5. Generate a WireGuard keypair with WireGuardGenerateKeypair

    master

    The WireGuardGenerateKeypair function generates a new Curve25519 keypair. It populates two 32-byte buffers provided by the caller: one for the public key and one for the private key. The function handles the necessary bit manipulation to ensure the private key is valid for Curve25519 (clamping) and then computes the public key using curve25519.ScalarBaseMult.

    // The caller must provide pointers to 32-byte arrays
    // WireGuardGenerateKeypair(publicKeyPtr, privateKeyPtr)
  6. Copy configuration file owner to IPC security descriptor

    master

    The CopyConfigOwnerToIPCSecurityDescriptor function synchronizes the permissions of the Inter-Process Communication (IPC) mechanism with the owner of a specific configuration file.

    This ensures that the user who owns the configuration file also has full access (GENERIC_ALL) to the IPC interface. The function performs the following logic:

    1. Checks if the filename is encrypted using conf.PathIsEncrypted. If so, it returns nil.
    2. Retrieves the owner SID of the provided filename using Windows security APIs.
    3. If the owner is the WinLocalSystemSid, it skips the update.
    4. Creates a new Access Control Entry (ACE) granting GENERIC_ALL access to the file owner.
    5. Updates the global ipc.UAPISecurityDescriptor with a new Discretionary Access Control List (DACL) that includes this additional entry.

    This is used to prevent permission mismatches where a user might own a VPN configuration but be unable to communicate with the background service via IPC.

    err := CopyConfigOwnerToIPCSecurityDescriptor("path/to/config.conf")
    if err != nil {
        // handle error
    }
  7. Start the WireGuard tunnel service with WireGuardTunnelService

    master

    The WireGuardTunnelService function is an exported entry point used to start the WireGuard tunnel service. It accepts two UTF-16 encoded strings: a configuration string and a name string. The function returns true if the service started successfully, and false if an error occurred. Internally, it sets UseFixedGUIDInsteadOfDeterministic to true before executing the tunnel logic.

    // Note: The function expects pointers to UTF-16 strings (uint16)
    // success := WireGuardTunnelService(confString16, nameString16)
  8. Configure an interface watcher with Configure()

    master

    The Configure(binder conn.BindSocketToInterface, conf *conf.Config, tun *tun.NativeTun) method attaches the required tunnel components to the watcher. It allows the watcher to identify which interface changes are relevant (by matching the tunnel's LUID) and triggers the initial IP configuration for both IPv4 and IPv6.

    iw.Configure(binder, conf, tun)
  9. Service Error Codes

    master

    When the Run function fails, it returns error codes mapped to specific failure points. These are used by the Windows Service Control Manager to diagnose issues. Common error mappings include:

    Error ConstantMeaning
    services.ErrorRingloggerOpenFailed to initialize the global ring logger.
    services.ErrorLoadConfigurationFailed to parse the provided configuration string.
    services.ErrorSetNetConfigFailed to watch or configure network interfaces.
    services.ErrorDNSLookupFailed to resolve DNS names during configuration.
    services.ErrorCreateWintunFailed to create the Wintun TUN device.
    services.ErrorRunScriptA PreUp or PostUp script command failed.
    services.ErrorFirewallFailed to configure the Windows firewall rules.
    services.ErrorDropPrivilegesFailed to drop privileges after setup.
    services.ErrorUAPIListenFailed to start the UAPI listener.
    services.ErrorDeviceSetConfigFailed to apply configuration to the device via UAPI.
    services.ErrorDeviceSetConfigFailed to apply configuration to the device via UAPI.
    services.ErrorFirewallFailed to configure the Windows firewall rules.
    services.ErrorDropPrivilegesFailed to drop privileges after setup.
    services.ErrorUAPIListenFailed to start the UAPI listener.
    services.ErrorDeviceSetConfigFailed to apply configuration to the device via UAPI.