Consolidate getNextHopMAC to libnetutil

This commit is contained in:
dmiller 2026-06-13 06:09:21 +00:00
parent 8d7038e51e
commit 738455f46c
6 changed files with 125 additions and 176 deletions

View file

@ -518,6 +518,45 @@ int ip_is_reserved(const struct sockaddr_storage *addr)
return addrset_contains(reserved, (struct sockaddr *)addr);
}
bool getNextHopMAC(const char *iface, const u8 *srcmac, const struct sockaddr_storage *srcss,
const struct sockaddr_storage *dstss, u8 *dstmac) {
arp_t *a;
struct arp_entry ae;
/* First, let us check the Nmap arp cache ... */
if (mac_cache_get(dstss, dstmac))
return true;
/* Maybe the system ARP cache will be more helpful */
a = arp_open();
if (a) {
addr_ston((sockaddr *) dstss, &ae.arp_pa);
if (arp_get(a, &ae) == 0) {
mac_cache_set(dstss, ae.arp_ha.addr_eth.data);
memcpy(dstmac, ae.arp_ha.addr_eth.data, 6);
arp_close(a);
return true;
}
arp_close(a);
}
/* OK, the last choice is to send our own damn ARP request (and
retransmissions if necessary) to determine the MAC */
if (dstss->ss_family == AF_INET) {
if (doArp(iface, srcmac, srcss, dstss, dstmac, NULL)) {
mac_cache_set(dstss, dstmac);
return true;
}
} else if (dstss->ss_family == AF_INET6) {
if (doND(iface, srcmac, srcss, dstss, dstmac, NULL)) {
mac_cache_set(dstss, dstmac);
return true;
}
}
return false;
}
/* A trivial functon that maintains a cache of IP to MAC Address
entries. If the command is MACCACHE_GET, this func looks for the
IPv4 address in ss and fills in the 'mac' parameter and returns

View file

@ -173,7 +173,8 @@ struct addrinfo *resolve_all(const char *hostname, int pf);
*/
int ip_is_reserved(const struct sockaddr_storage *addr);
bool getNextHopMAC(const char *iface, const u8 *srcmac, const struct sockaddr_storage *srcss,
const struct sockaddr_storage *dstss, u8 *dstmac);
/* A couple of trivial functions that maintain a cache of IP to MAC
* Address entries. Function mac_cache_get() looks for the IPv4 address

View file

@ -71,7 +71,6 @@
#endif
#include "NpingTarget.h"
#include <dnet.h>
#include "nbase.h"
#include "nping.h"
#include "output.h"
@ -735,9 +734,7 @@ u16 NpingTarget::getICMPIdentifier(){
bool NpingTarget::determineNextHopMACAddress() {
struct sockaddr_storage targetss, srcss;
size_t sslen;
arp_t *a;
u8 mac[6];
struct arp_entry ae;
if (this->getDeviceType() != devt_ethernet)
return false; /* Duh. */
@ -760,57 +757,12 @@ bool NpingTarget::determineNextHopMACAddress() {
fatal("%s: Failed to determine nextHop to target", __func__);
}
/* First, let us check the ARP cache ... */
if (mac_cache_get(&targetss, mac)) {
this->setNextHopMACAddress(mac);
return true;
}
/* Maybe the system ARP cache will be more helpful */
nping_print(DBG_3," > Checking system's ARP cache...");
a = arp_open();
if (a) {
addr_ston((sockaddr *)&targetss, &ae.arp_pa);
if (arp_get(a, &ae) == 0) {
mac_cache_set(&targetss, ae.arp_ha.addr_eth.data);
this->setNextHopMACAddress(ae.arp_ha.addr_eth.data);
arp_close(a);
nping_print(DBG_3," > Success: Entry found [%s]", this->getNextHopMACStr() );
return true;
}
arp_close(a);
nping_print(DBG_3," > No relevant entries found in system's ARP cache.");
}
else {
nping_print(DBG_3," > Failed to open system's ARP cache.");
}
/* OK, the last choice is to send our own damn ARP request (and
retransmissions if necessary) to determine the MAC */
/* We first try sending the ARP with our spoofed IP address on it */
if( this->spoofingSourceAddress() ){
nping_print(DBG_3," > Sending ARP request using spoofed IP %s...", this->getSpoofedSourceIPStr() );
this->getSpoofedSourceSockAddr(&srcss, NULL);
if (doArp(this->getDeviceName(), this->getSrcMACAddress(), &srcss, &targetss, mac, NULL)) {
mac_cache_set(&targetss, mac);
this->setNextHopMACAddress(mac);
nping_print(DBG_4," > Success: 1 ARP response received [%s]", this->getNextHopMACStr() );
return true;
}
}
nping_print(DBG_3," > No ARP responses received." );
/* If our spoofed IP address didn't work, try our real IP */
nping_print(DBG_4," > Sending ARP request using our real IP %s...", this->getSourceIPStr() );
this->getSourceSockAddr(&srcss, NULL);
if (doArp(this->getDeviceName(), this->getSrcMACAddress(), &srcss, &targetss, mac, NULL)) {
mac_cache_set(&targetss, mac);
if (getNextHopMAC(this->getDeviceName(), this->getSrcMACAddress(),
&srcss, &targetss, mac)) {
this->setNextHopMACAddress(mac);
nping_print(DBG_3," > Success: 1 ARP response received [%s]", this->getNextHopMACStr() );
return true;
}
nping_print(DBG_3," > No ARP responses received" );
/* I'm afraid that we couldn't find it! Maybe it doesn't exist?*/
return false;

View file

@ -226,89 +226,90 @@ int NpingTargets::processSpecs(){
/* Get next host IP address and, if it is a named host, its hostname */
while ( this->getNextTargetAddressAndName(&ss, &slen, buff, MAX_NPING_HOSTNAME_LEN) == OP_SUCCESS ){
NpingTarget *mytarget = new NpingTarget();
mytarget->setTargetSockAddr(&ss, slen);
if( buff[0]=='\0')
mytarget->setNamedHost(false);
else{
mytarget->setSuppliedHostName(buff);
mytarget->setNamedHost(true);
}
/* For the moment, we only run this code if we are not dealing with IPv6 */
if( !o.ipv6() ){
/* Get all the information needed to send packets to this target.
* (Only in case we are not in unprivileged modes) */
if(o.getMode()!=TCP_CONNECT && o.getMode()!=UDP_UNPRIV){
result=route_dst( &ss, &rnfo, o.getDevice(), NULL );
if(result==false){
nping_warning(QT_2, "Failed to determine route to host %s. Skipping it...", mytarget->getTargetIPstr() );
delete mytarget;
continue;
}
#ifdef WIN32
if (!o.havePcap() && rnfo.ii.device_type == devt_loopback){
nping_warning(QT_2, "Skipping %s because Windows does not allow localhost scans (try --unprivileged).", mytarget->getTargetIPstr() );
delete mytarget;
continue;
}
#endif
/* Determine next hop */
if( rnfo.direct_connect ){
mytarget->setDirectlyConnected(true);
mytarget->setNextHop(&ss, slen);
}
else{
mytarget->setDirectlyConnected(false);
mytarget->setNextHop(&rnfo.nexthop, sizeof(struct sockaddr_storage));
}
/* Source IP address that we should use when targeting this host */
mytarget->setSourceSockAddr(&rnfo.srcaddr, sizeof(struct sockaddr_storage));
/* If user requested to spoof IP source address, set it */
if( o.spoofSource() ){
mytarget->setSpoofedSourceSockAddr( o.getSourceSockAddr(), sizeof(struct sockaddr_storage));
}
/* Network interface */
mytarget->setDeviceNames( rnfo.ii.devname, rnfo.ii.devfullname );
mytarget->setDeviceType( rnfo.ii.device_type );
/* Set source MAC address */
mytarget->setSrcMACAddress( rnfo.ii.mac );
if( rnfo.ii.device_up == false )
nping_warning(QT_2, "Device used for target host %s seems to be down.", mytarget->getTargetIPstr());
/* Determine next hop MAC address and target MAC address */
if( o.sendEth() ){
#ifdef WIN32
if (o.havePcap() && rnfo.ii.device_type == devt_loopback) {
mytarget->setNextHopMACAddress(mytarget->getSrcMACAddress());
}
else {
#endif
mytarget->determineNextHopMACAddress();
mytarget->determineTargetMACAddress(); /* Sets Target MAC only if is directly connected to us */
#ifdef WIN32
}
#endif
}
/* If we are in debug mode print target details */
if(o.getDebugging() >= DBG_3)
mytarget->printTargetDetails();
}
}else{
struct sockaddr_storage ss;
struct sockaddr_in6 *s6=(struct sockaddr_in6 *)&ss;
memset(&ss, 0, sizeof(sockaddr_storage));
s6->sin6_family=AF_INET6;
mytarget->setSourceSockAddr(&ss, sizeof(struct sockaddr_storage));
NpingTarget *mytarget = new NpingTarget();
mytarget->setTargetSockAddr(&ss, slen);
if( buff[0]=='\0')
mytarget->setNamedHost(false);
else{
mytarget->setSuppliedHostName(buff);
mytarget->setNamedHost(true);
}
/* Insert current target into targets array */
this->Targets.push_back(mytarget);
if (o.spoofSource()) {
mytarget->setSourceSockAddr(o.getSourceSockAddr(), sizeof(sockaddr_storage));
}
/* Get all the information needed to send packets to this target.
* (Only in case we are not in unprivileged modes) */
if(o.getMode()!=TCP_CONNECT && o.getMode()!=UDP_UNPRIV){
result=route_dst( &ss, &rnfo, o.getDevice(),
o.spoofSource() ? o.getSourceSockAddr() : NULL );
if(result==false){
nping_warning(QT_2, "Failed to determine route to host %s. Skipping it...", mytarget->getTargetIPstr() );
delete mytarget;
continue;
}
#ifdef WIN32
if (!o.havePcap() && rnfo.ii.device_type == devt_loopback){
nping_warning(QT_2, "Skipping %s because Windows does not allow localhost scans (try --unprivileged).", mytarget->getTargetIPstr() );
delete mytarget;
continue;
}
#endif
printf("%s %s", rnfo.ii.devname, rnfo.ii.devfullname);
printf(" srcaddr %s", inet_ntop_ez(&rnfo.srcaddr, sizeof(rnfo.srcaddr)));
if (rnfo.direct_connect)
printf(" direct");
else
printf(" nexthop %s\n", inet_ntop_ez(&rnfo.nexthop, sizeof(rnfo.nexthop)));
/* Determine next hop */
if( rnfo.direct_connect ){
mytarget->setDirectlyConnected(true);
mytarget->setNextHop(&ss, slen);
}
else{
mytarget->setDirectlyConnected(false);
mytarget->setNextHop(&rnfo.nexthop, sizeof(struct sockaddr_storage));
}
/* Source IP address that we should use when targeting this host */
mytarget->setSourceSockAddr(&rnfo.srcaddr, sizeof(struct sockaddr_storage));
/* If user requested to spoof IP source address, set it */
if( o.spoofSource() ){
mytarget->setSpoofedSourceSockAddr( o.getSourceSockAddr(), sizeof(struct sockaddr_storage));
}
/* Network interface */
mytarget->setDeviceNames( rnfo.ii.devname, rnfo.ii.devfullname );
mytarget->setDeviceType( rnfo.ii.device_type );
/* Set source MAC address */
mytarget->setSrcMACAddress( rnfo.ii.mac );
if( rnfo.ii.device_up == false )
nping_warning(QT_2, "Device used for target host %s seems to be down.", mytarget->getTargetIPstr());
/* Determine next hop MAC address and target MAC address */
if( o.sendEth() ){
#ifdef WIN32
if (o.havePcap() && rnfo.ii.device_type == devt_loopback) {
mytarget->setNextHopMACAddress(mytarget->getSrcMACAddress());
}
else {
#endif
mytarget->determineNextHopMACAddress();
mytarget->determineTargetMACAddress(); /* Sets Target MAC only if is directly connected to us */
#ifdef WIN32
}
#endif
}
/* If we are in debug mode print target details */
if(o.getDebugging() >= DBG_3)
mytarget->printTargetDetails();
}
/* Insert current target into targets array */
this->Targets.push_back(mytarget);
}
/* getNextTarget() checks this to ensure user has previously called processSpecs() */

View file

@ -1561,47 +1561,6 @@ bool setTargetNextHopMAC(Target *target) {
return false;
}
/* Like to getTargetNextHopMAC(), but for arbitrary hosts (not Targets) */
bool getNextHopMAC(const char *iface, const u8 *srcmac, const struct sockaddr_storage *srcss,
const struct sockaddr_storage *dstss, u8 *dstmac) {
arp_t *a;
struct arp_entry ae;
/* First, let us check the Nmap arp cache ... */
if (mac_cache_get(dstss, dstmac))
return true;
/* Maybe the system ARP cache will be more helpful */
a = arp_open();
if (a) {
addr_ston((sockaddr *) dstss, &ae.arp_pa);
if (arp_get(a, &ae) == 0) {
mac_cache_set(dstss, ae.arp_ha.addr_eth.data);
memcpy(dstmac, ae.arp_ha.addr_eth.data, 6);
arp_close(a);
return true;
}
arp_close(a);
}
/* OK, the last choice is to send our own damn ARP request (and
retransmissions if necessary) to determine the MAC */
if (dstss->ss_family == AF_INET) {
if (doArp(iface, srcmac, srcss, dstss, dstmac, PacketTrace::traceArp)) {
mac_cache_set(dstss, dstmac);
return true;
}
} else if (dstss->ss_family == AF_INET6) {
if (doND(iface, srcmac, srcss, dstss, dstmac, PacketTrace::traceND)) {
mac_cache_set(dstss, dstmac);
return true;
}
}
return false;
}
int nmap_route_dst(const struct sockaddr_storage *dst, struct route_nfo *rnfo) {
struct sockaddr_storage spoofss;
size_t spoofsslen;

View file

@ -339,9 +339,6 @@ int setTargetMACIfAvailable(Target *target, struct link_header *linkhdr,
after an ARP scan if many directly connected machines are involved. */
bool setTargetNextHopMAC(Target *target);
bool getNextHopMAC(const char *iface, const u8 *srcmac, const struct sockaddr_storage *srcss,
const struct sockaddr_storage *dstss, u8 *dstmac);
/* If rcvdtime is non-null and a packet is returned, rcvd will be
filled with the time that packet was captured from the wire by
pcap. If linknfo is not NULL, lnkinfo->headerlen and