summaryrefslogtreecommitdiffstats
path: root/src/network/kernel
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2015-12-02 11:08:56 -0800
committerThiago Macieira <thiago.macieira@intel.com>2015-12-08 06:32:22 +0000
commitbdd4ddd8fae7ba14548e1b6f01f7b9d143261db2 (patch)
tree0c9f091d1b422a46c31e9befad3064864ef78195 /src/network/kernel
parent401507b348936d346cec8734cac5cacad70a3174 (diff)
QNetworkInterface: fix support for address labels on Linux interfaces
Commit 64a1448d87727878d9789906b2f4f5b9e3d74e38 (Qt 5.2) caused QNetworkInterface to report address labels (a.k.a. interface aliases) as separate interfaces. This is caused by the fact that glibc, uClibc and MUSL copy the address label (netlink address attribute IFA_LABEL) to the ifa_name field, which made QNetworkInterfaceManager think that it was an interface it hadn't yet seen. Address labels are the old way to add more than one IP address to an interface on Linux, for example: ifconfig eth0:1 192.0.2.2 Those do not create a new interface, so the "eth0:1" label maps to the same interface index as the parent interface. This has been deprecated for 10 years, but there are still tools out there that add addresses in this manner. This commit restores behavior compatibility with Qt 4.2-5.1. The Qt 5.2-5.5 behavior is incorrect because it reports more than one interface with the same index. On systems configured like the above, the tst_QNetworkInterface::interfaceFromXXX test was failing. Change-Id: I8de47ed6c7be4847b99bffff141c2d9de8cf7329 Reviewed-by: Richard J. Moore <rich@kde.org>
Diffstat (limited to 'src/network/kernel')
-rw-r--r--src/network/kernel/qnetworkinterface_unix.cpp38
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;