File indexing completed on 2024-04-14 14:10:27
0001 /* 0002 SPDX-FileCopyrightText: 2016 Alex Spataru 0003 SPDX-License-Identifier: MIT 0004 */ 0005 0006 #include "qMDNS.h" 0007 0008 #include <QHostInfo> 0009 #include <QUdpSocket> 0010 #include <QHostAddress> 0011 #include <QNetworkInterface> 0012 0013 #ifdef Q_OS_LINUX 0014 #include <sys/socket.h> 0015 #endif 0016 0017 #include "kstars_debug.h" 0018 /* 0019 * DNS port and mutlicast addresses 0020 */ 0021 const quint16 MDNS_PORT = 5353; 0022 const QHostAddress IPV6_ADDRESS = QHostAddress ("FF02::FB"); 0023 const QHostAddress IPV4_ADDRESS = QHostAddress ("224.0.0.251"); 0024 0025 /* 0026 * mDNS/DNS operation flags 0027 */ 0028 const quint16 kQR_Query = 0x0000; 0029 const quint16 kQR_Response = 0x8000; 0030 const quint16 kRecordA = 0x0001; 0031 const quint16 kRecordAAAA = 0x001C; 0032 const quint16 kNsecType = 0x002F; 0033 const quint16 kFQDN_Separator = 0x0000; 0034 const quint16 kFQDN_Length = 0xC00C; 0035 const quint16 kIN_BitFlush = 0x8001; 0036 const quint16 kIN_Normal = 0x0001; 0037 0038 /* 0039 * DNS query properties 0040 */ 0041 const quint16 kQuery_QDCOUNT = 0x02; 0042 const quint16 kQuery_ANCOUNT = 0x00; 0043 const quint16 kQuery_NSCOUNT = 0x00; 0044 const quint16 kQuery_ARCOUNT = 0x00; 0045 0046 /* 0047 * DNS response properties 0048 */ 0049 const quint16 kResponse_QDCOUNT = 0x00; 0050 const quint16 kResponse_ANCOUNT = 0x01; 0051 const quint16 kResponse_NSCOUNT = 0x00; 0052 const quint16 kResponse_ARCOUNT = 0x02; 0053 0054 /* Packet constants */ 0055 const int MIN_LENGTH = 13; 0056 const int IPI_LENGTH = 10; 0057 const int IP4_LENGTH = IPI_LENGTH + 4; 0058 const int IP6_LENGTH = IPI_LENGTH + 16; 0059 0060 /** 0061 * Encodes the 16-bit \a number as two 8-bit numbers in a byte array 0062 */ 0063 QByteArray ENCODE_16_BIT (quint16 number) 0064 { 0065 QByteArray data; 0066 data.append ((number & 0xff00) >> 8); 0067 data.append ((number & 0xff)); 0068 return data; 0069 } 0070 0071 /** 0072 * Encodes the 32-bit \a number as four 8-bit numbers 0073 */ 0074 QByteArray ENCODE_32_BIT (quint32 number) 0075 { 0076 QByteArray data; 0077 data.append ((number & 0xff000000UL) >> 24); 0078 data.append ((number & 0x00ff0000UL) >> 16); 0079 data.append ((number & 0x0000ff00UL) >> 8); 0080 data.append ((number & 0x000000ffUL)); 0081 return data; 0082 } 0083 0084 /** 0085 * Obtains the 16-bit number stored in the \a upper and \a lower 8-bit numbers 0086 */ 0087 quint16 DECODE_16_BIT (quint8 upper, quint8 lower) 0088 { 0089 return (quint16) ((upper << 8) | lower); 0090 } 0091 0092 /** 0093 * Binds the given \a socket to the given \a address and \a port. 0094 * Under GNU/Linux, this function implements a workaround of QTBUG-33419. 0095 */ 0096 bool BIND (QUdpSocket* socket, const QHostAddress &address, const int port) 0097 { 0098 if (!socket) 0099 return false; 0100 0101 #ifdef Q_OS_LINUX 0102 int reuse = 1; 0103 int domain = PF_UNSPEC; 0104 0105 if (address.protocol() == QAbstractSocket::IPv4Protocol) 0106 domain = PF_INET; 0107 else if (address.protocol() == QAbstractSocket::IPv6Protocol) 0108 domain = PF_INET6; 0109 0110 socket->setSocketDescriptor (::socket (domain, SOCK_DGRAM, 0), 0111 QUdpSocket::UnconnectedState); 0112 0113 setsockopt (socket->socketDescriptor(), SOL_SOCKET, SO_REUSEADDR, 0114 &reuse, sizeof (reuse)); 0115 #endif 0116 0117 return socket->bind (address, port, 0118 QUdpSocket::ShareAddress | 0119 QUdpSocket::ReuseAddressHint); 0120 } 0121 0122 qMDNS::qMDNS() 0123 { 0124 /* Set default TTL to 4500 seconds */ 0125 m_ttl = 4500; 0126 0127 /* Initialize sockets */ 0128 m_IPv4Socket = new QUdpSocket (this); 0129 m_IPv6Socket = new QUdpSocket (this); 0130 0131 /* Read and interpret data received from mDNS group */ 0132 connect (m_IPv4Socket, &QUdpSocket::readyRead, this, &qMDNS::onReadyRead); 0133 connect (m_IPv6Socket, &QUdpSocket::readyRead, this, &qMDNS::onReadyRead); 0134 0135 /* Bind the sockets to the mDNS multicast group */ 0136 if (BIND (m_IPv4Socket, QHostAddress::AnyIPv4, MDNS_PORT)) 0137 m_IPv4Socket->joinMulticastGroup (IPV4_ADDRESS); 0138 if (BIND (m_IPv6Socket, QHostAddress::AnyIPv6, MDNS_PORT)) 0139 m_IPv6Socket->joinMulticastGroup (IPV6_ADDRESS); 0140 } 0141 0142 qMDNS::~qMDNS() 0143 { 0144 delete m_IPv4Socket; 0145 delete m_IPv6Socket; 0146 } 0147 0148 /** 0149 * Returns the only running instance of this class 0150 */ 0151 qMDNS* qMDNS::getInstance() 0152 { 0153 static qMDNS instance; 0154 return &instance; 0155 } 0156 0157 /** 0158 * Returns the mDNS name assigned to the client computer 0159 */ 0160 QString qMDNS::hostName() const 0161 { 0162 return m_hostName; 0163 } 0164 0165 /** 0166 * Ensures that the given \a string is a valid mDNS/DNS address. 0167 */ 0168 QString qMDNS::getAddress (const QString &string) 0169 { 0170 QString address = string; 0171 0172 if (!string.endsWith (".local") && !string.contains (".")) 0173 address = string + ".local"; 0174 0175 if (string.endsWith (".")) 0176 return ""; 0177 0178 return address; 0179 } 0180 0181 /** 0182 * Changes the TTL send to other computers in the mDNS network 0183 */ 0184 void qMDNS::setTTL (const quint32 ttl) 0185 { 0186 m_ttl = ttl; 0187 } 0188 0189 /** 0190 * Performs a mDNS lookup to find the given host \a name. 0191 * If \a preferIPv6 is set to \c true, then this function will generate a 0192 * packet that requests an AAAA-type Resource Record instead of an A-type 0193 * Resource Record. 0194 */ 0195 void qMDNS::lookup (const QString &name) 0196 { 0197 /* The host name is empty, abort lookup */ 0198 if (name.isEmpty()) 0199 { 0200 qCWarning(KSTARS) << Q_FUNC_INFO << "Empty host name specified"; 0201 return; 0202 } 0203 0204 qCInfo(KSTARS) << "Starting lookup for service" << name; 0205 0206 m_serviceName = name; 0207 0208 /* Ensure that we host name is a valid DNS address */ 0209 QString address = getAddress (name); 0210 if (address.isEmpty()) 0211 return; 0212 0213 /* Check if we are dealing with a normal DNS address */ 0214 if (!address.endsWith (".local", Qt::CaseInsensitive)) 0215 { 0216 QHostInfo::lookupHost (address, this, SIGNAL (hostFound(QHostInfo))); 0217 return; 0218 } 0219 0220 /* Perform a mDNS lookup */ 0221 else 0222 { 0223 QByteArray data; 0224 0225 /* Get the host name and domain */ 0226 QString host = address.split (".").first(); 0227 QString domain = address.split (".").last(); 0228 0229 /* Check that domain length is valid */ 0230 if (host.length() > 255) 0231 { 0232 qWarning() << Q_FUNC_INFO << host << "is too long!"; 0233 return; 0234 } 0235 0236 /* Create header & flags */ 0237 data.append (ENCODE_16_BIT (0)); 0238 data.append (ENCODE_16_BIT (kQR_Query)); 0239 data.append (ENCODE_16_BIT (kQuery_QDCOUNT)); 0240 data.append (ENCODE_16_BIT (kQuery_ANCOUNT)); 0241 data.append (ENCODE_16_BIT (kQuery_NSCOUNT)); 0242 data.append (ENCODE_16_BIT (kQuery_ARCOUNT)); 0243 0244 /* Add name data */ 0245 data.append (host.length()); 0246 data.append (host.toUtf8()); 0247 0248 /* Add domain data */ 0249 data.append (domain.length()); 0250 data.append (domain.toUtf8()); 0251 0252 /* Add FQDN/TLD separator */ 0253 data.append ((char) kFQDN_Separator); 0254 0255 /* Add IPv4 record type */ 0256 data.append (ENCODE_16_BIT (kRecordA)); 0257 data.append (ENCODE_16_BIT (kIN_Normal)); 0258 0259 /* Add FQDN length */ 0260 data.append (ENCODE_16_BIT (kFQDN_Length)); 0261 0262 /* Add IPv6 record type */ 0263 data.append (ENCODE_16_BIT (kRecordAAAA)); 0264 data.append (ENCODE_16_BIT (kIN_Normal)); 0265 0266 /* Send the datagram */ 0267 sendPacket (data); 0268 } 0269 } 0270 0271 /** 0272 * Changes the host name of the client computer 0273 */ 0274 void qMDNS::setHostName (const QString &name) 0275 { 0276 if (name.contains (".") && !name.endsWith (".local")) 0277 { 0278 qWarning() << "Invalid domain name"; 0279 return; 0280 } 0281 0282 m_hostName = getAddress (name); 0283 } 0284 0285 /** 0286 * Called when we receive data from a mDNS client on the network. 0287 */ 0288 void qMDNS::onReadyRead() 0289 { 0290 QByteArray data; 0291 QUdpSocket* socket = qobject_cast<QUdpSocket*> (sender()); 0292 0293 /* Read data from the socket */ 0294 if (socket) 0295 { 0296 while (socket->hasPendingDatagrams()) 0297 { 0298 data.resize (socket->pendingDatagramSize()); 0299 socket->readDatagram (data.data(), data.size()); 0300 } 0301 } 0302 0303 /* Packet is a valid mDNS datagram */ 0304 if (data.length() > MIN_LENGTH) 0305 { 0306 quint16 flag = DECODE_16_BIT (data.at (2), data.at (3)); 0307 0308 if (flag == kQR_Query) 0309 readQuery (data); 0310 0311 else if (flag >= kQR_Response) 0312 readResponse (data); 0313 } 0314 } 0315 0316 /** 0317 * Reads the given query \a data and instructs the class to send a response 0318 * packet if the query is looking for the host name assigned to this computer. 0319 */ 0320 void qMDNS::readQuery (const QByteArray &data) 0321 { 0322 /* Query packet is invalid */ 0323 if (data.length() < MIN_LENGTH) 0324 return; 0325 0326 /* Get the lengths of the host name and domain */ 0327 int n = 12; 0328 int hostLength = data.at (n); 0329 int domainLength = data.at (n + hostLength + 1); 0330 0331 /* Read the host name until we stumble with the domain length character */ 0332 QString name; 0333 int h = n + 1; 0334 while (data.at (h) != (char) domainLength) 0335 { 0336 name.append (data.at (h)); 0337 ++h; 0338 } 0339 0340 /* Read domain length until we stumble with the FQDN/TLD separator */ 0341 QString domain; 0342 int d = n + hostLength + 2; 0343 while (data.at (d) != kFQDN_Separator) 0344 { 0345 domain.append (data.at (d)); 0346 ++d; 0347 } 0348 0349 /* Construct the full host name (name + domain) */ 0350 QString host = getAddress (name + "." + domain); 0351 0352 /* The query packet wants to know more about us */ 0353 if (host.toLower() == hostName().toLower()) 0354 sendResponse (DECODE_16_BIT (data.at (0), data.at (1))); 0355 } 0356 0357 /** 0358 * Sends the given \a data to both the IPv4 and IPv6 mDNS multicast groups 0359 */ 0360 void qMDNS::sendPacket (const QByteArray &data) 0361 { 0362 if (!data.isEmpty()) 0363 { 0364 m_IPv4Socket->writeDatagram (data, IPV4_ADDRESS, MDNS_PORT); 0365 m_IPv6Socket->writeDatagram (data, IPV6_ADDRESS, MDNS_PORT); 0366 } 0367 } 0368 0369 /** 0370 * Reads the given \a data of a response packet and obtains: 0371 * - The remote host name 0372 * - The remote IPv4 0373 * - The remote IPv6 0374 */ 0375 void qMDNS::readResponse (const QByteArray &data) 0376 { 0377 if (data.length() < MIN_LENGTH) 0378 return; 0379 0380 qCDebug(KSTARS) << data; 0381 0382 // data must contain service name 0383 if (data.contains(m_serviceName.toLatin1()) == false) 0384 return; 0385 0386 QString host = getHostNameFromResponse (data); 0387 QList<QHostAddress> addresses = getAddressesFromResponse (data, host); 0388 0389 if (!host.isEmpty() && !addresses.isEmpty()) 0390 { 0391 QHostInfo info; 0392 info.setHostName (host); 0393 info.setAddresses (addresses); 0394 info.setError (QHostInfo::NoError); 0395 0396 qCInfo(KSTARS) << "Found service on" << host; 0397 0398 emit hostFound (info); 0399 } 0400 } 0401 0402 /** 0403 * Sends a response packet with: 0404 * - Our mDNS host name 0405 * - Our IPv4 address 0406 * - Our IPv6 address 0407 */ 0408 void qMDNS::sendResponse (const quint16 query_id) 0409 { 0410 if (!hostName().isEmpty() && hostName().endsWith (".local")) 0411 { 0412 QByteArray data; 0413 0414 /* Get the host name and domain */ 0415 QString host = hostName().split (".").first(); 0416 QString domain = hostName().split (".").last(); 0417 0418 /* Get local IPs */ 0419 quint32 ipv4 = 0; 0420 QList<QIPv6Address> ipv6; 0421 foreach (QHostAddress address, QNetworkInterface::allAddresses()) 0422 { 0423 if (!address.isLoopback()) 0424 { 0425 if (address.protocol() == QAbstractSocket::IPv4Protocol) 0426 ipv4 = (ipv4 == 0 ? address.toIPv4Address() : ipv4); 0427 0428 if (address.protocol() == QAbstractSocket::IPv6Protocol) 0429 ipv6.append (address.toIPv6Address()); 0430 } 0431 } 0432 0433 /* Check that domain length is valid */ 0434 if (host.length() > 255) 0435 { 0436 qCWarning(KSTARS) << Q_FUNC_INFO << host << "is too long!"; 0437 return; 0438 } 0439 0440 /* Create header and flags */ 0441 data.append (ENCODE_16_BIT (query_id)); 0442 data.append (ENCODE_16_BIT (kQR_Response)); 0443 data.append (ENCODE_16_BIT (kResponse_QDCOUNT)); 0444 data.append (ENCODE_16_BIT (kResponse_ANCOUNT)); 0445 data.append (ENCODE_16_BIT (kResponse_NSCOUNT)); 0446 data.append (ENCODE_16_BIT (kResponse_ARCOUNT)); 0447 0448 /* Add name data */ 0449 data.append (host.length()); 0450 data.append (host.toUtf8()); 0451 0452 /* Add domain data and FQDN/TLD separator */ 0453 data.append (domain.length()); 0454 data.append (domain.toUtf8()); 0455 data.append ((char) kFQDN_Separator); 0456 0457 /* Add IPv4 address header */ 0458 data.append (ENCODE_16_BIT (kRecordA)); 0459 data.append (ENCODE_16_BIT (kIN_BitFlush)); 0460 data.append (ENCODE_32_BIT (m_ttl)); 0461 data.append (ENCODE_16_BIT (sizeof (ipv4))); 0462 0463 /* Add IPv4 bytes */ 0464 data.append (ENCODE_32_BIT (ipv4)); 0465 0466 /* Add FQDN offset */ 0467 data.append (ENCODE_16_BIT (kFQDN_Length)); 0468 0469 /* Add IPv6 addresses */ 0470 foreach (QIPv6Address ip, ipv6) 0471 { 0472 data.append (ENCODE_16_BIT (kRecordAAAA)); 0473 data.append (ENCODE_16_BIT (kIN_BitFlush)); 0474 data.append (ENCODE_32_BIT (m_ttl)); 0475 data.append (ENCODE_16_BIT (sizeof (ip.c))); 0476 0477 /* Add IPv6 bytes */ 0478 for (unsigned long i = 0; i < sizeof (ip.c); ++i) 0479 data.append (ip.c [i]); 0480 0481 /* Add FQDN offset */ 0482 data.append (ENCODE_16_BIT (kFQDN_Length)); 0483 } 0484 0485 /* TODO: Generate NSEC code block */ 0486 int nsec_length = 0; 0487 0488 /* Add NSEC data */ 0489 data.append (ENCODE_16_BIT (kNsecType)); 0490 data.append (ENCODE_16_BIT (kIN_BitFlush)); 0491 data.append (ENCODE_32_BIT (m_ttl)); 0492 data.append (ENCODE_16_BIT (nsec_length)); 0493 0494 /* Send the response */ 0495 sendPacket (data); 0496 } 0497 } 0498 0499 /** 0500 * Extracts the host name from the \a data received from the mDNS network. 0501 * The host name begins at byte #12 (when the header and flags end) and ends 0502 * with a mandatory NUL character after the domain. 0503 * 0504 * The host name is constructed in the following way (without spaces): 0505 * \c NAME_LENGTH + \c NAME + \c DOMAIN_LENGTH + \c DOMAIN + \c NUL 0506 * 0507 * For example, appletv.local would be formatted as: 0508 * \c 0x07 + \c appletv + \c 0x05 + \c local + \c 0x00 0509 * 0510 * Or, if you prefer hex data: 0511 * \c { 07 61 70 70 6c 65 74 76 05 6c 6f 63 61 6c 00 } 0512 * \c { 7 a p p l e t v 5 l o c a l 0 } 0513 * 0514 * In order to obtain the full host name (and its mDNS domain), we construct 0515 * the string backwards. When the code notices that the current character is 0516 * the same as the domain length, we know that the domain name has been 0517 * extracted, and thus we can replace the domain length with a dot (.) and 0518 * begin extracting the host name. 0519 */ 0520 QString qMDNS::getHostNameFromResponse (const QByteArray &data) 0521 { 0522 QList<char> list; 0523 QString address = ""; 0524 0525 /* Begin reading host name at byte 13 (byte 12 is the host name length) */ 0526 int n = 13; 0527 0528 /* Read the host name until we stumble with the FQDN/TLD separator */ 0529 while (data.at (n) != kFQDN_Separator) 0530 { 0531 list.append (data.at (n)); 0532 ++n; 0533 } 0534 0535 /* Construct the string backwards (to replace domain length with a dot) */ 0536 for (int i = 0; i < list.count(); ++i) 0537 { 0538 char character = list.at (list.count() - i - 1); 0539 0540 if (character == (char) address.length()) 0541 address.prepend ("."); 0542 else 0543 address.prepend (character); 0544 } 0545 0546 return address; 0547 } 0548 0549 /** 0550 * Extracts the IPv4 from the \a data received from the mDNS network. 0551 * The IPv4 data begins when the host name data ends. 0552 * 0553 * For the packet to contain IPv4 information, the DNS Record Type code must 0554 * be "A" (IPv4) and the DNS Class code should correspond to "IN" (Internet). 0555 * 0556 * Here is the layout of the IPv4 section of the packet: 0557 * 0558 * - DNS Record Type 0559 * - DNS Class Code 0560 * - TTL 0561 * - IP length 0562 * - IP address bytes 0563 * 0564 * This is an example IPv4 section: 0565 * \c {00 01 80 01 00 00 78 00 00 04 99 6d 07 5a} 0566 * 0567 * Data in example section: 0568 * - \c {00 01} Type Codes 0569 * - \c {80 01} Class Codes 0570 * - \c {00 00 78 00} IP TTL 0571 * - \c {00 04} Number of address bytes (length in layman's terms) 0572 * - \c {99 6d 07 5a} IPv4 Address bytes (153, 109, 7, 90) 0573 */ 0574 QString qMDNS::getIPv4FromResponse (const QByteArray &data, 0575 const QString &host) 0576 { 0577 QString ip = ""; 0578 0579 /* n stands for the byte index in which the host name data ends */ 0580 int n = MIN_LENGTH + host.length(); 0581 0582 /* Packet is too small */ 0583 if (data.length() < n + IP4_LENGTH) 0584 return ip; 0585 0586 /* Get the IP type and class codes */ 0587 quint16 typeCode = DECODE_16_BIT (data.at (n + 1), data.at (n + 2)); 0588 quint16 classCode = DECODE_16_BIT (data.at (n + 3), data.at (n + 4)); 0589 0590 /* Check if type and class codes are good */ 0591 if (typeCode != kRecordA || classCode != kIN_BitFlush) 0592 return ip; 0593 0594 /* Skip TTL indicator and obtain the number of address bytes */ 0595 quint8 length = data.at (n + IPI_LENGTH); 0596 0597 /* Append each IPv4 address byte (and decimal dots) to the IP string */ 0598 for (int i = 1; i < length + 1; ++i) 0599 { 0600 ip += QString::number ((quint8) data.at (n + IPI_LENGTH + i)); 0601 ip += (i < length) ? "." : ""; 0602 } 0603 0604 return ip; 0605 } 0606 0607 /** 0608 * Extracts the IPv6 from the \a data received from the mDNS network. 0609 * The IPv6 data begins when the host name data ends. 0610 * 0611 * For the packet to contain IPv6 information, the DNS Record Type code must 0612 * be "AAAA" (IPv6) and the DNS Class code should correspond to "IN" (Internet). 0613 * 0614 * Here is the layout of the IPv4 section of the packet: 0615 * 0616 * - DNS Record Type 0617 * - DNS Class Code 0618 * - TTL 0619 * - IP length 0620 * - IP address bytes 0621 * 0622 * This is an example IPv6 section: 0623 * \c { 00 1c 80 01 00 00 78 00 00 10 fe 80 00 00 00 00 00 00 02 23 32 ff fe b1 21 52 } 0624 * 0625 * Data in example section: 0626 * - \c {00 1c} Type Codes 0627 * - \c {80 01} Class Codes 0628 * - \c {00 00 78 00} IP TTL 0629 * - \c {00 10} Number of address bytes (length in layman's terms) 0630 * - \c {fe 80 00 00 ... 52} IPv6 Address bytes (there are 16 of them) 0631 */ 0632 QStringList qMDNS::getIPv6FromResponse (const QByteArray &data, 0633 const QString &host) 0634 { 0635 QStringList list; 0636 0637 /* Skip the FQDN and IPv4 section */ 0638 int n = MIN_LENGTH + IP4_LENGTH + host.length(); 0639 0640 /* Get the IPv6 list */ 0641 bool isIPv6 = true; 0642 while (isIPv6) 0643 { 0644 /* Skip FQDN bytes */ 0645 n += 2; 0646 0647 /* Packet is invalid */ 0648 if (data.length() < n + IP6_LENGTH) 0649 break; 0650 0651 /* Get the IP type and class codes */ 0652 quint16 typeCode = DECODE_16_BIT (data.at (n + 1), data.at (n + 2)); 0653 quint16 classCode = DECODE_16_BIT (data.at (n + 3), data.at (n + 4)); 0654 isIPv6 = (typeCode == kRecordAAAA && classCode == kIN_BitFlush); 0655 0656 /* IP type and class codes are OK, extract IP */ 0657 if (isIPv6) 0658 { 0659 /* Skip TTL indicator and obtain the number of address bytes */ 0660 quint8 length = data.at (n + IPI_LENGTH); 0661 0662 /* Append each IPv6 address byte (encoded as hex) to the IP string */ 0663 QString ip = ""; 0664 for (int i = 1; i < length + 1; ++i) 0665 { 0666 /* Get the hexadecimal representation of the byte */ 0667 QString byte; 0668 byte.setNum ((quint8) data.at (n + i + IPI_LENGTH), 16); 0669 0670 /* Add the obtained string */ 0671 ip += byte; 0672 0673 /* Append colons after even indexes (except in the last byte) */ 0674 if ((i & 1) == 0 && (i < length)) 0675 ip += ":"; 0676 } 0677 0678 /* Increase the counter to 'jump' to the next section */ 0679 n += 26; 0680 0681 /* Append the obtained IP to the list */ 0682 if (!list.contains (ip)) 0683 list.append (ip); 0684 } 0685 } 0686 0687 return list; 0688 } 0689 0690 /** 0691 * Obtains the IPv4 and IPv6 addresses from the received data. 0692 * \note This function will only generate a list with the valid IP addresses. 0693 */ 0694 QList<QHostAddress> qMDNS::getAddressesFromResponse (const QByteArray &data, 0695 const QString &host) 0696 { 0697 QList<QHostAddress> list; 0698 0699 /* Add IPv4 address */ 0700 QHostAddress IPv4Address = QHostAddress (getIPv4FromResponse (data, host)); 0701 if (!IPv4Address.isNull()) 0702 list.append (IPv4Address); 0703 0704 /* Add IPv6 addresses */ 0705 foreach (QString ip, getIPv6FromResponse (data, host)) 0706 { 0707 QHostAddress address = QHostAddress (ip); 0708 if (!address.isNull()) 0709 list.append (address); 0710 } 0711 0712 return list; 0713 }