1
0
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:
david
2010-04-14 01:05:51 +00:00
parent 62955f75e6
commit 859ef5ecaf
14 changed files with 1059 additions and 431 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

@@ -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, &currenths->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();

View File

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

@@ -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 = "&lt;";
else if (*p == '>')
repl = "&gt;";
else if (*p == '&')
repl = "&amp;";
else if (*p == '"')
repl = "&quot;";
else if (*p == '\'')
repl = "&apos;";
else if (*p == '-' && p > str && *(p - 1) == '-') {
/* Escape -- for comments. */
repl = "&#45;";
} 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();
}

View File

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

View File

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

View File

@@ -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
View 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="&amp;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="&amp;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 = "&lt;";
else if (*p == '>')
repl = "&gt;";
else if (*p == '&')
repl = "&amp;";
else if (*p == '"')
repl = "&quot;";
else if (*p == '\'')
repl = "&apos;";
else if (*p == '-' && p > str && *(p - 1) == '-') {
/* Escape -- for comments. */
repl = "&#45;";
} 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
View 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