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
395static QNetworkInterface::InterfaceType probeIfType(
int socket,
int iftype,
struct ifmediareq *req)
404 return QNetworkInterface::Ppp;
407 return QNetworkInterface::Loopback;
410 return QNetworkInterface::Slip;
413 return QNetworkInterface::Ieee80211;
416 return QNetworkInterface::Ieee1394;
420 return QNetworkInterface::Virtual;
425 if (qt_safe_ioctl(socket, SIOCGIFMEDIA, req) == 0) {
428 switch (IFM_TYPE(req->ifm_current)) {
430 return QNetworkInterface::Ethernet;
434 return QNetworkInterface::Fddi;
438 return QNetworkInterface::Ieee80211;
442 return QNetworkInterface::Unknown;
445static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
447 QList<QNetworkInterfacePrivate *> interfaces;
449 struct ifmediareq mediareq;
453 memset(&mediareq, 0,
sizeof(mediareq));
456 static_assert(
sizeof(mediareq.ifm_name) ==
sizeof(req.ifr_name));
457 static_assert(offsetof(
struct ifmediareq, ifm_name) == 0);
458 static_assert(offsetof(
struct ifreq, ifr_name) == 0);
462 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next)
463 if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_LINK) {
464 QNetworkInterfacePrivate *iface =
new QNetworkInterfacePrivate;
467 sockaddr_dl *sdl = (sockaddr_dl *)ptr->ifa_addr;
468 iface->index = sdl->sdl_index;
469 iface->name = QString::fromLatin1(ptr->ifa_name);
470 iface->flags = convertFlags(ptr->ifa_flags);
471 iface->hardwareAddress = iface->makeHwAddress(sdl->sdl_alen, (uchar*)LLADDR(sdl));
473 qstrncpy(mediareq.ifm_name, ptr->ifa_name,
sizeof(mediareq.ifm_name));
474 iface->type = probeIfType(openSocket(socket), sdl->sdl_type, &mediareq);
475 iface->mtu = getMtu(socket, &req);
479 qt_safe_close(socket);
483static void getAddressExtraInfo(QNetworkAddressEntry *entry,
struct sockaddr *sa,
const char *ifname)
486 if (sa->sa_family != AF_INET6)
489 struct in6_ifreq ifr;
491 int s6 = qt_safe_socket(AF_INET6, SOCK_DGRAM, 0);
492 if (Q_UNLIKELY(s6 < 0)) {
493 qErrnoWarning(
"QNetworkInterface: could not create IPv6 socket");
497 qstrncpy(ifr.ifr_name, ifname,
sizeof(ifr.ifr_name));
500 ifr.ifr_addr = *
reinterpret_cast<
struct sockaddr_in6 *>(sa);
501 if (qt_safe_ioctl(s6, SIOCGIFAFLAG_IN6, &ifr) < 0) {
505 int flags = ifr.ifr_ifru.ifru_flags6;
506 QNetworkInterfacePrivate::calculateDnsEligibility(entry,
507 flags & IN6_IFF_TEMPORARY,
508 flags & IN6_IFF_DEPRECATED);
511 ifr.ifr_addr = *
reinterpret_cast<
struct sockaddr_in6 *>(sa);
512 if (qt_safe_ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr) < 0) {
518 auto toDeadline = [](time_t when) {
519 QDeadlineTimer deadline = QDeadlineTimer::Forever;
521 deadline.setPreciseDeadline(when);
525 entry->setAddressLifetime(toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_preferred),
526 toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_expire));
531static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
533 QList<QNetworkInterfacePrivate *> interfaces;
537 for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
539 int ifindex = if_nametoindex(ptr->ifa_name);
541 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
542 for ( ; if_it != interfaces.end(); ++if_it)
543 if ((*if_it)->index == ifindex)
547 if (if_it == interfaces.end()) {
553 iface->name = QString::fromLatin1(ptr->ifa_name);
554 iface->flags = convertFlags(ptr->ifa_flags);
556 if ((socket = openSocket(socket)) >= 0) {
558 qstrncpy(ifr.ifr_name, ptr->ifa_name,
sizeof(ifr.ifr_name));
565 qt_safe_close(socket);
570static void getAddressExtraInfo(QNetworkAddressEntry *entry,
struct sockaddr *sa,
const char *ifname)
578static QList<QNetworkInterfacePrivate *> interfaceListing()
580 QList<QNetworkInterfacePrivate *> interfaces;
582 ifaddrs *interfaceListing;
583 if (getifaddrs(&interfaceListing) == -1) {
588 interfaces = createInterfaces(interfaceListing);
589 for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) {
591 QLatin1StringView name(ptr->ifa_name);
593 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
594 for ( ; if_it != interfaces.end(); ++if_it)
595 if ((*if_it)->name == name) {
603 int ifindex = if_nametoindex(ptr->ifa_name);
604 for (if_it = interfaces.begin(); if_it != interfaces.end(); ++if_it)
605 if ((*if_it)->index == ifindex) {
618 entry.setIp(addressFromSockaddr(ptr->ifa_addr, iface->index, iface->name));
619 if (entry.ip().isNull())
623 entry.setNetmask(addressFromSockaddr(ptr->ifa_netmask, iface->index, iface->name));
624 if (iface->flags & QNetworkInterface::CanBroadcast)
625 entry.setBroadcast(addressFromSockaddr(ptr->ifa_broadaddr, iface->index, iface->name));
626 getAddressExtraInfo(&entry, ptr->ifa_addr, name.latin1());
628 iface->addressEntries << entry;
631 freeifaddrs(interfaceListing);
638 return interfaceListing();
The QNetworkAddressEntry class stores one IP address supported by a network interface,...
static uint interfaceIndexFromName(const QString &name)
static QString interfaceNameFromIndex(uint index)
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)