# Client Network List (CNL)

## Overview

See [Client Network List (CNL)](/paas/sdk/unified-vpn-sdk/features/client-network-list-cnl.md)

## Use Cases

### Initialization

The CNL interface is accessed through the UnifiedSdk instance:

```kotlin
import unified.vpn.sdk.*

val sdk = UnifiedSdk.getInstance()
val cnl = sdk.cnl // Get CNL interface
```

### Enable VPN on Public WiFi

Automatically enable VPN when connecting to any public WiFi network:

```kotlin
import unified.vpn.sdk.*

val sdk = UnifiedSdk.getInstance()

// Load existing rules first
sdk.cnl.loadList(object : Callback<List<CnlConfig>> {
    override fun success(existingConfigs: List<CnlConfig>) {
        // Create new rule
        val publicWifiRule = CnlConfig(
            CnlConfig.Type.WIFI,
            listOf(""),  // Match any SSID
            listOf(""),  // Match any BSSID
            CnlConfig.Action.ENABLE,
            CnlConfig.Authorized.UNKNOWN  // Match both open and protected
        )

        // Add to existing list
        val updatedConfigs = existingConfigs.toMutableList()
        updatedConfigs.add(publicWifiRule)

        // Save updated list
        sdk.cnl.updateList(updatedConfigs, object : CompletableCallback {
            override fun complete() {
                Log.d("CNL", "Public WiFi rule added")
            }

            override fun error(error: VpnException) {
                Log.e("CNL", "Failed to update: ${error.message}")
            }
        })
    }

    override fun failure(error: VpnException) {
        Log.e("CNL", "Failed to load existing rules: ${error.message}")
    }
})
```

### Disable VPN on Trusted Home Network

Automatically disable VPN when connecting to your home WiFi:

```kotlin
import unified.vpn.sdk.*

val sdk = UnifiedSdk.getInstance()

sdk.cnl.loadList(object : Callback<List<CnlConfig>> {
    override fun success(existingConfigs: List<CnlConfig>) {
        // Create rule for home WiFi
        val homeWifiRule = CnlConfig(
            CnlConfig.Type.WIFI,
            listOf("MyHomeWiFi"),  // Specific SSID
            listOf(""),            // Any BSSID
            CnlConfig.Action.DISABLE,
            CnlConfig.Authorized.YES  // Only match protected networks
        )

        val updatedConfigs = existingConfigs.toMutableList()
        updatedConfigs.add(homeWifiRule)

        sdk.cnl.updateList(updatedConfigs, object : CompletableCallback {
            override fun complete() {
                Log.d("CNL", "Home WiFi rule added - VPN will auto-disable")
            }

            override fun error(error: VpnException) {
                Log.e("CNL", "Failed to update: ${error.message}")
            }
        })
    }

    override fun failure(error: VpnException) {
        Log.e("CNL", "Failed to load: ${error.message}")
    }
})
```

### Enable VPN on Mobile Data

Always enable VPN when using mobile/cellular data:

```kotlin
import unified.vpn.sdk.*

val sdk = UnifiedSdk.getInstance()

sdk.cnl.loadList(object : Callback<List<CnlConfig>> {
    override fun success(existingConfigs: List<CnlConfig>) {
        val mobileRule = CnlConfig(
            CnlConfig.Type.MOBILE,
            emptyList(),  // Not applicable for mobile
            emptyList(),  // Not applicable for mobile
            CnlConfig.Action.ENABLE,
            CnlConfig.Authorized.UNKNOWN
        )

        val updatedConfigs = existingConfigs.toMutableList()
        updatedConfigs.add(mobileRule)

        sdk.cnl.updateList(updatedConfigs, object : CompletableCallback {
            override fun complete() {
                Log.d("CNL", "Mobile data rule added")
            }

            override fun error(error: VpnException) {
                Log.e("CNL", "Failed to update: ${error.message}")
            }
        })
    }

    override fun failure(error: VpnException) {
        Log.e("CNL", "Failed to load: ${error.message}")
    }
})
```

### Clear All CNL Rules

```kotlin
import unified.vpn.sdk.*

val sdk = UnifiedSdk.getInstance()

sdk.cnl.clear(object : CompletableCallback {
    override fun complete() {
        Log.d("CNL", "All CNL rules cleared")
    }

    override fun error(error: VpnException) {
        Log.e("CNL", "Failed to clear CNL: ${error.message}")
    }
})
```

### Rule Evaluation

* Rules are evaluated in the order they appear in the list
* The first matching rule determines the action (ENABLE or DISABLE)
* If no rules match, the current VPN state is maintained

## CNL Rule Action Behavior

When a device connects to a network that matches a CNL rule, the SDK performs an action based on the rule's configuration. There are two possible actions:

### Action: Enable

When the current network matches a CNL rule with the **Enable** action, the SDK automatically starts a VPN session using the last used VPN configuration (protocol, virtual location, and other settings from the most recent connection).

### Action: Disable

When the current network matches a CNL rule with the **Disable** action, the SDK stops the active VPN session and will not reconnect on this network.

If a user changes networks while a VPN session is active and the new network matches a CNL rule with the **Disable** action, the SDK throws a `CnlBlockedException` in the `VpnStateListener#vpnError` callback:

```
"VPN disabled. Connected to a network not allowed by CNL rules."
```

### Android Permissions

* For Android 8.1+ (API 27) and Android 10+ (API 29), you need to set up and request runtime permission for location to match networks by SSID and/or BSSID.
* If the required permission is missing, the SDK will not be able to access the network SSID and BSSID.

## Permissions Required

### Android 8.1+ (API 27)

If you want to match network by SSID and/or BSSID on Android 8.1+ (API 27), you need to setup and request runtime permission for use location:

* `ACCESS_COARSE_LOCATION`
* `ACCESS_WIFI_STATE` - required for accessing WiFi information

### Android 10+ (API 29)

If you want to match network by SSID and/or BSSID on Android 10+ (API 29), you need to setup and request runtime permission for use location:

* `ACCESS_FINE_LOCATION`
* `ACCESS_WIFI_STATE` - required for accessing WiFi information

**Note**: In case of missing permission, the SDK will not be able to get network SSID and BSSID, and WiFi-specific rules may not work correctly.

## Client-side CNL Configuration

The CNL configuration can also be managed on the client side.

### Loading the list of saved network configurations

See [`loadList`](#loadlistcallback)

### Updating the network configurations

See [`updateList`](#updatelistconfigs-callback)

### Resetting the network configurations

See [`clear`](#clearcallback)

## Custom Notifications for CNL State

When CNL is active and waiting for a matching network, the SDK will show a notification. You can customize the notification message shown to the user when the VPN is waiting for a secure network:

```java
SdkNotificationConfig.Builder builder = SdkNotificationConfig.newBuilder();
builder.inCnl("VPN Waiting", "Waiting for configured network");
UnifiedSDK.update(builder.build());
```

If you don't customize the notification, it will display the default title and message:

* `title` - "CNL"
* `message` - "Waiting"

## Actions

### loadList(callback)

Loads the current CNL configuration list from local storage.

```java
sdk.cnl.loadList(new Callback<List<CnlConfig>>() {
    @Override
    public void success(List<CnlConfig> configs) {
        // Handle loaded configurations
        for (CnlConfig config : configs) {
            Log.d("CNL", "Type: " + config.getType() + ", Action: " + config.getAction());
        }
    }

    @Override
    public void failure(VpnException error) {
        // Handle error
        Log.e("CNL", "Failed to load CNL: " + error.getMessage());
    }
});
```

### updateList(configs, callback)

Updates the CNL configuration list. This replaces the existing list with the provided configurations.

```java
List<CnlConfig> configs = new ArrayList<>();

// Add a rule: Enable VPN on any WiFi network
CnlConfig publicWifiRule = new CnlConfig(
    CnlConfig.Type.WIFI,
    Arrays.asList(""),  // Empty SSID = match any
    Arrays.asList(""),  // Empty BSSID = match any
    CnlConfig.Action.ENABLE,
    CnlConfig.Authorized.UNKNOWN
);
configs.add(publicWifiRule);

sdk.cnl.updateList(configs, new CompletableCallback() {
    @Override
    public void complete() {
        Log.d("CNL", "CNL rules updated successfully");
    }

    @Override
    public void error(VpnException error) {
        Log.e("CNL", "Failed to update CNL: " + error.getMessage());
    }
});
```

### clear(callback)

Clears all CNL configurations.

```java
sdk.cnl.clear(new CompletableCallback() {
    @Override
    public void complete() {
        Log.d("CNL", "All CNL rules cleared");
    }

    @Override
    public void error(VpnException error) {
        Log.e("CNL", "Failed to clear CNL: " + error.getMessage());
    }
});
```

## Data Models

### CnlConfig

```java
CnlConfig config = new CnlConfig(
    type,        // Network type: WIFI, MOBILE, or LAN
    ssid,        // List of WiFi SSIDs (empty = match any)
    bssid,       // List of WiFi BSSIDs (empty = match any)
    action,      // Action: ENABLE or DISABLE VPN
    authorized   // Authorization: UNKNOWN, YES, or NO
);
```

#### CnlConfig.Type

Network Types

* `CnlConfig.Type.WIFI` - WiFi networks
* `CnlConfig.Type.MOBILE` - Mobile/cellular networks (WWAN)
* `CnlConfig.Type.LAN` - Ethernet/LAN networks

#### CnlConfig.Action

Actions

* `CnlConfig.Action.ENABLE` - Start VPN when matching network is detected
* `CnlConfig.Action.DISABLE` - Stop VPN when matching network is detected

#### CnlConfig.Authorized

Authorization Status

* `CnlConfig.Authorized.UNKNOWN` - Match both open and protected networks
* `CnlConfig.Authorized.YES` - Only match authorized/protected networks
* `CnlConfig.Authorized.NO` - Only match open/unprotected networks


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pango.gitbook.io/paas/sdk/vpn-sdk-for-android/features/cnl-list.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
