From 0896ed3f5d8a4560dd53e7e1582adaaf024c1a5e Mon Sep 17 00:00:00 2001 From: dmiller Date: Mon, 13 May 2024 14:31:32 +0000 Subject: [PATCH] Simplify mass_dns for the case of requesting A and AAAA records --- TargetGroup.cc | 38 +++++++---------- nmap_dns.cc | 114 ++++++++++++++++++++++++++++++++----------------- nmap_dns.h | 1 + 3 files changed, 91 insertions(+), 62 deletions(-) diff --git a/TargetGroup.cc b/TargetGroup.cc index 3ecc5b98f..2d6fcb85a 100644 --- a/TargetGroup.cc +++ b/TargetGroup.cc @@ -115,7 +115,7 @@ public: * NetBlock subclass, override this method. Otherwise, it's safe to reassign * the return value to the pointer that this method was called through. * On error, return NULL. */ - virtual NetBlock *resolve(const DNS::Request &reqA, const DNS::Request &reqAAAA) { return this; } + virtual NetBlock *resolve(const DNS::Request &req) { return this; } virtual void reject_last_host() {} virtual bool next(struct sockaddr_storage *ss, size_t *sslen) = 0; virtual void apply_netmask(int bits) = 0; @@ -174,7 +174,7 @@ public: int af; int bits; - NetBlock *resolve(const DNS::Request &reqA, const DNS::Request &reqAAAA); + NetBlock *resolve(const DNS::Request &req); bool next(struct sockaddr_storage *ss, size_t *sslen); void apply_netmask(int bits); @@ -306,9 +306,7 @@ static NetBlock *parse_expr_without_netmask(const char *hostexp, int af, std::ve DNS::Request req; req.name = hostexp; req.userdata = nb; - req.type = DNS::A; - requests.push_back(req); - req.type = DNS::AAAA; + req.type = DNS::ANY; requests.push_back(req); return nb; } @@ -706,22 +704,19 @@ std::string NetBlockIPv6Netmask::str() const { return result.str(); } -NetBlock *NetBlockHostname::resolve(const DNS::Request &reqA, const DNS::Request &reqAAAA) { +NetBlock *NetBlockHostname::resolve(const DNS::Request &req) { std::list resolvedaddrs; std::list unscanned_addrs; NetBlock *netblock; - const DNS::Request &req_same_fam = (af == AF_INET ? reqA : reqAAAA); - const DNS::Request &req_other_fam = (af == AF_INET ? reqAAAA : reqA); - if (!req_same_fam.ssv.empty()) { - resolvedaddrs.push_back(req_same_fam.ssv[0]); - std::list &remainder = o.resolve_all ? resolvedaddrs : unscanned_addrs; - for (size_t i = 1; i < req_same_fam.ssv.size(); i++) { - remainder.push_back(req_same_fam.ssv[i]); + for (size_t i = 0; i < req.ssv.size(); i++) { + const struct sockaddr_storage &ss = req.ssv[i]; + if (ss.ss_family == af && (o.resolve_all || resolvedaddrs.empty())) { + resolvedaddrs.push_back(ss); + } + else { + unscanned_addrs.push_back(ss); } - } - for (size_t i = 0; i < req_other_fam.ssv.size(); i++) { - unscanned_addrs.push_back(req_other_fam.ssv[i]); } if (resolvedaddrs.empty()) { @@ -825,7 +820,7 @@ bool TargetGroup::load_expressions(HostGroupState *hs, int af) { assert(netblocks.empty()); const char *target_expr = NULL; std::vector requests; - requests.reserve(EXPR_PARSE_BATCH_SZ/2); + requests.reserve(EXPR_PARSE_BATCH_SZ/4); while (netblocks.size() < EXPR_PARSE_BATCH_SZ && NULL != (target_expr = hs->next_expression())) { NetBlock *nb = NetBlock::parse_expr(target_expr, af, requests); @@ -845,12 +840,9 @@ bool TargetGroup::load_expressions(HostGroupState *hs, int af) { std::list::iterator nb_it = netblocks.begin(); for (std::vector::const_iterator rit = requests.begin(); rit != requests.end(); rit++) { - const DNS::Request &reqA = *rit++; - const DNS::Request &reqAAAA = *rit; - NetBlock *nb_old = (NetBlock *) reqA.userdata; - assert(reqA.userdata == reqAAAA.userdata); - assert(reqA.type == DNS::A && reqAAAA.type == DNS::AAAA); - NetBlock *nb_new = nb_old->resolve(reqA, reqAAAA); + const DNS::Request &req = *rit; + NetBlock *nb_old = (NetBlock *) req.userdata; + NetBlock *nb_new = nb_old->resolve(req); nb_it = std::find(nb_it, netblocks.end(), nb_old); if (nb_new == NULL) { diff --git a/nmap_dns.cc b/nmap_dns.cc index 583564b18..776be44c1 100644 --- a/nmap_dns.cc +++ b/nmap_dns.cc @@ -1,6 +1,6 @@ /*************************************************************************** - * nmap_dns.cc -- Handles parallel reverse DNS resolution for target IPs * + * nmap_dns.cc -- Handles parallel DNS resolution for target IPs * * * ***********************IMPORTANT NMAP LICENSE TERMS************************ * @@ -225,6 +225,7 @@ struct request { dns_server *first_server; dns_server *curr_server; u16 id; + bool alt_req; }; /*keeps record of a request going through a particular DNS server @@ -469,6 +470,13 @@ static void write_evt_handler(nsock_pool nsp, nsock_event evt, void *req_v) { do_possible_writes(); } +static DNS::RECORD_TYPE wire_type(DNS::RECORD_TYPE t) { + if (t == DNS::ANY) { + return DNS::A; + } + return t; +} + // Takes a DNS request structure and actually puts it on the wire // (calls nsock_write()). Does various other tasks like recording // the time for the timeout. @@ -485,9 +493,10 @@ static void put_dns_packet_on_wire(request *req) { DNS::Request &reqt = *req->targ; switch(reqt.type) { + case DNS::ANY: case DNS::A: case DNS::AAAA: - plen = DNS::Factory::buildSimpleRequest(reqt.name, reqt.type, packet, maxlen); + plen = DNS::Factory::buildSimpleRequest(reqt.name, wire_type(reqt.type), packet, maxlen); break; case DNS::PTR: assert(reqt.ssv.size() > 0); @@ -604,7 +613,7 @@ static void process_request(int action, info &reqinfo) { server->in_process.remove(tpreq); server->reqs_on_wire--; total_reqs--; - if (action == ACTION_SYSTEM_RESOLVE) { + if (action == ACTION_SYSTEM_RESOLVE && !tpreq->alt_req) { deferred_reqs.push_back(tpreq); } else { @@ -628,6 +637,14 @@ static void process_request(int action, info &reqinfo) { static bool process_result(const std::string &name, const DNS::Record *rr, info &reqinfo, bool already_matched) { DNS::Request *reqt = reqinfo.tpreq->targ; + std::vector *ssv; + if (reqinfo.tpreq->alt_req) { + DNS::Request *alt_req = (DNS::Request *) reqinfo.tpreq->targ->userdata; + ssv = &alt_req->ssv; + } + else { + ssv = &reqt->ssv; + } const struct sockaddr_storage *ss = NULL; const DNS::A_Record *a_rec = NULL; sockaddr_storage ip; @@ -635,11 +652,12 @@ static bool process_result(const std::string &name, const DNS::Record *rr, info switch (reqt->type) { case DNS::A: case DNS::AAAA: + case DNS::ANY: if (!already_matched && name != reqt->name) { return false; } a_rec = static_cast(rr); - reqt->ssv.push_back(a_rec->value); + ssv->push_back(a_rec->value); if (o.debugging >= TRACE_DEBUG_LEVEL) { log_write(LOG_STDOUT, "mass_dns: OK MATCHED <%s> to <%s>\n", @@ -744,7 +762,7 @@ static void read_evt_handler(nsock_pool nsp, nsock_event evt, void *) { const DNS::Answer &a = *it; if(a.record_class == DNS::CLASS_IN) { - if (reqt->type == a.record_type) { + if (wire_type(reqt->type) == a.record_type) { processing_successful = process_result(a.name, a.record, reqinfo, a.name == alias); if (!processing_successful && o.debugging) { log_write(LOG_STDOUT, "mass_dns: Mismatched record for request %s\n", reqt->repr()); @@ -1077,34 +1095,42 @@ static bool system_resolve(DNS::Request &reqt) int af = AF_INET; struct addrinfo *ai_result = NULL, *ai = NULL; - switch (reqt.type) { - case DNS::PTR: - assert(reqt.ssv.size() > 0); - if (getnameinfo((const struct sockaddr *) &reqt.ssv.front(), - sizeof(sockaddr_storage), hostname, - sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { - reqt.name = hostname; - return true; - } - break; - case DNS::AAAA: - af = AF_INET6; - case DNS::A: - ai_result = resolve_all(reqt.name.c_str(), af); - for (ai = ai_result; ai != NULL; ai = ai->ai_next) { - if (ai->ai_addr->sa_family == af && ai->ai_addrlen <= sizeof(struct sockaddr_storage)) { - reqt.ssv.push_back(*(struct sockaddr_storage *)ai->ai_addr); - } - } - if (ai_result != NULL) - freeaddrinfo(ai_result); - return true; - break; - default: - error("System DNS resolution of %s could not be performed.\n", reqt.repr()); - break; + if (reqt.type == DNS::PTR) { + assert(reqt.ssv.size() > 0); + if (getnameinfo((const struct sockaddr *) &reqt.ssv.front(), + sizeof(sockaddr_storage), hostname, + sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { + reqt.name = hostname; + } } - return false; + else { + switch (reqt.type) { + case DNS::A: + af = AF_INET; + break; + case DNS::AAAA: + af = AF_INET6; + break; + case DNS::ANY: + af = AF_UNSPEC; + break; + default: + error("System DNS resolution of %s could not be performed.\n", reqt.repr()); + return false; + break; + } + ai_result = resolve_all(reqt.name.c_str(), af); + for (ai = ai_result; ai != NULL; ai = ai->ai_next) { + if (ai->ai_addrlen <= sizeof(struct sockaddr_storage)) { + reqt.ssv.push_back(*(struct sockaddr_storage *)ai->ai_addr); + } + } + if (ai_result != NULL) + freeaddrinfo(ai_result); + else + return false; + } + return true; } //------------------- Main loops --------------------- @@ -1136,11 +1162,9 @@ static void nmap_mass_dns_core(DNS::Request *requests, int num_requests) { total_reqs = 0; // Set up the request structure - std::string *prev = NULL; for (int i=0; i < num_requests; i++) { DNS::Request &reqt = requests[i]; - assert(reqt.type == DNS::PTR || reqt.type == DNS::A || reqt.type == DNS::AAAA); // See if it's cached if (reqt.type == DNS::PTR) { @@ -1154,14 +1178,25 @@ static void nmap_mass_dns_core(DNS::Request *requests, int num_requests) { tpreq->targ = &reqt; tpreq->tries = 0; tpreq->servers_tried = 0; + tpreq->alt_req = false; new_reqs.push_back(tpreq); - - if (!prev || *prev != reqt.name) { - stat_actual++; - } total_reqs++; - prev = &reqt.name; + + if (reqt.type == DNS::ANY) { + DNS::Request *req_aaaa = new DNS::Request; + req_aaaa->type = DNS::AAAA; + req_aaaa->name = reqt.name; + req_aaaa->userdata = &reqt; + request *tpreq_alt = new request; + *tpreq_alt = *tpreq; + tpreq_alt->targ = req_aaaa; + tpreq_alt->alt_req = true; + new_reqs.push_back(tpreq_alt); + total_reqs++; + } + + stat_actual++; } if (total_reqs == 0 || servs.size() == 0) return; @@ -1789,6 +1824,7 @@ const char *DNS::Request::repr() break; case DNS::A: case DNS::AAAA: + case DNS::ANY: return name.c_str(); break; case DNS::PTR: diff --git a/nmap_dns.h b/nmap_dns.h index a2b88641a..0af8b012b 100644 --- a/nmap_dns.h +++ b/nmap_dns.h @@ -128,6 +128,7 @@ typedef enum { CNAME = 5, PTR = 12, AAAA = 28, + ANY = 255, // Internally defined as "A and AAAA" } RECORD_TYPE; typedef enum {