Single protocol SDK

Suitable if you're planning to use just one specific protocol or implement protocols switching inside your app manually.

API Documentation

To see all available API, check API Reference.

Table of Contents

Integration

VPN SDK integration process usually consists of 2 steps: application and network extension targets setup. The only exception is IPSecSDK: it uses internal Apple tunnel implementation, so you don't need to setup network extension by yourself.

  1. Setup application target

  2. Setup network extension target

Start using SDK

Configure SDK

To start using SDK, you need to import import VPNApplicationSDK to your file under the application target. There is a SDK/configuration pair for every protocol:

  • HydraSDK/HydraConfiguration

  • IPSecSDK/IPSecConfiguration

  • WireguardSDK/WireguardConfiguration

Pick needed protocol, then initialize SDK using corresponding configuration. For instance, in order to use Hydra protocol you write following code:

import VPNApplicationSDK    
// ...
    
let configuration = HydraConfiguration(
    carrierID: "CARRIER_ID",
    extensionBundleID: "NETWORK_EXTENSION_BUNDLE_ID,
    groupData: VPNGroupData(
        groupID: "group.GROUP_ID",
        usesSystemExtension: false
    ),
    profileName: "PROFILE_NAME",
    fireshieldConfig: fireshieldConfig,
    isOnDemandEnabled: true,
    isVPNIconFixEnabled: true
)

self.hydra = HydraSDK(configuration: configuration)

NOTE: for macOS even though you don't need to enable App Groups, groupData should be provided and groupID property still has to have a value, starting with group..

The best place to put initialization code is you AppDelegate's application:didFinishLaunchingWithOptions:.

After SDK is initialized, you need to login to be able to start VPN. If you are using OAuth authentication, provide your own OAuth dialogs UI and receive OAuth access token. Login example with OAuth token:

import VPNApplicationSDK
// ...

let hydra: HydraSDK
// ...

let authMethod = AuthMethod(type: .oauth, token: "OAUTH_TOKEN")

hydra.login(method: authMethod) { error, user in
    print("isLogged: \(error == nil)")
}

See AuthMethod reference for more authentication methods.

Connecting VPN and obtaining status

To connect VPN use function start(location:completion:) on SDK instance. When VPN is started or an error occurred, completion handler will be called. To obtain VPN connection status you need to subscribe to vpnStateDidChange notification provided by SDK. For example:

NotificationCenter.default.addObserver(forName: .vpnStateDidChange, object: nil, queue: nil) { notification in
    // ...
}

When you receive notification, get updated VPN status from SDK instance state property and handle this status as designed by your app.

While using Hydra you can also switch location using applyLocationIfConnected(:completion:) when VPN is in connected status. It will update location in the same network extension (without killing it and starting new one). This method will return error if VPN is not currently connected.

Using On Demand mode

iOS and macOS, both provide an ability to connect to VPN automatically when certain (preconfigured) coditions are met. This functionality is called On Demand.

VPN SDK can be configured for On Demand mode with corresponding configuration via isOnDemandEnabled and onDemandRules properties. The SDK could be initialized with this parameter.

On Demand and users with limited traffic

If your service provides limited traffic or a transport error occurs (e.g. credentials to VPN nodes are expired), current session will be killed with VPNTunnelError.trafficExceeded error. If On Demand mode conditions are met, the System will try to restart Network Extension process, until it is up and running. Due to NetworkExtension framework's limitation, it is not possible to disable On Demand mode from Custom Tunnel Provider extension upon receiving these errors. This makes System trying endlessly reconnect to VPN, while Network Extension is unable to provide VPN service due to the error.

In order to overcome this issue, VPN SDK disables real tunneling, leaving Network Extension running in Bypass mode. By doing this, iOS can meet On Demand mode conditions while the traffic is routed locally, without VPN server. It means that user will have their real IP address and there will be no traffic protection.

Whenever app starts, it's highly recommended to check if VPN is connected and if user is out of traffic limit. In this case, it's necessary to disconnect current VPN session and optionally show user a message. To check if current VPN connection is running in Bypass mode read isBypassEnabled property from SDK instance.

In order to catch situation when user is out of traffic without main app running, use BaseNetworkExtensionDelegate callback method vpnDidReceiveError(_:).

Error Handling

Most of the SDK instance calls are accepting completion blocks with errors. If some error occurs, you will receive non-nil Error object with an explanation. Some errors types that can be thrown by VPN SDK methods: PartnerAPI.APIError, VPNSDKError, VPNTransportError, VPNTunnelError. If you need localized description make these types conform to LocalizedError protocol and provide var errorDescription: String? property. Then you can use localizedDescription property on returned Error.

If you are just disconnected from VPN session, you could also check lastTunnelError property of SDK instance, if there was an error during network extension initialization or session management system disconnected VPN remotely, there will be VPNTunnelError case here. You can handle such errors and report if appropriate. Pay attention that this property is always nil for IPSecSDK, because we don't have access to internal IPSec implementation.

Crash Reporting

Some project might consider crash reporting integration (such as, Crashlytics) for Network Extension side. If your crash reporting framework supports Application Extensions and requires additional code to setup it, put the configuration code inside BaseNetworkExtensionDelegate's -init override:

import HydraTunnelProvider

class ProviderDelegate: NSObject, BaseNetworkExtensionDelegate {
    override init() {
        Fabric.with([Crashlytics.self])
    }
}

Categorization service (aka Fireshield)

Note: Fireshield service is available only for Hydra protocol.

Additionally to VPN services, Hydra SDK provides a content categorization service, namely Fireshield. When the SDK is configured to work with Fireshield enabled, the websites' URLs that user visits are checked agains a blacklist. If a website's URL is listed in the blacklist, the traffic to/from it is blocked, otherwise it is passed through. Hydra SDK provides API to configure Fireshield and monitor its work.

Create fireshield config

Categorization configuration based on specification of categories and rules for categories.

To create categories you can use one of factory methods of FireshieldCategory type:

  • FireshieldCategory.block(category: CategoryType) -> FireshieldCategory - will create category, with action block(traffic gets blocked).

  • FireshieldCategory.proxy(category: CategoryType) -> FireshieldCategory - will create category, with action proxy(traffic (encrypted) goes through the tunnel just as payload (for TCP only)).

  • FireshieldCategory.bypasss(category: CategoryType) -> FireshieldCategory - will create category, with action bypass(traffic goes directly to its destination, without vpn tunnel).

  • FireshieldCategory.alert(category: CategoryType) -> FireshieldCategory - will create category, with action block(traffic gets blocked) and redirection to Alert Page specified(works for http only).

To add category rules (which domains gets to specified category) you can use instance methods of FireshieldConfig type:

  • addRule(withFileName fileName: String, categoryType: FireshieldCategory.CategoryType, in bundle: Foundation.Bundle = .main) - add category rules from file in the application bundle.

  • addRule(withDomains domains: [String], categoryType: FireshieldCategory.CategoryType) - add category rules from list of domains.

To addition to category file configuration it's possible to use online categorization services.

Possible values defined as constants in FireshieldConfig header file.

Fireshield configuration

Fireshield can be either disabled or enabled with particular mode. The mode is set with fireshieldMode property of FireshieldConfig instance. You can pass respective config at the moment of HydraSDK initialization (e.g. during the application launch):

// ...

self.configuration = HydraConfiguration(
    ...
    fireshieldConfig: makeFireshieldConfig(),
    ...
)

// Fireshield config example
private func makeFireshieldConfig() -> FireshieldConfig {
    guard isFireshieldEnabled else {
        // just return `.disabled` if you don't need Fireshield at all
        return FireshieldConfig(
            mode: .disabled,
            groupData: VPNGroupData(
                groupID: "your_group_id",
                usesSystemExtension: false
            )
        )
    }

    let config = FireshieldConfig(
        mode: .vpn,
        groupData: VPNGroupData(
            groupID: "your_group_id",
            usesSystemExtension: false
        )
    )
    
    // Indicates that Fireshield started in DNS-mode only, by default set to `false`
    config.isDNSModeEnabled = isDNSModeEnabled

    // Black and white lists
    do {
        // Blacklist rule
        try config.addRule(
            withDomains: ["untrusted-domain.com"],
            categoryType: .unsafe
        )

        // Whilelist rule
        try config.addRule(
            withFileName: "whitelist.txt",
            categoryType: .safe
        )

        print("Fireshield rules added")
    } catch {
        print("Fireshield rules error: \(error)")
    }
    
    config.addService(.bitdefender)

    // Add needed behavior for safe category
    let safeCategory: FireshieldCategory = isBypassSafeTrafficEnabled ?
        .bypass(category: .safe) : .proxy(category: .safe)
    config.addCategory(safeCategory)
    
    // Indicates that Fireshield should block resources from unsafe category
    config.addCategory(.block(category: .unsafe))

    // Custom categories
    if isSocialNetworkBlockingEnabled {
        config.addCategory(.block(category: .custom("safe:socialnetworks")))
    }

    return config
}

Important note: You always need to add a safe category to FireshieldConfig to allow safe traffic.

Fireshield modes

Fireshield can work in various modes, adding flexibility to your application. For instance, you can blend VPN and Fireshield functionality or hide VPN icon in iOS Status Bar. The modes are represented by FireshieldMode type.

  • disabled — Fireshield is disabled.

  • enabled — Fireshield is enabled. The VPN icon in Status Bar is displayed, however, the traffic does not go through VPN.

  • vpn — Blend Fireshield and VPN together. All traffic goes through VPN, while Fireshield blocks access to websites in the blacklist. The VPN icon is Status Bar is displayed. Default value.

Important note: Fireshield config settings may be overwritten by remote config.

Monitoring

Hydra SDK reports its content categorization service's work through HydraSDK's fireshieldScannedConnections(completion:) and lastCategorization variable (available from Application part of the SDK) and vpnDidHandleCategorization(_ categorization: VPNCategorization) of FireshieldNetworkExtensionDelegate (available from Network Extension part of the SDK).

Call fireshieldScannedConnections(completion:) to receive number of network connection that have been scanned.

Implement vpnDidHandleCategorization(_ categorization: VPNCategorization) delegate method in your FireshieldNetworkExtensionDelegate to get the categorization result of latest connection. Hydra SDK will automatically call back on every new categorization being processed.

NOTE: Because Network Extension process is running when Fireshield is enabled, even when the application is suspended by user or terminated by iOS, vpnDidHandleCategorization(_ categorization: VPNCategorization) is a good place to schedule User Notifications. By doing this, users can be notified when particular resource is blocked by Fireshield. Remember, that User Notification permissions have to be obtained via the application before they can be scheduled by Network Extension. For more information, see Local and Remote Notifications Overview.

Logs sharing

If you pass debugLoggingEnabled: true to VPN SDK configuration, you can fetch/share your log files using VPNLogSharingHelper. There are static methods for presenting sharing activity in iOS/macOS or getting log file URLs.

Last updated