Skip to content

Commit

Permalink
[feature] Added support for custom zt ifname #284
Browse files Browse the repository at this point in the history
Closes #284
  • Loading branch information
Aryamanz29 authored Sep 22, 2023
1 parent 2ebc2b2 commit 67ab548
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 95 deletions.
106 changes: 55 additions & 51 deletions docs/source/backends/zerotier.rst
Original file line number Diff line number Diff line change
Expand Up @@ -274,30 +274,32 @@ Client specific settings

Required properties:

* id
* name

+------------------------+---------+--------------+----------------------------------------------------------------------------------------------------+
| key name | type | default | description |
+========================+=========+==============+====================================================================================================+
| ``name`` | string | | name of the zerotier network |
+------------------------+---------+--------------+----------------------------------------------------------------------------------------------------+
| ``id`` | list | ``[]`` | list of strings containing **16-digit** hexadecimal network IDs to join |
| | | | |
| | | | **note:** must contain at least one network ID |
+------------------------+---------+--------------+----------------------------------------------------------------------------------------------------+
| ``config_path`` | string | | path to the persistent configuration folder |
+------------------------+---------+--------------+----------------------------------------------------------------------------------------------------+
| ``copy_config_path`` | string | ``'0'`` | specifies whether to copy the configuration file to RAM |
| | | | |
| | | | ``'0'`` - No, ``'1'`` - Yes, this prevents writing to flash in zerotier controller mode |
+------------------------+---------+--------------+----------------------------------------------------------------------------------------------------+
| ``port`` | integer | ``9993`` | port number of the zerotier service |
+------------------------+---------+--------------+----------------------------------------------------------------------------------------------------+
| ``local_conf`` | boolean | | path of the local zerotier configuration |
+------------------------+---------+--------------+----------------------------------------------------------------------------------------------------+
| ``secret`` | boolean | | secret key of the zerotier client (network member), leave it blank to be automatically determined |
+------------------------+---------+--------------+----------------------------------------------------------------------------------------------------+
* 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`` | string | | path of the local zerotier configuration (only used for advanced configuration) |
+------------------------+---------+----------------------------+-----------------------------------------------------------------------------------------------------------+

Working around schema limitations
---------------------------------
Expand All @@ -315,18 +317,15 @@ Automatic generation of clients

.. automethod:: netjsonconfig.OpenWrt.zerotier_auto_client

Example:
Example (with custom zerotier interface name):

.. code-block:: python
from netjsonconfig import OpenWrt
server_config = {
"id": ["9536600adf654321"],
"name": "ow_zt",
}
client_config = OpenWrt.zerotier_auto_client(
nwid=server_config['id'], name=server_config['name']
name='ow_zt',
networks=[{"id": "9536600adf654321", "ifname": "owzt654321"}],
)
print(OpenWrt(client_config).render())
Expand All @@ -337,9 +336,19 @@ 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 '{{zt_identity_secret}}'
option secret '{{secret}}'
# ---------- files ---------- #
# path: /etc/openwisp/zerotier/devicemap
# mode: 0644
# network_id=interface_name
9536600adf654321=owzt654321
.. note::

Expand Down Expand Up @@ -367,42 +376,37 @@ configuration settings, please refer to the following OpenAPI API specifications
Advanced configuration
~~~~~~~~~~~~~~~~~~~~~~

The OpenWRT ZeroTier service can be configured to run on multiple ports,
for example, **9993 (default)** and **9994**. This can be achieved by creating
a file named ``zt_local.conf`` in a persistent filesystem location, such as
``/etc/config/zt_local.conf``, and then adding the option ``local_conf``
to the ZeroTier UCI 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`` option to the ZeroTier UCI configuration.

``/etc/config/zt_local.conf``
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.

.. code-block:: json
{
"settings": {
"primaryPort": 9994
"physical": {
"10.0.0.0/24": {
"blacklist": true
}
}
}
``/etc/config/zerotier``
Now add ``local_conf`` option to ``/etc/config/zerotier``:

.. code-block:: text
package zerotier
# This config utilizes port 9993 (default)
config zerotier 'ow_zt1'
option enabled '1'
list join '9536600adf654321'
option secret '{{zt_identity_secret}}'
# This config utilizes port 9994
config zerotier 'ow_zt2' (new)
config zerotier 'ow_zt'
option enabled '1'
list join '9536600adf654322'
option secret '{{zt_identity_secret}}'
option local_conf '/etc/config/zerotier.local.conf'
option secret '{{secret}}'
option local_conf '/etc/openwisp/zerotier/local.conf'
**More information**
Expand Down
39 changes: 37 additions & 2 deletions netjsonconfig/backends/openwrt/converters/zerotier.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,55 @@ class ZeroTier(OpenWrtConverter, BaseZeroTier):
_schema = schema['properties']['zerotier']['items']

def __intermediate_vpn(self, vpn):
nwid_ifnames = vpn.get('networks', [])
files = self.netjson.get('files', [])
self.netjson['files'] = self.__get_zt_ifname_files(vpn, files)
vpn.update(
{
'.name': self._get_uci_name(vpn.pop('name')),
'.type': 'zerotier',
'join': vpn.pop('id'),
'config_path': vpn.get('config_path', '/etc/openwisp/zerotier'),
'copy_config_path': vpn.get('copy_config_path', '1'),
'join': [networks.get('id', '') for networks in nwid_ifnames],
'enabled': not vpn.pop('disabled', False),
}
)
del vpn['networks']
return super().__intermediate_vpn(vpn, remove=[''])

def __netjson_vpn(self, vpn):
vpn['id'] = vpn.pop('join')
nwids = vpn.pop('join')
vpn['name'] = vpn.pop('.name')
vpn['networks'] = [{"id": nwid, "ifname": f"owzt{nwid[-6:]}"} for nwid in nwids]
# 'disabled' defaults to False in OpenWRT
vpn['disabled'] = vpn.pop('enabled', '0') == '0'
del vpn['.type']
return super().__netjson_vpn(vpn)

def __get_zt_ifname_files(self, vpn, files):
config_path = vpn.get('config_path', '/etc/openwisp/zerotier')
nwid_ifnames = vpn.get('networks', [])
zt_file_contents = '# network_id=interface_name\n'

for networks in nwid_ifnames:
nwid = networks.get('id', '')
ifname = networks.get('ifname')
zt_file_contents += f"{nwid}={ifname}\n"

zt_interface_map = {
'path': f"{config_path}/devicemap",
'mode': '0644',
'contents': zt_file_contents,
}

if not files:
return [zt_interface_map]
updated_files = []
for file in files:
if file.get('path') == zt_interface_map.get('path'):
zt_interface_map['contents'] += '\n' + file['contents']
else:
updated_files.append(file)
if zt_interface_map.get('contents'):
updated_files.append(zt_interface_map)
return updated_files
68 changes: 47 additions & 21 deletions netjsonconfig/backends/openwrt/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -1008,9 +1008,9 @@
"propertyOrder": 14,
"items": {
"type": "object",
"title": "Network Member",
"title": "Network Member Configuration",
"additionalProperties": True,
"required": ["id", "name"],
"required": ["name", "networks"],
"properties": {
# ZeroTier customization (disabled) for OpenWRT
"disabled": {
Expand All @@ -1024,34 +1024,65 @@
"name": {
"type": "string",
"propertyOrder": 2,
"default": "openwisp_zerotier_network",
"description": "Name of the zerotier network",
"default": "ow_zt",
"minLength": 1,
"description": "Name of the zerotier network member configuration",
},
"id": {
"networks": {
"type": "array",
"title": "16-digit hexadecimal network IDs to join",
"title": "Networks",
"minItems": 1,
"propertyOrder": 3,
"uniqueItems": True,
"additionalProperties": True,
"items": {
"type": "string",
"title": "Network ID",
"maxLength": 16,
"minLength": 16,
"type": "object",
"title": "Network Member",
"allOf": [{"required": ["id", "ifname"]}],
"properties": {
"id": {
"type": "string",
"title": "Network ID",
"maxLength": 16,
"minLength": 16,
"description": "Network ID to join",
},
"ifname": {
"type": "string",
"title": "Interface name",
"minLength": 1,
"maxLength": 10,
"description": "Name of zerotier interface",
},
},
},
},
"config_path": {
"secret": {
"type": "string",
"propertyOrder": 4,
"default": "{{secret}}",
"description": (
"Identity secret of the zerotier client (network member), "
"You can leave it as the default and OpenWISP will automatically determine it"
),
},
# Hidden properties
"config_path": {
"type": "string",
"propertyOrder": 5,
"options": {"hidden": True},
"default": "/etc/openwisp/zerotier",
"description": (
"Path to the persistent configuration "
"folder (for zerotier controller mode)"
"directory (for zerotier controller mode)"
),
},
"copy_config_path": {
"type": "string",
"propertyOrder": 5,
"propertyOrder": 6,
"options": {"hidden": True},
"enum": ["0", "1"],
"default": "1",
"description": (
"Specifies whether to copy the configuration "
"file to RAM ('0' - No, '1' - Yes), this prevents "
Expand All @@ -1063,20 +1094,15 @@
"minimum": 1,
"maximum": 65535,
"default": 9993,
"propertyOrder": 6,
"propertyOrder": 7,
"description": "Port number of the zerotier service",
},
"local_conf": {
"type": "string",
"propertyOrder": 7,
"description": "Path of the local zerotier configuration",
},
"secret": {
"type": "string",
"propertyOrder": 8,
"description": (
"Secret key of the zerotier client (network member), "
"leave it blank to be automatically determined"
"Path of the local zerotier configuration "
"(only used for advanced configuration)"
),
},
},
Expand Down
10 changes: 6 additions & 4 deletions netjsonconfig/backends/zerotier/zerotier.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ class ZeroTier(BaseVpnBackend):
def auto_client(
cls,
name='ow_zt',
nwid=None,
identity_secret='{{zt_identity_secret}}',
networks=None,
identity_secret='{{secret}}',
config_path='/etc/openwisp/zerotier',
disabled=False,
):
nwid = nwid or ['']
networks = networks or []
return {
'id': nwid,
'name': name,
'networks': networks,
'secret': identity_secret,
'config_path': config_path,
'disabled': disabled,
}
Loading

0 comments on commit 67ab548

Please sign in to comment.