mirror of
https://github.com/nmap/nmap.git
synced 2025-12-07 05:01:29 +00:00
Merge r17202:17298 from /nmap-exp/david/nmap-xml. This brings in
structured XML output, automatic closing of XML elements on error, and inclusion of error messages in XML output.
This commit is contained in:
@@ -91,11 +91,11 @@ NSE_OBJS+=nse_openssl.o nse_ssl_cert.o
|
||||
endif
|
||||
endif
|
||||
|
||||
export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc osscan2.cc output.cc payload.cc scan_engine.cc timing.cc charpool.cc services.cc protocols.cc nmap_rpc.cc portlist.cc NmapOps.cc TargetGroup.cc Target.cc FingerPrintResults.cc service_scan.cc NmapOutputTable.cc MACLookup.cc nmap_tty.cc nmap_dns.cc traceroute.cc portreasons.cc $(NSE_SRC) @COMPAT_SRCS@
|
||||
export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc osscan2.cc output.cc payload.cc scan_engine.cc timing.cc charpool.cc services.cc protocols.cc nmap_rpc.cc portlist.cc NmapOps.cc TargetGroup.cc Target.cc FingerPrintResults.cc service_scan.cc NmapOutputTable.cc MACLookup.cc nmap_tty.cc nmap_dns.cc traceroute.cc portreasons.cc xml.cc $(NSE_SRC) @COMPAT_SRCS@
|
||||
|
||||
export HDRS = charpool.h FingerPrintResults.h global_structures.h idle_scan.h MACLookup.h nmap_amigaos.h nmap_dns.h nmap_error.h nmap.h NmapOps.h NmapOutputTable.h nmap_rpc.h nmap_tty.h nmap_winconfig.h osscan.h osscan2.h output.h payload.h portlist.h protocols.h scan_engine.h service_scan.h services.h TargetGroup.h Target.h targets.h tcpip.h timing.h utils.h traceroute.h portreasons.h $(NSE_HDRS)
|
||||
export HDRS = charpool.h FingerPrintResults.h global_structures.h idle_scan.h MACLookup.h nmap_amigaos.h nmap_dns.h nmap_error.h nmap.h NmapOps.h NmapOutputTable.h nmap_rpc.h nmap_tty.h nmap_winconfig.h osscan.h osscan2.h output.h payload.h portlist.h protocols.h scan_engine.h service_scan.h services.h TargetGroup.h Target.h targets.h tcpip.h timing.h utils.h traceroute.h portreasons.h xml.h $(NSE_HDRS)
|
||||
|
||||
OBJS = main.o nmap.o targets.o tcpip.o nmap_error.o utils.o idle_scan.o osscan.o osscan2.o output.o payload.o scan_engine.o timing.o charpool.o services.o protocols.o nmap_rpc.o portlist.o NmapOps.o TargetGroup.o Target.o FingerPrintResults.o service_scan.o NmapOutputTable.o MACLookup.o nmap_tty.o nmap_dns.o traceroute.o portreasons.o $(NSE_OBJS) @COMPAT_OBJS@
|
||||
OBJS = main.o nmap.o targets.o tcpip.o nmap_error.o utils.o idle_scan.o osscan.o osscan2.o output.o payload.o scan_engine.o timing.o charpool.o services.o protocols.o nmap_rpc.o portlist.o NmapOps.o TargetGroup.o Target.o FingerPrintResults.o service_scan.o NmapOutputTable.o MACLookup.o nmap_tty.o nmap_dns.o traceroute.o portreasons.o xml.o $(NSE_OBJS) @COMPAT_OBJS@
|
||||
|
||||
# %.o : %.cc -- nope this is a GNU extension
|
||||
.cc.o:
|
||||
|
||||
@@ -157,7 +157,7 @@ const struct in_addr *NmapOps::v4sourceip() {
|
||||
|
||||
// Number of milliseconds since getStartTime(). The current time is an
|
||||
// optional argument to avoid an extra gettimeofday() call.
|
||||
int NmapOps::TimeSinceStartMS(struct timeval *now) {
|
||||
int NmapOps::TimeSinceStartMS(const struct timeval *now) {
|
||||
struct timeval tv;
|
||||
if (!now)
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
@@ -115,7 +115,7 @@ class NmapOps {
|
||||
const struct timeval *getStartTime() { return &start_time; }
|
||||
// Number of milliseconds since getStartTime(). The current time is an
|
||||
// optional argument to avoid an extra gettimeofday() call.
|
||||
int TimeSinceStartMS(struct timeval *now=NULL);
|
||||
int TimeSinceStartMS(const struct timeval *now=NULL);
|
||||
struct in_addr v4source();
|
||||
const struct in_addr *v4sourceip();
|
||||
|
||||
|
||||
@@ -95,10 +95,6 @@
|
||||
|
||||
#include "nmap.h"
|
||||
|
||||
#ifndef __attribute__
|
||||
#define __attribute__(args)
|
||||
#endif
|
||||
|
||||
/********************** DEFINES/ENUMS ***********************************/
|
||||
|
||||
/********************** STRUCTURES ***********************************/
|
||||
@@ -131,7 +127,7 @@ class NmapOutputTable {
|
||||
|
||||
// Like addItem except this version takes a printf-style format string followed by varargs
|
||||
void addItemFormatted(unsigned int row, unsigned int column, bool fullrow, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 4, 5)));
|
||||
__attribute__ ((format (printf, 5, 6))); // Offset by 1 to account for implicit "this" parameter.
|
||||
|
||||
// This function sticks the entire table into a character buffer.
|
||||
// Note that the buffer is likely to be reused if you call the
|
||||
|
||||
@@ -313,12 +313,15 @@
|
||||
<!ATTLIST output type (interactive) #IMPLIED>
|
||||
|
||||
<!-- these elements are generated in output.c:printfinaloutput() -->
|
||||
<!ELEMENT runstats (finished, hosts) >
|
||||
<!ELEMENT runstats (finished, hosts)>
|
||||
|
||||
<!ELEMENT finished EMPTY >
|
||||
<!ATTLIST finished time %attr_numeric; #REQUIRED
|
||||
timestr CDATA #IMPLIED
|
||||
elapsed %attr_numeric; #REQUIRED
|
||||
summary CDATA #IMPLIED
|
||||
exit (error|success) #IMPLIED
|
||||
errormsg CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT hosts EMPTY >
|
||||
|
||||
@@ -366,6 +366,10 @@
|
||||
RelativePath="..\utils.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\xml.cc"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="Windows"
|
||||
>
|
||||
@@ -559,6 +563,10 @@
|
||||
RelativePath="..\utils.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\xml.h"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="Win Headers"
|
||||
>
|
||||
|
||||
89
nmap.cc
89
nmap.cc
@@ -109,6 +109,7 @@
|
||||
#include "charpool.h"
|
||||
#include "nmap_error.h"
|
||||
#include "utils.h"
|
||||
#include "xml.h"
|
||||
|
||||
#ifndef NOLUA
|
||||
#include "nse_main.h"
|
||||
@@ -1565,39 +1566,53 @@ int nmap_main(int argc, char *argv[]) {
|
||||
Strncpy(mytime, ctime(&timep), sizeof(mytime));
|
||||
chomp(mytime);
|
||||
char *xslfname = o.XSLStyleSheet();
|
||||
char xslline[1024];
|
||||
xml_start_document();
|
||||
if (xslfname) {
|
||||
char *p = xml_convert(xslfname);
|
||||
Snprintf(xslline, sizeof(xslline), "<?xml-stylesheet href=\"%s\" type=\"text/xsl\"?>\n", p);
|
||||
free(p);
|
||||
} else xslline[0] = '\0';
|
||||
log_write(LOG_XML, "<?xml version=\"1.0\" ?>\n%s<!-- ", xslline);
|
||||
xml_open_pi("xml-stylesheet");
|
||||
xml_attribute("href", "%s", xslfname);
|
||||
xml_attribute("type", "test/xsl");
|
||||
xml_close_pi();
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
std::string command;
|
||||
if (argc > 0)
|
||||
command += fakeargv[0];
|
||||
for (i = 1; i < argc; i++) {
|
||||
command += " ";
|
||||
command += fakeargv[i];
|
||||
}
|
||||
|
||||
xml_start_comment();
|
||||
xml_write_escaped(" %s %s scan initiated %s as: %s ", NMAP_NAME, NMAP_VERSION, mytime, command.c_str());
|
||||
xml_end_comment();
|
||||
xml_newline();
|
||||
|
||||
log_write(LOG_NORMAL|LOG_MACHINE, "# ");
|
||||
log_write(LOG_NORMAL|LOG_MACHINE|LOG_XML, "%s %s scan initiated %s as: ", NMAP_NAME, NMAP_VERSION, mytime);
|
||||
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");
|
||||
|
||||
for(i=0; i < argc; i++) {
|
||||
char *p = xml_convert(fakeargv[i]);
|
||||
log_write(LOG_XML,"%s ", p);
|
||||
free(p);
|
||||
log_write(LOG_NORMAL|LOG_MACHINE,"%s ", fakeargv[i]);
|
||||
}
|
||||
log_write(LOG_XML, "-->");
|
||||
log_write(LOG_NORMAL|LOG_MACHINE|LOG_XML,"\n");
|
||||
|
||||
log_write(LOG_XML, "<nmaprun scanner=\"nmap\" args=\"");
|
||||
for(i=0; i < argc; i++) {
|
||||
char *p = xml_convert(fakeargv[i]);
|
||||
log_write(LOG_XML, (i == argc-1)? "%s\" " : "%s ", p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
log_write(LOG_XML, "start=\"%lu\" startstr=\"%s\" version=\"%s\" xmloutputversion=\"1.03\">\n",
|
||||
(unsigned long) timep, mytime, NMAP_VERSION);
|
||||
xml_open_start_tag("nmaprun");
|
||||
xml_attribute("scanner", "nmap");
|
||||
xml_attribute("args", "%s", command.c_str());
|
||||
xml_attribute("start", "%lu", (unsigned long) timep);
|
||||
xml_attribute("startstr", "%s", mytime);
|
||||
xml_attribute("version", "%s", NMAP_VERSION);
|
||||
xml_attribute("xmloutputversion", "1.03");
|
||||
xml_close_start_tag();
|
||||
xml_newline();
|
||||
|
||||
output_xml_scaninfo_records(&ports);
|
||||
|
||||
log_write(LOG_XML, "<verbose level=\"%d\" />\n<debugging level=\"%d\" />\n",
|
||||
o.verbose, o.debugging);
|
||||
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 */
|
||||
@@ -1740,13 +1755,14 @@ int nmap_main(int argc, char *argv[]) {
|
||||
#endif
|
||||
) || o.listscan) {
|
||||
/* We're done with the hosts */
|
||||
log_write(LOG_XML, "<host>");
|
||||
xml_start_tag("host");
|
||||
write_host_header(currenths);
|
||||
printmacinfo(currenths);
|
||||
// if (currenths->flags & HOST_UP)
|
||||
// log_write(LOG_PLAIN,"\n");
|
||||
printtimes(currenths);
|
||||
log_write(LOG_XML, "</host>\n");
|
||||
xml_end_tag();
|
||||
xml_newline();
|
||||
log_flush_all();
|
||||
delete currenths;
|
||||
o.numhosts_scanned++;
|
||||
@@ -1762,9 +1778,10 @@ int nmap_main(int argc, char *argv[]) {
|
||||
rare cases, such IPs CAN be port successfully scanned and even connected to */
|
||||
if (!(currenths->flags & HOST_UP)) {
|
||||
if (o.verbose && (!o.openOnly() || currenths->ports.hasOpenPorts())) {
|
||||
log_write(LOG_XML, "<host>");
|
||||
xml_start_tag("host");
|
||||
write_host_header(currenths);
|
||||
log_write(LOG_XML, "</host>\n");
|
||||
xml_end_tag();
|
||||
xml_newline();
|
||||
}
|
||||
delete currenths;
|
||||
o.numhosts_scanned++;
|
||||
@@ -1920,9 +1937,10 @@ int nmap_main(int argc, char *argv[]) {
|
||||
if (o.openOnly() && !currenths->ports.hasOpenPorts())
|
||||
continue;
|
||||
|
||||
log_write(LOG_XML, "<host starttime=\"%lu\" endtime=\"%lu\">",
|
||||
(unsigned long) currenths->StartTime(),
|
||||
(unsigned long) currenths->EndTime());
|
||||
xml_open_start_tag("host");
|
||||
xml_attribute("starttime", "%lu", (unsigned long) currenths->StartTime());
|
||||
xml_attribute("endtime", "%lu", (unsigned long) currenths->EndTime());
|
||||
xml_close_start_tag();
|
||||
write_host_header(currenths);
|
||||
printportoutput(currenths, ¤ths->ports);
|
||||
printmacinfo(currenths);
|
||||
@@ -1935,7 +1953,8 @@ int nmap_main(int argc, char *argv[]) {
|
||||
printtraceroute(currenths);
|
||||
printtimes(currenths);
|
||||
log_write(LOG_PLAIN|LOG_MACHINE,"\n");
|
||||
log_write(LOG_XML, "</host>\n");
|
||||
xml_end_tag(); /* host */
|
||||
xml_newline();
|
||||
}
|
||||
}
|
||||
log_flush_all();
|
||||
|
||||
156
nmap_error.cc
156
nmap_error.cc
@@ -92,6 +92,7 @@
|
||||
#include "nmap_error.h"
|
||||
#include "output.h"
|
||||
#include "NmapOps.h"
|
||||
#include "xml.h"
|
||||
|
||||
extern NmapOps o;
|
||||
|
||||
@@ -99,8 +100,15 @@ extern NmapOps o;
|
||||
#include <windows.h>
|
||||
#endif /* WIN32 */
|
||||
|
||||
|
||||
void fatal(const char *fmt, ...) {
|
||||
time_t timep;
|
||||
struct timeval tv;
|
||||
va_list ap;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
timep = time(NULL);
|
||||
|
||||
va_start(ap, fmt);
|
||||
log_vwrite(LOG_STDERR, fmt, ap);
|
||||
va_end(ap);
|
||||
@@ -110,6 +118,37 @@ void fatal(const char *fmt, ...) {
|
||||
va_end(ap);
|
||||
}
|
||||
log_write(o.log_errors? LOG_NORMAL|LOG_STDERR : LOG_STDERR, "\nQUITTING!\n");
|
||||
|
||||
if (!xml_root_written())
|
||||
xml_start_tag("nmaprun");
|
||||
/* Close all open XML elements but one. */
|
||||
while (xml_depth() > 1) {
|
||||
xml_end_tag();
|
||||
xml_newline();
|
||||
}
|
||||
if (xml_depth() == 1) {
|
||||
char errbuf[1024];
|
||||
|
||||
va_start(ap, fmt);
|
||||
Vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
xml_start_tag("runstats");
|
||||
print_xml_finished_open(timep, &tv);
|
||||
xml_attribute("exit", "error");
|
||||
xml_attribute("errormsg", "%s", errbuf);
|
||||
xml_close_empty_tag();
|
||||
|
||||
print_xml_hosts();
|
||||
xml_newline();
|
||||
|
||||
xml_end_tag(); /* runstats */
|
||||
xml_newline();
|
||||
|
||||
xml_end_tag(); /* nmaprun */
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -129,72 +168,93 @@ void error(const char *fmt, ...) {
|
||||
return;
|
||||
}
|
||||
|
||||
void pfatal(const char *err, ...) {
|
||||
#ifdef WIN32
|
||||
int lasterror =0;
|
||||
char *errstr = NULL;
|
||||
#endif
|
||||
void pfatal(const char *fmt, ...) {
|
||||
time_t timep;
|
||||
struct timeval tv;
|
||||
va_list ap;
|
||||
int error_number;
|
||||
char errbuf[1024], *strerror_s;
|
||||
|
||||
va_start(ap, err);
|
||||
log_vwrite(LOG_STDERR, err, ap);
|
||||
#ifdef WIN32
|
||||
error_number = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, error_number, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &strerror_s, 0, NULL);
|
||||
#else
|
||||
error_number = errno;
|
||||
strerror_s = strerror(error_number);
|
||||
#endif
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
timep = time(NULL);
|
||||
|
||||
va_start(ap, fmt);
|
||||
Vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (o.log_errors) {
|
||||
va_start(ap, err);
|
||||
log_vwrite(LOG_NORMAL, err, ap);
|
||||
va_end(ap);
|
||||
log_write(o.log_errors? LOG_NORMAL|LOG_STDERR : LOG_STDERR, "%s: %s (%d)\n",
|
||||
errbuf, strerror_s, error_number);
|
||||
|
||||
if (!xml_root_written())
|
||||
xml_start_tag("nmaprun");
|
||||
/* Close all open XML elements but one. */
|
||||
while (xml_depth() > 1) {
|
||||
xml_end_tag();
|
||||
xml_newline();
|
||||
}
|
||||
if (xml_depth() == 1) {
|
||||
xml_start_tag("runstats");
|
||||
print_xml_finished_open(timep, &tv);
|
||||
xml_attribute("exit", "error");
|
||||
xml_attribute("errormsg", "%s: %s (%d)", errbuf, strerror_s, error_number);
|
||||
xml_close_empty_tag();
|
||||
|
||||
print_xml_hosts();
|
||||
xml_newline();
|
||||
|
||||
xml_end_tag(); /* runstats */
|
||||
xml_newline();
|
||||
|
||||
xml_end_tag(); /* nmaprun */
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
lasterror = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, lasterror, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &errstr, 0, NULL);
|
||||
log_write(o.log_errors? LOG_NORMAL|LOG_STDERR : LOG_STDERR, ": %s (%d)\n",
|
||||
errstr, lasterror);
|
||||
HeapFree(GetProcessHeap(), 0, errstr);
|
||||
#else
|
||||
log_write(o.log_errors? LOG_NORMAL|LOG_STDERR : LOG_STDERR, ": %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
#endif /* WIN32 perror() compatability switch */
|
||||
HeapFree(GetProcessHeap(), 0, strerror_s);
|
||||
#endif
|
||||
|
||||
if (o.log_errors) log_flush(LOG_NORMAL);
|
||||
fflush(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* This function is the Nmap version of perror. It is just copy and
|
||||
pasted from pfatal(), except the exit has been replaced with a
|
||||
return. */
|
||||
void gh_perror(const char *err, ...) {
|
||||
#ifdef WIN32
|
||||
int lasterror =0;
|
||||
char *errstr = NULL;
|
||||
#endif
|
||||
/* This function is the Nmap version of perror. It is like pfatal, but it
|
||||
doesn't write to XML and it only returns, doesn't exit. */
|
||||
void gh_perror(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, err);
|
||||
log_vwrite(LOG_STDERR, err, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (o.log_errors) {
|
||||
va_start(ap, err);
|
||||
log_vwrite(LOG_NORMAL, err, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
int error_number;
|
||||
char *strerror_s;
|
||||
|
||||
#ifdef WIN32
|
||||
lasterror = GetLastError();
|
||||
error_number = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, lasterror, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &errstr, 0, NULL);
|
||||
log_write(o.log_errors? LOG_NORMAL|LOG_STDERR : LOG_STDERR, ": %s (%d)\n",
|
||||
errstr, lasterror);
|
||||
HeapFree(GetProcessHeap(), 0, errstr);
|
||||
NULL, error_number, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &strerror_s, 0, NULL);
|
||||
#else
|
||||
error_number = errno;
|
||||
strerror_s = strerror(error_number);
|
||||
#endif
|
||||
|
||||
va_start(ap, fmt);
|
||||
log_vwrite(o.log_errors? LOG_NORMAL|LOG_STDERR : LOG_STDERR, fmt, ap);
|
||||
va_end(ap);
|
||||
log_write(o.log_errors? LOG_NORMAL|LOG_STDERR : LOG_STDERR, ": %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
#endif /* WIN32 perror() compatability switch */
|
||||
strerror_s, error_number);
|
||||
|
||||
#ifdef WIN32
|
||||
HeapFree(GetProcessHeap(), 0, strerror_s);
|
||||
#endif
|
||||
|
||||
if (o.log_errors) log_flush(LOG_NORMAL);
|
||||
fflush(stderr);
|
||||
return;
|
||||
|
||||
597
output.cc
597
output.cc
@@ -104,6 +104,7 @@
|
||||
#include "nmap_rpc.h"
|
||||
#include "Target.h"
|
||||
#include "utils.h"
|
||||
#include "xml.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@@ -171,7 +172,7 @@ static void skid_output(char *s) {
|
||||
}
|
||||
|
||||
/* Remove all "\nSF:" from fingerprints */
|
||||
static char *xml_sf_convert(const char *str) {
|
||||
static char *servicefp_sf_remove(const char *str) {
|
||||
char *temp = (char *) safe_malloc(strlen(str) + 1);
|
||||
char *dst = temp, *src = (char *) str;
|
||||
char *ampptr = 0;
|
||||
@@ -197,106 +198,44 @@ static char *xml_sf_convert(const char *str) {
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Creates an XML <service> element for the information given in
|
||||
// Prints an XML <service> element for the information given in
|
||||
// serviceDeduction. This function should only be called if ether
|
||||
// the service name or the service fingerprint is non-null.
|
||||
// Returns a pointer to a buffer containing the element,
|
||||
// you will have to call free on it.
|
||||
static char *getServiceXMLBuf(const struct serviceDeductions *sd) {
|
||||
string versionxmlstring = "";
|
||||
char rpcbuf[128];
|
||||
char confBuf[20];
|
||||
char *xml_product = NULL, *xml_version = NULL, *xml_extrainfo = NULL;
|
||||
char *xml_hostname = NULL, *xml_ostype = NULL, *xml_devicetype = NULL;
|
||||
char *xml_servicefp = NULL, *xml_servicefp_temp = NULL;
|
||||
|
||||
versionxmlstring = "<service name=\"";
|
||||
versionxmlstring += sd->name ? sd->name : "unknown";
|
||||
versionxmlstring += "\"";
|
||||
if (sd->product) {
|
||||
xml_product = xml_convert(sd->product);
|
||||
versionxmlstring += " product=\"";
|
||||
versionxmlstring += xml_product;
|
||||
free(xml_product);
|
||||
xml_product = NULL;
|
||||
versionxmlstring += '\"';
|
||||
}
|
||||
|
||||
if (sd->version) {
|
||||
xml_version = xml_convert(sd->version);
|
||||
versionxmlstring += " version=\"";
|
||||
versionxmlstring += xml_version;
|
||||
free(xml_version);
|
||||
xml_version = NULL;
|
||||
versionxmlstring += '\"';
|
||||
}
|
||||
|
||||
if (sd->extrainfo) {
|
||||
xml_extrainfo = xml_convert(sd->extrainfo);
|
||||
versionxmlstring += " extrainfo=\"";
|
||||
versionxmlstring += xml_extrainfo;
|
||||
free(xml_extrainfo);
|
||||
xml_extrainfo = NULL;
|
||||
versionxmlstring += '\"';
|
||||
}
|
||||
|
||||
if (sd->hostname) {
|
||||
xml_hostname = xml_convert(sd->hostname);
|
||||
versionxmlstring += " hostname=\"";
|
||||
versionxmlstring += xml_hostname;
|
||||
free(xml_hostname);
|
||||
xml_hostname = NULL;
|
||||
versionxmlstring += '\"';
|
||||
}
|
||||
|
||||
if (sd->ostype) {
|
||||
xml_ostype = xml_convert(sd->ostype);
|
||||
versionxmlstring += " ostype=\"";
|
||||
versionxmlstring += xml_ostype;
|
||||
free(xml_ostype);
|
||||
xml_ostype = NULL;
|
||||
versionxmlstring += '\"';
|
||||
}
|
||||
|
||||
if (sd->devicetype) {
|
||||
xml_devicetype = xml_convert(sd->devicetype);
|
||||
versionxmlstring += " devicetype=\"";
|
||||
versionxmlstring += xml_devicetype;
|
||||
free(xml_devicetype);
|
||||
xml_devicetype = NULL;
|
||||
versionxmlstring += '\"';
|
||||
}
|
||||
static void print_xml_service(const struct serviceDeductions *sd) {
|
||||
xml_open_start_tag("service");
|
||||
|
||||
xml_attribute("name", "%s", sd->name ? sd->name : "unknown");
|
||||
if (sd->product)
|
||||
xml_attribute("product", "%s", sd->product);
|
||||
if (sd->version)
|
||||
xml_attribute("version", "%s", sd->version);
|
||||
if (sd->extrainfo)
|
||||
xml_attribute("extrainfo", "%s", sd->extrainfo);
|
||||
if (sd->hostname)
|
||||
xml_attribute("hostname", "%s", sd->hostname);
|
||||
if (sd->ostype)
|
||||
xml_attribute("ostype", "%s", sd->ostype);
|
||||
if (sd->devicetype)
|
||||
xml_attribute("devicetype", "%s", sd->devicetype);
|
||||
if (sd->service_fp) {
|
||||
xml_servicefp_temp = xml_convert(sd->service_fp);
|
||||
xml_servicefp = xml_sf_convert(xml_servicefp_temp);
|
||||
versionxmlstring += " servicefp=\"";
|
||||
versionxmlstring += xml_servicefp;
|
||||
free(xml_servicefp_temp);
|
||||
xml_servicefp_temp = NULL;
|
||||
free(xml_servicefp);
|
||||
xml_servicefp = NULL;
|
||||
versionxmlstring += '\"';
|
||||
char *servicefp = servicefp_sf_remove(sd->service_fp);
|
||||
xml_attribute("servicefp", "%s", servicefp);
|
||||
free(servicefp);
|
||||
}
|
||||
|
||||
if (sd->service_tunnel == SERVICE_TUNNEL_SSL)
|
||||
xml_attribute("tunnel", "ssl");
|
||||
xml_attribute("method", "%s", (sd->dtype == SERVICE_DETECTION_TABLE) ? "table" : "probed");
|
||||
xml_attribute("conf", "%i", sd->name_confidence);
|
||||
|
||||
if (o.rpcscan && sd->rpc_status == RPC_STATUS_GOOD_PROG) {
|
||||
Snprintf(rpcbuf, sizeof(rpcbuf),
|
||||
" rpcnum=\"%li\" lowver=\"%i\" highver=\"%i\" proto=\"rpc\"",
|
||||
sd->rpc_program, sd->rpc_lowver, sd->rpc_highver);
|
||||
} else
|
||||
rpcbuf[0] = '\0';
|
||||
xml_attribute("rpcnum", "%li", sd->rpc_program);
|
||||
xml_attribute("lowver", "%i", sd->rpc_lowver);
|
||||
xml_attribute("highver", "%i", sd->rpc_highver);
|
||||
xml_attribute("proto", "rpc");
|
||||
}
|
||||
|
||||
versionxmlstring += " ";
|
||||
versionxmlstring += (sd->service_tunnel == SERVICE_TUNNEL_SSL) ? "tunnel=\"ssl\" " : "";
|
||||
versionxmlstring += "method=\"";
|
||||
versionxmlstring += (sd->dtype == SERVICE_DETECTION_TABLE) ? "table" : "probed";
|
||||
versionxmlstring += "\" conf=\"";
|
||||
Snprintf(confBuf, 20, "%i", sd->name_confidence);
|
||||
versionxmlstring += confBuf;
|
||||
versionxmlstring += "\"";
|
||||
versionxmlstring += rpcbuf;
|
||||
versionxmlstring += " />";
|
||||
return strdup(versionxmlstring.c_str());
|
||||
xml_close_empty_tag();
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -514,7 +453,6 @@ void printportoutput(Target * currenths, PortList * plist) {
|
||||
char portinfo[64];
|
||||
char grepvers[256];
|
||||
char *p;
|
||||
char *xmlBuf = NULL;
|
||||
const char *state;
|
||||
char serviceinfo[64];
|
||||
char *name = NULL;
|
||||
@@ -542,15 +480,19 @@ void printportoutput(Target * currenths, PortList * plist) {
|
||||
if (o.noportscan)
|
||||
return;
|
||||
|
||||
log_write(LOG_XML, "<ports>");
|
||||
xml_start_tag("ports");
|
||||
int prevstate = PORT_UNKNOWN;
|
||||
int istate;
|
||||
|
||||
while ((istate = plist->nextIgnoredState(prevstate)) != PORT_UNKNOWN) {
|
||||
log_write(LOG_XML, "<extraports state=\"%s\" count=\"%d\">\n",
|
||||
statenum2str(istate), plist->getStateCounts(istate));
|
||||
xml_open_start_tag("extraports");
|
||||
xml_attribute("state", "%s", statenum2str(istate));
|
||||
xml_attribute("count", "%d", plist->getStateCounts(istate));
|
||||
xml_close_start_tag();
|
||||
xml_newline();
|
||||
print_xml_state_summary(plist, istate);
|
||||
log_write(LOG_XML, "</extraports>\n");
|
||||
xml_end_tag();
|
||||
xml_newline();
|
||||
prevstate = istate;
|
||||
}
|
||||
|
||||
@@ -583,7 +525,8 @@ void printportoutput(Target * currenths, PortList * plist) {
|
||||
|
||||
log_write(LOG_MACHINE, "Host: %s (%s)\tStatus: Up",
|
||||
currenths->targetipstr(), currenths->HostName());
|
||||
log_write(LOG_XML, "</ports>\n");
|
||||
xml_end_tag(); /* ports */
|
||||
xml_newline();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -688,19 +631,28 @@ void printportoutput(Target * currenths, PortList * plist) {
|
||||
Tbl->addItem(rowno, servicecol, true, portinfo);
|
||||
log_write(LOG_MACHINE, "%d/%s/%s/", current->portno, state,
|
||||
(proto) ? proto->p_name : "");
|
||||
log_write(LOG_XML, "<port protocol=\"ip\" portid=\"%d\">"
|
||||
"<state state=\"%s\" reason=\"%s\" reason_ttl=\"%d\"",
|
||||
current->portno, state,
|
||||
reason_str(current->reason.reason_id, SINGULAR),
|
||||
current->reason.ttl);
|
||||
|
||||
xml_open_start_tag("port");
|
||||
xml_attribute("protocol", "ip");
|
||||
xml_attribute("portid", "%d", current->portno);
|
||||
xml_close_start_tag();
|
||||
xml_open_start_tag("state");
|
||||
xml_attribute("state", "%s", state);
|
||||
xml_attribute("reason", "%s", reason_str(current->reason.reason_id, SINGULAR));
|
||||
xml_attribute("reason_ttl", "%d", current->reason.ttl);
|
||||
if (current->reason.ip_addr.s_addr)
|
||||
log_write(LOG_XML, " reason_ip=\"%s\"", inet_ntoa(current->reason.ip_addr));
|
||||
log_write(LOG_XML, "/>");
|
||||
xml_attribute("reason_ip", "%s", inet_ntoa(current->reason.ip_addr));
|
||||
xml_close_empty_tag();
|
||||
|
||||
if (proto && proto->p_name && *proto->p_name)
|
||||
log_write(LOG_XML, "\n<service name=\"%s\" conf=\"8\" method=\"table\" />", proto->p_name);
|
||||
log_write(LOG_XML, "</port>\n");
|
||||
if (proto && proto->p_name && *proto->p_name) {
|
||||
xml_newline();
|
||||
xml_open_start_tag("service");
|
||||
xml_attribute("name", "%s", proto->p_name);
|
||||
xml_attribute("conf", "8");
|
||||
xml_attribute("method", "table");
|
||||
xml_close_empty_tag();
|
||||
}
|
||||
xml_end_tag(); /* port */
|
||||
xml_newline();
|
||||
rowno++;
|
||||
}
|
||||
}
|
||||
@@ -797,23 +749,20 @@ void printportoutput(Target * currenths, PortList * plist) {
|
||||
log_write(LOG_MACHINE, "%d/%s/%s//%s/%s/%s/", current->portno,
|
||||
state, protocol, serviceinfo, rpcmachineinfo, grepvers);
|
||||
|
||||
log_write(LOG_XML, "<port protocol=\"%s\" portid=\"%d\">",
|
||||
protocol, current->portno);
|
||||
log_write(LOG_XML, "<state state=\"%s\" reason=\"%s\" reason_ttl=\"%d\"",
|
||||
state, reason_str(current->reason.reason_id, SINGULAR),
|
||||
current->reason.ttl);
|
||||
xml_open_start_tag("port");
|
||||
xml_attribute("protocol", "%s", protocol);
|
||||
xml_attribute("portid", "%d", current->portno);
|
||||
xml_close_start_tag();
|
||||
xml_open_start_tag("state");
|
||||
xml_attribute("state", "%s", state);
|
||||
xml_attribute("reason", "%s", reason_str(current->reason.reason_id, SINGULAR));
|
||||
xml_attribute("reason_ttl", "%d", current->reason.ttl);
|
||||
if (current->reason.ip_addr.s_addr)
|
||||
log_write(LOG_XML, " reason_ip=\"%s\"", inet_ntoa(current->reason.ip_addr));
|
||||
log_write(LOG_XML, "/>");
|
||||
xml_attribute("reason_ip", "%s", inet_ntoa(current->reason.ip_addr));
|
||||
xml_close_empty_tag();
|
||||
|
||||
if (sd.name || sd.service_fp) {
|
||||
xmlBuf = getServiceXMLBuf(&sd);
|
||||
if (xmlBuf) {
|
||||
log_write(LOG_XML, "%s", xmlBuf);
|
||||
free(xmlBuf);
|
||||
xmlBuf = NULL;
|
||||
}
|
||||
}
|
||||
if (sd.name || sd.service_fp)
|
||||
print_xml_service(&sd);
|
||||
|
||||
rowno++;
|
||||
#ifndef NOLUA
|
||||
@@ -822,13 +771,10 @@ void printportoutput(Target * currenths, PortList * plist) {
|
||||
|
||||
for (ssr_iter = current->scriptResults.begin();
|
||||
ssr_iter != current->scriptResults.end(); ssr_iter++) {
|
||||
char *xml_id = xml_convert(ssr_iter->get_id().c_str());
|
||||
char *xml_scriptoutput =
|
||||
xml_convert(ssr_iter->get_output().c_str());
|
||||
log_write(LOG_XML, "<script id=\"%s\" output=\"%s\" />",
|
||||
xml_id, xml_scriptoutput);
|
||||
free(xml_id);
|
||||
free(xml_scriptoutput);
|
||||
xml_open_start_tag("script");
|
||||
xml_attribute("id", "%s", ssr_iter->get_id().c_str());
|
||||
xml_attribute("output", "%s", ssr_iter->get_output().c_str());
|
||||
xml_close_empty_tag();
|
||||
|
||||
char *script_output = formatScriptOutput((*ssr_iter));
|
||||
Tbl->addItem(rowno, 0, true, true, script_output);
|
||||
@@ -839,7 +785,8 @@ void printportoutput(Target * currenths, PortList * plist) {
|
||||
}
|
||||
#endif
|
||||
|
||||
log_write(LOG_XML, "</port>\n");
|
||||
xml_end_tag(); /* port */
|
||||
xml_newline();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -852,7 +799,8 @@ void printportoutput(Target * currenths, PortList * plist) {
|
||||
log_write(LOG_MACHINE, "\tIgnored State: %s (%d)",
|
||||
statenum2str(istate), plist->getStateCounts(istate));
|
||||
}
|
||||
log_write(LOG_XML, "</ports>\n");
|
||||
xml_end_tag(); /* ports */
|
||||
xml_newline();
|
||||
|
||||
// Now we write the table for the user
|
||||
log_write(LOG_PLAIN, "%s", Tbl->printableTable(NULL));
|
||||
@@ -876,65 +824,6 @@ void printportoutput(Target * currenths, PortList * plist) {
|
||||
}
|
||||
|
||||
|
||||
/* 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 normalization of \r\n\t
|
||||
in attribute values. If this is not desired in some cases, we'll have to add
|
||||
a parameter to control this. */
|
||||
char *xml_convert(const char *str) {
|
||||
/* result is the result buffer; n + 1 is the allocated size. Double the
|
||||
allocation when space runs out. */
|
||||
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 == '<')
|
||||
repl = "<";
|
||||
else if (*p == '>')
|
||||
repl = ">";
|
||||
else if (*p == '&')
|
||||
repl = "&";
|
||||
else if (*p == '"')
|
||||
repl = """;
|
||||
else if (*p == '\'')
|
||||
repl = "'";
|
||||
else if (*p == '-' && p > str && *(p - 1) == '-') {
|
||||
/* Escape -- for comments. */
|
||||
repl = "-";
|
||||
} else if (*p < 0x20 || (unsigned char) *p > 0x7F) {
|
||||
/* Escape control characters and anything outside of ASCII. We have to
|
||||
emit UTF-8 and an easy way to do that is to emit ASCII. */
|
||||
Snprintf(buf, sizeof(buf), "&#x%x;", (unsigned char) *p);
|
||||
repl = buf;
|
||||
} else {
|
||||
/* Unescaped character. */
|
||||
buf[0] = *p;
|
||||
buf[1] = '\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;
|
||||
}
|
||||
|
||||
char *logfilename(const char *str, struct tm *tm) {
|
||||
char *ret, *end, *p;
|
||||
char tbuf[10];
|
||||
@@ -1257,28 +1146,33 @@ static void doscanflags() {
|
||||
{ TH_ECE, "ECE" },
|
||||
{ TH_CWR, "CWR" }
|
||||
};
|
||||
|
||||
if (o.scanflags != -1) {
|
||||
log_write(LOG_XML, "scanflags=\"");
|
||||
string flagstring;
|
||||
|
||||
for (unsigned int i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
|
||||
if (o.scanflags & flags[i].flag) {
|
||||
log_write(LOG_XML, "%s", flags[i].name);
|
||||
if (o.scanflags & flags[i].flag)
|
||||
flagstring += flags[i].name;
|
||||
}
|
||||
}
|
||||
log_write(LOG_XML, "\"");
|
||||
xml_attribute("scanflags", "%s", flagstring.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/* Simple helper function for output_xml_scaninfo_records */
|
||||
static void doscaninfo(const char *type, const char *proto,
|
||||
unsigned short *ports, int numports) {
|
||||
log_write(LOG_XML, "<scaninfo type=\"%s\" ", type);
|
||||
xml_open_start_tag("scaninfo");
|
||||
xml_attribute("type", "%s", type);
|
||||
if (strncmp(proto, "tcp", 3) == 0) {
|
||||
doscanflags();
|
||||
}
|
||||
log_write(LOG_XML, " protocol=\"%s\" numservices=\"%d\" services=\"",
|
||||
proto, numports);
|
||||
xml_attribute("protocol", "%s", proto);
|
||||
xml_attribute("numservices", "%d", numports);
|
||||
xml_write_raw(" services=\"");
|
||||
output_rangelist_given_ports(LOG_XML, ports, numports);
|
||||
log_write(LOG_XML, "\" />\n");
|
||||
xml_write_raw("\"");
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
/* Similar to output_ports_to_machine_parseable_output, this function
|
||||
@@ -1318,21 +1212,18 @@ void output_xml_scaninfo_records(struct scan_lists *scanlist) {
|
||||
static void print_MAC_XML_Info(Target * currenths) {
|
||||
const u8 *mac = currenths->MACAddress();
|
||||
char macascii[32];
|
||||
char vendorstr[128];
|
||||
char *xml_mac = NULL;
|
||||
|
||||
if (mac) {
|
||||
const char *macvendor = MACPrefix2Corp(mac);
|
||||
Snprintf(macascii, sizeof(macascii), "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
if (macvendor) {
|
||||
xml_mac = xml_convert(macvendor);
|
||||
Snprintf(vendorstr, sizeof(vendorstr), " vendor=\"%s\"", xml_mac);
|
||||
free(xml_mac);
|
||||
} else
|
||||
vendorstr[0] = '\0';
|
||||
log_write(LOG_XML, "<address addr=\"%s\" addrtype=\"mac\"%s />\n",
|
||||
macascii, vendorstr);
|
||||
xml_open_start_tag("address");
|
||||
xml_attribute("addr", "%s", macascii);
|
||||
xml_attribute("addrtype", "mac");
|
||||
if (macvendor)
|
||||
xml_attribute("vendor", "%s", macvendor);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1340,24 +1231,38 @@ static void print_MAC_XML_Info(Target * currenths) {
|
||||
into the XML log */
|
||||
static void write_xml_initial_hostinfo(Target *currenths,
|
||||
const char *status) {
|
||||
log_write(LOG_XML, "<status state=\"%s\" reason=\"%s\"/>\n", status,
|
||||
reason_str(currenths->reason.reason_id, SINGULAR));
|
||||
log_write(LOG_XML, "<address addr=\"%s\" addrtype=\"%s\" />\n",
|
||||
currenths->targetipstr(), (o.af() == AF_INET) ? "ipv4" : "ipv6");
|
||||
xml_open_start_tag("status");
|
||||
xml_attribute("state", "%s", status);
|
||||
xml_attribute("reason", "%s", reason_str(currenths->reason.reason_id, SINGULAR));
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
xml_open_start_tag("address");
|
||||
xml_attribute("addr", "%s", currenths->targetipstr());
|
||||
xml_attribute("addrtype", "%s", (o.af() == AF_INET) ? "ipv4" : "ipv6");
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
print_MAC_XML_Info(currenths);
|
||||
/* Output a hostnames element whenever we have a name to write or the target
|
||||
is up. */
|
||||
if (currenths->TargetName() != NULL || *currenths->HostName() || strcmp(status, "up") == 0) {
|
||||
log_write(LOG_XML, "<hostnames>\n");
|
||||
xml_start_tag("hostnames");
|
||||
xml_newline();
|
||||
if (currenths->TargetName() != NULL) {
|
||||
log_write(LOG_XML, "<hostname name=\"%s\" type=\"user\"/>\n",
|
||||
currenths->TargetName());
|
||||
xml_open_start_tag("hostname");
|
||||
xml_attribute("name", "%s", currenths->TargetName());
|
||||
xml_attribute("type", "user");
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
if (*currenths->HostName()) {
|
||||
log_write(LOG_XML, "<hostname name=\"%s\" type=\"PTR\"/>\n",
|
||||
currenths->HostName());
|
||||
xml_open_start_tag("hostname");
|
||||
xml_attribute("name", "%s", currenths->HostName());
|
||||
xml_attribute("type", "PTR");
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
log_write(LOG_XML, "</hostnames>\n");
|
||||
xml_end_tag();
|
||||
xml_newline();
|
||||
}
|
||||
log_flush_all();
|
||||
}
|
||||
@@ -1429,8 +1334,10 @@ void write_host_status(Target * currenths, int resolve_all) {
|
||||
write_xml_initial_hostinfo(currenths,
|
||||
(currenths->
|
||||
flags & HOST_UP) ? "up" : "down");
|
||||
log_write(LOG_XML, "<smurf responses=\"%d\" />\n",
|
||||
currenths->weird_responses);
|
||||
xml_open_start_tag("smurf");
|
||||
xml_attribute("responses", "%d", currenths->weird_responses);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
log_write(LOG_MACHINE, "Host: %s (%s)\tStatus: Smurf (%d responses)\n",
|
||||
currenths->targetipstr(), currenths->HostName(),
|
||||
currenths->weird_responses);
|
||||
@@ -1514,26 +1421,16 @@ static void printosclassificationoutput(const struct
|
||||
|
||||
/* Print the OS Classification results to XML output */
|
||||
for (classno = 0; classno < OSR->OSC_num_matches; classno++) {
|
||||
xml_open_start_tag("osclass");
|
||||
xml_attribute("type", "%s", OSR->OSC[classno]->Device_Type);
|
||||
xml_attribute("vendor", "%s", OSR->OSC[classno]->OS_Vendor);
|
||||
xml_attribute("osfamily", "%s", OSR->OSC[classno]->OS_Family);
|
||||
// Because the OS_Generation filed is optional
|
||||
if (OSR->OSC[classno]->OS_Generation) {
|
||||
Snprintf(tmpbuf, sizeof(tmpbuf), " osgen=\"%s\"",
|
||||
OSR->OSC[classno]->OS_Generation);
|
||||
} else {
|
||||
tmpbuf[0] = '\0';
|
||||
}
|
||||
{
|
||||
char *xml_type, *xml_vendor, *xml_class;
|
||||
xml_type = xml_convert(OSR->OSC[classno]->Device_Type);
|
||||
xml_vendor = xml_convert(OSR->OSC[classno]->OS_Vendor);
|
||||
xml_class = xml_convert(OSR->OSC[classno]->OS_Family);
|
||||
log_write(LOG_XML,
|
||||
"<osclass type=\"%s\" vendor=\"%s\" osfamily=\"%s\"%s accuracy=\"%d\" />\n",
|
||||
xml_type, xml_vendor, xml_class, tmpbuf,
|
||||
(int) (OSR->OSC_Accuracy[classno] * 100));
|
||||
free(xml_type);
|
||||
free(xml_vendor);
|
||||
free(xml_class);
|
||||
}
|
||||
if (OSR->OSC[classno]->OS_Generation)
|
||||
xml_attribute("osgen", "%s", OSR->OSC[classno]->OS_Generation);
|
||||
xml_attribute("accuracy", "%d", (int) (OSR->OSC_Accuracy[classno] * 100));
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
// Now to create the fodder for normal output
|
||||
@@ -1656,9 +1553,10 @@ static void write_merged_fpr(const FingerPrintResults * FPR,
|
||||
|
||||
/* Added code here to print fingerprint to XML file any time it would be
|
||||
printed to any other output format */
|
||||
char *xml_osfp = xml_convert(merge_fpr(FPR, currenths, isGoodFP, wrapit));
|
||||
log_write(LOG_XML, "<osfingerprint fingerprint=\"%s\" />\n", xml_osfp);
|
||||
free(xml_osfp);
|
||||
xml_open_start_tag("osfingerprint");
|
||||
xml_attribute("fingerprint", "%s", merge_fpr(FPR, currenths, isGoodFP, wrapit));
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
/* Prints the formatted OS Scan output to stdout, logfiles, etc (but only
|
||||
@@ -1677,21 +1575,30 @@ void printosscanoutput(Target * currenths) {
|
||||
return;
|
||||
FPR = currenths->FPR;
|
||||
|
||||
log_write(LOG_XML, "<os>");
|
||||
xml_start_tag("os");
|
||||
if (FPR->osscan_opentcpport > 0) {
|
||||
log_write(LOG_XML,
|
||||
"<portused state=\"open\" proto=\"tcp\" portid=\"%hu\" />\n",
|
||||
FPR->osscan_opentcpport);
|
||||
xml_open_start_tag("portused");
|
||||
xml_attribute("state", "open");
|
||||
xml_attribute("proto", "tcp");
|
||||
xml_attribute("portid", "%hu", FPR->osscan_opentcpport);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
if (FPR->osscan_closedtcpport > 0) {
|
||||
log_write(LOG_XML,
|
||||
"<portused state=\"closed\" proto=\"tcp\" portid=\"%hu\" />\n",
|
||||
FPR->osscan_closedtcpport);
|
||||
xml_open_start_tag("portused");
|
||||
xml_attribute("state", "closed");
|
||||
xml_attribute("proto", "tcp");
|
||||
xml_attribute("portid", "%hu", FPR->osscan_closedtcpport);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
if (FPR->osscan_closedudpport > 0) {
|
||||
log_write(LOG_XML,
|
||||
"<portused state=\"closed\" proto=\"udp\" portid=\"%hu\" />\n",
|
||||
FPR->osscan_closedudpport);
|
||||
xml_open_start_tag("portused");
|
||||
xml_attribute("state", "closed");
|
||||
xml_attribute("proto", "udp");
|
||||
xml_attribute("portid", "%hu", FPR->osscan_closedudpport);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
if (osscan_flag == OS_PERF_UNREL &&
|
||||
@@ -1709,12 +1616,12 @@ void printosscanoutput(Target * currenths) {
|
||||
if (FPR->num_perfect_matches > 0) {
|
||||
/* Some perfect matches. */
|
||||
for (i = 0; FPR->accuracy[i] == 1; i++) {
|
||||
char *p;
|
||||
log_write(LOG_XML,
|
||||
"<osmatch name=\"%s\" accuracy=\"100\" line=\"%d\" />\n",
|
||||
p = xml_convert(FPR->prints[i]->OS_name),
|
||||
FPR->prints[i]->line);
|
||||
free(p);
|
||||
xml_open_start_tag("osmatch");
|
||||
xml_attribute("name", "%s", FPR->prints[i]->OS_name);
|
||||
xml_attribute("accuracy", "100");
|
||||
xml_attribute("line", "%d", FPR->prints[i]->line);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
log_write(LOG_MACHINE, "\tOS: %s", FPR->prints[0]->OS_name);
|
||||
@@ -1737,12 +1644,12 @@ void printosscanoutput(Target * currenths) {
|
||||
if ((o.osscan_guess || reason) && FPR->num_matches > 0) {
|
||||
/* Print the best guesses available */
|
||||
for (i = 0; i < 10 && i < FPR->num_matches && FPR->accuracy[i] > FPR->accuracy[0] - 0.10; i++) {
|
||||
char *p;
|
||||
log_write(LOG_XML,
|
||||
"<osmatch name=\"%s\" accuracy=\"%d\" line=\"%d\"/>\n",
|
||||
p = xml_convert(FPR->prints[i]->OS_name),
|
||||
(int) (FPR->accuracy[i] * 100), FPR->prints[i]->line);
|
||||
free(p);
|
||||
xml_open_start_tag("osmatch");
|
||||
xml_attribute("name", "%s", FPR->prints[i]->OS_name);
|
||||
xml_attribute("accuracy", "%d", (int) (FPR->accuracy[i] * 100));
|
||||
xml_attribute("line", "%d", FPR->prints[i]->line);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
log_write(LOG_PLAIN, "Aggressive OS guesses: %s (%.f%%)",
|
||||
@@ -1789,7 +1696,8 @@ void printosscanoutput(Target * currenths) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
log_write(LOG_XML, "</os>\n");
|
||||
xml_end_tag(); /* os */
|
||||
xml_newline();
|
||||
|
||||
if (currenths->seq.lastboot) {
|
||||
char tmbuf[128];
|
||||
@@ -1803,14 +1711,20 @@ void printosscanoutput(Target * currenths) {
|
||||
log_write(LOG_PLAIN, "Uptime guess: %.3f days (since %s)\n",
|
||||
(double) (tv.tv_sec - currenths->seq.lastboot) / 86400,
|
||||
tmbuf);
|
||||
log_write(LOG_XML, "<uptime seconds=\"%li\" lastboot=\"%s\" />\n",
|
||||
tv.tv_sec - currenths->seq.lastboot, tmbuf);
|
||||
xml_open_start_tag("uptime");
|
||||
xml_attribute("seconds", "%li", tv.tv_sec - currenths->seq.lastboot);
|
||||
xml_attribute("lastboot", "%s", tmbuf);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
if (currenths->distance != -1) {
|
||||
log_write(LOG_PLAIN, "Network Distance: %d hop%s\n",
|
||||
currenths->distance, (currenths->distance == 1) ? "" : "s");
|
||||
log_write(LOG_XML, "<distance value=\"%d\" />\n", currenths->distance);
|
||||
xml_open_start_tag("distance");
|
||||
xml_attribute("value", "%d", currenths->distance);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
if (currenths->seq.responses > 3) {
|
||||
@@ -1825,10 +1739,12 @@ void printosscanoutput(Target * currenths) {
|
||||
p++;
|
||||
}
|
||||
|
||||
log_write(LOG_XML,
|
||||
"<tcpsequence index=\"%li\" difficulty=\"%s\" values=\"%s\" />\n",
|
||||
(long) currenths->seq.index,
|
||||
seqidx2difficultystr(currenths->seq.index), numlst);
|
||||
xml_open_start_tag("tcpsequence");
|
||||
xml_attribute("index", "%li", (long) currenths->seq.index);
|
||||
xml_attribute("difficulty", "%s", seqidx2difficultystr(currenths->seq.index));
|
||||
xml_attribute("values", "%s", numlst);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
if (o.verbose)
|
||||
log_write(LOG_PLAIN, "%s", seqreport(&(currenths->seq)));
|
||||
|
||||
@@ -1846,8 +1762,11 @@ void printosscanoutput(Target * currenths) {
|
||||
while (*p)
|
||||
p++;
|
||||
}
|
||||
log_write(LOG_XML, "<ipidsequence class=\"%s\" values=\"%s\" />\n",
|
||||
ipidclass2ascii(currenths->seq.ipid_seqclass), numlst);
|
||||
xml_open_start_tag("ipidsequence");
|
||||
xml_attribute("class", "%s", ipidclass2ascii(currenths->seq.ipid_seqclass));
|
||||
xml_attribute("values", "%s", numlst);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
if (o.verbose)
|
||||
log_write(LOG_PLAIN, "IP ID Sequence Generation: %s\n",
|
||||
ipidclass2ascii(currenths->seq.ipid_seqclass));
|
||||
@@ -1865,12 +1784,13 @@ void printosscanoutput(Target * currenths) {
|
||||
p++;
|
||||
}
|
||||
|
||||
log_write(LOG_XML, "<tcptssequence class=\"%s\"",
|
||||
tsseqclass2ascii(currenths->seq.ts_seqclass));
|
||||
xml_open_start_tag("tcptssequence");
|
||||
xml_attribute("class", "%s", tsseqclass2ascii(currenths->seq.ts_seqclass));
|
||||
if (currenths->seq.ts_seqclass != TS_SEQ_UNSUPPORTED) {
|
||||
log_write(LOG_XML, " values=\"%s\"", numlst);
|
||||
xml_attribute("values", "%s", numlst);
|
||||
}
|
||||
log_write(LOG_XML, " />\n");
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
log_flush_all();
|
||||
}
|
||||
@@ -1986,25 +1906,23 @@ void printserviceinfooutput(Target * currenths) {
|
||||
#ifndef NOLUA
|
||||
void printhostscriptresults(Target * currenths) {
|
||||
ScriptResults::iterator iter;
|
||||
char *script_output, *xml_id, *xml_scriptoutput;
|
||||
char *script_output;
|
||||
|
||||
if (currenths->scriptResults.size() > 0) {
|
||||
log_write(LOG_XML, "<hostscript>");
|
||||
xml_start_tag("hostscript");
|
||||
log_write(LOG_PLAIN, "\nHost script results:\n");
|
||||
for (iter = currenths->scriptResults.begin();
|
||||
iter != currenths->scriptResults.end();
|
||||
iter++) {
|
||||
xml_id = xml_convert(iter->get_id().c_str());
|
||||
xml_scriptoutput = xml_convert(iter->get_output().c_str());
|
||||
log_write(LOG_XML, "<script id=\"%s\" output=\"%s\" />",
|
||||
xml_id, xml_scriptoutput);
|
||||
xml_open_start_tag("script");
|
||||
xml_attribute("id", "%s", iter->get_id().c_str());
|
||||
xml_attribute("output", "%s", iter->get_output().c_str());
|
||||
xml_close_empty_tag();
|
||||
script_output = formatScriptOutput((*iter));
|
||||
log_write(LOG_PLAIN, "%s\n", script_output);
|
||||
free(script_output);
|
||||
free(xml_id);
|
||||
free(xml_scriptoutput);
|
||||
}
|
||||
log_write(LOG_XML, "</hostscript>");
|
||||
xml_end_tag();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -2126,44 +2044,49 @@ static void printtraceroute_xml(Target * currenths) {
|
||||
return;
|
||||
|
||||
/* XML traceroute header */
|
||||
log_write(LOG_XML, "<trace ");
|
||||
xml_open_start_tag("trace");
|
||||
|
||||
probe = currenths->traceroute_probespec;
|
||||
if (probe.type == PS_TCP) {
|
||||
log_write(LOG_XML, "port=\"%d\" proto=\"%s\"",
|
||||
probe.pd.tcp.dport, proto2ascii(probe.proto));
|
||||
xml_attribute("port", "%d", probe.pd.tcp.dport);
|
||||
xml_attribute("proto", "%s", proto2ascii(probe.proto));
|
||||
} else if (probe.type == PS_UDP) {
|
||||
log_write(LOG_XML, "port=\"%d\" proto=\"%s\"",
|
||||
probe.pd.udp.dport, proto2ascii(probe.proto));
|
||||
xml_attribute("port", "%d", probe.pd.udp.dport);
|
||||
xml_attribute("proto", "%s", proto2ascii(probe.proto));
|
||||
} else if (probe.type == PS_SCTP) {
|
||||
log_write(LOG_XML, "port=\"%d\" proto=\"%s\"",
|
||||
probe.pd.sctp.dport, proto2ascii(probe.proto));
|
||||
xml_attribute("port", "%d", probe.pd.sctp.dport);
|
||||
xml_attribute("proto", "%s", proto2ascii(probe.proto));
|
||||
} else if (probe.type == PS_ICMP || probe.type == PS_PROTO) {
|
||||
struct protoent *proto = nmap_getprotbynum(htons(probe.proto));
|
||||
if (proto == NULL)
|
||||
log_write(LOG_XML, "proto=\"%d\"", probe.proto);
|
||||
xml_attribute("proto", "%d", probe.proto);
|
||||
else
|
||||
log_write(LOG_XML, "proto=\"%s\"", proto->p_name);
|
||||
xml_attribute("proto", "%s", proto->p_name);
|
||||
}
|
||||
log_write(LOG_XML, ">\n");
|
||||
xml_close_start_tag();
|
||||
xml_newline();
|
||||
|
||||
for (it = currenths->traceroute_hops.begin();
|
||||
it != currenths->traceroute_hops.end();
|
||||
it++) {
|
||||
if (it->timedout)
|
||||
continue;
|
||||
log_write(LOG_XML, "<hop ttl=\"%d\" ipaddr=\"%s\"",
|
||||
it->ttl, inet_ntop_ez(&it->addr, sizeof(it->addr)));
|
||||
xml_open_start_tag("hop");
|
||||
xml_attribute("ttl", "%d", it->ttl);
|
||||
xml_attribute("ipaddr", "%s", inet_ntop_ez(&it->addr, sizeof(it->addr)));
|
||||
if (it->rtt < 0)
|
||||
log_write(LOG_XML, " rtt=\"--\"");
|
||||
xml_attribute("rtt", "--");
|
||||
else
|
||||
log_write(LOG_XML, " rtt=\"%.2f\"", it->rtt);
|
||||
xml_attribute("rtt", "%.2f", it->rtt);
|
||||
if (!it->name.empty())
|
||||
log_write(LOG_XML, " host=\"%s\"", it->name.c_str());
|
||||
log_write(LOG_XML, "/>\n");
|
||||
xml_attribute("host", "%s", it->name.c_str());
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
/* traceroute XML footer */
|
||||
log_write(LOG_XML, "</trace>\n");
|
||||
xml_end_tag();
|
||||
xml_newline();
|
||||
log_flush(LOG_XML);
|
||||
}
|
||||
|
||||
@@ -2178,8 +2101,12 @@ void printtimes(Target *currenths) {
|
||||
log_write(LOG_STDOUT, "Final times for host: srtt: %d rttvar: %d to: %d\n",
|
||||
currenths->to.srtt, currenths->to.rttvar, currenths->to.timeout);
|
||||
}
|
||||
log_write(LOG_XML, "<times srtt=\"%d\" rttvar=\"%d\" to=\"%d\" />\n",
|
||||
currenths->to.srtt, currenths->to.rttvar, currenths->to.timeout);
|
||||
xml_open_start_tag("times");
|
||||
xml_attribute("srtt", "%d", currenths->to.srtt);
|
||||
xml_attribute("rttvar", "%d", currenths->to.rttvar);
|
||||
xml_attribute("to", "%d", currenths->to.timeout);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2196,6 +2123,34 @@ void printStatusMessage() {
|
||||
scantype2str(o.current_scantype));
|
||||
}
|
||||
|
||||
/* Prints the beginning of a "finished" start tag, with time, timestr, and
|
||||
elapsed attributes. Leaves the start tag open so you can add more attributes.
|
||||
You have to close the tag with xml_close_empty_tag. */
|
||||
void print_xml_finished_open(time_t timep, const struct timeval *tv) {
|
||||
char mytime[128];
|
||||
|
||||
Strncpy(mytime, ctime(&timep), sizeof(mytime));
|
||||
chomp(mytime);
|
||||
|
||||
xml_open_start_tag("finished");
|
||||
xml_attribute("time", "%lu", (unsigned long) timep);
|
||||
xml_attribute("timestr", "%s", mytime);
|
||||
xml_attribute("elapsed", "%.2f", o.TimeSinceStartMS(tv) / 1000.0);
|
||||
xml_attribute("summary",
|
||||
"Nmap done at %s; %d %s (%d %s up) scanned in %.2f seconds",
|
||||
mytime, o.numhosts_scanned,
|
||||
(o.numhosts_scanned == 1) ? "IP address" : "IP addresses",
|
||||
o.numhosts_up, (o.numhosts_up == 1) ? "host" : "hosts",
|
||||
o.TimeSinceStartMS(tv) / 1000.0);
|
||||
}
|
||||
|
||||
void print_xml_hosts() {
|
||||
xml_open_start_tag("hosts");
|
||||
xml_attribute("up", "%d", o.numhosts_up);
|
||||
xml_attribute("down", "%d", o.numhosts_scanned - o.numhosts_up);
|
||||
xml_attribute("total", "%d", o.numhosts_scanned);
|
||||
xml_close_empty_tag();
|
||||
}
|
||||
|
||||
/* Prints the statistics and other information that goes at the very end
|
||||
of an Nmap run */
|
||||
@@ -2239,18 +2194,15 @@ void printfinaloutput() {
|
||||
Strncpy(mytime, ctime(&timep), sizeof(mytime));
|
||||
chomp(mytime);
|
||||
|
||||
log_write(LOG_XML,
|
||||
"<runstats><finished time=\"%lu\" timestr=\"%s\" elapsed=\"%.2f\"/><hosts up=\"%d\" down=\"%d\" total=\"%d\" />\n",
|
||||
(unsigned long) timep, mytime,
|
||||
o.TimeSinceStartMS(&tv) / 1000.0, o.numhosts_up,
|
||||
o.numhosts_scanned - o.numhosts_up, o.numhosts_scanned);
|
||||
xml_start_tag("runstats");
|
||||
print_xml_finished_open(timep, &tv);
|
||||
xml_attribute("exit", "success");
|
||||
xml_close_empty_tag();
|
||||
print_xml_hosts();
|
||||
xml_newline();
|
||||
xml_end_tag();
|
||||
xml_newline();
|
||||
|
||||
log_write(LOG_XML,
|
||||
"<!-- Nmap done at %s; %d %s (%d %s up) scanned in %.2f seconds -->\n",
|
||||
mytime, o.numhosts_scanned,
|
||||
(o.numhosts_scanned == 1) ? "IP address" : "IP addresses",
|
||||
o.numhosts_up, (o.numhosts_up == 1) ? "host" : "hosts",
|
||||
o.TimeSinceStartMS(&tv) / 1000.0);
|
||||
log_write(LOG_NORMAL | LOG_MACHINE,
|
||||
"# Nmap done at %s -- %d %s (%d %s up) scanned in %.2f seconds\n",
|
||||
mytime, o.numhosts_scanned,
|
||||
@@ -2258,7 +2210,8 @@ void printfinaloutput() {
|
||||
o.numhosts_up, (o.numhosts_up == 1) ? "host" : "hosts",
|
||||
o.TimeSinceStartMS(&tv) / 1000.0);
|
||||
|
||||
log_write(LOG_XML, "</runstats></nmaprun>\n");
|
||||
xml_end_tag(); /* nmaprun */
|
||||
xml_newline();
|
||||
log_flush_all();
|
||||
}
|
||||
|
||||
|
||||
5
output.h
5
output.h
@@ -211,6 +211,10 @@ int print_iflist(void);
|
||||
/* Prints a status message while the program is running */
|
||||
void printStatusMessage();
|
||||
|
||||
void print_xml_finished_open(time_t timep, const struct timeval *tv);
|
||||
|
||||
void print_xml_hosts();
|
||||
|
||||
/* Prints the statistics and other information that goes at the very end
|
||||
of an Nmap run */
|
||||
void printfinaloutput();
|
||||
@@ -219,5 +223,4 @@ void printfinaloutput();
|
||||
were found. */
|
||||
void printdatafilepaths();
|
||||
|
||||
char* xml_convert (const char* str);
|
||||
#endif /* OUTPUT_H */
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
#include "NmapOps.h"
|
||||
#include "portreasons.h"
|
||||
#include "Target.h"
|
||||
#include "xml.h"
|
||||
#ifdef WIN32
|
||||
#include "winfix.h"
|
||||
#endif
|
||||
@@ -345,9 +346,13 @@ void print_xml_state_summary(PortList *Ports, int state) {
|
||||
return;
|
||||
|
||||
while(currentr != NULL) {
|
||||
if(currentr->count > 0)
|
||||
log_write(LOG_XML, "<extrareasons reason=\"%s\" count=\"%d\"/>\n",
|
||||
reason_str(currentr->reason_id, currentr->count), currentr->count);
|
||||
if(currentr->count > 0) {
|
||||
xml_open_start_tag("extrareasons");
|
||||
xml_attribute("reason", "%s", reason_str(currentr->reason_id, currentr->count));
|
||||
xml_attribute("count", "%d", currentr->count);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
currentr = currentr->next;
|
||||
}
|
||||
state_reason_summary_dinit(reason_head);
|
||||
|
||||
30
timing.cc
30
timing.cc
@@ -95,6 +95,7 @@
|
||||
#include "timing.h"
|
||||
#include "NmapOps.h"
|
||||
#include "utils.h"
|
||||
#include "xml.h"
|
||||
|
||||
extern NmapOps o;
|
||||
|
||||
@@ -590,9 +591,14 @@ bool ScanProgressMeter::printStats(double perc_done,
|
||||
floor(time_left_s / 60.0 / 60.0),
|
||||
floor(fmod(time_left_s / 60.0, 60.0)),
|
||||
floor(fmod(time_left_s, 60.0)));
|
||||
log_write(LOG_XML, "<taskprogress task=\"%s\" time=\"%lu\" percent=\"%.2f\" remaining=\"%.f\" etc=\"%lu\" />\n",
|
||||
scantypestr, (unsigned long) now->tv_sec,
|
||||
perc_done * 100, time_left_s, (unsigned long) last_est.tv_sec);
|
||||
xml_open_start_tag("taskprogress");
|
||||
xml_attribute("task", "%s", scantypestr);
|
||||
xml_attribute("time", "%lu", (unsigned long) now->tv_sec);
|
||||
xml_attribute("percent", "%.2f", perc_done * 100);
|
||||
xml_attribute("remaining", "%.f", time_left_s);
|
||||
xml_attribute("etc", "%lu", (unsigned long) last_est.tv_sec);
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
log_flush(LOG_STDOUT|LOG_XML);
|
||||
|
||||
return true;
|
||||
@@ -620,22 +626,28 @@ bool ScanProgressMeter::beginOrEndTask(const struct timeval *now, const char *ad
|
||||
tm = localtime(&tv_sec);
|
||||
if (beginning) {
|
||||
log_write(LOG_STDOUT, "Initiating %s at %02d:%02d", scantypestr, tm->tm_hour, tm->tm_min);
|
||||
log_write(LOG_XML, "<taskbegin task=\"%s\" time=\"%lu\"", scantypestr, (unsigned long) now->tv_sec);
|
||||
xml_open_start_tag("taskbegin");
|
||||
xml_attribute("task", "%s", scantypestr);
|
||||
xml_attribute("time", "%lu", (unsigned long) now->tv_sec);
|
||||
if (additional_info) {
|
||||
log_write(LOG_STDOUT, " (%s)", additional_info);
|
||||
log_write(LOG_XML, " extrainfo=\"%s\"", additional_info);
|
||||
xml_attribute("extrainfo", "%s", additional_info);
|
||||
}
|
||||
log_write(LOG_STDOUT, "\n");
|
||||
log_write(LOG_XML, " />\n");
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
} else {
|
||||
log_write(LOG_STDOUT, "Completed %s at %02d:%02d, %.2fs elapsed", scantypestr, tm->tm_hour, tm->tm_min, TIMEVAL_MSEC_SUBTRACT(*now, begin) / 1000.0);
|
||||
log_write(LOG_XML, "<taskend task=\"%s\" time=\"%lu\"", scantypestr, (unsigned long) now->tv_sec);
|
||||
xml_open_start_tag("taskend");
|
||||
xml_attribute("task", "%s", scantypestr);
|
||||
xml_attribute("time", "%lu", (unsigned long) now->tv_sec);
|
||||
if (additional_info) {
|
||||
log_write(LOG_STDOUT, " (%s)", additional_info);
|
||||
log_write(LOG_XML, " extrainfo=\"%s\"", additional_info);
|
||||
xml_attribute("extrainfo", "%s", additional_info);
|
||||
}
|
||||
log_write(LOG_STDOUT, "\n");
|
||||
log_write(LOG_XML, " />\n");
|
||||
xml_close_empty_tag();
|
||||
xml_newline();
|
||||
}
|
||||
log_flush(LOG_STDOUT|LOG_XML);
|
||||
return true;
|
||||
|
||||
449
xml.cc
Normal file
449
xml.cc
Normal file
@@ -0,0 +1,449 @@
|
||||
/***************************************************************************
|
||||
* xml.cc -- Simple library to emit XML. *
|
||||
***********************IMPORTANT NMAP LICENSE TERMS************************
|
||||
* *
|
||||
* The Nmap Security Scanner is (C) 1996-2009 Insecure.Com LLC. Nmap is *
|
||||
* also a registered trademark of Insecure.Com LLC. This program is free *
|
||||
* software; you may redistribute and/or modify it under the terms of the *
|
||||
* GNU General Public License as published by the Free Software *
|
||||
* Foundation; Version 2 with the clarifications and exceptions described *
|
||||
* below. This guarantees your right to use, modify, and redistribute *
|
||||
* this software under certain conditions. If you wish to embed Nmap *
|
||||
* technology into proprietary software, we sell alternative licenses *
|
||||
* (contact sales@insecure.com). Dozens of software vendors already *
|
||||
* license Nmap technology such as host discovery, port scanning, OS *
|
||||
* detection, and version detection. *
|
||||
* *
|
||||
* Note that the GPL places important restrictions on "derived works", yet *
|
||||
* it does not provide a detailed definition of that term. To avoid *
|
||||
* misunderstandings, we consider an application to constitute a *
|
||||
* "derivative work" for the purpose of this license if it does any of the *
|
||||
* following: *
|
||||
* o Integrates source code from Nmap *
|
||||
* o Reads or includes Nmap copyrighted data files, such as *
|
||||
* nmap-os-db or nmap-service-probes. *
|
||||
* o Executes Nmap and parses the results (as opposed to typical shell or *
|
||||
* execution-menu apps, which simply display raw Nmap output and so are *
|
||||
* not derivative works.) *
|
||||
* o Integrates/includes/aggregates Nmap into a proprietary executable *
|
||||
* installer, such as those produced by InstallShield. *
|
||||
* o Links to a library or executes a program that does any of the above *
|
||||
* *
|
||||
* The term "Nmap" should be taken to also include any portions or derived *
|
||||
* works of Nmap. This list is not exclusive, but is meant to clarify our *
|
||||
* interpretation of derived works with some common examples. Our *
|
||||
* interpretation applies only to Nmap--we don't speak for other people's *
|
||||
* GPL works. *
|
||||
* *
|
||||
* If you have any questions about the GPL licensing restrictions on using *
|
||||
* Nmap in non-GPL works, we would be happy to help. As mentioned above, *
|
||||
* we also offer alternative license to integrate Nmap into proprietary *
|
||||
* applications and appliances. These contracts have been sold to dozens *
|
||||
* of software vendors, and generally include a perpetual license as well *
|
||||
* as providing for priority support and updates as well as helping to *
|
||||
* fund the continued development of Nmap technology. Please email *
|
||||
* sales@insecure.com for further information. *
|
||||
* *
|
||||
* As a special exception to the GPL terms, Insecure.Com LLC grants *
|
||||
* permission to link the code of this program with any version of the *
|
||||
* OpenSSL library which is distributed under a license identical to that *
|
||||
* listed in the included COPYING.OpenSSL file, and distribute linked *
|
||||
* combinations including the two. You must obey the GNU GPL in all *
|
||||
* respects for all of the code used other than OpenSSL. If you modify *
|
||||
* this file, you may extend this exception to your version of the file, *
|
||||
* but you are not obligated to do so. *
|
||||
* *
|
||||
* If you received these files with a written license agreement or *
|
||||
* contract stating terms other than the terms above, then that *
|
||||
* alternative license agreement takes precedence over these comments. *
|
||||
* *
|
||||
* Source is provided to this software because we believe users have a *
|
||||
* right to know exactly what a program is going to do before they run it. *
|
||||
* This also allows you to audit the software for security holes (none *
|
||||
* have been found so far). *
|
||||
* *
|
||||
* Source code also allows you to port Nmap to new platforms, fix bugs, *
|
||||
* and add new features. You are highly encouraged to send your changes *
|
||||
* to nmap-dev@insecure.org for possible incorporation into the main *
|
||||
* distribution. By sending these changes to Fyodor or one of the *
|
||||
* Insecure.Org development mailing lists, it is assumed that you are *
|
||||
* offering the Nmap Project (Insecure.Com LLC) the unlimited, *
|
||||
* non-exclusive right to reuse, modify, and relicense the code. Nmap *
|
||||
* will always be available Open Source, but this is important because the *
|
||||
* inability to relicense code has caused devastating problems for other *
|
||||
* Free Software projects (such as KDE and NASM). We also occasionally *
|
||||
* relicense the code to third parties as discussed above. If you wish to *
|
||||
* specify special license conditions of your contributions, just say so *
|
||||
* when you send them. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* General Public License v2.0 for more details at *
|
||||
* http://www.gnu.org/licenses/gpl-2.0.html , or in the COPYING file *
|
||||
* included with Nmap. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/* $Id: xml.cc 15135 2009-08-19 21:05:21Z david $ */
|
||||
|
||||
/*
|
||||
This is a simple library for writing XML. It handles two main things:
|
||||
keeping track of the element stack, and escaping text where necessary.
|
||||
Here is an example of writing
|
||||
<?xml version="1.0"?>
|
||||
<elem name="&10.5"></elem>
|
||||
Each function call is followed by the text it prints enclosed in ||.
|
||||
|
||||
xml_start_document() |<?xml version="1.0"?>
|
||||
xml_newline(); |\n|
|
||||
xml_open_start_tag("elem"); |<elem|
|
||||
xml_attribute("name", "&%.1f", 10.5); | name="&10.5"|
|
||||
xml_close_start_tag(); |>|
|
||||
xml_end_tag(); |</elem>|
|
||||
|
||||
The typical use is to call xml_open_start_tag, then call xml_attribute a
|
||||
number of times. That is followed by xml_close_empty_tag, or else
|
||||
xml_close_start_tag followed by xml_end_tag later one. You can call
|
||||
xml_start_tag if there are no attributes. Whenever a start tag is opened
|
||||
with xml_open_start_tag or xml_start_tag, the element name is pushed on
|
||||
the tag stack. xml_end_tag pops the element stack and closes the element
|
||||
it finds.
|
||||
|
||||
Here is a summary of all the elementary writing functions. The functions
|
||||
return 0 on success and -1 on error. The terms "start" and "end" refer
|
||||
to start and end tags and the start and end of comments. The terms
|
||||
"open" and "close" refer only to start tags and processing instructions.
|
||||
|
||||
xml_start_comment() |<!--|
|
||||
xml_end_comment() |-->|
|
||||
xml_open_pi("elem") |<?elem|
|
||||
xml_close_pi() |?>|
|
||||
xml_open_start_tag("elem") |<elem|
|
||||
xml_close_start_tag() |>|
|
||||
xml_close_empty_tag() |/>|
|
||||
xml_start_tag("elem") |<elem>|
|
||||
xml_end_tag() |</elem>|
|
||||
xml_attribute("name", "val") | name="val"|
|
||||
xml_newline() |\n|
|
||||
|
||||
Additional functions are
|
||||
|
||||
xml_write_raw Raw unescaped output.
|
||||
xml_write_escaped XML-escaped output.
|
||||
xml_write_escaped_v XML_escaped output, with a va_list.
|
||||
xml_start_document Writes <?xml version="1.0"?>.
|
||||
xml_depth Returns the size of the element stack.
|
||||
|
||||
The library makes it harder but not impossible to make non-well-formed
|
||||
XML. For example, you can call xml_start_tag, xml_end_tag,
|
||||
xml_start_tag, xml_end_tag to create a document with two root elements.
|
||||
Things like element names aren't checked to be sure they're legal. Text
|
||||
given to these functions should be ASCII or UTF-8.
|
||||
|
||||
All writing is done with log_write(LOG_XML), so if LOG_XML hasn't been
|
||||
opened, calling these functions has no effect.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <list>
|
||||
|
||||
#include "output.h"
|
||||
#include "xml.h"
|
||||
|
||||
struct xml_writer {
|
||||
/* Sanity checking: Don't open a new tag while still defining
|
||||
attributes for another, like "<elem1<elem2". */
|
||||
bool tag_open;
|
||||
/* Has the root element been started yet? If so, and if
|
||||
element_stack.size() == 0, then the document is finished. */
|
||||
bool root_written;
|
||||
std::list<const char *> element_stack;
|
||||
};
|
||||
|
||||
static struct xml_writer xml;
|
||||
|
||||
static char *alloc_vsprintf(const char *fmt, va_list va) __attribute__ ((format (printf, 1, 0)));
|
||||
|
||||
/* vsprintf into a dynamically allocated buffer, similar to asprintf in
|
||||
Glibc. Return the buffer or NULL on error. */
|
||||
static char *alloc_vsprintf(const char *fmt, va_list va) {
|
||||
va_list va_tmp;
|
||||
char *s, *p;
|
||||
int size = 32;
|
||||
int n;
|
||||
|
||||
s = NULL;
|
||||
size = 32;
|
||||
for (;;) {
|
||||
p = (char *) realloc(s, size);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
s = p;
|
||||
|
||||
#ifdef WIN32
|
||||
va_tmp = va;
|
||||
#else
|
||||
va_copy(va_tmp, va);
|
||||
#endif
|
||||
n = vsnprintf(s, size, fmt, va_tmp);
|
||||
|
||||
if (n >= size)
|
||||
size = n + 1;
|
||||
else if (n < 0)
|
||||
size = size * 2;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* 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
|
||||
normalization of \r\n\t in attribute values. If this is not desired
|
||||
in some cases, we'll have to add a parameter to control this. */
|
||||
static char *escape(const char *str) {
|
||||
/* result is the result buffer; n + 1 is the allocated size. Double the
|
||||
allocation when space runs out. */
|
||||
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 == '<')
|
||||
repl = "<";
|
||||
else if (*p == '>')
|
||||
repl = ">";
|
||||
else if (*p == '&')
|
||||
repl = "&";
|
||||
else if (*p == '"')
|
||||
repl = """;
|
||||
else if (*p == '\'')
|
||||
repl = "'";
|
||||
else if (*p == '-' && p > str && *(p - 1) == '-') {
|
||||
/* Escape -- for comments. */
|
||||
repl = "-";
|
||||
} else if (*p < 0x20 || (unsigned char) *p > 0x7F) {
|
||||
/* Escape control characters and anything outside of ASCII. We have to
|
||||
emit UTF-8 and an easy way to do that is to emit ASCII. */
|
||||
Snprintf(buf, sizeof(buf), "&#x%x;", (unsigned char) *p);
|
||||
repl = buf;
|
||||
} else {
|
||||
/* Unescaped character. */
|
||||
buf[0] = *p;
|
||||
buf[1] = '\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;
|
||||
}
|
||||
|
||||
/* Write data directly to the XML file with no escaping. Make sure you
|
||||
know what you're doing. */
|
||||
int xml_write_raw(const char *fmt, ...) {
|
||||
va_list va;
|
||||
char *s;
|
||||
|
||||
va_start(va, fmt);
|
||||
s = alloc_vsprintf(fmt, va);
|
||||
va_end(va);
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
|
||||
log_write(LOG_XML, "%s", s);
|
||||
free(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write data directly to the XML file after escaping it. */
|
||||
int xml_write_escaped(const char *fmt, ...) {
|
||||
va_list va;
|
||||
int n;
|
||||
|
||||
va_start(va, fmt);
|
||||
n = xml_write_escaped_v(fmt, va);
|
||||
va_end(va);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Write data directly to the XML file after escaping it. This version takes a
|
||||
va_list like vprintf. */
|
||||
int xml_write_escaped_v(const char *fmt, va_list va) {
|
||||
char *s, *esc_s;
|
||||
|
||||
s = alloc_vsprintf(fmt, va);
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
esc_s = escape(s);
|
||||
free(s);
|
||||
if (esc_s == NULL)
|
||||
return -1;
|
||||
|
||||
log_write(LOG_XML, "%s", esc_s);
|
||||
free(esc_s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write the XML declaration: <?xml version="1.0"?>. */
|
||||
int xml_start_document() {
|
||||
if (xml_open_pi("xml") < 0)
|
||||
return -1;
|
||||
if (xml_attribute("version", "1.0") < 0)
|
||||
return -1;
|
||||
if (xml_close_pi() < 0)
|
||||
return -1;
|
||||
if (xml_newline() < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xml_start_comment() {
|
||||
log_write(LOG_XML, "<!--");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xml_end_comment() {
|
||||
log_write(LOG_XML, "-->");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xml_open_pi(const char *name) {
|
||||
assert(!xml.tag_open);
|
||||
log_write(LOG_XML, "<?%s", name);
|
||||
xml.tag_open = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xml_close_pi() {
|
||||
assert(xml.tag_open);
|
||||
log_write(LOG_XML, "?>");
|
||||
xml.tag_open = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
assert(!xml.tag_open);
|
||||
log_write(LOG_XML, "<%s", name);
|
||||
xml.element_stack.push_back(name);
|
||||
xml.tag_open = true;
|
||||
xml.root_written = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xml_close_start_tag() {
|
||||
assert(xml.tag_open);
|
||||
log_write(LOG_XML, ">");
|
||||
xml.tag_open = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Close an empty-element tag. It should have been opened with
|
||||
xml_open_start_tag. */
|
||||
int xml_close_empty_tag() {
|
||||
assert(xml.tag_open);
|
||||
assert(!xml.element_stack.empty());
|
||||
xml.element_stack.pop_back();
|
||||
log_write(LOG_XML, "/>");
|
||||
xml.tag_open = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xml_start_tag(const char *name) {
|
||||
if (xml_open_start_tag(name) < 0)
|
||||
return -1;
|
||||
if (xml_close_start_tag() < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write an end tag for the element at the top of the element stack. */
|
||||
int xml_end_tag() {
|
||||
const char *name;
|
||||
|
||||
assert(!xml.tag_open);
|
||||
assert(!xml.element_stack.empty());
|
||||
name = xml.element_stack.back();
|
||||
xml.element_stack.pop_back();
|
||||
|
||||
log_write(LOG_XML, "</%s>", name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write an attribute. The only place this makes sense is between
|
||||
xml_open_start_tag and either xml_close_start_tag or
|
||||
xml_close_empty_tag. */
|
||||
int xml_attribute(const char *name, const char *fmt, ...) {
|
||||
va_list va;
|
||||
char *val, *esc_val;
|
||||
|
||||
assert(xml.tag_open);
|
||||
|
||||
va_start(va, fmt);
|
||||
val = alloc_vsprintf(fmt, va);
|
||||
va_end(va);
|
||||
if (val == NULL)
|
||||
return -1;
|
||||
esc_val = escape(val);
|
||||
free(val);
|
||||
if (esc_val == NULL)
|
||||
return -1;
|
||||
|
||||
log_write(LOG_XML, " %s=\"%s\"", name, esc_val);
|
||||
free(esc_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xml_newline() {
|
||||
log_write(LOG_XML, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the size of the element stack. */
|
||||
int xml_depth() {
|
||||
return xml.element_stack.size();
|
||||
}
|
||||
|
||||
/* Return true iff a root element has been started. */
|
||||
bool xml_root_written() {
|
||||
return xml.root_written;
|
||||
}
|
||||
120
xml.h
Normal file
120
xml.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/***************************************************************************
|
||||
* xml.h *
|
||||
***********************IMPORTANT NMAP LICENSE TERMS************************
|
||||
* *
|
||||
* The Nmap Security Scanner is (C) 1996-2009 Insecure.Com LLC. Nmap is *
|
||||
* also a registered trademark of Insecure.Com LLC. This program is free *
|
||||
* software; you may redistribute and/or modify it under the terms of the *
|
||||
* GNU General Public License as published by the Free Software *
|
||||
* Foundation; Version 2 with the clarifications and exceptions described *
|
||||
* below. This guarantees your right to use, modify, and redistribute *
|
||||
* this software under certain conditions. If you wish to embed Nmap *
|
||||
* technology into proprietary software, we sell alternative licenses *
|
||||
* (contact sales@insecure.com). Dozens of software vendors already *
|
||||
* license Nmap technology such as host discovery, port scanning, OS *
|
||||
* detection, and version detection. *
|
||||
* *
|
||||
* Note that the GPL places important restrictions on "derived works", yet *
|
||||
* it does not provide a detailed definition of that term. To avoid *
|
||||
* misunderstandings, we consider an application to constitute a *
|
||||
* "derivative work" for the purpose of this license if it does any of the *
|
||||
* following: *
|
||||
* o Integrates source code from Nmap *
|
||||
* o Reads or includes Nmap copyrighted data files, such as *
|
||||
* nmap-os-db or nmap-service-probes. *
|
||||
* o Executes Nmap and parses the results (as opposed to typical shell or *
|
||||
* execution-menu apps, which simply display raw Nmap output and so are *
|
||||
* not derivative works.) *
|
||||
* o Integrates/includes/aggregates Nmap into a proprietary executable *
|
||||
* installer, such as those produced by InstallShield. *
|
||||
* o Links to a library or executes a program that does any of the above *
|
||||
* *
|
||||
* The term "Nmap" should be taken to also include any portions or derived *
|
||||
* works of Nmap. This list is not exclusive, but is meant to clarify our *
|
||||
* interpretation of derived works with some common examples. Our *
|
||||
* interpretation applies only to Nmap--we don't speak for other people's *
|
||||
* GPL works. *
|
||||
* *
|
||||
* If you have any questions about the GPL licensing restrictions on using *
|
||||
* Nmap in non-GPL works, we would be happy to help. As mentioned above, *
|
||||
* we also offer alternative license to integrate Nmap into proprietary *
|
||||
* applications and appliances. These contracts have been sold to dozens *
|
||||
* of software vendors, and generally include a perpetual license as well *
|
||||
* as providing for priority support and updates as well as helping to *
|
||||
* fund the continued development of Nmap technology. Please email *
|
||||
* sales@insecure.com for further information. *
|
||||
* *
|
||||
* As a special exception to the GPL terms, Insecure.Com LLC grants *
|
||||
* permission to link the code of this program with any version of the *
|
||||
* OpenSSL library which is distributed under a license identical to that *
|
||||
* listed in the included COPYING.OpenSSL file, and distribute linked *
|
||||
* combinations including the two. You must obey the GNU GPL in all *
|
||||
* respects for all of the code used other than OpenSSL. If you modify *
|
||||
* this file, you may extend this exception to your version of the file, *
|
||||
* but you are not obligated to do so. *
|
||||
* *
|
||||
* If you received these files with a written license agreement or *
|
||||
* contract stating terms other than the terms above, then that *
|
||||
* alternative license agreement takes precedence over these comments. *
|
||||
* *
|
||||
* Source is provided to this software because we believe users have a *
|
||||
* right to know exactly what a program is going to do before they run it. *
|
||||
* This also allows you to audit the software for security holes (none *
|
||||
* have been found so far). *
|
||||
* *
|
||||
* Source code also allows you to port Nmap to new platforms, fix bugs, *
|
||||
* and add new features. You are highly encouraged to send your changes *
|
||||
* to nmap-dev@insecure.org for possible incorporation into the main *
|
||||
* distribution. By sending these changes to Fyodor or one of the *
|
||||
* Insecure.Org development mailing lists, it is assumed that you are *
|
||||
* offering the Nmap Project (Insecure.Com LLC) the unlimited, *
|
||||
* non-exclusive right to reuse, modify, and relicense the code. Nmap *
|
||||
* will always be available Open Source, but this is important because the *
|
||||
* inability to relicense code has caused devastating problems for other *
|
||||
* Free Software projects (such as KDE and NASM). We also occasionally *
|
||||
* relicense the code to third parties as discussed above. If you wish to *
|
||||
* specify special license conditions of your contributions, just say so *
|
||||
* when you send them. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* General Public License v2.0 for more details at *
|
||||
* http://www.gnu.org/licenses/gpl-2.0.html , or in the COPYING file *
|
||||
* included with Nmap. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/* $Id: xml.h 15135 2009-08-19 21:05:21Z david $ */
|
||||
|
||||
#ifndef _XML_H
|
||||
#define _XML_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
int xml_write_raw(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
int xml_write_escaped(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
int xml_write_escaped_v(const char *fmt, va_list va) __attribute__ ((format (printf, 1, 0)));
|
||||
|
||||
int xml_start_document();
|
||||
|
||||
int xml_start_comment();
|
||||
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_close_empty_tag();
|
||||
int xml_start_tag(const char *name);
|
||||
int xml_end_tag();
|
||||
|
||||
int xml_attribute(const char *name, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
int xml_newline();
|
||||
|
||||
int xml_depth();
|
||||
bool xml_root_written();
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user