diff --git a/Makefile.in b/Makefile.in
index d4646883a..f0b3b7f03 100644
--- a/Makefile.in
+++ b/Makefile.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:
diff --git a/NmapOps.cc b/NmapOps.cc
index 9cb965c4d..2b234db9d 100644
--- a/NmapOps.cc
+++ b/NmapOps.cc
@@ -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);
diff --git a/NmapOps.h b/NmapOps.h
index 7629b9fff..9b8414e07 100644
--- a/NmapOps.h
+++ b/NmapOps.h
@@ -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();
diff --git a/NmapOutputTable.h b/NmapOutputTable.h
index 55f1becb3..6297b4b85 100644
--- a/NmapOutputTable.h
+++ b/NmapOutputTable.h
@@ -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
diff --git a/docs/nmap.dtd b/docs/nmap.dtd
index 502af1472..41bde3a53 100644
--- a/docs/nmap.dtd
+++ b/docs/nmap.dtd
@@ -313,12 +313,15 @@
-
+
diff --git a/mswin32/nmap.vcproj b/mswin32/nmap.vcproj
index f53908395..737bca9c9 100644
--- a/mswin32/nmap.vcproj
+++ b/mswin32/nmap.vcproj
@@ -366,6 +366,10 @@
RelativePath="..\utils.cc"
>
+
+
@@ -559,6 +563,10 @@
RelativePath="..\utils.h"
>
+
+
diff --git a/nmap.cc b/nmap.cc
index f8c628549..9cbfacec0 100644
--- a/nmap.cc
+++ b/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), "\n", p);
- free(p);
- } else xslline[0] = '\0';
- log_write(LOG_XML, "\n%s");
- log_write(LOG_NORMAL|LOG_MACHINE|LOG_XML,"\n");
-
- log_write(LOG_XML, "\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, "\n\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, "");
+ 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, "\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, "");
+ xml_start_tag("host");
write_host_header(currenths);
- log_write(LOG_XML, "\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, "",
- (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, "\n");
+ xml_end_tag(); /* host */
+ xml_newline();
}
}
log_flush_all();
diff --git a/nmap_error.cc b/nmap_error.cc
index 082059a47..043c54f40 100644
--- a/nmap_error.cc
+++ b/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
#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;
-
- va_start(ap, err);
- log_vwrite(LOG_STDERR, err, ap);
+ int error_number;
+ char errbuf[1024], *strerror_s;
+
+#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
- log_write(o.log_errors? LOG_NORMAL|LOG_STDERR : LOG_STDERR, ": %s (%d)\n",
- strerror(errno), errno);
-#endif /* WIN32 perror() compatability switch */
+ 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_s, error_number);
+
+#ifdef WIN32
+ HeapFree(GetProcessHeap(), 0, strerror_s);
+#endif
+
if (o.log_errors) log_flush(LOG_NORMAL);
fflush(stderr);
return;
diff --git a/output.cc b/output.cc
index a02f00a88..d7728eb5c 100644
--- a/output.cc
+++ b/output.cc
@@ -104,6 +104,7 @@
#include "nmap_rpc.h"
#include "Target.h"
#include "utils.h"
+#include "xml.h"
#include
@@ -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 element for the information given in
+// Prints an XML 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 = "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, "");
+ xml_start_tag("ports");
int prevstate = PORT_UNKNOWN;
int istate;
while ((istate = plist->nextIgnoredState(prevstate)) != PORT_UNKNOWN) {
- log_write(LOG_XML, "\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, "\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, "\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, ""
- "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", proto->p_name);
- log_write(LOG_XML, "\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, "",
- protocol, current->portno);
- log_write(LOG_XML, "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, "",
- 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, "\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, "\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;", (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, "\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, "\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, "\n", status,
- reason_str(currenths->reason.reason_id, SINGULAR));
- log_write(LOG_XML, "\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, "\n");
+ xml_start_tag("hostnames");
+ xml_newline();
if (currenths->TargetName() != NULL) {
- log_write(LOG_XML, "\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, "\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, "\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, "\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,
- "\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, "\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, "");
+ xml_start_tag("os");
if (FPR->osscan_opentcpport > 0) {
- log_write(LOG_XML,
- "\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,
- "\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,
- "\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,
- "\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,
- "\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, "\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, "\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, "\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,
- "\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, "\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, "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, "");
+ 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, "",
- 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, "");
+ xml_end_tag();
}
}
#endif
@@ -2126,44 +2044,49 @@ static void printtraceroute_xml(Target * currenths) {
return;
/* XML traceroute header */
- log_write(LOG_XML, "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, "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, "\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, "\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,
- "\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,
- "\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, "\n");
+ xml_end_tag(); /* nmaprun */
+ xml_newline();
log_flush_all();
}
diff --git a/output.h b/output.h
index 05ea6ca6d..b71054dca 100644
--- a/output.h
+++ b/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 */
diff --git a/portreasons.cc b/portreasons.cc
index 720abb78e..20eb05e96 100644
--- a/portreasons.cc
+++ b/portreasons.cc
@@ -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, "\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);
diff --git a/timing.cc b/timing.cc
index 6ffb937f7..d26623e26 100644
--- a/timing.cc
+++ b/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, "\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, "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, "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;
diff --git a/xml.cc b/xml.cc
new file mode 100644
index 000000000..3ad182d93
--- /dev/null
+++ b/xml.cc
@@ -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
+
+
+Each function call is followed by the text it prints enclosed in ||.
+
+xml_start_document() |
+xml_newline(); |\n|
+xml_open_start_tag("elem"); ||
+xml_end_tag(); ||
+
+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_open_pi("elem") ||
+xml_open_start_tag("elem") ||
+xml_close_empty_tag() |/>|
+xml_start_tag("elem") ||
+xml_end_tag() ||
+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_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
+#include
+#include
+#include
+
+#include "output.h"
+#include "xml.h"
+
+struct xml_writer {
+ /* Sanity checking: Don't open a new tag while still defining
+ attributes for another, like " 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;", (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: . */
+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_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 "");
+ 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;
+}
diff --git a/xml.h b/xml.h
new file mode 100644
index 000000000..838ac6a4f
--- /dev/null
+++ b/xml.h
@@ -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
+
+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