1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Simplify mass_dns for the case of requesting A and AAAA records

This commit is contained in:
dmiller
2024-05-13 14:31:32 +00:00
parent 43e70c09d2
commit 0896ed3f5d
3 changed files with 91 additions and 62 deletions

View File

@@ -115,7 +115,7 @@ public:
* NetBlock subclass, override this method. Otherwise, it's safe to reassign * NetBlock subclass, override this method. Otherwise, it's safe to reassign
* the return value to the pointer that this method was called through. * the return value to the pointer that this method was called through.
* On error, return NULL. */ * 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 void reject_last_host() {}
virtual bool next(struct sockaddr_storage *ss, size_t *sslen) = 0; virtual bool next(struct sockaddr_storage *ss, size_t *sslen) = 0;
virtual void apply_netmask(int bits) = 0; virtual void apply_netmask(int bits) = 0;
@@ -174,7 +174,7 @@ public:
int af; int af;
int bits; 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); bool next(struct sockaddr_storage *ss, size_t *sslen);
void apply_netmask(int bits); 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; DNS::Request req;
req.name = hostexp; req.name = hostexp;
req.userdata = nb; req.userdata = nb;
req.type = DNS::A; req.type = DNS::ANY;
requests.push_back(req);
req.type = DNS::AAAA;
requests.push_back(req); requests.push_back(req);
return nb; return nb;
} }
@@ -706,22 +704,19 @@ std::string NetBlockIPv6Netmask::str() const {
return result.str(); return result.str();
} }
NetBlock *NetBlockHostname::resolve(const DNS::Request &reqA, const DNS::Request &reqAAAA) { NetBlock *NetBlockHostname::resolve(const DNS::Request &req) {
std::list<struct sockaddr_storage> resolvedaddrs; std::list<struct sockaddr_storage> resolvedaddrs;
std::list<struct sockaddr_storage> unscanned_addrs; std::list<struct sockaddr_storage> unscanned_addrs;
NetBlock *netblock; NetBlock *netblock;
const DNS::Request &req_same_fam = (af == AF_INET ? reqA : reqAAAA); for (size_t i = 0; i < req.ssv.size(); i++) {
const DNS::Request &req_other_fam = (af == AF_INET ? reqAAAA : reqA); const struct sockaddr_storage &ss = req.ssv[i];
if (!req_same_fam.ssv.empty()) { if (ss.ss_family == af && (o.resolve_all || resolvedaddrs.empty())) {
resolvedaddrs.push_back(req_same_fam.ssv[0]); resolvedaddrs.push_back(ss);
std::list<struct sockaddr_storage> &remainder = o.resolve_all ? resolvedaddrs : unscanned_addrs; }
for (size_t i = 1; i < req_same_fam.ssv.size(); i++) { else {
remainder.push_back(req_same_fam.ssv[i]); 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()) { if (resolvedaddrs.empty()) {
@@ -825,7 +820,7 @@ bool TargetGroup::load_expressions(HostGroupState *hs, int af) {
assert(netblocks.empty()); assert(netblocks.empty());
const char *target_expr = NULL; const char *target_expr = NULL;
std::vector<DNS::Request> requests; std::vector<DNS::Request> requests;
requests.reserve(EXPR_PARSE_BATCH_SZ/2); requests.reserve(EXPR_PARSE_BATCH_SZ/4);
while (netblocks.size() < EXPR_PARSE_BATCH_SZ while (netblocks.size() < EXPR_PARSE_BATCH_SZ
&& NULL != (target_expr = hs->next_expression())) { && NULL != (target_expr = hs->next_expression())) {
NetBlock *nb = NetBlock::parse_expr(target_expr, af, requests); NetBlock *nb = NetBlock::parse_expr(target_expr, af, requests);
@@ -845,12 +840,9 @@ bool TargetGroup::load_expressions(HostGroupState *hs, int af) {
std::list<NetBlock *>::iterator nb_it = netblocks.begin(); std::list<NetBlock *>::iterator nb_it = netblocks.begin();
for (std::vector<DNS::Request>::const_iterator rit = requests.begin(); for (std::vector<DNS::Request>::const_iterator rit = requests.begin();
rit != requests.end(); rit++) { rit != requests.end(); rit++) {
const DNS::Request &reqA = *rit++; const DNS::Request &req = *rit;
const DNS::Request &reqAAAA = *rit; NetBlock *nb_old = (NetBlock *) req.userdata;
NetBlock *nb_old = (NetBlock *) reqA.userdata; NetBlock *nb_new = nb_old->resolve(req);
assert(reqA.userdata == reqAAAA.userdata);
assert(reqA.type == DNS::A && reqAAAA.type == DNS::AAAA);
NetBlock *nb_new = nb_old->resolve(reqA, reqAAAA);
nb_it = std::find(nb_it, netblocks.end(), nb_old); nb_it = std::find(nb_it, netblocks.end(), nb_old);
if (nb_new == NULL) { if (nb_new == NULL) {

View File

@@ -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************************ ***********************IMPORTANT NMAP LICENSE TERMS************************
* *
@@ -225,6 +225,7 @@ struct request {
dns_server *first_server; dns_server *first_server;
dns_server *curr_server; dns_server *curr_server;
u16 id; u16 id;
bool alt_req;
}; };
/*keeps record of a request going through a particular DNS server /*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(); 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 // Takes a DNS request structure and actually puts it on the wire
// (calls nsock_write()). Does various other tasks like recording // (calls nsock_write()). Does various other tasks like recording
// the time for the timeout. // the time for the timeout.
@@ -485,9 +493,10 @@ static void put_dns_packet_on_wire(request *req) {
DNS::Request &reqt = *req->targ; DNS::Request &reqt = *req->targ;
switch(reqt.type) { switch(reqt.type) {
case DNS::ANY:
case DNS::A: case DNS::A:
case DNS::AAAA: 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; break;
case DNS::PTR: case DNS::PTR:
assert(reqt.ssv.size() > 0); assert(reqt.ssv.size() > 0);
@@ -604,7 +613,7 @@ static void process_request(int action, info &reqinfo) {
server->in_process.remove(tpreq); server->in_process.remove(tpreq);
server->reqs_on_wire--; server->reqs_on_wire--;
total_reqs--; total_reqs--;
if (action == ACTION_SYSTEM_RESOLVE) { if (action == ACTION_SYSTEM_RESOLVE && !tpreq->alt_req) {
deferred_reqs.push_back(tpreq); deferred_reqs.push_back(tpreq);
} }
else { 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) static bool process_result(const std::string &name, const DNS::Record *rr, info &reqinfo, bool already_matched)
{ {
DNS::Request *reqt = reqinfo.tpreq->targ; DNS::Request *reqt = reqinfo.tpreq->targ;
std::vector<struct sockaddr_storage> *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 struct sockaddr_storage *ss = NULL;
const DNS::A_Record *a_rec = NULL; const DNS::A_Record *a_rec = NULL;
sockaddr_storage ip; sockaddr_storage ip;
@@ -635,11 +652,12 @@ static bool process_result(const std::string &name, const DNS::Record *rr, info
switch (reqt->type) { switch (reqt->type) {
case DNS::A: case DNS::A:
case DNS::AAAA: case DNS::AAAA:
case DNS::ANY:
if (!already_matched && name != reqt->name) { if (!already_matched && name != reqt->name) {
return false; return false;
} }
a_rec = static_cast<const DNS::A_Record *>(rr); a_rec = static_cast<const DNS::A_Record *>(rr);
reqt->ssv.push_back(a_rec->value); ssv->push_back(a_rec->value);
if (o.debugging >= TRACE_DEBUG_LEVEL) if (o.debugging >= TRACE_DEBUG_LEVEL)
{ {
log_write(LOG_STDOUT, "mass_dns: OK MATCHED <%s> to <%s>\n", 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; const DNS::Answer &a = *it;
if(a.record_class == DNS::CLASS_IN) 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); processing_successful = process_result(a.name, a.record, reqinfo, a.name == alias);
if (!processing_successful && o.debugging) { if (!processing_successful && o.debugging) {
log_write(LOG_STDOUT, "mass_dns: Mismatched record for request %s\n", reqt->repr()); 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; int af = AF_INET;
struct addrinfo *ai_result = NULL, *ai = NULL; struct addrinfo *ai_result = NULL, *ai = NULL;
switch (reqt.type) { if (reqt.type == DNS::PTR) {
case DNS::PTR: assert(reqt.ssv.size() > 0);
assert(reqt.ssv.size() > 0); if (getnameinfo((const struct sockaddr *) &reqt.ssv.front(),
if (getnameinfo((const struct sockaddr *) &reqt.ssv.front(), sizeof(sockaddr_storage), hostname,
sizeof(sockaddr_storage), hostname, sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) {
sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { reqt.name = hostname;
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;
} }
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 --------------------- //------------------- Main loops ---------------------
@@ -1136,11 +1162,9 @@ static void nmap_mass_dns_core(DNS::Request *requests, int num_requests) {
total_reqs = 0; total_reqs = 0;
// Set up the request structure // Set up the request structure
std::string *prev = NULL;
for (int i=0; i < num_requests; i++) for (int i=0; i < num_requests; i++)
{ {
DNS::Request &reqt = 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 // See if it's cached
if (reqt.type == DNS::PTR) { 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->targ = &reqt;
tpreq->tries = 0; tpreq->tries = 0;
tpreq->servers_tried = 0; tpreq->servers_tried = 0;
tpreq->alt_req = false;
new_reqs.push_back(tpreq); new_reqs.push_back(tpreq);
if (!prev || *prev != reqt.name) {
stat_actual++;
}
total_reqs++; 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; if (total_reqs == 0 || servs.size() == 0) return;
@@ -1789,6 +1824,7 @@ const char *DNS::Request::repr()
break; break;
case DNS::A: case DNS::A:
case DNS::AAAA: case DNS::AAAA:
case DNS::ANY:
return name.c_str(); return name.c_str();
break; break;
case DNS::PTR: case DNS::PTR:

View File

@@ -128,6 +128,7 @@ typedef enum {
CNAME = 5, CNAME = 5,
PTR = 12, PTR = 12,
AAAA = 28, AAAA = 28,
ANY = 255, // Internally defined as "A and AAAA"
} RECORD_TYPE; } RECORD_TYPE;
typedef enum { typedef enum {