File indexing completed on 2023-09-24 04:04:39
0001 /* -*- C++ -*- 0002 * Copyright (C) 2003,2004 Thiago Macieira <thiago@kde.org> 0003 * 0004 * 0005 * Permission is hereby granted, free of charge, to any person obtaining 0006 * a copy of this software and associated documentation files (the 0007 * "Software"), to deal in the Software without restriction, including 0008 * without limitation the rights to use, copy, modify, merge, publish, 0009 * distribute, sublicense, and/or sell copies of the Software, and to 0010 * permit persons to whom the Software is furnished to do so, subject to 0011 * the following conditions: 0012 * 0013 * The above copyright notice and this permission notice shall be included 0014 * in all copies or substantial portions of the Software. 0015 * 0016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 0017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 0018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 0019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 0020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 0021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 0022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0023 */ 0024 0025 #include "k3resolverstandardworkers_p.h" 0026 0027 #include <config-network.h> 0028 0029 #include <sys/types.h> 0030 #include <sys/socket.h> 0031 #include <sys/un.h> 0032 #include <netinet/in.h> 0033 #include <netdb.h> 0034 #include <errno.h> 0035 #include <string.h> 0036 #include <stdlib.h> 0037 #include <unistd.h> 0038 0039 #if HAVE_NET_IF_H 0040 #include <net/if.h> 0041 #endif 0042 0043 #include <QFile> 0044 #include <QList> 0045 #include <QMutex> 0046 #include <QTextStream> 0047 #include <QThread> 0048 #ifdef Q_OS_WIN 0049 #include <winsock2.h> 0050 #endif 0051 0052 #include "kdebug.h" 0053 #include "kglobal.h" 0054 #include "kcomponentdata.h" 0055 #include "kstandarddirs.h" 0056 0057 #include "k3resolver.h" 0058 #include "k3socketaddress.h" 0059 0060 struct hostent; 0061 struct addrinfo; 0062 0063 using namespace KNetwork; 0064 using namespace KNetwork::Internal; 0065 0066 static bool hasIPv6() 0067 { 0068 #ifdef Q_OS_WIN 0069 extern void KNetwork_initSocket(); 0070 KNetwork_initSocket(); 0071 #endif 0072 #ifdef AF_INET6 0073 if (!qgetenv("KDE_NO_IPV6").isEmpty()) { 0074 return false; 0075 } 0076 0077 # ifdef Q_OS_WIN 0078 SOCKET s = ::socket(AF_INET6, SOCK_STREAM, 0); 0079 if (s == INVALID_SOCKET) { 0080 return false; 0081 } 0082 ::closesocket(s); 0083 # else 0084 int fd = ::socket(AF_INET6, SOCK_STREAM, 0); 0085 if (fd == -1) { 0086 return false; 0087 } 0088 ::close(fd); 0089 # endif 0090 return true; 0091 #else 0092 return false; 0093 #endif 0094 } 0095 0096 // blacklist management 0097 static QMutex blacklistMutex; // KDE4: change to a QReadWriteLock 0098 QStringList KBlacklistWorker::blacklist; 0099 0100 void KBlacklistWorker::init() 0101 { 0102 if (!KComponentData::hasMainComponent()) { 0103 return; 0104 } 0105 0106 static bool beenhere = false; 0107 0108 if (beenhere) { 0109 return; 0110 } 0111 0112 beenhere = true; 0113 loadBlacklist(); 0114 } 0115 0116 void KBlacklistWorker::loadBlacklist() 0117 { 0118 QMutexLocker locker(&blacklistMutex); 0119 QStringList filelist = KGlobal::dirs()->findAllResources("config", QLatin1String("ipv6blacklist")); 0120 0121 QStringList::ConstIterator it = filelist.constBegin(), 0122 end = filelist.constEnd(); 0123 for (; it != end; ++it) { 0124 // for each file, each line is a domainname to be blacklisted 0125 QFile f(*it); 0126 if (!f.open(QIODevice::ReadOnly)) { 0127 continue; 0128 } 0129 0130 QTextStream stream(&f); 0131 stream.setCodec("latin1"); 0132 for (QString line = stream.readLine(); !line.isNull(); 0133 line = stream.readLine()) { 0134 if (line.isEmpty()) { 0135 continue; 0136 } 0137 0138 // make sure there are no surrounding whitespaces 0139 // and that it starts with . 0140 line = line.trimmed(); 0141 if (line[0] != QLatin1Char('.')) { 0142 line.prepend(QLatin1Char('.')); 0143 } 0144 0145 blacklist.append(line.toLower()); 0146 } 0147 } 0148 } 0149 0150 // checks the blacklist to see if the domain is listed 0151 // it matches the domain ending part 0152 bool KBlacklistWorker::isBlacklisted(const QString &host) 0153 { 0154 KBlacklistWorker::init(); 0155 0156 // empty hostnames cannot be blacklisted 0157 if (host.isEmpty()) { 0158 return false; 0159 } 0160 0161 QString ascii = QLatin1String(KResolver::domainToAscii(host)); 0162 0163 QMutexLocker locker(&blacklistMutex); 0164 0165 // now find out if this hostname is present 0166 QStringList::ConstIterator it = blacklist.constBegin(), 0167 end = blacklist.constEnd(); 0168 for (; it != end; ++it) 0169 if (ascii.endsWith(*it)) { 0170 return true; 0171 } 0172 0173 // no match: 0174 return false; 0175 } 0176 0177 bool KBlacklistWorker::preprocess() 0178 { 0179 if (isBlacklisted(nodeName())) { 0180 results.setError(KResolver::NoName); 0181 finished(); 0182 return true; 0183 } 0184 return false; 0185 } 0186 0187 bool KBlacklistWorker::run() 0188 { 0189 results.setError(KResolver::NoName); 0190 finished(); 0191 return false; // resolution failure 0192 } 0193 0194 namespace 0195 { 0196 /* 0197 * Note on the use of the system resolver functions: 0198 * 0199 * In all cases, we prefer to use the new getaddrinfo(3) call. That means 0200 * it will always be used if it is found. 0201 * 0202 * If it's not found, we have the option to use gethostbyname2_r, 0203 * gethostbyname_r, gethostbyname2 and gethostbyname. If gethostbyname2_r 0204 * is defined, we will use it. 0205 * 0206 * If it's not defined, we have to choose between the non-reentrant 0207 * gethostbyname2 and the reentrant but IPv4-only gethostbyname_r: 0208 * we will choose gethostbyname2 if AF_INET6 is defined. 0209 * 0210 * Lastly, gethostbyname will be used if nothing else is present. 0211 */ 0212 0213 #if !HAVE_GETADDRINFO 0214 0215 # if HAVE_GETHOSTBYNAME2_R 0216 # define USE_GETHOSTBYNAME2_R 0217 # elif HAVE_GETHOSTBYNAME_R && (!defined(AF_INET6) || !HAVE_GETHOSTBYNAME2) 0218 # define USE_GETHOSTBYNAME_R 0219 # elif HAVE_GETHOSTBYNAME2 0220 # define USE_GETHOSTBYNAME2 0221 # else 0222 # define USE_GETHOSTBYNAME 0223 # endif 0224 0225 class GetHostByNameThread: public KResolverWorkerBase 0226 { 0227 public: 0228 QByteArray m_hostname; // might be different! 0229 quint16 m_port; 0230 int m_scopeid; 0231 int m_af; 0232 KResolverResults &results; 0233 0234 GetHostByNameThread(const char *hostname, quint16 port, 0235 int scopeid, int af, KResolverResults *res) : 0236 m_hostname(hostname), m_port(port), m_scopeid(scopeid), m_af(af), 0237 results(*res) 0238 { } 0239 0240 ~GetHostByNameThread() 0241 { } 0242 0243 virtual bool preprocess() 0244 { 0245 return true; 0246 } 0247 0248 virtual bool run(); 0249 0250 void processResults(hostent *he, int my_h_errno); 0251 }; 0252 0253 bool GetHostByNameThread::run() 0254 { 0255 0256 hostent *resultptr; 0257 hostent my_results; 0258 unsigned buflen = 1024; 0259 int res; 0260 int my_h_errno; 0261 char *buf = 0L; 0262 0263 // qDebug("ResolveThread::run(): started threaded gethostbyname for %s (af = %d)", 0264 // m_hostname.data(), m_af); 0265 0266 ResolverLocker resLock(this); 0267 do { 0268 res = 0; 0269 my_h_errno = HOST_NOT_FOUND; 0270 0271 // check blacklist 0272 if (m_af != AF_INET && 0273 KBlacklistWorker::isBlacklisted(QLatin1String(m_hostname))) { 0274 break; 0275 } 0276 0277 # ifdef USE_GETHOSTBYNAME2_R 0278 buf = new char[buflen]; 0279 res = gethostbyname2_r(m_hostname, m_af, &my_results, buf, buflen, 0280 &resultptr, &my_h_errno); 0281 0282 # elif defined(USE_GETHOSTBYNAME_R) 0283 if (m_af == AF_INET) { 0284 buf = new char[buflen]; 0285 res = gethostbyname_r(m_hostname, &my_results, buf, buflen, 0286 &resultptr, &my_h_errno); 0287 } else { 0288 resultptr = 0; // signal error 0289 } 0290 0291 # elif defined(USE_GETHOSTBYNAME2) 0292 // must lock mutex 0293 resultptr = gethostbyname2(m_hostname, m_af); 0294 my_h_errno = h_errno; 0295 0296 # else 0297 if (m_af == AF_INET) { 0298 // must lock mutex 0299 resultptr = gethostbyname(m_hostname); 0300 my_h_errno = h_errno; 0301 } else { 0302 resultptr = 0; 0303 } 0304 # endif 0305 0306 if (resultptr != 0L) { 0307 my_h_errno = 0; 0308 } 0309 // qDebug("GetHostByNameThread::run(): gethostbyname for %s (af = %d) returned: %d", 0310 // m_hostname.data(), m_af, my_h_errno); 0311 0312 if (res == ERANGE) { 0313 // Enlarge the buffer 0314 buflen += 1024; 0315 delete [] buf; 0316 buf = new char[buflen]; 0317 } 0318 0319 if ((res == ERANGE || my_h_errno != 0) && checkResolver()) { 0320 // resolver needs updating, so we might as well do it now 0321 resLock.openClose(); 0322 } 0323 } while (res == ERANGE); 0324 processResults(resultptr, my_h_errno); 0325 0326 delete [] buf; 0327 0328 finished(); 0329 return results.error() == KResolver::NoError; 0330 } 0331 0332 void GetHostByNameThread::processResults(hostent *he, int herrno) 0333 { 0334 if (herrno) { 0335 qDebug("KStandardWorker::processResults: got error %d", herrno); 0336 switch (herrno) { 0337 case HOST_NOT_FOUND: 0338 results.setError(KResolver::NoName); 0339 return; 0340 0341 case TRY_AGAIN: 0342 results.setError(KResolver::TryAgain); 0343 return; 0344 0345 case NO_RECOVERY: 0346 results.setError(KResolver::NonRecoverable); 0347 return; 0348 0349 case NO_ADDRESS: 0350 results.setError(KResolver::NoName); 0351 return; 0352 0353 default: 0354 results.setError(KResolver::UnknownError); 0355 return; 0356 } 0357 } else if (he == 0L) { 0358 results.setError(KResolver::NoName); 0359 return; // this was an error 0360 } 0361 0362 // clear any errors 0363 setError(KResolver::NoError); 0364 results.setError(KResolver::NoError); 0365 0366 // we process results in the reverse order 0367 // that is, we prepend each result to the list of results 0368 int proto = protocol(); 0369 int socktype = socketType(); 0370 if (socktype == 0) { 0371 socktype = SOCK_STREAM; // default 0372 } 0373 0374 QString canon = KResolver::domainToUnicode(QLatin1String(he->h_name)); 0375 KInetSocketAddress sa; 0376 sa.setPort(m_port); 0377 if (he->h_addrtype != AF_INET) { 0378 sa.setScopeId(m_scopeid); // this will also change the socket into IPv6 0379 } 0380 0381 for (int i = 0; he->h_addr_list[i]; i++) { 0382 sa.setHost(KIpAddress(he->h_addr_list[i], he->h_addrtype == AF_INET ? 4 : 6)); 0383 results.prepend(KResolverEntry(sa, socktype, proto, canon, m_hostname)); 0384 // qDebug("KStandardWorker::processResults: adding %s", sa.toString().toLatin1().constData()); 0385 } 0386 // qDebug("KStandardWorker::processResults: added %d entries", i); 0387 } 0388 0389 #else // HAVE_GETADDRINFO 0390 0391 class GetAddrInfoThread: public KResolverWorkerBase 0392 { 0393 public: 0394 QByteArray m_node; 0395 QByteArray m_serv; 0396 int m_af; 0397 int m_flags; 0398 KResolverResults &results; 0399 0400 GetAddrInfoThread(const char *node, const char *serv, int af, int flags, 0401 KResolverResults *res) : 0402 m_node(node), m_serv(serv), m_af(af), m_flags(flags), results(*res) 0403 { } 0404 0405 ~GetAddrInfoThread() override 0406 { } 0407 0408 bool preprocess() override 0409 { 0410 return true; 0411 } 0412 0413 bool run() override; 0414 0415 void processResults(addrinfo *ai, int ret_code, KResolverResults &rr); 0416 }; 0417 0418 bool GetAddrInfoThread::run() 0419 { 0420 // check blacklist 0421 if ((m_af != AF_INET && m_af != AF_UNSPEC) && 0422 KBlacklistWorker::isBlacklisted(QLatin1String(m_node))) { 0423 results.setError(KResolver::NoName); 0424 finished(); 0425 return false; // failed 0426 } 0427 0428 do { 0429 ResolverLocker resLock(this); 0430 0431 // process hints 0432 addrinfo hint; 0433 memset(&hint, 0, sizeof(hint)); 0434 hint.ai_family = m_af; 0435 hint.ai_socktype = socketType(); 0436 hint.ai_protocol = protocol(); 0437 0438 if (hint.ai_socktype == 0) { 0439 hint.ai_socktype = SOCK_STREAM; // default 0440 } 0441 0442 if (m_flags & KResolver::Passive) { 0443 hint.ai_flags |= AI_PASSIVE; 0444 } 0445 if (m_flags & KResolver::CanonName) { 0446 hint.ai_flags |= AI_CANONNAME; 0447 } 0448 # ifdef AI_NUMERICHOST 0449 if (m_flags & KResolver::NoResolve) { 0450 hint.ai_flags |= AI_NUMERICHOST; 0451 } 0452 # endif 0453 # ifdef AI_ADDRCONFIG 0454 hint.ai_flags |= AI_ADDRCONFIG; 0455 # endif 0456 0457 // now we do the blocking processing 0458 if (m_node.isEmpty()) { 0459 m_node = "*"; // krazy:exclude=doublequote_chars 0460 } 0461 0462 addrinfo *result; 0463 int res = getaddrinfo(m_node, m_serv, &hint, &result); 0464 // kDebug(179) << "getaddrinfo(\"" 0465 // << m_node << "\", \"" << m_serv << "\", af=" 0466 // << m_af << ") returned " << res << endl; 0467 0468 if (res != 0) { 0469 if (checkResolver()) { 0470 // resolver requires reinitialisation 0471 resLock.openClose(); 0472 continue; 0473 } 0474 0475 switch (res) { 0476 case EAI_BADFLAGS: 0477 results.setError(KResolver::BadFlags); 0478 break; 0479 0480 #ifdef EAI_NODATA 0481 // In some systems, EAI_NODATA was #define'd to EAI_NONAME which would break this case. 0482 #if EAI_NODATA != EAI_NONAME 0483 case EAI_NODATA: // it was removed in RFC 3493 0484 #endif 0485 #endif 0486 case EAI_NONAME: 0487 results.setError(KResolver::NoName); 0488 break; 0489 0490 case EAI_AGAIN: 0491 results.setError(KResolver::TryAgain); 0492 break; 0493 0494 case EAI_FAIL: 0495 results.setError(KResolver::NonRecoverable); 0496 break; 0497 0498 case EAI_FAMILY: 0499 results.setError(KResolver::UnsupportedFamily); 0500 break; 0501 0502 case EAI_SOCKTYPE: 0503 results.setError(KResolver::UnsupportedSocketType); 0504 break; 0505 0506 case EAI_SERVICE: 0507 results.setError(KResolver::UnsupportedService); 0508 break; 0509 0510 case EAI_MEMORY: 0511 results.setError(KResolver::Memory); 0512 break; 0513 0514 #ifdef EAI_SYSTEM // not available on windows 0515 case EAI_SYSTEM: 0516 results.setError(KResolver::SystemError, errno); 0517 break; 0518 #endif 0519 default: 0520 results.setError(KResolver::UnknownError, errno); 0521 break; 0522 } 0523 0524 finished(); 0525 return false; // failed 0526 } 0527 0528 // if we are here, lookup succeeded 0529 QString canon; 0530 const char *previous_canon = nullptr; 0531 0532 for (addrinfo *p = result; p; p = p->ai_next) { 0533 // cache the last canon name to avoid doing the ToUnicode processing unnecessarily 0534 if ((previous_canon && !p->ai_canonname) || 0535 (!previous_canon && p->ai_canonname) || 0536 (p->ai_canonname != previous_canon && 0537 strcmp(p->ai_canonname, previous_canon) != 0)) { 0538 canon = KResolver::domainToUnicode(QString::fromLatin1(p->ai_canonname)); 0539 previous_canon = p->ai_canonname; 0540 } 0541 0542 results.append(KResolverEntry(p->ai_addr, p->ai_addrlen, p->ai_socktype, 0543 p->ai_protocol, canon, m_node)); 0544 } 0545 0546 freeaddrinfo(result); 0547 results.setError(KResolver::NoError); 0548 finished(); 0549 return results.error() == KResolver::NoError; 0550 } while (true); 0551 } 0552 0553 #endif // HAVE_GETADDRINFO 0554 } // namespace 0555 0556 KStandardWorker::~KStandardWorker() 0557 { 0558 qDeleteAll(resultList); 0559 } 0560 0561 bool KStandardWorker::sanityCheck() 0562 { 0563 // check that the requested values are sensible 0564 0565 if (!nodeName().isEmpty()) { 0566 QString node = nodeName(); 0567 if (node.indexOf(QLatin1Char('%')) != -1) { 0568 node.truncate(node.indexOf(QLatin1Char('%'))); 0569 } 0570 0571 if (node.isEmpty() || node == QLatin1String("*") || 0572 node == QLatin1String("localhost")) { 0573 m_encodedName.truncate(0); 0574 } else { 0575 m_encodedName = KResolver::domainToAscii(node); 0576 0577 if (m_encodedName.isNull()) { 0578 qDebug("could not encode hostname '%s' (UTF-8)", node.toUtf8().data()); 0579 setError(KResolver::NoName); 0580 return false; // invalid hostname! 0581 } 0582 0583 // qDebug("Using encoded hostname '%s' for '%s' (UTF-8)", m_encodedName.data(), 0584 // node.toUtf8().data()); 0585 } 0586 } else { 0587 m_encodedName.truncate(0); // just to be sure, but it should be clear already 0588 } 0589 0590 if (protocol() == -1) { 0591 setError(KResolver::NonRecoverable); 0592 return false; // user passed invalid protocol name 0593 } 0594 0595 return true; // it's sane 0596 } 0597 0598 bool KStandardWorker::resolveScopeId() 0599 { 0600 // we must test the original name, not the encoded one 0601 scopeid = 0; 0602 int pos = nodeName().lastIndexOf(QLatin1Char('%')); 0603 if (pos == -1) { 0604 return true; 0605 } 0606 0607 QString scopename = nodeName().mid(pos + 1); 0608 0609 bool ok; 0610 scopeid = scopename.toInt(&ok); 0611 if (!ok) { 0612 // it's not a number 0613 // therefore, it's an interface name 0614 #if HAVE_IF_NAMETOINDEX 0615 scopeid = if_nametoindex(scopename.toLatin1()); 0616 #else 0617 scopeid = 0; 0618 #endif 0619 } 0620 0621 return true; 0622 } 0623 0624 bool KStandardWorker::resolveService() 0625 { 0626 // find the service first 0627 bool ok; 0628 port = serviceName().toUInt(&ok); 0629 if (!ok) { 0630 // service name does not contain a port number 0631 // must be a name 0632 0633 if (serviceName().isEmpty() || serviceName().compare(QLatin1String("*")) == 0) { 0634 port = 0; 0635 } else { 0636 // it's a name. We need the protocol name in order to lookup. 0637 QByteArray protoname = protocolName(); 0638 0639 if (protoname.isEmpty() && protocol()) { 0640 protoname = KResolver::protocolName(protocol()).first(); 0641 0642 // if it's still empty... 0643 if (protoname.isEmpty()) { 0644 // lookup failed! 0645 setError(KResolver::NoName); 0646 return false; 0647 } 0648 } else { 0649 protoname = "tcp"; 0650 } 0651 0652 // it's not, so we can do a port lookup 0653 int result = KResolver::servicePort(serviceName().toLatin1(), protoname); 0654 if (result == -1) { 0655 // lookup failed! 0656 setError(KResolver::NoName); 0657 return false; 0658 } 0659 0660 // it worked, we have a port number 0661 port = (quint16)result; 0662 } 0663 } 0664 0665 // we found a port 0666 return true; 0667 } 0668 0669 KResolver::ErrorCodes KStandardWorker::addUnix() 0670 { 0671 // before trying to add, see if the user wants Unix sockets 0672 if ((familyMask() & KResolver::UnixFamily) == 0) 0673 // no, Unix sockets are not wanted 0674 { 0675 return KResolver::UnsupportedFamily; 0676 } 0677 0678 // now check if the requested data are good for a Unix socket 0679 if (!m_encodedName.isEmpty()) { 0680 return KResolver::AddrFamily; // non local hostname 0681 } 0682 0683 if (protocol() || !protocolName().isNull()) { 0684 return KResolver::BadFlags; // cannot have Unix sockets with protocols 0685 } 0686 0687 QString pathname = serviceName(); 0688 if (pathname.isEmpty()) { 0689 return KResolver::NoName; 0690 }; // no path? 0691 0692 if (pathname[0] != QLatin1Char('/')) 0693 // non absolute pathname 0694 // put it in /tmp 0695 { 0696 pathname.prepend(QLatin1String("/tmp/")); 0697 } 0698 0699 // qDebug("QNoResolveWorker::addUnix(): adding Unix socket for %s", pathname.toLocal8Bit().data()); 0700 KUnixSocketAddress sa(pathname); 0701 int socktype = socketType(); 0702 if (socktype == 0) { 0703 socktype = SOCK_STREAM; // default 0704 } 0705 0706 results.append(KResolverEntry(sa, socktype, 0)); 0707 setError(KResolver::NoError); 0708 0709 return KResolver::NoError; 0710 } 0711 0712 bool KStandardWorker::resolveNumerically() 0713 { 0714 // if the NoResolve flag is active, our result from this point forward 0715 // will always be true, even if the resolution failed. 0716 // that indicates that our result is authoritative. 0717 0718 bool wantV4 = familyMask() & KResolver::IPv4Family, 0719 wantV6 = familyMask() & KResolver::IPv6Family; 0720 0721 if (!wantV6 && !wantV4) 0722 // no Internet address is wanted! 0723 { 0724 return (flags() & KResolver::NoResolve); 0725 } 0726 0727 // now try to find results 0728 if (!resolveScopeId() || !resolveService()) { 0729 return (flags() & KResolver::NoResolve); 0730 } 0731 0732 // we have scope IDs and port numbers 0733 // now try to resolve the hostname numerically 0734 KInetSocketAddress sa; 0735 setError(KResolver::NoError); 0736 sa.setHost(KIpAddress(QLatin1String(m_encodedName))); 0737 0738 // if it failed, the length was reset to 0 0739 bool ok = sa.length() != 0; 0740 0741 sa.setPort(port); 0742 if (sa.ipVersion() == 6) { 0743 sa.setScopeId(scopeid); 0744 } 0745 int proto = protocol(); 0746 int socktype = socketType(); 0747 if (socktype == 0) { 0748 socktype = SOCK_STREAM; 0749 } 0750 0751 if (ok) { 0752 // the given hostname was successfully converted to an IP address 0753 // check if the user wanted this kind of address 0754 0755 if ((sa.ipVersion() == 4 && wantV4) || 0756 (sa.ipVersion() == 6 && wantV6)) { 0757 results.append(KResolverEntry(sa, socktype, proto)); 0758 } else { 0759 // Note: the address *IS* a numeric IP 0760 // but it's not of the kind the user asked for 0761 // 0762 // that means that it cannot be a Unix socket (because it's an IP) 0763 // and that means that no resolution will tell us otherwise 0764 // 0765 // This is a failed resolution 0766 0767 setError(KResolver::AddrFamily); 0768 return true; 0769 } 0770 } else if (m_encodedName.isEmpty()) { 0771 // user wanted localhost 0772 if (flags() & KResolver::Passive) { 0773 if (wantV6) { 0774 sa.setHost(KIpAddress::anyhostV6); 0775 results.append(KResolverEntry(sa, socktype, proto)); 0776 } 0777 0778 if (wantV4) { 0779 sa.setHost(KIpAddress::anyhostV4); 0780 results.append(KResolverEntry(sa, socktype, proto)); 0781 } 0782 } else { 0783 if (wantV6) { 0784 sa.setHost(KIpAddress::localhostV6); 0785 results.append(KResolverEntry(sa, socktype, proto)); 0786 } 0787 0788 if (wantV4) { 0789 sa.setHost(KIpAddress::localhostV4); 0790 results.append(KResolverEntry(sa, socktype, proto)); 0791 } 0792 } 0793 0794 ok = true; 0795 } else { 0796 // probably bad flags, since the address is not convertible without 0797 // resolution 0798 0799 setError(KResolver::BadFlags); 0800 ok = false; 0801 } 0802 0803 return ok || (flags() & KResolver::NoResolve); 0804 } 0805 0806 bool KStandardWorker::preprocess() 0807 { 0808 // check sanity 0809 if (!sanityCheck()) { 0810 return false; 0811 } 0812 0813 // this worker class can only handle known families 0814 if (familyMask() & KResolver::UnknownFamily) { 0815 setError(KResolver::UnsupportedFamily); 0816 return false; // we don't know about this 0817 } 0818 0819 // check the socket types 0820 if (socketType() != SOCK_STREAM && socketType() != SOCK_DGRAM && socketType() != 0) { 0821 setError(KResolver::UnsupportedSocketType); 0822 return false; 0823 } 0824 0825 // check if we can resolve all numerically 0826 // resolveNumerically always returns true if the NoResolve flag is set 0827 if (resolveNumerically() || m_encodedName.isEmpty()) { 0828 // indeed, we have resolved numerically 0829 setError(addUnix()); 0830 if (results.count()) { 0831 setError(KResolver::NoError); 0832 } 0833 finished(); 0834 return true; 0835 } 0836 0837 // check if the user wants something we know about 0838 #ifdef AF_INET6 0839 # define mask (KResolver::IPv6Family | KResolver::IPv4Family | KResolver::UnixFamily) 0840 #else 0841 # define mask (KResolver::IPv4Family | KResolver::UnixFamily) 0842 #endif 0843 0844 if ((familyMask() & mask) == 0) 0845 // errr... nothing we know about 0846 { 0847 return false; 0848 } 0849 0850 #undef mask 0851 0852 return true; // it's ok 0853 } 0854 0855 bool KStandardWorker::run() 0856 { 0857 #if !HAVE_GETADDRINFO 0858 // check the scope id first 0859 // since most of the resolutions won't have a scope id, this should be fast 0860 // and we won't have wasted time on services if this fails 0861 if (!resolveScopeId()) { 0862 return false; 0863 } 0864 0865 // resolve the service now, before entering the blocking operation 0866 if (!resolveService()) { 0867 return false; 0868 } 0869 #endif 0870 0871 // good 0872 // now we need the hostname 0873 setError(KResolver::NoName); 0874 0875 // these are the family types that we know of 0876 struct { 0877 KResolver::SocketFamilies mask; 0878 int af; 0879 } families[] = { { KResolver::IPv4Family, AF_INET } 0880 #ifdef AF_INET6 0881 , { KResolver::IPv6Family, AF_INET6 } 0882 #endif 0883 }; 0884 int familyCount = sizeof(families) / sizeof(families[0]); 0885 bool skipIPv6 = !hasIPv6(); 0886 0887 for (int i = 0; i < familyCount; i++) 0888 if (familyMask() & families[i].mask) { 0889 #ifdef AF_INET6 0890 if (skipIPv6 && families[i].af == AF_INET6) { 0891 continue; 0892 } 0893 #endif 0894 0895 KResolverWorkerBase *worker; 0896 KResolverResults *res = new KResolverResults; 0897 resultList.append(res); 0898 #if HAVE_GETADDRINFO 0899 worker = new GetAddrInfoThread(m_encodedName, 0900 serviceName().toLatin1(), 0901 families[i].af, flags(), res); 0902 #else 0903 worker = new GetHostByNameThread(m_encodedName, port, scopeid, 0904 families[i].af, res); 0905 #endif 0906 0907 enqueue(worker); 0908 } 0909 0910 // not finished 0911 return true; 0912 } 0913 0914 bool KStandardWorker::postprocess() 0915 { 0916 if (results.count()) { 0917 return true; // no need 0918 } 0919 // now copy over what we need from the underlying results 0920 0921 // start backwards because IPv6 was launched later (if at all) 0922 if (resultList.isEmpty()) { 0923 results.setError(KResolver::NoName); 0924 return true; 0925 } 0926 0927 for (int i = resultList.size(); i > 0; --i) { 0928 KResolverResults *rr = resultList.at(i - 1); 0929 if (!rr->isEmpty()) { 0930 results.setError(KResolver::NoError); 0931 KResolverResults::Iterator it = rr->begin(); 0932 for (; it != rr->end(); ++it) { 0933 results.append(*it); 0934 } 0935 } else if (results.isEmpty()) 0936 // this generated an error 0937 // copy the error code over 0938 { 0939 setError(rr->error(), rr->systemError()); 0940 } 0941 0942 delete rr; 0943 resultList[i - 1] = nullptr; 0944 } 0945 0946 resultList.clear(); 0947 return true; 0948 } 0949 0950 #if HAVE_GETADDRINFO 0951 KGetAddrinfoWorker::~KGetAddrinfoWorker() 0952 { 0953 } 0954 0955 bool KGetAddrinfoWorker::preprocess() 0956 { 0957 // getaddrinfo(3) can always handle any kind of request that makes sense 0958 if (!sanityCheck()) { 0959 return false; 0960 } 0961 0962 if (flags() & KResolver::NoResolve) 0963 // oops, numeric resolution? 0964 { 0965 return run(); 0966 } 0967 0968 return true; 0969 } 0970 0971 bool KGetAddrinfoWorker::run() 0972 { 0973 // make an AF_UNSPEC getaddrinfo(3) call 0974 GetAddrInfoThread worker(m_encodedName, serviceName().toLatin1(), 0975 AF_UNSPEC, flags(), &results); 0976 0977 if (!worker.run()) { 0978 if (wantThis(AF_UNIX)) { 0979 if (addUnix() == KResolver::NoError) { 0980 setError(KResolver::NoError); 0981 } 0982 } else { 0983 setError(worker.results.error(), worker.results.systemError()); 0984 } 0985 0986 return false; 0987 } 0988 0989 // The worker has finished working 0990 // now copy over only what we may want 0991 // keep track of any Unix-domain sockets 0992 0993 bool seen_unix = false; 0994 int i = 0; 0995 while (i < results.count()) { 0996 const KResolverEntry &res = results[i]; 0997 if (res.family() == AF_UNIX) { 0998 seen_unix = true; 0999 } 1000 if (!wantThis(res.family())) { 1001 results.removeAt(i); 1002 } else { 1003 ++i; 1004 } 1005 } 1006 1007 if (!seen_unix) { 1008 addUnix(); 1009 } 1010 1011 finished(); 1012 return true; 1013 } 1014 1015 bool KGetAddrinfoWorker::wantThis(int family) 1016 { 1017 // tells us if the user wants a socket of this family 1018 1019 #ifdef AF_INET6 1020 if (family == AF_INET6 && familyMask() & KResolver::IPv6Family) { 1021 return true; 1022 } 1023 #endif 1024 if (family == AF_INET && familyMask() & KResolver::IPv4Family) { 1025 return true; 1026 } 1027 if (family == AF_UNIX && familyMask() & KResolver::UnixFamily) { 1028 return true; 1029 } 1030 1031 // it's not a family we know about... 1032 if (familyMask() & KResolver::UnknownFamily) { 1033 return true; 1034 } 1035 1036 return false; 1037 } 1038 1039 #endif 1040 1041 void KNetwork::Internal::initStandardWorkers() 1042 { 1043 //KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KBlacklistWorker>); 1044 KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KStandardWorker>); 1045 1046 #if HAVE_GETADDRINFO 1047 KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KGetAddrinfoWorker>); 1048 #endif 1049 }