1// Copyright (C) 2017 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qhostaddress.h"
6#include "qhostaddress_p.h"
7#include "private/qipaddress_p.h"
8#include "qdebug.h"
9#if defined(Q_OS_WIN)
10# include <winsock2.h>
11# include <ws2tcpip.h>
12#else
13# include <netinet/in.h>
14#endif
15#include "qplatformdefs.h"
16#include "qstringlist.h"
17#include "qendian.h"
18#ifndef QT_NO_DATASTREAM
19#include <qdatastream.h>
20#endif
21#ifdef __SSE2__
22# include <private/qsimd_p.h>
23#endif
24
25#ifdef QT_LINUXBASE
26# include <arpa/inet.h>
27#endif
28
29QT_BEGIN_NAMESPACE
30
31QHostAddressPrivate::QHostAddressPrivate()
32 : a(0), protocol(QHostAddress::UnknownNetworkLayerProtocol)
33{
34 memset(s: &a6, c: 0, n: sizeof(a6));
35}
36
37QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QHostAddressPrivate)
38
39void QHostAddressPrivate::setAddress(quint32 a_)
40{
41 a = a_;
42 protocol = QHostAddress::IPv4Protocol;
43
44 //create mapped address, except for a_ == 0 (any)
45 a6_64.c[0] = 0;
46 if (a) {
47 a6_32.c[2] = qToBigEndian(source: 0xffff);
48 a6_32.c[3] = qToBigEndian(source: a);
49 } else {
50 a6_64.c[1] = 0;
51 }
52}
53
54/// parses v4-mapped addresses or the AnyIPv6 address and stores in \a a;
55/// returns true if the address was one of those
56static bool convertToIpv4(quint32& a, const Q_IPV6ADDR &a6, const QHostAddress::ConversionMode mode)
57{
58 if (mode == QHostAddress::StrictConversion)
59 return false;
60
61 const uchar *ptr = a6.c;
62 if (qFromUnaligned<quint64>(src: ptr) != 0)
63 return false;
64
65 const quint32 mid = qFromBigEndian<quint32>(src: ptr + 8);
66 if ((mid == 0xffff) && (mode & QHostAddress::ConvertV4MappedToIPv4)) {
67 a = qFromBigEndian<quint32>(src: ptr + 12);
68 return true;
69 }
70 if (mid != 0)
71 return false;
72
73 const quint32 low = qFromBigEndian<quint32>(src: ptr + 12);
74 if ((low == 0) && (mode & QHostAddress::ConvertUnspecifiedAddress)) {
75 a = 0;
76 return true;
77 }
78 if ((low == 1) && (mode & QHostAddress::ConvertLocalHost)) {
79 a = INADDR_LOOPBACK;
80 return true;
81 }
82 if ((low != 1) && (mode & QHostAddress::ConvertV4CompatToIPv4)) {
83 a = low;
84 return true;
85 }
86 return false;
87}
88
89void QHostAddressPrivate::setAddress(const quint8 *a_)
90{
91 protocol = QHostAddress::IPv6Protocol;
92 memcpy(dest: a6.c, src: a_, n: sizeof(a6));
93 a = 0;
94 convertToIpv4(a, a6: a6, mode: (QHostAddress::ConvertV4MappedToIPv4
95 | QHostAddress::ConvertUnspecifiedAddress));
96}
97
98void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_)
99{
100 setAddress(a_.c);
101}
102
103static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr, QString *scopeId)
104{
105 QStringView tmp(address);
106 qsizetype scopeIdPos = tmp.lastIndexOf(c: u'%');
107 if (scopeIdPos != -1) {
108 *scopeId = tmp.mid(pos: scopeIdPos + 1).toString();
109 tmp.chop(n: tmp.size() - scopeIdPos);
110 } else {
111 scopeId->clear();
112 }
113 return QIPAddressUtils::parseIp6(address&: addr, begin: tmp.begin(), end: tmp.end()) == nullptr;
114}
115
116bool QHostAddressPrivate::parse(const QString &ipString)
117{
118 protocol = QHostAddress::UnknownNetworkLayerProtocol;
119 QString a = ipString.simplified();
120 if (a.isEmpty())
121 return false;
122
123 // All IPv6 addresses contain a ':', and may contain a '.'.
124 if (a.contains(c: u':')) {
125 quint8 maybeIp6[16];
126 if (parseIp6(address: a, addr&: maybeIp6, scopeId: &scopeId)) {
127 setAddress(maybeIp6);
128 return true;
129 }
130 }
131
132 quint32 maybeIp4 = 0;
133 if (QIPAddressUtils::parseIp4(address&: maybeIp4, begin: a.constBegin(), end: a.constEnd())) {
134 setAddress(maybeIp4);
135 return true;
136 }
137
138 return false;
139}
140
141void QHostAddressPrivate::clear()
142{
143 a = 0;
144 protocol = QHostAddress::UnknownNetworkLayerProtocol;
145 memset(s: &a6, c: 0, n: sizeof(a6));
146}
147
148AddressClassification QHostAddressPrivate::classify() const
149{
150 if (a) {
151 // This is an IPv4 address or an IPv6 v4-mapped address includes all
152 // IPv6 v4-compat addresses, except for ::ffff:0.0.0.0 (because `a' is
153 // zero). See setAddress(quint8*) below, which calls convertToIpv4(),
154 // for details.
155 // Source: RFC 5735
156 if ((a & 0xff000000U) == 0x7f000000U) // 127.0.0.0/8
157 return LoopbackAddress;
158 if ((a & 0xf0000000U) == 0xe0000000U) // 224.0.0.0/4
159 return MulticastAddress;
160 if ((a & 0xffff0000U) == 0xa9fe0000U) // 169.254.0.0/16
161 return LinkLocalAddress;
162 if ((a & 0xff000000U) == 0) // 0.0.0.0/8 except 0.0.0.0 (handled below)
163 return LocalNetAddress;
164 if ((a & 0xf0000000U) == 0xf0000000U) { // 240.0.0.0/4
165 if (a == 0xffffffffU) // 255.255.255.255
166 return BroadcastAddress;
167 return UnknownAddress;
168 }
169 if (((a & 0xff000000U) == 0x0a000000U) // 10.0.0.0/8
170 || ((a & 0xfff00000U) == 0xac100000U) // 172.16.0.0/12
171 || ((a & 0xffff0000U) == 0xc0a80000U)) // 192.168.0.0/16
172 return PrivateNetworkAddress;
173
174 // Not testing for TestNetworkAddress
175 // since we don't need them yet.
176 return GlobalAddress;
177 }
178
179 // As `a' is zero, this address is either ::ffff:0.0.0.0 or a non-v4-mapped IPv6 address.
180 // Source: https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
181 if (a6_64.c[0]) {
182 quint32 high16 = qFromBigEndian(source: a6_32.c[0]) >> 16;
183 switch (high16 >> 8) {
184 case 0xff: // ff00::/8
185 return MulticastAddress;
186 case 0xfe:
187 switch (high16 & 0xffc0) {
188 case 0xfec0: // fec0::/10
189 return SiteLocalAddress;
190
191 case 0xfe80: // fe80::/10
192 return LinkLocalAddress;
193
194 default: // fe00::/9
195 return UnknownAddress;
196 }
197 case 0xfd: // fc00::/7
198 case 0xfc:
199 return UniqueLocalAddress;
200 default:
201 return GlobalAddress;
202 }
203 }
204
205 quint64 low64 = qFromBigEndian(source: a6_64.c[1]);
206 if (low64 == 1) // ::1
207 return LoopbackAddress;
208 if (low64 >> 32 == 0xffff) { // ::ffff:0.0.0.0/96
209 Q_ASSERT(quint32(low64) == 0);
210 return LocalNetAddress;
211 }
212 if (low64) // not ::
213 return GlobalAddress;
214
215 if (protocol == QHostAddress::UnknownNetworkLayerProtocol)
216 return UnknownAddress;
217
218 // only :: and 0.0.0.0 remain now
219 return LocalNetAddress;
220}
221
222bool QNetmask::setAddress(const QHostAddress &address)
223{
224 static const quint8 zeroes[16] = { 0 };
225 union {
226 quint32 v4;
227 quint8 v6[16];
228 } ip;
229
230 int netmask = 0;
231 quint8 *ptr = ip.v6;
232 quint8 *end;
233 length = 255;
234
235 if (address.protocol() == QHostAddress::IPv4Protocol) {
236 ip.v4 = qToBigEndian(source: address.toIPv4Address());
237 end = ptr + 4;
238 } else if (address.protocol() == QHostAddress::IPv6Protocol) {
239 memcpy(dest: ip.v6, src: address.toIPv6Address().c, n: 16);
240 end = ptr + 16;
241 } else {
242 return false;
243 }
244
245 while (ptr < end) {
246 switch (*ptr) {
247 case 255:
248 netmask += 8;
249 ++ptr;
250 continue;
251
252 default:
253 return false; // invalid IP-style netmask
254
255 case 254:
256 ++netmask;
257 Q_FALLTHROUGH();
258 case 252:
259 ++netmask;
260 Q_FALLTHROUGH();
261 case 248:
262 ++netmask;
263 Q_FALLTHROUGH();
264 case 240:
265 ++netmask;
266 Q_FALLTHROUGH();
267 case 224:
268 ++netmask;
269 Q_FALLTHROUGH();
270 case 192:
271 ++netmask;
272 Q_FALLTHROUGH();
273 case 128:
274 ++netmask;
275 Q_FALLTHROUGH();
276 case 0:
277 break;
278 }
279 break;
280 }
281
282 // confirm that the rest is only zeroes
283 if (ptr < end && memcmp(s1: ptr + 1, s2: zeroes, n: end - ptr - 1) != 0)
284 return false;
285
286 length = netmask;
287 return true;
288}
289
290static void clearBits(quint8 *where, int start, int end)
291{
292 Q_ASSERT(end == 32 || end == 128);
293 if (start == end)
294 return;
295
296 // for the byte where 'start' is, clear the lower bits only
297 quint8 bytemask = 256 - (1 << (8 - (start & 7)));
298 where[start / 8] &= bytemask;
299
300 // for the tail part, clear everything
301 memset(s: where + (start + 7) / 8, c: 0, n: end / 8 - (start + 7) / 8);
302}
303
304QHostAddress QNetmask::address(QHostAddress::NetworkLayerProtocol protocol) const
305{
306 if (length == 255 || protocol == QHostAddress::AnyIPProtocol ||
307 protocol == QHostAddress::UnknownNetworkLayerProtocol) {
308 return QHostAddress();
309 } else if (protocol == QHostAddress::IPv4Protocol) {
310 quint32 a;
311 if (length == 0)
312 a = 0;
313 else if (length == 32)
314 a = quint32(0xffffffff);
315 else
316 a = quint32(0xffffffff) >> (32 - length) << (32 - length);
317 return QHostAddress(a);
318 } else {
319 Q_IPV6ADDR a6;
320 memset(s: a6.c, c: 0xFF, n: sizeof(a6));
321 clearBits(where: a6.c, start: length, end: 128);
322 return QHostAddress(a6);
323 }
324}
325
326/*!
327 \class QHostAddress
328 \brief The QHostAddress class provides an IP address.
329 \ingroup network
330 \ingroup shared
331 \inmodule QtNetwork
332
333 This class holds an IPv4 or IPv6 address in a platform- and
334 protocol-independent manner.
335
336 QHostAddress is normally used with the QTcpSocket, QTcpServer,
337 and QUdpSocket to connect to a host or to set up a server.
338
339 A host address is set with setAddress(), and retrieved with
340 toIPv4Address(), toIPv6Address(), or toString(). You can check the
341 type with protocol().
342
343 \note Please note that QHostAddress does not do DNS lookups.
344 QHostInfo is needed for that.
345
346 The class also supports common predefined addresses: \l Null, \l
347 LocalHost, \l LocalHostIPv6, \l Broadcast, and \l Any.
348
349 \sa QHostInfo, QTcpSocket, QTcpServer, QUdpSocket
350*/
351
352/*! \enum QHostAddress::SpecialAddress
353
354 \value Null The null address object. Equivalent to QHostAddress(). See also QHostAddress::isNull().
355 \value LocalHost The IPv4 localhost address. Equivalent to QHostAddress("127.0.0.1").
356 \value LocalHostIPv6 The IPv6 localhost address. Equivalent to QHostAddress("::1").
357 \value Broadcast The IPv4 broadcast address. Equivalent to QHostAddress("255.255.255.255").
358 \value AnyIPv4 The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0"). A socket bound with this address will listen only on IPv4 interfaces.
359 \value AnyIPv6 The IPv6 any-address. Equivalent to QHostAddress("::"). A socket bound with this address will listen only on IPv6 interfaces.
360 \value Any The dual stack any-address. A socket bound with this address will listen on both IPv4 and IPv6 interfaces.
361*/
362
363/*! \enum QHostAddress::ConversionModeFlag
364
365 \since 5.8
366
367 \value StrictConversion Don't convert IPv6 addresses to IPv4 when comparing two QHostAddress objects of different protocols, so they will always be considered different.
368 \value ConvertV4MappedToIPv4 Convert IPv4-mapped IPv6 addresses (RFC 4291 sect. 2.5.5.2) when comparing. Therefore QHostAddress("::ffff:192.168.1.1") will compare equal to QHostAddress("192.168.1.1").
369 \value ConvertV4CompatToIPv4 Convert IPv4-compatible IPv6 addresses (RFC 4291 sect. 2.5.5.1) when comparing. Therefore QHostAddress("::192.168.1.1") will compare equal to QHostAddress("192.168.1.1").
370 \value ConvertLocalHost Convert the IPv6 loopback addresses to its IPv4 equivalent when comparing. Therefore e.g. QHostAddress("::1") will compare equal to QHostAddress("127.0.0.1").
371 \value ConvertUnspecifiedAddress All unspecified addresses will compare equal, namely AnyIPv4, AnyIPv6 and Any.
372 \value TolerantConversion Sets all three preceding flags.
373
374 \sa isEqual()
375 */
376
377/*! Constructs a null host address object, i.e. an address which is not valid for any host or interface.
378
379 \sa clear()
380*/
381QHostAddress::QHostAddress()
382 : d(new QHostAddressPrivate)
383{
384}
385
386/*!
387 Constructs a host address object with the IPv4 address \a ip4Addr.
388*/
389QHostAddress::QHostAddress(quint32 ip4Addr)
390 : d(new QHostAddressPrivate)
391{
392 setAddress(ip4Addr);
393}
394
395/*!
396 \since 5.5
397 Constructs a host address object with the IPv6 address \a ip6Addr.
398
399 \a ip6Addr must be a 16-byte array in network byte order (big
400 endian).
401*/
402QHostAddress::QHostAddress(const quint8 *ip6Addr)
403 : d(new QHostAddressPrivate)
404{
405 setAddress(ip6Addr);
406}
407
408/*!
409 Constructs a host address object with the IPv6 address \a ip6Addr.
410*/
411QHostAddress::QHostAddress(const Q_IPV6ADDR &ip6Addr)
412 : d(new QHostAddressPrivate)
413{
414 setAddress(ip6Addr);
415}
416
417/*!
418 Constructs an IPv4 or IPv6 address based on the string \a address
419 (e.g., "127.0.0.1").
420
421 \sa setAddress()
422*/
423QHostAddress::QHostAddress(const QString &address)
424 : d(new QHostAddressPrivate)
425{
426 d->parse(ipString: address);
427}
428
429/*!
430 \fn QHostAddress::QHostAddress(const sockaddr *sockaddr)
431
432 Constructs an IPv4 or IPv6 address using the address specified by
433 the native structure \a sockaddr.
434
435 \sa setAddress()
436*/
437QHostAddress::QHostAddress(const struct sockaddr *sockaddr)
438 : d(new QHostAddressPrivate)
439{
440 if (sockaddr->sa_family == AF_INET)
441 setAddress(htonl(hostlong: ((const sockaddr_in *)sockaddr)->sin_addr.s_addr));
442 else if (sockaddr->sa_family == AF_INET6)
443 setAddress(((const sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr);
444}
445
446/*!
447 Constructs a copy of the given \a address.
448*/
449QHostAddress::QHostAddress(const QHostAddress &address)
450 : d(address.d)
451{
452}
453
454/*!
455 \fn QHostAddress::QHostAddress(QHostAddress &&other)
456
457 \since 6.8
458
459 Move-constructs a new QHostAddress from \a other.
460
461 \note The moved-from object \a other is placed in a partially-formed state,
462 in which the only valid operations are destruction and assignment of a new
463 value.
464*/
465
466/*!
467 Constructs a QHostAddress object for \a address.
468*/
469QHostAddress::QHostAddress(SpecialAddress address)
470 : d(new QHostAddressPrivate)
471{
472 setAddress(address);
473}
474
475/*!
476 Destroys the host address object.
477*/
478QHostAddress::~QHostAddress()
479{
480}
481
482/*!
483 Assigns another host \a address to this object, and returns a reference
484 to this object.
485*/
486QHostAddress &QHostAddress::operator=(const QHostAddress &address)
487{
488 d = address.d;
489 return *this;
490}
491
492/*!
493 \since 5.8
494 Assigns the special address \a address to this object, and returns a
495 reference to this object.
496
497 \sa setAddress()
498*/
499QHostAddress &QHostAddress::operator=(SpecialAddress address)
500{
501 setAddress(address);
502 return *this;
503}
504
505/*!
506 \fn void QHostAddress::swap(QHostAddress &other)
507 \since 5.6
508
509 Swaps this host address with \a other. This operation is very fast
510 and never fails.
511*/
512
513/*!
514 \fn bool QHostAddress::operator!=(const QHostAddress &other) const
515 \since 4.2
516
517 Returns \c true if this host address is not the same as the \a other
518 address given; otherwise returns \c false.
519*/
520
521/*!
522 \fn bool QHostAddress::operator!=(SpecialAddress other) const
523
524 Returns \c true if this host address is not the same as the \a other
525 address given; otherwise returns \c false.
526*/
527
528/*!
529 Sets the host address to null and sets the protocol to
530 QAbstractSocket::UnknownNetworkLayerProtocol.
531
532 \sa QHostAddress::Null
533*/
534void QHostAddress::clear()
535{
536 d.detach();
537 d->clear();
538}
539
540/*!
541 Set the IPv4 address specified by \a ip4Addr.
542*/
543void QHostAddress::setAddress(quint32 ip4Addr)
544{
545 d.detach();
546 d->setAddress(ip4Addr);
547}
548
549/*!
550 \overload
551 \since 5.5
552
553 Set the IPv6 address specified by \a ip6Addr.
554
555 \a ip6Addr must be an array of 16 bytes in network byte order
556 (high-order byte first).
557*/
558void QHostAddress::setAddress(const quint8 *ip6Addr)
559{
560 d.detach();
561 d->setAddress(ip6Addr);
562}
563
564/*!
565 \overload
566
567 Set the IPv6 address specified by \a ip6Addr.
568*/
569void QHostAddress::setAddress(const Q_IPV6ADDR &ip6Addr)
570{
571 d.detach();
572 d->setAddress(ip6Addr);
573}
574
575/*!
576 \overload
577
578 Sets the IPv4 or IPv6 address specified by the string
579 representation specified by \a address (e.g. "127.0.0.1").
580 Returns \c true and sets the address if the address was successfully
581 parsed; otherwise returns \c false.
582*/
583bool QHostAddress::setAddress(const QString &address)
584{
585 d.detach();
586 return d->parse(ipString: address);
587}
588
589/*!
590 \fn void QHostAddress::setAddress(const sockaddr *sockaddr)
591 \overload
592
593 Sets the IPv4 or IPv6 address specified by the native structure \a
594 sockaddr. Returns \c true and sets the address if the address was
595 successfully parsed; otherwise returns \c false.
596*/
597void QHostAddress::setAddress(const struct sockaddr *sockaddr)
598{
599 d.detach();
600 clear();
601 if (sockaddr->sa_family == AF_INET)
602 setAddress(htonl(hostlong: ((const sockaddr_in *)sockaddr)->sin_addr.s_addr));
603 else if (sockaddr->sa_family == AF_INET6)
604 setAddress(((const sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr);
605}
606
607/*!
608 \overload
609 \since 5.8
610
611 Sets the special address specified by \a address.
612*/
613void QHostAddress::setAddress(SpecialAddress address)
614{
615 clear();
616
617 Q_IPV6ADDR ip6;
618 memset(s: &ip6, c: 0, n: sizeof ip6);
619 quint32 ip4 = INADDR_ANY;
620
621 switch (address) {
622 case Null:
623 return;
624
625 case Broadcast:
626 ip4 = INADDR_BROADCAST;
627 break;
628 case LocalHost:
629 ip4 = INADDR_LOOPBACK;
630 break;
631 case AnyIPv4:
632 break;
633
634 case LocalHostIPv6:
635 ip6[15] = 1;
636 Q_FALLTHROUGH();
637 case AnyIPv6:
638 d->setAddress(ip6);
639 return;
640
641 case Any:
642 d->protocol = QHostAddress::AnyIPProtocol;
643 return;
644 }
645
646 // common IPv4 part
647 d->setAddress(ip4);
648}
649
650/*!
651 Returns the IPv4 address as a number.
652
653 For example, if the address is 127.0.0.1, the returned value is
654 2130706433 (i.e. 0x7f000001).
655
656 This value is valid if the protocol() is
657 \l{QAbstractSocket::}{IPv4Protocol},
658 or if the protocol is
659 \l{QAbstractSocket::}{IPv6Protocol},
660 and the IPv6 address is an IPv4 mapped address (RFC4291). In those
661 cases, \a ok will be set to true. Otherwise, it will be set to false.
662
663 \sa toString()
664*/
665quint32 QHostAddress::toIPv4Address(bool *ok) const
666{
667 quint32 dummy;
668 if (ok)
669 *ok = d->protocol == QHostAddress::IPv4Protocol || d->protocol == QHostAddress::AnyIPProtocol
670 || (d->protocol == QHostAddress::IPv6Protocol
671 && convertToIpv4(a&: dummy, a6: d->a6, mode: ConversionMode(QHostAddress::ConvertV4MappedToIPv4
672 | QHostAddress::ConvertUnspecifiedAddress)));
673 return d->a;
674}
675
676/*!
677 Returns the network layer protocol of the host address.
678*/
679QHostAddress::NetworkLayerProtocol QHostAddress::protocol() const
680{
681 return QHostAddress::NetworkLayerProtocol(d->protocol);
682}
683
684/*!
685 Returns the IPv6 address as a Q_IPV6ADDR structure. The structure
686 consists of 16 unsigned characters.
687
688 \snippet code/src_network_kernel_qhostaddress.cpp 0
689
690 This value is valid if the protocol() is
691 \l{QAbstractSocket::}{IPv6Protocol}.
692 If the protocol is
693 \l{QAbstractSocket::}{IPv4Protocol},
694 then the address is returned as an IPv4 mapped IPv6 address. (RFC4291)
695
696 \sa toString()
697*/
698Q_IPV6ADDR QHostAddress::toIPv6Address() const
699{
700 return d->a6;
701}
702
703/*!
704 Returns the address as a string.
705
706 For example, if the address is the IPv4 address 127.0.0.1, the
707 returned string is "127.0.0.1". For IPv6 the string format will
708 follow the RFC5952 recommendation.
709 For QHostAddress::Any, its IPv4 address will be returned ("0.0.0.0")
710
711 \sa toIPv4Address()
712*/
713QString QHostAddress::toString() const
714{
715 QString s;
716 if (d->protocol == QHostAddress::IPv4Protocol
717 || d->protocol == QHostAddress::AnyIPProtocol) {
718 quint32 i = toIPv4Address();
719 QIPAddressUtils::toString(appendTo&: s, address: i);
720 } else if (d->protocol == QHostAddress::IPv6Protocol) {
721 QIPAddressUtils::toString(appendTo&: s, address: d->a6.c);
722 if (!d->scopeId.isEmpty())
723 s += u'%' + d->scopeId;
724 }
725 return s;
726}
727
728/*!
729 \since 4.1
730
731 Returns the scope ID of an IPv6 address. For IPv4 addresses, or if the
732 address does not contain a scope ID, an empty QString is returned.
733
734 The IPv6 scope ID specifies the scope of \e reachability for non-global
735 IPv6 addresses, limiting the area in which the address can be used. All
736 IPv6 addresses are associated with such a reachability scope. The scope ID
737 is used to disambiguate addresses that are not guaranteed to be globally
738 unique.
739
740 IPv6 specifies the following four levels of reachability:
741
742 \list
743
744 \li Node-local: Addresses that are only used for communicating with
745 services on the same interface (e.g., the loopback interface "::1").
746
747 \li Link-local: Addresses that are local to the network interface
748 (\e{link}). There is always one link-local address for each IPv6 interface
749 on your host. Link-local addresses ("fe80...") are generated from the MAC
750 address of the local network adaptor, and are not guaranteed to be unique.
751
752 \li Global: For globally routable addresses, such as public servers on the
753 Internet.
754
755 \endlist
756
757 When using a link-local or site-local address for IPv6 connections, you
758 must specify the scope ID. The scope ID for a link-local address is
759 usually the same as the interface name (e.g., "eth0", "en1") or number
760 (e.g., "1", "2").
761
762 \sa setScopeId(), QNetworkInterface, QNetworkInterface::interfaceFromName
763*/
764QString QHostAddress::scopeId() const
765{
766 return (d->protocol == QHostAddress::IPv6Protocol) ? d->scopeId : QString();
767}
768
769/*!
770 \since 4.1
771
772 Sets the IPv6 scope ID of the address to \a id. If the address protocol is
773 not IPv6, this function does nothing. The scope ID may be set as an
774 interface name (such as "eth0" or "en1") or as an integer representing the
775 interface index. If \a id is an interface name, QtNetwork will convert to
776 an interface index using QNetworkInterface::interfaceIndexFromName() before
777 calling the operating system networking functions.
778
779 \sa scopeId(), QNetworkInterface, QNetworkInterface::interfaceFromName
780*/
781void QHostAddress::setScopeId(const QString &id)
782{
783 d.detach();
784 if (d->protocol == QHostAddress::IPv6Protocol)
785 d->scopeId = id;
786}
787
788/*!
789 Returns \c true if this host address is the same as the \a other address
790 given; otherwise returns \c false. This operator just calls isEqual(other, StrictConversion).
791
792 \sa isEqual()
793*/
794bool QHostAddress::operator==(const QHostAddress &other) const
795{
796 return d == other.d || isEqual(address: other, mode: StrictConversion);
797}
798
799/*!
800 \since 5.8
801
802 Returns \c true if this host address is the same as the \a other address
803 given; otherwise returns \c false.
804
805 The parameter \a mode controls which conversions are performed between addresses
806 of differing protocols. If no \a mode is given, \c TolerantConversion is performed
807 by default.
808
809 \sa ConversionMode, operator==()
810 */
811bool QHostAddress::isEqual(const QHostAddress &other, ConversionMode mode) const
812{
813 if (d == other.d)
814 return true;
815
816 if (d->protocol == QHostAddress::IPv4Protocol) {
817 switch (other.d->protocol) {
818 case QHostAddress::IPv4Protocol:
819 return d->a == other.d->a;
820 case QHostAddress::IPv6Protocol:
821 quint32 a4;
822 return convertToIpv4(a&: a4, a6: other.d->a6, mode) && (a4 == d->a);
823 case QHostAddress::AnyIPProtocol:
824 return (mode & QHostAddress::ConvertUnspecifiedAddress) && d->a == 0;
825 case QHostAddress::UnknownNetworkLayerProtocol:
826 return false;
827 }
828 }
829
830 if (d->protocol == QHostAddress::IPv6Protocol) {
831 switch (other.d->protocol) {
832 case QHostAddress::IPv4Protocol:
833 quint32 a4;
834 return convertToIpv4(a&: a4, a6: d->a6, mode) && (a4 == other.d->a);
835 case QHostAddress::IPv6Protocol:
836 return memcmp(s1: &d->a6, s2: &other.d->a6, n: sizeof(Q_IPV6ADDR)) == 0;
837 case QHostAddress::AnyIPProtocol:
838 return (mode & QHostAddress::ConvertUnspecifiedAddress)
839 && (d->a6_64.c[0] == 0) && (d->a6_64.c[1] == 0);
840 case QHostAddress::UnknownNetworkLayerProtocol:
841 return false;
842 }
843 }
844
845 if ((d->protocol == QHostAddress::AnyIPProtocol)
846 && (mode & QHostAddress::ConvertUnspecifiedAddress)) {
847 switch (other.d->protocol) {
848 case QHostAddress::IPv4Protocol:
849 return other.d->a == 0;
850 case QHostAddress::IPv6Protocol:
851 return (other.d->a6_64.c[0] == 0) && (other.d->a6_64.c[1] == 0);
852 default:
853 break;
854 }
855 }
856
857 return d->protocol == other.d->protocol;
858}
859
860/*!
861 Returns \c true if this host address is the same as the \a other
862 address given; otherwise returns \c false.
863*/
864bool QHostAddress::operator ==(SpecialAddress other) const
865{
866 quint32 ip4 = INADDR_ANY;
867 switch (other) {
868 case Null:
869 return d->protocol == QHostAddress::UnknownNetworkLayerProtocol;
870
871 case Broadcast:
872 ip4 = INADDR_BROADCAST;
873 break;
874
875 case LocalHost:
876 ip4 = INADDR_LOOPBACK;
877 break;
878
879 case Any:
880 return d->protocol == QHostAddress::AnyIPProtocol;
881
882 case AnyIPv4:
883 break;
884
885 case LocalHostIPv6:
886 case AnyIPv6:
887 if (d->protocol == QHostAddress::IPv6Protocol) {
888 quint64 second = quint8(other == LocalHostIPv6); // 1 for localhost, 0 for any
889 return d->a6_64.c[0] == 0 && d->a6_64.c[1] == qToBigEndian(source: second);
890 }
891 return false;
892 }
893
894 // common IPv4 part
895 return d->protocol == QHostAddress::IPv4Protocol && d->a == ip4;
896}
897
898/*!
899 Returns \c true if this host address is not valid for any host or interface.
900
901 The default constructor creates a null address.
902
903 \sa QHostAddress::Null
904*/
905bool QHostAddress::isNull() const
906{
907 return d->protocol == QHostAddress::UnknownNetworkLayerProtocol;
908}
909
910/*!
911 \since 4.5
912
913 Returns \c true if this IP is in the subnet described by the network
914 prefix \a subnet and netmask \a netmask.
915
916 An IP is considered to belong to a subnet if it is contained
917 between the lowest and the highest address in that subnet. In the
918 case of IP version 4, the lowest address is the network address,
919 while the highest address is the broadcast address.
920
921 The \a subnet argument does not have to be the actual network
922 address (the lowest address in the subnet). It can be any valid IP
923 belonging to that subnet. In particular, if it is equal to the IP
924 address held by this object, this function will always return true
925 (provided the netmask is a valid value).
926
927 \sa parseSubnet()
928*/
929bool QHostAddress::isInSubnet(const QHostAddress &subnet, int netmask) const
930{
931 if (subnet.protocol() != d->protocol || netmask < 0)
932 return false;
933
934 union {
935 quint32 ip;
936 quint8 data[4];
937 } ip4, net4;
938 const quint8 *ip;
939 const quint8 *net;
940 if (d->protocol == QHostAddress::IPv4Protocol) {
941 if (netmask > 32)
942 netmask = 32;
943 ip4.ip = qToBigEndian(source: d->a);
944 net4.ip = qToBigEndian(source: subnet.d->a);
945 ip = ip4.data;
946 net = net4.data;
947 } else if (d->protocol == QHostAddress::IPv6Protocol) {
948 if (netmask > 128)
949 netmask = 128;
950 ip = d->a6.c;
951 net = subnet.d->a6.c;
952 } else {
953 return false;
954 }
955
956 if (netmask >= 8 && memcmp(s1: ip, s2: net, n: netmask / 8) != 0)
957 return false;
958 if ((netmask & 7) == 0)
959 return true;
960
961 // compare the last octet now
962 quint8 bytemask = 256 - (1 << (8 - (netmask & 7)));
963 quint8 ipbyte = ip[netmask / 8];
964 quint8 netbyte = net[netmask / 8];
965 return (ipbyte & bytemask) == (netbyte & bytemask);
966}
967
968/*!
969 \since 4.5
970 \overload
971
972 Returns \c true if this IP is in the subnet described by \a
973 subnet. The QHostAddress member of \a subnet contains the network
974 prefix and the int (second) member contains the netmask (prefix
975 length).
976*/
977bool QHostAddress::isInSubnet(const QPair<QHostAddress, int> &subnet) const
978{
979 return isInSubnet(subnet: subnet.first, netmask: subnet.second);
980}
981
982
983/*!
984 \since 4.5
985
986 Parses the IP and subnet information contained in \a subnet and
987 returns the network prefix for that network and its prefix length.
988
989 The IP address and the netmask must be separated by a slash
990 (/).
991
992 This function supports arguments in the form:
993 \list
994 \li 123.123.123.123/n where n is any value between 0 and 32
995 \li 123.123.123.123/255.255.255.255
996 \li <ipv6-address>/n where n is any value between 0 and 128
997 \endlist
998
999 For IP version 4, this function accepts as well missing trailing
1000 components (i.e., less than 4 octets, like "192.168.1"), followed
1001 or not by a dot. If the netmask is also missing in that case, it
1002 is set to the number of octets actually passed (in the example
1003 above, it would be 24, for 3 octets).
1004
1005 \sa isInSubnet()
1006*/
1007QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet)
1008{
1009 // We support subnets in the form:
1010 // ddd.ddd.ddd.ddd/nn
1011 // ddd.ddd.ddd/nn
1012 // ddd.ddd/nn
1013 // ddd/nn
1014 // ddd.ddd.ddd.
1015 // ddd.ddd.ddd
1016 // ddd.ddd.
1017 // ddd.ddd
1018 // ddd.
1019 // ddd
1020 // <ipv6-address>/nn
1021 //
1022 // where nn can be an IPv4-style netmask for the IPv4 forms
1023
1024 const QPair<QHostAddress, int> invalid = qMakePair(value1: QHostAddress(), value2: -1);
1025 if (subnet.isEmpty())
1026 return invalid;
1027
1028 qsizetype slash = subnet.indexOf(ch: u'/');
1029 QStringView netStr(subnet);
1030 if (slash != -1)
1031 netStr.truncate(n: slash);
1032
1033 int netmask = -1;
1034 bool isIpv6 = netStr.contains(c: u':');
1035
1036 if (slash != -1) {
1037 // is the netmask given in IP-form or in bit-count form?
1038 if (!isIpv6 && subnet.indexOf(ch: u'.', from: slash + 1) != -1) {
1039 // IP-style, convert it to bit-count form
1040 QHostAddress mask;
1041 QNetmask parser;
1042 if (!mask.setAddress(subnet.mid(position: slash + 1)))
1043 return invalid;
1044 if (!parser.setAddress(mask))
1045 return invalid;
1046 netmask = parser.prefixLength();
1047 } else {
1048 bool ok;
1049 netmask = QStringView{subnet}.mid(pos: slash + 1).toUInt(ok: &ok);
1050 if (!ok)
1051 return invalid; // failed to parse the subnet
1052 }
1053 }
1054
1055 if (isIpv6) {
1056 // looks like it's an IPv6 address
1057 if (netmask > 128)
1058 return invalid; // invalid netmask
1059 if (netmask < 0)
1060 netmask = 128;
1061
1062 QHostAddress net;
1063 if (!net.setAddress(netStr.toString()))
1064 return invalid; // failed to parse the IP
1065
1066 clearBits(where: net.d->a6.c, start: netmask, end: 128);
1067 return qMakePair(value1&: net, value2&: netmask);
1068 }
1069
1070 if (netmask > 32)
1071 return invalid; // invalid netmask
1072
1073 // parse the address manually
1074 auto parts = netStr.split(sep: u'.');
1075 if (parts.isEmpty() || parts.size() > 4)
1076 return invalid; // invalid IPv4 address
1077
1078 if (parts.constLast().isEmpty())
1079 parts.removeLast();
1080
1081 quint32 addr = 0;
1082 for (int i = 0; i < parts.size(); ++i) {
1083 bool ok;
1084 uint byteValue = parts.at(i).toUInt(ok: &ok);
1085 if (!ok || byteValue > 255)
1086 return invalid; // invalid IPv4 address
1087
1088 addr <<= 8;
1089 addr += byteValue;
1090 }
1091 addr <<= 8 * (4 - parts.size());
1092 if (netmask == -1) {
1093 netmask = 8 * parts.size();
1094 } else if (netmask == 0) {
1095 // special case here
1096 // x86's instructions "shr" and "shl" do not operate when
1097 // their argument is 32, so the code below doesn't work as expected
1098 addr = 0;
1099 } else if (netmask != 32) {
1100 // clear remaining bits
1101 quint32 mask = quint32(0xffffffff) >> (32 - netmask) << (32 - netmask);
1102 addr &= mask;
1103 }
1104
1105 return qMakePair(value1: QHostAddress(addr), value2&: netmask);
1106}
1107
1108/*!
1109 \since 5.0
1110
1111 returns \c true if the address is the IPv6 loopback address, or any
1112 of the IPv4 loopback addresses.
1113*/
1114bool QHostAddress::isLoopback() const
1115{
1116 return d->classify() == LoopbackAddress;
1117}
1118
1119/*!
1120 \since 5.11
1121
1122 Returns \c true if the address is an IPv4 or IPv6 global address, \c false
1123 otherwise. A global address is an address that is not reserved for
1124 special purposes (like loopback or multicast) or future purposes.
1125
1126 Note that IPv6 unique local unicast addresses are considered global
1127 addresses (see isUniqueLocalUnicast()), as are IPv4 addresses reserved for
1128 local networks by \l {RFC 1918}.
1129
1130 Also note that IPv6 site-local addresses are deprecated and should be
1131 considered as global in new applications. This function returns true for
1132 site-local addresses too.
1133
1134 \sa isLoopback(), isSiteLocal(), isUniqueLocalUnicast(), isPrivateUse()
1135*/
1136bool QHostAddress::isGlobal() const
1137{
1138 return d->classify() & GlobalAddress; // GlobalAddress is a bit
1139}
1140
1141/*!
1142 \since 5.11
1143
1144 Returns \c true if the address is an IPv4 or IPv6 link-local address, \c
1145 false otherwise.
1146
1147 An IPv4 link-local address is an address in the network 169.254.0.0/16. An
1148 IPv6 link-local address is one in the network fe80::/10. See the
1149 \l{https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml}{IANA
1150 IPv6 Address Space} registry for more information.
1151
1152 \sa isLoopback(), isGlobal(), isMulticast(), isSiteLocal(), isUniqueLocalUnicast(), isPrivateUse()
1153*/
1154bool QHostAddress::isLinkLocal() const
1155{
1156 return d->classify() == LinkLocalAddress;
1157}
1158
1159/*!
1160 \since 5.11
1161
1162 Returns \c true if the address is an IPv6 site-local address, \c
1163 false otherwise.
1164
1165 An IPv6 site-local address is one in the network fec0::/10. See the
1166 \l{https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml}{IANA
1167 IPv6 Address Space} registry for more information.
1168
1169 IPv6 site-local addresses are deprecated and should not be depended upon in
1170 new applications. New applications should not depend on this function and
1171 should consider site-local addresses the same as global (which is why
1172 isGlobal() also returns true). Site-local addresses were replaced by Unique
1173 Local Addresses (ULA).
1174
1175 \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast(), isPrivateUse()
1176*/
1177bool QHostAddress::isSiteLocal() const
1178{
1179 return d->classify() == SiteLocalAddress;
1180}
1181
1182/*!
1183 \since 5.11
1184
1185 Returns \c true if the address is an IPv6 unique local unicast address, \c
1186 false otherwise.
1187
1188 An IPv6 unique local unicast address is one in the network fc00::/7. See the
1189 \l{https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml}
1190 {IANA IPv6 Address Space} registry for more information.
1191
1192 Note that Unique local unicast addresses count as global addresses too. RFC
1193 4193 says that, in practice, "applications may treat these addresses like
1194 global scoped addresses." Only routers need care about the distinction.
1195
1196 \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast(), isPrivateUse()
1197*/
1198bool QHostAddress::isUniqueLocalUnicast() const
1199{
1200 return d->classify() == UniqueLocalAddress;
1201}
1202
1203/*!
1204 \since 5.6
1205
1206 Returns \c true if the address is an IPv4 or IPv6 multicast address, \c
1207 false otherwise.
1208
1209 \sa isLoopback(), isGlobal(), isLinkLocal(), isSiteLocal(), isUniqueLocalUnicast(), isPrivateUse()
1210*/
1211bool QHostAddress::isMulticast() const
1212{
1213 return d->classify() == MulticastAddress;
1214}
1215
1216/*!
1217 \since 5.11
1218
1219 Returns \c true if the address is the IPv4 broadcast address, \c false
1220 otherwise. The IPv4 broadcast address is 255.255.255.255.
1221
1222 Note that this function does not return true for an IPv4 network's local
1223 broadcast address. For that, please use \l QNetworkInterface to obtain the
1224 broadcast addresses of the local machine.
1225
1226 \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast(), isPrivateUse()
1227*/
1228bool QHostAddress::isBroadcast() const
1229{
1230 return d->classify() == BroadcastAddress;
1231}
1232
1233/*!
1234 \since 6.6
1235
1236 Returns \c true if the address is an IPv6 unique local unicast address or
1237 IPv4 address reserved for local networks by \l {RFC 1918}, \c false otherwise.
1238
1239 \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast(), isBroadcast()
1240*/
1241bool QHostAddress::isPrivateUse() const
1242{
1243 const AddressClassification classification = d->classify();
1244 return (classification == PrivateNetworkAddress) || (classification == UniqueLocalAddress);
1245}
1246
1247#ifndef QT_NO_DEBUG_STREAM
1248QDebug operator<<(QDebug d, const QHostAddress &address)
1249{
1250 QDebugStateSaver saver(d);
1251 d.resetFormat().nospace();
1252 if (address == QHostAddress::Any)
1253 d << "QHostAddress(QHostAddress::Any)";
1254 else
1255 d << "QHostAddress(" << address.toString() << ')';
1256 return d;
1257}
1258#endif
1259
1260/*!
1261 \since 5.0
1262 \relates QHostAddress
1263 Returns a hash of the host address \a key, using \a seed to seed the calculation.
1264*/
1265size_t qHash(const QHostAddress &key, size_t seed) noexcept
1266{
1267 return qHashBits(p: key.d->a6.c, size: 16, seed);
1268}
1269
1270/*!
1271 \fn bool QHostAddress::operator==(QHostAddress::SpecialAddress lhs, const QHostAddress &rhs)
1272
1273 Returns \c true if special address \a lhs is the same as host address \a rhs;
1274 otherwise returns \c false.
1275
1276 \sa isEqual()
1277*/
1278
1279/*!
1280 \fn bool QHostAddress::operator!=(QHostAddress::SpecialAddress lhs, const QHostAddress &rhs)
1281 \since 5.9
1282
1283 Returns \c false if special address \a lhs is the same as host address \a rhs;
1284 otherwise returns \c true.
1285
1286 \sa isEqual()
1287*/
1288
1289#ifndef QT_NO_DATASTREAM
1290
1291/*! \relates QHostAddress
1292
1293 Writes host address \a address to the stream \a out and returns a reference
1294 to the stream.
1295
1296 \sa {Serializing Qt Data Types}
1297*/
1298QDataStream &operator<<(QDataStream &out, const QHostAddress &address)
1299{
1300 qint8 prot;
1301 prot = qint8(address.protocol());
1302 out << prot;
1303 switch (address.protocol()) {
1304 case QHostAddress::UnknownNetworkLayerProtocol:
1305 case QHostAddress::AnyIPProtocol:
1306 break;
1307 case QHostAddress::IPv4Protocol:
1308 out << address.toIPv4Address();
1309 break;
1310 case QHostAddress::IPv6Protocol:
1311 {
1312 Q_IPV6ADDR ipv6 = address.toIPv6Address();
1313 for (int i = 0; i < 16; ++i)
1314 out << ipv6[i];
1315 out << address.scopeId();
1316 }
1317 break;
1318 }
1319 return out;
1320}
1321
1322/*! \relates QHostAddress
1323
1324 Reads a host address into \a address from the stream \a in and returns a
1325 reference to the stream.
1326
1327 \sa {Serializing Qt Data Types}
1328*/
1329QDataStream &operator>>(QDataStream &in, QHostAddress &address)
1330{
1331 qint8 prot;
1332 in >> prot;
1333 switch (QHostAddress::NetworkLayerProtocol(prot)) {
1334 case QHostAddress::UnknownNetworkLayerProtocol:
1335 address.clear();
1336 break;
1337 case QHostAddress::IPv4Protocol:
1338 {
1339 quint32 ipv4;
1340 in >> ipv4;
1341 address.setAddress(ipv4);
1342 }
1343 break;
1344 case QHostAddress::IPv6Protocol:
1345 {
1346 Q_IPV6ADDR ipv6;
1347 for (int i = 0; i < 16; ++i)
1348 in >> ipv6[i];
1349 address.setAddress(ipv6);
1350
1351 QString scope;
1352 in >> scope;
1353 address.setScopeId(scope);
1354 }
1355 break;
1356 case QHostAddress::AnyIPProtocol:
1357 address = QHostAddress::Any;
1358 break;
1359 default:
1360 address.clear();
1361 in.setStatus(QDataStream::ReadCorruptData);
1362 }
1363 return in;
1364}
1365
1366#endif //QT_NO_DATASTREAM
1367
1368QT_END_NAMESPACE
1369
1370#include "moc_qhostaddress.cpp"
1371

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtbase/src/network/kernel/qhostaddress.cpp