File indexing completed on 2024-12-08 08:02:32

0001 /*
0002     SPDX-FileCopyrightText: 2019 Bruce Anderson <banderson19com@san.rr.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 #include "wireguardinterfacewidget.h"
0007 #include "simpleiplistvalidator.h"
0008 #include "wireguardkeyvalidator.h"
0009 #include "wireguardtabwidget.h"
0010 
0011 #include <QFile>
0012 #include <QFileInfo>
0013 #include <QPointer>
0014 #include <QStandardItemModel>
0015 
0016 #include <KColorScheme>
0017 #include <KConfig>
0018 #include <KConfigGroup>
0019 #include <NetworkManagerQt/Ipv4Setting>
0020 #include <NetworkManagerQt/Ipv6Setting>
0021 #include <NetworkManagerQt/Utils>
0022 
0023 // Tags used in a WireGuard .conf file - Used for importing
0024 #define PNM_WG_CONF_TAG_INTERFACE "[Interface]"
0025 #define PNM_WG_CONF_TAG_ADDRESS "Address"
0026 #define PNM_WG_CONF_TAG_LISTEN_PORT "ListenPort"
0027 #define PNM_WG_CONF_TAG_MTU "MTU"
0028 #define PNM_WG_CONF_TAG_DNS "DNS"
0029 #define PNM_WG_CONF_TAG_FWMARK "FwMark"
0030 #define PNM_WG_CONF_TAG_PRIVATE_KEY "PrivateKey"
0031 #define PNM_WG_CONF_TAG_PEER "[Peer]"
0032 #define PNM_WG_CONF_TAG_PUBLIC_KEY "PublicKey"
0033 #define PNM_WG_CONF_TAG_PRESHARED_KEY "PresharedKey"
0034 #define PNM_WG_CONF_TAG_ALLOWED_IPS "AllowedIPs"
0035 #define PNM_WG_CONF_TAG_ENDPOINT "Endpoint"
0036 #define PNM_WG_CONF_TAG_PERSISTENT_KEEPALIVE "PersistentKeepalive"
0037 #define PNM_WG_CONF_TAG_TABLE "Table"
0038 #define PNM_WG_CONF_TAG_PRE_UP "PreUp"
0039 #define PNM_WG_CONF_TAG_POST_UP "PostUp"
0040 #define PNM_WG_CONF_TAG_PRE_DOWN "PreDown"
0041 #define PNM_WG_CONF_TAG_POST_DOWN "PostDown"
0042 
0043 #define PNM_WG_KEY_PEERS "peers"
0044 #define PNM_WG_KEY_MTU "mtu"
0045 #define PNM_WG_KEY_PEER_ROUTES "peer-routes"
0046 #define PNM_WG_PEER_KEY_ALLOWED_IPS "allowed-ips"
0047 #define PNM_WG_PEER_KEY_ENDPOINT "endpoint"
0048 #define PNM_WG_PEER_KEY_PERSISTENT_KEEPALIVE "persistent-keepalive"
0049 #define PNM_WG_PEER_KEY_PRESHARED_KEY "preshared-key"
0050 #define PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS "preshared-key-flags"
0051 #define PNM_WG_PEER_KEY_PUBLIC_KEY "public-key"
0052 
0053 // Keys for the NetworkManager configuration
0054 #define PNM_SETTING_WIREGUARD_SETTING_NAME "wireguard"
0055 
0056 #define PNM_WG_KEY_FWMARK "fwmark"
0057 #define PNM_WG_KEY_LISTEN_PORT "listen-port"
0058 #define PNM_WG_KEY_PRIVATE_KEY "private-key"
0059 #define PNM_WG_KEY_PRIVATE_KEY_FLAGS "private-key-flags"
0060 
0061 class WireGuardInterfaceWidget::Private
0062 {
0063 public:
0064     ~Private();
0065 
0066     Ui_WireGuardInterfaceProp ui;
0067     NetworkManager::WireGuardSetting::Ptr setting;
0068     KSharedConfigPtr config;
0069     QPalette warningPalette;
0070     QPalette normalPalette;
0071     WireGuardKeyValidator *keyValidator;
0072     QRegularExpressionValidator *fwmarkValidator;
0073     QIntValidator *mtuValidator;
0074     QIntValidator *portValidator;
0075     bool privateKeyValid = false;
0076     bool fwmarkValid = true;
0077     bool listenPortValid = true;
0078     bool peersValid = false;
0079     NMVariantMapList peers;
0080 };
0081 
0082 WireGuardInterfaceWidget::Private::~Private()
0083 {
0084     delete keyValidator;
0085     delete fwmarkValidator;
0086     delete mtuValidator;
0087     delete portValidator;
0088 }
0089 
0090 WireGuardInterfaceWidget::WireGuardInterfaceWidget(const NetworkManager::Setting::Ptr &setting, QWidget *parent, Qt::WindowFlags f)
0091     : SettingWidget(setting, parent, f)
0092     , d(new Private)
0093 {
0094     d->ui.setupUi(this);
0095     d->setting = setting.staticCast<NetworkManager::WireGuardSetting>();
0096     d->config = KSharedConfig::openConfig();
0097     d->warningPalette = KColorScheme::createApplicationPalette(d->config);
0098     d->normalPalette = KColorScheme::createApplicationPalette(d->config);
0099     KColorScheme::adjustBackground(d->warningPalette, KColorScheme::NegativeBackground, QPalette::Base, KColorScheme::ColorSet::View, d->config);
0100 
0101     KColorScheme::adjustBackground(d->normalPalette, KColorScheme::NormalBackground, QPalette::Base, KColorScheme::ColorSet::View, d->config);
0102 
0103     connect(d->ui.privateKeyLineEdit, &PasswordField::textChanged, this, &WireGuardInterfaceWidget::checkPrivateKeyValid);
0104     connect(d->ui.privateKeyLineEdit, &PasswordField::passwordOptionChanged, this, &WireGuardInterfaceWidget::checkPrivateKeyValid);
0105     connect(d->ui.fwmarkLineEdit, &QLineEdit::textChanged, this, &WireGuardInterfaceWidget::checkFwmarkValid);
0106     connect(d->ui.listenPortLineEdit, &QLineEdit::textChanged, this, &WireGuardInterfaceWidget::checkListenPortValid);
0107     connect(d->ui.btnPeers, &QPushButton::clicked, this, &WireGuardInterfaceWidget::showPeers);
0108 
0109     d->ui.privateKeyLineEdit->setPasswordModeEnabled(true);
0110     d->ui.privateKeyLineEdit->setPasswordOptionsEnabled(true);
0111     d->ui.privateKeyLineEdit->setPasswordNotSavedEnabled(false);
0112 
0113     // This is done as a private variable rather than a local variable so it can be
0114     // used both here and to validate the private key later
0115     d->keyValidator = new WireGuardKeyValidator(this);
0116 
0117     // Create validator for listen port
0118     d->portValidator = new QIntValidator;
0119     d->portValidator->setBottom(0);
0120     d->portValidator->setTop(65535);
0121 
0122     // Create a validator for the fwmark input. Acceptable
0123     // inputs are: "off" and numbers in either decimal
0124     // or hex (with 0x prefix)
0125     d->fwmarkValidator = new QRegularExpressionValidator(QRegularExpression("(off)|([0-9]{0,10})|(0x[0-9a-fA-F]{1,8})"));
0126     d->ui.fwmarkLineEdit->setValidator(d->fwmarkValidator);
0127 
0128     // Create a validator for the MTU field.
0129     d->mtuValidator = new QIntValidator();
0130     d->mtuValidator->setBottom(0);
0131     d->ui.mtuLineEdit->setValidator(d->mtuValidator);
0132 
0133     // Default Peer Routes to true
0134     d->ui.peerRouteCheckBox->setChecked(true);
0135 
0136     // Connect for setting check
0137     watchChangedSetting();
0138 
0139     KAcceleratorManager::manage(this);
0140 
0141     if (setting && !setting->isNull()) {
0142         loadConfig(d->setting);
0143     }
0144 
0145     // Set the initial backgrounds on all the widgets
0146     checkPrivateKeyValid();
0147 }
0148 
0149 WireGuardInterfaceWidget::~WireGuardInterfaceWidget()
0150 {
0151     delete d;
0152 }
0153 
0154 void WireGuardInterfaceWidget::loadConfig(const NetworkManager::Setting::Ptr &setting)
0155 {
0156     NetworkManager::WireGuardSetting::Ptr wireGuardSetting = setting.staticCast<NetworkManager::WireGuardSetting>();
0157     d->ui.privateKeyLineEdit->setText(wireGuardSetting->privateKey());
0158 
0159     if (wireGuardSetting->listenPort() != 0)
0160         d->ui.listenPortLineEdit->setText(QString::number(wireGuardSetting->listenPort()));
0161     else
0162         d->ui.listenPortLineEdit->clear();
0163 
0164     if (wireGuardSetting->fwmark() != 0)
0165         d->ui.fwmarkLineEdit->setText(QString::number(wireGuardSetting->fwmark()));
0166     else
0167         d->ui.fwmarkLineEdit->clear();
0168 
0169     if (wireGuardSetting->mtu() != 0)
0170         d->ui.mtuLineEdit->setText(QString::number(wireGuardSetting->mtu()));
0171     else
0172         d->ui.mtuLineEdit->clear();
0173 
0174     d->ui.peerRouteCheckBox->setChecked(wireGuardSetting->peerRoutes());
0175 
0176     NetworkManager::Setting::SecretFlags type = wireGuardSetting->privateKeyFlags();
0177     switch (type) {
0178     case NetworkManager::Setting::AgentOwned:
0179         d->ui.privateKeyLineEdit->setPasswordOption(PasswordField::StoreForUser);
0180         break;
0181     case NetworkManager::Setting::None:
0182         d->ui.privateKeyLineEdit->setPasswordOption(PasswordField::StoreForAllUsers);
0183         break;
0184     // Not saved is not a valid option for the private key so set it to StoreForUser instead
0185     case NetworkManager::Setting::NotSaved:
0186         d->ui.privateKeyLineEdit->setPasswordOption(PasswordField::StoreForUser);
0187         break;
0188     case NetworkManager::Setting::NotRequired:
0189         d->ui.privateKeyLineEdit->setPasswordOption(PasswordField::NotRequired);
0190         break;
0191     }
0192 
0193     d->peers = wireGuardSetting->peers();
0194     loadSecrets(setting);
0195 }
0196 
0197 void WireGuardInterfaceWidget::loadSecrets(const NetworkManager::Setting::Ptr &setting)
0198 {
0199     NetworkManager::WireGuardSetting::Ptr wireGuardSetting = setting.staticCast<NetworkManager::WireGuardSetting>();
0200     if (wireGuardSetting) {
0201         const QString key = wireGuardSetting->privateKey();
0202         if (!key.isEmpty())
0203             d->ui.privateKeyLineEdit->setText(key);
0204 
0205         const NMVariantMapList peers = wireGuardSetting->peers();
0206         if (!peers.isEmpty()) {
0207             // For each of the peers returned, see if it contains a preshared key
0208             for (QList<QVariantMap>::const_iterator i = peers.cbegin(); i != peers.cend(); i++) {
0209                 if (i->contains(PNM_WG_PEER_KEY_PRESHARED_KEY)) {
0210                     // We have a preshared key so find the matching public key in the local peer list
0211                     QString currentPublicKey = (*i)[PNM_WG_PEER_KEY_PUBLIC_KEY].toString();
0212                     if (!currentPublicKey.isEmpty()) {
0213                         for (QList<QVariantMap>::iterator j = d->peers.begin(); j != d->peers.end(); j++) {
0214                             if ((*j)[PNM_WG_PEER_KEY_PUBLIC_KEY].toString() == currentPublicKey) {
0215                                 (*j)[PNM_WG_PEER_KEY_PRESHARED_KEY] = (*i)[PNM_WG_PEER_KEY_PRESHARED_KEY].toString();
0216                                 break;
0217                             }
0218                         }
0219                     }
0220                 }
0221             }
0222         }
0223     }
0224     // On the assumption that a saved configuration is valid (because how could it be saved if it
0225     // wasn't valid) then the peers section is valid unless it didn't get a preshared key if one
0226     // is required, so a simple minded "validity" check is done here. Real validity checks are done
0227     // when the peers widget is open which is the only time changes which might be invalid are
0228     // possible.
0229     d->peersValid = true;
0230     for (QList<QVariantMap>::iterator j = d->peers.begin(); j != d->peers.end(); j++) {
0231         if ((*j).contains(PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS) && (*j)[PNM_WG_PEER_KEY_PRESHARED_KEY_FLAGS] != NetworkManager::Setting::NotRequired
0232             && (!(*j).contains(PNM_WG_PEER_KEY_PRESHARED_KEY) || (*j)[PNM_WG_PEER_KEY_PRESHARED_KEY].toString().isEmpty())) {
0233             d->peersValid = false;
0234             break;
0235         }
0236     }
0237 }
0238 
0239 QVariantMap WireGuardInterfaceWidget::setting() const
0240 {
0241     NetworkManager::WireGuardSetting wgSetting;
0242     QString val = d->ui.fwmarkLineEdit->displayText();
0243 
0244     if (!val.isEmpty())
0245         wgSetting.setFwmark(val.toUInt());
0246 
0247     val = d->ui.listenPortLineEdit->displayText();
0248     if (!val.isEmpty())
0249         wgSetting.setListenPort(val.toUInt());
0250 
0251     val = d->ui.mtuLineEdit->displayText();
0252     if (!val.isEmpty())
0253         wgSetting.setMtu(val.toUInt());
0254 
0255     val = d->ui.privateKeyLineEdit->text();
0256     if (!val.isEmpty())
0257         wgSetting.setPrivateKey(val);
0258 
0259     wgSetting.setPeerRoutes(d->ui.peerRouteCheckBox->isChecked());
0260 
0261     PasswordField::PasswordOption option = d->ui.privateKeyLineEdit->passwordOption();
0262     switch (option) {
0263     case PasswordField::StoreForUser:
0264         wgSetting.setPrivateKeyFlags(NetworkManager::Setting::AgentOwned);
0265         break;
0266     case PasswordField::StoreForAllUsers:
0267         wgSetting.setPrivateKeyFlags(NetworkManager::Setting::None);
0268         break;
0269     // Always Ask is not a valid option for the private key so set it to AgentOwned instead
0270     case PasswordField::AlwaysAsk:
0271         wgSetting.setPrivateKeyFlags(NetworkManager::Setting::AgentOwned);
0272         break;
0273     case PasswordField::NotRequired:
0274         wgSetting.setPrivateKeyFlags(NetworkManager::Setting::NotRequired);
0275         break;
0276     }
0277     wgSetting.setPeers(d->peers);
0278     return wgSetting.toMap();
0279 }
0280 
0281 bool WireGuardInterfaceWidget::isValid() const
0282 {
0283     return d->privateKeyValid && d->fwmarkValid && d->listenPortValid && d->peersValid;
0284 }
0285 
0286 void WireGuardInterfaceWidget::checkPrivateKeyValid()
0287 {
0288     int pos = 0;
0289     PasswordField *widget = d->ui.privateKeyLineEdit;
0290     QString value = widget->text();
0291     bool valid = (QValidator::Acceptable == d->keyValidator->validate(value, pos));
0292     d->privateKeyValid = valid;
0293     setBackground(widget, valid);
0294     slotWidgetChanged();
0295 }
0296 void WireGuardInterfaceWidget::checkFwmarkValid()
0297 {
0298     int pos = 0;
0299     QLineEdit *widget = d->ui.fwmarkLineEdit;
0300     QString value = widget->displayText();
0301     d->fwmarkValid = QValidator::Acceptable == widget->validator()->validate(value, pos) || value.isEmpty();
0302     setBackground(widget, d->fwmarkValid);
0303     slotWidgetChanged();
0304 }
0305 
0306 void WireGuardInterfaceWidget::checkListenPortValid()
0307 {
0308     int pos = 0;
0309     QLineEdit *widget = d->ui.listenPortLineEdit;
0310     QString value = widget->displayText();
0311     d->listenPortValid = QValidator::Acceptable == d->portValidator->validate(value, pos) || value.isEmpty();
0312     setBackground(widget, d->listenPortValid);
0313     slotWidgetChanged();
0314 }
0315 
0316 void WireGuardInterfaceWidget::setBackground(QWidget *w, bool result) const
0317 {
0318     if (result)
0319         w->setPalette(d->normalPalette);
0320     else
0321         w->setPalette(d->warningPalette);
0322 }
0323 
0324 QString WireGuardInterfaceWidget::supportedFileExtensions()
0325 {
0326     return "*.conf";
0327 }
0328 
0329 void WireGuardInterfaceWidget::showPeers()
0330 {
0331     QPointer<WireGuardTabWidget> peers = new WireGuardTabWidget(d->peers, this);
0332     peers->setAttribute(Qt::WA_DeleteOnClose);
0333 
0334     connect(peers.data(), &WireGuardTabWidget::accepted, [peers, this]() {
0335         NMVariantMapList peersData = peers->setting();
0336         if (!peersData.isEmpty()) {
0337             d->peers = peersData;
0338             // The peers widget won't allow "OK" to be hit
0339             // unless all the peers are valid so no need to check
0340             d->peersValid = true;
0341             slotWidgetChanged();
0342         }
0343     });
0344     peers->setModal(true);
0345     peers->show();
0346 }
0347 
0348 NMVariantMapMap WireGuardInterfaceWidget::importConnectionSettings(const QString &fileName)
0349 {
0350     NMVariantMapMap result;
0351 
0352     QFile impFile(fileName);
0353     QList<NetworkManager::IpAddress> ipv4AddressList;
0354     QList<NetworkManager::IpAddress> ipv6AddressList;
0355 
0356     if (!impFile.open(QFile::ReadOnly | QFile::Text)) {
0357         return result;
0358     }
0359 
0360     const QString connectionName = QFileInfo(fileName).completeBaseName();
0361     NMVariantMapList peers;
0362     QVariantMap *currentPeer = nullptr;
0363     WireGuardKeyValidator keyValidator;
0364     NetworkManager::Ipv4Setting ipv4Setting;
0365     NetworkManager::Ipv6Setting ipv6Setting;
0366     NetworkManager::WireGuardSetting wgSetting;
0367 
0368     bool havePrivateKey = false;
0369     bool haveIpv4Setting = false;
0370     bool haveIpv6Setting = false;
0371     // Set the "PEER" elements true because they
0372     // need to be true to allocate the
0373     // first [Peer] section below
0374     bool havePublicKey = true;
0375     bool haveAllowedIps = true;
0376     int pos = 0;
0377 
0378     QTextStream in(&impFile);
0379     enum { IDLE, INTERFACE_SECTION, PEER_SECTION } currentState = IDLE;
0380 
0381     ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Disabled);
0382     ipv6Setting.setMethod(NetworkManager::Ipv6Setting::Ignored);
0383 
0384     while (!in.atEnd()) {
0385         QStringList keyValue;
0386         QString line = in.readLine();
0387 
0388         // Remove comments starting with '#'
0389         if (int index = line.indexOf(QLatin1Char('#')) > 0)
0390             line.truncate(index);
0391 
0392         // Ignore blank lines
0393         if (line.isEmpty())
0394             continue;
0395 
0396         keyValue.clear();
0397         keyValue << line.split(QLatin1Char('='));
0398 
0399         if (keyValue[0] == PNM_WG_CONF_TAG_INTERFACE) {
0400             currentState = INTERFACE_SECTION;
0401             continue;
0402         } else if (keyValue[0] == PNM_WG_CONF_TAG_PEER) {
0403             // Check to make sure the previous PEER section has
0404             // all the required elements. If not it's an error
0405             // so just return the empty result.
0406             if (!havePublicKey || !haveAllowedIps) {
0407                 return result;
0408             } else {
0409                 havePublicKey = false;
0410                 haveAllowedIps = false;
0411                 currentState = PEER_SECTION;
0412                 peers.append(*(new QVariantMap));
0413                 currentPeer = &peers[peers.size() - 1];
0414                 continue;
0415             }
0416         }
0417 
0418         // If we didn't get an '=' sign in the line, it's probably an error but
0419         // we're going to treat it as a comment and ignore it
0420         if (keyValue.length() < 2)
0421             continue;
0422 
0423         QString key = keyValue[0].trimmed();
0424 
0425         // If we are in the [Interface] section look for the possible tags
0426         if (currentState == INTERFACE_SECTION) {
0427             // Address
0428             if (key == PNM_WG_CONF_TAG_ADDRESS) {
0429                 QStringList valueList = keyValue[1].split(QLatin1Char(','));
0430                 if (valueList.isEmpty())
0431                     return result;
0432 
0433                 for (const QString &address : valueList) {
0434                     const QPair<QHostAddress, int> addressIn = QHostAddress::parseSubnet(address.trimmed());
0435                     auto addr = new NetworkManager::IpAddress;
0436                     addr->setIp(addressIn.first);
0437                     addr->setPrefixLength(addressIn.second);
0438                     if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) {
0439                         ipv4AddressList.append(*addr);
0440                     } else if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv6Protocol) {
0441                         ipv6AddressList.append(*addr);
0442                     } else { // Error condition
0443                         return result;
0444                     }
0445                 }
0446                 if (!ipv4AddressList.isEmpty()) {
0447                     ipv4Setting.setAddresses(ipv4AddressList);
0448                     ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Manual);
0449                     haveIpv4Setting = true;
0450                 }
0451                 if (!ipv6AddressList.isEmpty()) {
0452                     ipv6Setting.setAddresses(ipv6AddressList);
0453                     ipv6Setting.setMethod(NetworkManager::Ipv6Setting::Manual);
0454                     haveIpv6Setting = true;
0455                 }
0456             }
0457 
0458             // Listen Port
0459             else if (key == PNM_WG_CONF_TAG_LISTEN_PORT) {
0460                 uint val = keyValue[1].toUInt();
0461                 if (val <= 65535)
0462                     wgSetting.setListenPort(val);
0463             } else if (key == PNM_WG_CONF_TAG_PRIVATE_KEY) {
0464                 QString val = keyValue[1].trimmed();
0465                 // WireGuard keys present a slight problem because they
0466                 // must end in '=' which is removed during the 'split' above
0467                 // so if there are 3 parts and the 3 is empty, there must
0468                 // have been an '=' so add it back on
0469                 if (keyValue.size() == 3 && keyValue[2].isEmpty())
0470                     val += "=";
0471                 if (QValidator::Acceptable == keyValidator.validate(val, pos)) {
0472                     wgSetting.setPrivateKey(val);
0473                     havePrivateKey = true;
0474                 }
0475             } else if (key == PNM_WG_CONF_TAG_DNS) {
0476                 QStringList addressList = keyValue[1].split(QLatin1Char(','));
0477                 QList<QHostAddress> ipv4DnsList;
0478                 QList<QHostAddress> ipv6DnsList;
0479                 if (!addressList.isEmpty()) {
0480                     for (const QString &address : addressList) {
0481                         const QPair<QHostAddress, int> addressIn = QHostAddress::parseSubnet(address.trimmed());
0482                         if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) {
0483                             ipv4DnsList.append(addressIn.first);
0484                         } else if (addressIn.first.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv6Protocol) {
0485                             ipv6DnsList.append(addressIn.first);
0486                         } else { // Error condition
0487                             return result;
0488                         }
0489                     }
0490                 }
0491 
0492                 // If there are any addresses put them on the correct tab and set the "method" to
0493                 // "Automatic (Only addresses)" by setting "ignore-auto-dns=true"
0494                 if (!ipv4DnsList.isEmpty()) {
0495                     if (ipv4Setting.method() == NetworkManager::Ipv4Setting::Disabled)
0496                         ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Automatic);
0497                     ipv4Setting.setIgnoreAutoDns(true);
0498                     ipv4Setting.setDns(ipv4DnsList);
0499                     haveIpv4Setting = true;
0500                 }
0501 
0502                 if (!ipv6DnsList.isEmpty()) {
0503                     ipv6Setting.setMethod(NetworkManager::Ipv6Setting::Automatic);
0504                     ipv6Setting.setIgnoreAutoDns(true);
0505                     ipv6Setting.setDns(ipv6DnsList);
0506                     haveIpv6Setting = true;
0507                 }
0508             } else if (key == PNM_WG_CONF_TAG_MTU) {
0509                 uint val = keyValue[1].toUInt();
0510                 if (val > 0)
0511                     wgSetting.setMtu(val);
0512             } else if (key == PNM_WG_CONF_TAG_FWMARK) {
0513                 uint val;
0514                 if (keyValue[1].trimmed().toLower() == QLatin1String("off"))
0515                     val = 0;
0516                 else
0517                     val = keyValue[1].toUInt();
0518                 wgSetting.setFwmark(val);
0519             } else if (key == PNM_WG_CONF_TAG_TABLE //
0520                        || key == PNM_WG_CONF_TAG_PRE_UP //
0521                        || key == PNM_WG_CONF_TAG_POST_UP //
0522                        || key == PNM_WG_CONF_TAG_PRE_DOWN //
0523                        || key == PNM_WG_CONF_TAG_POST_DOWN) {
0524                 // plasma-nm does not handle these items
0525             } else {
0526                 // We got a wrong field in the Interface section so it
0527                 // is an error
0528                 break;
0529             }
0530         } else if (currentState == PEER_SECTION) {
0531             // Public Key
0532             if (key == PNM_WG_CONF_TAG_PUBLIC_KEY) {
0533                 QString val = keyValue[1].trimmed();
0534                 // WireGuard keys present a slight problem because they
0535                 // must end in '=' which is removed during the 'split' above
0536                 // so if there are 3 parts and the 3 is empty, there must
0537                 // have been an '=' so add it back on
0538                 if (keyValue.size() == 3 && keyValue[2].isEmpty())
0539                     val += "=";
0540 
0541                 if (QValidator::Acceptable == keyValidator.validate(val, pos)) {
0542                     currentPeer->insert(PNM_WG_PEER_KEY_PUBLIC_KEY, val);
0543                     havePublicKey = true;
0544                 }
0545             } else if (key == PNM_WG_CONF_TAG_ALLOWED_IPS) {
0546                 SimpleIpListValidator validator(SimpleIpListValidator::WithCidr, SimpleIpListValidator::Both);
0547                 QString val = keyValue[1].trimmed();
0548                 if (QValidator::Acceptable == validator.validate(val, pos)) {
0549                     QStringList valList = val.split(QLatin1Char(','));
0550                     for (QString &str : valList)
0551                         str = str.trimmed();
0552                     currentPeer->insert(PNM_WG_PEER_KEY_ALLOWED_IPS, valList);
0553                     haveAllowedIps = true;
0554                 }
0555             } else if (key == PNM_WG_CONF_TAG_ENDPOINT) {
0556                 if (keyValue[1].length() > 0)
0557                     currentPeer->insert(PNM_WG_PEER_KEY_ENDPOINT, keyValue[1].trimmed());
0558             } else if (key == PNM_WG_CONF_TAG_PRESHARED_KEY) {
0559                 QString val = keyValue[1].trimmed();
0560                 // WireGuard keys present a slight problem because they
0561                 // must end in '=' which is removed during the 'split' above
0562                 // so if there are 3 parts and the 3 is empty, there must
0563                 // have been an '=' so add it back on
0564                 if (keyValue.size() == 3 && keyValue[2].isEmpty())
0565                     val += "=";
0566 
0567                 if (QValidator::Acceptable == keyValidator.validate(val, pos)) {
0568                     currentPeer->insert(PNM_WG_PEER_KEY_PRESHARED_KEY, val);
0569                 }
0570             }
0571         } else {
0572             return result;
0573         }
0574     }
0575     if (!havePrivateKey || !haveAllowedIps || !havePublicKey)
0576         return result;
0577 
0578     QVariantMap conn;
0579     wgSetting.setPeers(peers);
0580     conn.insert("id", connectionName);
0581     conn.insert("interface-name", connectionName);
0582     conn.insert("type", "wireguard");
0583     conn.insert("autoconnect", "false");
0584     result.insert("connection", conn);
0585     result.insert("wireguard", wgSetting.toMap());
0586     if (haveIpv4Setting)
0587         result.insert("ipv4", ipv4Setting.toMap());
0588     if (haveIpv6Setting)
0589         result.insert("ipv6", ipv6Setting.toMap());
0590 
0591     impFile.close();
0592     return result;
0593 }
0594 
0595 #include "moc_wireguardinterfacewidget.cpp"