diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/network/kernel/qnetworkinterface_unix.cpp | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp index cc53087024..5e6d24dd44 100644 --- a/src/network/kernel/qnetworkinterface_unix.cpp +++ b/src/network/kernel/qnetworkinterface_unix.cpp @@ -314,10 +314,15 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) { QList<QNetworkInterfacePrivate *> interfaces; QSet<QString> seenInterfaces; - - // on Linux, AF_PACKET addresses carry the hardware address and interface index; - // scan for them first (they're usually first, but we have no guarantee this - // will be the case forever) + QVarLengthArray<int, 16> seenIndexes; // faster than QSet<int> + + // On Linux, glibc, uClibc and MUSL obtain the address listing via two + // netlink calls: first an RTM_GETLINK to obtain the interface listing, + // then one RTM_GETADDR to get all the addresses (uClibc implementation is + // copied from glibc; Bionic currently doesn't support getifaddrs). They + // synthesize AF_PACKET addresses from the RTM_GETLINK responses, which + // means by construction they currently show up first in the interface + // listing. for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) { if (ptr->ifa_addr && ptr->ifa_addr->sa_family == AF_PACKET) { sockaddr_ll *sll = (sockaddr_ll *)ptr->ifa_addr; @@ -328,23 +333,30 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) iface->flags = convertFlags(ptr->ifa_flags); iface->hardwareAddress = iface->makeHwAddress(sll->sll_halen, (uchar*)sll->sll_addr); + Q_ASSERT(!seenIndexes.contains(iface->index)); + seenIndexes.append(iface->index); seenInterfaces.insert(iface->name); } } // see if we missed anything: - // virtual interfaces with no HW address have no AF_PACKET + // - virtual interfaces with no HW address have no AF_PACKET + // - interface labels have no AF_PACKET, but shouldn't be shown as a new interface for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) { if (ptr->ifa_addr && ptr->ifa_addr->sa_family != AF_PACKET) { QString name = QString::fromLatin1(ptr->ifa_name); if (seenInterfaces.contains(name)) continue; + int ifindex = if_nametoindex(ptr->ifa_name); + if (seenIndexes.contains(ifindex)) + continue; + QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate; interfaces << iface; iface->name = name; iface->flags = convertFlags(ptr->ifa_flags); - iface->index = if_nametoindex(ptr->ifa_name); + iface->index = ifindex; } } @@ -423,7 +435,7 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() interfaces = createInterfaces(interfaceListing); for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) { - // Get the interface index + // Find the interface QString name = QString::fromLatin1(ptr->ifa_name); QNetworkInterfacePrivate *iface = 0; QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin(); @@ -433,6 +445,18 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() iface = *if_it; break; } + + if (!iface) { + // it may be an interface label, search by interface index + int ifindex = if_nametoindex(ptr->ifa_name); + for (if_it = interfaces.begin(); if_it != interfaces.end(); ++if_it) + if ((*if_it)->index == ifindex) { + // found this interface already + iface = *if_it; + break; + } + } + if (!iface) { // skip all non-IP interfaces continue; |