NetworkManagerQt

utils.cpp
1 /*
2  SPDX-FileCopyrightText: 2009 Will Stephenson <[email protected]>
3  SPDX-FileCopyrightText: 2012-2013 Jan Grulich <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7 
8 #include <QRegularExpression>
9 
10 #include "time.h"
11 #include "utils.h"
12 
14 {
15  // Q_ASSERT(address.size() == 16);
16  Q_IPV6ADDR tmp;
17  for (int i = 0; i < 16; ++i) {
18  tmp[i] = address[i];
19  }
20  QHostAddress hostaddress(tmp);
21  Q_ASSERT(hostaddress.protocol() == QAbstractSocket::IPv6Protocol);
22 
23  return hostaddress;
24 }
25 
27 {
28  // Q_ASSERT(address.protocol() == QAbstractSocket::IPv6Protocol);
29  Q_IPV6ADDR tmp = address.toIPv6Address();
30  QByteArray assembledAddress;
31  assembledAddress.reserve(16);
32  for (int i = 0; i < 16; ++i) {
33  assembledAddress.push_back(tmp[i]);
34  }
35 
36  return assembledAddress;
37 }
38 
40 {
41  QStringList mac;
42 
43  for (int i = 0; i < ba.size(); ++i) {
44  mac << QString("%1").arg((quint8)ba[i], 2, 16, QLatin1Char('0')).toUpper();
45  }
46 
47  return mac.join(":");
48 }
49 
51 {
52  const QStringList macStringList = s.split(':');
53  // Q_ASSERT(macStringList.size() == 6);
54  QByteArray ba;
55  if (!s.isEmpty()) {
56  ba.resize(6);
57  int i = 0;
58 
59  for (const QString &macPart : macStringList) {
60  ba[i++] = macPart.toUInt(nullptr, 16);
61  }
62  }
63  return ba;
64 }
65 
66 bool NetworkManager::macAddressIsValid(const QString &macAddress)
67 {
68  QRegularExpression macAddressCheck(QStringLiteral("([a-fA-F0-9][a-fA-F0-9]:){5}[0-9a-fA-F][0-9a-fA-F]"));
69 
70  return macAddressCheck.match(macAddress).hasMatch();
71 }
72 
73 bool NetworkManager::macAddressIsValid(const QByteArray &macAddress)
74 {
75  return macAddressIsValid(macAddressAsString(macAddress));
76 }
77 
79 {
80  int channel;
81  if (freq < 2500) {
82  channel = 0;
83  int i = 0;
84  QList<QPair<int, int>> bFreqs = getBFreqs();
85  while (i < bFreqs.size()) {
86  if (bFreqs.at(i).second <= freq) {
87  channel = bFreqs.at(i).first;
88  } else {
89  break;
90  }
91  i++;
92  }
93  return channel;
94  }
95  channel = 0;
96  int i = 0;
97  QList<QPair<int, int>> aFreqs = getAFreqs();
98  while (i < aFreqs.size()) {
99  if (aFreqs.at(i).second <= freq) {
100  channel = aFreqs.at(i).first;
101  } else {
102  break;
103  }
104  i++;
105  }
106 
107  return channel;
108 }
109 
110 NetworkManager::WirelessSetting::FrequencyBand NetworkManager::findFrequencyBand(int freq)
111 {
112  if (freq < 2500) {
113  return WirelessSetting::Bg;
114  }
115 
116  return WirelessSetting::A;
117 }
118 
119 bool NetworkManager::deviceSupportsApCiphers(NetworkManager::WirelessDevice::Capabilities interfaceCaps,
121  WirelessSecurityType type)
122 {
123  bool havePair = false;
124  bool haveGroup = true;
125 
126  if (type == NetworkManager::StaticWep) {
127  havePair = true;
128  } else {
129  if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep40) && apCiphers.testFlag(NetworkManager::AccessPoint::PairWep40)) {
130  havePair = true;
131  }
132  if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep104) && apCiphers.testFlag(NetworkManager::AccessPoint::PairWep104)) {
133  havePair = true;
134  }
135  if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Tkip) && apCiphers.testFlag(NetworkManager::AccessPoint::PairTkip)) {
136  havePair = true;
137  }
138  if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Ccmp) && apCiphers.testFlag(NetworkManager::AccessPoint::PairCcmp)) {
139  havePair = true;
140  }
141  }
142 
143  if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep40) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupWep40)) {
144  haveGroup = true;
145  }
146  if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wep104) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupWep104)) {
147  haveGroup = true;
148  }
149  if (type != StaticWep) {
150  if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Tkip) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupTkip)) {
151  haveGroup = true;
152  }
153  if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Ccmp) && apCiphers.testFlag(NetworkManager::AccessPoint::GroupCcmp)) {
154  haveGroup = true;
155  }
156  }
157 
158  return (havePair && haveGroup);
159 }
160 
161 // Keep this in sync with NetworkManager/libnm-core/nm-utils.c:nm_utils_security_valid()
162 bool NetworkManager::securityIsValid(WirelessSecurityType type,
164  bool haveAp,
165  bool adhoc,
169 {
170  bool good = true;
171 
172  // kDebug() << "type(" << type << ") interfaceCaps(" << interfaceCaps << ") haveAp(" << haveAp << ") adhoc(" << adhoc << ") apCaps(" << apCaps << ") apWpa("
173  // << apWpa << " apRsn(" << apRsn << ")";
174 
175  if (!haveAp) {
176  if (type == NoneSecurity) {
177  return true;
178  }
179  if ((type == StaticWep) //
180  || ((type == DynamicWep) && !adhoc) //
181  || ((type == Leap) && !adhoc)) {
183  return true;
184  } else {
185  return false;
186  }
187  }
188 
189  // apCaps.testFlag(Privacy) == true for StaticWep, Leap and DynamicWep
190  // see libs/internals/wirelessinterfaceconnectionhelpers.cpp
191 
192  // TODO: this is not in nm-utils.c
193  // if (type == Knm::WirelessSecurity::WpaPsk
194  // || ((type == Knm::WirelessSecurity::WpaEap) && !adhoc)) {
195  // if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wpa) &&
196  // !apCaps.testFlag(NetworkManager::AccessPoint::Privacy)) {
197  // return true;
198  // }
199  // }
200  // if (type == Knm::WirelessSecurity::Wpa2Psk
201  // || ((type == Knm::WirelessSecurity::Wpa2Eap) && !adhoc)) {
202  // if (interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn) &&
203  // !apCaps.testFlag(NetworkManager::AccessPoint::Privacy)) {
204  // return true;
205  // }
206  // }
207  }
208 
209  switch (type) {
210  case NoneSecurity:
211  Q_ASSERT(haveAp);
213  return false;
214  }
215  if (apWpa || apRsn) {
216  return false;
217  }
218  break;
219  case Leap: /* require PRIVACY bit for LEAP? */
220  if (adhoc) {
221  return false;
222  }
223  /* Fall through */
224  case StaticWep:
225  Q_ASSERT(haveAp);
227  return false;
228  }
229  if (apWpa || apRsn) {
230  if (!deviceSupportsApCiphers(interfaceCaps, apWpa, StaticWep)) {
231  if (!deviceSupportsApCiphers(interfaceCaps, apRsn, StaticWep)) {
232  return false;
233  }
234  }
235  }
236  break;
237  case DynamicWep:
238  if (adhoc) {
239  return false;
240  }
241  Q_ASSERT(haveAp);
242  if (apRsn || !(apCaps.testFlag(NetworkManager::AccessPoint::Privacy))) {
243  return false;
244  }
245  /* Some APs broadcast minimal WPA-enabled beacons that must be handled */
246  if (apWpa) {
247  if (!apWpa.testFlag(NetworkManager::AccessPoint::KeyMgmt8021x)) {
248  return false;
249  }
250  if (!deviceSupportsApCiphers(interfaceCaps, apWpa, DynamicWep)) {
251  return false;
252  }
253  }
254  break;
255  case WpaPsk:
256  if (adhoc) {
257  return false;
258  }
259 
260  if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wpa)) {
261  return false;
262  }
263  if (haveAp) {
264  if (apWpa.testFlag(NetworkManager::AccessPoint::KeyMgmtPsk)) {
265  if (apWpa.testFlag(NetworkManager::AccessPoint::PairTkip) //
267  return true;
268  }
269  if (apWpa.testFlag(NetworkManager::AccessPoint::PairCcmp) //
271  return true;
272  }
273  }
274  return false;
275  }
276  break;
277  case Wpa2Psk:
278  if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
279  return false;
280  }
281  if (haveAp) {
282  if (adhoc) {
284  return false;
285  }
286  if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
288  return true;
289  }
290  } else {
291  if (apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmtPsk)) {
292  if (apRsn.testFlag(NetworkManager::AccessPoint::PairTkip) //
294  return true;
295  }
296  if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
298  return true;
299  }
300  }
301  }
302  return false;
303  }
304  break;
305  case WpaEap:
306  if (adhoc) {
307  return false;
308  }
309  if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Wpa)) {
310  return false;
311  }
312  if (haveAp) {
313  if (!apWpa.testFlag(NetworkManager::AccessPoint::KeyMgmt8021x)) {
314  return false;
315  }
316  /* Ensure at least one WPA cipher is supported */
317  if (!deviceSupportsApCiphers(interfaceCaps, apWpa, WpaEap)) {
318  return false;
319  }
320  }
321  break;
322  case Wpa2Eap:
323  if (adhoc) {
324  return false;
325  }
326  if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
327  return false;
328  }
329  if (haveAp) {
330  if (!apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmt8021x)) {
331  return false;
332  }
333  /* Ensure at least one WPA cipher is supported */
334  if (!deviceSupportsApCiphers(interfaceCaps, apRsn, Wpa2Eap)) {
335  return false;
336  }
337  }
338  break;
339  case SAE:
340  if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
341  return false;
342  }
343  if (haveAp) {
344  if (adhoc) {
346  return false;
347  }
348  if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
350  return true;
351  }
352  } else {
353  if (apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmtSAE)) {
354  if (apRsn.testFlag(NetworkManager::AccessPoint::PairTkip) //
356  return true;
357  }
358  if (apRsn.testFlag(NetworkManager::AccessPoint::PairCcmp) //
360  return true;
361  }
362  }
363  }
364  return false;
365  }
366  break;
367  case Wpa3SuiteB192:
368  if (adhoc) {
369  return false;
370  }
371  if (!interfaceCaps.testFlag(NetworkManager::WirelessDevice::Rsn)) {
372  return false;
373  }
374  if (haveAp && !apRsn.testFlag(NetworkManager::AccessPoint::KeyMgmtEapSuiteB192)) {
375  return false;
376  }
377  break;
378  default:
379  good = false;
380  break;
381  }
382 
383  return good;
384 }
385 
386 NetworkManager::WirelessSecurityType NetworkManager::findBestWirelessSecurity(NetworkManager::WirelessDevice::Capabilities interfaceCaps,
387  bool haveAp,
388  bool adHoc,
392 {
393  // The ordering of this list is a pragmatic combination of security level and popularity.
394  // Therefore static WEP is before LEAP and Dynamic WEP because there is no way to detect
395  // if an AP is capable of Dynamic WEP and showing Dynamic WEP first would confuse
396  // Static WEP users.
397  const QList<NetworkManager::WirelessSecurityType> types = {NetworkManager::Wpa3SuiteB192,
398  NetworkManager::SAE,
399  NetworkManager::Wpa2Eap,
400  NetworkManager::Wpa2Psk,
401  NetworkManager::WpaEap,
402  NetworkManager::WpaPsk,
403  NetworkManager::StaticWep,
404  NetworkManager::DynamicWep,
405  NetworkManager::Leap,
406  NetworkManager::NoneSecurity};
407 
408  for (NetworkManager::WirelessSecurityType type : types) {
409  if (NetworkManager::securityIsValid(type, interfaceCaps, haveAp, adHoc, apCaps, apWpa, apRsn)) {
410  return type;
411  }
412  }
413  return NetworkManager::UnknownSecurity;
414 }
415 
416 bool NetworkManager::wepKeyIsValid(const QString &key, NetworkManager::WirelessSecuritySetting::WepKeyType type)
417 {
418  if (key.isEmpty()) {
419  return false;
420  }
421 
422  const int keylen = key.length();
423 
424  if (type != WirelessSecuritySetting::NotSpecified) {
425  if (type == WirelessSecuritySetting::Hex) {
426  if (keylen == 10 || keylen == 26) {
427  /* Hex key */
428  for (int i = 0; i < keylen; ++i) {
429  if (!(key.at(i).isDigit() || (key.at(i) >= 'A' && key.at(i) <= 'F') || (key.at(i) >= 'a' && key.at(i) <= 'f'))) {
430  return false;
431  }
432  }
433  return true;
434  } else if (keylen == 5 || keylen == 13) {
435  /* ASCII KEY */
436  for (int i = 0; i < keylen; ++i) {
437  if (!key.at(i).isPrint()) {
438  return false;
439  }
440  }
441  return true;
442  }
443 
444  return false;
445  } else if (type == WirelessSecuritySetting::Passphrase) {
446  if (!keylen || keylen > 64) {
447  return false;
448  }
449 
450  return true;
451  }
452  }
453 
454  return false;
455 }
456 
457 bool NetworkManager::wpaPskIsValid(const QString &psk)
458 {
459  if (psk.isEmpty()) {
460  return false;
461  }
462 
463  const int psklen = psk.length();
464 
465  if (psklen < 8 || psklen > 64) {
466  return false;
467  }
468 
469  if (psklen == 64) {
470  /* Hex PSK */
471  for (int i = 0; i < psklen; ++i) {
472  if (!psk.at(i).isLetterOrNumber()) {
473  return false;
474  }
475  }
476  }
477 
478  return true;
479 }
480 
481 NetworkManager::WirelessSecurityType NetworkManager::securityTypeFromConnectionSetting(const NetworkManager::ConnectionSettings::Ptr &settings)
482 {
483  NetworkManager::WirelessSecuritySetting::Ptr wifiSecuritySetting = settings->setting(Setting::WirelessSecurity).dynamicCast<WirelessSecuritySetting>();
484  if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::Wep) {
485  return StaticWep;
486  } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::Ieee8021x) {
487  if (wifiSecuritySetting->authAlg() == WirelessSecuritySetting::Leap) {
488  return Leap;
489  } else {
490  return DynamicWep;
491  }
492  } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::WpaPsk) {
493  if (wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Wpa) && !wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Rsn)) {
494  return WpaPsk;
495  }
496  return Wpa2Psk;
497  } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::WpaEap) {
498  if (wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Wpa) && !wifiSecuritySetting->proto().contains(WirelessSecuritySetting::Rsn)) {
499  return WpaEap;
500  }
501  return Wpa2Eap;
502  } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::SAE) {
503  return SAE;
504  } else if (wifiSecuritySetting->keyMgmt() == WirelessSecuritySetting::WpaEapSuiteB192) {
505  return Wpa3SuiteB192;
506  }
507 
508  return NoneSecurity;
509 }
510 
511 QList<QPair<int, int>> NetworkManager::getBFreqs()
512 {
513  QList<QPair<int, int>> freqs;
514 
515  freqs.append(QPair<int, int>(1, 2412));
516  freqs.append(QPair<int, int>(2, 2417));
517  freqs.append(QPair<int, int>(3, 2422));
518  freqs.append(QPair<int, int>(4, 2427));
519  freqs.append(QPair<int, int>(5, 2432));
520  freqs.append(QPair<int, int>(6, 2437));
521  freqs.append(QPair<int, int>(7, 2442));
522  freqs.append(QPair<int, int>(8, 2447));
523  freqs.append(QPair<int, int>(9, 2452));
524  freqs.append(QPair<int, int>(10, 2457));
525  freqs.append(QPair<int, int>(11, 2462));
526  freqs.append(QPair<int, int>(12, 2467));
527  freqs.append(QPair<int, int>(13, 2472));
528  freqs.append(QPair<int, int>(14, 2484));
529 
530  return freqs;
531 }
532 
533 QList<QPair<int, int>> NetworkManager::getAFreqs()
534 {
535  QList<QPair<int, int>> freqs;
536 
537  freqs.append(QPair<int, int>(7, 5035));
538  freqs.append(QPair<int, int>(8, 5040));
539  freqs.append(QPair<int, int>(9, 5045));
540  freqs.append(QPair<int, int>(11, 5055));
541  freqs.append(QPair<int, int>(12, 5060));
542  freqs.append(QPair<int, int>(16, 5080));
543  freqs.append(QPair<int, int>(34, 5170));
544  freqs.append(QPair<int, int>(36, 5180));
545  freqs.append(QPair<int, int>(38, 5190));
546  freqs.append(QPair<int, int>(40, 5200));
547  freqs.append(QPair<int, int>(42, 5210));
548  freqs.append(QPair<int, int>(44, 5220));
549  freqs.append(QPair<int, int>(46, 5230));
550  freqs.append(QPair<int, int>(48, 5240));
551  freqs.append(QPair<int, int>(52, 5260));
552  freqs.append(QPair<int, int>(56, 5280));
553  freqs.append(QPair<int, int>(60, 5300));
554  freqs.append(QPair<int, int>(64, 5320));
555  freqs.append(QPair<int, int>(100, 5500));
556  freqs.append(QPair<int, int>(104, 5520));
557  freqs.append(QPair<int, int>(108, 5540));
558  freqs.append(QPair<int, int>(112, 5560));
559  freqs.append(QPair<int, int>(116, 5580));
560  freqs.append(QPair<int, int>(120, 5600));
561  freqs.append(QPair<int, int>(124, 5620));
562  freqs.append(QPair<int, int>(128, 5640));
563  freqs.append(QPair<int, int>(132, 5660));
564  freqs.append(QPair<int, int>(136, 5680));
565  freqs.append(QPair<int, int>(140, 5700));
566  freqs.append(QPair<int, int>(149, 5745));
567  freqs.append(QPair<int, int>(153, 5765));
568  freqs.append(QPair<int, int>(157, 5785));
569  freqs.append(QPair<int, int>(161, 5805));
570  freqs.append(QPair<int, int>(165, 5825));
571  freqs.append(QPair<int, int>(183, 4915));
572  freqs.append(QPair<int, int>(184, 4920));
573  freqs.append(QPair<int, int>(185, 4925));
574  freqs.append(QPair<int, int>(187, 4935));
575  freqs.append(QPair<int, int>(188, 4940));
576  freqs.append(QPair<int, int>(189, 4945));
577  freqs.append(QPair<int, int>(192, 4960));
578  freqs.append(QPair<int, int>(196, 4980));
579 
580  return freqs;
581 }
582 
583 QDateTime NetworkManager::clockBootTimeToDateTime(qlonglong clockBootime)
584 {
585  clockid_t clk_id = CLOCK_BOOTTIME;
586  struct timespec tp;
587  int r;
588 
589  // now is used as a point of reference
590  // with the timespec that contains the number of msec since boot
592  r = clock_gettime(clk_id, &tp);
593  if (r == -1 && errno == EINVAL) {
594  clk_id = CLOCK_MONOTONIC;
595  r = clock_gettime(clk_id, &tp);
596  }
597 
598  // convert to msecs
599  long now_msecs = tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
600 
601  // diff the msecs and construct a QDateTime based on the offset
602  QDateTime res;
603  if (clockBootime > now_msecs) {
604  qlonglong offset = clockBootime - now_msecs;
606  } else {
607  qlonglong offset = now_msecs - clockBootime;
609  }
610 
611  return res;
612 }
@ Privacy
Access point supports privacy measures.
Definition: accesspoint.h:47
void append(const T &value)
QString toUpper() const const
Type type(const QSqlDatabase &db)
QDateTime currentDateTime()
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
NETWORKMANAGERQT_EXPORT QString macAddressAsString(const QByteArray &ba)
Definition: utils.cpp:39
bool isLetterOrNumber() const const
bool testFlag(Enum flag) const const
QDateTime fromMSecsSinceEpoch(qint64 msecs)
bool isDigit() const const
NETWORKMANAGERQT_EXPORT QHostAddress ipv6AddressAsHostAddress(const QByteArray &address)
Definition: utils.cpp:13
QAbstractSocket::NetworkLayerProtocol protocol() const const
uint toUInt(bool *ok, int base) const const
QStringList types(Mode mode=Writing)
void push_back(char ch)
int size() const const
bool isPrint() const const
bool isEmpty() const const
@ Rsn
RSN authethication protocol.
int length() const const
const T & at(int i) const const
qint64 toMSecsSinceEpoch() const const
QString join(const QString &separator) const const
NETWORKMANAGERQT_EXPORT QByteArray macAddressFromString(const QString &s)
Definition: utils.cpp:50
NETWORKMANAGERQT_EXPORT QByteArray ipv6AddressFromHostAddress(const QHostAddress &address)
Definition: utils.cpp:26
void resize(int size)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
void reserve(int size)
const QChar at(int position) const const
@ Tkip
TKIP encryption cipher.
int size() const const
@ Wpa
WPA authentication protocol.
@ Wep104
104 bit WEP cipher
@ Ccmp
CCMP encryption cipher.
@ IBSSRsn
device supports WPA2/RSN in an IBSS network
NETWORKMANAGERQT_EXPORT int findChannel(int freq)
Definition: utils.cpp:78
QSharedPointer< X > dynamicCast() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 04:05:36 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.