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

Add --resume from XML output. Closes #316. See #243

This commit is contained in:
dmiller
2016-12-06 02:55:55 +00:00
parent b87b0c7de0
commit b18d6fe5f7
7 changed files with 172 additions and 70 deletions

View File

@@ -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]

View File

@@ -389,6 +389,7 @@ void NmapOps::Initialize() {
portlist = NULL;
exclude_portlist = NULL;
proxy_chain = NULL;
resuming = false;
}
bool NmapOps::SCTPScan() {

View File

@@ -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

View File

@@ -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);
}

60
nmap.cc
View File

@@ -1855,10 +1855,11 @@ 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);
if (!o.resuming) {
/* Brief info in case they forget what was scanned */
char *xslfname = o.XSLStyleSheet();
xml_start_document("nmaprun");
if (xslfname) {
@@ -1869,24 +1870,11 @@ int nmap_main(int argc, char *argv[]) {
xml_newline();
}
std::string command;
if (argc > 0)
command += argv[0];
for (i = 1; i < argc; i++) {
command += " ";
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());
@@ -1907,6 +1895,22 @@ int nmap_main(int argc, char *argv[]) {
xml_attribute("level", "%d", o.debugging);
xml_close_empty_tag();
xml_newline();
} else {
xml_start_tag("nmaprun", false);
}
std::string command;
if (argc > 0)
command += argv[0];
for (i = 1; i < argc; i++) {
command += " ";
command += argv[i];
}
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");
/* Before we randomize the ports scanned, lets output them to machine
parseable output */
@@ -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");
}
@@ -2359,6 +2372,20 @@ int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv) {
if (inet_pton(AF_INET, found, &lastip) == 0)
fatal("Unable to parse supposed log file %s. Sorry", fname);
*q = ' ';
} else {
/* Let's see if it's an XML log (-oX) */
q = p;
found = NULL;
while ((q = strstr(q, "\n<address addr=\"")))
found = q = q + 16;
if (found) {
q = strchr(found, '"');
if (!q)
fatal("Unable to parse supposed log file %s. Sorry", fname);
*q = '\0';
if (inet_pton(AF_INET, found, &lastip) == 0)
fatal("Unable to parse supposed log file %s. Sorry", fname);
*q = '"';
} else {
/* OK, I guess (hope) it is a normal log then (-oN) */
q = p;
@@ -2393,6 +2420,7 @@ int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv) {
lastip.s_addr = 0;
}
}
}
o.resume_ip = lastip;
/* Ensure the log file ends with a newline */

74
xml.cc
View File

@@ -201,6 +201,68 @@ struct xml_writer {
static struct xml_writer xml;
char *xml_unescape(const char *str) {
char *result = NULL;
size_t n = 0, len;
const char *p;
int i;
i = 0;
for (p = str; *p != '\0'; p++) {
const char *repl;
char buf[32];
if (*p != '&') {
/* Based on the asumption that ampersand is only used for escaping. */
buf[0] = *p;
buf[1] = '\0';
repl = buf;
} else if (strncmp(p, "&lt;", 4) == 0) {
repl = "<";
p += 3;
} else if (strncmp(p, "&gt;", 4) == 0) {
repl = ">";
p += 3;
} else if (strncmp(p, "&amp;", 5) == 0) {
repl = "&";
p += 4;
} else if (strncmp(p, "&quot;", 6) == 0) {
repl = "\"";
p += 5;
} else if (strncmp(p, "&apos;", 6) == 0) {
repl = "\'";
p += 5;
} else if (strncmp(p, "&#45;", 5) == 0) {
repl = "-";
p += 4;
} else {
/* Escaped control characters and anything outside of ASCII. */
Strncpy(buf, p + 3, sizeof(buf));
char *q;
q = strchr(buf, ';');
if(!q)
buf[0] = '\0';
else
*q = '\0';
repl = buf;
}
len = strlen(repl);
/* Double the size of the result buffer if necessary. */
if (i == 0 || i + len > 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,8 +424,9 @@ int xml_close_pi() {
/* Open a start tag, like "<name". The tag must be later closed with
xml_close_start_tag or xml_close_empty_tag. Usually the tag is closed
after writing some attributes. */
int xml_open_start_tag(const char *name) {
int xml_open_start_tag(const char *name, const bool write) {
assert(!xml.tag_open);
if (write)
log_write(LOG_XML, "<%s", name);
xml.element_stack.push_back(name);
xml.tag_open = true;
@@ -372,8 +435,9 @@ int xml_open_start_tag(const char *name) {
return 0;
}
int xml_close_start_tag() {
int xml_close_start_tag(const bool write) {
assert(xml.tag_open);
if(write)
log_write(LOG_XML, ">");
xml.tag_open = false;
@@ -392,10 +456,10 @@ int xml_close_empty_tag() {
return 0;
}
int xml_start_tag(const char *name) {
if (xml_open_start_tag(name) < 0)
int xml_start_tag(const char *name, const bool write) {
if (xml_open_start_tag(name, write) < 0)
return -1;
if (xml_close_start_tag() < 0)
if (xml_close_start_tag(write) < 0)
return -1;
return 0;

9
xml.h
View File

@@ -137,10 +137,10 @@ int xml_end_comment();
int xml_open_pi(const char *name);
int xml_close_pi();
int xml_open_start_tag(const char *name);
int xml_close_start_tag();
int xml_open_start_tag(const char *name, const bool write = true);
int xml_close_start_tag(const bool write = true);
int xml_close_empty_tag();
int xml_start_tag(const char *name);
int xml_start_tag(const char *name, const bool write = true);
int xml_end_tag();
int xml_attribute(const char *name, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
@@ -151,5 +151,8 @@ int xml_depth();
bool xml_tag_open();
bool xml_root_written();
char *xml_unescape(const char *str);
#endif