File indexing completed on 2024-04-21 04:00:08

0001 /*
0002     SPDX-FileCopyrightText: 2019 Jan Grulich <jgrulich@redhat.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "wireguardsetting.h"
0008 #include "wireguardsetting_p.h"
0009 
0010 #include <QDebug>
0011 
0012 #if !NM_CHECK_VERSION(1, 16, 0)
0013 #define NM_SETTING_WIREGUARD_SETTING_NAME "wireguard"
0014 
0015 #define NM_SETTING_WIREGUARD_FWMARK "fwmark"
0016 #define NM_SETTING_WIREGUARD_LISTEN_PORT "listen-port"
0017 #define NM_SETTING_WIREGUARD_PRIVATE_KEY "private-key"
0018 #define NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS "private-key-flags"
0019 #define NM_SETTING_WIREGUARD_PEERS "peers"
0020 #define NM_SETTING_WIREGUARD_MTU "mtu"
0021 #define NM_SETTING_WIREGUARD_PEER_ROUTES "peer-routes"
0022 
0023 #define NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY "preshared-key"
0024 #define NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS "preshared-key-flags"
0025 #define NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY "public-key"
0026 #endif
0027 
0028 NetworkManager::WireGuardSettingPrivate::WireGuardSettingPrivate()
0029     : name(NM_SETTING_WIREGUARD_SETTING_NAME)
0030     , fwmark(0)
0031     , listenPort(0)
0032     , mtu(0)
0033     , peerRoutes(true)
0034     , privateKeyFlags(NetworkManager::Setting::None)
0035 {
0036 }
0037 
0038 NetworkManager::WireGuardSetting::WireGuardSetting()
0039     : Setting(Setting::WireGuard)
0040     , d_ptr(new WireGuardSettingPrivate())
0041 {
0042 }
0043 
0044 NetworkManager::WireGuardSetting::WireGuardSetting(const Ptr &other)
0045     : Setting(other)
0046     , d_ptr(new WireGuardSettingPrivate())
0047 {
0048     setFwmark(other->fwmark());
0049     setListenPort(other->listenPort());
0050     setMtu(other->mtu());
0051     setPeerRoutes(other->peerRoutes());
0052     setPeers(other->peers());
0053     setPrivateKey(other->privateKey());
0054     setPrivateKeyFlags(other->privateKeyFlags());
0055 }
0056 
0057 NetworkManager::WireGuardSetting::~WireGuardSetting()
0058 {
0059     delete d_ptr;
0060 }
0061 
0062 QString NetworkManager::WireGuardSetting::name() const
0063 {
0064     Q_D(const WireGuardSetting);
0065 
0066     return d->name;
0067 }
0068 
0069 quint32 NetworkManager::WireGuardSetting::fwmark() const
0070 {
0071     Q_D(const WireGuardSetting);
0072 
0073     return d->fwmark;
0074 }
0075 
0076 void NetworkManager::WireGuardSetting::setFwmark(quint32 fwmark)
0077 {
0078     Q_D(WireGuardSetting);
0079 
0080     d->fwmark = fwmark;
0081 }
0082 
0083 quint32 NetworkManager::WireGuardSetting::listenPort() const
0084 {
0085     Q_D(const WireGuardSetting);
0086 
0087     return d->listenPort;
0088 }
0089 
0090 void NetworkManager::WireGuardSetting::setListenPort(quint32 port)
0091 {
0092     Q_D(WireGuardSetting);
0093 
0094     d->listenPort = port;
0095 }
0096 
0097 quint32 NetworkManager::WireGuardSetting::mtu() const
0098 {
0099     Q_D(const WireGuardSetting);
0100 
0101     return d->mtu;
0102 }
0103 
0104 void NetworkManager::WireGuardSetting::setMtu(quint32 mtu)
0105 {
0106     Q_D(WireGuardSetting);
0107 
0108     d->mtu = mtu;
0109 }
0110 
0111 bool NetworkManager::WireGuardSetting::peerRoutes() const
0112 {
0113     Q_D(const WireGuardSetting);
0114 
0115     return d->peerRoutes;
0116 }
0117 
0118 void NetworkManager::WireGuardSetting::setPeerRoutes(bool peerRoutes)
0119 {
0120     Q_D(WireGuardSetting);
0121 
0122     d->peerRoutes = peerRoutes;
0123 }
0124 
0125 NMVariantMapList NetworkManager::WireGuardSetting::peers() const
0126 {
0127     Q_D(const WireGuardSetting);
0128 
0129     return d->peers;
0130 }
0131 
0132 void NetworkManager::WireGuardSetting::setPeers(const NMVariantMapList &peers)
0133 {
0134     Q_D(WireGuardSetting);
0135 
0136     d->peers = peers;
0137 }
0138 
0139 QString NetworkManager::WireGuardSetting::privateKey() const
0140 {
0141     Q_D(const WireGuardSetting);
0142 
0143     return d->privateKey;
0144 }
0145 
0146 void NetworkManager::WireGuardSetting::setPrivateKey(const QString &key)
0147 {
0148     Q_D(WireGuardSetting);
0149 
0150     d->privateKey = key;
0151 }
0152 
0153 NetworkManager::Setting::SecretFlags NetworkManager::WireGuardSetting::privateKeyFlags() const
0154 {
0155     Q_D(const WireGuardSetting);
0156 
0157     return d->privateKeyFlags;
0158 }
0159 
0160 void NetworkManager::WireGuardSetting::setPrivateKeyFlags(NetworkManager::Setting::SecretFlags flags)
0161 {
0162     Q_D(WireGuardSetting);
0163 
0164     d->privateKeyFlags = flags;
0165 }
0166 
0167 void NetworkManager::WireGuardSetting::secretsFromMap(const QVariantMap &secrets)
0168 {
0169     if (secrets.contains(QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY))) {
0170         setPrivateKey(secrets.value(QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY)).toString());
0171     }
0172 
0173     if (secrets.contains(QLatin1String(NM_SETTING_WIREGUARD_PEERS))) {
0174         NMVariantMapList listOfPeers = qdbus_cast<NMVariantMapList>(secrets.value(QLatin1String(NM_SETTING_WIREGUARD_PEERS)));
0175         NMVariantMapList origPeers = peers();
0176 
0177         for (const QVariantMap &peer : listOfPeers) {
0178             if (peer.contains(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY))) {
0179                 QString presharedKey = peer.value(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)).toString();
0180                 QString publicKey = peer.value(QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)).toString();
0181                 for (int i = 0; i < origPeers.size(); i++) {
0182                     if (origPeers[i][QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)].toString() == publicKey) {
0183                         origPeers[i].insert(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY), presharedKey);
0184                     }
0185                 }
0186             }
0187         }
0188         setPeers(origPeers);
0189     }
0190 }
0191 
0192 QVariantMap NetworkManager::WireGuardSetting::secretsToMap() const
0193 {
0194     QVariantMap secrets;
0195 
0196     if (!privateKey().isEmpty()) {
0197         secrets.insert(QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY), privateKey());
0198     }
0199 
0200     NMVariantMapList peersSecrets;
0201 
0202     for (const QVariantMap &map : peers()) {
0203         if (map.contains(QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)) && map.contains(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY))) {
0204             QVariantMap newMap;
0205             newMap.insert(QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY), map.value(QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)));
0206             newMap.insert(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY), map.value(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)));
0207 
0208             peersSecrets << newMap;
0209         }
0210     }
0211 
0212     if (!peersSecrets.isEmpty()) {
0213         secrets.insert(QLatin1String(NM_SETTING_WIREGUARD_PEERS), QVariant::fromValue(peersSecrets));
0214     }
0215 
0216     return secrets;
0217 }
0218 
0219 void NetworkManager::WireGuardSetting::secretsFromStringMap(const NMStringMap &map)
0220 {
0221     QVariantMap secretsMap;
0222     NMVariantMapList peers;
0223 
0224     auto it = map.constBegin();
0225     while (it != map.constEnd()) {
0226         if (it.key() == QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY)) {
0227             secretsMap.insert(it.key(), it.value());
0228         }
0229 
0230         if (it.key().startsWith(QLatin1String(NM_SETTING_WIREGUARD_PEERS)) && it.key().endsWith(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY))) {
0231             QStringList peerStrList = it.key().split(QLatin1Char('.'));
0232 
0233             QVariantMap peer;
0234             peer.insert(QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY), peerStrList.at(1));
0235             peer.insert(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY), it.value());
0236 
0237             peers << peer;
0238         }
0239         ++it;
0240     }
0241 
0242     if (!peers.isEmpty()) {
0243         secretsMap.insert(QLatin1String(NM_SETTING_WIREGUARD_PEERS), QVariant::fromValue(peers));
0244     }
0245 
0246     secretsFromMap(secretsMap);
0247 }
0248 
0249 NMStringMap NetworkManager::WireGuardSetting::secretsToStringMap() const
0250 {
0251     NMStringMap ret;
0252     QVariantMap secretsMap = secretsToMap();
0253 
0254     auto it = secretsMap.constBegin();
0255     while (it != secretsMap.constEnd()) {
0256         if (it.key() == QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY)) {
0257             ret.insert(it.key(), it.value().toString());
0258         }
0259 
0260         if (it.key() == QLatin1String(NM_SETTING_WIREGUARD_PEERS)) {
0261             NMVariantMapList listOfPeers = qdbus_cast<NMVariantMapList>(it.value());
0262 
0263             for (const QVariantMap &map : listOfPeers) {
0264                 const QString str = QStringLiteral("%1.%2.%3")
0265                                         .arg(QLatin1String(NM_SETTING_WIREGUARD_PEERS))
0266                                         .arg(map.value(QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)).toString())
0267                                         .arg(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY));
0268                 ret.insert(str, map.value(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)).toString());
0269             }
0270         }
0271         ++it;
0272     }
0273 
0274     return ret;
0275 }
0276 
0277 QStringList NetworkManager::WireGuardSetting::needSecrets(bool requestNew) const
0278 {
0279     QStringList secrets;
0280 
0281     if (!privateKeyFlags().testFlag(Setting::NotRequired)) {
0282         if (privateKey().isEmpty() || requestNew) {
0283             secrets << QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY);
0284         }
0285     }
0286 
0287     for (const QVariantMap &map : peers()) {
0288         const QString presharedKey = map.value(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY)).toString();
0289         SecretFlags preSharedKeyFlags = (SecretFlags)map.value(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS)).toInt();
0290 
0291         if (!presharedKey.isEmpty()) {
0292             continue;
0293         }
0294 
0295         if (preSharedKeyFlags.testFlag(Setting::NotRequired)) {
0296             continue;
0297         }
0298 
0299         const QString str = QStringLiteral("%1.%2.%3")
0300                                 .arg(QLatin1String(NM_SETTING_WIREGUARD_PEERS))
0301                                 .arg(map.value(QLatin1String(NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY)).toString())
0302                                 .arg(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY));
0303         secrets << str;
0304     }
0305 
0306     return secrets;
0307 }
0308 
0309 void NetworkManager::WireGuardSetting::fromMap(const QVariantMap &setting)
0310 {
0311     if (setting.contains(QLatin1String(NM_SETTING_WIREGUARD_FWMARK))) {
0312         setFwmark(setting.value(QLatin1String(NM_SETTING_WIREGUARD_FWMARK)).toInt());
0313     }
0314 
0315     if (setting.contains(QLatin1String(NM_SETTING_WIREGUARD_LISTEN_PORT))) {
0316         setListenPort(setting.value(QLatin1String(NM_SETTING_WIREGUARD_LISTEN_PORT)).toInt());
0317     }
0318 
0319     if (setting.contains(QLatin1String(NM_SETTING_WIREGUARD_MTU))) {
0320         setMtu(setting.value(QLatin1String(NM_SETTING_WIREGUARD_MTU)).toInt());
0321     }
0322 
0323     if (setting.contains(QLatin1String(NM_SETTING_WIREGUARD_PEER_ROUTES))) {
0324         setPeerRoutes(setting.value(QLatin1String(NM_SETTING_WIREGUARD_PEER_ROUTES)).toBool());
0325     }
0326 
0327     if (setting.contains(QLatin1String(NM_SETTING_WIREGUARD_PEERS))) {
0328         setPeers(qdbus_cast<NMVariantMapList>(setting.value(QLatin1String(NM_SETTING_WIREGUARD_PEERS))));
0329     }
0330 
0331     if (setting.contains(QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY))) {
0332         setPrivateKey(setting.value(QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY)).toString());
0333     }
0334 
0335     if (setting.contains(QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS))) {
0336         setPrivateKeyFlags((SecretFlags)setting.value(QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS)).toInt());
0337     }
0338 }
0339 
0340 QVariantMap NetworkManager::WireGuardSetting::toMap() const
0341 {
0342     QVariantMap setting;
0343 
0344     setting.insert(QLatin1String(NM_SETTING_WIREGUARD_FWMARK), fwmark());
0345     setting.insert(QLatin1String(NM_SETTING_WIREGUARD_LISTEN_PORT), listenPort());
0346     setting.insert(QLatin1String(NM_SETTING_WIREGUARD_MTU), mtu());
0347     setting.insert(QLatin1String(NM_SETTING_WIREGUARD_PEER_ROUTES), peerRoutes());
0348 
0349     if (!peers().isEmpty()) {
0350         // FIXME we seem to have SecretFlags as an int, but NM expects an uint, while this is not
0351         // problem for rest of *-flags properties, it's problem for "preshared-key" which NM handless
0352         // as GVariant and asks for "u" when getting it's value
0353         NMVariantMapList fixedPeers = peers();
0354         for (QVariantMap &map : fixedPeers) {
0355             if (map.contains(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS))) {
0356                 map.insert(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS),
0357                            map.value(QLatin1String(NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS)).toUInt());
0358             }
0359         }
0360 
0361         setting.insert(QLatin1String(NM_SETTING_WIREGUARD_PEERS), QVariant::fromValue(fixedPeers));
0362     }
0363 
0364     if (!privateKey().isEmpty()) {
0365         setting.insert(QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY), privateKey());
0366     }
0367     setting.insert(QLatin1String(NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS), (int)privateKeyFlags());
0368 
0369     return setting;
0370 }
0371 
0372 QDebug NetworkManager::operator<<(QDebug dbg, const NetworkManager::WireGuardSetting &setting)
0373 {
0374     dbg.nospace() << "type: " << setting.typeAsString(setting.type()) << '\n';
0375     dbg.nospace() << "initialized: " << !setting.isNull() << '\n';
0376 
0377     dbg.nospace() << NM_SETTING_WIREGUARD_FWMARK << ": " << setting.fwmark() << '\n';
0378     dbg.nospace() << NM_SETTING_WIREGUARD_LISTEN_PORT << ": " << setting.listenPort() << '\n';
0379     dbg.nospace() << NM_SETTING_WIREGUARD_MTU << ": " << setting.mtu() << '\n';
0380     dbg.nospace() << NM_SETTING_WIREGUARD_PEER_ROUTES << ": " << setting.peerRoutes() << '\n';
0381     dbg.nospace() << NM_SETTING_WIREGUARD_PEERS << ": " << setting.peers() << '\n';
0382     dbg.nospace() << NM_SETTING_WIREGUARD_PRIVATE_KEY << ": " << setting.privateKey() << '\n';
0383     dbg.nospace() << NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS << ": " << setting.privateKeyFlags() << '\n';
0384 
0385     return dbg.maybeSpace();
0386 }