12#include <QtCore/private/qduplicatetracker_p.h>
14#ifndef QT_NO_NETWORKINTERFACE
16#if defined(QT_NO_CLOCK_MONOTONIC)
17# include "qdatetime.h"
20#if QT_CONFIG(getifaddrs)
25# include <arpa/inet.h>
26# ifndef SIOCGIFBRDADDR
27# define SIOCGIFBRDADDR 0x8919
31#include <qplatformdefs.h>
41 if (sa->sa_family == AF_INET)
42 address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr));
43 else if (sa->sa_family ==
AF_INET6) {
44 address.setAddress(((sockaddr_in6 *)sa)->sin6_addr.s6_addr);
45 int scope = ((sockaddr_in6 *)sa)->sin6_scope_id;
46 if (scope && scope == ifindex) {
49 address.setScopeId(ifname);
57template <
typename Req> [[maybe_unused]]
58static auto &
ifreq_index(Req &req, std::enable_if_t<
sizeof(std::declval<Req>().ifr_index) != 0,
int> = 0)
63template <
typename Req> [[maybe_unused]]
64static auto &
ifreq_index(Req &req, std::enable_if_t<
sizeof(std::declval<Req>().ifr_ifindex) != 0,
int> = 0)
66 return req.ifr_ifindex;
71#if QT_CONFIG(ipv6ifname)
72 return ::if_nametoindex(name.toLatin1().constData());
73#elif defined(SIOCGIFINDEX)
75 int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0);
79 const QByteArray name8bit = name.toLatin1();
80 memset(&req, 0,
sizeof(ifreq));
81 if (!name8bit.isNull())
82 memcpy(req.ifr_name, name8bit.data(), qMin(size_t(name8bit.length()) + 1,
sizeof(req.ifr_name) - 1));
85 if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
86 id = ifreq_index(req);
87 qt_safe_close(socket);
97#if QT_CONFIG(ipv6ifname)
98 char buf[IF_NAMESIZE];
99 if (::if_indextoname(index, buf))
100 return QString::fromLatin1(buf);
101#elif defined(SIOCGIFNAME)
103 int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0);
105 memset(&req, 0,
sizeof(ifreq));
106 ifreq_index(req) = index;
107 if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) {
108 qt_safe_close(socket);
109 return QString::fromLatin1(req.ifr_name);
111 qt_safe_close(socket);
114 return QString::number(uint(index));
117static int getMtu(
int socket,
struct ifreq *req)
120 if (qt_safe_ioctl(socket, SIOCGIFMTU, req) == 0)
126#if !QT_CONFIG(getifaddrs)
129static QSet<QByteArray> interfaceNames(
int socket)
131 QSet<QByteArray> result;
132#if !QT_CONFIG(ipv6ifname)
133 QByteArray storageBuffer;
134 struct ifconf interfaceList;
135 static const int STORAGEBUFFER_GROWTH = 256;
139 storageBuffer.resize(storageBuffer.size() + STORAGEBUFFER_GROWTH);
140 interfaceList.ifc_buf = storageBuffer.data();
141 interfaceList.ifc_len = storageBuffer.size();
144 if (qt_safe_ioctl(socket, SIOCGIFCONF, &interfaceList) >= 0) {
145 if (
int(interfaceList.ifc_len +
sizeof(ifreq) + 64) < storageBuffer.size()) {
147 storageBuffer.resize(interfaceList.ifc_len);
154 if (storageBuffer.size() > 100000) {
160 int interfaceCount = interfaceList.ifc_len /
sizeof(ifreq);
161 for (
int i = 0; i < interfaceCount; ++i) {
162 QByteArray name = QByteArray(interfaceList.ifc_req[i].ifr_name);
172 struct if_nameindex *interfaceList = ::if_nameindex();
173 for (
struct if_nameindex *ptr = interfaceList; ptr && ptr->if_name; ++ptr)
174 result << ptr->if_name;
176 if_freenameindex(interfaceList);
181static QNetworkInterfacePrivate *findInterface(
int socket, QList<QNetworkInterfacePrivate *> &interfaces,
184 QNetworkInterfacePrivate *iface =
nullptr;
187#if QT_CONFIG(ipv6ifname) || defined(SIOCGIFINDEX)
190 if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
191 ifindex = ifreq_index(req);
193 ifindex = if_nametoindex(req.ifr_name);
197 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
198 for ( ; if_it != interfaces.end(); ++if_it)
199 if ((*if_it)->index == ifindex) {
207 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
208 for ( ; if_it != interfaces.end(); ++if_it)
209 if ((*if_it)->name == QLatin1StringView(req.ifr_name)) {
218 iface =
new QNetworkInterfacePrivate;
219 iface->index = ifindex;
226static QList<QNetworkInterfacePrivate *> interfaceListing()
228 QList<QNetworkInterfacePrivate *> interfaces;
231 if ((socket = qt_safe_socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
234 QSet<QByteArray> names = interfaceNames(socket);
235 QSet<QByteArray>::ConstIterator it = names.constBegin();
236 for ( ; it != names.constEnd(); ++it) {
238 memset(&req, 0,
sizeof(ifreq));
240 memcpy(req.ifr_name, it->constData(), qMin(size_t(it->length()) + 1,
sizeof(req.ifr_name) - 1));
242 QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
246 QByteArray oldName = req.ifr_name;
247 if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) {
248 iface->name = QString::fromLatin1(req.ifr_name);
251 if (!oldName.isNull())
252 memcpy(req.ifr_name, oldName.constData(), qMin(size_t(oldName.length()) + 1,
sizeof(req.ifr_name) - 1));
257 iface->name = QString::fromLatin1(req.ifr_name);
261 if (qt_safe_ioctl(socket, SIOCGIFFLAGS, &req) >= 0) {
262 iface->flags = convertFlags(req.ifr_flags);
264 iface->mtu = getMtu(socket, &req);
268 if (qt_safe_ioctl(socket, SIOCGIFHWADDR, &req) >= 0) {
269 uchar *addr = (uchar *)req.ifr_addr.sa_data;
270 iface->hardwareAddress = iface->makeHwAddress(6, addr);
275 QNetworkAddressEntry entry;
276 if (qt_safe_ioctl(socket, SIOCGIFADDR, &req) >= 0) {
277 sockaddr *sa = &req.ifr_addr;
278 entry.setIp(addressFromSockaddr(sa));
281 if (iface->flags & QNetworkInterface::CanBroadcast) {
282 if (qt_safe_ioctl(socket, SIOCGIFBRDADDR, &req) >= 0) {
283 sockaddr *sa = &req.ifr_addr;
284 if (sa->sa_family == AF_INET)
285 entry.setBroadcast(addressFromSockaddr(sa));
290 if (qt_safe_ioctl(socket, SIOCGIFNETMASK, &req) >= 0) {
291 sockaddr *sa = &req.ifr_addr;
292 entry.setNetmask(addressFromSockaddr(sa));
295 iface->addressEntries << entry;
308QT_BEGIN_INCLUDE_NAMESPACE
309# include <features.h>
310QT_END_INCLUDE_NAMESPACE
313static int openSocket(
int &socket)
316 socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0);
320# if defined(Q_OS_LINUX) && __GLIBC__
- 0
>= 2
&& __GLIBC_MINOR__
- 0
>= 1
&& !defined(QT_LINUXBASE)
321# include <netpacket/packet.h>
323static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
326 Q_UNUSED(openSocket);
327 QList<QNetworkInterfacePrivate *> interfaces;
328 QDuplicateTracker<QString> seenInterfaces;
329 QDuplicateTracker<
int> seenIndexes;
338 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
339 if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_PACKET) {
340 sockaddr_ll *sll = (sockaddr_ll *)ptr->ifa_addr;
341 QNetworkInterfacePrivate *iface =
new QNetworkInterfacePrivate;
343 iface->index = sll->sll_ifindex;
344 iface->name = QString::fromLatin1(ptr->ifa_name);
345 iface->flags = convertFlags(ptr->ifa_flags);
346 iface->hardwareAddress = iface->makeHwAddress(sll->sll_halen, (uchar*)sll->sll_addr);
348 const bool sawIfaceIndex = seenIndexes.hasSeen(iface->index);
349 Q_ASSERT(!sawIfaceIndex);
350 (
void)seenInterfaces.hasSeen(iface->name);
357 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
358 if (!ptr->ifa_addr || ptr->ifa_addr->sa_family != AF_PACKET) {
359 QString name = QString::fromLatin1(ptr->ifa_name);
360 if (seenInterfaces.hasSeen(name))
363 int ifindex = if_nametoindex(ptr->ifa_name);
364 if (seenIndexes.hasSeen(ifindex))
367 QNetworkInterfacePrivate *iface =
new QNetworkInterfacePrivate;
370 iface->flags = convertFlags(ptr->ifa_flags);
371 iface->index = ifindex;
378static void getAddressExtraInfo(QNetworkAddressEntry *entry,
struct sockaddr *sa,
const char *ifname)
385# elif defined(Q_OS_BSD4)
386QT_BEGIN_INCLUDE_NAMESPACE
387# include <net/if_dl.h>
388#if defined(QT_PLATFORM_UIKIT)
389# include "qnetworkinterface_uikit_p.h"
390# include <net/if_types.h>
392# include <net/if_media.h>
393# include <net/if_types.h>
394# include <netinet/in_var.h>
396QT_END_INCLUDE_NAMESPACE
398static QNetworkInterface::InterfaceType probeIfType(
int socket,
int iftype,
struct ifmediareq *req)
407 return QNetworkInterface::Ppp;
410 return QNetworkInterface::Loopback;
413 return QNetworkInterface::Slip;
416 return QNetworkInterface::Ieee80211;
419 return QNetworkInterface::Ieee1394;
423 return QNetworkInterface::Virtual;
428 if (qt_safe_ioctl(socket, SIOCGIFMEDIA, req) == 0) {
431 switch (IFM_TYPE(req->ifm_current)) {
433 return QNetworkInterface::Ethernet;
437 return QNetworkInterface::Fddi;
441 return QNetworkInterface::Ieee80211;
445 return QNetworkInterface::Unknown;
448static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
450 QList<QNetworkInterfacePrivate *> interfaces;
452 struct ifmediareq mediareq;
456 memset(&mediareq, 0,
sizeof(mediareq));
459 static_assert(
sizeof(mediareq.ifm_name) ==
sizeof(req.ifr_name));
460 static_assert(offsetof(
struct ifmediareq, ifm_name) == 0);
461 static_assert(offsetof(
struct ifreq, ifr_name) == 0);
465 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next)
466 if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_LINK) {
467 QNetworkInterfacePrivate *iface =
new QNetworkInterfacePrivate;
470 sockaddr_dl *sdl = (sockaddr_dl *)ptr->ifa_addr;
471 iface->index = sdl->sdl_index;
472 iface->name = QString::fromLatin1(ptr->ifa_name);
473 iface->flags = convertFlags(ptr->ifa_flags);
474 iface->hardwareAddress = iface->makeHwAddress(sdl->sdl_alen, (uchar*)LLADDR(sdl));
476 qstrncpy(mediareq.ifm_name, ptr->ifa_name,
sizeof(mediareq.ifm_name));
477 iface->type = probeIfType(openSocket(socket), sdl->sdl_type, &mediareq);
478 iface->mtu = getMtu(socket, &req);
482 qt_safe_close(socket);
486static void getAddressExtraInfo(QNetworkAddressEntry *entry,
struct sockaddr *sa,
const char *ifname)
489 if (sa->sa_family != AF_INET6)
492 struct in6_ifreq ifr;
494 int s6 = qt_safe_socket(AF_INET6, SOCK_DGRAM, 0);
495 if (Q_UNLIKELY(s6 < 0)) {
496 qErrnoWarning(
"QNetworkInterface: could not create IPv6 socket");
500 qstrncpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
503 ifr.ifr_addr = *
reinterpret_cast<
struct sockaddr_in6 *>(sa);
504 if (qt_safe_ioctl(s6, SIOCGIFAFLAG_IN6, &ifr) < 0) {
508 int flags = ifr.ifr_ifru.ifru_flags6;
509 QNetworkInterfacePrivate::calculateDnsEligibility(entry,
510 flags & IN6_IFF_TEMPORARY,
511 flags & IN6_IFF_DEPRECATED);
514 ifr.ifr_addr = *
reinterpret_cast<
struct sockaddr_in6 *>(sa);
515 if (qt_safe_ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr) < 0) {
521 auto toDeadline = [](time_t when) {
522 QDeadlineTimer deadline = QDeadlineTimer::Forever;
524#if defined(QT_NO_CLOCK_MONOTONIC)
526 deadline.setPreciseRemainingTime(when - QDateTime::currentSecsSinceEpoch());
528 deadline.setPreciseDeadline(when);
533 entry->setAddressLifetime(toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_preferred),
534 toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_expire));
539static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
541 QList<QNetworkInterfacePrivate *> interfaces;
545 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
547 int ifindex = if_nametoindex(ptr->ifa_name);
549 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
550 for ( ; if_it != interfaces.end(); ++if_it)
551 if ((*if_it)->index == ifindex)
555 if (if_it == interfaces.end()) {
561 iface->name = QString::fromLatin1(ptr->ifa_name);
562 iface->flags = convertFlags(ptr->ifa_flags);
564 if ((socket = openSocket(socket)) >= 0) {
566 qstrncpy(ifr.ifr_name, ptr->ifa_name,
sizeof(ifr.ifr_name));
573 qt_safe_close(socket);
578static void getAddressExtraInfo(QNetworkAddressEntry *entry,
struct sockaddr *sa,
const char *ifname)
586static QList<QNetworkInterfacePrivate *> interfaceListing()
588 QList<QNetworkInterfacePrivate *> interfaces;
590 ifaddrs *interfaceListing;
591 if (getifaddrs(&interfaceListing) == -1) {
596 interfaces = createInterfaces(interfaceListing);
597 for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) {
599 QLatin1StringView name(ptr->ifa_name);
601 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
602 for ( ; if_it != interfaces.end(); ++if_it)
603 if ((*if_it)->name == name) {
611 int ifindex = if_nametoindex(ptr->ifa_name);
612 for (if_it = interfaces.begin(); if_it != interfaces.end(); ++if_it)
613 if ((*if_it)->index == ifindex) {
626 entry.setIp(addressFromSockaddr(ptr->ifa_addr, iface->index, iface->name));
627 if (entry.ip().isNull())
631 entry.setNetmask(addressFromSockaddr(ptr->ifa_netmask, iface->index, iface->name));
632 if (iface->flags & QNetworkInterface::CanBroadcast)
633 entry.setBroadcast(addressFromSockaddr(ptr->ifa_broadaddr, iface->index, iface->name));
634 getAddressExtraInfo(&entry, ptr->ifa_addr, name.latin1());
636 iface->addressEntries << entry;
639 freeifaddrs(interfaceListing);
646 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)