From 738455f46c2b4c85a9fcf0b698d80d4c5d891bf1 Mon Sep 17 00:00:00 2001 From: dmiller Date: Sat, 13 Jun 2026 06:09:21 +0000 Subject: [PATCH] Consolidate getNextHopMAC to libnetutil --- libnetutil/netutil.cc | 39 ++++++++++ libnetutil/netutil.h | 3 +- nping/NpingTarget.cc | 52 +------------- nping/NpingTargets.cc | 163 +++++++++++++++++++++--------------------- tcpip.cc | 41 ----------- tcpip.h | 3 - 6 files changed, 125 insertions(+), 176 deletions(-) diff --git a/libnetutil/netutil.cc b/libnetutil/netutil.cc index 6becdbacd..7b609989a 100644 --- a/libnetutil/netutil.cc +++ b/libnetutil/netutil.cc @@ -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 diff --git a/libnetutil/netutil.h b/libnetutil/netutil.h index 7a4df69f2..b4f5c9497 100644 --- a/libnetutil/netutil.h +++ b/libnetutil/netutil.h @@ -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 diff --git a/nping/NpingTarget.cc b/nping/NpingTarget.cc index 34abef648..539f868c2 100644 --- a/nping/NpingTarget.cc +++ b/nping/NpingTarget.cc @@ -71,7 +71,6 @@ #endif #include "NpingTarget.h" -#include #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; diff --git a/nping/NpingTargets.cc b/nping/NpingTargets.cc index a2e8844a9..8df779d0d 100644 --- a/nping/NpingTargets.cc +++ b/nping/NpingTargets.cc @@ -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() */ diff --git a/tcpip.cc b/tcpip.cc index 1b3626734..1fcdb1a3b 100644 --- a/tcpip.cc +++ b/tcpip.cc @@ -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; diff --git a/tcpip.h b/tcpip.h index 28b654688..e22cbd390 100644 --- a/tcpip.h +++ b/tcpip.h @@ -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