13#include <QtCore/private/qduplicatetracker_p.h>
15#ifndef QT_NO_NETWORKINTERFACE
17#if defined(QT_NO_CLOCK_MONOTONIC)
18# include "qdatetime.h"
21#if QT_CONFIG(getifaddrs)
26# include <arpa/inet.h>
27# ifndef SIOCGIFBRDADDR
28# define SIOCGIFBRDADDR 0x8919
32#include <qplatformdefs.h>
42 if (sa->sa_family == AF_INET)
43 address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr));
44 else if (sa->sa_family ==
AF_INET6) {
45 address.setAddress(((sockaddr_in6 *)sa)->sin6_addr.s6_addr);
46 int scope = ((sockaddr_in6 *)sa)->sin6_scope_id;
47 if (scope && scope == ifindex) {
50 address.setScopeId(ifname);
58template <
typename Req> [[maybe_unused]]
59static auto &
ifreq_index(Req &req, std::enable_if_t<
sizeof(std::declval<Req>().ifr_index) != 0,
int> = 0)
64template <
typename Req> [[maybe_unused]]
65static auto &
ifreq_index(Req &req, std::enable_if_t<
sizeof(std::declval<Req>().ifr_ifindex) != 0,
int> = 0)
67 return req.ifr_ifindex;
72#if QT_CONFIG(ipv6ifname)
73 return ::if_nametoindex(name.toLatin1().constData());
74#elif defined(SIOCGIFINDEX)
76 int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0);
80 const QByteArray name8bit = name.toLatin1();
81 memset(&req, 0,
sizeof(ifreq));
82 if (!name8bit.isNull())
83 memcpy(req.ifr_name, name8bit.data(), qMin(size_t(name8bit.length()) + 1,
sizeof(req.ifr_name) - 1));
86 if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
87 id = ifreq_index(req);
88 qt_safe_close(socket);
98#if QT_CONFIG(ipv6ifname)
99 char buf[IF_NAMESIZE];
100 if (::if_indextoname(index, buf))
101 return QString::fromLatin1(buf);
102#elif defined(SIOCGIFNAME)
104 int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0);
106 memset(&req, 0,
sizeof(ifreq));
107 ifreq_index(req) = index;
108 if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) {
109 qt_safe_close(socket);
110 return QString::fromLatin1(req.ifr_name);
112 qt_safe_close(socket);
115 return QString::number(uint(index));
118static int getMtu(
int socket,
struct ifreq *req)
121 if (qt_safe_ioctl(socket, SIOCGIFMTU, req) == 0)
127#if !QT_CONFIG(getifaddrs)
130static QSet<QByteArray> interfaceNames(
int socket)
132 QSet<QByteArray> result;
133#if !QT_CONFIG(ipv6ifname)
134 QByteArray storageBuffer;
135 struct ifconf interfaceList;
136 static const int STORAGEBUFFER_GROWTH = 256;
140 storageBuffer.resize(storageBuffer.size() + STORAGEBUFFER_GROWTH);
141 interfaceList.ifc_buf = storageBuffer.data();
142 interfaceList.ifc_len = storageBuffer.size();
145 if (qt_safe_ioctl(socket, SIOCGIFCONF, &interfaceList) >= 0) {
146 if (
int(interfaceList.ifc_len +
sizeof(ifreq) + 64) < storageBuffer.size()) {
148 storageBuffer.resize(interfaceList.ifc_len);
155 if (storageBuffer.size() > 100000) {
161 int interfaceCount = interfaceList.ifc_len /
sizeof(ifreq);
162 for (
int i = 0; i < interfaceCount; ++i) {
163 QByteArray name = QByteArray(interfaceList.ifc_req[i].ifr_name);
173 struct if_nameindex *interfaceList = ::if_nameindex();
174 for (
struct if_nameindex *ptr = interfaceList; ptr && ptr->if_name; ++ptr)
175 result << ptr->if_name;
177 if_freenameindex(interfaceList);
182static QNetworkInterfacePrivate *findInterface(
int socket, QList<QNetworkInterfacePrivate *> &interfaces,
185 QNetworkInterfacePrivate *iface =
nullptr;
188#if QT_CONFIG(ipv6ifname) || defined(SIOCGIFINDEX)
191 if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
192 ifindex = ifreq_index(req);
194 ifindex = if_nametoindex(req.ifr_name);
198 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
199 for ( ; if_it != interfaces.end(); ++if_it)
200 if ((*if_it)->index == ifindex) {
208 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
209 for ( ; if_it != interfaces.end(); ++if_it)
210 if ((*if_it)->name == QLatin1StringView(req.ifr_name)) {
219 iface =
new QNetworkInterfacePrivate;
220 iface->index = ifindex;
227static QList<QNetworkInterfacePrivate *> interfaceListing()
229 QList<QNetworkInterfacePrivate *> interfaces;
232 if ((socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
235 QSet<QByteArray> names = interfaceNames(socket);
236 QSet<QByteArray>::ConstIterator it = names.constBegin();
237 for ( ; it != names.constEnd(); ++it) {
239 memset(&req, 0,
sizeof(ifreq));
241 memcpy(req.ifr_name, it->constData(), qMin(size_t(it->length()) + 1,
sizeof(req.ifr_name) - 1));
243 QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
247 QByteArray oldName = req.ifr_name;
248 if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) {
249 iface->name = QString::fromLatin1(req.ifr_name);
252 if (!oldName.isNull())
253 memcpy(req.ifr_name, oldName.constData(), qMin(size_t(oldName.length()) + 1,
sizeof(req.ifr_name) - 1));
258 iface->name = QString::fromLatin1(req.ifr_name);
262 if (qt_safe_ioctl(socket, SIOCGIFFLAGS, &req) >= 0) {
263 iface->flags = convertFlags(req.ifr_flags);
265 iface->mtu = getMtu(socket, &req);
269 if (qt_safe_ioctl(socket, SIOCGIFHWADDR, &req) >= 0) {
270 uchar *addr = (uchar *)req.ifr_addr.sa_data;
271 iface->hardwareAddress = iface->makeHwAddress(6, addr);
276 QNetworkAddressEntry entry;
277 if (qt_safe_ioctl(socket, SIOCGIFADDR, &req) >= 0) {
278 sockaddr *sa = &req.ifr_addr;
279 entry.setIp(addressFromSockaddr(sa));
282 if (iface->flags & QNetworkInterface::CanBroadcast) {
283 if (qt_safe_ioctl(socket, SIOCGIFBRDADDR, &req) >= 0) {
284 sockaddr *sa = &req.ifr_addr;
285 if (sa->sa_family == AF_INET)
286 entry.setBroadcast(addressFromSockaddr(sa));
291 if (qt_safe_ioctl(socket, SIOCGIFNETMASK, &req) >= 0) {
292 sockaddr *sa = &req.ifr_addr;
293 entry.setNetmask(addressFromSockaddr(sa));
296 iface->addressEntries << entry;
309QT_BEGIN_INCLUDE_NAMESPACE
310# include <features.h>
311QT_END_INCLUDE_NAMESPACE
314static int openSocket(
int &socket)
317 socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0);
321# if defined(Q_OS_LINUX) && __GLIBC__
- 0
>= 2
&& __GLIBC_MINOR__
- 0
>= 1
&& !defined(QT_LINUXBASE)
322# include <netpacket/packet.h>
324static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
327 Q_UNUSED(openSocket);
328 QList<QNetworkInterfacePrivate *> interfaces;
329 QDuplicateTracker<QString> seenInterfaces;
330 QDuplicateTracker<
int> seenIndexes;
339 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
340 if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_PACKET) {
341 sockaddr_ll *sll = (sockaddr_ll *)ptr->ifa_addr;
342 QNetworkInterfacePrivate *iface =
new QNetworkInterfacePrivate;
344 iface->index = sll->sll_ifindex;
345 iface->name = QString::fromLatin1(ptr->ifa_name);
346 iface->flags = convertFlags(ptr->ifa_flags);
347 iface->hardwareAddress = iface->makeHwAddress(sll->sll_halen, (uchar*)sll->sll_addr);
349 const bool sawIfaceIndex = seenIndexes.hasSeen(iface->index);
350 Q_ASSERT(!sawIfaceIndex);
351 (
void)seenInterfaces.hasSeen(iface->name);
358 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
359 if (!ptr->ifa_addr || ptr->ifa_addr->sa_family != AF_PACKET) {
360 QString name = QString::fromLatin1(ptr->ifa_name);
361 if (seenInterfaces.hasSeen(name))
364 int ifindex = if_nametoindex(ptr->ifa_name);
365 if (seenIndexes.hasSeen(ifindex))
368 QNetworkInterfacePrivate *iface =
new QNetworkInterfacePrivate;
371 iface->flags = convertFlags(ptr->ifa_flags);
372 iface->index = ifindex;
379static void getAddressExtraInfo(QNetworkAddressEntry *entry,
struct sockaddr *sa,
const char *ifname)
386# elif defined(Q_OS_BSD4)
387QT_BEGIN_INCLUDE_NAMESPACE
388# include <net/if_dl.h>
389#if defined(QT_PLATFORM_UIKIT)
390# include "qnetworkinterface_uikit_p.h"
391# include <net/if_types.h>
393# include <net/if_media.h>
394# include <net/if_types.h>
395# include <netinet/in_var.h>
397QT_END_INCLUDE_NAMESPACE
399static QNetworkInterface::InterfaceType probeIfType(
int socket,
int iftype,
struct ifmediareq *req)
408 return QNetworkInterface::Ppp;
411 return QNetworkInterface::Loopback;
414 return QNetworkInterface::Slip;
417 return QNetworkInterface::Ieee80211;
420 return QNetworkInterface::Ieee1394;
424 return QNetworkInterface::Virtual;
429 if (qt_safe_ioctl(socket, SIOCGIFMEDIA, req) == 0) {
432 switch (IFM_TYPE(req->ifm_current)) {
434 return QNetworkInterface::Ethernet;
438 return QNetworkInterface::Fddi;
442 return QNetworkInterface::Ieee80211;
446 return QNetworkInterface::Unknown;
449static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
451 QList<QNetworkInterfacePrivate *> interfaces;
453 struct ifmediareq mediareq;
457 memset(&mediareq, 0,
sizeof(mediareq));
460 static_assert(
sizeof(mediareq.ifm_name) ==
sizeof(req.ifr_name));
461 static_assert(offsetof(
struct ifmediareq, ifm_name) == 0);
462 static_assert(offsetof(
struct ifreq, ifr_name) == 0);
466 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next)
467 if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_LINK) {
468 QNetworkInterfacePrivate *iface =
new QNetworkInterfacePrivate;
471 sockaddr_dl *sdl = (sockaddr_dl *)ptr->ifa_addr;
472 iface->index = sdl->sdl_index;
473 iface->name = QString::fromLatin1(ptr->ifa_name);
474 iface->flags = convertFlags(ptr->ifa_flags);
475 iface->hardwareAddress = iface->makeHwAddress(sdl->sdl_alen, (uchar*)LLADDR(sdl));
477 qstrncpy(mediareq.ifm_name, ptr->ifa_name,
sizeof(mediareq.ifm_name));
478 iface->type = probeIfType(openSocket(socket), sdl->sdl_type, &mediareq);
479 iface->mtu = getMtu(socket, &req);
483 qt_safe_close(socket);
487static void getAddressExtraInfo(QNetworkAddressEntry *entry,
struct sockaddr *sa,
const char *ifname)
490 if (sa->sa_family != AF_INET6)
493 struct in6_ifreq ifr;
495 int s6 = qt_safe_socket(AF_INET6, SOCK_DGRAM, 0);
496 if (Q_UNLIKELY(s6 < 0)) {
497 qErrnoWarning(
"QNetworkInterface: could not create IPv6 socket");
501 qstrncpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
504 ifr.ifr_addr = *
reinterpret_cast<
struct sockaddr_in6 *>(sa);
505 if (qt_safe_ioctl(s6, SIOCGIFAFLAG_IN6, &ifr) < 0) {
509 int flags = ifr.ifr_ifru.ifru_flags6;
510 QNetworkInterfacePrivate::calculateDnsEligibility(entry,
511 flags & IN6_IFF_TEMPORARY,
512 flags & IN6_IFF_DEPRECATED);
515 ifr.ifr_addr = *
reinterpret_cast<
struct sockaddr_in6 *>(sa);
516 if (qt_safe_ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr) < 0) {
522 auto toDeadline = [](time_t when) {
523 QDeadlineTimer deadline = QDeadlineTimer::Forever;
525#if defined(QT_NO_CLOCK_MONOTONIC)
527 deadline.setPreciseRemainingTime(when - QDateTime::currentSecsSinceEpoch());
529 deadline.setPreciseDeadline(when);
534 entry->setAddressLifetime(toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_preferred),
535 toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_expire));
540static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
542 QList<QNetworkInterfacePrivate *> interfaces;
546 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
548 int ifindex = if_nametoindex(ptr->ifa_name);
550 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
551 for ( ; if_it != interfaces.end(); ++if_it)
552 if ((*if_it)->index == ifindex)
556 if (if_it == interfaces.end()) {
562 iface->name = QString::fromLatin1(ptr->ifa_name);
563 iface->flags = convertFlags(ptr->ifa_flags);
565 if ((socket = openSocket(socket)) >= 0) {
567 qstrncpy(ifr.ifr_name, ptr->ifa_name,
sizeof(ifr.ifr_name));
574 qt_safe_close(socket);
579static void getAddressExtraInfo(QNetworkAddressEntry *entry,
struct sockaddr *sa,
const char *ifname)
587static QList<QNetworkInterfacePrivate *> interfaceListing()
589 QList<QNetworkInterfacePrivate *> interfaces;
591 ifaddrs *interfaceListing;
592 if (getifaddrs(&interfaceListing) == -1) {
597 interfaces = createInterfaces(interfaceListing);
598 for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) {
600 QLatin1StringView name(ptr->ifa_name);
602 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
603 for ( ; if_it != interfaces.end(); ++if_it)
604 if ((*if_it)->name == name) {
612 int ifindex = if_nametoindex(ptr->ifa_name);
613 for (if_it = interfaces.begin(); if_it != interfaces.end(); ++if_it)
614 if ((*if_it)->index == ifindex) {
627 entry.setIp(addressFromSockaddr(ptr->ifa_addr, iface->index, iface->name));
628 if (entry.ip().isNull())
632 entry.setNetmask(addressFromSockaddr(ptr->ifa_netmask, iface->index, iface->name));
633 if (iface->flags & QNetworkInterface::CanBroadcast)
634 entry.setBroadcast(addressFromSockaddr(ptr->ifa_broadaddr, iface->index, iface->name));
635 getAddressExtraInfo(&entry, ptr->ifa_addr, name.latin1());
637 iface->addressEntries << entry;
640 freeifaddrs(interfaceListing);
647 return interfaceListing();
The QNetworkAddressEntry class stores one IP address supported by a network interface,...
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)