47. Appendix 5 – Using the REST API

The REST API calls can be consulted at docs.andrisoft.com/wanguard-api-ui. To be able to use the REST API, go to General Settings » User Management and enable REST API Access for one of your users. Open http://<console_ip>/wanguard-api-ui and authenticate with the user’s credentials by clicking the [Authorize] button from the top-right part of the web page.

API calls are grouped similarly to the navigation structure of Wanguard Console. When you click a resource, you’ll see the required parameters, you can test the call, and even copy/paste the command for use in scripts or from the CLI. Wanguard 9.0 updates the interactive API interface and adds new calls, including endpoints for managing bookmarks (saved report views). API requests are authorized according to the role of the authenticated user; configuration calls require an Administrator or Operator account. Each REST API call uses one of the following HTTP methods:

● GET → Retrieve data from the server
● POST → Create a resource
● PUT → Update a resource
● DELETE → Remove a resource

47.1. CLI Examples

As an example, if you click the first resource (GET /wanguard-api/v1/anomalies) and set the Status parameter to Active, then click [Try it out!], you’ll see a cURL command you can run from the CLI or any script to fetch a JSON list of active anomalies, along with href links for additional details.
Below is an example script (/opt/andrisoft/bin/active_anomalies_id.sh) that does exactly that:
#!/bin/sh

curl -X GET --header 'Accept: application/json' --header 'Authorization: Basic XXXXXXX==' 'https://wanguard_console/wanguard-api/v1/anomalies?status=Active'

Make the script executable by running:

chmod +x /opt/andrisoft/bin/active_anomalies_id.sh

The examples below authenticate with -u <user>:<password>, which is equivalent to the Authorization: Basic header above, and use -k to accept the Console’s self-signed TLS certificate (see the note at the end of the PHP example).

By default, each listed anomaly contains only an href link to its resource. To include values in the listing, request them with the fields parameter. The JSON output can be parsed with jq:

curl -s -k -u api_user:api_pass 'https://wanguard_console/wanguard-api/v1/anomalies?status=Active&fields=anomaly_id,prefix,anomaly' | jq -r '.[] | "\(.anomaly_id)\t\(.prefix)\t\(.anomaly)"'

To black-hole the traffic sent to an IP address for one hour, POST a BGP announcement on a BGP Connector. The top-level JSON key selects the operation; the other options are blackhole source prefix, redirect destination prefix and flowspec announcement:

curl -k -u api_user:api_pass -X POST --header 'Content-Type: application/json' \
  --data '{"blackhole destination prefix": {"bgp_connector_id": 1, "destination_prefix": "192.0.2.10/32", "withdraw_after": 3600, "comments": "black-holed over the REST API"}}' \
  'https://wanguard_console/wanguard-api/v1/bgp_announcements'

To change the expiration (inactivity) interval of the anomaly with ID 18143 to 60 seconds:

curl -k -u api_user:api_pass -X PUT 'https://wanguard_console/wanguard-api/v1/anomalies/18143/expiration?expiration=60'

To render a two-day traffic graph for a subnet as a PNG file – -G together with --data-urlencode keeps parameter values such as -2 days URL-safe:

curl -s -k -u api_user:api_pass -G -o /tmp/graph.png 'https://wanguard_console/wanguard-api/v1/ip_graphs' \
  --data-urlencode 'prefixes=192.0.2.0/24' \
  --data-urlencode 'unit=Bits' \
  --data-urlencode 'from=-2 days' \
  --data-urlencode 'until=now' \
  --data-urlencode 'width=980' \
  --data-urlencode 'height=270' \
  --data-urlencode 'legend=Full' \
  --data-urlencode 'consolidation=Average' \
  --data-urlencode 'direction=Both' \
  --data-urlencode 'stacking=Decoders' \
  --data-urlencode 'format=PNG'

47.2. PHP Example

The code below (/opt/andrisoft/bin/clear_orphaned_prefixes.php) simulates clicking the Clear option from Reports » Tools » Routing » Active BGP Announcements » Batch Actions:

#!/usr/bin/php
<?php
error_reporting(E_ALL);
$wgUser     = 'api_user';
$wgPass     = 'api_pass';
$wgUrl      = 'https://wanguard_console/wanguard-api/v1/bgp_announcements_actions';

$payload = json_encode([ 'batch_action'   => "Clear" ]);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $wgUrl);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_USERPWD, "$wgUser:$wgPass");
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type:application/json']);

$result = curl_exec($ch);

if (curl_errno($ch)) {
    echo sprintf("Error: %s\n", curl_error($ch));
} else {
    echo $result;
}

curl_close($ch);
?>

Note

The example sets CURLOPT_SSL_VERIFYHOST and CURLOPT_SSL_VERIFYPEER to 0, which disables TLS certificate validation so the script works with the Console’s self-signed certificate. For production use, install a trusted certificate on the Console and set these options to 2 and true respectively.

This PHP script can be executed from the CLI after running:

chmod +x /opt/andrisoft/bin/clear_orphaned_prefixes.php

47.3. Python Example

The script below (/opt/andrisoft/bin/add_customer_prefix.py) provisions a new customer subnet: it adds a prefix to the IP Zone named Default, then defines a threshold on it. POST requests return the new resource as an href link, which the script follows to chain the calls:

#!/usr/bin/python3
import requests

console = 'https://wanguard_console'
auth = ('api_user', 'api_pass')

# Look up the IP Zone and the decoders by name
zone = requests.get(f'{console}/wanguard-api/v1/ip_zones',
                    params={'ip_zone_name': 'Default'}, auth=auth, verify=False).json()[0]
decoders = {d['decoder_name']: d['decoder_id']
            for d in requests.get(f'{console}/wanguard-api/v1/decoders',
                                  auth=auth, verify=False).json()}

# Add the prefix to the IP Zone
r = requests.post(f"{console}{zone['href']}/prefixes",
                  json={'prefix': '198.51.100.0/24', 'ip_group': 'Customer-A'},
                  auth=auth, verify=False)
r.raise_for_status()
prefix_href = r.json()['href']

# Any internal IP that receives over 500 Mbps of TCP traffic raises an anomaly
r = requests.post(f'{console}{prefix_href}/thresholds',
                  json={'domain': 'Internal IP', 'direction': 'receives',
                        'comparison': 'over', 'value': '500M',
                        'decoder_id': decoders['TCP'], 'unit': 'bits/s',
                        'response_id': 1,  # 1 = the "None" Response; list others with GET /responses
                        'parent': False},
                  auth=auth, verify=False)
r.raise_for_status()
Threshold values accept the multiplier suffixes k, M and G, so 500M stands for 500,000,000 bits/s. Setting parent to true makes the threshold inheritable by more-specific prefixes added underneath.