ZeroTier Backend

The ZeroTier backend generates JSON configurations that can be used with the ZeroTier Service API to manage ZeroTier networks on Self-hosted ZeroTier controllers.

Its schema is limited to a subset of the features available in ZeroTier and it doesn’t recognize interfaces, radios, wireless settings and so on.

The main methods work just like the OpenWrt backend:

  • __init__

  • render

  • generate

  • write

  • json

The main differences are in the resulting configuration and in its schema.

See an example of initialization and rendering below:

from netjsonconfig import ZeroTier

config = ZeroTier(
    {
        "zerotier": [
            {
                "id": "9536600adf654321",
                "nwid": "9536600adf654321",
                "objtype": "network",
                "revision": 1,
                "creationTime": 1632012345,
                "name": "zerotier-openwisp-network",
                "private": True,
                "enableBroadcast": True,
                "v4AssignMode": {"zt": True},
                "v6AssignMode": {
                    "6plane": False,
                    "rfc4193": True,
                    "zt": True,
                },
                "mtu": 2700,
                "multicastLimit": 16,
                "routes": [{"target": "10.0.0.0/24", "via": "10.0.0.1"}],
                "ipAssignmentPools": [
                    {
                        "ipRangeStart": "10.0.0.10",
                        "ipRangeEnd": "10.0.0.100",
                    }
                ],
                "dns": {
                    "domain": "zerotier.openwisp.io",
                    "servers": ["10.147.20.3"],
                },
                "rules": [
                    {
                        "etherType": 2048,
                        "not": True,
                        "or": False,
                        "type": "MATCH_ETHERTYPE",
                    },
                    {"type": "ACTION_DROP"},
                ],
                "capabilities": [
                    {
                        "default": True,
                        "id": 1,
                        "rules": [
                            {
                                "etherType": 2048,
                                "not": True,
                                "or": False,
                                "type": "MATCH_ETHERTYPE",
                            }
                        ],
                    }
                ],
                "tags": [{"default": 1, "id": 1}],
                "remoteTraceTarget": "7f5d90eb87",
                "remoteTraceLevel": 1,
                "client_options": {
                    "allow_managed": True,
                    "allowed_global": False,
                    "allowed_default": False,
                    "allowed_dns": False,
                },
            }
        ]
    }
)
print(config.render())

Will return the following output:

// zerotier controller config: 9536600adf654321.json

{
    "capabilities": [
        {
            "default": true,
            "id": 1,
            "rules": [
                {
                    "etherType": 2048,
                    "not": true,
                    "or": false,
                    "type": "MATCH_ETHERTYPE"
                }
            ]
        }
    ],
    "creationTime": 1632012345,
    "dns": {
        "domain": "zerotier.openwisp.io",
        "servers": [
            "10.147.20.3"
        ]
    },
    "enableBroadcast": true,
    "id": "9536600adf654321",
    "ipAssignmentPools": [
        {
            "ipRangeEnd": "10.0.0.100",
            "ipRangeStart": "10.0.0.10"
        }
    ],
    "mtu": 2700,
    "multicastLimit": 16,
    "name": "zerotier-openwisp-network",
    "nwid": "9536600adf654321",
    "objtype": "network",
    "private": true,
    "remoteTraceLevel": 1,
    "remoteTraceTarget": "7f5d90eb87",
    "revision": 1,
    "routes": [
        {
            "target": "10.0.0.0/24",
            "via": "10.0.0.1"
        }
    ],
    "rules": [
        {
            "etherType": 2048,
            "not": true,
            "or": false,
            "type": "MATCH_ETHERTYPE"
        },
        {
            "type": "ACTION_DROP"
        }
    ],
    "tags": [
        {
            "default": 1,
            "id": 1
        }
    ],
    "v4AssignMode": {
        "zt": true
    },
    "v6AssignMode": {
        "6plane": false,
        "rfc4193": true,
        "zt": true
    }
}

ZeroTier backend schema

The ZeroTier backend schema is limited, it only recognizes an zerotier key with a list of dictionaries representing vpn instances. The structure of these dictionaries is described below.

Alternatively you may also want to take a look at the ZeroTier JSON-Schema source code.

According to the NetJSON spec, any unrecognized property will be ignored.

Server specific settings

Required properties:

  • name

key name

type

default

description

name

string

name of the network

id

string

16-digit hexadecimal Network ID

nwid

string

16-digit hexadecimal Network ID (legacy field)

objtype

string

network

specifies the type of object

revision

integer

revision number of the network configuration

creationTime

integer

time when the network was created

private

boolean

whether or not the network is private if False

members will NOT need to be authorized to join

enableBroadcast

boolean

enable broadcast packets on the network

v4AssignMode

object

{}

key name

type

description

zt

boolean

whether ZeroTier should assign IPv4 addresses to members

v6AssignMode

dict

{}

key name

type

description

6plane

boolean

6PLANE assigns each device a single IPv6 address from a

fully routable /80 block. It utilizes NDP emulation to route

the entire /80 to the device owner, enabling up to 2^48 IPs

without additional configuration. Ideal for Docker or VM hosts

rfc4193

boolean

RFC4193 assigns each device a single IPv6 /128 address

computed from the network ID and device address and uses NDP

emulation to make these addresses instantly resolvable without

multicast

zt

boolean

whether ZeroTier should assign IPv6 addresses to members

mtu

integer

MTU to set on the client virtual network adapter

multicastLimit

integer

maximum number of recipients per multicast or broadcast,

warning - Setting this to 0 will disable IPv4 communication on your network

routes

list

[{}]

list of route dictionaries

key name

type

description

target

string

target IP address range for the route

via

string

IP address of the next hop for the route

ipAssignmentPools

list

[{}]

list that contains dictionaries specifying
a range of IP addresses for the auto assign pool

key name

type

description

ipRangeStart

string

starting IP address of the pool range

ipRangeEnd

string

ending IP address of the pool range

dns

dict

{}

key name

type

description

domain

string

domain for DNS resolution

server

list

DNS server IP addresses

rules

list

[{}]

list of network rules dictionaries

tags

list

[{}]

list of network tags dictionaries

remoteTraceTarget

string

remote target ID for network tracing

remoteTraceLevel

integer

level of network tracing

client_options

dict

{}

These options are only used for client configurations

key name

type

description

allow_managed

boolean

allow ZeroTier to set IP addresses and routes

allowed_global

boolean

allow ZeroTier to set global/public/not-private range IPs and routes

allowed_default

boolean

allow ZeroTier to set the default route on the system

allowed_dns

boolean

allow ZeroTier to set DNS servers

Client specific settings

Required properties:

  • name

  • networks

key name

type

default

description

name

string

ow_zt

name of the zerotier network

networks

list

[{}]

list of dictionaries containing strings with 16-digit hexadecimal network IDs for joining,

along with a corresponding custom 10-digit ZeroTier interface name for each network

note: ensure that the list includes at least one such dictionary

config_path

string

/etc/openwisp/zerotier

path to the persistent configuration directory

copy_config_path

string

'1'

specifies whether to copy the configuration file to RAM

'0' - No, '1' - Yes, this prevents writing to flash in zerotier controller mode

secret

string

''

identity secret of the zerotier client (network member), leave it blank to be automatically determined

port

integer

9993

port number of the zerotier service

local_conf_path

string

path of the local zerotier configuration (only used for advanced configuration)

Working around schema limitations

The schema does not include all the possible ZeroTier settings, but it can render appropiately any property not included in the schema as long as its type is one the following:

  • boolean

  • integer

  • strings

  • lists

Automatic generation of clients

classmethod OpenWrt.zerotier_auto_client(**kwargs)[source]

Example (with custom zerotier interface name):

from netjsonconfig import OpenWrt

client_config = OpenWrt.zerotier_auto_client(
    name="ow_zt",
    networks=[{"id": "9536600adf654321", "ifname": "owzt654321"}],
)
print(OpenWrt(client_config).render())

Will be rendered as:

package zerotier

config zerotier 'ow_zt'
    option config_path '/etc/openwisp/zerotier'
    option copy_config_path '1'
    option enabled '1'
    list join '9536600adf654321'
    option secret '{{secret}}'

# ---------- files ---------- #

# path: /etc/openwisp/zerotier/devicemap
# mode: 0644

# network_id=interface_name
9536600adf654321=owzt654321

Note

The current implementation of ZeroTier VPN backend is implemented with OpenWrt backend. Hence, the example above shows configuration generated for OpenWrt.

Useful resources

The default flow rules used in zerotier/schema.py for the ZeroTier self-hosted controller are taken from the flow rules mentioned in the documentation below.

To explore a comprehensive list of all available ZeroTier network configuration settings, please refer to the following OpenAPI API specifications.

Advanced configuration

If you want to use advanced configuration options that apply to your OpenWrt device, such as setting up trusted paths, blacklisting physical paths, setting up physical path hints for certain nodes, and defining trusted upstream devices, this can be achieved by creating a file named local.conf in a persistent filesystem location, such as /etc/openwisp/zerotier/local.conf and then adding the local_conf_path option to the ZeroTier UCI configuration.

For example, let’s create a local configuration file at /etc/openwisp/zerotier/local.conf (JSON) to blacklist a specific physical network path (10.0.0.0/24) from all ZeroTier traffic.

{
  "physical": {
    "10.0.0.0/24": {
      "blacklist": true
    }
  }
}

Now add local_conf_path option to /etc/config/zerotier:

package zerotier

config zerotier 'ow_zt'
    option enabled '1'
    list join '9536600adf654322'
    option secret '{{secret}}'
    option local_conf_path '/etc/openwisp/zerotier/local.conf'

More information