nmap_dns.cc
来自「Ubuntu packages of security software。 相」· CC 代码 · 共 1,261 行 · 第 1/3 页
CC
1,261 行
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 timeoutstatic int deal_with_timedout_reads() { std::list<dns_server *>::iterator servI; std::list<dns_server *>::iterator servItemp; std::list<request *>::iterator reqI; std::list<request *>::iterator nextI; dns_server *tpserv; request *tpreq; struct timeval now; int tp, min_timeout = INT_MAX; memcpy(&now, nsock_gettimeofday(), sizeof(struct timeval)); if (keyWasPressed()) SPM->printStats((double) (stat_ok + stat_nx + stat_dropped) / stat_actual, &now); for(servI = servs.begin(); servI != servs.end(); servI++) { tpserv = *servI; nextI = tpserv->in_process.begin(); if (nextI == tpserv->in_process.end()) continue; do { reqI = nextI++; tpreq = *reqI; tp = TIMEVAL_MSEC_SUBTRACT(tpreq->timeout, now); if (tp > 0 && tp < min_timeout) min_timeout = tp; if (tp <= 0) { tpserv->capacity = (int) (tpserv->capacity * CAPACITY_MINOR_DOWN_SCALE); check_capacities(tpserv); tpserv->in_process.erase(reqI); tpserv->reqs_on_wire--; // If we've tried this server enough times, move to the next one if (read_timeouts[read_timeout_index][tpreq->tries] == -1) { tpserv->capacity = (int) (tpserv->capacity * CAPACITY_MAJOR_DOWN_SCALE); check_capacities(tpserv); servItemp = servI; servItemp++; if (servItemp == servs.end()) servItemp = servs.begin(); tpreq->curr_server = *servItemp; tpreq->tries = 0; tpreq->servers_tried++; if (tpreq->curr_server == tpreq->first_server || tpreq->servers_tried == SERVERS_TO_TRY) { // 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 >= TRACE_DEBUG_LEVEL) 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); } } } while (nextI != tpserv->in_process.end()); } if (min_timeout > 500) return 500; else return min_timeout;}// 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 forstatic int process_result(u32 ia, char *result, int action, u16 id) { std::list<dns_server *>::iterator servI; std::list<request *>::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 (id == tpreq->id) { if (ia != 0 && (u32) (tpreq->targ->v4host().s_addr) != ia) continue; if (action == ACTION_CNAME_LIST || action == ACTION_FINISHED) { tpserv->capacity += CAPACITY_UP_STEP; check_capacities(tpserv); if (result) tpreq->targ->setHostName(result); tpserv->in_process.remove(tpreq); tpserv->reqs_on_wire--; total_reqs--; if (action == ACTION_CNAME_LIST) cname_reqs.push_back(tpreq); if (action == ACTION_FINISHED) delete tpreq; } else { memcpy(&tpreq->timeout, nsock_gettimeofday(), sizeof(struct timeval)); deal_with_timedout_reads(); } do_possible_writes(); // Close DNS servers if we're all done so that we kill // all events and return from nsock_loop immediatley if (total_reqs == 0) close_dns_servers(); return 1; } } } return 0;}// Gets an IP address from a X.X.X.X.in-addr.arpa DNS// encoded string inside a packet.// maxlen is the very maximum length (in total bytes)// that should be processedstatic u32 parse_inaddr_arpa(unsigned char *buf, int maxlen) { u32 ip=0; int i, j; if (maxlen <= 0) return 0; for (i=0; i<=3; i++) { if (buf[0] < 1 || buf[0] > 3) return 0; maxlen -= buf[0] + 1; if (maxlen <= 0) return 0; for (j=1; j<=buf[0]; j++) if (!isdigit(buf[j])) return 0; ip |= atoi((char *) buf+1) << (8*i); buf += buf[0] + 1; } if (maxlen < 14) return 0; // length of the following string if (strcasecmp((char *) buf, "\x07in-addr\004arpa\0")) return 0; return ntohl(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 VERIFIEDstatic int encoded_name_to_normal(unsigned 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.static int advance_past_dns_name(u8 *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] + (buf[curbuf] << 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;}// Nsock read handler. One nsock read for each DNS server exists at each// time. This function uses various helper functions as defined above.static void read_evt_handler(nsock_pool nsp, nsock_event evt, void *nothing) { u8 *buf; int buflen, curbuf=0; int i, nameloc, rdlen, atype, aclass; int errcode=0; int queries, answers; u16 packet_id; 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 = (unsigned char *) nse_readbuf(evt, &buflen); // Size of header is 12, and we must have additional data as well if (buflen <= 12) return; packet_id = buf[1] + (buf[0] << 8); // 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 the zero field is all zeros and there is no error condition. // We don't care if recursion is available or not since we might be querying // an authoritative DNS server. if (buf[3] != 0x80 && buf[3] != 0) { if ((buf[3] & 0xF) == 2) errcode = 2; else if ((buf[3] & 0xF) == 3) errcode = 3; else return; } queries = buf[5] + (buf[4] << 8); answers = buf[7] + (buf[6] << 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) { int found; // NXDomain means we're finished (doesn't exist for sure) // but SERVFAIL might just mean a server timeout found = process_result(0, NULL, errcode == 3 ? ACTION_FINISHED : ACTION_TIMEOUT, packet_id); if (errcode == 2 && found) { if (o.debugging >= TRACE_DEBUG_LEVEL) log_write(LOG_STDOUT, "mass_rdns: SERVFAIL <id = %d>\n", packet_id); stat_sf++; } else if (errcode == 3 && found) { if (o.debugging >= TRACE_DEBUG_LEVEL) log_write(LOG_STDOUT, "mass_rdns: NXDOMAIN <id = %d>\n", packet_id); output_summary(); stat_nx++; } return; } if (queries <= 0 || answers <= 0) return; curbuf = 12; // Need to safely skip past QUERY section for (i=0; i<queries; i++) { curbuf = advance_past_dns_name(buf, buflen, curbuf, &nameloc); if (curbuf == -1) return; // Make sure we have the QTYPE and QCLASS fields if (curbuf + 4 >= buflen) return; curbuf += 4; } // We're now at the ANSWER section for (i=0; i<answers; i++) { curbuf = advance_past_dns_name(buf, buflen, curbuf, &nameloc); if (curbuf == -1) return; // Make sure we have the TYPE (2), CLASS (2), TTL (4), and // RDLENGTH (2) fields if (curbuf + 10 >= buflen) return; atype = buf[curbuf+1] + (buf[curbuf+0] << 8); aclass = buf[curbuf+3] + (buf[curbuf+2] << 8); rdlen = buf[curbuf+9] + (buf[curbuf+8] << 8); curbuf += 10; if (atype == 12 && aclass == 1) { // TYPE 12 is PTR struct in_addr ia; char outbuf[512]; ia.s_addr = parse_inaddr_arpa(buf+nameloc, buflen-nameloc); if (ia.s_addr == 0) return; curbuf = advance_past_dns_name(buf, buflen, curbuf, &nameloc); if (curbuf == -1 || curbuf > buflen) return; if (encoded_name_to_normal(buf+nameloc, outbuf, sizeof(outbuf)) == -1) return; if (process_result(ia.s_addr, outbuf, ACTION_FINISHED, packet_id)) { if (o.debugging >= TRACE_DEBUG_LEVEL) log_write(LOG_STDOUT, "mass_rdns: OK MATCHED <%s> to <%s>\n", inet_ntoa(ia), outbuf); output_summary(); stat_ok++; } } else if (atype == 5 && aclass == 1) { // TYPE 5 is CNAME struct in_addr ia; ia.s_addr = parse_inaddr_arpa(buf+nameloc, buflen-nameloc); if (ia.s_addr == 0) return; if (o.debugging >= TRACE_DEBUG_LEVEL) log_write(LOG_STDOUT, "mass_rdns: CNAME found for <%s>\n", inet_ntoa(ia)); process_result(ia.s_addr, NULL, ACTION_CNAME_LIST, packet_id); } else { if (rdlen < 0 || rdlen + curbuf >= buflen) return; curbuf += rdlen; } if (curbuf >= buflen) return; }}// nsock connect handler - Empty because it doesn't really need to do anything...static 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!static void add_dns_server(char *ipaddrs) { std::list<dns_server *>::iterator servI; dns_server *tpserv; char *hostname; struct sockaddr_in addr; size_t addr_len = sizeof(addr); for (hostname = strtok(ipaddrs, " ,"); hostname != NULL; hostname = strtok(NULL, " ,")) { if (!resolve(hostname, (struct sockaddr_storage *) &addr, &addr_len, PF_INET)) continue; for(servI = servs.begin(); servI != servs.end(); servI++) { tpserv = *servI; // Already added! if (memcmp(&addr, &tpserv->addr, sizeof(addr)) == 0) break; } // If it hasn't already been added, add it! if (servI == servs.end()) { tpserv = new dns_server; tpserv->hostname = strdup(hostname); memcpy(&tpserv->addr, &addr, sizeof(addr)); servs.push_front(tpserv); if (o.debugging) log_write(LOG_STDOUT, "mass_rdns: Using DNS server %s\n", hostname); } }}void free_dns_servers() { std::list<dns_server *>::iterator servI; dns_server *tpserv; for(servI = servs.begin(); servI != servs.end();servI++){ tpserv = *servI; if(tpserv){ if(tpserv->hostname) free(tpserv->hostname); delete tpserv; } } servs.clear();}// Creates a new nsi for each DNS serverstatic void connect_dns_servers() { std::list<dns_server *>::iterator serverI; dns_server *s; for(serverI = servs.begin(); serverI != servs.end(); serverI++) { s = *serverI;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?