/
githubmirror
/
nmap
Обзор
Документация
Войти
/
githubmirror
/
nmap
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
nping/NpingTargets.cc
414 строк
15 KB
dmiller
Properly determine device name from target if possible
15 июн 2026, 18:14
15 июн 2026, 18:14
75d16aa
Код
Авторство
О чём код?
/*************************************************************************** * NpingTargets.cc -- Class that handles target spec parsing and allows to * * obtain the different targets that need to be ping-ed. * * * ***********************IMPORTANT NMAP LICENSE TERMS************************ * * The Nmap Security Scanner is (C) 1996-2026 Nmap Software LLC ("The Nmap * Project"). Nmap is also a registered trademark of the Nmap Project. * * This program is distributed under the terms of the Nmap Public Source * License (NPSL). The exact license text applying to a particular Nmap * release or source code control revision is contained in the LICENSE * file distributed with that version of Nmap or source code control * revision. More Nmap copyright/legal information is available from * https://nmap.org/book/man-legal.html, and further information on the * NPSL license itself can be found at https://nmap.org/npsl/ . This * header summarizes some key points from the Nmap license, but is no * substitute for the actual license text. * * Nmap is generally free for end users to download and use themselves, * including commercial use. It is available from https://nmap.org. * * The Nmap license generally prohibits companies from using and * redistributing Nmap in commercial products, but we sell a special Nmap * OEM Edition with a more permissive license and special features for * this purpose. See https://nmap.org/oem/ * * If you have received a written Nmap license agreement or contract * stating terms other than these (such as an Nmap OEM license), you may * choose to use and redistribute Nmap under those terms instead. * * The official Nmap Windows builds include the Npcap software * (https://npcap.com) for packet capture and transmission. It is under * separate license terms which forbid redistribution without special * permission. So the official Nmap Windows builds may not be redistributed * without special permission (such as an Nmap OEM license). * * Source is provided to this software because we believe users have a * right to know exactly what a program is going to do before they run it. * This also allows you to audit the software for security holes. * * Source code also allows you to port Nmap to new platforms, fix bugs, and * add new features. You are highly encouraged to submit your changes as a * Github PR or by email to the dev@nmap.org mailing list for possible * incorporation into the main distribution. Unless you specify otherwise, it * is understood that you are offering us very broad rights to use your * submissions as described in the Nmap Public Source License Contributor * Agreement. This is important because we fund the project by selling licenses * with various terms, and also because the inability to relicense code has * caused devastating problems for other Free Software projects (such as KDE * and NASM). * * The free version of Nmap is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties, * indemnification and commercial support are all available through the * Npcap OEM program--see https://nmap.org/oem/ * ***************************************************************************/ #include "nping.h" #include "NpingOps.h" #include "output.h" #include "nbase.h" #include "utils.h" #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 */ /** Adds a target specification to an internal array of specs */ int NpingTargets::addSpec(char *spec){ if(spec==NULL) return OP_FAILURE; int family= (o.getIPVersion()==IP_VERSION_6) ? AF_INET6 : AF_INET; NetBlock *nb = NetBlock::parse_expr(spec, family, requests, false, o.issetDevice() ? o.getDevice() : NULL); if (nb == NULL) return OP_FAILURE; netblocks.push_back(nb); return OP_SUCCESS; } /* 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){ if( t==NULL || tlen==NULL ) nping_fatal(QT_3,"getNextTarget(): NULL values supplied."); NetBlock *nb = NULL; while (!netblocks.empty()) { nb = netblocks.front(); if (nb->next(t, tlen)) { break; } // Ran out of hosts in that block. Remove it. netblocks.pop_front(); delete nb; nb = NULL; } if (nb == NULL) { // Ran out of netblocks return OP_FAILURE; } /* If current spec is a named host (not a range), store name in supplied buff */ /* If current spec is not a named host, c_str() is "\0" */ if( hname!=NULL && hlen>0 ) strncpy(hname, nb->hostname.c_str(), hlen); return OP_SUCCESS; } /* End of getNextTarget() */ int NpingTargets::getNextIPv4Address(u32 *addr){ struct sockaddr_storage t; size_t tlen; char buff[257]; memset(buff, 0, 257); if( addr == NULL ) nping_fatal(QT_3, "getNextIPv4Address(): NULL value supplied. "); if ( this->getNextTargetAddressAndName(&t, &tlen, buff, 256) != OP_SUCCESS ) return OP_FAILURE; struct sockaddr_in *p=( struct sockaddr_in *)&t; if(p->sin_family!=AF_INET) nping_fatal(QT_3, "getNextIPv4Address(): Trying to obtain an IPv4 address from an IPv6 target."); *addr = p->sin_addr.s_addr; return OP_SUCCESS; } /* End of getNextIPv4Address() */ unsigned long int NpingTargets::getTargetsFetched(){ return this->Targets.size(); } /* getTargetsFetched() */ int NpingTargets::getTargetSpecCount(){ return this->netblocks.size(); } /* End of getTargetSpecCount() */ static void nping_mass_dns(DNS::Request requests[], int num_requests) { static DNS::Resolver resolver; static bool initialized = false; if (!initialized) { int family= (o.getIPVersion()==IP_VERSION_6) ? AF_INET6 : AF_INET; resolver.setAF(family); // TODO: resolver.setStatusCallback(); // TODO: resolver.setLogFunc(); if (o.issetDevice() || o.spoofSource()) { resolver.setSource(o.getDevice(), o.getSourceSockAddr(), sizeof(sockaddr_storage), o.spoofSource()); } if (o.issetIPOptions()) { // TODO: NpingOps.ip_options should have a length, not be null-terminated. const char *ipopts = o.getIPOptions(); resolver.setIpOptions((const u8 *)ipopts, strlen(ipopts)); } // TODO: NpingOps may need to support --dns-servers and --system-dns } const char *errstr = NULL; bool use_systemdns = false; resolver.Init(requests, num_requests); if (!resolver.isMassDnsOK(&errstr)) { error("%s. Falling back to System DNS resolver.", errstr); use_systemdns = true; } resolver.Resolve(use_systemdns); } /** This method should be called when all the target specs have been entered * using addSpec(). What it does is to create a NpingTarget objects for * each IP address extracted from the specs. Objects are stored in an internal * vector. */ int NpingTargets::processSpecs(){ char buff[MAX_NPING_HOSTNAME_LEN+1]; struct sockaddr_storage ss; size_t slen=0; bool result=false; struct route_nfo rnfo; memset(&ss, 0, sizeof(struct sockaddr_storage)); memset(buff, 0, MAX_NPING_HOSTNAME_LEN+1); if (requests.size() > 0) { nping_mass_dns(requests.data(), requests.size()); std::list<NetBlock *>::iterator nb_it = netblocks.begin(); for (std::vector<DNS::Request>::const_iterator rit = requests.begin(); rit != requests.end(); rit++) { const DNS::Request &req = *rit; NetBlock *nb_old = (NetBlock *) req.userdata; assert(nb_old != NULL); NetBlock *nb_new = nb_old->resolve(req); nb_it = std::find(nb_it, netblocks.end(), nb_old); assert(nb_it != netblocks.end()); if (nb_new == NULL) { // Resolution failed; remove the NetBlock nb_it = netblocks.erase(nb_it); } else { assert (nb_new != nb_old); // Resolution succeeded; replace the NetBlock *nb_it = nb_new; } delete nb_old; } requests.clear(); } /* 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); } 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); this->addDevice(mytarget->getDeviceName()); } /* getNextTarget() checks this to ensure user has previously called processSpecs() */ this->ready=true; o.targets.rewind(); return OP_SUCCESS; } /* End of processSpecs() */ NpingTarget *NpingTargets::getNextTarget(){ /* When !ready it means that processSpecs() has not been called yet. This * happens when user hits CTRL-C early. */ if( this->ready == false ) return NULL; /* Did we reach the end of the vector in the last call? */ if( this->current_target >= this->Targets.size() ) return NULL; nping_print(DBG_4, "Next target returned by getNextTarget(): Targets[%lu/%lu] --> %s \n", this->current_target, (unsigned long) this->Targets.size(), this->Targets.at(this->current_target)->getTargetIPstr() ); return this->Targets.at( this->current_target++ ); } /* End of getNextTarget() */ int NpingTargets::rewind(){ current_target=0; return OP_SUCCESS; } /* End of rewind() */ /* Frees all of the Targets. Returns the number of freed targets. The number * return should match value returned by getTargetsFetched(). */ unsigned long int NpingTargets::freeTargets(){ unsigned long int cnt=0; while(!this->Targets.empty()) { this->currenths = Targets.back(); delete currenths; Targets.pop_back(); cnt++; } return cnt; } /* End of freeTargets() */ NpingTarget *NpingTargets::findTarget(const struct sockaddr_storage *tt){ size_t i=0; struct sockaddr_storage ss; size_t ss_len; struct sockaddr_in *s_ip4=(struct sockaddr_in *)&ss; struct sockaddr_in6 *s_ip6=(struct sockaddr_in6 *)&ss; const struct sockaddr_in *t_ip4=(const struct sockaddr_in *)tt; const struct sockaddr_in6 *t_ip6=(const struct sockaddr_in6 *)tt; if (tt==NULL) return NULL; for(i=0; i<this->Targets.size(); i++){ this->Targets[i]->getTargetSockAddr(&ss, &ss_len); /* Are we are dealing with IPv4 addresses? */ if( s_ip4->sin_family==AF_INET && t_ip4->sin_family==AF_INET){ if( !memcmp(&(s_ip4->sin_addr), &(t_ip4->sin_addr), sizeof(struct in_addr)) ) return this->Targets[i]; } /* Are they IPv6 addresses? */ else if( s_ip6->sin6_family==AF_INET6 && t_ip6->sin6_family==AF_INET6 ){ if( !memcmp(&(s_ip6->sin6_addr), &(t_ip6->sin6_addr), sizeof(struct in6_addr)) ) return this->Targets[i]; } /* Unknown type of address, skipping... */ else{ continue; } } return NULL; } /* End of findTarget() */