From e8c7e7ba01b8d56afaf8af2dc7f1c2c1dff73390 Mon Sep 17 00:00:00 2001 From: dmiller Date: Thu, 18 Apr 2024 19:16:23 +0000 Subject: [PATCH] Generalize nmap_mass_rdns to support more than just Targets and PTR requests --- nmap_dns.cc | 243 ++++++++++++++++++++++++++++++-------------------- nmap_dns.h | 11 +++ traceroute.cc | 42 ++++----- 3 files changed, 170 insertions(+), 126 deletions(-) diff --git a/nmap_dns.cc b/nmap_dns.cc index 2b9addbf9..089345ff6 100644 --- a/nmap_dns.cc +++ b/nmap_dns.cc @@ -219,7 +219,7 @@ struct dns_server { }; struct request { - Target *targ; + DNS::Request *targ; struct timeval timeout; int tries; int servers_tried; @@ -447,7 +447,7 @@ static void do_possible_writes() { if (tpreq) { if (o.debugging >= TRACE_DEBUG_LEVEL) - log_write(LOG_STDOUT, "mass_rdns: TRANSMITTING for <%s> (server <%s>)\n", tpreq->targ->targetipstr() , servI->hostname.c_str()); + log_write(LOG_STDOUT, "mass_rdns: TRANSMITTING for <%s> (server <%s>)\n", tpreq->targ->repr(), servI->hostname.c_str()); stat_trans++; put_dns_packet_on_wire(tpreq); } @@ -483,8 +483,19 @@ static void put_dns_packet_on_wire(request *req) { req->id = DNS::Factory::progressiveId; req->curr_server->write_busy = 1; req->curr_server->reqs_on_wire++; + DNS::Request &reqt = *req->targ; - plen = DNS::Factory::buildReverseRequest(*req->targ->TargetSockAddr(), packet, maxlen); + switch(reqt.type) { + case DNS::A: + case DNS::AAAA: + plen = DNS::Factory::buildSimpleRequest(reqt.name, reqt.type, packet, maxlen); + break; + case DNS::PTR: + plen = DNS::Factory::buildReverseRequest(reqt.ss, packet, maxlen); + break; + default: + break; + } memcpy(&now, nsock_gettimeofday(), sizeof(struct timeval)); TIMEVAL_MSEC_ADD(timeout, now, read_timeouts[read_timeout_index][req->tries]); @@ -551,7 +562,7 @@ static int deal_with_timedout_reads() { // FIXME: Find a good compromise // **** We've already tried all servers... give up - if (o.debugging >= TRACE_DEBUG_LEVEL) log_write(LOG_STDOUT, "mass_rdns: *DR*OPPING <%s>\n", tpreq->targ->targetipstr()); + if (o.debugging >= TRACE_DEBUG_LEVEL) log_write(LOG_STDOUT, "mass_rdns: *DR*OPPING <%s>\n", tpreq->targ->repr()); output_summary(); stat_dropped++; @@ -579,60 +590,67 @@ static int deal_with_timedout_reads() { } -// After processing a DNS response, we search through the IPs we're -// looking for and update their results as necessary. -// Returns non-zero if this matches a query we're looking for -static int process_result(const sockaddr_storage &ip, const std::string &result, int action, u16 id) -{ - request *tpreq; - std::map::iterator infoI; - dns_server *server; +static void process_request(int action, info &reqinfo) { + request *tpreq = reqinfo.tpreq; + dns_server *server = reqinfo.server; - infoI = records.find(id); - - if( infoI != records.end() ){ - - tpreq = infoI->second.tpreq; - server = infoI->second.server; - - if( !result.empty() && !sockaddr_storage_equal(&ip, tpreq->targ->TargetSockAddr()) ) - return 0; - - if (action == ACTION_SYSTEM_RESOLVE || action == ACTION_FINISHED) - { + switch (action) { + case ACTION_SYSTEM_RESOLVE: + case ACTION_FINISHED: server->capacity += CAPACITY_UP_STEP; check_capacities(&*server); - - if(!result.empty()) - { - tpreq->targ->setHostName(result.c_str()); - host_cache.add(* tpreq->targ->TargetSockAddr(), result); - } - - records.erase(infoI); + records.erase(tpreq->id); server->in_process.remove(tpreq); server->reqs_on_wire--; - total_reqs--; + if (action == ACTION_SYSTEM_RESOLVE) { + deferred_reqs.push_back(tpreq); + } + else { + delete tpreq; + } - if (action == ACTION_SYSTEM_RESOLVE) deferred_reqs.push_back(tpreq); - if (action == ACTION_FINISHED) delete tpreq; - } - else - { + break; + case ACTION_TIMEOUT: memcpy(&tpreq->timeout, nsock_gettimeofday(), sizeof(struct timeval)); deal_with_timedout_reads(); + break; + default: + assert(false); + break; + } +} + +// After processing a DNS response, we search through the IPs we're +// looking for and update their results as necessary. +static int process_result(const sockaddr_storage &ip, const std::string &result, int action, info &reqinfo) +{ + assert(action == ACTION_FINISHED); + request *tpreq = reqinfo.tpreq; + + if (!result.empty()) + { + if (!sockaddr_storage_equal(&ip, &tpreq->targ->ss)) + { + if (o.debugging) + log_write(LOG_STDOUT, "mass_rdns: Mismatched record for ID %d\n", tpreq->id); + return 0; } - do_possible_writes(); - // Close DNS servers if we're all done so that we kill - // all events and return from nsock_loop immediateley - if (total_reqs == 0) - close_dns_servers(); - return 1; + tpreq->targ->name = result; + host_cache.add(tpreq->targ->ss, result); } - return 0; + + process_request(action, reqinfo); + + do_possible_writes(); + + // Close DNS servers if we're all done so that we kill + // all events and return from nsock_loop immediateley + if (total_reqs == 0) + close_dns_servers(); + return 1; } // Nsock read handler. One nsock read for each DNS server exists at each @@ -666,29 +684,30 @@ static void read_evt_handler(nsock_pool nsp, nsock_event evt, void *) { DNS_HAS_ERR(f, DNS::ERR_NOT_IMPLEMENTED) || DNS_HAS_ERR(f, DNS::ERR_REFUSED)) return; + // Check for matching request + std::map::iterator infoI = records.find(p.id); + if (infoI == records.end()) { + return; + } + info &reqinfo = infoI->second; + if (DNS_HAS_ERR(f, DNS::ERR_NAME)) { - sockaddr_storage discard; - if(process_result(discard, "", ACTION_FINISHED, p.id)) - { - if (o.debugging >= TRACE_DEBUG_LEVEL) - log_write(LOG_STDOUT, "mass_rdns: NXDOMAIN \n", p.id); - output_summary(); - stat_nx++; - } + process_request(ACTION_FINISHED, reqinfo); + if (o.debugging >= TRACE_DEBUG_LEVEL) + log_write(LOG_STDOUT, "mass_rdns: NXDOMAIN \n", p.id); + output_summary(); + stat_nx++; return; } if (DNS_HAS_ERR(f, DNS::ERR_SERVFAIL)) { - sockaddr_storage discard; - if (process_result(discard, "", ACTION_TIMEOUT, p.id)) - { - if (o.debugging >= TRACE_DEBUG_LEVEL) - log_write(LOG_STDOUT, "mass_rdns: SERVFAIL \n", p.id); - stat_sf++; - } + process_request(ACTION_TIMEOUT, reqinfo); + if (o.debugging >= TRACE_DEBUG_LEVEL) + log_write(LOG_STDOUT, "mass_rdns: SERVFAIL \n", p.id); + stat_sf++; return; } @@ -717,7 +736,7 @@ static void read_evt_handler(nsock_pool nsp, nsock_event evt, void *) { // Or if we can get an IP from reversing the .arpa PTR address || DNS::Factory::ptrToIp(a.name, ip)) { - if ((processing_successful = process_result(ip, ptr->value, ACTION_FINISHED, p.id))) + if ((processing_successful = process_result(ip, ptr->value, ACTION_FINISHED, reqinfo))) { if (o.debugging >= TRACE_DEBUG_LEVEL) { @@ -757,19 +776,17 @@ static void read_evt_handler(nsock_pool nsp, nsock_event evt, void *) { if (!processing_successful) { if (DNS_HAS_FLAG(f, DNS::TRUNCATED)) { // TODO: TCP fallback, or only use system resolver if user didn't specify --dns-servers - process_result(ip, "", ACTION_SYSTEM_RESOLVE, p.id); + process_request(ACTION_SYSTEM_RESOLVE, reqinfo); } else if (!alias.empty()) { if (o.debugging >= TRACE_DEBUG_LEVEL) { - char ipstr[INET6_ADDRSTRLEN]; - sockaddr_storage_iptop(&ip, ipstr); - log_write(LOG_STDOUT, "mass_rdns: CNAME for <%s> not processed.\n", ipstr); + log_write(LOG_STDOUT, "mass_rdns: CNAME for <%s> not processed.\n", reqinfo.tpreq->targ->repr()); } // TODO: Send a PTR request for alias instead. Meanwhile, we'll just fall // back to using system resolver. Alternative: report the canonical name // (alias), but that's not very useful. - process_result(ip, "", ACTION_SYSTEM_RESOLVE, p.id); + process_request(ACTION_SYSTEM_RESOLVE, reqinfo); } else { if (o.debugging >= TRACE_DEBUG_LEVEL) { @@ -1056,12 +1073,11 @@ static void init_servs(void) { // Actual main loop -static void nmap_mass_rdns_core(Target **targets, int num_targets) { +static void nmap_mass_dns_core(DNS::Request *requests, int num_requests) { std::list::iterator reqI; request *tpreq; int timeout; - const char *tpname; int i; char spmobuf[1024]; @@ -1082,21 +1098,17 @@ static void nmap_mass_rdns_core(Target **targets, int num_targets) { total_reqs = 0; // Set up the request structure - for (int i=0; i < num_targets; i++) + for (int i=0; i < num_requests; i++) { - Target *target = targets[i]; - if (!(target->flags & HOST_UP) && !o.always_resolve) continue; + DNS::Request &reqt = requests[i]; // See if it's cached - std::string res; - if (host_cache.lookup(*target->TargetSockAddr(), res)) { - tpname = res.c_str(); - target->setHostName(tpname); + if (host_cache.lookup(reqt.ss, reqt.name)) { continue; } tpreq = new request; - tpreq->targ = target; + tpreq->targ = &reqt; tpreq->tries = 0; tpreq->servers_tried = 0; @@ -1165,12 +1177,12 @@ static void nmap_mass_rdns_core(Target **targets, int num_targets) { tpreq = *reqI; - if (getnameinfo((const struct sockaddr *)tpreq->targ->TargetSockAddr(), + if (getnameinfo((const struct sockaddr *)&tpreq->targ->ss, sizeof(struct sockaddr_storage), hostname, sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { stat_ok++; stat_cname++; - tpreq->targ->setHostName(hostname); + tpreq->targ->name = hostname; } delete tpreq; @@ -1185,35 +1197,26 @@ static void nmap_mass_rdns_core(Target **targets, int num_targets) { } -static void nmap_system_rdns_core(Target **targets, int num_targets) { +static void nmap_system_dns_core(DNS::Request requests[], int num_requests) { char hostname[FQDN_LEN + 1] = ""; char spmobuf[1024]; - int i; - - for (int i=0; i < num_targets; i++) - { - Target *currenths = targets[i]; - - if (((currenths->flags & HOST_UP) || o.always_resolve) && !o.noresolve) stat_actual++; - } + stat_actual = num_requests; Snprintf(spmobuf, sizeof(spmobuf), "System DNS resolution of %d host%s.", stat_actual, stat_actual-1 ? "s" : ""); SPM = new ScanProgressMeter(spmobuf); - for (int i=0; i < num_targets; i++) + for (int i=0; i < num_requests; i++) { - Target *currenths = targets[i]; + DNS::Request &reqt = requests[i]; if (keyWasPressed()) SPM->printStats((double) i / stat_actual, NULL); - if (((currenths->flags & HOST_UP) || o.always_resolve) && !o.noresolve) { - if (getnameinfo((struct sockaddr *)currenths->TargetSockAddr(), - sizeof(sockaddr_storage), hostname, - sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { - stat_ok++; - currenths->setHostName(hostname); - } + if (getnameinfo((const struct sockaddr *)&reqt.ss, + sizeof(sockaddr_storage), hostname, + sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { + stat_ok++; + reqt.name = hostname; } } @@ -1224,7 +1227,7 @@ static void nmap_system_rdns_core(Target **targets, int num_targets) { // Publicly available function. Basically just a wrapper so we // can record time information, restart statistics, etc. -void nmap_mass_rdns(Target **targets, int num_targets) { +void nmap_mass_dns(DNS::Request requests[], int num_requests) { struct timeval now; @@ -1233,9 +1236,9 @@ void nmap_mass_rdns(Target **targets, int num_targets) { stat_actual = stat_ok = stat_nx = stat_sf = stat_trans = stat_dropped = stat_cname = 0; if (o.mass_dns) - nmap_mass_rdns_core(targets, num_targets); + nmap_mass_dns_core(requests, num_requests); else - nmap_system_rdns_core(targets, num_targets); + nmap_system_dns_core(requests, num_requests); gettimeofday(&now, NULL); @@ -1263,6 +1266,29 @@ void nmap_mass_rdns(Target **targets, int num_targets) { } +void nmap_mass_rdns(Target ** targets, int num_targets) { + /* Second, make an array of pointer to DNS::Request to suit the interface of + nmap_mass_rdns. */ + DNS::Request *requests = new DNS::Request[num_targets]; + for (int i = 0; i < num_targets; i++) { + Target *target = targets[i]; + if (!(target->flags & HOST_UP) && !o.always_resolve) continue; + + DNS::Request &reqt = requests[i]; + size_t sslen = sizeof(struct sockaddr_storage); + target->TargetSockAddr(&reqt.ss, &sslen); + reqt.type = DNS::PTR; + } + nmap_mass_dns(requests, num_targets); + for (int i = 0; i < num_targets; i++) { + std::string &name = requests[i].name; + if (!name.empty()) { + targets[i]->setHostName(name.c_str()); + } + } + delete[] requests; +} + // Returns a list of known DNS servers std::list get_dns_servers() { init_servs(); @@ -1695,3 +1721,22 @@ size_t DNS::Packet::parseFromBuffer(const u8 *buf, size_t maxlen) return ret; } + +const char *DNS::Request::repr() +{ + switch(type) { + case DNS::NONE: + return "Uninitialized request"; + break; + case DNS::A: + case DNS::AAAA: + return name.c_str(); + break; + case DNS::PTR: + return inet_ntop_ez(&ss, sizeof(ss)); + break; + default: + return "Invalid request"; + break; + } +} diff --git a/nmap_dns.h b/nmap_dns.h index 91085aa2d..ddb5f9f19 100644 --- a/nmap_dns.h +++ b/nmap_dns.h @@ -122,6 +122,7 @@ typedef enum { } ERRORS; typedef enum { + NONE = 0, A = 1, CNAME = 5, PTR = 12, @@ -244,8 +245,18 @@ public: std::list answers; }; +struct Request +{ + RECORD_TYPE type; + struct sockaddr_storage ss; + std::string name; + Request() : type(NONE), name() {} + const char *repr(); // string representation +}; } + +void nmap_mass_dns(DNS::Request requests[], int num_requests); void nmap_mass_rdns(Target ** targets, int num_targets); std::list get_dns_servers(); diff --git a/traceroute.cc b/traceroute.cc index 8c7612bac..a1f9af0d1 100644 --- a/traceroute.cc +++ b/traceroute.cc @@ -1333,7 +1333,6 @@ void TracerouteState::resolve_hops() { std::set::iterator addr_iter; std::vector::iterator host_iter; std::map name_map; - Target **targets; Hop *hop; int i, n; @@ -1347,43 +1346,32 @@ void TracerouteState::resolve_hops() { } } n = addrs.size(); - /* Second, make an array of pointer to Target to suit the interface of - nmap_mass_rdns. */ - targets = (Target **) safe_malloc(sizeof(*targets) * n); - i = 0; - addr_iter = addrs.begin(); - while (i < n) { - targets[i] = new Target(); - targets[i]->setTargetSockAddr(&*addr_iter, sizeof(*addr_iter)); - targets[i]->flags = HOST_UP; - i++; - addr_iter++; + /* Second, make an array of pointer to DNS::Request to suit the interface of + nmap_mass_dns. */ + DNS::Request *requests = new DNS::Request[n]; + for (i = 0, addr_iter = addrs.begin(); i < n; i++, addr_iter++) { + memcpy(&requests[i].ss, &*addr_iter, sizeof(*addr_iter)); + requests[i].type = DNS::PTR; } - nmap_mass_rdns(targets, n); + nmap_mass_dns(requests, n); /* Third, make a map from addresses to names for easy lookup. */ for (i = 0; i < n; i++) { - struct sockaddr_storage ss; - size_t ss_len; - const char *hostname = targets[i]->HostName(); - if (*hostname == '\0') - hostname = NULL; - ss_len = sizeof(ss); - targets[i]->TargetSockAddr(&ss, &ss_len); - name_map[ss] = hostname; + std::string &hostname = requests[i].name; + if (!hostname.empty()) + name_map[requests[i].ss] = hostname.c_str(); } /* Finally, copy the names into the hops. */ for (host_iter = hosts.begin(); host_iter != hosts.end(); host_iter++) { for (hop = (*host_iter)->hops; hop != NULL; hop = hop->parent) { if (hop->addr.ss_family != AF_UNSPEC) { - const char *hostname = name_map[hop->addr]; - if (hostname != NULL) - hop->hostname = hostname; + std::map::const_iterator it; + it = name_map.find(hop->addr); + if (it != name_map.end()) + hop->hostname = it->second; } } } - for (i = 0; i < n; i++) - delete targets[i]; - free(targets); + delete [] requests; } void TracerouteState::transfer_hops() {