mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
@@ -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]
|
||||
|
||||
@@ -389,6 +389,7 @@ void NmapOps::Initialize() {
|
||||
portlist = NULL;
|
||||
exclude_portlist = NULL;
|
||||
proxy_chain = NULL;
|
||||
resuming = false;
|
||||
}
|
||||
|
||||
bool NmapOps::SCTPScan() {
|
||||
|
||||
@@ -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
|
||||
|
||||
1
main.cc
1
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);
|
||||
}
|
||||
|
||||
|
||||
60
nmap.cc
60
nmap.cc
@@ -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
74
xml.cc
@@ -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, "<", 4) == 0) {
|
||||
repl = "<";
|
||||
p += 3;
|
||||
} else if (strncmp(p, ">", 4) == 0) {
|
||||
repl = ">";
|
||||
p += 3;
|
||||
} else if (strncmp(p, "&", 5) == 0) {
|
||||
repl = "&";
|
||||
p += 4;
|
||||
} else if (strncmp(p, """, 6) == 0) {
|
||||
repl = "\"";
|
||||
p += 5;
|
||||
} else if (strncmp(p, "'", 6) == 0) {
|
||||
repl = "\'";
|
||||
p += 5;
|
||||
} else if (strncmp(p, "-", 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
9
xml.h
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user