VyOS API scripting

Posted on Oct 4, 2023

I spent some time reading the VyOS documentation again, and rediscovered that there is an API…and that VyOS ships with both python and requests installed. So I hacked together some code to solve a problem, and it actually worked!

Enabling the API

First thing I did was to enable the API, in my case only over loopback:

set service https api keys id helloworld key replaceme
set service https api port 8080

Hacky script

I then hacked together a short Python script to check my external IP, compare it to an IP stored in an address-group, and update this IP if necessary.

Why, one might ask? I will use this external IP to setup NAT reflection, but since I’m on a residental connection my IP is dynamic, and I need to keep track of the current one.

The script isn’t pretty but it should do the trick. I saved mine to /config/scripts/check-wan-ip.py.

#!/usr/bin/env python3

import json
import requests

API_KEY = "replaceme"
API_URL = "http://localhost:8080"
GROUP_NAME = "wan-ip"

def build_cmds(ip_list, external):
    cmds, internal = [], ip_list[-1]
    if internal != external:
        for ip in ip_list:
            if len(ip) > 0:
                cmds.append(split_cfg_cmd(f"delete firewall group address-group {GROUP_NAME} address {ip}"))
        cmds.append(split_cfg_cmd(f"set firewall group address-group {GROUP_NAME} address {external}"))
    return cmds

def split_cfg_cmd(cmd):
    parts = cmd.split(" ")
    return { 'op': parts[0], 'path': parts[1:] }

def api_request(api_url, headers, payload):
    request = requests.request("POST", api_url, headers=headers, data=payload)
    return request.json()

if __name__ == '__main__':
    external_ip = requests.get('https://ifconfig.me/').text

    cmd = split_cfg_cmd(f"showConfig firewall group address-group {GROUP_NAME}")
    payload = { 'data': json.dumps(cmd), 'key': f'{API_KEY}' }
    internal_ip = api_request(f"{API_URL}/retrieve", {}, payload)

    ip_data = internal_ip.get('data')
    address = ip_data.get('address')

    cmds = []
    if isinstance(address, str):
        cmds = build_cmds([address,], external_ip)
    elif isinstance(address, list):
        cmds = build_cmds(address, external_ip)
    else:
        cmds = api_single_ip(["",], external_ip)

    if cmds:
        update_payload = { 'data': json.dumps(cmds), 'key': API_KEY }
        url = f"{API_URL}/configure"
        api_request(url, {}, update_payload)

Schedule execution

Then, run this script using the builtin task scheduler (aka as a cronjob):

# Also remember to make the script executable...
set system task-scheduler task check-wan-ip interval 7m
set system task-scheduler task check-wan-ip executable path /config/scripts/check-wan-ip.py