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 | |
28 | NetworkManager::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 | |
38 | NetworkManager::WireGuardSetting::WireGuardSetting() |
39 | : Setting(Setting::WireGuard) |
40 | , d_ptr(new WireGuardSettingPrivate()) |
41 | { |
42 | } |
43 | |
44 | NetworkManager::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 | |
57 | NetworkManager::WireGuardSetting::~WireGuardSetting() |
58 | { |
59 | delete d_ptr; |
60 | } |
61 | |
62 | QString NetworkManager::WireGuardSetting::name() const |
63 | { |
64 | Q_D(const WireGuardSetting); |
65 | |
66 | return d->name; |
67 | } |
68 | |
69 | quint32 NetworkManager::WireGuardSetting::fwmark() const |
70 | { |
71 | Q_D(const WireGuardSetting); |
72 | |
73 | return d->fwmark; |
74 | } |
75 | |
76 | void NetworkManager::WireGuardSetting::setFwmark(quint32 fwmark) |
77 | { |
78 | Q_D(WireGuardSetting); |
79 | |
80 | d->fwmark = fwmark; |
81 | } |
82 | |
83 | quint32 NetworkManager::WireGuardSetting::listenPort() const |
84 | { |
85 | Q_D(const WireGuardSetting); |
86 | |
87 | return d->listenPort; |
88 | } |
89 | |
90 | void NetworkManager::WireGuardSetting::setListenPort(quint32 port) |
91 | { |
92 | Q_D(WireGuardSetting); |
93 | |
94 | d->listenPort = port; |
95 | } |
96 | |
97 | quint32 NetworkManager::WireGuardSetting::mtu() const |
98 | { |
99 | Q_D(const WireGuardSetting); |
100 | |
101 | return d->mtu; |
102 | } |
103 | |
104 | void NetworkManager::WireGuardSetting::setMtu(quint32 mtu) |
105 | { |
106 | Q_D(WireGuardSetting); |
107 | |
108 | d->mtu = mtu; |
109 | } |
110 | |
111 | bool NetworkManager::WireGuardSetting::peerRoutes() const |
112 | { |
113 | Q_D(const WireGuardSetting); |
114 | |
115 | return d->peerRoutes; |
116 | } |
117 | |
118 | void NetworkManager::WireGuardSetting::setPeerRoutes(bool peerRoutes) |
119 | { |
120 | Q_D(WireGuardSetting); |
121 | |
122 | d->peerRoutes = peerRoutes; |
123 | } |
124 | |
125 | NMVariantMapList NetworkManager::WireGuardSetting::peers() const |
126 | { |
127 | Q_D(const WireGuardSetting); |
128 | |
129 | return d->peers; |
130 | } |
131 | |
132 | void NetworkManager::WireGuardSetting::setPeers(const NMVariantMapList &peers) |
133 | { |
134 | Q_D(WireGuardSetting); |
135 | |
136 | d->peers = peers; |
137 | } |
138 | |
139 | QString NetworkManager::WireGuardSetting::privateKey() const |
140 | { |
141 | Q_D(const WireGuardSetting); |
142 | |
143 | return d->privateKey; |
144 | } |
145 | |
146 | void NetworkManager::WireGuardSetting::setPrivateKey(const QString &key) |
147 | { |
148 | Q_D(WireGuardSetting); |
149 | |
150 | d->privateKey = key; |
151 | } |
152 | |
153 | NetworkManager::Setting::SecretFlags NetworkManager::WireGuardSetting::privateKeyFlags() const |
154 | { |
155 | Q_D(const WireGuardSetting); |
156 | |
157 | return d->privateKeyFlags; |
158 | } |
159 | |
160 | void NetworkManager::WireGuardSetting::setPrivateKeyFlags(NetworkManager::Setting::SecretFlags flags) |
161 | { |
162 | Q_D(WireGuardSetting); |
163 | |
164 | d->privateKeyFlags = flags; |
165 | } |
166 | |
167 | void 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 | |
192 | QVariantMap 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 ; |
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 | |
219 | void 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 | |
249 | NMStringMap 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 | |
277 | QStringList 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 | |
309 | void 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 | |
340 | QVariantMap 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 | |
372 | QDebug 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 | |