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

Generalize nmap_mass_rdns to support more than just Targets and PTR requests

This commit is contained in:
dmiller
2024-04-18 19:16:23 +00:00
parent 22ee545f7e
commit e8c7e7ba01
3 changed files with 170 additions and 126 deletions

View File

@@ -219,7 +219,7 @@ struct dns_server {
}; };
struct request { struct request {
Target *targ; DNS::Request *targ;
struct timeval timeout; struct timeval timeout;
int tries; int tries;
int servers_tried; int servers_tried;
@@ -447,7 +447,7 @@ static void do_possible_writes() {
if (tpreq) { if (tpreq) {
if (o.debugging >= TRACE_DEBUG_LEVEL) 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++; stat_trans++;
put_dns_packet_on_wire(tpreq); 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->id = DNS::Factory::progressiveId;
req->curr_server->write_busy = 1; req->curr_server->write_busy = 1;
req->curr_server->reqs_on_wire++; 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)); memcpy(&now, nsock_gettimeofday(), sizeof(struct timeval));
TIMEVAL_MSEC_ADD(timeout, now, read_timeouts[read_timeout_index][req->tries]); 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 // FIXME: Find a good compromise
// **** We've already tried all servers... give up // **** 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(); output_summary();
stat_dropped++; stat_dropped++;
@@ -579,60 +590,67 @@ static int deal_with_timedout_reads() {
} }
// After processing a DNS response, we search through the IPs we're static void process_request(int action, info &reqinfo) {
// looking for and update their results as necessary. request *tpreq = reqinfo.tpreq;
// Returns non-zero if this matches a query we're looking for dns_server *server = reqinfo.server;
static int process_result(const sockaddr_storage &ip, const std::string &result, int action, u16 id)
{
request *tpreq;
std::map<u16, info>::iterator infoI;
dns_server *server;
infoI = records.find(id); switch (action) {
case ACTION_SYSTEM_RESOLVE:
if( infoI != records.end() ){ case ACTION_FINISHED:
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)
{
server->capacity += CAPACITY_UP_STEP; server->capacity += CAPACITY_UP_STEP;
check_capacities(&*server); check_capacities(&*server);
records.erase(tpreq->id);
if(!result.empty())
{
tpreq->targ->setHostName(result.c_str());
host_cache.add(* tpreq->targ->TargetSockAddr(), result);
}
records.erase(infoI);
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) {
deferred_reqs.push_back(tpreq);
}
else {
delete tpreq;
}
if (action == ACTION_SYSTEM_RESOLVE) deferred_reqs.push_back(tpreq); break;
if (action == ACTION_FINISHED) delete tpreq; case ACTION_TIMEOUT:
}
else
{
memcpy(&tpreq->timeout, nsock_gettimeofday(), sizeof(struct timeval)); memcpy(&tpreq->timeout, nsock_gettimeofday(), sizeof(struct timeval));
deal_with_timedout_reads(); 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 tpreq->targ->name = result;
// all events and return from nsock_loop immediateley host_cache.add(tpreq->targ->ss, result);
if (total_reqs == 0)
close_dns_servers();
return 1;
} }
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 // 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)) DNS_HAS_ERR(f, DNS::ERR_NOT_IMPLEMENTED) || DNS_HAS_ERR(f, DNS::ERR_REFUSED))
return; return;
// Check for matching request
std::map<u16, info>::iterator infoI = records.find(p.id);
if (infoI == records.end()) {
return;
}
info &reqinfo = infoI->second;
if (DNS_HAS_ERR(f, DNS::ERR_NAME)) if (DNS_HAS_ERR(f, DNS::ERR_NAME))
{ {
sockaddr_storage discard; process_request(ACTION_FINISHED, reqinfo);
if(process_result(discard, "", ACTION_FINISHED, p.id)) if (o.debugging >= TRACE_DEBUG_LEVEL)
{ log_write(LOG_STDOUT, "mass_rdns: NXDOMAIN <id = %d>\n", p.id);
if (o.debugging >= TRACE_DEBUG_LEVEL) output_summary();
log_write(LOG_STDOUT, "mass_rdns: NXDOMAIN <id = %d>\n", p.id); stat_nx++;
output_summary();
stat_nx++;
}
return; return;
} }
if (DNS_HAS_ERR(f, DNS::ERR_SERVFAIL)) if (DNS_HAS_ERR(f, DNS::ERR_SERVFAIL))
{ {
sockaddr_storage discard; process_request(ACTION_TIMEOUT, reqinfo);
if (process_result(discard, "", ACTION_TIMEOUT, p.id)) if (o.debugging >= TRACE_DEBUG_LEVEL)
{ log_write(LOG_STDOUT, "mass_rdns: SERVFAIL <id = %d>\n", p.id);
if (o.debugging >= TRACE_DEBUG_LEVEL) stat_sf++;
log_write(LOG_STDOUT, "mass_rdns: SERVFAIL <id = %d>\n", p.id);
stat_sf++;
}
return; 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 // Or if we can get an IP from reversing the .arpa PTR address
|| DNS::Factory::ptrToIp(a.name, ip)) || 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) 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 (!processing_successful) {
if (DNS_HAS_FLAG(f, DNS::TRUNCATED)) { if (DNS_HAS_FLAG(f, DNS::TRUNCATED)) {
// TODO: TCP fallback, or only use system resolver if user didn't specify --dns-servers // 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()) { else if (!alias.empty()) {
if (o.debugging >= TRACE_DEBUG_LEVEL) if (o.debugging >= TRACE_DEBUG_LEVEL)
{ {
char ipstr[INET6_ADDRSTRLEN]; log_write(LOG_STDOUT, "mass_rdns: CNAME for <%s> not processed.\n", reqinfo.tpreq->targ->repr());
sockaddr_storage_iptop(&ip, ipstr);
log_write(LOG_STDOUT, "mass_rdns: CNAME for <%s> not processed.\n", ipstr);
} }
// TODO: Send a PTR request for alias instead. Meanwhile, we'll just fall // TODO: Send a PTR request for alias instead. Meanwhile, we'll just fall
// back to using system resolver. Alternative: report the canonical name // back to using system resolver. Alternative: report the canonical name
// (alias), but that's not very useful. // (alias), but that's not very useful.
process_result(ip, "", ACTION_SYSTEM_RESOLVE, p.id); process_request(ACTION_SYSTEM_RESOLVE, reqinfo);
} }
else { else {
if (o.debugging >= TRACE_DEBUG_LEVEL) { if (o.debugging >= TRACE_DEBUG_LEVEL) {
@@ -1056,12 +1073,11 @@ static void init_servs(void) {
// Actual main loop // 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<request *>::iterator reqI; std::list<request *>::iterator reqI;
request *tpreq; request *tpreq;
int timeout; int timeout;
const char *tpname;
int i; int i;
char spmobuf[1024]; char spmobuf[1024];
@@ -1082,21 +1098,17 @@ static void nmap_mass_rdns_core(Target **targets, int num_targets) {
total_reqs = 0; total_reqs = 0;
// Set up the request structure // 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]; DNS::Request &reqt = requests[i];
if (!(target->flags & HOST_UP) && !o.always_resolve) continue;
// See if it's cached // See if it's cached
std::string res; if (host_cache.lookup(reqt.ss, reqt.name)) {
if (host_cache.lookup(*target->TargetSockAddr(), res)) {
tpname = res.c_str();
target->setHostName(tpname);
continue; continue;
} }
tpreq = new request; tpreq = new request;
tpreq->targ = target; tpreq->targ = &reqt;
tpreq->tries = 0; tpreq->tries = 0;
tpreq->servers_tried = 0; tpreq->servers_tried = 0;
@@ -1165,12 +1177,12 @@ static void nmap_mass_rdns_core(Target **targets, int num_targets) {
tpreq = *reqI; tpreq = *reqI;
if (getnameinfo((const struct sockaddr *)tpreq->targ->TargetSockAddr(), if (getnameinfo((const struct sockaddr *)&tpreq->targ->ss,
sizeof(struct sockaddr_storage), hostname, sizeof(struct sockaddr_storage), hostname,
sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) {
stat_ok++; stat_ok++;
stat_cname++; stat_cname++;
tpreq->targ->setHostName(hostname); tpreq->targ->name = hostname;
} }
delete tpreq; 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 hostname[FQDN_LEN + 1] = "";
char spmobuf[1024]; 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" : ""); Snprintf(spmobuf, sizeof(spmobuf), "System DNS resolution of %d host%s.", stat_actual, stat_actual-1 ? "s" : "");
SPM = new ScanProgressMeter(spmobuf); 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()) if (keyWasPressed())
SPM->printStats((double) i / stat_actual, NULL); SPM->printStats((double) i / stat_actual, NULL);
if (((currenths->flags & HOST_UP) || o.always_resolve) && !o.noresolve) { if (getnameinfo((const struct sockaddr *)&reqt.ss,
if (getnameinfo((struct sockaddr *)currenths->TargetSockAddr(), sizeof(sockaddr_storage), hostname,
sizeof(sockaddr_storage), hostname, sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) {
sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { stat_ok++;
stat_ok++; reqt.name = hostname;
currenths->setHostName(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 // Publicly available function. Basically just a wrapper so we
// can record time information, restart statistics, etc. // 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; 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; stat_actual = stat_ok = stat_nx = stat_sf = stat_trans = stat_dropped = stat_cname = 0;
if (o.mass_dns) if (o.mass_dns)
nmap_mass_rdns_core(targets, num_targets); nmap_mass_dns_core(requests, num_requests);
else else
nmap_system_rdns_core(targets, num_targets); nmap_system_dns_core(requests, num_requests);
gettimeofday(&now, NULL); 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 // Returns a list of known DNS servers
std::list<std::string> get_dns_servers() { std::list<std::string> get_dns_servers() {
init_servs(); init_servs();
@@ -1695,3 +1721,22 @@ size_t DNS::Packet::parseFromBuffer(const u8 *buf, size_t maxlen)
return ret; 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;
}
}

View File

@@ -122,6 +122,7 @@ typedef enum {
} ERRORS; } ERRORS;
typedef enum { typedef enum {
NONE = 0,
A = 1, A = 1,
CNAME = 5, CNAME = 5,
PTR = 12, PTR = 12,
@@ -244,8 +245,18 @@ public:
std::list<Answer> answers; std::list<Answer> 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); void nmap_mass_rdns(Target ** targets, int num_targets);
std::list<std::string> get_dns_servers(); std::list<std::string> get_dns_servers();

View File

@@ -1333,7 +1333,6 @@ void TracerouteState::resolve_hops() {
std::set<sockaddr_storage, lt_sockaddr_storage>::iterator addr_iter; std::set<sockaddr_storage, lt_sockaddr_storage>::iterator addr_iter;
std::vector<HostState *>::iterator host_iter; std::vector<HostState *>::iterator host_iter;
std::map<sockaddr_storage, const char *, lt_sockaddr_storage> name_map; std::map<sockaddr_storage, const char *, lt_sockaddr_storage> name_map;
Target **targets;
Hop *hop; Hop *hop;
int i, n; int i, n;
@@ -1347,43 +1346,32 @@ void TracerouteState::resolve_hops() {
} }
} }
n = addrs.size(); n = addrs.size();
/* Second, make an array of pointer to Target to suit the interface of /* Second, make an array of pointer to DNS::Request to suit the interface of
nmap_mass_rdns. */ nmap_mass_dns. */
targets = (Target **) safe_malloc(sizeof(*targets) * n); DNS::Request *requests = new DNS::Request[n];
i = 0; for (i = 0, addr_iter = addrs.begin(); i < n; i++, addr_iter++) {
addr_iter = addrs.begin(); memcpy(&requests[i].ss, &*addr_iter, sizeof(*addr_iter));
while (i < n) { requests[i].type = DNS::PTR;
targets[i] = new Target();
targets[i]->setTargetSockAddr(&*addr_iter, sizeof(*addr_iter));
targets[i]->flags = HOST_UP;
i++;
addr_iter++;
} }
nmap_mass_rdns(targets, n); nmap_mass_dns(requests, n);
/* Third, make a map from addresses to names for easy lookup. */ /* Third, make a map from addresses to names for easy lookup. */
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
struct sockaddr_storage ss; std::string &hostname = requests[i].name;
size_t ss_len; if (!hostname.empty())
const char *hostname = targets[i]->HostName(); name_map[requests[i].ss] = hostname.c_str();
if (*hostname == '\0')
hostname = NULL;
ss_len = sizeof(ss);
targets[i]->TargetSockAddr(&ss, &ss_len);
name_map[ss] = hostname;
} }
/* Finally, copy the names into the hops. */ /* Finally, copy the names into the hops. */
for (host_iter = hosts.begin(); host_iter != hosts.end(); host_iter++) { for (host_iter = hosts.begin(); host_iter != hosts.end(); host_iter++) {
for (hop = (*host_iter)->hops; hop != NULL; hop = hop->parent) { for (hop = (*host_iter)->hops; hop != NULL; hop = hop->parent) {
if (hop->addr.ss_family != AF_UNSPEC) { if (hop->addr.ss_family != AF_UNSPEC) {
const char *hostname = name_map[hop->addr]; std::map<sockaddr_storage, const char *, lt_sockaddr_storage>::const_iterator it;
if (hostname != NULL) it = name_map.find(hop->addr);
hop->hostname = hostname; if (it != name_map.end())
hop->hostname = it->second;
} }
} }
} }
for (i = 0; i < n; i++) delete [] requests;
delete targets[i];
free(targets);
} }
void TracerouteState::transfer_hops() { void TracerouteState::transfer_hops() {