From 0196c402fc9b37a48ad54f61da6fa9f0551f887d Mon Sep 17 00:00:00 2001 From: Christian Herdtweck Date: Tue, 3 Mar 2026 13:22:36 +0100 Subject: [PATCH] Create template for WireGuard VPNCONN WireGuard VPN connections have so many different cnfvars when compared to IPSec vpns, that we create a different template for them. The "vpnconn" function uses the VPNCONN_PROTO to decide which of the two templates it should use. Also add two fully functional wireguard vpnconns to test config (a roadwarrior and a site-to-site) including interface, own keys and foreign keys. This is the first step in cleaning up vpn connection creation in QA. The new functionality is not used there, yet, but can be easily be triggered in the future to simplify vpnconn creation. --- src/cnfvar/templates.py | 84 +++++++++++++++++++++++++++++++++++++++------- test/cnfvar/cnfs.cnf | 63 +++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 13 deletions(-) diff --git a/src/cnfvar/templates.py b/src/cnfvar/templates.py index 4c157fa..f29b7ab 100644 --- a/src/cnfvar/templates.py +++ b/src/cnfvar/templates.py @@ -155,8 +155,8 @@ key_own_defaults = { "KEY_OWN_CREATE_CN": "", "KEY_OWN_CREATE_EMAIL": "" } -#: UI defaults for a VPN connection instance -vpnconn_defaults = { +#: UI defaults for an [IPSec] VPN connection instance +vpnconn_ipsec_defaults = { "VPNCONN_ACTIVATION": "ALWAYS", "VPNCONN_DISABLED": "0", "VPNCONN_DNS_RELAYING_ALLOWED": "1", @@ -200,6 +200,40 @@ vpnconn_defaults = { "VPNCONN_XAUTH_SERVER_ENABLE": "0" } +# defaults for a WireGuard connection (roadwarrior) +vpnconn_wireguard_defaults = dict( + # proto-independent: + VPNCONN_DISABLED=0, + VPNCONN_ACTIVATION="PASSIVE", + VPNCONN_FIREWALL_RULESET_REF=5, + VPNCONN_DNS_RELAYING_ALLOWED=1, + VPNCONN_EMAIL_RELAYING_ALLOWED=1, + VPNCONN_KEY_FOREIGN_REF=1, + VPNCONN_PROXY_PROFILE_REF=-2, + VPNCONN_REMOTE_INET_NAT=0, + # WireGuard-specific: + VPNCONN_PROTO="WIREGUARD", + VPNCONN_VPN_WG_INTERFACE_REF=1, + # VPNCONN_WG_ENDPOINT_HOST="", # cannot be empty; must be set ... + # VPNCONN_WG_ENDPOINT_PORT="", # ... or be completely absent + VPNCONN_OFFLINE_DETECTION_SEC=60, + VPNCONN_WG_LOCAL_NET=dict( + value="NIC", + children=[ + ("VPNCONN_WG_LOCAL_NET_NIC_REF", "0"), + ], + ), + VPNCONN_WG_LOCAL_TYPE="CONFIGURED", + VPNCONN_WG_PSK="", + VPNCONN_WG_REMOTE_NET=dict( + value="", + children=[ + ("VPNCONN_WG_REMOTE_NET_IP", "192.168.40.1"), + ("VPNCONN_WG_REMOTE_NET_NETMASK", "255.255.255.255"), + ], + ), +) + ############################################################################### # MINOR CONFIGURATION @@ -235,8 +269,10 @@ def template(name, value, instance=-1, defaults=None, **kwargs): prefix = name.lower() + "_" for key in kwargs.keys(): if key.lower().startswith(prefix): - log.warning(f"For overwriting template params, omit the leading name " - f"(here: {name}_) from keys (here: {key})") + log.warning( + f"For overwriting template params, omit the leading name " + f"(here: {name}_) from keys (here: {key})" + ) cnf.children.single_with_name(f"{prefix}{key}").value = kwargs[key] return cnf @@ -401,18 +437,40 @@ def vpnconn(name, instance=-1, **kwargs): """ Generate a vpn connection cnf variable. + Creates an IPSec vpn connection per default, will create a + WireGuard VPN from different template if a different `VPNCONN_PROTO` + is set (via argument `proto="wireguard"`). + :param str name: name for the vpn connection :param int instance: instance number for the vpn connection :returns: generated cnf variable :rtype: :py:class:`Cnf` """ - log.info(f"Generating a vpn connection {name} cnfvar") - vpnconn_cnf = template("vpnconn", name, instance=instance, - defaults=vpnconn_defaults, **kwargs) - if vpnconn_cnf.children.single_with_name("vpnconn_lan_type").value not in ["NIC", "CUSTOM"]: - vpnconn_cnf.children.remove_where(lambda c: c.name == "vpnconn_lan_net") - if vpnconn_cnf.children.single_with_name("vpnconn_remote_type").value != "CUSTOM": - vpnconn_cnf.children.remove_where(lambda c: c.name == "vpnconn_remote_net") - if vpnconn_cnf.children.single_with_name("vpnconn_remote_type").value != "MODECONFIG": - vpnconn_cnf.children.remove_where(lambda c: c.name == "vpnconn_remote_modeconfig_ip") + # since wireguard and ipsec use very different cnfvars, we first check for + # the protocol. Use IPSec as default + proto = "ipsec" + for key, value in kwargs.items(): + if key.lower() == "proto": + proto = value.lower() + + # create an IPSec connection + if proto == "ipsec": + log.info(f"Generating an IPSec vpn connection {name} cnfvar") + vpnconn_cnf = template("vpnconn", name, instance=instance, + defaults=vpnconn_ipsec_defaults, **kwargs) + if vpnconn_cnf.children.single_with_name("vpnconn_lan_type").value not in ["NIC", "CUSTOM"]: + vpnconn_cnf.children.remove_where(lambda c: c.name == "vpnconn_lan_net") + if vpnconn_cnf.children.single_with_name("vpnconn_remote_type").value != "CUSTOM": + vpnconn_cnf.children.remove_where(lambda c: c.name == "vpnconn_remote_net") + if vpnconn_cnf.children.single_with_name("vpnconn_remote_type").value != "MODECONFIG": + vpnconn_cnf.children.remove_where(lambda c: c.name == "vpnconn_remote_modeconfig_ip") + + # create a WireGuard connection + elif proto == "wireguard": + log.info(f"Generating a WireGuard vpn connection {name} cnfvar") + vpnconn_cnf = template("vpnconn", name, instance=instance, + defaults=vpnconn_wireguard_defaults, **kwargs) + + else: + raise ValueError(f"Invalid vpn connection protocol: {proto!r}") return vpnconn_cnf diff --git a/test/cnfvar/cnfs.cnf b/test/cnfvar/cnfs.cnf index d52da21..09f01b3 100644 --- a/test/cnfvar/cnfs.cnf +++ b/test/cnfvar/cnfs.cnf @@ -1349,3 +1349,66 @@ 1348 (1346) VPN_ENCRYPTION_PROFILE_IPSEC_HASH,0: "MD5" 1349 (1304) VPN_ENCRYPTION_PROFILE_PFSGROUP,0: "None" 1350 VPN_NAT_T,0: "1" +1351 KEY_OWN,2: "wireguard key" +1352 (1351) KEY_OWN_PRIVATE_KEY,0: "mDJzyGuSJm8QPlEEIdLd9K5BfTmLUzwuPx5h9t7ILH8=" +1353 (1351) KEY_OWN_PUBLIC_KEY,0: "Pw7eCPgCjAEXtQ1jQ3/So+envZaG9nUDiDBd4PI3XHQ=" +1354 (1351) KEY_OWN_TYPE,0: "WIREGUARD" +1355 (1351) KEY_OWN_VALIDFROM,0: "20221129T143552" +1357 VPN_WG_INTERFACE,1: "wireguard interface" +1358 (1357) VPN_WG_INTERFACE_KEY_OWN_REF,0: "2" +1359 (1357) VPN_WG_INTERFACE_NIC_REF,0: "0" +1360 (1357) VPN_WG_INTERFACE_PORT,0: "800" +1361 VPNCONN,1: "wireguard roadwarrior" +1362 (1361) VPNCONN_ACTIVATION,0: "PASSIVE" +1363 (1361) VPNCONN_DISABLED,0: "0" +1364 (1361) VPNCONN_DNS_RELAYING_ALLOWED,0: "1" +1365 (1361) VPNCONN_EMAIL_RELAYING_ALLOWED,0: "1" +1366 (1361) VPNCONN_FIREWALL_RULESET_REF,0: "9" +1367 (1361) VPNCONN_GENERATED_PROFILE,0: "WGQUICK" +1368 (1361) VPNCONN_KEY_FOREIGN_REF,0: "1" +1369 (1361) VPNCONN_OFFLINE_DETECTION_SEC,0: "60" +1370 (1361) VPNCONN_PROTO,0: "WIREGUARD" +1371 (1361) VPNCONN_PROXY_PROFILE_REF,0: "-1" +1372 (1361) VPNCONN_REMOTE_INET_NAT,0: "0" +1373 (1361) VPNCONN_VPN_WG_INTERFACE_REF,0: "1" +1374 (1361) VPNCONN_WG_LOCAL_NET,0: "NIC" +1375 (1374) VPNCONN_WG_LOCAL_NET_NIC_REF,0: "2" +1376 (1361) VPNCONN_WG_LOCAL_TYPE,0: "CONFIGURED" +1377 (1361) VPNCONN_WG_PSK,0: "9ZdjkFSNcDAIOwwMQZ/6bBNFc35Rd4bWyPeIpJpm5qI=" +1378 (1361) VPNCONN_WG_REMOTE_NET,0: "" +1379 (1378) VPNCONN_WG_REMOTE_NET_IP,0: "192.168.40.5" +1380 (1378) VPNCONN_WG_REMOTE_NET_NETMASK,0: "255.255.255.255" +1381 VPNCONN,2: "wg site2site" +1382 (1381) VPNCONN_ACTIVATION,0: "ALWAYS" +1383 (1381) VPNCONN_DISABLED,0: "1" +1384 (1381) VPNCONN_DNS_RELAYING_ALLOWED,0: "1" +1385 (1381) VPNCONN_EMAIL_RELAYING_ALLOWED,0: "1" +1386 (1381) VPNCONN_FIREWALL_RULESET_REF,0: "9" +1387 (1381) VPNCONN_GENERATED_PROFILE,0: "WGI2N" +1388 (1381) VPNCONN_KEY_FOREIGN_REF,0: "2" +1389 (1381) VPNCONN_OFFLINE_DETECTION_SEC,0: "60" +1390 (1381) VPNCONN_PROTO,0: "WIREGUARD" +1391 (1381) VPNCONN_PROXY_PROFILE_REF,0: "4" +1392 (1381) VPNCONN_REMOTE_INET_NAT,0: "0" +1393 (1381) VPNCONN_VPN_WG_INTERFACE_REF,0: "1" +1394 (1381) VPNCONN_WG_ENDPOINT_HOST,0: "hauptsitz.meine-firma.de" +1395 (1381) VPNCONN_WG_ENDPOINT_PORT,0: "51821" +1396 (1381) VPNCONN_WG_LOCAL_NET,0: "NIC" +1397 (1396) VPNCONN_WG_LOCAL_NET_NIC_REF,0: "2" +1398 (1381) VPNCONN_WG_LOCAL_TYPE,0: "CONFIGURED" +1399 (1381) VPNCONN_WG_PSK,0: "g42DVjQz1gu4LAhWfedKGAOzevZu3Daos6ukSReYw7c=" +1400 (1381) VPNCONN_WG_REMOTE_NET,0: "" +1401 (1400) VPNCONN_WG_REMOTE_NET_IP,0: "192.168.10.0" +1402 (1400) VPNCONN_WG_REMOTE_NET_NETMASK,0: "255.255.255.0" +1403 KEY_FOREIGN,1: "wireguard roadwarrior" +1404 (1403) KEY_FOREIGN_AUTOCREATE_TYPE,0: "WGQUICK" +1405 (1403) KEY_FOREIGN_PRIVATE_KEY,0: "Nm9fIqDI/sgQNJDbM+bTJTYP6pDjaHIEjMyVyprVlIE=" +1406 (1403) KEY_FOREIGN_PUBLIC_KEY,0: "xw2eBw6e/yReSvGlVDknp/1+BJua9qMzpEDA6LQRUDc=" +1407 (1403) KEY_FOREIGN_TYPE,0: "WIREGUARD" +1408 (1403) KEY_FOREIGN_VALIDFROM,0: "20241105T100559" +1409 KEY_FOREIGN,2: "wireguard site2site" +1410 (1409) KEY_FOREIGN_AUTOCREATE_TYPE,0: "WGQUICK" +1411 (1409) KEY_FOREIGN_PRIVATE_KEY,0: "Nm9fIqDI/sgQNJDbM+bTJTYP6pDjaHIEjMyVyprVlIE=" +1412 (1409) KEY_FOREIGN_PUBLIC_KEY,0: "xw2eBw6e/yReSvGlVDknp/1+BJua9qMzpEDA6LQRUDc=" +1413 (1409) KEY_FOREIGN_TYPE,0: "WIREGUARD" +1414 (1409) KEY_FOREIGN_VALIDFROM,0: "20241105T100559" -- 1.7.1