diff --git a/CHANGELOG b/CHANGELOG index 1fbed2fe6..61e4ee8c4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ # Nmap Changelog ($Id$); -*-text-*- +o [GH#316] Added scan resume from Nmap's XML output. Now you can --resume a + canceled scan from all 3 major output formats: -oN, -oG, and -oX. + [Tudor Emil Coman] + o [Ndiff][GH#591] Fix a bug where hosts with the same IP but different hostnames were shown as changing hostnames between scans. Made sort stable with regard to hostnames. [Daniel Miller] diff --git a/NmapOps.cc b/NmapOps.cc index 22dc426ab..6e9e2b686 100644 --- a/NmapOps.cc +++ b/NmapOps.cc @@ -389,6 +389,7 @@ void NmapOps::Initialize() { portlist = NULL; exclude_portlist = NULL; proxy_chain = NULL; + resuming = false; } bool NmapOps::SCTPScan() { diff --git a/NmapOps.h b/NmapOps.h index 16a94a083..c4de002a1 100644 --- a/NmapOps.h +++ b/NmapOps.h @@ -181,6 +181,7 @@ class NmapOps { /* Whether we have pcap functions (can be false on Windows). */ bool have_pcap; int debugging; + bool resuming; #define PACKET_SEND_NOPREF 1 #define PACKET_SEND_ETH_WEAK 2 diff --git a/main.cc b/main.cc index f94646364..410ff02b9 100644 --- a/main.cc +++ b/main.cc @@ -222,6 +222,7 @@ int main(int argc, char *argv[]) { if (gather_logfile_resumption_state(argv[2], &myargc, &myargv) == -1) { fatal("Cannot resume from (supposed) log file %s", argv[2]); } + o.resuming = true; return nmap_main(myargc, myargv); } diff --git a/nmap.cc b/nmap.cc index af0d51b74..0f61049e6 100644 --- a/nmap.cc +++ b/nmap.cc @@ -1855,18 +1855,48 @@ int nmap_main(int argc, char *argv[]) { fflush(stderr); timep = time(NULL); - - /* Brief info in case they forget what was scanned */ Strncpy(mytime, ctime(&timep), sizeof(mytime)); chomp(mytime); - char *xslfname = o.XSLStyleSheet(); - xml_start_document("nmaprun"); - if (xslfname) { - xml_open_pi("xml-stylesheet"); - xml_attribute("href", "%s", xslfname); - xml_attribute("type", "text/xsl"); - xml_close_pi(); + + if (!o.resuming) { + /* Brief info in case they forget what was scanned */ + char *xslfname = o.XSLStyleSheet(); + xml_start_document("nmaprun"); + if (xslfname) { + xml_open_pi("xml-stylesheet"); + xml_attribute("href", "%s", xslfname); + xml_attribute("type", "text/xsl"); + xml_close_pi(); + xml_newline(); + } + + xml_start_comment(); + xml_write_escaped(" %s %s scan initiated %s as: %s ", NMAP_NAME, NMAP_VERSION, mytime, join_quoted(argv, argc).c_str()); + xml_end_comment(); xml_newline(); + + xml_open_start_tag("nmaprun"); + xml_attribute("scanner", "nmap"); + xml_attribute("args", "%s", join_quoted(argv, argc).c_str()); + xml_attribute("start", "%lu", (unsigned long) timep); + xml_attribute("startstr", "%s", mytime); + xml_attribute("version", "%s", NMAP_VERSION); + xml_attribute("xmloutputversion", NMAP_XMLOUTPUTVERSION); + xml_close_start_tag(); + xml_newline(); + + output_xml_scaninfo_records(&ports); + + xml_open_start_tag("verbose"); + xml_attribute("level", "%d", o.verbose); + xml_close_empty_tag(); + xml_newline(); + xml_open_start_tag("debugging"); + xml_attribute("level", "%d", o.debugging); + xml_close_empty_tag(); + xml_newline(); + } else { + xml_start_tag("nmaprun", false); } std::string command; @@ -1877,37 +1907,11 @@ int nmap_main(int argc, char *argv[]) { command += argv[i]; } - xml_start_comment(); - xml_write_escaped(" %s %s scan initiated %s as: %s ", NMAP_NAME, NMAP_VERSION, mytime, join_quoted(argv, argc).c_str()); - xml_end_comment(); - xml_newline(); - log_write(LOG_NORMAL | LOG_MACHINE, "# "); log_write(LOG_NORMAL | LOG_MACHINE, "%s %s scan initiated %s as: ", NMAP_NAME, NMAP_VERSION, mytime); log_write(LOG_NORMAL | LOG_MACHINE, "%s", command.c_str()); log_write(LOG_NORMAL | LOG_MACHINE, "\n"); - xml_open_start_tag("nmaprun"); - xml_attribute("scanner", "nmap"); - xml_attribute("args", "%s", join_quoted(argv, argc).c_str()); - xml_attribute("start", "%lu", (unsigned long) timep); - xml_attribute("startstr", "%s", mytime); - xml_attribute("version", "%s", NMAP_VERSION); - xml_attribute("xmloutputversion", NMAP_XMLOUTPUTVERSION); - xml_close_start_tag(); - xml_newline(); - - output_xml_scaninfo_records(&ports); - - xml_open_start_tag("verbose"); - xml_attribute("level", "%d", o.verbose); - xml_close_empty_tag(); - xml_newline(); - xml_open_start_tag("debugging"); - xml_attribute("level", "%d", o.debugging); - xml_close_empty_tag(); - xml_newline(); - /* Before we randomize the ports scanned, lets output them to machine parseable output */ if (o.verbose) @@ -2328,13 +2332,22 @@ int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv) { if (!q || ((unsigned int) (q - p) >= sizeof(nmap_arg_buffer) - 32)) fatal("Unable to parse supposed log file %s. Perhaps the Nmap execution had not finished at least one host? In that case there is no use \"resuming\"", fname); - strncpy(nmap_arg_buffer, "nmap --append-output ", sizeof(nmap_arg_buffer)); if ((q - p) + 21 + 1 >= (int) sizeof(nmap_arg_buffer)) fatal("0verfl0w"); memcpy(nmap_arg_buffer + 21, p, q - p); nmap_arg_buffer[21 + q - p] = '\0'; + q = strstr(nmap_arg_buffer, "-->"); + if (q) { + *q = '\0'; + char *unescaped = xml_unescape(nmap_arg_buffer); + if (sizeof(nmap_arg_buffer) < strlen(unescaped) + 1) + fatal("0verfl0w"); + memcpy(nmap_arg_buffer, unescaped, strlen(unescaped) + 1); + free(unescaped); + } + if (strstr(nmap_arg_buffer, "--randomize-hosts") != NULL) { error("WARNING: You are attempting to resume a scan which used --randomize-hosts. Some hosts in the last randomized batch may be missed and others may be repeated once"); } @@ -2360,37 +2373,52 @@ int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv) { fatal("Unable to parse supposed log file %s. Sorry", fname); *q = ' '; } else { - /* OK, I guess (hope) it is a normal log then (-oN) */ + /* Let's see if it's an XML log (-oX) */ q = p; found = NULL; - while ((q = strstr(q, "\nNmap scan report for "))) - found = q = q + 22; - - /* There may be some later IPs of the form : - "Nmap scan report for florence (x.x.7.10)" (dns reverse lookup) - or "Nmap scan report for x.x.7.10". - */ + while ((q = strstr(q, "\n
n) { + n = (i + len) * 2; + result = (char *) safe_realloc(result, n + 1); + } + memcpy(result + i, repl, len); + i += len; + } + /* Trim to length. (Also does initial allocation when str is empty.) */ + result = (char *) safe_realloc(result, i + 1); + result[i] = '\0'; + + return result; +} + /* Escape a string for inclusion in XML. This gets <>&, "' for attribute values, -- for inside comments, and characters with value > 0x7F. It also gets control characters with value < 0x20 to avoid parser @@ -362,9 +424,10 @@ int xml_close_pi() { /* Open a start tag, like "