Skip to content

Commit b3ebe35

Browse files
pandafynemesifier
authored andcommitted
[feature] Added autoclient classmethods to Wireguard, VXLAN and OpenWRT backend
1 parent 72e04b7 commit b3ebe35

13 files changed

Lines changed: 352 additions & 6 deletions

File tree

netjsonconfig/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from .backends.openvpn.openvpn import OpenVpn # noqa
66
from .backends.openwisp.openwisp import OpenWisp # noqa
77
from .backends.openwrt.openwrt import OpenWrt # noqa
8+
from .backends.vxlan.vxlan_wireguard import VxlanWireguard # noqa
89
from .backends.wireguard.wireguard import Wireguard # noqa
910
from .version import VERSION, __version__, get_version # noqa
1011

netjsonconfig/backends/openwrt/openwrt.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from ..base.backend import BaseBackend
2+
from ..vxlan.vxlan_wireguard import VxlanWireguard
3+
from ..wireguard.wireguard import Wireguard
24
from . import converters
35
from .parser import OpenWrtParser, config_path, packages_pattern
46
from .renderer import OpenWrtRenderer
@@ -51,3 +53,70 @@ def _generate_contents(self, tar):
5153
name='{0}{1}'.format(config_path, package_name),
5254
contents=text_contents,
5355
)
56+
57+
@classmethod
58+
def wireguard_auto_client(cls, **kwargs):
59+
data = Wireguard.auto_client(**kwargs)
60+
config = {
61+
'interfaces': [
62+
{
63+
'name': data['interface_name'],
64+
'type': 'wireguard',
65+
'private_key': data['client']['private_key'],
66+
'port': data['client']['port'],
67+
# Default values for Wireguard Interface
68+
'mtu': 1420,
69+
'nohostroute': False,
70+
'fwmark': '',
71+
'ip6prefix': [],
72+
'addresses': [],
73+
'network': '',
74+
}
75+
],
76+
'wireguard_peers': [
77+
{
78+
'interface': data['interface_name'],
79+
'public_key': data['server']['public_key'],
80+
'allowed_ips': data['server']['allowed_ips'],
81+
'endpoint_host': data['server']['endpoint_host'],
82+
'endpoint_port': data['server']['endpoint_port'],
83+
# Default values for Wireguard Peers
84+
'preshared_key': '',
85+
'persistent_keepalive': 60,
86+
'route_allowed_ips': True,
87+
}
88+
],
89+
}
90+
if data['client']['ip_address']:
91+
config['interfaces'][0]['addresses'] = [
92+
{
93+
'proto': 'static',
94+
'family': 'ipv4',
95+
'address': data['client']['ip_address'],
96+
'mask': 32,
97+
},
98+
]
99+
return config
100+
101+
@classmethod
102+
def vxlan_wireguard_auto_client(cls, **kwargs):
103+
config = cls.wireguard_auto_client(**kwargs)
104+
vxlan_config = VxlanWireguard.auto_client(**kwargs)
105+
vxlan_interface = {
106+
'name': 'vxlan',
107+
'type': 'vxlan',
108+
'vtep': vxlan_config['server_ip_address'],
109+
'port': 4789,
110+
'vni': vxlan_config['vni'],
111+
'tunlink': config['interfaces'][0]['name'],
112+
# Default values for VXLAN interface
113+
'rxcsum': True,
114+
'txcsum': True,
115+
'mtu': 1280,
116+
'ttl': 64,
117+
'mac': '',
118+
'disabled': False,
119+
'network': '',
120+
}
121+
config['interfaces'].append(vxlan_interface)
122+
return config

netjsonconfig/backends/openwrt/schema.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,6 @@
307307
"type": "string",
308308
"title": "ipv4 address",
309309
"minLength": 7,
310-
"format": "ipv4",
311310
"propertyOrder": 3,
312311
},
313312
"mask": {
@@ -371,7 +370,6 @@
371370
},
372371
"vtep": {
373372
"type": "string",
374-
"format": "hostname",
375373
"title": "VTEP",
376374
"description": "VXLAN Tunnel End Point",
377375
"propertyOrder": 1.1,

netjsonconfig/backends/vxlan/__init__.py

Whitespace-only changes.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from ..wireguard.wireguard import Wireguard
2+
3+
4+
class VxlanWireguard(Wireguard):
5+
@classmethod
6+
def auto_client(cls, vni=0, server_ip_address='', **kwargs):
7+
"""
8+
Returns a configuration dictionary representing VXLAN configuration
9+
that is compatible with the passed server configuration.
10+
11+
:param vni: Virtual Network Identifier
12+
:param server_ip_address: server internal tunnel address
13+
:returns: dictionary representing VXLAN properties
14+
"""
15+
config = {
16+
'server_ip_address': server_ip_address,
17+
'vni': vni,
18+
}
19+
return config

netjsonconfig/backends/wireguard/converters.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def to_intermediate_loop(self, block, result, index=None):
1616
def __intermediate_vpn(self, config, remove=None):
1717
config['ListenPort'] = config.pop('port')
1818
config['PrivateKey'] = config.pop('private_key')
19+
config['Address'] = config.pop('address')
1920
config['peers'] = self.__intermediate_peers(config.get('peers', []))
2021
return self.sorted_dict(config)
2122

netjsonconfig/backends/wireguard/wireguard.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,30 @@ class Wireguard(BaseVpnBackend):
1212
# BaseVpnBackend attributes
1313
vpn_pattern = vpn_pattern
1414
config_suffix = config_suffix
15+
16+
@classmethod
17+
def auto_client(cls, host='', public_key='', server={}, port=51820, **kwargs):
18+
"""
19+
Returns a configuration dictionary representing Wireguard configuration
20+
that is compatible with the passed server configuration.
21+
22+
:param host: remote VPN server
23+
:param port: listen port for Wireguard Client
24+
:param server: dictionary representing a single Wireguard server configuration
25+
:param public_key: public key of the Wireguard server
26+
:returns: dictionary representing a Wireguard server and client properties
27+
"""
28+
return {
29+
'interface_name': server.get('name', ''),
30+
'client': {
31+
'port': port,
32+
'private_key': kwargs.get('private_key', '{{private_key}}'),
33+
'ip_address': kwargs.get('ip_address'),
34+
},
35+
'server': {
36+
'public_key': public_key,
37+
'endpoint_host': host,
38+
'endpoint_port': server.get('port', 51820),
39+
'allowed_ips': [kwargs.get('server_ip_network', '')],
40+
},
41+
}

tests/openwrt/test_backend.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,3 +421,124 @@ def test_override_file(self):
421421
# ensure the additional files are there present in the tar.gz archive
422422
tar = tarfile.open(fileobj=o.generate(), mode='r')
423423
self.assertEqual(len(tar.getmembers()), 1)
424+
425+
def _get_wireguard_empty_configuration(self):
426+
return {
427+
'interfaces': [
428+
{
429+
'addresses': [],
430+
'fwmark': '',
431+
'ip6prefix': [],
432+
'mtu': 1420,
433+
'name': '',
434+
'network': '',
435+
'nohostroute': False,
436+
'port': 51820,
437+
'private_key': '{{private_key}}',
438+
'type': 'wireguard',
439+
}
440+
],
441+
'wireguard_peers': [
442+
{
443+
'allowed_ips': [''],
444+
'endpoint_host': '',
445+
'endpoint_port': 51820,
446+
'interface': '',
447+
'persistent_keepalive': 60,
448+
'preshared_key': '',
449+
'public_key': '',
450+
'route_allowed_ips': True,
451+
}
452+
],
453+
}
454+
455+
def _get_vxlan_wireguard_empty_configuration(self):
456+
wireguard_config = self._get_wireguard_empty_configuration()
457+
vxlan_config = {
458+
'disabled': False,
459+
'mac': '',
460+
'mtu': 1280,
461+
'name': 'vxlan',
462+
'network': '',
463+
'port': 4789,
464+
'rxcsum': True,
465+
'ttl': 64,
466+
'tunlink': '',
467+
'txcsum': True,
468+
'type': 'vxlan',
469+
'vni': 0,
470+
'vtep': '',
471+
}
472+
wireguard_config['interfaces'].append(vxlan_config)
473+
return wireguard_config
474+
475+
def test_wireguard_auto_client(self):
476+
with self.subTest('No arguments provided'):
477+
expected = self._get_wireguard_empty_configuration()
478+
self.assertDictEqual(OpenWrt.wireguard_auto_client(), expected)
479+
with self.subTest('Required arguments provided'):
480+
expected = self._get_wireguard_empty_configuration()
481+
expected['interfaces'][0].update(
482+
{
483+
'name': 'wg',
484+
'private_key': '{{private_key}}',
485+
'addresses': [
486+
{
487+
'address': '10.0.0.2',
488+
'family': 'ipv4',
489+
'mask': 32,
490+
'proto': 'static',
491+
},
492+
],
493+
}
494+
)
495+
expected['wireguard_peers'][0].update(
496+
{
497+
'allowed_ips': ['10.0.0.1/24'],
498+
'endpoint_host': '0.0.0.0',
499+
'public_key': 'server_public_key',
500+
'interface': 'wg',
501+
}
502+
)
503+
self.assertDictEqual(
504+
OpenWrt.wireguard_auto_client(
505+
host='0.0.0.0',
506+
public_key='server_public_key',
507+
server={'name': 'wg', 'port': 51820},
508+
server_ip_network='10.0.0.1/24',
509+
ip_address='10.0.0.2',
510+
),
511+
expected,
512+
)
513+
514+
def test_vxlan_wireguard_auto_client(self):
515+
with self.subTest('No arguments provided'):
516+
expected = self._get_vxlan_wireguard_empty_configuration()
517+
self.assertDictEqual(OpenWrt.vxlan_wireguard_auto_client(), expected)
518+
with self.subTest('Required arguments provided'):
519+
expected = self._get_vxlan_wireguard_empty_configuration()
520+
expected['interfaces'][0].update(
521+
{'name': 'wg', 'private_key': '{{private_key}}'}
522+
)
523+
expected['wireguard_peers'][0].update(
524+
{
525+
'allowed_ips': ['10.0.0.1/24'],
526+
'endpoint_host': '0.0.0.0',
527+
'public_key': 'server_public_key',
528+
'interface': 'wg',
529+
}
530+
)
531+
expected['interfaces'][1].update(
532+
{'tunlink': 'wg', 'vni': 1, 'vtep': '10.0.0.1'}
533+
)
534+
self.assertDictEqual(
535+
OpenWrt.vxlan_wireguard_auto_client(
536+
host='0.0.0.0',
537+
public_key='server_public_key',
538+
server={'name': 'wg', 'port': 51820},
539+
server_ip_network='10.0.0.1/24',
540+
vni=1,
541+
server_ip_address='10.0.0.1',
542+
),
543+
expected,
544+
)

tests/openwrt/test_wireguard.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,9 @@ def test_render_wireguard_peer_with_variables(self):
161161
"wireguard_peers": [
162162
{
163163
"interface": "wg0",
164-
"public_key": "{{pub_key_8097b09be57a4b278e2ef2ea9ea809f3}}",
164+
"public_key": "{{public_key_8097b09be57a4b278e2ef2ea9ea809f3}}",
165165
"allowed_ips": [
166-
"{{server_ip_max_prefix_8097b09be57a4b278e2ef2ea9ea809f3}}"
166+
"{{server_ip_network_8097b09be57a4b278e2ef2ea9ea809f3}}"
167167
],
168168
"endpoint_host": "{{vpn_host_8097b09be57a4b278e2ef2ea9ea809f3}}",
169169
"endpoint_port": 40840,
@@ -174,9 +174,9 @@ def test_render_wireguard_peer_with_variables(self):
174174
]
175175
},
176176
context={
177-
"server_ip_max_prefix_8097b09be57a4b278e2ef2ea9ea809f3": "10.0.0.1/32",
177+
"server_ip_network_8097b09be57a4b278e2ef2ea9ea809f3": "10.0.0.1/32",
178178
"vpn_host_8097b09be57a4b278e2ef2ea9ea809f3": "192.168.1.42",
179-
"pub_key_8097b09be57a4b278e2ef2ea9ea809f3": "rn+isMBpyQ4HX6ZzE709bKnZw5IaLZoIS3hIjmfKCkk=",
179+
"public_key_8097b09be57a4b278e2ef2ea9ea809f3": "rn+isMBpyQ4HX6ZzE709bKnZw5IaLZoIS3hIjmfKCkk=",
180180
"pre_key_8097b09be57a4b278e2ef2ea9ea809f3": "oPZmGdHBseaV1TF0julyElNuJyeKs2Eo+o62R/09IB4=",
181181
},
182182
)

tests/vxlan/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)