NetworkDeviceDiscovery: Skip duplicated discovery if there are multiple network interfaces connected to the same network

This commit is contained in:
Simon Stürz 2022-11-30 00:31:37 +01:00
parent da6d7b8efe
commit 285abcdd36
2 changed files with 76 additions and 34 deletions

View File

@ -29,10 +29,11 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "networkdevicediscoveryimpl.h" #include "networkdevicediscoveryimpl.h"
#include "nymeasettings.h" #include "nymeasettings.h"
#include "loggingcategories.h" #include "loggingcategories.h"
#include <math.h>
#include <network/ping.h> #include <network/ping.h>
#include <network/arpsocket.h> #include <network/arpsocket.h>
#include <network/networkutils.h> #include <network/networkutils.h>
@ -339,6 +340,9 @@ void NetworkDeviceDiscoveryImpl::setEnabled(bool enabled)
void NetworkDeviceDiscoveryImpl::pingAllNetworkDevices() void NetworkDeviceDiscoveryImpl::pingAllNetworkDevices()
{ {
QList<QHostAddress> ownAddresses;
QList<TargetNetwork> targetNetworks;
qCDebug(dcNetworkDeviceDiscovery()) << "Starting ping for all network devices..."; qCDebug(dcNetworkDeviceDiscovery()) << "Starting ping for all network devices...";
foreach (const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) { foreach (const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
if (networkInterface.flags().testFlag(QNetworkInterface::IsLoopBack)) if (networkInterface.flags().testFlag(QNetworkInterface::IsLoopBack))
@ -352,31 +356,64 @@ void NetworkDeviceDiscoveryImpl::pingAllNetworkDevices()
qCDebug(dcNetworkDeviceDiscovery()) << "Verifying network interface" << networkInterface.name() << networkInterface.hardwareAddress() << "..."; qCDebug(dcNetworkDeviceDiscovery()) << "Verifying network interface" << networkInterface.name() << networkInterface.hardwareAddress() << "...";
foreach (const QNetworkAddressEntry &entry, networkInterface.addressEntries()) { foreach (const QNetworkAddressEntry &entry, networkInterface.addressEntries()) {
qCDebug(dcNetworkDeviceDiscovery()) << " Checking entry" << entry.ip().toString();
// Only IPv4 // Only IPv4
if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol) if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol)
continue; continue;
// Store the own address of this network interface in any case,
// since we don't want to ping our self
ownAddresses.append(entry.ip());
TargetNetwork targetNetwork;
targetNetwork.networkInterface = networkInterface;
targetNetwork.addressEntry = entry;
targetNetwork.address = QHostAddress(entry.ip().toIPv4Address() & entry.netmask().toIPv4Address());
qCDebug(dcNetworkDeviceDiscovery()) << " Checking entry" << entry.ip().toString();
qCDebug(dcNetworkDeviceDiscovery()) << " Host address:" << entry.ip().toString(); qCDebug(dcNetworkDeviceDiscovery()) << " Host address:" << entry.ip().toString();
qCDebug(dcNetworkDeviceDiscovery()) << " Network address:" << targetNetwork.address.toString();
qCDebug(dcNetworkDeviceDiscovery()) << " Broadcast address:" << entry.broadcast().toString(); qCDebug(dcNetworkDeviceDiscovery()) << " Broadcast address:" << entry.broadcast().toString();
qCDebug(dcNetworkDeviceDiscovery()) << " Netmask:" << entry.netmask().toString(); qCDebug(dcNetworkDeviceDiscovery()) << " Netmask:" << entry.netmask().toString();
quint32 addressRangeStart = entry.ip().toIPv4Address() & entry.netmask().toIPv4Address(); qCDebug(dcNetworkDeviceDiscovery()) << " Address rang from" << targetNetwork.address.toString() << "-->" << targetNetwork.addressEntry.broadcast().toString();
quint32 addressRangeStop = entry.broadcast().toIPv4Address() | addressRangeStart;
quint32 range = addressRangeStop - addressRangeStart;
// Let's scan only 255.255.255.0 networks for now // Let's scan only 255.255.255.0 networks for now
if (range > 255) if (entry.prefixLength() < 24) {
qCDebug(dcNetworkDeviceDiscovery()) << "Skipping network interface" << networkInterface.name() << "because there are to many hosts to contact. The network detector was designed for /24 networks.";
continue;
}
// Filter out duplicated networks (for example connected using wifi and ethernet to the same network) ...
bool duplicatedNetwork = false;
foreach (const TargetNetwork &tn, targetNetworks) {
if (tn.address == targetNetwork.address && tn.addressEntry.netmask() == targetNetwork.addressEntry.netmask()) {
qCDebug(dcNetworkDeviceDiscovery()) << "Skipping network interface" << targetNetwork.networkInterface.name() << targetNetwork.address.toString() << "as ping target network because it seems to be the same network as" << tn.networkInterface.name() << tn.address.toString();
duplicatedNetwork = true;
break;
}
}
if (duplicatedNetwork)
continue; continue;
qCDebug(dcNetworkDeviceDiscovery()) << " Address range" << range << " | from" << QHostAddress(addressRangeStart).toString() << "-->" << QHostAddress(addressRangeStop).toString(); targetNetworks.append(targetNetwork);
}
}
foreach (const TargetNetwork &targetNetwork, targetNetworks) {
// Send ping request to each address within the range // Send ping request to each address within the range
for (quint32 i = 1; i < range; i++) { quint32 targetHostsCount = pow(2, 32 - targetNetwork.addressEntry.prefixLength()) - 1;
quint32 address = addressRangeStart + i; for (quint32 i = 1; i < targetHostsCount; i++) {
QHostAddress targetAddress(address); QHostAddress targetAddress(targetNetwork.address.toIPv4Address() + i);
// Skip the broadcast
if (targetAddress == targetNetwork.addressEntry.broadcast())
continue;
// Skip our self // Skip our self
if (targetAddress == entry.ip()) if (ownAddresses.contains(targetAddress))
continue; continue;
// Retry only once to ping a device and lookup the hostname on success // Retry only once to ping a device and lookup the hostname on success
@ -404,7 +441,6 @@ void NetworkDeviceDiscoveryImpl::pingAllNetworkDevices()
} }
} }
} }
}
void NetworkDeviceDiscoveryImpl::processMonitorPingResult(PingReply *reply, NetworkDeviceMonitorImpl *monitor) void NetworkDeviceDiscoveryImpl::processMonitorPingResult(PingReply *reply, NetworkDeviceMonitorImpl *monitor)
{ {

View File

@ -85,6 +85,12 @@ protected:
void setEnabled(bool enabled) override; void setEnabled(bool enabled) override;
private: private:
typedef struct TargetNetwork {
QNetworkInterface networkInterface;
QNetworkAddressEntry addressEntry;
QHostAddress address;
} TargetNetwork;
MacAddressDatabase *m_macAddressDatabase = nullptr; MacAddressDatabase *m_macAddressDatabase = nullptr;
ArpSocket *m_arpSocket = nullptr; ArpSocket *m_arpSocket = nullptr;
Ping *m_ping = nullptr; Ping *m_ping = nullptr;