Properly determine device name from target if possible

This commit is contained in:
dmiller 2026-06-15 15:14:10 +00:00
parent 65ed79b280
commit 75d16aab1b
6 changed files with 72 additions and 95 deletions

View file

@ -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 */

View file

@ -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; z<this->targets.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 ");

View file

@ -344,7 +344,7 @@ class NpingOps {
bool sendEth();
int setDevice(char *n);
char *getDevice();
const char *getDevice();
bool issetDevice();
int setSpoofSource();

View file

@ -67,16 +67,33 @@
#include "NpingTargets.h"
#include "common_modified.h"
#include <algorithm>
#include <cstring>
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<NpingDevice *>::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() */

View file

@ -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<NpingTarget *> Targets;
std::vector<NpingDevice *> devices;
}; /* End of class NpingTargets */

View file

@ -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! */