PageRenderTime 79ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/output.cc

https://github.com/prakashgamit/nmap
C++ | 2686 lines | 2062 code | 291 blank | 333 comment | 681 complexity | c9720ad72338456ff6e6de7118c157b5 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /***************************************************************************
  2. * output.cc -- Handles the Nmap output system. This currently involves *
  3. * console-style human readable output, XML output, Script |<iddi3 *
  4. * output, and the legacy greppable output (used to be called "machine *
  5. * readable"). I expect that future output forms (such as HTML) may be *
  6. * created by a different program, library, or script using the XML *
  7. * output. *
  8. * *
  9. ***********************IMPORTANT NMAP LICENSE TERMS************************
  10. * *
  11. * The Nmap Security Scanner is (C) 1996-2013 Insecure.Com LLC. Nmap is *
  12. * also a registered trademark of Insecure.Com LLC. This program is free *
  13. * software; you may redistribute and/or modify it under the terms of the *
  14. * GNU General Public License as published by the Free Software *
  15. * Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE CLARIFICATIONS *
  16. * AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your right to use, *
  17. * modify, and redistribute this software under certain conditions. If *
  18. * you wish to embed Nmap technology into proprietary software, we sell *
  19. * alternative licenses (contact sales@nmap.com). Dozens of software *
  20. * vendors already license Nmap technology such as host discovery, port *
  21. * scanning, OS detection, version detection, and the Nmap Scripting *
  22. * Engine. *
  23. * *
  24. * Note that the GPL places important restrictions on "derivative works", *
  25. * yet it does not provide a detailed definition of that term. To avoid *
  26. * misunderstandings, we interpret that term as broadly as copyright law *
  27. * allows. For example, we consider an application to constitute a *
  28. * derivative work for the purpose of this license if it does any of the *
  29. * following with any software or content covered by this license *
  30. * ("Covered Software"): *
  31. * *
  32. * o Integrates source code from Covered Software. *
  33. * *
  34. * o Reads or includes copyrighted data files, such as Nmap's nmap-os-db *
  35. * or nmap-service-probes. *
  36. * *
  37. * o Is designed specifically to execute Covered Software and parse the *
  38. * results (as opposed to typical shell or execution-menu apps, which will *
  39. * execute anything you tell them to). *
  40. * *
  41. * o Includes Covered Software in a proprietary executable installer. The *
  42. * installers produced by InstallShield are an example of this. Including *
  43. * Nmap with other software in compressed or archival form does not *
  44. * trigger this provision, provided appropriate open source decompression *
  45. * or de-archiving software is widely available for no charge. For the *
  46. * purposes of this license, an installer is considered to include Covered *
  47. * Software even if it actually retrieves a copy of Covered Software from *
  48. * another source during runtime (such as by downloading it from the *
  49. * Internet). *
  50. * *
  51. * o Links (statically or dynamically) to a library which does any of the *
  52. * above. *
  53. * *
  54. * o Executes a helper program, module, or script to do any of the above. *
  55. * *
  56. * This list is not exclusive, but is meant to clarify our interpretation *
  57. * of derived works with some common examples. Other people may interpret *
  58. * the plain GPL differently, so we consider this a special exception to *
  59. * the GPL that we apply to Covered Software. Works which meet any of *
  60. * these conditions must conform to all of the terms of this license, *
  61. * particularly including the GPL Section 3 requirements of providing *
  62. * source code and allowing free redistribution of the work as a whole. *
  63. * *
  64. * As another special exception to the GPL terms, Insecure.Com LLC grants *
  65. * permission to link the code of this program with any version of the *
  66. * OpenSSL library which is distributed under a license identical to that *
  67. * listed in the included docs/licenses/OpenSSL.txt file, and distribute *
  68. * linked combinations including the two. *
  69. * *
  70. * Any redistribution of Covered Software, including any derived works, *
  71. * must obey and carry forward all of the terms of this license, including *
  72. * obeying all GPL rules and restrictions. For example, source code of *
  73. * the whole work must be provided and free redistribution must be *
  74. * allowed. All GPL references to "this License", are to be treated as *
  75. * including the terms and conditions of this license text as well. *
  76. * *
  77. * Because this license imposes special exceptions to the GPL, Covered *
  78. * Work may not be combined (even as part of a larger work) with plain GPL *
  79. * software. The terms, conditions, and exceptions of this license must *
  80. * be included as well. This license is incompatible with some other open *
  81. * source licenses as well. In some cases we can relicense portions of *
  82. * Nmap or grant special permissions to use it in other open source *
  83. * software. Please contact fyodor@nmap.org with any such requests. *
  84. * Similarly, we don't incorporate incompatible open source software into *
  85. * Covered Software without special permission from the copyright holders. *
  86. * *
  87. * If you have any questions about the licensing restrictions on using *
  88. * Nmap in other works, are happy to help. As mentioned above, we also *
  89. * offer alternative license to integrate Nmap into proprietary *
  90. * applications and appliances. These contracts have been sold to dozens *
  91. * of software vendors, and generally include a perpetual license as well *
  92. * as providing for priority support and updates. They also fund the *
  93. * continued development of Nmap. Please email sales@nmap.com for further *
  94. * information. *
  95. * *
  96. * If you have received a written license agreement or contract for *
  97. * Covered Software stating terms other than these, you may choose to use *
  98. * and redistribute Covered Software under those terms instead of these. *
  99. * *
  100. * Source is provided to this software because we believe users have a *
  101. * right to know exactly what a program is going to do before they run it. *
  102. * This also allows you to audit the software for security holes (none *
  103. * have been found so far). *
  104. * *
  105. * Source code also allows you to port Nmap to new platforms, fix bugs, *
  106. * and add new features. You are highly encouraged to send your changes *
  107. * to the dev@nmap.org mailing list for possible incorporation into the *
  108. * main distribution. By sending these changes to Fyodor or one of the *
  109. * Insecure.Org development mailing lists, or checking them into the Nmap *
  110. * source code repository, it is understood (unless you specify otherwise) *
  111. * that you are offering the Nmap Project (Insecure.Com LLC) the *
  112. * unlimited, non-exclusive right to reuse, modify, and relicense the *
  113. * code. Nmap will always be available Open Source, but this is important *
  114. * because the inability to relicense code has caused devastating problems *
  115. * for other Free Software projects (such as KDE and NASM). We also *
  116. * occasionally relicense the code to third parties as discussed above. *
  117. * If you wish to specify special license conditions of your *
  118. * contributions, just say so when you send them. *
  119. * *
  120. * This program is distributed in the hope that it will be useful, but *
  121. * WITHOUT ANY WARRANTY; without even the implied warranty of *
  122. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Nmap *
  123. * license file for more details (it's in a COPYING file included with *
  124. * Nmap, and also available from https://svn.nmap.org/nmap/COPYING *
  125. * *
  126. ***************************************************************************/
  127. /* $Id$ */
  128. #include "nmap.h"
  129. #include "output.h"
  130. #include "osscan.h"
  131. #include "NmapOps.h"
  132. #include "NmapOutputTable.h"
  133. #include "MACLookup.h"
  134. #include "portreasons.h"
  135. #include "protocols.h"
  136. #include "Target.h"
  137. #include "utils.h"
  138. #include "xml.h"
  139. #include "nbase.h"
  140. #include "libnetutil/netutil.h"
  141. #include <math.h>
  142. #include <set>
  143. #include <vector>
  144. #include <list>
  145. #include <sstream>
  146. extern NmapOps o;
  147. static const char *logtypes[LOG_NUM_FILES] = LOG_NAMES;
  148. /* Used in creating skript kiddie style output. |<-R4d! */
  149. static void skid_output(char *s) {
  150. int i;
  151. for (i = 0; s[i]; i++)
  152. /* We need a 50/50 chance here, use a random number */
  153. if ((get_random_u8() & 0x01) == 0)
  154. /* Substitutions commented out are not known to me, but maybe look nice */
  155. switch (s[i]) {
  156. case 'A':
  157. s[i] = '4';
  158. break;
  159. /* case 'B': s[i]='8'; break;
  160. case 'b': s[i]='6'; break;
  161. case 'c': s[i]='k'; break;
  162. case 'C': s[i]='K'; break; */
  163. case 'e':
  164. case 'E':
  165. s[i] = '3';
  166. break;
  167. case 'i':
  168. case 'I':
  169. s[i] = "!|1"[get_random_u8() % 3];
  170. break;
  171. /* case 'k': s[i]='c'; break;
  172. case 'K': s[i]='C'; break; */
  173. case 'o':
  174. case 'O':
  175. s[i] = '0';
  176. break;
  177. case 's':
  178. case 'S':
  179. if (s[i + 1] && !isalnum((int) (unsigned char) s[i + 1]))
  180. s[i] = 'z';
  181. else
  182. s[i] = '$';
  183. break;
  184. case 'z':
  185. s[i] = 's';
  186. break;
  187. case 'Z':
  188. s[i] = 'S';
  189. break;
  190. } else {
  191. if (s[i] >= 'A' && s[i] <= 'Z' && (get_random_u8() % 3 == 0)) {
  192. s[i] += 'a' - 'A'; /* 1/3 chance of lower-case */
  193. } else if (s[i] >= 'a' && s[i] <= 'z' && (get_random_u8() % 3 == 0)) {
  194. s[i] -= 'a' - 'A'; /* 1/3 chance of upper-case */
  195. }
  196. }
  197. }
  198. /* Remove all "\nSF:" from fingerprints */
  199. static char *servicefp_sf_remove(const char *str) {
  200. char *temp = (char *) safe_malloc(strlen(str) + 1);
  201. char *dst = temp, *src = (char *) str;
  202. char *ampptr = 0;
  203. while (*src) {
  204. if (strncmp(src, "\nSF:", 4) == 0) {
  205. src += 4;
  206. continue;
  207. }
  208. /* Needed so "&something;" is not truncated midway */
  209. if (*src == '&') {
  210. ampptr = dst;
  211. } else if (*src == ';') {
  212. ampptr = 0;
  213. }
  214. *dst++ = *src++;
  215. }
  216. if (ampptr != 0) {
  217. *ampptr = '\0';
  218. } else {
  219. *dst = '\0';
  220. }
  221. return temp;
  222. }
  223. // Prints an XML <service> element for the information given in
  224. // serviceDeduction. This function should only be called if ether
  225. // the service name or the service fingerprint is non-null.
  226. static void print_xml_service(const struct serviceDeductions *sd) {
  227. xml_open_start_tag("service");
  228. xml_attribute("name", "%s", sd->name ? sd->name : "unknown");
  229. if (sd->product)
  230. xml_attribute("product", "%s", sd->product);
  231. if (sd->version)
  232. xml_attribute("version", "%s", sd->version);
  233. if (sd->extrainfo)
  234. xml_attribute("extrainfo", "%s", sd->extrainfo);
  235. if (sd->hostname)
  236. xml_attribute("hostname", "%s", sd->hostname);
  237. if (sd->ostype)
  238. xml_attribute("ostype", "%s", sd->ostype);
  239. if (sd->devicetype)
  240. xml_attribute("devicetype", "%s", sd->devicetype);
  241. if (sd->service_fp) {
  242. char *servicefp = servicefp_sf_remove(sd->service_fp);
  243. xml_attribute("servicefp", "%s", servicefp);
  244. free(servicefp);
  245. }
  246. if (sd->service_tunnel == SERVICE_TUNNEL_SSL)
  247. xml_attribute("tunnel", "ssl");
  248. xml_attribute("method", "%s", (sd->dtype == SERVICE_DETECTION_TABLE) ? "table" : "probed");
  249. xml_attribute("conf", "%i", sd->name_confidence);
  250. if (sd->cpe.empty()) {
  251. xml_close_empty_tag();
  252. } else {
  253. unsigned int i;
  254. xml_close_start_tag();
  255. for (i = 0; i < sd->cpe.size(); i++) {
  256. xml_start_tag("cpe");
  257. xml_write_escaped("%s", sd->cpe[i]);
  258. xml_end_tag();
  259. }
  260. xml_end_tag();
  261. }
  262. }
  263. #ifdef WIN32
  264. /* Show a fatal error explaining that an interface is not Ethernet and won't
  265. work on Windows. Do nothing if --send-ip (PACKET_SEND_IP_STRONG) was used. */
  266. void win32_fatal_raw_sockets(const char *devname) {
  267. if ((o.sendpref & PACKET_SEND_IP_STRONG) != 0)
  268. return;
  269. if (devname != NULL) {
  270. fatal("Only ethernet devices can be used for raw scans on Windows, and\n"
  271. "\"%s\" is not an ethernet device. Use the --unprivileged option\n"
  272. "for this scan.", devname);
  273. } else {
  274. fatal("Only ethernet devices can be used for raw scans on Windows. Use\n"
  275. "the --unprivileged option for this scan.", devname);
  276. }
  277. }
  278. /* Display the mapping from libdnet interface names (like "eth0") to WinPcap
  279. interface names (like "\Device\NPF_{...}"). This is the same mapping used by
  280. eth_open and so can help diagnose connection problems. Additionally display
  281. WinPcap interface names that are not mapped to by any libdnet name, in other
  282. words the names of interfaces Nmap has no way of using.*/
  283. static void print_iflist_pcap_mapping(const struct interface_info *iflist,
  284. int numifs) {
  285. pcap_if_t *pcap_ifs;
  286. std::list<const pcap_if_t *> leftover_pcap_ifs;
  287. std::list<const pcap_if_t *>::iterator leftover_p;
  288. int i;
  289. /* Build a list of "leftover" libpcap interfaces. Initially it contains all
  290. the interfaces. */
  291. pcap_ifs = getpcapinterfaces();
  292. for (const pcap_if_t *p = pcap_ifs; p != NULL; p = p->next)
  293. leftover_pcap_ifs.push_front(p);
  294. if (numifs > 0 || !leftover_pcap_ifs.empty()) {
  295. NmapOutputTable Tbl(1 + numifs + leftover_pcap_ifs.size(), 2);
  296. Tbl.addItem(0, 0, false, "DEV");
  297. Tbl.addItem(0, 1, false, "WINDEVICE");
  298. /* Show the libdnet names and what they map to. */
  299. for (i = 0; i < numifs; i++) {
  300. char pcap_name[1024];
  301. if (DnetName2PcapName(iflist[i].devname, pcap_name, sizeof(pcap_name))) {
  302. /* We got a name. Remove it from the list of leftovers. */
  303. std::list<const pcap_if_t *>::iterator next;
  304. for (leftover_p = leftover_pcap_ifs.begin();
  305. leftover_p != leftover_pcap_ifs.end(); leftover_p = next) {
  306. next = leftover_p;
  307. next++;
  308. if (strcmp((*leftover_p)->name, pcap_name) == 0)
  309. leftover_pcap_ifs.erase(leftover_p);
  310. }
  311. } else {
  312. Strncpy(pcap_name, "<none>", sizeof(pcap_name));
  313. }
  314. Tbl.addItem(i + 1, 0, false, iflist[i].devname);
  315. Tbl.addItem(i + 1, 1, true, pcap_name);
  316. }
  317. /* Show the "leftover" libpcap interface names (those without a libdnet
  318. name that maps to them). */
  319. for (leftover_p = leftover_pcap_ifs.begin();
  320. leftover_p != leftover_pcap_ifs.end();
  321. leftover_p++) {
  322. Tbl.addItem(i + 1, 0, false, "<none>");
  323. Tbl.addItem(i + 1, 1, false, (*leftover_p)->name);
  324. i++;
  325. }
  326. log_write(LOG_PLAIN, "%s\n", Tbl.printableTable(NULL));
  327. log_flush_all();
  328. }
  329. pcap_freealldevs(pcap_ifs);
  330. }
  331. #endif
  332. /* Print a detailed list of Nmap interfaces and routes to
  333. normal/skiddy/stdout output */
  334. int print_iflist(void) {
  335. int numifs = 0, numroutes = 0;
  336. struct interface_info *iflist;
  337. struct sys_route *routes;
  338. NmapOutputTable *Tbl = NULL;
  339. char errstr[256];
  340. errstr[0]='\0';
  341. iflist = getinterfaces(&numifs, errstr, sizeof(errstr));
  342. int i;
  343. /* First let's handle interfaces ... */
  344. if (iflist==NULL || numifs<=0) {
  345. log_write(LOG_PLAIN, "INTERFACES: NONE FOUND(!)\n");
  346. if (o.debugging)
  347. log_write(LOG_STDOUT, "Reason: %s\n", errstr);
  348. } else {
  349. int devcol = 0, shortdevcol = 1, ipcol = 2, typecol = 3, upcol = 4, mtucol = 5, maccol = 6;
  350. Tbl = new NmapOutputTable(numifs + 1, 7);
  351. Tbl->addItem(0, devcol, false, "DEV", 3);
  352. Tbl->addItem(0, shortdevcol, false, "(SHORT)", 7);
  353. Tbl->addItem(0, ipcol, false, "IP/MASK", 7);
  354. Tbl->addItem(0, typecol, false, "TYPE", 4);
  355. Tbl->addItem(0, upcol, false, "UP", 2);
  356. Tbl->addItem(0, mtucol, false, "MTU", 3);
  357. Tbl->addItem(0, maccol, false, "MAC", 3);
  358. for (i = 0; i < numifs; i++) {
  359. Tbl->addItem(i + 1, devcol, false, iflist[i].devfullname);
  360. Tbl->addItemFormatted(i + 1, shortdevcol, false, "(%s)",
  361. iflist[i].devname);
  362. Tbl->addItemFormatted(i + 1, ipcol, false, "%s/%d",
  363. inet_ntop_ez(&(iflist[i].addr), sizeof(iflist[i].addr)),
  364. iflist[i].netmask_bits);
  365. if (iflist[i].device_type == devt_ethernet) {
  366. Tbl->addItem(i + 1, typecol, false, "ethernet");
  367. Tbl->addItemFormatted(i + 1, maccol, false,
  368. "%02X:%02X:%02X:%02X:%02X:%02X",
  369. iflist[i].mac[0], iflist[i].mac[1],
  370. iflist[i].mac[2], iflist[i].mac[3],
  371. iflist[i].mac[4], iflist[i].mac[5]);
  372. } else if (iflist[i].device_type == devt_loopback)
  373. Tbl->addItem(i + 1, typecol, false, "loopback");
  374. else if (iflist[i].device_type == devt_p2p)
  375. Tbl->addItem(i + 1, typecol, false, "point2point");
  376. else
  377. Tbl->addItem(i + 1, typecol, false, "other");
  378. Tbl->addItem(i + 1, upcol, false,
  379. (iflist[i].device_up ? "up" : "down"));
  380. Tbl->addItemFormatted(i + 1, mtucol, false, "%d", iflist[i].mtu);
  381. }
  382. log_write(LOG_PLAIN, "************************INTERFACES************************\n");
  383. log_write(LOG_PLAIN, "%s\n", Tbl->printableTable(NULL));
  384. log_flush_all();
  385. delete Tbl;
  386. }
  387. #ifdef WIN32
  388. /* Print the libdnet->libpcap interface name mapping. */
  389. print_iflist_pcap_mapping(iflist, numifs);
  390. #endif
  391. /* OK -- time to handle routes */
  392. errstr[0]='\0';
  393. routes = getsysroutes(&numroutes, errstr, sizeof(errstr));
  394. u16 nbits;
  395. if (routes==NULL || numroutes<= 0) {
  396. log_write(LOG_PLAIN, "ROUTES: NONE FOUND(!)\n");
  397. if (o.debugging)
  398. log_write(LOG_STDOUT, "Reason: %s\n", errstr);
  399. } else {
  400. int dstcol = 0, devcol = 1, metcol = 2, gwcol = 3;
  401. Tbl = new NmapOutputTable(numroutes + 1, 4);
  402. Tbl->addItem(0, dstcol, false, "DST/MASK", 8);
  403. Tbl->addItem(0, devcol, false, "DEV", 3);
  404. Tbl->addItem(0, metcol, false, "METRIC", 6);
  405. Tbl->addItem(0, gwcol, false, "GATEWAY", 7);
  406. for (i = 0; i < numroutes; i++) {
  407. nbits = routes[i].netmask_bits;
  408. Tbl->addItemFormatted(i + 1, dstcol, false, "%s/%d",
  409. inet_ntop_ez(&routes[i].dest, sizeof(routes[i].dest)), nbits);
  410. Tbl->addItem(i + 1, devcol, false, routes[i].device->devfullname);
  411. Tbl->addItemFormatted(i + 1, metcol, false, "%d", routes[i].metric);
  412. if (!sockaddr_equal_zero(&routes[i].gw))
  413. Tbl->addItem(i + 1, gwcol, true, inet_ntop_ez(&routes[i].gw, sizeof(routes[i].gw)));
  414. }
  415. log_write(LOG_PLAIN, "**************************ROUTES**************************\n");
  416. log_write(LOG_PLAIN, "%s\n", Tbl->printableTable(NULL));
  417. log_flush_all();
  418. delete Tbl;
  419. }
  420. return 0;
  421. }
  422. #ifndef NOLUA
  423. /* Escape control characters to make a string safe to display on a terminal. */
  424. static std::string escape_for_screen(const std::string s) {
  425. std::string r;
  426. for (unsigned int i = 0; i < s.size(); i++) {
  427. char buf[5];
  428. unsigned char c = s[i];
  429. if (c == '\t' || c == '\r' || c == '\n' || (0x20 <= c && c <= 0x7e)) {
  430. r += c;
  431. } else {
  432. Snprintf(buf, sizeof(buf), "\\x%02X", c);
  433. r += buf;
  434. }
  435. }
  436. return r;
  437. }
  438. /* Do something to protect characters that can't appear in XML. This is not a
  439. reversible transform, more a last-ditch effort to write readable XML with
  440. characters that shouldn't be part of regular output anyway. The escaping that
  441. xml_write_escaped is not enough; some characters are not allowed to appear in
  442. XML, not even escaped. */
  443. std::string protect_xml(const std::string s) {
  444. /* escape_for_screen is good enough. */
  445. return escape_for_screen(s);
  446. }
  447. /* This is a helper function to determine the ordering of the script results
  448. based on their id. */
  449. static bool scriptid_lessthan(ScriptResult a, ScriptResult b) {
  450. return strcmp(a.get_id(), b.get_id()) < 0;
  451. }
  452. static char *formatScriptOutput(ScriptResult sr) {
  453. std::vector<std::string> lines;
  454. std::string c_output;
  455. const char *p, *q;
  456. std::string result;
  457. unsigned int i;
  458. c_output = escape_for_screen(sr.get_output_str());
  459. if (c_output.empty())
  460. return NULL;
  461. p = c_output.c_str();
  462. while (*p != '\0') {
  463. q = strchr(p, '\n');
  464. if (q == NULL) {
  465. lines.push_back(std::string(p));
  466. break;
  467. } else {
  468. lines.push_back(std::string(p, q - p));
  469. p = q + 1;
  470. }
  471. }
  472. if (lines.empty())
  473. lines.push_back("");
  474. for (i = 0; i < lines.size(); i++) {
  475. if (i < lines.size() - 1)
  476. result += "| ";
  477. else
  478. result += "|_";
  479. if (i == 0)
  480. result += std::string(sr.get_id()) + ": ";
  481. result += lines[i];
  482. if (i < lines.size() - 1)
  483. result += "\n";
  484. }
  485. return strdup(result.c_str());
  486. }
  487. #endif /* NOLUA */
  488. /* Prints the familiar Nmap tabular output showing the "interesting"
  489. ports found on the machine. It also handles the Machine/Greppable
  490. output and the XML output. It is pretty ugly -- in particular I
  491. should write helper functions to handle the table creation */
  492. void printportoutput(Target *currenths, PortList *plist) {
  493. char protocol[MAX_IPPROTOSTRLEN + 1];
  494. char portinfo[64];
  495. char grepvers[256];
  496. char *p;
  497. const char *state;
  498. char serviceinfo[64];
  499. int i;
  500. int first = 1;
  501. struct protoent *proto;
  502. Port *current;
  503. Port port;
  504. char hostname[1200];
  505. struct serviceDeductions sd;
  506. NmapOutputTable *Tbl = NULL;
  507. int portcol = -1; // port or IP protocol #
  508. int statecol = -1; // port/protocol state
  509. int servicecol = -1; // service or protocol name
  510. int versioncol = -1;
  511. int reasoncol = -1;
  512. int colno = 0;
  513. unsigned int rowno;
  514. int numrows;
  515. int numignoredports = plist->numIgnoredPorts();
  516. int numports = plist->numPorts();
  517. std::vector<const char *> saved_servicefps;
  518. if (o.noportscan)
  519. return;
  520. xml_start_tag("ports");
  521. int prevstate = PORT_UNKNOWN;
  522. int istate;
  523. while ((istate = plist->nextIgnoredState(prevstate)) != PORT_UNKNOWN) {
  524. xml_open_start_tag("extraports");
  525. xml_attribute("state", "%s", statenum2str(istate));
  526. xml_attribute("count", "%d", plist->getStateCounts(istate));
  527. xml_close_start_tag();
  528. xml_newline();
  529. print_xml_state_summary(plist, istate);
  530. xml_end_tag();
  531. xml_newline();
  532. prevstate = istate;
  533. }
  534. if (numignoredports == numports) {
  535. if (numignoredports == 0) {
  536. log_write(LOG_PLAIN, "0 ports scanned on %s\n",
  537. currenths->NameIP(hostname, sizeof(hostname)));
  538. } else {
  539. log_write(LOG_PLAIN, "%s %d scanned %s on %s %s ",
  540. (numignoredports == 1) ? "The" : "All", numignoredports,
  541. (numignoredports == 1) ? "port" : "ports",
  542. currenths->NameIP(hostname, sizeof(hostname)),
  543. (numignoredports == 1) ? "is" : "are");
  544. if (plist->numIgnoredStates() == 1) {
  545. log_write(LOG_PLAIN, "%s", statenum2str(plist->nextIgnoredState(PORT_UNKNOWN)));
  546. } else {
  547. prevstate = PORT_UNKNOWN;
  548. while ((istate = plist->nextIgnoredState(prevstate)) != PORT_UNKNOWN) {
  549. if (prevstate != PORT_UNKNOWN)
  550. log_write(LOG_PLAIN, " or ");
  551. log_write(LOG_PLAIN, "%s (%d)", statenum2str(istate),
  552. plist->getStateCounts(istate));
  553. prevstate = istate;
  554. }
  555. }
  556. if (o.reason)
  557. print_state_summary(plist, STATE_REASON_EMPTY);
  558. log_write(LOG_PLAIN, "\n");
  559. }
  560. log_write(LOG_MACHINE, "Host: %s (%s)\tStatus: Up",
  561. currenths->targetipstr(), currenths->HostName());
  562. xml_end_tag(); /* ports */
  563. xml_newline();
  564. return;
  565. }
  566. if (o.verbose > 1 || o.debugging) {
  567. time_t tm_secs, tm_sece;
  568. struct tm *tm;
  569. char tbufs[128];
  570. tm_secs = currenths->StartTime();
  571. tm_sece = currenths->EndTime();
  572. tm = localtime(&tm_secs);
  573. if (strftime(tbufs, sizeof(tbufs), "%Y-%m-%d %H:%M:%S %Z", tm) <= 0)
  574. fatal("Unable to properly format host start time");
  575. log_write(LOG_PLAIN, "Scanned at %s for %lds\n",
  576. tbufs, (long) (tm_sece - tm_secs));
  577. }
  578. log_write(LOG_MACHINE, "Host: %s (%s)", currenths->targetipstr(),
  579. currenths->HostName());
  580. /* Show line like:
  581. Not shown: 3995 closed ports, 514 filtered ports
  582. if appropriate (note that states are reverse-sorted by # of ports) */
  583. prevstate = PORT_UNKNOWN;
  584. while ((istate = plist->nextIgnoredState(prevstate)) != PORT_UNKNOWN) {
  585. if (prevstate == PORT_UNKNOWN)
  586. log_write(LOG_PLAIN, "Not shown: ");
  587. else
  588. log_write(LOG_PLAIN, ", ");
  589. char desc[32];
  590. if (o.ipprotscan)
  591. Snprintf(desc, sizeof(desc),
  592. (plist->getStateCounts(istate) ==
  593. 1) ? "protocol" : "protocols");
  594. else
  595. Snprintf(desc, sizeof(desc),
  596. (plist->getStateCounts(istate) == 1) ? "port" : "ports");
  597. log_write(LOG_PLAIN, "%d %s %s", plist->getStateCounts(istate),
  598. statenum2str(istate), desc);
  599. prevstate = istate;
  600. }
  601. if (prevstate != PORT_UNKNOWN)
  602. log_write(LOG_PLAIN, "\n");
  603. if (o.reason)
  604. print_state_summary(plist, STATE_REASON_FULL);
  605. /* OK, now it is time to deal with the service table ... */
  606. colno = 0;
  607. portcol = colno++;
  608. statecol = colno++;
  609. servicecol = colno++;
  610. if (o.reason)
  611. reasoncol = colno++;
  612. if (o.servicescan)
  613. versioncol = colno++;
  614. numrows = numports - numignoredports;
  615. #ifndef NOLUA
  616. int scriptrows = 0;
  617. if (plist->numscriptresults > 0)
  618. scriptrows = plist->numscriptresults;
  619. numrows += scriptrows;
  620. #endif
  621. assert(numrows > 0);
  622. numrows++; // The header counts as a row
  623. Tbl = new NmapOutputTable(numrows, colno);
  624. // Lets start with the headers
  625. if (o.ipprotscan)
  626. Tbl->addItem(0, portcol, false, "PROTOCOL", 8);
  627. else
  628. Tbl->addItem(0, portcol, false, "PORT", 4);
  629. Tbl->addItem(0, statecol, false, "STATE", 5);
  630. Tbl->addItem(0, servicecol, false, "SERVICE", 7);
  631. if (versioncol > 0)
  632. Tbl->addItem(0, versioncol, false, "VERSION", 7);
  633. if (reasoncol > 0)
  634. Tbl->addItem(0, reasoncol, false, "REASON", 6);
  635. log_write(LOG_MACHINE, "\t%s: ", (o.ipprotscan) ? "Protocols" : "Ports");
  636. rowno = 1;
  637. if (o.ipprotscan) {
  638. current = NULL;
  639. while ((current = plist->nextPort(current, &port, IPPROTO_IP, 0)) != NULL) {
  640. if (!plist->isIgnoredState(current->state)) {
  641. if (!first)
  642. log_write(LOG_MACHINE, ", ");
  643. else
  644. first = 0;
  645. if (o.reason)
  646. Tbl->addItem(rowno, reasoncol, true, port_reason_str(current->reason));
  647. state = statenum2str(current->state);
  648. proto = nmap_getprotbynum(current->portno);
  649. Snprintf(portinfo, sizeof(portinfo), "%s", proto ? proto->p_name : "unknown");
  650. Tbl->addItemFormatted(rowno, portcol, false, "%d", current->portno);
  651. Tbl->addItem(rowno, statecol, true, state);
  652. Tbl->addItem(rowno, servicecol, true, portinfo);
  653. log_write(LOG_MACHINE, "%d/%s/%s/", current->portno, state,
  654. (proto) ? proto->p_name : "");
  655. xml_open_start_tag("port");
  656. xml_attribute("protocol", "ip");
  657. xml_attribute("portid", "%d", current->portno);
  658. xml_close_start_tag();
  659. xml_open_start_tag("state");
  660. xml_attribute("state", "%s", state);
  661. xml_attribute("reason", "%s", reason_str(current->reason.reason_id, SINGULAR));
  662. xml_attribute("reason_ttl", "%d", current->reason.ttl);
  663. if (current->reason.ip_addr.sockaddr.sa_family != AF_UNSPEC) {
  664. struct sockaddr_storage ss;
  665. memcpy(&ss, &current->reason.ip_addr, sizeof(current->reason.ip_addr));
  666. xml_attribute("reason_ip", "%s", inet_ntop_ez(&ss, sizeof(ss)));
  667. }
  668. xml_close_empty_tag();
  669. if (proto && proto->p_name && *proto->p_name) {
  670. xml_newline();
  671. xml_open_start_tag("service");
  672. xml_attribute("name", "%s", proto->p_name);
  673. xml_attribute("conf", "8");
  674. xml_attribute("method", "table");
  675. xml_close_empty_tag();
  676. }
  677. xml_end_tag(); /* port */
  678. xml_newline();
  679. rowno++;
  680. }
  681. }
  682. } else {
  683. char fullversion[160];
  684. current = NULL;
  685. while ((current = plist->nextPort(current, &port, TCPANDUDPANDSCTP, 0)) != NULL) {
  686. if (!plist->isIgnoredState(current->state)) {
  687. if (!first)
  688. log_write(LOG_MACHINE, ", ");
  689. else
  690. first = 0;
  691. strcpy(protocol, IPPROTO2STR(current->proto));
  692. Snprintf(portinfo, sizeof(portinfo), "%d/%s", current->portno, protocol);
  693. state = statenum2str(current->state);
  694. plist->getServiceDeductions(current->portno, current->proto, &sd);
  695. if (sd.service_fp && saved_servicefps.size() <= 8)
  696. saved_servicefps.push_back(sd.service_fp);
  697. current->getNmapServiceName(serviceinfo, sizeof(serviceinfo));
  698. Tbl->addItem(rowno, portcol, true, portinfo);
  699. Tbl->addItem(rowno, statecol, false, state);
  700. Tbl->addItem(rowno, servicecol, true, serviceinfo);
  701. if (o.reason)
  702. Tbl->addItem(rowno, reasoncol, true, port_reason_str(current->reason));
  703. sd.populateFullVersionString(fullversion, sizeof(fullversion));
  704. if (*fullversion && versioncol > 0)
  705. Tbl->addItem(rowno, versioncol, true, fullversion);
  706. // How should we escape illegal chars in grepable output?
  707. // Well, a reasonably clean way would be backslash escapes
  708. // such as \/ and \\ . // But that makes it harder to pick
  709. // out fields with awk, cut, and such. So I'm gonna use the
  710. // ugly hack (fitting to grepable output) of replacing the '/'
  711. // character with '|' in the version field.
  712. Strncpy(grepvers, fullversion, sizeof(grepvers) / sizeof(*grepvers));
  713. p = grepvers;
  714. while ((p = strchr(p, '/'))) {
  715. *p = '|';
  716. p++;
  717. }
  718. if (!sd.name)
  719. serviceinfo[0] = '\0';
  720. else {
  721. p = serviceinfo;
  722. while ((p = strchr(p, '/'))) {
  723. *p = '|';
  724. p++;
  725. }
  726. }
  727. log_write(LOG_MACHINE, "%d/%s/%s//%s//%s/", current->portno,
  728. state, protocol, serviceinfo, grepvers);
  729. xml_open_start_tag("port");
  730. xml_attribute("protocol", "%s", protocol);
  731. xml_attribute("portid", "%d", current->portno);
  732. xml_close_start_tag();
  733. xml_open_start_tag("state");
  734. xml_attribute("state", "%s", state);
  735. xml_attribute("reason", "%s", reason_str(current->reason.reason_id, SINGULAR));
  736. xml_attribute("reason_ttl", "%d", current->reason.ttl);
  737. if (current->reason.ip_addr.sockaddr.sa_family != AF_UNSPEC) {
  738. struct sockaddr_storage ss;
  739. memcpy(&ss, &current->reason.ip_addr, sizeof(current->reason.ip_addr));
  740. xml_attribute("reason_ip", "%s", inet_ntop_ez(&ss, sizeof(ss)));
  741. }
  742. xml_close_empty_tag();
  743. if (sd.name || sd.service_fp || sd.service_tunnel != SERVICE_TUNNEL_NONE)
  744. print_xml_service(&sd);
  745. rowno++;
  746. #ifndef NOLUA
  747. if (o.script) {
  748. ScriptResults::const_iterator ssr_iter;
  749. //Sort the results before outputing them on the screen
  750. current->scriptResults.sort(scriptid_lessthan);
  751. for (ssr_iter = current->scriptResults.begin();
  752. ssr_iter != current->scriptResults.end(); ssr_iter++) {
  753. ssr_iter->write_xml();
  754. char *script_output = formatScriptOutput((*ssr_iter));
  755. if (script_output != NULL) {
  756. Tbl->addItem(rowno, 0, true, true, script_output);
  757. free(script_output);
  758. }
  759. rowno++;
  760. }
  761. }
  762. #endif
  763. xml_end_tag(); /* port */
  764. xml_newline();
  765. }
  766. }
  767. }
  768. /* log_write(LOG_PLAIN,"\n"); */
  769. /* Grepable output supports only one ignored state. */
  770. if (plist->numIgnoredStates() == 1) {
  771. istate = plist->nextIgnoredState(PORT_UNKNOWN);
  772. if (plist->getStateCounts(istate) > 0)
  773. log_write(LOG_MACHINE, "\tIgnored State: %s (%d)",
  774. statenum2str(istate), plist->getStateCounts(istate));
  775. }
  776. xml_end_tag(); /* ports */
  777. xml_newline();
  778. // Now we write the table for the user
  779. log_write(LOG_PLAIN, "%s", Tbl->printableTable(NULL));
  780. delete Tbl;
  781. // There may be service fingerprints I would like the user to submit
  782. if (saved_servicefps.size() > 0) {
  783. int numfps = saved_servicefps.size();
  784. log_write(LOG_PLAIN, "%d service%s unrecognized despite returning data."
  785. " If you know the service/version, please submit the following"
  786. " fingerprint%s at"
  787. " http://www.insecure.org/cgi-bin/servicefp-submit.cgi :\n",
  788. numfps, (numfps > 1) ? "s" : "", (numfps > 1) ? "s" : "");
  789. for (i = 0; i < numfps; i++) {
  790. if (numfps > 1)
  791. log_write(LOG_PLAIN, "==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============\n");
  792. log_write(LOG_PLAIN, "%s\n", saved_servicefps[i]);
  793. }
  794. }
  795. log_flush_all();
  796. }
  797. char *logfilename(const char *str, struct tm *tm) {
  798. char *ret, *end, *p;
  799. char tbuf[10];
  800. int retlen = strlen(str) * 6 + 1;
  801. ret = (char *) safe_malloc(retlen);
  802. end = ret + retlen;
  803. for (p = ret; *str; str++) {
  804. if (*str == '%') {
  805. str++;
  806. if (!*str)
  807. break;
  808. switch (*str) {
  809. case 'H':
  810. strftime(tbuf, sizeof tbuf, "%H", tm);
  811. break;
  812. case 'M':
  813. strftime(tbuf, sizeof tbuf, "%M", tm);
  814. break;
  815. case 'S':
  816. strftime(tbuf, sizeof tbuf, "%S", tm);
  817. break;
  818. case 'T':
  819. strftime(tbuf, sizeof tbuf, "%H%M%S", tm);
  820. break;
  821. case 'R':
  822. strftime(tbuf, sizeof tbuf, "%H%M", tm);
  823. break;
  824. case 'm':
  825. strftime(tbuf, sizeof tbuf, "%m", tm);
  826. break;
  827. case 'd':
  828. strftime(tbuf, sizeof tbuf, "%d", tm);
  829. break;
  830. case 'y':
  831. strftime(tbuf, sizeof tbuf, "%y", tm);
  832. break;
  833. case 'Y':
  834. strftime(tbuf, sizeof tbuf, "%Y", tm);
  835. break;
  836. case 'D':
  837. strftime(tbuf, sizeof tbuf, "%m%d%y", tm);
  838. break;
  839. default:
  840. *p++ = *str;
  841. continue;
  842. }
  843. assert(end - p > 1);
  844. Strncpy(p, tbuf, end - p - 1);
  845. p += strlen(tbuf);
  846. } else {
  847. *p++ = *str;
  848. }
  849. }
  850. *p = 0;
  851. return (char *) safe_realloc(ret, strlen(ret) + 1);
  852. }
  853. /* This is the workhorse of the logging functions. Usually it is
  854. called through log_write(), but it can be called directly if you are dealing
  855. with a vfprintf-style va_list. YOU MUST SANDWHICH EACH EXECUTION IF THIS CALL
  856. BETWEEN va_start() AND va_end() calls. */
  857. void log_vwrite(int logt, const char *fmt, va_list ap) {
  858. char *writebuf;
  859. bool skid_noxlate = false;
  860. int rc = 0;
  861. int len;
  862. int fileidx = 0;
  863. int l;
  864. int logtype;
  865. va_list apcopy;
  866. for (logtype = 1; logtype <= LOG_MAX; logtype <<= 1) {
  867. if (!(logt & logtype))
  868. continue;
  869. switch (logtype) {
  870. case LOG_STDOUT:
  871. vfprintf(o.nmap_stdout, fmt, ap);
  872. break;
  873. case LOG_STDERR:
  874. fflush(stdout); // Otherwise some systems will print stderr out of order
  875. vfprintf(stderr, fmt, ap);
  876. break;
  877. case LOG_SKID_NOXLT:
  878. skid_noxlate = true;
  879. /* no break */
  880. case LOG_NORMAL:
  881. case LOG_MACHINE:
  882. case LOG_SKID:
  883. case LOG_XML:
  884. len = alloc_vsprintf(&writebuf, fmt, ap);
  885. if (writebuf == NULL)
  886. fatal("%s: alloc_vsprintf failed.", __func__);
  887. if (logtype == LOG_SKID_NOXLT)
  888. l = LOG_SKID;
  889. else
  890. l = logtype;
  891. fileidx = 0;
  892. while ((l & 1) == 0) {
  893. fileidx++;
  894. l >>= 1;
  895. }
  896. assert(fileidx < LOG_NUM_FILES);
  897. if (o.logfd[fileidx] && len) {
  898. if ((logtype & (LOG_SKID|LOG_SKID_NOXLT)) && !skid_noxlate)
  899. skid_output(writebuf);
  900. rc = fwrite(writebuf, len, 1, o.logfd[fileidx]);
  901. if (rc != 1) {
  902. fatal("Failed to write %d bytes of data to (logt==%d) stream. fwrite returned %d. Quitting.", len, logtype, rc);
  903. }
  904. va_end(apcopy);
  905. }
  906. free(writebuf);
  907. break;
  908. default:
  909. /* Unknown log type.
  910. * ---
  911. * Note that we're not calling fatal() here to avoid infinite call loop
  912. * between fatal() and this log_vwrite() function. */
  913. assert(0); /* We want people to report it. */
  914. }
  915. }
  916. return;
  917. }
  918. /* Write some information (printf style args) to the given log stream(s).
  919. Remember to watch out for format string bugs. */
  920. void log_write(int logt, const char *fmt, ...) {
  921. va_list ap;
  922. assert(logt > 0);
  923. if (!fmt || !*fmt)
  924. return;
  925. for (int l = 1; l <= LOG_MAX; l <<= 1) {
  926. if (logt & l) {
  927. va_start(ap, fmt);
  928. log_vwrite(l, fmt, ap);
  929. va_end(ap);
  930. }
  931. }
  932. return;
  933. }
  934. /* Close the given log stream(s) */
  935. void log_close(int logt) {
  936. int i;
  937. if (logt < 0 || logt > LOG_FILE_MASK)
  938. return;
  939. for (i = 0; logt; logt >>= 1, i++)
  940. if (o.logfd[i] && (logt & 1))
  941. fclose(o.logfd[i]);
  942. }
  943. /* Flush the given log stream(s). In other words, all buffered output
  944. is written to the log immediately */
  945. void log_flush(int logt) {
  946. int i;
  947. if (logt & LOG_STDOUT) {
  948. fflush(o.nmap_stdout);
  949. logt -= LOG_STDOUT;
  950. }
  951. if (logt & LOG_STDERR) {
  952. fflush(stderr);
  953. logt -= LOG_STDERR;
  954. }
  955. if (logt & LOG_SKID_NOXLT)
  956. fatal("You are not allowed to %s() with LOG_SKID_NOXLT", __func__);
  957. if (logt < 0 || logt > LOG_FILE_MASK)
  958. return;
  959. for (i = 0; logt; logt >>= 1, i++) {
  960. if (!o.logfd[i] || !(logt & 1))
  961. continue;
  962. fflush(o.logfd[i]);
  963. }
  964. }
  965. /* Flush every single log stream -- all buffered output is written to the
  966. corresponding logs immediately */
  967. void log_flush_all() {
  968. int fileno;
  969. for (fileno = 0; fileno < LOG_NUM_FILES; fileno++) {
  970. if (o.logfd[fileno])
  971. fflush(o.logfd[fileno]);
  972. }
  973. fflush(stdout);
  974. fflush(stderr);
  975. }
  976. /* Open a log descriptor of the type given to the filename given. If
  977. append is nonzero, the file will be appended instead of clobbered if
  978. it already exists. If the file does not exist, it will be created */
  979. int log_open(int logt, int append, char *filename) {
  980. int i = 0;
  981. if (logt <= 0 || logt > LOG_FILE_MASK)
  982. return -1;
  983. while ((logt & 1) == 0) {
  984. i++;
  985. logt >>= 1;
  986. }
  987. if (o.logfd[i])
  988. fatal("Only one %s output filename allowed", logtypes[i]);
  989. if (*filename == '-' && *(filename + 1) == '\0') {
  990. o.logfd[i] = stdout;
  991. o.nmap_stdout = fopen(DEVNULL, "w");
  992. if (!o.nmap_stdout)
  993. fatal("Could not assign %s to stdout for writing", DEVNULL);
  994. } else {
  995. if (append)
  996. o.logfd[i] = fopen(filename, "a");
  997. else
  998. o.logfd[i] = fopen(filename, "w");
  999. if (!o.logfd[i])
  1000. fatal("Failed to open %s output file %s for writing", logtypes[i],
  1001. filename);
  1002. }
  1003. return 1;
  1004. }
  1005. /* The items in ports should be
  1006. in sequential order for space savings and easier to read output. Outputs the
  1007. rangelist to the log stream given (such as LOG_MACHINE or LOG_XML) */
  1008. static void output_rangelist_given_ports(int logt, unsigned short *ports,
  1009. int numports) {
  1010. int start, end;
  1011. start = 0;
  1012. while (start < numports) {
  1013. end = start;
  1014. while (end + 1 < numports && ports[end + 1] == ports[end] + 1)
  1015. end++;
  1016. if (start > 0)
  1017. log_write(logt, ",");
  1018. if (start == end)
  1019. log_write(logt, "%hu", ports[start]);
  1020. else
  1021. log_write(logt, "%hu-%hu", ports[start], ports[end]);
  1022. start = end + 1;
  1023. }
  1024. }
  1025. /* Output the list of ports scanned to the top of machine parseable
  1026. logs (in a comment, unfortunately). The items in ports should be
  1027. in sequential order for space savings and easier to read output */
  1028. void output_ports_to_machine_parseable_output(struct scan_lists *ports) {
  1029. int tcpportsscanned = ports->tcp_count;
  1030. int udpportsscanned = ports->udp_count;
  1031. int sctpportsscanned = ports->sctp_count;
  1032. int protsscanned = ports->prot_count;
  1033. log_write(LOG_MACHINE, "# Ports scanned: TCP(%d;", tcpportsscanned);
  1034. if (tcpportsscanned)
  1035. output_rangelist_given_ports(LOG_MACHINE, ports->tcp_ports, tcpportsscanned);
  1036. log_write(LOG_MACHINE, ") UDP(%d;", udpportsscanned);
  1037. if (udpportsscanned)
  1038. output_rangelist_given_ports(LOG_MACHINE, ports->udp_ports, udpportsscanned);
  1039. log_write(LOG_MACHINE, ") SCTP(%d;", sctpportsscanned);
  1040. if (sctpportsscanned)
  1041. output_rangelist_given_ports(LOG_MACHINE, ports->sctp_ports, sctpportsscanned);
  1042. log_write(LOG_MACHINE, ") PROTOCOLS(%d;", protsscanned);
  1043. if (protsscanned)
  1044. output_rangelist_given_ports(LOG_MACHINE, ports->prots, protsscanned);
  1045. log_write(LOG_MACHINE, ")\n");
  1046. log_flush_all();
  1047. }
  1048. // A simple helper function for doscaninfo handles the c14n of o.scanflags
  1049. static void doscanflags() {
  1050. struct {
  1051. unsigned char flag;
  1052. const char *name;
  1053. } flags[] = {
  1054. { TH_FIN, "FIN" },
  1055. { TH_SYN, "SYN" },
  1056. { TH_RST, "RST" },
  1057. { TH_PUSH, "PSH" },
  1058. { TH_ACK, "ACK" },
  1059. { TH_URG, "URG" },
  1060. { TH_ECE, "ECE" },
  1061. { TH_CWR, "CWR" }
  1062. };
  1063. if (o.scanflags != -1) {
  1064. std::string flagstring;
  1065. for (unsigned int i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
  1066. if (o.scanflags & flags[i].flag)
  1067. flagstring += flags[i].name;
  1068. }
  1069. xml_attribute("scanflags", "%s", flagstring.c_str());
  1070. }
  1071. }
  1072. /* Simple helper function for output_xml_scaninfo_records */
  1073. static void doscaninfo(const char *type, const char *proto,
  1074. unsigned short *ports, int numports) {
  1075. xml_open_start_tag("scaninfo");
  1076. xml_attribute("type", "%s", type);
  1077. if (strncmp(proto, "tcp", 3) == 0) {
  1078. doscanflags();
  1079. }
  1080. xml_attribute("protocol", "%s", proto);
  1081. xml_attribute("numservices", "%d", numports);
  1082. xml_write_raw(" services=\"");
  1083. output_rangelist_given_ports(LOG_XML, ports, numports);
  1084. xml_write_raw("\"");
  1085. xml_close_empty_tag();
  1086. xml_newline();
  1087. }
  1088. static std::string quote(const char *s) {
  1089. std::string result("");
  1090. const char *p;
  1091. bool space;
  1092. space = false;
  1093. for (p = s; *p != '\0'; p++) {
  1094. if (isspace(*p))
  1095. space = true;
  1096. if (*p == '"' || *p == '\\')
  1097. result += "\\";
  1098. result += *p;
  1099. }
  1100. if (space)
  1101. result = "\"" + result + "\"";
  1102. return result;
  1103. }
  1104. /* Return a std::string containing all n strings separated by whitespace, and
  1105. individually quoted if needed. */
  1106. std::string join_quoted(const char * const strings[], unsigned int n) {
  1107. std::string result("");
  1108. unsigned int i;
  1109. for (i = 0; i < n; i++) {
  1110. if (i > 0)
  1111. result += " ";
  1112. result += quote(strings[i]);
  1113. }
  1114. return result;
  1115. }
  1116. /* Similar to output_ports_to_machine_parseable_output, this function
  1117. outputs the XML version, which is scaninfo records of each scan
  1118. requested and the ports which it will scan for */
  1119. void output_xml_scaninfo_records(struct scan_lists *scanlist) {
  1120. if (o.synscan)
  1121. doscaninfo("syn", "tcp", scanlist->tcp_ports, scanlist->tcp_count);
  1122. if (o.ackscan)
  1123. doscaninfo("ack", "tcp", scanlist->tcp_ports, scanlist->tcp_count);
  1124. if (o.bouncescan)
  1125. doscaninfo("bounce", "tcp", scanlist->tcp_ports, scanlist->tcp_count);
  1126. if (o.connectscan)
  1127. doscaninfo("connect", "tcp", scanlist->tcp_ports, scanlist->tcp_count);
  1128. if (o.nullscan)
  1129. doscaninfo("null", "tcp", scanlist->tcp_ports, scanlist->tcp_count);
  1130. if (o.xmasscan)
  1131. doscaninfo("xmas", "tcp", scanlist->tcp_ports, scanlist->tcp_count);
  1132. if (o.windowscan)
  1133. doscaninfo("window", "tcp", scanlist->tcp_ports, scanlist->tcp_count);
  1134. if (o.maimonscan)
  1135. doscaninfo("maimon", "tcp", scanlist->tcp_ports, scanlist->tcp_count);
  1136. if (o.finscan)
  1137. doscaninfo("fin", "tcp", scanlist->tcp_ports, scanlist->tcp_count);
  1138. if (o.udpscan)
  1139. doscaninfo("udp", "udp", scanlist->udp_ports, scanlist->udp_count);
  1140. if (o.sctpinitscan)
  1141. doscaninfo("sctpinit", "sctp", scanlist->sctp_ports, scanlist->sctp_count);
  1142. if (o.sctpcookieechoscan)
  1143. doscaninfo("sctpcookieecho", "sctp", scanlist->sctp_ports, scanlist->sctp_count);
  1144. if (o.ipprotscan)
  1145. doscaninfo("ipproto", "ip", scanlist->prots, scanlist->prot_count);
  1146. log_flush_all();
  1147. }
  1148. /* Prints the MAC address (if discovered) to XML output */
  1149. static void print_MAC_XML_Info(Target *currenths) {
  1150. const u8 *mac = currenths->MACAddress();
  1151. char macascii[32];
  1152. if (mac) {
  1153. const char *macvendor = MACPrefix2Corp(mac);
  1154. Snprintf(macascii, sizeof(macascii), "%02X:%02X:%02X:%02X:%02X:%02X",
  1155. mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  1156. xml_open_start_tag("address");
  1157. xml_attribute("addr", "%s", macascii);
  1158. xml_attribute("addrtype", "mac");
  1159. if (macvendor)
  1160. xml_attribute("vendor", "%s", macvendor);
  1161. xml_close_empty_tag();
  1162. xml_newline();
  1163. }
  1164. }
  1165. /* Helper function to write the status and address/hostname info of a host
  1166. into the XML log */
  1167. static void write_xml_initial_hostinfo(Target *currenths,
  1168. const char *status) {
  1169. xml_open_start_tag("status");
  1170. xml_attribute("state", "%s", status);
  1171. xml_attribute("reason", "%s", reason_str(currenths->reason.reason_id, SINGULAR));
  1172. xml_attribute("reason_ttl", "%d", currenths->reason.ttl);
  1173. xml_close_empty_tag();
  1174. xml_newline();
  1175. xml_open_start_tag("address");
  1176. xml_attribute("addr", "%s", currenths->targetipstr());
  1177. xml_attribute("addrtype", "%s", (o.af() == AF_INET) ? "ipv4" : "ipv6");
  1178. xml_close_empty_tag();
  1179. xml_newline();
  1180. print_MAC_XML_Info(currenths);
  1181. /* Output a hostnames element whenever we have a name to write or the target
  1182. is up. */
  1183. if (currenths->TargetName() != NULL || *currenths->HostName() || strcmp(status, "up") == 0) {
  1184. xml_start_tag("hostnames");
  1185. xml_newline();
  1186. if (currenths->TargetName() != NULL) {
  1187. xml_open_start_tag("hostname");
  1188. xml_attribute("name", "%s", currenths->TargetName());
  1189. xml_attribute("type", "user");
  1190. xml_close_empty_tag();
  1191. xml_newline();
  1192. }
  1193. if (*currenths->HostName()) {
  1194. xml_open_start_tag("hostname");
  1195. xml_attribute("name", "%s", currenths->HostName());
  1196. xml_attribute("type", "PTR");
  1197. xml_close_empty_tag();
  1198. xml_newline();
  1199. }
  1200. xml_end_tag();
  1201. xml_newline();
  1202. }
  1203. log_flush_all();
  1204. }
  1205. static void write_xml_osclass(const OS_Classification *osclass, double accuracy) {
  1206. xml_open_start_tag("osclass");
  1207. xml_attribute("type", "%s", osclass->Device_Type);
  1208. xml_attribute("vendor", "%s", osclass->OS_Vendor);
  1209. xml_attribute("osfamily", "%s", osclass->OS_Family);
  1210. // Because the OS_Generation field is optional.
  1211. if (osclass->OS_Generation)
  1212. xml_attribute("osgen", "%s", osclass->OS_Generation);
  1213. xml_attribute("accuracy", "%d", (int) (accuracy * 100));
  1214. if (osclass->cpe.empty()) {
  1215. xml_close_empty_tag();
  1216. } else {
  1217. unsigned int i;
  1218. xml_close_start_tag();
  1219. for (i = 0; i < osclass->cpe.size(); i++) {
  1220. xml_start_tag("cpe");
  1221. xml_write_escaped("%s", osclass->cpe[i]);
  1222. xml_end_tag();
  1223. }
  1224. xml_end_tag();
  1225. }
  1226. xml_newline();
  1227. }
  1228. static void write_xml_osmatch(const FingerMatch *match, double accuracy) {
  1229. xml_open_start_tag("osmatch");
  1230. xml_attribute("name", "%s", match->OS_name);
  1231. xml_attribute("accuracy", "%d", (int) (accuracy * 100));
  1232. xml_attribute("line", "%d", match->line);
  1233. /* When o.deprecated_xml_osclass is true, we don't write osclass elements as
  1234. children of osmatch but rather as unrelated siblings. */
  1235. if (match->OS_class.empty() || o.deprecated_xml_osclass) {
  1236. xml_close_empty_tag();
  1237. } else {
  1238. unsigned int i;
  1239. xml_close_start_tag();
  1240. xml_newline();
  1241. for (i = 0; i < match->OS_class.size(); i++)
  1242. write_xml_osclass(&match->OS_class[i], accuracy);
  1243. xml_end_tag();
  1244. }
  1245. xml_newline();
  1246. }
  1247. /* Convert a number to a string, keeping the given number of significant digits.
  1248. The result is returned in a static buffer. */
  1249. static char *num_to_string_sigdigits(double d, int digits) {
  1250. static char buf[32];
  1251. int shift;
  1252. int n;
  1253. assert(digits >= 0);
  1254. if (d == 0.0) {
  1255. shift = -digits;
  1256. } else {
  1257. shift = (int) floor(log10(fabs(d))) - digits + 1;
  1258. d = floo

Large files files are truncated, but you can click here to view the full file