NetworkManagerQt

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

KDE's Doxygen guidelines are available online.