diff -urNb old.nmap.rev/Makefile.in new.nmap.rev/Makefile.in --- old.nmap.rev/Makefile.in Fri Dec 9 15:36:25 2005 +++ new.nmap.rev/Makefile.in Fri Dec 9 15:36:25 2005 @@ -46,11 +46,11 @@ TARGETNMAPFE=@TARGETNMAPFE@ INSTALLNMAPFE=@INSTALLNMAPFE@ -export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc output.cc scan_engine.cc timing.cc charpool.cc services.cc protocols.cc nmap_rpc.cc portlist.cc NmapOps.cc TargetGroup.cc Target.cc FingerPrintResults.cc service_scan.cc NmapOutputTable.cc MACLookup.cc @COMPAT_SRCS@ +export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc output.cc scan_engine.cc timing.cc charpool.cc services.cc protocols.cc nmap_rpc.cc portlist.cc NmapOps.cc TargetGroup.cc Target.cc FingerPrintResults.cc service_scan.cc NmapOutputTable.cc MACLookup.cc nmap_dns.cc @COMPAT_SRCS@ -OBJS = main.o nmap.o targets.o tcpip.o nmap_error.o utils.o idle_scan.o osscan.o output.o scan_engine.o timing.o charpool.o services.o protocols.o nmap_rpc.o portlist.o NmapOps.o TargetGroup.o Target.o FingerPrintResults.o service_scan.o NmapOutputTable.o MACLookup.o @COMPAT_OBJS@ +OBJS = main.o nmap.o targets.o tcpip.o nmap_error.o utils.o idle_scan.o osscan.o output.o scan_engine.o timing.o charpool.o services.o protocols.o nmap_rpc.o portlist.o NmapOps.o TargetGroup.o Target.o FingerPrintResults.o service_scan.o NmapOutputTable.o MACLookup.o nmap_dns.o @COMPAT_OBJS@ -export DEPS = nmap.h nmap_amigaos.h nmap_error.h targets.h idle_scan.h osscan.h output.h scan_engine.h timing.h tcpip.h utils.h global_structures.h charpool.h services.h protocols.h nmap_rpc.h portlist.h NmapOps.h TargetGroup.h Target.h FingerPrintResults.h service_scan.h NmapOutputTable.h MACLookup.h +export DEPS = nmap.h nmap_amigaos.h nmap_error.h targets.h idle_scan.h osscan.h output.h scan_engine.h timing.h tcpip.h utils.h global_structures.h charpool.h services.h protocols.h nmap_rpc.h portlist.h NmapOps.h TargetGroup.h Target.h FingerPrintResults.h service_scan.h NmapOutputTable.h MACLookup.h nmap_dns.h # %.o : %.cc -- nope this is a GNU extension diff -urNb old.nmap.rev/NmapOps.cc new.nmap.rev/NmapOps.cc --- old.nmap.rev/NmapOps.cc Fri Dec 9 15:36:24 2005 +++ new.nmap.rev/NmapOps.cc Fri Dec 9 15:36:25 2005 @@ -246,6 +246,9 @@ if (xsl_stylesheet) free(xsl_stylesheet); xsl_stylesheet = strdup(tmpxsl); spoof_mac_set = false; + mass_dns = false; + resolve_all = 0; + dns_servers = NULL; } bool NmapOps::TCPScan() { @@ -427,6 +430,9 @@ if (af() == AF_INET6 && (numdecoys|osscan|bouncescan|fragscan|ackscan|finscan|idlescan|ipprotscan|maimonscan|nullscan|rpcscan|synscan|udpscan|windowscan|xmasscan)) { fatal("Sorry -- IPv6 support is currently only available for connect() scan (-sT), ping scan (-sP), and list scan (-sL). Further support is under consideration."); } + + if (af() != AF_INET) mass_dns = false; + } void NmapOps::setMaxRttTimeout(int rtt) diff -urNb old.nmap.rev/NmapOps.h new.nmap.rev/NmapOps.h --- old.nmap.rev/NmapOps.h Fri Dec 9 15:36:25 2005 +++ new.nmap.rev/NmapOps.h Fri Dec 9 15:36:25 2005 @@ -280,6 +280,9 @@ FILE *nmap_stdout; /* Nmap standard output */ int ttl; // Time to live char *datadir; + bool mass_dns; + int resolve_all; + char *dns_servers; private: int max_rtt_timeout; int min_rtt_timeout; diff -urNb old.nmap.rev/nmap.cc new.nmap.rev/nmap.cc --- old.nmap.rev/nmap.cc Fri Dec 9 15:36:24 2005 +++ new.nmap.rev/nmap.cc Fri Dec 9 15:36:25 2005 @@ -202,7 +202,7 @@ size_t j, argvlen; FILE *inputfd = NULL, *excludefd = NULL; char *host_spec = NULL, *exclude_spec = NULL; - short fastscan=0, randomize=1, resolve_all=0; + short fastscan=0, randomize=1; short quashargv = 0; int numhosts_scanned = 0; char **host_exp_group; @@ -301,6 +301,8 @@ {"version_intensity", required_argument, 0, 0}, {"version_light", no_argument, 0, 0}, {"version_all", no_argument, 0, 0}, + {"async_dns", no_argument, 0, 0}, + {"dns_servers", required_argument, 0, 0}, {0, 0, 0, 0} }; @@ -448,6 +450,10 @@ o.setXSLStyleSheet(optarg); } else if (strcmp(long_options[option_index].name, "no_stylesheet") == 0) { o.setXSLStyleSheet(NULL); + } else if (strcmp(long_options[option_index].name, "async_dns") == 0) { + o.mass_dns = true; + } else if (strcmp(long_options[option_index].name, "dns_servers") == 0) { + o.dns_servers = strdup(optarg); } else if (strcmp(long_options[option_index].name, "webxml") == 0) { o.setXSLStyleSheet("http://www.insecure.org/nmap/data/nmap.xsl"); } else if (strcmp(long_options[option_index].name, "oN") == 0) { @@ -682,7 +688,7 @@ fatal("Your port specification string is not parseable"); break; case 'q': quashargv++; break; - case 'R': resolve_all++; break; + case 'R': o.resolve_all++; break; case 'r': randomize = 0; break; @@ -1095,20 +1101,10 @@ if (currenths->flags & HOST_UP && !o.listscan) numhosts_up++; - /* Lookup the IP */ - if (((currenths->flags & HOST_UP) || resolve_all) && !o.noresolve) { - if (currenths->TargetSockAddr(&ss, &sslen) != 0) - fatal("Failed to get target socket address."); - if (getnameinfo((struct sockaddr *)&ss, sslen, hostname, - sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { - currenths->setHostName(hostname); - } - } - if (o.pingscan || o.listscan) { /* We're done with the hosts */ log_write(LOG_XML, ""); - write_host_status(currenths, resolve_all); + write_host_status(currenths, o.resolve_all); printmacinfo(currenths); // if (currenths->flags & HOST_UP) // log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"\n"); @@ -1235,7 +1231,7 @@ /* Now I can do the output and such for each host */ log_write(LOG_XML, ""); - write_host_status(currenths, resolve_all); + write_host_status(currenths, o.resolve_all); if (currenths->timedOut(NULL)) { log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"Skipping host %s due to host timeout\n", currenths->NameIP(hostname, sizeof(hostname))); diff -urNb old.nmap.rev/nmap_dns.cc new.nmap.rev/nmap_dns.cc --- old.nmap.rev/nmap_dns.cc Wed Dec 31 16:00:00 1969 +++ new.nmap.rev/nmap_dns.cc Fri Dec 9 15:36:25 2005 @@ -0,0 +1,813 @@ +// mass_rdns - Parallel Asynchronous Reverse DNS Resolution +// Created by Doug Hoyte +// doug at hcsw.org +// http://www.hcsw.org + +// TODO: +// +// *Tune performance parameters +// +// *Resolve IPs that resolve to CNAMES: +// $ host 217.31.174.62 +// 62.174.31.217.in-addr.arpa is an alias for 62.0-25.174.31.217.in-addr.arpa. +// 62.0-25.174.31.217.in-addr.arpa domain name pointer bitnetcomp62.bitnet.nu. + + +#include +#include +#include +#include + +#include "nmap.h" +#include "NmapOps.h" +#include "nmap_dns.h" +#include "nsock.h" +#include "utils.h" + +extern NmapOps o; + + + +//------------------- Configuration Parameters --------------------- + +// This is the default max number of DNS requests to let each +// server handle. +#define DEFAULT_CAPACITY 10 + +// These are the various retransmission intervals for each server +// before we move on to the next DNS server. (in milliseconds) +int read_timeouts[] = { 1000, 2500 }; + +// How often to display a short debugging summary if debugging is +// specified. Lower numbers means it's displayed more often. +#define SUMMARY_FREQ 50 + +// The amount of time we wait for nsock_write() to complete before +// retransmission. This should almost never happen. (in milliseconds) +#define WRITE_TIMEOUT 100 + + + +//------------------- Internal Structures --------------------- + +typedef struct dns_server_s dns_server; +typedef struct request_s request; + +struct dns_server_s { + char *ipaddr; + nsock_iod nsd; + int reqs_on_wire; + int capacity; + int write_busy; + std::list to_process; + std::list in_process; +}; + +struct request_s { + Target *targ; + struct timeval timeout; + int tries; + dns_server *first_server; + dns_server *curr_server; +}; + + +//------------------- Globals --------------------- + +std::list servs; +int total_reqs; +nsock_pool dnspool=NULL; + +int stat_actual, stat_ok, stat_nx, stat_sf, stat_retrans, stat_dropped; +struct timeval starttv; + + +//------------------- Prototypes --------------------- + +void write_evt_handler(nsock_pool nsp, nsock_event evt, void *req_v); +void do_possible_writes(); + + + + +//------------------- Output code --------------------- + +void output_summary() { + int tp = stat_ok + stat_nx + stat_sf + stat_dropped; + struct timeval now; + + memcpy(&now, nsock_gettimeofday(), sizeof(struct timeval)); + + if (o.debugging && (tp%SUMMARY_FREQ == 0)) + log_write(LOG_STDOUT, "mass_rdns: %.2fs %d/%d [#: %d, OK: %d, NX: %d, SF: %d, RE: %d, DR: %d]\n", + TIMEVAL_MSEC_SUBTRACT(now, starttv) / 1000.0, + tp, stat_actual, + servs.size(), stat_ok, stat_nx, stat_sf, stat_retrans, stat_dropped); + +} + + + + +//------------------- Read handling code --------------------- + +// 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 +int process_result(u32 ia, char *result) { + std::list::iterator servI; + std::list::iterator reqI; + dns_server *tpserv; + request *tpreq; + + for(servI = servs.begin(); servI != servs.end(); servI++) { + tpserv = *servI; + + for(reqI = tpserv->in_process.begin(); reqI != tpserv->in_process.end(); reqI++) { + tpreq = *reqI; + + if ((u32) (tpreq->targ->v4host().s_addr) == ia) { + if (result) tpreq->targ->setHostName(result); + tpserv->in_process.remove(tpreq); + tpserv->reqs_on_wire--; + total_reqs--; + + delete tpreq; + do_possible_writes(); + return 1; + } + } + } + + return 0; +} + + +// Gets an IP address from a X.X.X.X.in-addr.arpa DNS +// encoded string inside a packet. +// ASSUMES NAME LENGTH/VALIDITY HAS ALREADY BEEN VERIFIED +u32 parse_inaddr_arpa(char *buf) { + u32 ip=0; + int i, j; + + for (i=3; i>=0; i--) { + if (buf[0] < 1 || buf[0] > 3) return 0; + for (j=1; j<=buf[0]; j++) if (!isdigit(buf[j])) return 0; + + ip |= atoi(buf+1) << (8*i); + buf += buf[0] + 1; + } + + if (strcasecmp(buf, "\x07in-addr\004arpa\0")) return 0; + + return ip; +} + + +// Turns a DNS packet encoded name (see the RFC) and turns it into +// a normal decimal separated hostname. +// ASSUMES NAME LENGTH/VALIDITY HAS ALREADY BEEN VERIFIED +int encoded_name_to_normal(char *buf, char *output, int outputsize){ + while (buf[0]) { + if (buf[0] >= outputsize-1) return -1; + memcpy(output, buf+1, buf[0]); + outputsize -= buf[0]; + output += buf[0]; + buf += buf[0]+1; + + if (buf[0]) { + *output++ = '.'; + outputsize--; + } else { + *output = '\0'; + } + } + + return 0; +} + + +// Takes a pointer to the start of a DNS name inside a packet. It makes +// sure that there is enough space in the name, deals with compression, etc. +int advance_past_dns_name(char *buf, int buflen, int curbuf, int *nameloc) { + int compression=0; + + if (curbuf <= 0 || curbuf >= buflen) return -1; + + if ((buf[curbuf] & 0xc0)) { + // Need 2 bytes for compression info + if (curbuf + 1 >= buflen) return -1; + + // Compression is OK + compression = curbuf+2; + curbuf = ((buf[curbuf+1] & 0xFF) + ((buf[curbuf] & 0xFF) << 8)) & 0x3FFF; + if (curbuf < 0 || curbuf >= buflen) return -1; + } + + if (nameloc != NULL) *nameloc = curbuf; + + while(buf[curbuf]) { + if (curbuf + buf[curbuf] >= buflen || buf[curbuf] <= 0) return -1; + curbuf += buf[curbuf] + 1; + } + + if (compression) return compression; + else return curbuf+1; +} + + +// FIXME: 135.8.203.35 + +// Nsock read handler. One nsock read for each DNS server exists at each +// time. This function uses various helper functions as defined above. +void read_evt_handler(nsock_pool nsp, nsock_event evt, void *nothing) { + char *buf; + int buflen, curbuf=0; + int i, nameloc, rdlen, atype, aclass; + int errcode=0; + int queries, answers; + + if (total_reqs > 1) + nsock_read(nsp, nse_iod(evt), read_evt_handler, -1, NULL); + + if (nse_type(evt) != NSE_TYPE_READ || nse_status(evt) != NSE_STATUS_SUCCESS) { + if (o.debugging) + log_write(LOG_STDOUT, "mass_dns: warning: got a %s:%s in read_evt_handler()\n", + nse_type2str(nse_type(evt)), + nse_status2str(nse_status(evt))); + return; + } + + buf = nse_readbuf(evt, &buflen); + + // Size of header is 12, and we must have additional data as well + if (buflen <= 12) return; + + // Check that this is a response, standard query, and that no truncation was performed + // 0xFA == 11111010 (we're not concerned with AA or RD bits) + if ((buf[2] & 0xFA) != 0x80) return; + + // Check that Recursion is available, the zero field is all zeros + // and there is no error condition: + if ((buf[3] & 0xFF) != 0x80) { + if ((buf[3] & 0xF) == 2) errcode = 2; + else if ((buf[3] & 0xF) == 3) errcode = 3; + else return; + } + + queries = (buf[5] & 0xFF) + ((buf[4] & 0xFF) << 8); + answers = (buf[7] & 0xFF) + ((buf[6] & 0xFF) << 8); + + // With a normal resolution, we should have 1+ queries and 1+ answers. + // If the domain doesn't resolve (NXDOMAIN or SERVFAIL) we should have + // 1+ queries and 0 answers: + if (errcode) { + if (queries <= 0 || answers > 0) return; + } else { + if (queries <= 0 || answers <= 0) return; + } + + curbuf = 12; + + // Need to safely skip past QUERY section + + for (i=0; i= buflen) return; + curbuf += 4; + + if (errcode) { + struct in_addr ia; + ia.s_addr = parse_inaddr_arpa(buf+nameloc); + int found = process_result(ia.s_addr, NULL); + + if (errcode == 2 && found) { + if (o.debugging >= 2) log_write(LOG_STDOUT, "mass_rdns: SERVFAIL <%s>\n", inet_ntoa(ia)); + output_summary(); + stat_sf++; + } else if (errcode == 3 && found) { + if (o.debugging >= 2) log_write(LOG_STDOUT, "mass_rdns: NXDOMAIN <%s>\n", inet_ntoa(ia)); + output_summary(); + stat_nx++; + } + } + } + + // No answers if NXDOMAIN/SERVFAIL + if (errcode) return; + + // We're now at the ANSWER section + + for (i=0; i= buflen) return; + + atype = (buf[curbuf+1] & 0xFF) + ((buf[curbuf+0] & 0xFF) << 8); + aclass = (buf[curbuf+3] & 0xFF) + ((buf[curbuf+2] & 0xFF) << 8); + rdlen = (buf[curbuf+9] & 0xFF) + ((buf[curbuf+8] & 0xFF) << 8); + curbuf += 10; + + if (atype == 12 && aclass == 1) { + struct in_addr ia; + char outbuf[512]; + + ia.s_addr = parse_inaddr_arpa(buf+nameloc); + + curbuf = advance_past_dns_name(buf, buflen, curbuf, &nameloc); + if (curbuf == -1 || curbuf >= buflen) return; + + encoded_name_to_normal(buf+nameloc, outbuf, sizeof(outbuf)); + + if (process_result(ia.s_addr, outbuf)) { + if (o.debugging >= 2) log_write(LOG_STDOUT, "mass_rdns: OK MATCHED <%s> to <%s>\n", inet_ntoa(ia), outbuf); + output_summary(); + stat_ok++; + } + } + + if (curbuf >= buflen) return; + } + +} + + + + +//------------------- Write handling code --------------------- + +// Inserts an integer (endian non-specifically) into a DNS packet. +// Returns number of bytes written +int add_integer_to_dns_packet(char *packet, int c) { + char tpnum[4]; + int tplen; + + sprintf(tpnum, "%d", c); + tplen = strlen(tpnum); + packet[0] = (char) tplen; + memcpy(packet+1, tpnum, tplen); + + return tplen+1; +} + + +// 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. +void put_dns_packet_on_wire(request *req) { + char packet[512]; + int plen; + u32 ip; + struct timeval now, timeout; + + ip = (u32) req->targ->v4host().s_addr; + + memcpy(packet, "\x99\x99\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00", 12); + plen = 12; + + plen += add_integer_to_dns_packet(packet+plen, (ip>>24) & 0xFF); + plen += add_integer_to_dns_packet(packet+plen, (ip>>16) & 0xFF); + plen += add_integer_to_dns_packet(packet+plen, (ip>>8) & 0xFF); + plen += add_integer_to_dns_packet(packet+plen, ip & 0xFF); + + memcpy(packet+plen, "\x07in-addr\004arpa\x00\x00\x0c\x00\x01", 18); + plen += 18; + + req->curr_server->write_busy = 1; + req->curr_server->reqs_on_wire++; + + memcpy(&now, nsock_gettimeofday(), sizeof(struct timeval)); + TIMEVAL_MSEC_ADD(timeout, now, read_timeouts[req->tries]); + memcpy(&req->timeout, &timeout, sizeof(struct timeval)); + + req->tries++; + + nsock_write(dnspool, req->curr_server->nsd, write_evt_handler, WRITE_TIMEOUT, req, packet, plen); +} + + + + +// Processes DNS packets that have timed out +// Returns time until next read timeout +int deal_with_timedout_reads() { + std::list::iterator servI; + std::list::iterator servItemp; + std::list::iterator reqI; + dns_server *tpserv; + request *tpreq; + struct timeval now; + int tp, min_timeout = INT_MAX; + + memcpy(&now, nsock_gettimeofday(), sizeof(struct timeval)); + + for(servI = servs.begin(); servI != servs.end(); servI++) { + tpserv = *servI; + + restart_loop: + + for(reqI = tpserv->in_process.begin(); reqI != tpserv->in_process.end(); reqI++) { + tpreq = *reqI; + + tp = TIMEVAL_MSEC_SUBTRACT(tpreq->timeout, now); + if (tp > 0 && tp < min_timeout) min_timeout = tp; + + if (tp <= 0) { + if (o.debugging >= 2) log_write(LOG_STDOUT, "mass_rdns: *RE*TRANSMISSION for <%s> (server <%s>)\n", tpreq->targ->targetipstr() , tpserv->ipaddr); + stat_retrans++; + tpserv->in_process.remove(tpreq); + tpserv->reqs_on_wire--; + + // If we've tried this server enough times, move to the next one + if (tpreq->tries >= (int) (sizeof(read_timeouts) / sizeof(int))) { + servItemp = servI; + servItemp++; + + if (servItemp == servs.end()) servItemp = servs.begin(); + + tpreq->curr_server = *servItemp; + tpreq->tries = 0; + + if (tpreq->curr_server == tpreq->first_server) { + // Either give up on the IP + // or, for maximum reliability, put the server back into processing + // Note it's possible that this will never terminate. + // FIXME: Find a good compromise + + // **** We've already tried all servers... give up + if (o.debugging >= 2) log_write(LOG_STDOUT, "mass_rdns: *DR*OPPING <%s>\n", tpreq->targ->targetipstr()); + output_summary(); + stat_dropped++; + total_reqs--; + delete tpreq; + + // **** OR We start at the back of this server's queue + //(*servItemp)->to_process.push_back(tpreq); + } else { + (*servItemp)->to_process.push_back(tpreq); + } + } else { + tpserv->to_process.push_back(tpreq); + } + + goto restart_loop; + } + } + + } + + if (min_timeout == INT_MAX) return 200; + else return min_timeout; + +} + + +// Puts as many packets on the line as capacity will allow +void do_possible_writes() { + std::list::iterator servI; + dns_server *tpserv; + request *tpreq; + + for(servI = servs.begin(); servI != servs.end(); servI++) { + tpserv = *servI; + + if (!tpserv->to_process.empty() && tpserv->write_busy == 0 && tpserv->reqs_on_wire < tpserv->capacity) { + tpreq = tpserv->to_process.front(); + tpserv->to_process.pop_front(); + if (o.debugging >= 2) log_write(LOG_STDOUT, "mass_rdns: TRANSMITTING for <%s> (server <%s>)\n", tpreq->targ->targetipstr() , tpserv->ipaddr); + put_dns_packet_on_wire(tpreq); + } + + } + +} + + +// nsock write handler +void write_evt_handler(nsock_pool nsp, nsock_event evt, void *req_v) { + request *req = (request *) req_v; + + req->curr_server->write_busy = 0; + req->curr_server->in_process.push_front(req); + + do_possible_writes(); +} + + + +//------------------- DNS Server handling code --------------------- + +// nsock connect handler - Empty because it doesn't really need to do anything... +void connect_evt_handler(nsock_pool nsp, nsock_event evt, void *servers) { +} + + +// Adds DNS servers to the dns_server list. They can be separated by +// commas or spaces - NOTE this doesn't actually do any connecting! +void add_dns_server(char *ipaddrs) { + std::list::iterator servI; + dns_server *tpserv; + char *ipaddr; + struct in_addr junk; + + ipaddr = strtok(ipaddrs, " ,"); + + while (ipaddr != NULL) { + + for(servI = servs.begin(); servI != servs.end(); servI++) { + tpserv = *servI; + + // Already added! + if (strcmp(ipaddr, tpserv->ipaddr) == 0) break; + } + + // If it hasn't already been added and the address seems valid, add it! + if (servI == servs.end() && inet_aton(ipaddr, &junk)) { + tpserv = new dns_server; + + tpserv->ipaddr = strdup(ipaddr); + + servs.push_front(tpserv); + } + + ipaddr = strtok(NULL, " ,"); + } + +} + + +// Creates a new nsi for each DNS server +void connect_dns_servers() { + std::list::iterator serverI; + dns_server *s; + struct sockaddr_in ss; + int ss_len; + + for(serverI = servs.begin(); serverI != servs.end(); serverI++) { + s = *serverI; + + s->nsd = nsi_new(dnspool, NULL); + s->reqs_on_wire = 0; + s->capacity = DEFAULT_CAPACITY; + s->write_busy = 0; + + ss_len = sizeof(struct sockaddr_in); + ss.sin_family = AF_INET; + inet_aton(s->ipaddr, &ss.sin_addr); + + nsock_connect_udp(dnspool, s->nsd, connect_evt_handler, NULL, (struct sockaddr *) &ss, ss_len, 53); + nsock_read(dnspool, s->nsd, read_evt_handler, -1, NULL); + } + +} + + +// Closes all nsis created in connect_dns_servers() +void close_dns_servers() { + std::list::iterator serverI; + + for(serverI = servs.begin(); serverI != servs.end(); serverI++) { + nsi_delete((*serverI)->nsd, NSOCK_PENDING_SILENT); + (*serverI)->to_process.clear(); + (*serverI)->in_process.clear(); + } + +} + + +// Parses /etc/resolv.conf (unix) or the registry (win32) and adds +// all the nameservers found via the add_dns_server() function. +void parse_resolvdotconf() { + +#ifndef WIN32 + + FILE *fp; + char buf[2048], *tp; + char ipaddr[16]; + + fp = fopen("/etc/resolv.conf", "r"); + if (fp == NULL) { + fatal("Unable to open /etc/resolv.conf. Try NOT using --async_dns or specify valid servers with --dns_servers"); + } + + while (fgets(buf, sizeof(buf), fp)) { + tp = buf; + + // Clip off comments #, \r, \n + while (*tp != '\r' && *tp != '\n' && *tp != '#' && *tp) tp++; + *tp = '\0'; + + tp = buf; + // Skip any leading whitespace + while (*tp == ' ' || *tp == '\t') tp++; + + if (sscanf(tp, "nameserver %15s", ipaddr) == 1) add_dns_server(ipaddr); + } + + fclose(fp); + +#else + + // With win32, one or more of the following registry keys should hold + // the IP addresses of the current DNS servers: + // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\NameServer + // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DhcpNameServer + // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\*\NameServer + // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\*\DhcpNameServer + // Ouch! + + HKEY hKey; + HKEY hKey2; + char buf[2048], keyname[2048], *p; + long sz, i; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", + 0, KEY_READ, &hKey) != ERROR_SUCCESS) + fatal("Error opening registry to read DNS servers. Try NOT using --async_dns or specify valid servers with --dns_servers"); + + sz = sizeof(buf); + if (RegQueryValueEx(hKey, "NameServer", NULL, NULL, (LPBYTE) buf, (LPDWORD) &sz) == ERROR_SUCCESS) + add_dns_server(buf); + + sz = sizeof(buf); + if (RegQueryValueEx(hKey, "DhcpNameServer", NULL, NULL, (LPBYTE) buf, (LPDWORD) &sz) == ERROR_SUCCESS) + add_dns_server(buf); + + RegCloseKey(hKey); + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", + 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + + for (i=0; RegEnumKey(hKey, i, buf, sizeof(buf)) != ERROR_NO_MORE_ITEMS; i++) { + + snprintf(keyname, sizeof(keyname), "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s", buf); + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + keyname, + 0, KEY_READ, &hKey2) == ERROR_SUCCESS) { + + sz = sizeof(buf); + if (RegQueryValueEx(hKey2, "DhcpNameServer", NULL, NULL, (LPBYTE) buf, (LPDWORD) &sz) == ERROR_SUCCESS) + add_dns_server(buf); + + sz = sizeof(buf); + if (RegQueryValueEx(hKey2, "NameServer", NULL, NULL, (LPBYTE) buf, (LPDWORD) &sz) == ERROR_SUCCESS) + add_dns_server(buf); + + RegCloseKey(hKey2); + } + + } + + RegCloseKey(hKey); + + } + +#endif + +} + + + + +//------------------- Main loops --------------------- + + +// Actual main loop +void nmap_mass_rdns_core(Target **targets, int num_targets) { + + Target **hostI; + std::list::iterator serverI; + request *tpreq; + int timeout; + + if (o.mass_dns == false) { + Target *currenths; + struct sockaddr_storage ss; + size_t sslen; + char hostname[MAXHOSTNAMELEN + 1] = ""; + + for(hostI = targets; hostI < targets+num_targets; hostI++) { + currenths = *hostI; + + if (((currenths->flags & HOST_UP) || o.resolve_all) && !o.noresolve) { + if (currenths->TargetSockAddr(&ss, &sslen) != 0) + fatal("Failed to get target socket address."); + stat_actual++; + if (getnameinfo((struct sockaddr *)&ss, sslen, hostname, + sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { + stat_ok++; + currenths->setHostName(hostname); + } + } + } + + return; + } + + // If necessary, set up the dns server list from resolv.conf + if (servs.size() == 0) { + if (o.dns_servers) add_dns_server(o.dns_servers); + else parse_resolvdotconf(); + + if (servs.size() == 0) + fatal("Unable to determine any DNS servers. Try NOT using --async_dns or specify valid servers with --dns_servers"); + } + + + + // If necessary, set up the /etc/hosts hashtable + // FIXME: Do this + + + + total_reqs = 0; + + // Set up the request structure + serverI = servs.begin(); + for(hostI = targets; hostI < targets+num_targets; hostI++) { + if (!((*hostI)->flags & HOST_UP) && !o.resolve_all) continue; + + stat_actual++; + + tpreq = new request; + tpreq->targ = *hostI; + tpreq->tries = 0; + + tpreq->first_server = tpreq->curr_server = *serverI; + (*serverI)->to_process.push_back(tpreq); + + serverI++; + if (serverI == servs.end()) serverI = servs.begin(); + + total_reqs++; + } + + if (total_reqs == 0) return; + + // And finally, do it! + + if ((dnspool = nsp_new(NULL)) == NULL) + fatal("Unable to create nsock pool in nmap_mass_rdns_core()"); + + connect_dns_servers(); + + while (total_reqs > 0) { + timeout = deal_with_timedout_reads(); + + do_possible_writes(); + + if (total_reqs <= 0) break; + + nsock_loop(dnspool, timeout); + } + + close_dns_servers(); + + nsp_delete(dnspool); + +} + + + +// 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) { + + struct timeval now; + + gettimeofday(&starttv, NULL); + + stat_actual = stat_ok = stat_nx = stat_sf = stat_retrans = stat_dropped = 0; + + nmap_mass_rdns_core(targets, num_targets); + + gettimeofday(&now, NULL); + + if (o.verbose) { + if (o.mass_dns) { + // #: Number of DNS servers used + // OK: Number of fully reverse resolved queries + // NX: Number of confirmations of 'No such reverse domain eXists' + // SF: Number of IPs that got 'Server Failure's + // RE: Total number of retransmissions necessary. 0 is ideal, higher is worse + // DR: Dropped IPs (no valid responses were received) + log_write(LOG_STDOUT, "DNS resolution of %d IPs took %.2fs. Mode: Async [#: %d, OK: %d, NX: %d, SF: %d, RE: %d, DR: %d]\n", + stat_actual, TIMEVAL_MSEC_SUBTRACT(now, starttv) / 1000.0, + servs.size(), stat_ok, stat_nx, stat_sf, stat_retrans, stat_dropped); + } else { + log_write(LOG_STDOUT, "DNS resolution of %d IPs took %.2fs. Mode: System [OK: %d, ??: %d]\n", + stat_actual, TIMEVAL_MSEC_SUBTRACT(now, starttv) / 1000.0, + stat_ok, stat_actual - stat_ok); + } + } + +} diff -urNb old.nmap.rev/nmap_dns.h new.nmap.rev/nmap_dns.h --- old.nmap.rev/nmap_dns.h Wed Dec 31 16:00:00 1969 +++ new.nmap.rev/nmap_dns.h Fri Dec 9 15:36:25 2005 @@ -0,0 +1,3 @@ +#include "Target.h" + +void nmap_mass_rdns(Target ** targets, int num_targets); diff -urNb old.nmap.rev/targets.cc new.nmap.rev/targets.cc --- old.nmap.rev/targets.cc Fri Dec 9 15:36:25 2005 +++ new.nmap.rev/targets.cc Fri Dec 9 15:36:25 2005 @@ -108,6 +108,7 @@ #include "TargetGroup.h" #include "Target.h" #include "scan_engine.h" +#include "nmap_dns.h" using namespace std; extern NmapOps o; @@ -432,6 +433,8 @@ massping(hs->hostbatch, hs->current_batch_sz, ports, DEFAULT_PING_TYPES); else massping(hs->hostbatch, hs->current_batch_sz, ports, *pingtype); + + if (!o.noresolve) nmap_mass_rdns(hs->hostbatch, hs->current_batch_sz); return hs->hostbatch[hs->next_batch_no++]; }