diff --git a/CHANGELOG b/CHANGELOG index d9e752806..09183e775 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,12 @@ # Nmap Changelog ($Id$); -*-text-*- + +o Nmap's output options (-oA, -oX, etc.) now support strftime()-like + conversions in the filename. %H, %M, %S, %T, %R, %m, %d, %y, and + %Y are all the same as in strftime(). %t is the same as %H%M%S, + %r is the same as %H%M, and %D is the same as %m%d%y. This means + that "-oX 'scan-%T-%D.xml'" uses an XML file in the form of + "scan-14:48:40-121307.xml". [Kris] + 4.50 o Bumped up the version number to the big 4.50! diff --git a/docs/refguide.xml b/docs/refguide.xml index ea9d0e5d7..e73787c68 100644 --- a/docs/refguide.xml +++ b/docs/refguide.xml @@ -2868,6 +2868,18 @@ compatibility feature of Nmap will cause the creation of G- and Xscan.xml respectively. +All of these arguments support strftime()-like +conversions in the filename. %H, %M, +%S, %T, %R, +%m, %d, %y, +and %Y are all exactly the same as in +strftime(). %t is the same as +%H%M%S, %r is the same as +%H%M, and %D is the same as +%m%d%y. So +will use an XML file in the form of +scan-14:48:40-121307.xml. + Nmap also offers options to control scan verbosity and to append to output files rather than clobbering them. All of these options are described below. diff --git a/nmap.cc b/nmap.cc index 081c2aa71..4a403dc63 100644 --- a/nmap.cc +++ b/nmap.cc @@ -472,6 +472,8 @@ int nmap_main(int argc, char *argv[]) { int num_host_exp_groups; char *machinefilename = NULL, *kiddiefilename = NULL, *normalfilename = NULL, *xmlfilename = NULL; + time_t now; + struct tm *tm; HostGroupState *hstate = NULL; char *endptr = NULL; struct scan_lists *ports = NULL; @@ -647,6 +649,9 @@ int nmap_main(int argc, char *argv[]) { win_pre_init(); #endif + now = time(NULL); + tm = localtime(&now); + /* OK, lets parse these args! */ optind = 1; /* so it can be called multiple times */ while((arg = getopt_long_only(argc,fakeargv,"6Ab:D:d::e:Ffg:hIi:M:m:nO::o:P:p:qRrS:s:T:Vv", long_options, &option_index)) != EOF) { @@ -816,23 +821,23 @@ int nmap_main(int argc, char *argv[]) { } 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) { - normalfilename = optarg; + normalfilename = logfilename(optarg, tm); } else if (strcmp(long_options[option_index].name, "oG") == 0 || strcmp(long_options[option_index].name, "oM") == 0) { - machinefilename = optarg; + machinefilename = logfilename(optarg, tm); } else if (strcmp(long_options[option_index].name, "oS") == 0) { - kiddiefilename = optarg; + kiddiefilename = logfilename(optarg, tm); } else if (strcmp(long_options[option_index].name, "oH") == 0) { fatal("HTML output is not directly supported, though Nmap includes an XSL for transforming XML output into HTML. See the man page."); } else if (strcmp(long_options[option_index].name, "oX") == 0) { - xmlfilename = optarg; + xmlfilename = logfilename(optarg, tm); } else if (strcmp(long_options[option_index].name, "oA") == 0) { char buf[MAXPATHLEN]; - Snprintf(buf, sizeof(buf), "%s.nmap", optarg); + Snprintf(buf, sizeof(buf), "%s.nmap", logfilename(optarg, tm)); normalfilename = strdup(buf); - Snprintf(buf, sizeof(buf), "%s.gnmap", optarg); + Snprintf(buf, sizeof(buf), "%s.gnmap", logfilename(optarg, tm)); machinefilename = strdup(buf); - Snprintf(buf, sizeof(buf), "%s.xml", optarg); + Snprintf(buf, sizeof(buf), "%s.xml", logfilename(optarg, tm)); xmlfilename = strdup(buf); } else if (strcmp(long_options[option_index].name, "thc") == 0) { printf("!!Greets to Van Hauser, Plasmoid, Skyper and the rest of THC!!\n"); @@ -1008,7 +1013,7 @@ int nmap_main(int argc, char *argv[]) { fatal("Unknown argument to -O."); break; case 'o': - normalfilename = optarg; + normalfilename = logfilename(optarg, tm); break; case 'P': if (*optarg == '\0' || *optarg == 'I' || *optarg == 'E') @@ -1244,10 +1249,6 @@ int nmap_main(int argc, char *argv[]) { if (!o.interactivemode) { char tbuf[128]; - struct tm *tm; - time_t now = time(NULL); - if (!(tm = localtime(&now))) - fatal("Unable to get current localtime()#!#"); // ISO 8601 date/time -- http://www.cl.cam.ac.uk/~mgk25/iso-time.html if (strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M %Z", tm) <= 0) fatal("Unable to properly format time"); diff --git a/output.cc b/output.cc index 1696cfa1b..6221edaff 100644 --- a/output.cc +++ b/output.cc @@ -830,6 +830,77 @@ char* xml_convert (const char* str) { return temp; } +char *logfilename(const char *str, struct tm *tm) +{ + char *ret, *end, *p; + char tbuf[10]; + int retlen = strlen(str) * 6 + 1; + + ret = (char *) safe_malloc(retlen); + end = ret + retlen; + + for (p = ret; *str; str++) { + if (*str == '%') { + str++; + + if (!*str) + break; + + switch (*str) { + case 'H': + strftime(tbuf, sizeof tbuf, "%H", tm); + break; + case 'M': + strftime(tbuf, sizeof tbuf, "%M", tm); + break; + case 'S': + strftime(tbuf, sizeof tbuf, "%S", tm); + break; + case 'T': + strftime(tbuf, sizeof tbuf, "%T", tm); + break; + case 't': + strftime(tbuf, sizeof tbuf, "%H%M%S", tm); + break; + case 'R': + strftime(tbuf, sizeof tbuf, "%R", tm); + break; + case 'r': + strftime(tbuf, sizeof tbuf, "%H%M", tm); + break; + case 'm': + strftime(tbuf, sizeof tbuf, "%m", tm); + break; + case 'd': + strftime(tbuf, sizeof tbuf, "%d", tm); + break; + case 'y': + strftime(tbuf, sizeof tbuf, "%y", tm); + break; + case 'Y': + strftime(tbuf, sizeof tbuf, "%Y", tm); + break; + case 'D': + strftime(tbuf, sizeof tbuf, "%m%d%y", tm); + break; + default: + *p++ = *str; + continue; + } + + assert(end - p > 1); + Strncpy(p, tbuf, end - p - 1); + p += strlen(tbuf); + } else { + *p++ = *str; + } + } + + *p = 0; + + return (char *) safe_realloc(ret, strlen(ret) + 1); +} + /* This is the workhorse of the logging functions. Usually it is called through log_write(), but it can be called directly if you are dealing with a vfprintf-style va_list. Unlike log_write, YOU diff --git a/output.h b/output.h index 772bbda44..6ec6654ad 100644 --- a/output.h +++ b/output.h @@ -138,6 +138,8 @@ void printportoutput(Target *currenths, PortList *plist); in a certain place to conform to DTD. */ void printmacinfo(Target *currenths); +char *logfilename(const char *str, struct tm *tm); + /* Write some information (printf style args) to the given log stream(s). Remember to watch out for format string bugs. */ void log_write(int logt, const char *fmt, ...)