1/*
2 SPDX-FileCopyrightText: 2019 Jan Grulich <jgrulich@redhat.com>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include "wireguardsetting.h"
8#include "wireguardsetting_p.h"
9
10#include <QDebug>
11
12#if !NM_CHECK_VERSION(1, 16, 0)
13#define NM_SETTING_WIREGUARD_SETTING_NAME "wireguard"
14
15#define NM_SETTING_WIREGUARD_FWMARK "fwmark"
16#define NM_SETTING_WIREGUARD_LISTEN_PORT "listen-port"
17#define NM_SETTING_WIREGUARD_PRIVATE_KEY "private-key"
18#define NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS "private-key-flags"
19#define NM_SETTING_WIREGUARD_PEERS "peers"
20#define NM_SETTING_WIREGUARD_MTU "mtu"
21#define NM_SETTING_WIREGUARD_PEER_ROUTES "peer-routes"
22
23#define NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY "preshared-key"
24#define NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS "preshared-key-flags"
25#define NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY "public-key"
26#endif
27
28NetworkManager::WireGuardSettingPrivate::WireGuardSettingPrivate()
29 : name(NM_SETTING_WIREGUARD_SETTING_NAME)
30 , fwmark(0)
31 , listenPort(0)
32 , mtu(0)
33 , peerRoutes(true)
34 , privateKeyFlags(NetworkManager::Setting::None)
35{
36}
37
38NetworkManager::WireGuardSetting::WireGuardSetting()
39 : Setting(Setting::WireGuard)
40 , d_ptr(new WireGuardSettingPrivate())
41{
42}
43
44NetworkManager::WireGuardSetting::WireGuardSetting(const Ptr &other)
45 : Setting(other)
46 , d_ptr(new WireGuardSettingPrivate())
47{
48 setFwmark(other->fwmark());
49 setListenPort(other->listenPort());
50 setMtu(other->mtu());
51 setPeerRoutes(other->peerRoutes());
52 setPeers(other->peers());
53 setPrivateKey(other->privateKey());
54 setPrivateKeyFlags(other->privateKeyFlags());
55}
56
57NetworkManager::WireGuardSetting::~WireGuardSetting()
58{
59 delete d_ptr;
60}
61
62QString NetworkManager::WireGuardSetting::name() const
63{
64 Q_D(const WireGuardSetting);
65
66 return d->name;
67}
68
69quint32 NetworkManager::WireGuardSetting::fwmark() const
70{
71 Q_D(const WireGuardSetting);
72
73 return d->fwmark;
74}
75
76void NetworkManager::WireGuardSetting::setFwmark(quint32 fwmark)
77{
78 Q_D(WireGuardSetting);
79
80 d->fwmark = fwmark;
81}
82
83quint32 NetworkManager::WireGuardSetting::listenPort() const
84{
85 Q_D(const WireGuardSetting);
86
87 return d->listenPort;
88}
89
90void NetworkManager::WireGuardSetting::setListenPort(quint32 port)
91{
92 Q_D(WireGuardSetting);
93
94 d->listenPort = port;
95}
96
97quint32 NetworkManager::WireGuardSetting::mtu() const
98{
99 Q_D(const WireGuardSetting);
100
101 return d->mtu;
102}
103
104void NetworkManager::WireGuardSetting::setMtu(quint32 mtu)
105{
106 Q_D(WireGuardSetting);
107
108 d->mtu = mtu;
109}
110
111bool NetworkManager::WireGuardSetting::peerRoutes() const
112{
113 Q_D(const WireGuardSetting);
114
115 return d->peerRoutes;
116}
117
118void NetworkManager::WireGuardSetting::setPeerRoutes(bool peerRoutes)
119{
120 Q_D(WireGuardSetting);
121
122 d->peerRoutes = peerRoutes;
123}
124
125NMVariantMapList NetworkManager::WireGuardSetting::peers() const
126{
127 Q_D(const WireGuardSetting);
128
129 return d->peers;
130}
131
132void NetworkManager::WireGuardSetting::setPeers(const NMVariantMapList &peers)
133{
134 Q_D(WireGuardSetting);
135
136 d->peers = peers;
137}
138
139QString NetworkManager::WireGuardSetting::privateKey() const
140{
141 Q_D(const WireGuardSetting);
142
143 return d->privateKey;
144}
145
146void NetworkManager::WireGuardSetting::setPrivateKey(const QString &key)
147{
148 Q_D(WireGuardSetting);
149
150 d->privateKey = key;
151}
152
153NetworkManager::Setting::SecretFlags NetworkManager::WireGuardSetting::privateKeyFlags() const
154{
155 Q_D(const WireGuardSetting);
156
157 return d->privateKeyFlags;
158}
159
160void NetworkManager::WireGuardSetting::setPrivateKeyFlags(NetworkManager::Setting::SecretFlags flags)
161{
162 Q_D(WireGuardSetting);
163
164 d->privateKeyFlags = flags;
165}
166
167void NetworkManager::WireGuardSetting::secretsFromMap(const QVariantMap &secrets)
168{
169 if (secrets.contains(key: QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY))) {
170 setPrivateKey(secrets.value(key: QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY)).toString());
171 }
172
173 if (secrets.contains(key: QLatin1String(NM_SETTING_WIREGUARD_PEERS))) {
174 NMVariantMapList listOfPeers = qdbus_cast<NMVariantMapList>(v: secrets.value(key: QLatin1String(NM_SETTING_WIREGUARD_PEERS)));
175 NMVariantMapList origPeers = peers();
176
177 for (const QVariantMap &peer : listOfPeers) {
178 if (peer.contains(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY))) {
179 QString presharedKey = peer.value(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)).toString();
180 QString publicKey = peer.value(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)).toString();
181 for (int i = 0; i < origPeers.size(); i++) {
182 if (origPeers[i][QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)].toString() == publicKey) {
183 origPeers[i].insert(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY), value: presharedKey);
184 }
185 }
186 }
187 }
188 setPeers(origPeers);
189 }
190}
191
192QVariantMap NetworkManager::WireGuardSetting::secretsToMap() const
193{
194 QVariantMap secrets;
195
196 if (!privateKey().isEmpty()) {
197 secrets.insert(key: QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY), value: privateKey());
198 }
199
200 NMVariantMapList peersSecrets;
201
202 for (const QVariantMap &map : peers()) {
203 if (map.contains(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)) && map.contains(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY))) {
204 QVariantMap newMap;
205 newMap.insert(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY), value: map.value(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)));
206 newMap.insert(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY), value: map.value(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)));
207
208 peersSecrets << newMap;
209 }
210 }
211
212 if (!peersSecrets.isEmpty()) {
213 secrets.insert(key: QLatin1String(NM_SETTING_WIREGUARD_PEERS), value: QVariant::fromValue(value: peersSecrets));
214 }
215
216 return secrets;
217}
218
219void NetworkManager::WireGuardSetting::secretsFromStringMap(const NMStringMap &map)
220{
221 QVariantMap secretsMap;
222 NMVariantMapList peers;
223
224 auto it = map.constBegin();
225 while (it != map.constEnd()) {
226 if (it.key() == QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY)) {
227 secretsMap.insert(key: it.key(), value: it.value());
228 }
229
230 if (it.key().startsWith(s: QLatin1String(NM_SETTING_WIREGUARD_PEERS)) && it.key().endsWith(s: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY))) {
231 QStringList peerStrList = it.key().split(sep: QLatin1Char('.'));
232
233 QVariantMap peer;
234 peer.insert(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY), value: peerStrList.at(i: 1));
235 peer.insert(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY), value: it.value());
236
237 peers << peer;
238 }
239 ++it;
240 }
241
242 if (!peers.isEmpty()) {
243 secretsMap.insert(key: QLatin1String(NM_SETTING_WIREGUARD_PEERS), value: QVariant::fromValue(value: peers));
244 }
245
246 secretsFromMap(secrets: secretsMap);
247}
248
249NMStringMap NetworkManager::WireGuardSetting::secretsToStringMap() const
250{
251 NMStringMap ret;
252 QVariantMap secretsMap = secretsToMap();
253
254 auto it = secretsMap.constBegin();
255 while (it != secretsMap.constEnd()) {
256 if (it.key() == QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY)) {
257 ret.insert(key: it.key(), value: it.value().toString());
258 }
259
260 if (it.key() == QLatin1String(NM_SETTING_WIREGUARD_PEERS)) {
261 NMVariantMapList listOfPeers = qdbus_cast<NMVariantMapList>(v: it.value());
262
263 for (const QVariantMap &map : listOfPeers) {
264 const QString str = QStringLiteral("%1.%2.%3")
265 .arg(a: QLatin1String(NM_SETTING_WIREGUARD_PEERS))
266 .arg(a: map.value(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)).toString())
267 .arg(a: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY));
268 ret.insert(key: str, value: map.value(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)).toString());
269 }
270 }
271 ++it;
272 }
273
274 return ret;
275}
276
277QStringList NetworkManager::WireGuardSetting::needSecrets(bool requestNew) const
278{
279 QStringList secrets;
280
281 if (!privateKeyFlags().testFlag(flag: Setting::NotRequired)) {
282 if (privateKey().isEmpty() || requestNew) {
283 secrets << QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY);
284 }
285 }
286
287 for (const QVariantMap &map : peers()) {
288 const QString presharedKey = map.value(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)).toString();
289 SecretFlags preSharedKeyFlags = (SecretFlags)map.value(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS)).toInt();
290
291 if (!presharedKey.isEmpty()) {
292 continue;
293 }
294
295 if (preSharedKeyFlags.testFlag(flag: Setting::NotRequired)) {
296 continue;
297 }
298
299 const QString str = QStringLiteral("%1.%2.%3")
300 .arg(a: QLatin1String(NM_SETTING_WIREGUARD_PEERS))
301 .arg(a: map.value(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)).toString())
302 .arg(a: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY));
303 secrets << str;
304 }
305
306 return secrets;
307}
308
309void NetworkManager::WireGuardSetting::fromMap(const QVariantMap &setting)
310{
311 if (setting.contains(key: QLatin1String(NM_SETTING_WIREGUARD_FWMARK))) {
312 setFwmark(setting.value(key: QLatin1String(NM_SETTING_WIREGUARD_FWMARK)).toInt());
313 }
314
315 if (setting.contains(key: QLatin1String(NM_SETTING_WIREGUARD_LISTEN_PORT))) {
316 setListenPort(setting.value(key: QLatin1String(NM_SETTING_WIREGUARD_LISTEN_PORT)).toInt());
317 }
318
319 if (setting.contains(key: QLatin1String(NM_SETTING_WIREGUARD_MTU))) {
320 setMtu(setting.value(key: QLatin1String(NM_SETTING_WIREGUARD_MTU)).toInt());
321 }
322
323 if (setting.contains(key: QLatin1String(NM_SETTING_WIREGUARD_PEER_ROUTES))) {
324 setPeerRoutes(setting.value(key: QLatin1String(NM_SETTING_WIREGUARD_PEER_ROUTES)).toBool());
325 }
326
327 if (setting.contains(key: QLatin1String(NM_SETTING_WIREGUARD_PEERS))) {
328 setPeers(qdbus_cast<NMVariantMapList>(v: setting.value(key: QLatin1String(NM_SETTING_WIREGUARD_PEERS))));
329 }
330
331 if (setting.contains(key: QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY))) {
332 setPrivateKey(setting.value(key: QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY)).toString());
333 }
334
335 if (setting.contains(key: QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS))) {
336 setPrivateKeyFlags((SecretFlags)setting.value(key: QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS)).toInt());
337 }
338}
339
340QVariantMap NetworkManager::WireGuardSetting::toMap() const
341{
342 QVariantMap setting;
343
344 setting.insert(key: QLatin1String(NM_SETTING_WIREGUARD_FWMARK), value: fwmark());
345 setting.insert(key: QLatin1String(NM_SETTING_WIREGUARD_LISTEN_PORT), value: listenPort());
346 setting.insert(key: QLatin1String(NM_SETTING_WIREGUARD_MTU), value: mtu());
347 setting.insert(key: QLatin1String(NM_SETTING_WIREGUARD_PEER_ROUTES), value: peerRoutes());
348
349 if (!peers().isEmpty()) {
350 // FIXME we seem to have SecretFlags as an int, but NM expects an uint, while this is not
351 // problem for rest of *-flags properties, it's problem for "preshared-key" which NM handless
352 // as GVariant and asks for "u" when getting it's value
353 NMVariantMapList fixedPeers = peers();
354 for (QVariantMap &map : fixedPeers) {
355 if (map.contains(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS))) {
356 map.insert(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS),
357 value: map.value(key: QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS)).toUInt());
358 }
359 }
360
361 setting.insert(key: QLatin1String(NM_SETTING_WIREGUARD_PEERS), value: QVariant::fromValue(value: fixedPeers));
362 }
363
364 if (!privateKey().isEmpty()) {
365 setting.insert(key: QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY), value: privateKey());
366 }
367 setting.insert(key: QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS), value: (int)privateKeyFlags());
368
369 return setting;
370}
371
372QDebug NetworkManager::operator<<(QDebug dbg, const NetworkManager::WireGuardSetting &setting)
373{
374 dbg.nospace() << "type: " << setting.typeAsString(type: setting.type()) << '\n';
375 dbg.nospace() << "initialized: " << !setting.isNull() << '\n';
376
377 dbg.nospace() << NM_SETTING_WIREGUARD_FWMARK << ": " << setting.fwmark() << '\n';
378 dbg.nospace() << NM_SETTING_WIREGUARD_LISTEN_PORT << ": " << setting.listenPort() << '\n';
379 dbg.nospace() << NM_SETTING_WIREGUARD_MTU << ": " << setting.mtu() << '\n';
380 dbg.nospace() << NM_SETTING_WIREGUARD_PEER_ROUTES << ": " << setting.peerRoutes() << '\n';
381 dbg.nospace() << NM_SETTING_WIREGUARD_PEERS << ": " << setting.peers() << '\n';
382 dbg.nospace() << NM_SETTING_WIREGUARD_PRIVATE_KEY << ": " << setting.privateKey() << '\n';
383 dbg.nospace() << NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS << ": " << setting.privateKeyFlags() << '\n';
384
385 return dbg.maybeSpace();
386}
387

source code of networkmanager-qt/src/settings/wireguardsetting.cpp