Search code examples
qtnetwork-programmingqt5qtnetwork

QNetworkInterface returns duplicate addresses


Qt5.9.2 for RPi3. Here the current target scenario:

# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.167  netmask 255.255.0.0  broadcast 192.168.255.255
        inet6 fd00::b465:a62:a349:a7a5  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::dbfe:16c3:a5cd:9509  prefixlen 64  scopeid 0x20<link>
        ether b8:27:eb:22:00:43  txqueuelen 1000  (Ethernet)
        RX packets 338  bytes 44737 (43.6 KiB)
        RX errors 0  dropped 1  overruns 0  frame 0
        TX packets 238  bytes 27565 (26.9 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 40  bytes 8560 (8.3 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 40  bytes 8560 (8.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.179  netmask 255.255.0.0  broadcast 192.168.255.255
        inet6 fd00::2eed:5f16:9646:fe07  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::c460:6252:ee34:8695  prefixlen 64  scopeid 0x20<link>
        ether 00:c6:b1:8f:a1:38  txqueuelen 1000  (Ethernet)
        RX packets 149  bytes 45709 (44.6 KiB)
        RX errors 0  dropped 97  overruns 0  frame 0
        TX packets 106  bytes 17632 (17.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Here my code that should retrieve the IPv4 addresses:

const QHostAddress &localhost = QHostAddress(QHostAddress::LocalHost);
for (const QNetworkInterface &interface: QNetworkInterface::allInterfaces())
{
    QString name = interface.name();
    for (const QHostAddress &address: interface.allAddresses())
    {
        if (address.protocol() == QAbstractSocket::IPv4Protocol && address != localhost && (interface.flags() & QNetworkInterface::IsRunning))
            qDebug() << name << address << interface.flags();
    }
}

Here the output:

"lo" QHostAddress("192.168.1.167") QFlags(0x1|0x2|0x8)
"lo" QHostAddress("192.168.1.179") QFlags(0x1|0x2|0x8)
"eth0" QHostAddress("192.168.1.167") QFlags(0x1|0x2|0x4|0x20)
"eth0" QHostAddress("192.168.1.179") QFlags(0x1|0x2|0x4|0x20)
"wlan0" QHostAddress("192.168.1.167") QFlags(0x1|0x2|0x4|0x20)
"wlan0" QHostAddress("192.168.1.179") QFlags(0x1|0x2|0x4|0x20)

Instead, according to ifconfig, I'm expecting only:

"eth0" QHostAddress("192.168.1.167") QFlags(0x1|0x2|0x4|0x20)
"wlan0" QHostAddress("192.168.1.179") QFlags(0x1|0x2|0x4|0x20)

Is my code wrong?


Solution

  • Cause

    As the documentation of QNetworkInterface::allInterfaces says:

    This convenience function returns all IP addresses found on the host machine.

    Note: The emphasis is mine.

    This means, that with two interfaces, your code will essentially loop through the addresses twice.

    Solution

    Use QNetworkInterface::addressEntries instead. Then use QNetworkAddressEntry::ip to obtain the information you need.

    Example

    Here is an example implementation of the proposed solution:

    for (auto interface : QNetworkInterface::allInterfaces()) {
        for (auto address : interface.addressEntries()) {
            const QHostAddress &ip(address.ip());
    
            if (!ip.isLoopback() && (ip.protocol() == QAbstractSocket::IPv4Protocol) && (interface.flags() & QNetworkInterface::IsRunning))
                qDebug() << interface.humanReadableName() << ip.toString();
        }
    }