Skip to content

Commit 76a3c2c

Browse files
authored
Added async vpn example (#58)
Thank you!
1 parent f1fcc1d commit 76a3c2c

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#!/usr/bin/env python
2+
# SPDX-License-Identifier: LGPL-2.1-or-later
3+
#
4+
# Example to create a new VPN network connection profile. Currently supported only with tls-auth
5+
#
6+
# $ examples/async/add-openvpn-connection-async.py --help
7+
# usage: add-openvpn-connection.py [-h] [-c CONN_ID] [-d DEV] [--remote REMOTE] [--remote-cert-tls] [-a] [--save]
8+
# [--ca, CA_PATH] [--cert, CERT_PATH] [--key, KEY_path] [--ta, TA_PATH]
9+
#
10+
# Optional arguments have example values:
11+
#
12+
# optional arguments:
13+
# -h, --help show this help message and exit
14+
# -c CONN_ID Connection Id
15+
# -u UUID Connection UUID
16+
# -f OVPN .ovpn connection file
17+
# -a autoconnect
18+
# --save Save
19+
# --ca Path to CA file
20+
# --cert Path to cert file
21+
# --key Path to key file
22+
# --ta Path to tls-auth file
23+
#
24+
# $ add-vpn-connection.py
25+
# New unsaved connection profile created, show it with:
26+
# nmcli connection show "MyConnectionExample"|grep -v -e -- -e default
27+
#
28+
# Connection Profile settings are described at:
29+
# https://networkmanager.dev/docs/api/latest/ref-settings.html
30+
#
31+
# Note: By default, it uses add_connection_unsaved() to add a temporary
32+
# memory-only connection which is not saved to the system-connections folder:
33+
# For reference, see: https://networkmanager.dev/docs/api/latest/spec.html
34+
# -> org.freedesktop.NetworkManager.Settings (Settings Profile Manager)
35+
36+
import asyncio
37+
import functools
38+
import logging
39+
import sdbus
40+
from uuid import uuid4
41+
from argparse import ArgumentParser
42+
from pprint import pformat
43+
from sdbus_async.networkmanager import (
44+
NetworkManagerSettings as SettingsManager,
45+
ConnectionType,
46+
)
47+
from sdbus_async.networkmanager.settings import (
48+
ConnectionProfile,
49+
ConnectionSettings,
50+
Ipv4Settings,
51+
Ipv6Settings,
52+
VpnSettings
53+
)
54+
55+
56+
async def add_vpn_connection_async(conn_id: str,
57+
dev: str,
58+
remote: str,
59+
remote_cert_tls: str,
60+
uuid,
61+
auto: bool,
62+
save: bool,
63+
ca: str,
64+
cert: str,
65+
key: str,
66+
ta: str) -> str:
67+
# Add a temporary (not yet saved) network connection profile
68+
# param Namespace args: dev, remote, remote_cert_tls, ca_path, cert_path, key_path, ta_path
69+
# return: dbus connection path of the created connection profile
70+
71+
info = logging.getLogger().info
72+
73+
# If we add many connections passing the same id, things get messy. Check:
74+
if await SettingsManager().get_connections_by_id(conn_id):
75+
print(f'Connection "{conn_id}" exists, remove it first')
76+
print(f'Run: nmcli connection delete "{conn_id}"')
77+
return ""
78+
79+
profile = ConnectionProfile(
80+
connection=ConnectionSettings(
81+
connection_id=conn_id,
82+
uuid=str(uuid),
83+
connection_type=ConnectionType.VPN.value,
84+
autoconnect=bool(auto),
85+
),
86+
ipv4=Ipv4Settings(method="auto"),
87+
ipv6=Ipv6Settings(method="auto"),
88+
vpn=VpnSettings(data={
89+
'ca': ca,
90+
'cert': cert,
91+
'cert-pass-flags': '0',
92+
'connection-type': 'tls',
93+
'dev': dev,
94+
'key': key,
95+
'remote': remote,
96+
'remote-cert-tls': remote_cert_tls,
97+
'ta': ta,
98+
'ta-dir': '1'
99+
}, service_type='org.freedesktop.NetworkManager.openvpn')
100+
)
101+
102+
s = SettingsManager()
103+
save = bool(save)
104+
addconnection = s.add_connection if save else s.add_connection_unsaved
105+
connection_settings_dbus_path = await addconnection(profile.to_dbus())
106+
created = "created and saved" if save else "created"
107+
info(f"New unsaved connection profile {created}, show it with:")
108+
info(f'nmcli connection show "{conn_id}"|grep -v -e -- -e default')
109+
info("Settings used:")
110+
info(functools.partial(pformat, sort_dicts=False)(profile.to_settings_dict()))
111+
return connection_settings_dbus_path
112+
113+
114+
if __name__ == "__main__":
115+
logging.basicConfig(format="%(message)s", level=logging.INFO)
116+
p = ArgumentParser(description="Optional arguments have example values:")
117+
conn_id = "MyConnectionExample"
118+
p.add_argument("-c", dest="conn_id", default=conn_id, help="Connection Id")
119+
p.add_argument("-u", dest="uuid", default=uuid4(), help="Connection UUID")
120+
p.add_argument("--dev", dest="dev", default="tun", help="VPN Dev")
121+
p.add_argument("--remote", dest="remote", default="example.com:443:tcp", help="VPN Remote")
122+
p.add_argument("--remote-cert-tls", dest="remote_cert_tls", default="server", help="VPN Remote cert tls")
123+
p.add_argument("--ca", dest="ca", required=True, help="VPN CA file path")
124+
p.add_argument("--cert", dest="cert", required=True, help="VPN cert file path")
125+
p.add_argument("--key", dest="key", required=True, help="VPN key file path")
126+
p.add_argument("--ta", dest="ta", required=True, help="VPN TA file path")
127+
p.add_argument("-a", dest="auto", action="store_true", help="autoconnect")
128+
p.add_argument("--save", dest="save", action="store_true", help="Save")
129+
args = p.parse_args()
130+
sdbus.set_default_bus(sdbus.sd_bus_open_system())
131+
if connection_dpath := asyncio.run(add_vpn_connection_async(**vars(args))):
132+
print(f"Path of the new connection: {connection_dpath}")
133+
print(f"UUID of the new connection: {args.uuid}")
134+
else:
135+
print("Error: No new connection created.")

0 commit comments

Comments
 (0)