13#include <QtCore/private/qduplicatetracker_p.h>
15#ifndef QT_NO_NETWORKINTERFACE
17#if QT_CONFIG(getifaddrs)
22# include <arpa/inet.h>
23# ifndef SIOCGIFBRDADDR
24# define SIOCGIFBRDADDR 0x8919
28#include <qplatformdefs.h>
38 if (sa->sa_family == AF_INET)
39 address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr));
40 else if (sa->sa_family ==
AF_INET6) {
41 address.setAddress(((sockaddr_in6 *)sa)->sin6_addr.s6_addr);
42 int scope = ((sockaddr_in6 *)sa)->sin6_scope_id;
43 if (scope && scope == ifindex) {
46 address.setScopeId(ifname);
54template <
typename Req> [[maybe_unused]]
55static auto &
ifreq_index(Req &req, std::enable_if_t<
sizeof(std::declval<Req>().ifr_index) != 0,
int> = 0)
60template <
typename Req> [[maybe_unused]]
61static auto &
ifreq_index(Req &req, std::enable_if_t<
sizeof(std::declval<Req>().ifr_ifindex) != 0,
int> = 0)
63 return req.ifr_ifindex;
68#if QT_CONFIG(ipv6ifname)
69 return ::if_nametoindex(name.toLatin1().constData());
70#elif defined(SIOCGIFINDEX)
72 int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0);
76 const QByteArray name8bit = name.toLatin1();
77 memset(&req, 0,
sizeof(ifreq));
78 if (!name8bit.isNull())
79 memcpy(req.ifr_name, name8bit.data(), qMin(size_t(name8bit.length()) + 1,
sizeof(req.ifr_name) - 1));
82 if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
83 id = ifreq_index(req);
84 qt_safe_close(socket);
94#if QT_CONFIG(ipv6ifname)
95 char buf[IF_NAMESIZE];
96 if (::if_indextoname(index, buf))
97 return QString::fromLatin1(buf);
98#elif defined(SIOCGIFNAME)
100 int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0);
102 memset(&req, 0,
sizeof(ifreq));
103 ifreq_index(req) = index;
104 if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) {
105 qt_safe_close(socket);
106 return QString::fromLatin1(req.ifr_name);
108 qt_safe_close(socket);
111 return QString::number(uint(index));
114static int getMtu(
int socket,
struct ifreq *req)
117 if (qt_safe_ioctl(socket, SIOCGIFMTU, req) == 0)
123#if !QT_CONFIG(getifaddrs)
126static QSet<QByteArray> interfaceNames(
int socket)
128 QSet<QByteArray> result;
129#if !QT_CONFIG(ipv6ifname)
130 QByteArray storageBuffer;
131 struct ifconf interfaceList;
132 static const int STORAGEBUFFER_GROWTH = 256;
136 storageBuffer.resize(storageBuffer.size() + STORAGEBUFFER_GROWTH);
137 interfaceList.ifc_buf = storageBuffer.data();
138 interfaceList.ifc_len = storageBuffer.size();
141 if (qt_safe_ioctl(socket, SIOCGIFCONF, &interfaceList) >= 0) {
142 if (
int(interfaceList.ifc_len +
sizeof(ifreq) + 64) < storageBuffer.size()) {
144 storageBuffer.resize(interfaceList.ifc_len);
151 if (storageBuffer.size() > 100000) {
157 int interfaceCount = interfaceList.ifc_len /
sizeof(ifreq);
158 for (
int i = 0; i < interfaceCount; ++i) {
159 QByteArray name = QByteArray(interfaceList.ifc_req[i].ifr_name);
169 struct if_nameindex *interfaceList = ::if_nameindex();
170 for (
struct if_nameindex *ptr = interfaceList; ptr && ptr->if_name; ++ptr)
171 result << ptr->if_name;
173 if_freenameindex(interfaceList);
178static QNetworkInterfacePrivate *findInterface(
int socket, QList<QNetworkInterfacePrivate *> &interfaces,
181 QNetworkInterfacePrivate *iface =
nullptr;
184#if QT_CONFIG(ipv6ifname) || defined(SIOCGIFINDEX)
187 if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
188 ifindex = ifreq_index(req);
190 ifindex = if_nametoindex(req.ifr_name);
194 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
195 for ( ; if_it != interfaces.end(); ++if_it)
196 if ((*if_it)->index == ifindex) {
204 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
205 for ( ; if_it != interfaces.end(); ++if_it)
206 if ((*if_it)->name == QLatin1StringView(req.ifr_name)) {
215 iface =
new QNetworkInterfacePrivate;
216 iface->index = ifindex;
223static QList<QNetworkInterfacePrivate *> interfaceListing()
225 QList<QNetworkInterfacePrivate *> interfaces;
228 if ((socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
231 QSet<QByteArray> names = interfaceNames(socket);
232 QSet<QByteArray>::ConstIterator it = names.constBegin();
233 for ( ; it != names.constEnd(); ++it) {
235 memset(&req, 0,
sizeof(ifreq));
237 memcpy(req.ifr_name, it->constData(), qMin(size_t(it->length()) + 1,
sizeof(req.ifr_name) - 1));
239 QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
243 QByteArray oldName = req.ifr_name;
244 if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) {
245 iface->name = QString::fromLatin1(req.ifr_name);
248 if (!oldName.isNull())
249 memcpy(req.ifr_name, oldName.constData(), qMin(size_t(oldName.length()) + 1,
sizeof(req.ifr_name) - 1));
254 iface->name = QString::fromLatin1(req.ifr_name);
258 if (qt_safe_ioctl(socket, SIOCGIFFLAGS, &req) >= 0) {
259 iface->flags = convertFlags(req.ifr_flags);
261 iface->mtu = getMtu(socket, &req);
265 if (qt_safe_ioctl(socket, SIOCGIFHWADDR, &req) >= 0) {
266 uchar *addr = (uchar *)req.ifr_addr.sa_data;
267 iface->hardwareAddress = iface->makeHwAddress(6, addr);
272 QNetworkAddressEntry entry;
273 if (qt_safe_ioctl(socket, SIOCGIFADDR, &req) >= 0) {
274 sockaddr *sa = &req.ifr_addr;
275 entry.setIp(addressFromSockaddr(sa));
278 if (iface->flags & QNetworkInterface::CanBroadcast) {
279 if (qt_safe_ioctl(socket, SIOCGIFBRDADDR, &req) >= 0) {
280 sockaddr *sa = &req.ifr_addr;
281 if (sa->sa_family == AF_INET)
282 entry.setBroadcast(addressFromSockaddr(sa));
287 if (qt_safe_ioctl(socket, SIOCGIFNETMASK, &req) >= 0) {
288 sockaddr *sa = &req.ifr_addr;
289 entry.setNetmask(addressFromSockaddr(sa));
292 iface->addressEntries << entry;
305QT_BEGIN_INCLUDE_NAMESPACE
306# include <features.h>
307QT_END_INCLUDE_NAMESPACE
310static int openSocket(
int &socket)
313 socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0);
317# if defined(Q_OS_LINUX) && __GLIBC__
- 0
>= 2
&& __GLIBC_MINOR__
- 0
>= 1
&& !defined(QT_LINUXBASE)
318# include <netpacket/packet.h>
320static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
323 Q_UNUSED(openSocket);
324 QList<QNetworkInterfacePrivate *> interfaces;
325 QDuplicateTracker<QString> seenInterfaces;
326 QDuplicateTracker<
int> seenIndexes;
335 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
336 if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_PACKET) {
337 sockaddr_ll *sll = (sockaddr_ll *)ptr->ifa_addr;
338 QNetworkInterfacePrivate *iface =
new QNetworkInterfacePrivate;
340 iface->index = sll->sll_ifindex;
341 iface->name = QString::fromLatin1(ptr->ifa_name);
342 iface->flags = convertFlags(ptr->ifa_flags);
343 iface->hardwareAddress = iface->makeHwAddress(sll->sll_halen, (uchar*)sll->sll_addr);
345 const bool sawIfaceIndex = seenIndexes.hasSeen(iface->index);
346 Q_ASSERT(!sawIfaceIndex);
347 (
void)seenInterfaces.hasSeen(iface->name);
354 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
355 if (!ptr->ifa_addr || ptr->ifa_addr->sa_family != AF_PACKET) {
356 QString name = QString::fromLatin1(ptr->ifa_name);
357 if (seenInterfaces.hasSeen(name))
360 int ifindex = if_nametoindex(ptr->ifa_name);
361 if (seenIndexes.hasSeen(ifindex))
364 QNetworkInterfacePrivate *iface =
new QNetworkInterfacePrivate;
367 iface->flags = convertFlags(ptr->ifa_flags);
368 iface->index = ifindex;
375static void getAddressExtraInfo(QNetworkAddressEntry *entry,
struct sockaddr *sa,
const char *ifname)
382# elif defined(Q_OS_BSD4)
383QT_BEGIN_INCLUDE_NAMESPACE
384# include <net/if_dl.h>
385#if defined(QT_PLATFORM_UIKIT)
386# include "qnetworkinterface_uikit_p.h"
387# include <net/if_types.h>
389# include <net/if_media.h>
390# include <net/if_types.h>
391# include <netinet/in_var.h>
393QT_END_INCLUDE_NAMESPACE
395#if defined(Q_OS_MACOS)
396QT_BEGIN_INCLUDE_NAMESPACE
397# include <CoreFoundation/CoreFoundation.h>
398# include <SystemConfiguration/SystemConfiguration.h>
399# include <QtCore/private/qcore_mac_p.h>
400QT_END_INCLUDE_NAMESPACE
404static QHash<QString, QString> interfaceFriendlyNames()
406 QHash<QString, QString> result;
407 QCFType<CFArrayRef> interfaces = SCNetworkInterfaceCopyAll();
411 CFIndex count = CFArrayGetCount(interfaces);
412 result.reserve(count);
413 for (CFIndex i = 0; i < count; ++i) {
414 auto iface =
static_cast<SCNetworkInterfaceRef>(CFArrayGetValueAtIndex(interfaces, i));
415 CFStringRef bsdName = SCNetworkInterfaceGetBSDName(iface);
416 CFStringRef displayName = SCNetworkInterfaceGetLocalizedDisplayName(iface);
417 if (bsdName && displayName)
418 result.insert(QString::fromCFString(bsdName), QString::fromCFString(displayName));
423static QHash<QString, QString> interfaceFriendlyNames()
429static QNetworkInterface::InterfaceType probeIfType(
int socket,
int iftype,
struct ifmediareq *req)
438 return QNetworkInterface::Ppp;
441 return QNetworkInterface::Loopback;
444 return QNetworkInterface::Slip;
447 return QNetworkInterface::Ieee80211;
450 return QNetworkInterface::Ieee1394;
454 return QNetworkInterface::Virtual;
459 if (qt_safe_ioctl(socket, SIOCGIFMEDIA, req) == 0) {
462 switch (IFM_TYPE(req->ifm_current)) {
464 return QNetworkInterface::Ethernet;
468 return QNetworkInterface::Fddi;
472 return QNetworkInterface::Ieee80211;
476 return QNetworkInterface::Unknown;
479static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
481 QList<QNetworkInterfacePrivate *> interfaces;
483 struct ifmediareq mediareq;
487 memset(&mediareq, 0,
sizeof(mediareq));
490 static_assert(
sizeof(mediareq.ifm_name) ==
sizeof(req.ifr_name));
491 static_assert(offsetof(
struct ifmediareq, ifm_name) == 0);
492 static_assert(offsetof(
struct ifreq, ifr_name) == 0);
494 const QHash<QString, QString> friendlyNames = interfaceFriendlyNames();
498 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next)
499 if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_LINK) {
500 QNetworkInterfacePrivate *iface =
new QNetworkInterfacePrivate;
503 sockaddr_dl *sdl = (sockaddr_dl *)ptr->ifa_addr;
504 iface->index = sdl->sdl_index;
505 iface->name = QString::fromLatin1(ptr->ifa_name);
506 iface->flags = convertFlags(ptr->ifa_flags);
507 iface->hardwareAddress = iface->makeHwAddress(sdl->sdl_alen, (uchar*)LLADDR(sdl));
508 iface->friendlyName = friendlyNames.value(iface->name);
510 qstrncpy(mediareq.ifm_name, ptr->ifa_name,
sizeof(mediareq.ifm_name));
511 iface->type = probeIfType(openSocket(socket), sdl->sdl_type, &mediareq);
512 iface->mtu = getMtu(socket, &req);
516 qt_safe_close(socket);
520static void getAddressExtraInfo(QNetworkAddressEntry *entry,
struct sockaddr *sa,
const char *ifname)
523 if (sa->sa_family != AF_INET6)
526 struct in6_ifreq ifr;
528 int s6 = qt_safe_socket(AF_INET6, SOCK_DGRAM, 0);
529 if (Q_UNLIKELY(s6 < 0)) {
530 qErrnoWarning(
"QNetworkInterface: could not create IPv6 socket");
534 qstrncpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
537 ifr.ifr_addr = *
reinterpret_cast<
struct sockaddr_in6 *>(sa);
538 if (qt_safe_ioctl(s6, SIOCGIFAFLAG_IN6, &ifr) < 0) {
542 int flags = ifr.ifr_ifru.ifru_flags6;
543 QNetworkInterfacePrivate::calculateDnsEligibility(entry,
544 flags & IN6_IFF_TEMPORARY,
545 flags & IN6_IFF_DEPRECATED);
548 ifr.ifr_addr = *
reinterpret_cast<
struct sockaddr_in6 *>(sa);
549 if (qt_safe_ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr) < 0) {
555# if defined(Q_OS_DARWIN)
556 constexpr clockid_t LifetimeClock = CLOCK_REALTIME;
558 constexpr clockid_t LifetimeClock = CLOCK_UPTIME;
561 clock_gettime(LifetimeClock, &now);
562 auto toDeadline = [now](time_t when) {
563 QDeadlineTimer deadline = QDeadlineTimer::Forever;
565 deadline.setPreciseRemainingTime(when - now.tv_sec);
569 entry->setAddressLifetime(toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_preferred),
570 toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_expire));
575static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
577 QList<QNetworkInterfacePrivate *> interfaces;
581 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
583 int ifindex = if_nametoindex(ptr->ifa_name);
585 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
586 for ( ; if_it != interfaces.end(); ++if_it)
587 if ((*if_it)->index == ifindex)
591 if (if_it == interfaces.end()) {
597 iface->name = QString::fromLatin1(ptr->ifa_name);
598 iface->flags = convertFlags(ptr->ifa_flags);
600 if ((socket = openSocket(socket)) >= 0) {
602 qstrncpy(ifr.ifr_name, ptr->ifa_name,
sizeof(ifr.ifr_name));
609 qt_safe_close(socket);
614static void getAddressExtraInfo(QNetworkAddressEntry *entry,
struct sockaddr *sa,
const char *ifname)
622static QList<QNetworkInterfacePrivate *> interfaceListing()
624 QList<QNetworkInterfacePrivate *> interfaces;
626 ifaddrs *interfaceListing;
627 if (getifaddrs(&interfaceListing) == -1) {
632 interfaces = createInterfaces(interfaceListing);
633 for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) {
635 QLatin1StringView name(ptr->ifa_name);
637 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
638 for ( ; if_it != interfaces.end(); ++if_it)
639 if ((*if_it)->name == name) {
647 int ifindex = if_nametoindex(ptr->ifa_name);
648 for (if_it = interfaces.begin(); if_it != interfaces.end(); ++if_it)
649 if ((*if_it)->index == ifindex) {
662 entry.setIp(addressFromSockaddr(ptr->ifa_addr, iface->index, iface->name));
663 if (entry.ip().isNull())
667 entry.setNetmask(addressFromSockaddr(ptr->ifa_netmask, iface->index, iface->name));
668 if (iface->flags & QNetworkInterface::CanBroadcast)
669 entry.setBroadcast(addressFromSockaddr(ptr->ifa_broadaddr, iface->index, iface->name));
670 getAddressExtraInfo(&entry, ptr->ifa_addr, name.latin1());
672 iface->addressEntries << entry;
675 freeifaddrs(interfaceListing);
682 return interfaceListing();
The QNetworkAddressEntry class stores one IP address supported by a network interface,...
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE QHostAddress addressFromSockaddr(sockaddr *sa, int ifindex=0, const QString &ifname=QString())
static int getMtu(int socket, struct ifreq *req)
static auto & ifreq_index(Req &req, std::enable_if_t< sizeof(std::declval< Req >().ifr_index) !=0, int >=0)