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 {
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<u16, info>::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<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))
{
sockaddr_storage discard;
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);
output_summary();
stat_nx++;
}
process_request(ACTION_FINISHED, reqinfo);
if (o.debugging >= TRACE_DEBUG_LEVEL)
log_write(LOG_STDOUT, "mass_rdns: NXDOMAIN <id = %d>\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 <id = %d>\n", p.id);
stat_sf++;
}
process_request(ACTION_TIMEOUT, reqinfo);
if (o.debugging >= TRACE_DEBUG_LEVEL)
log_write(LOG_STDOUT, "mass_rdns: SERVFAIL <id = %d>\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<request *>::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<std::string> 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;
}
}

View File

@@ -122,6 +122,7 @@ typedef enum {
} ERRORS;
typedef enum {
NONE = 0,
A = 1,
CNAME = 5,
PTR = 12,
@@ -244,8 +245,18 @@ public:
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);
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::vector<HostState *>::iterator host_iter;
std::map<sockaddr_storage, const char *, lt_sockaddr_storage> 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<sockaddr_storage, const char *, lt_sockaddr_storage>::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() {