Skip to content

Commit

Permalink
Merge 5c70aaa into 2e7d548
Browse files Browse the repository at this point in the history
  • Loading branch information
Aryamanz29 committed Jun 5, 2023
2 parents 2e7d548 + 5c70aaa commit e293c09
Show file tree
Hide file tree
Showing 12 changed files with 642 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Its main features are listed below for your reference:
* `OpenWisp Firmware <https://github.com/openwisp/OpenWISP-Firmware>`_ support
* `OpenVPN <https://openvpn.net>`_ support
* `WireGuard <https://www.wireguard.com/>`_ support
* `ZeroTier <https://www.zerotier.com/>`_ support
* Possibility to support more firmwares via custom backends
* Based on the `NetJSON RFC <http://netjson.org/rfc.html>`_
* **Validation** based on `JSON-Schema <http://json-schema.org/>`_
Expand Down
2 changes: 2 additions & 0 deletions netjsonconfig/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .backends.openwrt.openwrt import OpenWrt # noqa
from .backends.vxlan.vxlan_wireguard import VxlanWireguard # noqa
from .backends.wireguard.wireguard import Wireguard # noqa
from .backends.zerotier.zerotier import ZeroTier # noqa
from .version import VERSION, __version__, get_version # noqa


Expand All @@ -16,6 +17,7 @@ def get_backends():
'openwisp': OpenWisp,
'openvpn': OpenVpn,
'wireguard': Wireguard,
'zerotier': ZeroTier,
}
logger = logging.getLogger(__name__)

Expand Down
Empty file.
17 changes: 17 additions & 0 deletions netjsonconfig/backends/zerotier/converters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from ..base.converter import BaseConverter
from .schema import schema


class ZeroTier(BaseConverter):
netjson_key = 'zerotier'
intermediate_key = 'zerotier'
_schema = schema

def to_intermediate_loop(self, block, result, index=None):
vpn = self.__intermediate_vpn(block)
result.setdefault('zerotier', [])
result['zerotier'].append(vpn)
return result

def __intermediate_vpn(self, config, remove=[False, 0, '']):
return self.sorted_dict(config)
21 changes: 21 additions & 0 deletions netjsonconfig/backends/zerotier/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import re

from ..base.parser import BaseParser

vpn_pattern = re.compile('^// zerotier controller config:\s', flags=re.MULTILINE)
config_pattern = re.compile('^([^\s]*) ?(.*)$')
config_suffix = ''


class ZeroTierParser(BaseParser):
def parse_text(self, config):
raise NotImplementedError()

def parse_tar(self, tar):
raise NotImplementedError()

def _get_vpns(self, text):
raise NotImplementedError()

def _get_config(self, contents):
raise NotImplementedError()
15 changes: 15 additions & 0 deletions netjsonconfig/backends/zerotier/renderer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from ..base.renderer import BaseRenderer


class ZeroTierRenderer(BaseRenderer):
"""
ZeroTier Renderer
"""

def cleanup(self, output):
# remove indentations
output = output.replace(' ', '')
# remove last newline
if output.endswith('\n\n'):
output = output[0:-1]
return output
209 changes: 209 additions & 0 deletions netjsonconfig/backends/zerotier/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
"""
ZeroTier specific JSON-Schema definition
"""

from copy import deepcopy

from ...schema import schema as default_schema

# The schema is taken from OpenAPI specification:
# https://docs.zerotier.com/service/v1/ (self-hosted controllers)
# https://docs.zerotier.com/openapi/centralv1.json (central controllers)
base_zerotier_schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": True,
"properties": {
"zerotier": {
"type": "array",
"title": "ZeroTier",
"uniqueItems": True,
"additionalItems": True,
"items": {
"type": "object",
"title": "ZeroTier Network",
"additionalProperties": True,
"required": ["name"],
"properties": {
# Read-only properties
"name": {
"type": "string",
# Since it is intended to be set by
# the VPN backend's name field, it is read-only
"readOnly": True,
"example": "openwisp-wifi-network",
"description": "Name of the network",
},
"id": {
"type": "string",
"maxLength": 16,
"readOnly": True,
"example": "3e245e31af000001",
"description": "Network ID",
},
"nwid": {
"type": "string",
"maxLength": 16,
"readOnly": True,
"example": "3e245e31af000001",
"description": "Network ID legacy field (same as 'id')",
},
"objtype": {
"type": "string",
"readOnly": True,
"default": "network",
"example": "network",
},
"revision": {
"type": "integer",
"example": 1,
"readOnly": True,
"description": "The revision number of the network configuration",
},
"creationTime": {
"type": "number",
"readOnly": True,
"example": 1623101592,
"description": "Time when the network was created",
},
# Configurable properties
"private": {
"type": "boolean",
"default": True,
"description": (
"Whether or not the network is private "
"If false, members will NOT need to be authorized to join"
),
},
"enableBroadcast": {
"type": "boolean",
"description": "Enable broadcast packets on the network",
},
"v4AssignMode": {
"type": "object",
"properties": {
"zt": {
"type": "boolean",
"description": "Whether ZeroTier should assign IPv4 addresses to members",
},
},
},
"v6AssignMode": {
"type": "object",
"properties": {
"6plane": {
"type": "boolean",
"description": "Whether 6PLANE addressing should be used for IPv6 assignment",
},
"rfc4193": {
"type": "boolean",
"description": "Whether RFC4193 addressing should be used for IPv6 assignment", # noqa
},
"zt": {
"type": "boolean",
"description": "Whether ZeroTier should assign IPv6 addresses to members",
},
},
},
"mtu": {
"type": "integer",
"example": 2800,
"description": "MTU to set on the client virtual network adapter",
},
"multicastLimit": {
"type": "integer",
"example": 32,
"description": (
"Maximum number of recipients per multicast or broadcast."
"Warning - Setting this to 0 will disable IPv4 communication on your network!"
),
},
"routes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"target": {
"type": "string",
"example": "192.168.192.0/24",
"description": "The target IP address range for the route",
},
"via": {
"type": "string",
"example": "192.168.192.1",
"description": "The IP address of the next hop for the route",
},
},
},
"description": "Array of route objects",
},
"ipAssignmentPools": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ipRangeStart": {
"type": "string",
"example": "192.168.192.1",
"description": "The starting IP address of the pool range",
},
"ipRangeEnd": {
"type": "string",
"example": "192.168.192.254",
"description": "The ending IP address of the pool range",
},
},
},
"description": "Range of IP addresses for the auto assign pool",
},
"dns": {
"type": "object",
"properties": {
"domain": {
"type": "string",
"example": "zerotier.openwisp.io",
"description": "The domain for DNS resolution",
},
"servers": {
"type": "array",
"items": {
"type": "string",
"example": "10.147.20.3",
"description": "The DNS server IP addresses",
},
},
},
},
"rules": {
"type": "array",
"items": {"type": "object"},
"description": "Array of network rule objects",
},
"capabilities": {
"type": "array",
"items": {"type": "object"},
"description": "Array of network capabilities",
},
"tags": {
"type": "array",
"items": {"type": "object"},
"description": "Array of network tag objects",
},
"remoteTraceTarget": {
"type": "string",
"example": "7f5d90eb87",
"description": "The remote target ID for network tracing",
},
"remoteTraceLevel": {
"type": "integer",
"description": "The level of network tracing",
},
},
},
},
},
}

schema = deepcopy(base_zerotier_schema)
schema['required'] = ['zerotier']
schema['properties']['files'] = default_schema['properties']['files']
6 changes: 6 additions & 0 deletions netjsonconfig/backends/zerotier/templates/zerotier.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% for vpn in data.zerotier %}
// zerotier controller config: {{ vpn.nwid }}.json

{{ vpn | tojson(indent=2)}}

{% endfor %}
26 changes: 26 additions & 0 deletions netjsonconfig/backends/zerotier/zerotier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from ..base.backend import BaseVpnBackend
from . import converters
from .parser import config_suffix, vpn_pattern
from .renderer import ZeroTierRenderer
from .schema import schema


class ZeroTier(BaseVpnBackend):
schema = schema
converters = [converters.ZeroTier]
renderer = ZeroTierRenderer
# BaseVpnBackend attributes
vpn_pattern = vpn_pattern
config_suffix = config_suffix

@classmethod
def auto_client(cls, server={}, **kwargs):
network_id = server.get('id', server.get('nwid', ''))
return {
'zerotier': [
{
'id': network_id,
'name': server.get('name', ''),
}
]
}
Empty file added tests/zerotier/__init__.py
Empty file.

0 comments on commit e293c09

Please sign in to comment.