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