WireGuard Apple Platform Implementation

repository·master·Indexed 23 days ago

https://github.com/wireguard/wireguard-apple

Implementation of WireGuard for iOS and macOS, featuring the WireGuardKit library for application integration. Includes documentation on building the applications from source, integrating WireGuardKit as a Swift package with the wireguard-go-bridge, and creating .mobileconfig Apple Configuration Profiles for tunnel deployment. Provides API references for managing tunnels via wgTurnOn, wgTurnOff, wgSetConfig, and wgGetConfig, as well as logging and network binding utilities.

Tokens
2.8K
Snippets
3
Records
14
Agent score
79%

What's inside wireguard-apple

  1. Create a .mobileconfig file for WireGuard tunnels

    master

    WireGuard configurations can be deployed on iOS and macOS using Apple Configuration Profiles (.mobileconfig files). These files are XML-formatted plists. A valid profile consists of a top-level payload dictionary containing metadata and a PayloadContent array that holds one or more WireGuard tunnel payload dictionaries.

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    	<key>PayloadDisplayName</key>
    	<string>WireGuard Demo Configuration Profile</string>
    	<key>PayloadType</key>
    	<string>Configuration</string>
    	<key>PayloadVersion</key>
    	<integer>1</integer>
    	<key>PayloadIdentifier</key>
    	<string>com.your-org.wireguard.FCC9BF80-C540-44C1-B243-521FDD1B2905</string>
    	<key>PayloadUUID</key>
    	<string>F346AAF4-53A2-4FA1-ACA3-EEE74DBED029</string>
    	<key>PayloadContent</key>
    	<array>
            <!-- An array of WireGuard configuration payload dictionaries -->
    	</array>
    </dict>
    </plist>
  2. Integrate WireGuardKit into your Xcode project

    master

    You can use WireGuardKit as a Swift package. However, because WireGuardKit links against the wireguard-go-bridge library, you must manually create build targets for the bridge due to Swift Package Manager limitations.

    1. Add the Swift Package

    Add the following URL to your Xcode project: https://git.zx2c4.com/wireguard-apple

    2. Create the wireguard-go-bridge Build Target

    For each platform you support (macOS or iOS), perform these steps:

    1. Create an External Build System Target:
      • In Xcode, go to File -> New -> Target.
      • Select the Other tab and choose External Build System.
      • Product name: Enter WireGuardGoBridge<PLATFORM> (e.g., WireGuardGoBridgemacOS or WireGuardGoBridgeiOS).
      • Build tool: Ensure it is set to /usr/bin/make.
    2. Configure the Directory:
      • In the Info tab of the new target, set the Directory path under "External Build Tool Configuration" to: ${BUILD_DIR%Build/*}SourcePackages/checkouts/wireguard-apple/Sources/WireGuardKitGo
    3. Set the SDK Root:
      • In Build Settings, find SDKROOT and set it to macosx (for macOS) or iphoneos (for iOS).

    3. Configure Dependencies and Linking

    For your Network Extension target:

    • In Build Phases -> Dependencies, add WireGuardGoBridge<PLATFORM>.
    • In Build Phases -> Link with binary libraries, add WireGuardKit.

    For your Main Bundle App target:

    • In Build Phases -> Link with binary libraries, add WireGuardKit.

    4. iOS Specific Requirement

    • In your application target, go to Build Settings -> Enable Bitcode and set it to No.
  3. Build the WireGuard iOS and macOS applications

    master

    To build the full WireGuard application for iOS and macOS from source, follow these steps:

    1. Clone the repository:

      $ git clone https://git.zx2c4.com/wireguard-apple
      $ cd wireguard-apple
    2. Configure Developer Team ID: Create and populate the Developer.xcconfig file from the template:

      $ cp Sources/WireGuardApp/Config/Developer.xcconfig.template Sources/WireGuardApp/Config/Developer.xcconfig
      $ vim Sources/WireGuardApp/Config/Developer.xcconfig
    3. Install dependencies: Ensure you have swiftlint and go (version 1.19 or later) installed via Homebrew:

      $ brew install swiftlint go
    4. Open and build: Open the project in Xcode using:

      $ open WireGuard.xcodeproj
    $ git clone https://git.zx2c4.com/wireguard-apple
    $ cd wireguard-apple
    $ cp Sources/WireGuardApp/Config/Developer.xcconfig.template Sources/WireGuardApp/Config/Developer.xcconfig
    $ brew install swiftlint go
    $ open WireGuard.xcodeproj
  4. Troubleshoot .mobileconfig installation issues

    master
    If you have installed a WireGuard configuration via a .mobileconfig file but the settings are not appearing in the keychain, ensure you have opened the WireGuard application at least once. Configurations are not migrated into the keychain until the app is launched.
  5. Configure the top-level .mobileconfig payload

    master

    The top-level dictionary of a .mobileconfig file must include these keys:

    • PayloadDisplayName (string): The name of the profile shown during installation.
    • PayloadType (string): Must be Configuration.
    • PayloadVersion (integer): Must be 1.
    • PayloadIdentifier (string): A unique reverse-DNS style identifier. Installing a new profile with an existing identifier will overwrite the old one.
    • PayloadUUID (string): A randomly generated UUID.
    • PayloadContent (array): An array of dictionaries, where each dictionary represents a WireGuard tunnel configuration.
  6. Configure a WireGuard payload entry

    master

    Each dictionary within the PayloadContent array defines a specific WireGuard tunnel. The payload must include the following keys:

    • PayloadDisplayName (string): Must be VPN.
    • PayloadType (string): Must be com.apple.vpn.managed.
    • PayloadVersion (integer): Must be 1.
    • PayloadIdentifier (string): A unique reverse-DNS style identifier for this specific configuration.
    • PayloadUUID (string): A randomly generated UUID.
    • UserDefinedName (string): The name of the tunnel as it appears in the WireGuard app and System VPN settings.
    • VPNType (string): Must be VPN.
    • VPNSubType (string): The bundle identifier of the WireGuard app:
      • iOS: com.wireguard.ios
      • macOS: com.wireguard.macos
    • VendorConfig (dict): Contains the tunnel configuration.
      • WgQuickConfig (string): A WireGuard configuration in wg-quick(8) / wg(8) format. Note: The keys FwMark, Table, PreUp, PostUp, PreDown, PostDown, and SaveConfig are not supported.
    • VPN (dict): Contains VPN-specific metadata.
      • RemoteAddress (string): The server name/address displayed in System VPN settings.
      • AuthenticationMethod (string): Must be Password.
    <!-- A WireGuard configuration payload dictionary -->
    <dict>
        <key>PayloadDisplayName</key>
        <string>VPN</string>
        <key>PayloadType</key>
        <string>com.apple.vpn.managed</string>
        <key>PayloadVersion</key>
        <integer>1</integer>
        <key>PayloadIdentifier</key>
        <string>com.your-org.wireguard.demo-profile-1.demo-tunnel</string>
        <key>PayloadUUID</key>
        <string>44CDFE9F-4DC7-472A-956F-61C68055117C</string>
        <key>UserDefinedName</key>
        <string>Demo from MobileConfig file</string>
        <key>VPNType</key>
        <string>VPN</string>
        <key>VPNSubType</key>
        <string>com.wireguard.ios</string>
        <key>VendorConfig</key>
        <dict>
            <key>WgQuickConfig</key>
            <string>
            [Interface]
            PrivateKey = mInDaw06K0NgfULRObHJjkWD3ahUC8XC1tVjIf6W+Vo=
            Address = 10.10.1.0/24
            DNS = 1.1.1.1, 1.0.0.1
    
            [Peer]
            PublicKey = JRI8Xc0zKP9kXk8qP84NdUQA04h6DLfFbwJn4g+/PFs=
            Endpoint = demo.wireguard.com:12912
            AllowedIPs = 0.0.0.0/0
            </string>
        </dict>
        <key>VPN</key>
         <dict>
            <key>RemoteAddress</key>
            <string>demo.wireguard.com:12912</string>
            <key>AuthenticationMethod</key>
            <string>Password</string>
        </dict>
    </dict>
  7. Set up logging with wgSetLogger

    master

    To receive logs from the WireGuard Go core, you must provide a logging function and a context pointer via wgSetLogger. The Go core will call this function using the provided context. The function is expected to handle different log levels (passed as an integer) and a message string.

    Note: The Go core also listens for SIGUSR2 signals. When received, it will attempt to log a full stack trace using the logger provided via wgSetLogger.

  8. Start a WireGuard tunnel with wgTurnOn

    master

    Use wgTurnOn to initialize and start a new WireGuard device. This function takes a configuration string (IPC settings) and a file descriptor for the TUN interface.

    Parameters:

    • settings: A C-string containing the initial IPC configuration.
    • tunFd: The file descriptor of the TUN device.

    Returns:

    • An int32 representing a unique tunnelHandle on success.
    • -1 on failure.

    Upon success, the device is brought Up and a handle is registered for subsequent management.

  9. Refresh network bindings with wgBumpSockets

    master
    Call wgBumpSockets to trigger a re-binding of the device's sockets. This is useful if the network environment has changed (e.g., switching from Wi-Fi to Cellular) and the tunnel needs to re-establish connectivity. The function attempts to call dev.BindUpdate() and dev.SendKeepalivesToPeersWithCurrentKeypair() in a background goroutine, retrying up to 10 times with a delay.