From 75d16aab1b21f20bf13e789a5d5c715a4b3f7652 Mon Sep 17 00:00:00 2001 From: dmiller Date: Mon, 15 Jun 2026 15:14:10 +0000 Subject: [PATCH] Properly determine device name from target if possible --- nping/EchoServer.cc | 11 ++++-- nping/NpingOps.cc | 90 +++++-------------------------------------- nping/NpingOps.h | 2 +- nping/NpingTargets.cc | 32 ++++++++++++++- nping/NpingTargets.h | 13 +++++++ nping/ProbeMode.cc | 19 +++++---- 6 files changed, 72 insertions(+), 95 deletions(-) diff --git a/nping/EchoServer.cc b/nping/EchoServer.cc index b0f51dabe..41108fc67 100644 --- a/nping/EchoServer.cc +++ b/nping/EchoServer.cc @@ -1411,14 +1411,17 @@ int EchoServer::start() { nping_fatal(QT_3, "Failed to create new nsock_iod. QUITTING.\n"); /* Open pcap */ - nping_print(DBG_2,"Opening pcap device %s", o.getDevice()); - Strncpy(pcapdev, o.getDevice(), sizeof(pcapdev)); + const char *device = o.getDevice(); + if (!device) + nping_fatal(QT_3, "Unable to determine device name. QUITTING.\n"); + nping_print(DBG_2,"Opening pcap device %s", device); + Strncpy(pcapdev, device, sizeof(pcapdev)); rc = nsock_pcap_open(nsp, pcap_nsi, pcapdev, MAX_ECHOED_PACKET_LEN, 1, ProbeMode::getBPFFilterString()); if (rc) - nping_fatal(QT_3, "Error opening capture device %s\n", o.getDevice()); + nping_fatal(QT_3, "Error opening capture device %s\n", device); else - nping_print(VB_0,"Packet capture will be performed using network interface %s.", o.getDevice()); + nping_print(VB_0,"Packet capture will be performed using network interface %s.", device); nping_print(VB_0,"Waiting for connections..."); /* Get a socket suitable for an accept() call */ diff --git a/nping/NpingOps.cc b/nping/NpingOps.cc index c9d79982e..07bbc7274 100644 --- a/nping/NpingOps.cc +++ b/nping/NpingOps.cc @@ -701,8 +701,14 @@ int NpingOps::setDevice(char *n){ } /* End of setDevice() */ -char *NpingOps::getDevice(){ - return this->device; +const char *NpingOps::getDevice(){ + if (this->device_set) + return this->device; + if (this->targets.devices.empty()) + return NULL; + if (this->targets.devices.size() > 1) + nping_fatal(QT_3, "Nping does not support targets on multiple devices. QUITTING.\n"); + return this->targets.devices.front()->getName(); } /* End of getDevice() */ @@ -2301,86 +2307,8 @@ if (this->isRoot() && this->havePcap()==false){ nping_print(VB_0, "Warning: Payload supplied in TCP Connect mode. Payload will be ignored."); } -/** SOURCE IP, SOURCE MAC and NETWORK DEVICE *********************************/ -/* If we are in a mode where we need to craft IP packets, then we need to - * obtain a network interface name and a source IP address. There are three - * different possibilities: - * 1. User did NOT specify both network interface and source IP address. - * 2. User did specify a network interface but not a source IP address. - * 3. User did actually supply a source IP but not a network interface name - * - * I know the following code is ugly but the thing is that we want to determine - * interface and source IP without user intervention, so we try in many ways - * until either we succeed or we run out of possibilities and fatal(). - */ -if( this->getMode()!=TCP_CONNECT && this->getMode()!=UDP_UNPRIV && this->getRole()!=ROLE_SERVER){ - - char devbuff[32]; - char *dev; - struct sockaddr_storage ss, ifaddr; - struct sockaddr_in *s4=(struct sockaddr_in *)&ifaddr; - struct sockaddr_in6 *s6=(struct sockaddr_in6 *)&ifaddr; - size_t ss_len; - char hostname[128]; - memset(&ss, 0, sizeof(struct sockaddr_storage)); - memset(&ifaddr, 0, sizeof(struct sockaddr_storage)); - - - /* CASE 1: User did not specify a device so we have to select one. */ - if( !this->issetDevice() ){ - if( this->ipv4() ){ - /* Ugly hack. Get the first resolvable target and determine net interface. Let's - * hope user did not specify something that mixes localhost with - * other targets, like "nping localhost google.com playboy.com" */ - for(int z=0; ztargets.getTargetSpecCount(); z++){ - if( this->targets.getNextTargetAddressAndName(&ss, &ss_len, hostname, sizeof(hostname)) == OP_SUCCESS ) - break; - else if( z>=(this->targets.getTargetSpecCount()-1) ) - nping_fatal(QT_3,"Cannot find a valid target. Please make sure the specified hosts are either IP addresses in standard notation or hostnames that can be resolved with DNS"); - } - this->targets.rewind(); - - /* Try to obtain a device name from the target IP */ - if ( getNetworkInterfaceName( &ss , devbuff) != OP_SUCCESS ) { - /* If that didn't work, ask libpcap */ - if ( (dev = this->select_network_iface()) == NULL) - nping_fatal(QT_3, "Cannot obtain device for packet capture"); - else { - this->setDevice( dev ); - free(dev); - } - /* Libpcap gave us a device name, try to obtain it's IP */ - if ( devname2ipaddr(this->getDevice(), this->af(), &ifaddr) != 0 ){ - if( this->isRoot() ) - nping_fatal(QT_3,"Cannot figure out what source address to use for device %s, does it even exist?", this->getDevice()); - else - nping_fatal(QT_3,"Cannot figure out what source address to use for device %s, are you root?", this->getDevice()); - } - else{ - if( s4->sin_family==AF_INET ) - this->setIPv4SourceAddress(s4->sin_addr); - else if ( s6->sin6_family==AF_INET6 ) - this->setIPv6SourceAddress(s6->sin6_addr.s6_addr); - } - }else{ - this->setDevice(devbuff); - } - }else{ /* In IPv6 we just select one in libpcap and hope is the right one */ - char *selected_iface=this->select_network_iface(); - if(selected_iface==NULL) - nping_fatal(QT_3, "Error trying to find a suitable network interface "); - else { - this->setDevice( selected_iface ); - free(selected_iface); - } - } - } /* CASE 2: User did actually supply a device name */ - else{ - nping_print(DBG_2, "Using network interface \"%s\"", this->getDevice() ); - } - /* The echo server needs to find out a network interface*/ -}else if (this->getRole()==ROLE_SERVER && this->issetDevice()==false){ +if (this->getRole()==ROLE_SERVER && this->issetDevice()==false){ char *selected_iface=this->select_network_iface(); if(selected_iface==NULL) nping_fatal(QT_3, "Error trying to find a suitable network interface "); diff --git a/nping/NpingOps.h b/nping/NpingOps.h index c9e57f5ab..91a850f23 100644 --- a/nping/NpingOps.h +++ b/nping/NpingOps.h @@ -344,7 +344,7 @@ class NpingOps { bool sendEth(); int setDevice(char *n); - char *getDevice(); + const char *getDevice(); bool issetDevice(); int setSpoofSource(); diff --git a/nping/NpingTargets.cc b/nping/NpingTargets.cc index 3cd83d24e..ac4b4af50 100644 --- a/nping/NpingTargets.cc +++ b/nping/NpingTargets.cc @@ -67,16 +67,33 @@ #include "NpingTargets.h" #include "common_modified.h" #include +#include extern NpingOps o; +bool NpingDevice::strEqual(const char *name) const +{ + return 0 == std::strcmp(devname, name); +} + NpingTargets::NpingTargets() : ready(false), current_target(0) { + if (o.issetDevice()) { + devices.push_back(new NpingDevice(o.getDevice())); + } } /* End of NpingTargets constructor */ NpingTargets::~NpingTargets(){ + while (!netblocks.empty()) { + delete netblocks.back(); + netblocks.pop_back(); + } + while (!devices.empty()) { + delete devices.back(); + devices.pop_back(); + } } /* End of NpingTargets destructor */ @@ -91,8 +108,20 @@ int NpingTargets::addSpec(char *spec){ return OP_FAILURE; netblocks.push_back(nb); return OP_SUCCESS; -} /* End of NpingTargets */ +} /* End of NpingTargets::addSpec */ +void NpingTargets::addDevice(const char *dev) +{ + if(dev == NULL || *dev == '\0') + return; + for (std::vector::iterator it=devices.begin(); + it != devices.end(); ++it) { + NpingDevice *d = *it; + if (d->strEqual(dev)) + return; + } + devices.push_back(new NpingDevice(dev)); +} /** Returns next target */ int NpingTargets::getNextTargetAddressAndName(struct sockaddr_storage *t, size_t *tlen, char *hname, size_t hlen){ @@ -309,6 +338,7 @@ int NpingTargets::processSpecs(){ /* Insert current target into targets array */ this->Targets.push_back(mytarget); + this->addDevice(mytarget->getDeviceName()); } /* getNextTarget() checks this to ensure user has previously called processSpecs() */ diff --git a/nping/NpingTargets.h b/nping/NpingTargets.h index 178c95317..02165b862 100644 --- a/nping/NpingTargets.h +++ b/nping/NpingTargets.h @@ -72,6 +72,17 @@ #define MAX_NPING_HOSTNAME_LEN 512 /**< Max length for named hosts */ +class NpingDevice { +private: + // Note: this class doesn't own the storage for this name; + // it has to continue to exist elsewhere. + const char *devname; +public: + NpingDevice(const char *d) : devname(d) {} + bool strEqual(const char *name) const; + const char *getName() const { return devname; } +}; + class NpingTargets { private: @@ -87,6 +98,7 @@ class NpingTargets { NpingTargets(); ~NpingTargets(); int addSpec(char *spec); + void addDevice(const char *dev); int getNextTargetSockAddr(struct sockaddr_storage *t, size_t *tlen); NpingTarget *getNextTarget(); int rewind(); @@ -102,6 +114,7 @@ class NpingTargets { /* TODO: Make private */ NpingTarget *currenths; std::vector Targets; + std::vector devices; }; /* End of class NpingTargets */ diff --git a/nping/ProbeMode.cc b/nping/ProbeMode.cc index 9bf2a8be5..587c00965 100644 --- a/nping/ProbeMode.cc +++ b/nping/ProbeMode.cc @@ -98,7 +98,7 @@ int ProbeMode::init_nsock(){ if ((nsp = nsock_pool_new(NULL)) == NULL) nping_fatal(QT_3, "Failed to create new pool. QUITTING.\n"); const char *device = o.getDevice(); - if (*device) + if (device && *device) nsock_pool_set_device(nsp, device); /* Allow broadcast addresses */ @@ -304,7 +304,7 @@ int ProbeMode::start(){ if( o.getMode()!=ARP && o.sendEth()==false ){ /* Get socket descriptor. No need for it in ARP since we send at eth level */ - if ((rawipsd = netutil_raw_socket(o.issetDevice() ? o.getDevice() : NULL)) < 0 ) + if ((rawipsd = netutil_raw_socket(o.getDevice())) < 0 ) nping_fatal(QT_3,"Couldn't acquire raw socket. Are you root?"); } @@ -314,30 +314,33 @@ int ProbeMode::start(){ /* Set up libpcap */ if(!o.disablePacketCapture()){ + const char *device = o.getDevice(); + if (!device) + nping_fatal(QT_3, "Unable to determine device name. QUITTING.\n"); /* Create new IOD for pcap */ if ((pcap_nsi = nsock_iod_new(nsp, NULL)) == NULL) nping_fatal(QT_3, "Failed to create new nsock_iod. QUITTING.\n"); /* Open pcap */ filterstring=getBPFFilterString(); - nping_print(DBG_2,"Opening pcap device %s", o.getDevice() ); + nping_print(DBG_2,"Opening pcap device %s", device); #ifdef WIN32 /* Nping normally uses device names obtained through dnet for interfaces, * but Pcap has its own naming system. So the conversion is done here */ - if (!DnetName2PcapName(o.getDevice(), pcapdev, sizeof(pcapdev))) { + if (!DnetName2PcapName(device, pcapdev, sizeof(pcapdev))) { /* Oh crap -- couldn't find the corresponding dev apparently. * Let's just go with what we have then ... */ - Strncpy(pcapdev, o.getDevice(), sizeof(pcapdev)); + Strncpy(pcapdev, device, sizeof(pcapdev)); } #else - Strncpy(pcapdev, o.getDevice(), sizeof(pcapdev)); + Strncpy(pcapdev, device, sizeof(pcapdev)); #endif rc = nsock_pcap_open(nsp, pcap_nsi, pcapdev, 8192, (o.spoofSource()) ? 1 : 0, filterstring); if (rc) - nping_fatal(QT_3, "Error opening capture device %s\n", o.getDevice()); - nping_print(DBG_2,"Pcap device %s open successfully", o.getDevice()); + nping_fatal(QT_3, "Error opening capture device %s\n", device); + nping_print(DBG_2,"Pcap device %s open successfully", device); } /* Ready? Go! */