diff --git a/Makefile.in b/Makefile.in index 6ad8ec622..4172ae621 100644 --- a/Makefile.in +++ b/Makefile.in @@ -51,11 +51,11 @@ TARGETNMAPFE=@TARGETNMAPFE@ INSTALLNMAPFE=@INSTALLNMAPFE@ INSTALLNSE=@INSTALLNSE@ -export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc osscan2.cc output.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 nse_main.cc nse_auxiliar.cc nse_nsock.cc nse_init.cc nse_nmaplib.cc nse_debug.cc nse_bitlib.cc nse_pcrelib.cc nse_string.cc traceroute.cc @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 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 nse_main.cc nse_auxiliar.cc nse_nsock.cc nse_init.cc nse_nmaplib.cc nse_debug.cc nse_bitlib.cc nse_pcrelib.cc nse_string.cc traceroute.cc reason.cc @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 portlist.h protocols.h scan_engine.h service_scan.h services.h TargetGroup.h Target.h targets.h tcpip.h timing.h utils.h nse_main.h nse_auxiliar.h nse_nsock.h nse_init.h nse_nmaplib.h nse_debug.h nse_macros.h nse_bitlib.h nse_pcrelib.h nse_string.h traceroute.h +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 portlist.h protocols.h scan_engine.h service_scan.h services.h TargetGroup.h Target.h targets.h tcpip.h timing.h utils.h nse_main.h nse_auxiliar.h nse_nsock.h nse_init.h nse_nmaplib.h nse_debug.h nse_macros.h nse_bitlib.h nse_pcrelib.h nse_string.h traceroute.h reason.h -OBJS = main.o nmap.o targets.o tcpip.o nmap_error.o utils.o idle_scan.o osscan.o osscan2.o output.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 nse_main.o nse_auxiliar.o nse_nsock.o nse_init.o nse_nmaplib.o nse_debug.o nse_bitlib.o nse_pcrelib.o nse_string.o traceroute.o @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 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 nse_main.o nse_auxiliar.o nse_nsock.o nse_init.o nse_nmaplib.o nse_debug.o nse_bitlib.o nse_pcrelib.o nse_string.o traceroute.o reason.o @COMPAT_OBJS@ # %.o : %.cc -- nope this is a GNU extension .cc.o: diff --git a/NmapOps.cc b/NmapOps.cc index cfa0f6de1..dccad7985 100644 --- a/NmapOps.cc +++ b/NmapOps.cc @@ -241,6 +241,7 @@ void NmapOps::Initialize() { nmap_stdout = stdout; gettimeofday(&start_time, NULL); pTrace = vTrace = false; + reason = false; if (datadir) free(datadir); datadir = NULL; #if WIN32 diff --git a/NmapOps.h b/NmapOps.h index 9a016f836..9f86f5966 100644 --- a/NmapOps.h +++ b/NmapOps.h @@ -304,6 +304,7 @@ class NmapOps { char *dns_servers; bool log_errors; bool traceroute; + bool reason; #ifndef NOLUA int script; diff --git a/Target.cc b/Target.cc index 44b004db6..435354b96 100644 --- a/Target.cc +++ b/Target.cc @@ -104,9 +104,8 @@ #include "nmap_winconfig.h" #endif -#include - #include "Target.h" +#include #include "osscan.h" #include "nbase.h" #include "NmapOps.h" @@ -142,6 +141,7 @@ void Target::Initialize() { interface_type = devt_other; devname[0] = '\0'; devfullname[0] = '\0'; + state_reason_init(&reason); } diff --git a/Target.h b/Target.h index c4fee8ed6..d2a334d1e 100644 --- a/Target.h +++ b/Target.h @@ -106,6 +106,7 @@ #include "nmap.h" #include "FingerPrintResults.h" #include "nse_main.h" +#include "reason.h" #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 46 @@ -234,6 +235,7 @@ class Target { char *hostname; // Null if unable to resolve or unset ScriptResults scriptResults; + state_reason_t reason; private: void Initialize(); diff --git a/docs/nmap.1 b/docs/nmap.1 index 4969a9a12..730fd255d 100644 --- a/docs/nmap.1 +++ b/docs/nmap.1 @@ -118,6 +118,7 @@ SCAN TECHNIQUES: \-sO: IP protocol scan \-b : FTP bounce scan \-\-traceroute: Trace hop path to each host + \-\-reason: Display the reason a port is in a particular state PORT SPECIFICATION AND SCAN ORDER: \-p : Only scan specified ports Ex: \-p22; \-p1\-65535; \-p U:53,111,137,T:21\-25,80,139,8080 @@ -395,6 +396,9 @@ Example\ 14.3.\ Reference consolidation (hop cache).sp .fi .TP +\fB\-\-reason\fR (Host and port state reasons) +Shows the reason each port is set to a specific state and the reason each host is up or down. This option displays the type of the packet that determined a port or hosts state. For example, A RST packet from a closed port or an echo reply from an alive host. The information nmap can provide is determined by the type of scan or ping. The SYN scan and SYN ping (\fB\-sS and -PT\fR) are very detailed. Whilst the TCP connect scan and ping (\fB\-sT\fR) are limited by the implementation of connect(). This feature is automatically enabled by the debug flag (\fB\-d\fR) and the results are stored in XML log files even if this option is not specified. +.TP \fB\-n\fR (No DNS resolution) Tells Nmap to \fInever\fR diff --git a/docs/nmap.dtd b/docs/nmap.dtd index ab465eb00..4251d9308 100644 --- a/docs/nmap.dtd +++ b/docs/nmap.dtd @@ -136,7 +136,9 @@ - + - + + + + - + diff --git a/docs/nmap.usage.txt b/docs/nmap.usage.txt index 3325358ff..d9184e492 100644 --- a/docs/nmap.usage.txt +++ b/docs/nmap.usage.txt @@ -25,6 +25,7 @@ SCAN TECHNIQUES: -sO: IP protocol scan -b : FTP bounce scan --traceroute: Trace hop path to each host + --reason: Display the reason a port is in a particular state PORT SPECIFICATION AND SCAN ORDER: -p : Only scan specified ports Ex: -p22; -p1-65535; -p U:53,111,137,T:21-25,80,139,8080 diff --git a/docs/nmap.xsl b/docs/nmap.xsl index 6eb7e8803..c2e552400 100644 --- a/docs/nmap.xsl +++ b/docs/nmap.xsl @@ -459,11 +459,19 @@ +

ping results

+
  • + + from + +
+

address

  • ()
  • +
@@ -499,12 +507,21 @@ +
    + + +
  • ports replied with:

  • +
    +
    +
+ + @@ -525,6 +542,12 @@ + @@ -549,6 +572,12 @@ + @@ -560,6 +589,12 @@ + @@ -571,6 +606,12 @@ + diff --git a/idle_scan.cc b/idle_scan.cc index 46850ca00..e28a42864 100644 --- a/idle_scan.cc +++ b/idle_scan.cc @@ -1040,7 +1040,9 @@ void idle_scan(Target *target, u16 *portarray, int numports, if (target->ports.getPortEntry(portarray[portidx], IPPROTO_TCP) == NULL) { target->ports.addPort(portarray[portidx], IPPROTO_TCP, NULL, PORT_CLOSEDFILTERED); - } + target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_NOIPIDCHANGE, 0, 0); + } else + target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_IPIDCHANGE, 0, 0); } target->stopTimeOutClock(NULL); diff --git a/mswin32/nmap.sln b/mswin32/nmap.sln index a878258eb..650c48d3d 100644 --- a/mswin32/nmap.sln +++ b/mswin32/nmap.sln @@ -1,12 +1,12 @@ Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 +# Visual C++ Express 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nmap", "nmap.vcproj", "{361719F0-AB42-4C93-9DE8-7D2144B96625}" ProjectSection(ProjectDependencies) = postProject {31FB0767-A71F-4575-8379-002D72B8AF86} = {31FB0767-A71F-4575-8379-002D72B8AF86} {5DE86C7A-DE72-4265-8807-4CA38F94F22A} = {5DE86C7A-DE72-4265-8807-4CA38F94F22A} - {B630C8F7-3138-43E8-89ED-78742FA2AC5F} = {B630C8F7-3138-43E8-89ED-78742FA2AC5F} - {F8D6D1E3-D4EA-402C-98AA-168E5309BAF4} = {F8D6D1E3-D4EA-402C-98AA-168E5309BAF4} {5328E0BE-BC0A-4C2A-8CB9-CE00B61B9C4C} = {5328E0BE-BC0A-4C2A-8CB9-CE00B61B9C4C} + {F8D6D1E3-D4EA-402C-98AA-168E5309BAF4} = {F8D6D1E3-D4EA-402C-98AA-168E5309BAF4} + {B630C8F7-3138-43E8-89ED-78742FA2AC5F} = {B630C8F7-3138-43E8-89ED-78742FA2AC5F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsock", "..\nsock\nsock.vcproj", "{F8D6D1E3-D4EA-402C-98AA-168E5309BAF4}" diff --git a/mswin32/nmap.vcproj b/mswin32/nmap.vcproj index e35204589..2eaecc730 100644 --- a/mswin32/nmap.vcproj +++ b/mswin32/nmap.vcproj @@ -317,6 +317,10 @@ RelativePath="..\protocols.cc" > + + @@ -506,6 +510,10 @@ RelativePath="..\protocols.h" > + + diff --git a/nmap.cc b/nmap.cc index 59d3ae842..cfd5093ed 100644 --- a/nmap.cc +++ b/nmap.cc @@ -227,6 +227,7 @@ printf("%s %s ( %s )\n" " -sO: IP protocol scan\n" " -b : FTP bounce scan\n" " --traceroute: Trace hop path to each host\n" + " --reason: Display the reason a port is in a particular state\n" "PORT SPECIFICATION AND SCAN ORDER:\n" " -p : Only scan specified ports\n" " Ex: -p22; -p1-65535; -p U:53,111,137,T:21-25,80,139,8080\n" @@ -589,6 +590,7 @@ int nmap_main(int argc, char *argv[]) { {"badsum", no_argument, 0, 0}, {"ttl", required_argument, 0, 0}, /* Time to live */ {"traceroute", no_argument, 0, 0}, + {"reason", no_argument, 0, 0}, {"allports", no_argument, 0, 0}, {"version_intensity", required_argument, 0, 0}, {"version-intensity", required_argument, 0, 0}, @@ -852,6 +854,8 @@ int nmap_main(int argc, char *argv[]) { fatal("Ip options must be multiple of 4 (read length is %i bytes)", o.ipoptionslen); } else if(strcmp(long_options[option_index].name, "traceroute") == 0) { o.traceroute = true; + } else if(strcmp(long_options[option_index].name, "reason") == 0) { + o.reason = true; } else { fatal("Unknown long option (%s) given@#!$#$", long_options[option_index].name); } @@ -907,6 +911,7 @@ int nmap_main(int argc, char *argv[]) { else { o.debugging++; o.verbose++; } + o.reason = true; break; case 'e': Strncpy(o.device, optarg, sizeof(o.device)); break; diff --git a/output.cc b/output.cc index 2e9156043..d7c7376e9 100644 --- a/output.cc +++ b/output.cc @@ -108,6 +108,7 @@ #include "NmapOps.h" #include "NmapOutputTable.h" #include "MACLookup.h" +#include "reason.h" #include @@ -417,6 +418,7 @@ void printportoutput(Target *currenths, PortList *plist) { int statecol = -1; // port/protocol state int servicecol = -1; // service or protocol name int versioncol = -1; + int reasoncol = -1; // int ownercol = -1; // Used for ident scan int colno = 0; unsigned int rowno; @@ -428,12 +430,15 @@ void printportoutput(Target *currenths, PortList *plist) { log_write(LOG_XML, ""); int prevstate = PORT_UNKNOWN; int istate; + while ((istate = plist->nextIgnoredState(prevstate)) != PORT_UNKNOWN) { log_write(LOG_XML, "\n", statenum2str(istate), plist->getStateCounts(istate)); prevstate = istate; } + print_xml_state_summary(plist); + if (numignoredports == plist->numports) { log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, "%s %d scanned %s on %s %s ", @@ -451,6 +456,8 @@ void printportoutput(Target *currenths, PortList *plist) { prevstate = istate; } } + if(o.reason) + print_state_summary(plist, STATE_REASON_EMPTY); log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, "\n"); log_write(LOG_MACHINE,"Host: %s (%s)\tStatus: Up", @@ -481,13 +488,19 @@ void printportoutput(Target *currenths, PortList *plist) { log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, "%d %s %s", plist->getStateCounts(istate), statenum2str(istate), desc); prevstate = istate; } + if (prevstate != PORT_UNKNOWN) log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, "\n"); + if(o.reason) + print_state_summary(plist, STATE_REASON_FULL); + /* OK, now it is time to deal with the service table ... */ colno = 0; portcol = colno++; statecol = colno++; servicecol = colno++; + if(o.reason) + reasoncol = colno++; /* if (o.identscan) ownercol = colno++; */ if (o.servicescan || o.rpcscan) @@ -511,11 +524,12 @@ void printportoutput(Target *currenths, PortList *plist) { if (o.ipprotscan) Tbl->addItem(0, portcol, false, "PROTOCOL", 8); else Tbl->addItem(0, portcol, false, "PORT", 4); - Tbl->addItem(0, statecol, false, "STATE", 5); Tbl->addItem(0, servicecol, false, "SERVICE", 7); if (versioncol > 0) Tbl->addItem(0, versioncol, false, "VERSION", 7); + if(reasoncol > 0) + Tbl->addItem(0, reasoncol, false, "REASON", 6); /* if (ownercol > 0) Tbl->addItem(0, ownercol, false, "OWNER", 5); */ @@ -528,16 +542,24 @@ void printportoutput(Target *currenths, PortList *plist) { if (!plist->isIgnoredState(current->state)) { if (!first) log_write(LOG_MACHINE,", "); else first = 0; + if(o.reason) + Tbl->addItem(rowno, reasoncol, true, port_reason_str(current->reason)); state = statenum2str(current->state); proto = nmap_getprotbynum(htons(current->portno)); - snprintf(portinfo, sizeof(portinfo), "%-24s", + snprintf(portinfo, sizeof(portinfo), "%s", proto?proto->p_name: "unknown"); Tbl->addItemFormatted(rowno, portcol, false, "%d", current->portno); Tbl->addItem(rowno, statecol, true, state); Tbl->addItem(rowno, servicecol, true, portinfo); log_write(LOG_MACHINE,"%d/%s/%s/", current->portno, state, (proto)? proto->p_name : ""); - log_write(LOG_XML, "", current->portno, state); + log_write(LOG_XML, "portno, state, reason_str(current->reason.reason_id, SINGULAR), current->reason.ttl); + + if(current->reason.ip_addr.s_addr) + log_write(LOG_XML, " reason_ip=\"%s\"", inet_ntoa(current->reason.ip_addr)); + log_write(LOG_XML, "/>"); + if (proto && proto->p_name && *proto->p_name) log_write(LOG_XML, "\n", proto->p_name); log_write(LOG_XML, "\n"); @@ -595,6 +617,9 @@ void printportoutput(Target *currenths, PortList *plist) { Tbl->addItem(rowno, portcol, true, portinfo); Tbl->addItem(rowno, statecol, false, state); Tbl->addItem(rowno, servicecol, true, serviceinfo); + if(o.reason) + Tbl->addItem(rowno, reasoncol, true, port_reason_str(current->reason)); + /* if (current->owner) Tbl->addItem(rowno, ownercol, true, current->owner); */ if (*sd.fullversion) @@ -635,7 +660,11 @@ void printportoutput(Target *currenths, PortList *plist) { protocol, grepown, serviceinfo, rpcmachineinfo, grepvers); log_write(LOG_XML, "", protocol, current->portno); - log_write(LOG_XML, "", state); + log_write(LOG_XML, "reason.reason_id, SINGULAR), current->reason.ttl); + if(current->reason.ip_addr.s_addr) + log_write(LOG_XML, " reason_ip=\"%s\"", inet_ntoa(current->reason.ip_addr)); + log_write(LOG_XML, "/>"); if (current->owner && *current->owner) { log_write(LOG_XML, "", current->owner); } @@ -1061,7 +1090,8 @@ static void print_MAC_XML_Info(Target *currenths) { static void write_xml_initial_hostinfo(Target *currenths, const char *status) { - log_write(LOG_XML, "\n
\n", status,currenths->targetipstr(), (o.af() == AF_INET)? "ipv4" : "ipv6"); + log_write(LOG_XML,"\n", status, reason_str(currenths->reason.reason_id, SINGULAR)); + log_write(LOG_XML,"
\n", currenths->targetipstr(), (o.af() == AF_INET)? "ipv4" : "ipv6"); print_MAC_XML_Info(currenths); if (*currenths->HostName()) { log_write(LOG_XML, "\n", currenths->HostName()); @@ -1077,6 +1107,7 @@ static void write_xml_initial_hostinfo(Target *currenths, for all hosts (even down ones) to be resolved */ void write_host_status(Target *currenths, int resolve_all) { char hostname[1200]; + char reasonbuf[512]; if (o.listscan) { /* write "unknown" to stdout, machine, and xml */ @@ -1107,10 +1138,16 @@ void write_host_status(Target *currenths, int resolve_all) { } else if (o.pingscan) { + + if(o.reason && currenths->flags & HOST_UP) + snprintf(reasonbuf, 512, "%s.\n", target_reason_str(currenths)); + else + snprintf(reasonbuf, 512, ".\n"); + write_xml_initial_hostinfo(currenths, (currenths->flags & HOST_UP)? "up" : "down"); if (currenths->flags & HOST_UP) { - log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"Host %s appears to be up.\n", currenths->NameIP(hostname, sizeof(hostname))); + log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"Host %s appears to be up%s", currenths->NameIP(hostname, sizeof(hostname)), reasonbuf); log_write(LOG_MACHINE,"Host: %s (%s)\tStatus: Up\n", currenths->targetipstr(), currenths->HostName()); } else if (o.verbose || resolve_all) { if (resolve_all) diff --git a/portlist.cc b/portlist.cc index b2c722899..cb856cad2 100644 --- a/portlist.cc +++ b/portlist.cc @@ -125,6 +125,7 @@ Port::Port() { serviceprobe_hostname = serviceprobe_ostype = serviceprobe_devicetype = NULL; serviceprobe_tunnel = SERVICE_TUNNEL_NONE; serviceprobe_fp = NULL; + state_reason_init(&reason); } Port::~Port() { @@ -442,7 +443,9 @@ int PortList::addPort(u16 portno, u8 protocol, char *owner, int state) { free(current->owner); current->owner = strdup(owner); } - + + if(state == PORT_FILTERED || state == PORT_OPENFILTERED) + setStateReason(portno, protocol, ER_NORESPONSE, 0, 0); return 0; /*success */ } @@ -726,6 +729,21 @@ int PortList::numIgnoredPorts() { return numports; } +int PortList::setStateReason(u16 portno, u8 proto, reason_t reason, u8 ttl, u32 ip_addr) { + Port *answer = NULL; + + if(!(answer = getPortEntry(portno, proto))) + return -1; + if(reason > ER_MAX) + return -1; + + /* set new reason and increment its count */ + answer->reason.reason_id = reason; + answer->reason.ip_addr.s_addr = ip_addr; + answer->reason.ttl = ttl; + setPortEntry(portno, proto, answer); + return 0; +} // Move some popular TCP ports to the beginning of the portlist, because // that can speed up certain scans. You should have already done any port diff --git a/portlist.h b/portlist.h index 2e3e66a53..90fd1c86d 100644 --- a/portlist.h +++ b/portlist.h @@ -104,6 +104,7 @@ #include #include "nbase.h" #include "nse_main.h" +#include "reason.h" /* port states */ #define PORT_UNKNOWN 0 @@ -180,8 +181,6 @@ struct serviceDeductions { }; - - class Port { public: Port(); @@ -223,6 +222,7 @@ class Port { char *owner; int state; int confidence; /* How sure are we about the state? */ + state_reason_t reason; ScriptResults scriptResults; @@ -300,6 +300,8 @@ class PortList { /* Set Port structure to PortList structure.*/ void setPortEntry(u16 portno, u8 protocol, Port *port); + int setStateReason(u16 portno, u8 proto, reason_t reason, u8 ttl, u32 ip_addr); + int numports; /* Total number of ports in list in ANY state */ int numscriptresults; /* Total number of scripts which produced output */ diff --git a/reason.cc b/reason.cc new file mode 100644 index 000000000..1d8fd3209 --- /dev/null +++ b/reason.cc @@ -0,0 +1,383 @@ +/*************************************************************************** + * reason.cc -- Verbose packet-level information on port states * + * * + ***********************IMPORTANT NMAP LICENSE TERMS************************ + * * + * The Nmap Security Scanner is (C) 1996-2004 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. 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 may be * + * willing to sell alternative licenses (contact sales@insecure.com). * + * Many security scanner vendors already license Nmap technology such as * + * our remote OS fingerprinting database and code, service/version * + * detection system, and port scanning code. * + * * + * 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-fingerprints 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 just meant to * + * clarify our interpretation of derived works with some common examples. * + * These restrictions only apply when you actually redistribute Nmap. For * + * example, nothing stops you from writing and selling a proprietary * + * front-end to Nmap. Just distribute it by itself, and point people to * + * http://www.insecure.org/nmap/ to download Nmap. * + * * + * We don't consider these to be added restrictions on top of the GPL, but * + * just a clarification of how we interpret "derived works" as it applies * + * to our GPL-licensed Nmap product. This is similar to the way Linus * + * Torvalds has announced his interpretation of how "derived works" * + * applies to Linux kernel modules. Our interpretation refers only to * + * Nmap - we don't speak for any other GPL products. * + * * + * 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 many * + * security 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 fyodor@insecure.org for possible incorporation into the main * + * distribution. By sending these changes to Fyodor or one the * + * Insecure.Org development mailing lists, it is assumed that you are * + * offering Fyodor and 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 for more details at * + * http://www.gnu.org/copyleft/gpl.html , or in the COPYING file included * + * with Nmap. * + * * + ***************************************************************************/ + +/* + * Written by Eddie Bell 2007 + */ + +#include +#include "nmap.h" +#include "portlist.h" +#include "NmapOps.h" +#include "reason.h" +#ifdef WIN32 +#include "winfix.h" +#endif + +extern NmapOps o; +class PortList; + +/* Possible plural and singular reasons */ +char *reason_text[ER_MAX+1]={ + "reset", "conn-refused", "syn-ack", "syn-ack", "udp-response", + "proto-response","net-unreach", "host-unreach", "proto-unreach", + "port-unreach", "echo-reply", "unknown", "unknown", "dest-unreach", + "source-quench", "net-prohibited", "host-prohibited", "unknown", + "unknown", "admin-prohibited", "unknown", "time-exceeded", "unknown", "unknown", + "timestamp-reply", "unknown", "unknown", "unknown", "addressmask-reply", + "no-ipid-change", "ipid-change", "arp-reponse", "tcp-response", + "no-response", "localhost-response", "unknown-response" +}; + +char *reason_pl_text[ER_MAX+1]={ + "resets", "conn-refused", "syn-acks", "syn-acks", "udp-responses", + "proto-responses","net-unreaches", "host-unreaches", "proto-unreaches", + "port-unreaches", "echo-replies", "unknowns", "unknowns", "dest-unreaches", + "source-quenches", "net-prohibiteds", "host-prohibiteds", "unknowns", + "unknowns", "admin-prohibiteds", "unknowns", "time-exceededs", "unknowns", + "unknowns", "timestamp-replies", "unknowns", "unknowns", "unknowns", + "addressmask-replies", "no-ipid-changes", "ipid-changes", "arp-responses", + "tcp-responses", "no-responses", "localhost-response", "unknown-responses" +}; + +static void state_reason_summary_init(state_reason_summary_t *r) { + r->reason_id = ER_UNKNOWN; + r->count = 0; + r->next = NULL; +} + +static void state_reason_summary_dinit(state_reason_summary_t *r) { + state_reason_summary_t *tmp; + + while(r != NULL) { + tmp = r->next; + free(r); + r = r->next; + } +} + +/* Counts how different valid state reasons exist */ +static int state_summary_size(state_reason_summary_t *head) { + state_reason_summary_t *current = head; + int size = 0; + + while(current) { + if(current->count > 0) + size++; + current = current->next; + } + return size; +} + +/* Simon Tatham's linked list merge sort + * + * Merge sort works really well on linked lists + * because it does not require the O(N) extra space + * needed with arrays */ +static state_reason_summary_t *reason_sort(state_reason_summary_t *list) { + state_reason_summary_t *p, *q, *e, *tail; + int insize = 1, nmerges, psize, qsize, i; + + if (!list) + return NULL; + + while (1) { + p = list; + list = NULL; + tail = NULL; + nmerges = 0; + + while (p) { + nmerges++; + q = p; + psize = 0; + for (i = 0; i < insize; i++) { + psize++; + q = q->next; + if (!q) break; + } + qsize = insize; + while (psize > 0 || (qsize > 0 && q)) { + if (psize == 0) { + e = q; q = q->next; qsize--; + } else if (qsize == 0 || !q) { + e = p; p = p->next; psize--; + } else if (q->countcount) { + e = p; p = p->next; psize--; + } else { + e = q; q = q->next; qsize--; + } + + if (tail) { + tail->next = e; + } else { + list = e; + } + tail = e; + } + p = q; + } + tail->next = NULL; + if (nmerges <= 1) + return list; + insize *= 2; + } +} + +/* Builds and aggregates reason state summary messages */ +static int update_state_summary(state_reason_summary_t *head, reason_t reason_id) { + state_reason_summary_t *tmp = head; + + if(tmp == NULL) + return -1; + + while(1) { + if(tmp->reason_id == reason_id) { + tmp->count++; + return 0; + } + + if(tmp->next == NULL) { + if((tmp->next = (state_reason_summary_t *)malloc(sizeof(state_reason_summary_t))) == NULL) { + perror("malloc() -> Cannot allocate state reason structures"); + return -1; + } + tmp = tmp->next; + break; + } + tmp = tmp->next; + } + state_reason_summary_init(tmp); + tmp->reason_id = reason_id; + tmp->count = 1; + return 0; +} + +/* Converts Port objects and their corrosponsing state_reason structures into + * state_reason_summary structures using update_state_summary */ +static unsigned int get_state_summary(state_reason_summary_t *head, PortList *Ports) { + Port *current = NULL; + state_reason_summary_t *reason; + unsigned int total = 0; + unsigned short proto = (o.ipprotscan) ? IPPROTO_IP : TCPANDUDP; + + if(head == NULL) + return 0; + reason = head; + + while((current = Ports->nextPort(current, proto, 0)) != NULL) { + if(Ports->isIgnoredState(current->state)) { + total++; + update_state_summary(reason, current->reason.reason_id); + } + } + return total; +} + +/* parse and sort reason summary for main print_* functions */ +static state_reason_summary_t *print_state_summary_internal(PortList *Ports) { + state_reason_summary_t *reason_head; + + if((reason_head = (state_reason_summary_t *)malloc(sizeof(state_reason_summary_t))) == NULL) { + perror("malloc() -> Cannot allocate state reason structures"); + return NULL; + } + + state_reason_summary_init(reason_head); + + if((get_state_summary(reason_head, Ports) < 1)) { + state_reason_summary_dinit(reason_head); + return NULL; + } + + if((reason_head = reason_sort(reason_head)) == NULL) + return NULL; + return reason_head; +} + +/* looks up reason_id's and returns with the plural or singular + * string representation. If 'number' is equal to 1 then the + * singular is used, otherwise the plural */ +const char *reason_str(reason_t reason_code, unsigned int number) { + if(reason_code > ER_MAX) + return "unknown"; + if(number == 1) + return reason_text[reason_code]; + else + return reason_pl_text[reason_code]; +} + +void state_reason_init(state_reason_t *reason) { + reason->reason_id = ER_UNKNOWN; + reason->ip_addr.s_addr = 0; + reason->ttl = 0; +} + +/* Main external interface to converting, building, sorting and + * printing plain-text state reason summaries */ +void print_state_summary(PortList *Ports, unsigned short type) { + state_reason_summary_t *reason_head, *currentr; + bool first_time = true; + char *separator = ", "; + int states; + + if((reason_head = print_state_summary_internal(Ports)) == NULL) + return; + + if(type == STATE_REASON_EMPTY) + log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, " because of"); + else if(type == STATE_REASON_FULL) + log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, "Reason:"); + else + assert(0); + + states = state_summary_size(reason_head); + currentr = reason_head; + + while(currentr != NULL) { + if(states == 1 && (!first_time)) + separator = " and "; + if(currentr->count > 0) { + log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, "%s%d %s", (first_time) ? " " : separator, + currentr->count, reason_str(currentr->reason_id, currentr->count)); + first_time = false; + + } + states--; + currentr = currentr->next; + } + if(type == STATE_REASON_FULL) + log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, "\n"); + state_reason_summary_dinit(reason_head); +} + +void print_xml_state_summary(PortList *Ports) { + state_reason_summary_t *reason_head, *currentr; + + if((currentr = reason_head = print_state_summary_internal(Ports)) == NULL) + return; + + while(currentr != NULL) { + if(currentr->count > 0) + log_write(LOG_XML, "\n", + reason_str(currentr->reason_id, currentr->count), currentr->count); + currentr = currentr->next; + } + state_reason_summary_dinit(reason_head); +} + +/* converts target into reason message for ping scans. Uses a static + * buffer so new values overwrite old values */ +char *target_reason_str(Target *t) { + static char reason[128]; + memset(reason,'\0', 128); + assert(t->reason.reason_id != ER_NORESPONSE); + snprintf(reason, 128, ", received %s",reason_str(t->reason.reason_id, SINGULAR)); + return reason; +} + +/* Build an output string based on reason and source ip address. + * uses a static return value so previous values will be over + * written by subsequent calls */ +char *port_reason_str(state_reason_t r) { + static char reason[128]; + memset(reason,'\0', 128); + snprintf(reason, 128, "%s%s%s", reason_str(r.reason_id, SINGULAR), + (r.ip_addr.s_addr==0)?"":" from ", + (r.ip_addr.s_addr==0)?"":inet_ntoa(r.ip_addr)); + return reason; +} diff --git a/reason.h b/reason.h new file mode 100644 index 000000000..945382bd2 --- /dev/null +++ b/reason.h @@ -0,0 +1,185 @@ +/*************************************************************************** + * reason.cc -- Verbose packet-level information on port states * + * * + ***********************IMPORTANT NMAP LICENSE TERMS************************ + * * + * The Nmap Security Scanner is (C) 1996-2004 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. 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 may be * + * willing to sell alternative licenses (contact sales@insecure.com). * + * Many security scanner vendors already license Nmap technology such as * + * our remote OS fingerprinting database and code, service/version * + * detection system, and port scanning code. * + * * + * 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-fingerprints 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 just meant to * + * clarify our interpretation of derived works with some common examples. * + * These restrictions only apply when you actually redistribute Nmap. For * + * example, nothing stops you from writing and selling a proprietary * + * front-end to Nmap. Just distribute it by itself, and point people to * + * http://www.insecure.org/nmap/ to download Nmap. * + * * + * We don't consider these to be added restrictions on top of the GPL, but * + * just a clarification of how we interpret "derived works" as it applies * + * to our GPL-licensed Nmap product. This is similar to the way Linus * + * Torvalds has announced his interpretation of how "derived works" * + * applies to Linux kernel modules. Our interpretation refers only to * + * Nmap - we don't speak for any other GPL products. * + * * + * 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 many * + * security 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 fyodor@insecure.org for possible incorporation into the main * + * distribution. By sending these changes to Fyodor or one the * + * Insecure.Org development mailing lists, it is assumed that you are * + * offering Fyodor and 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 for more details at * + * http://www.gnu.org/copyleft/gpl.html , or in the COPYING file included * + * with Nmap. * + * * + ***************************************************************************/ + +/* + * Written by Eddie Bell 2007 + */ + +#ifndef REASON_H +#define REASON_H + +#ifdef WIN32 +#include "winsock2.h" +#else +#include +#endif + +class Target; +class PortList; + +typedef unsigned short reason_t; + +/* stored inside a Port Object and describes + * why a port is in a specific state */ +typedef struct port_reason { + reason_t reason_id; + struct in_addr ip_addr; + unsigned short ttl; +} state_reason_t; + +/* used to calculate state reason summaries. + * I.E 10 ports filter because of 10 no-responses */ +typedef struct port_reason_summary { + reason_t reason_id; + unsigned int count; + struct port_reason_summary *next; +} state_reason_summary_t; + +/* reason.h:reason_codes and reason.cc:reason_str must stay in sync */ +enum reason_codes { + ER_RESETPEER=0, ER_CONREFUSED, ER_CONACCEPT, + ER_SYNACK, ER_UDPRESPONSE, ER_PROTORESPONSE, + ER_NETUNREACH, ER_HOSTUNREACH, ER_PROTOUNREACH, + ER_PORTUNREACH, ER_ECHOREPLY, /* 10 */ + + ER_DESTUNREACH=13, ER_SOURCEQUENCH, ER_NETPROHIBITED, + ER_HOSTPROHIBITED, ER_ADMINPROHIBITED=19, + ER_TIMEEXCCEDED=21, ER_TIMESTAMPREPLY=24, + + ER_ADDRESSMASKREPLY=28, ER_NOIPIDCHANGE, ER_IPIDCHANGE, + ER_ARPRESPONSE, ER_TCPRESPONSE, ER_NORESPONSE, + ER_LOCALHOST, ER_UNKNOWN, ER_MAX=ER_UNKNOWN /* 36 */ +}; + +/* Be careful to update these values if any ICMP + * ER_* definitions are modified. + * + * ICMP ER_* codes are calculated by adding the + * offsets below to an ICMP packets code/type value */ +#define ER_ICMPCODE_MOD 6 +#define ER_ICMPTYPE_MOD 10 + +/* passed to the print_state_summary. + * STATE_REASON_EMPTY will append to the current line, prefixed with " because of" + * STATE_REASON_FULL will start a new line, prefixed with "Reason:" */ +#define STATE_REASON_EMPTY 0 +#define STATE_REASON_FULL 1 + +/* Passed to reason_str to determine if string should be in + * plural of singular form */ +#define SINGULAR 1 +#define PLURAL 2 + +void state_reason_init(state_reason_t *reason); + +/* converts a reason_id to a string. number represents the + * amount ports in a given state. If there is more then one + * port the plural is used, otherwise the singular is used. */ +const char *reason_str(reason_t reason_id, unsigned int number); + +/* Displays reason summary messages */ +void print_state_summary(PortList *Ports, unsigned short type); +void print_xml_state_summary(PortList *Ports); + +/* Build an output string based on reason and source ip address. + * Uses static return value so previous values will be over + * written by subsequent calls */ +char *port_reason_str(state_reason_t r); +char *target_reason_str(Target *t); + +#endif + diff --git a/scan_engine.cc b/scan_engine.cc index a7c5b12bd..4df57b950 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -103,16 +103,14 @@ #ifdef WIN32 #include "nmap_winconfig.h" #endif - +#include "reason.h" #include - #include "scan_engine.h" #include "timing.h" #include "NmapOps.h" #include "nmap_tty.h" #include - using namespace std; extern NmapOps o; class UltraScanInfo; @@ -1710,7 +1708,7 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI, break; case PORT_FILTERED: if (newstate != PORT_FILTERED) { - if (!noresp_open_scan || newstate != PORT_OPEN) + if (!noresp_open_scan || newstate != PORT_OPEN) hss->target->ports.addPort(portno, proto, NULL, newstate); } break; @@ -1732,6 +1730,7 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI, break; } + /* Consider changing the ping port */ if (hss->pingprobestate != newstate) { /* TODO: UDP scan and such will have different preferences -- add them */ @@ -2521,6 +2520,7 @@ static bool do_one_select_round(UltraScanInfo *USI, struct timeval *stime) { int numGoodSD = 0; int err = 0; u16 pport = 0; + reason_t current_reason = ER_NORESPONSE; #ifdef LINUX int res; struct sockaddr_storage sin,sout; @@ -2639,27 +2639,35 @@ static bool do_one_select_round(UltraScanInfo *USI, struct timeval *stime) { #else newstate = PORT_OPEN; #endif + current_reason = (newstate == PORT_OPEN) ? ER_CONACCEPT : ER_CONREFUSED; break; case EACCES: /* Apparently this can be caused by dest unreachable admin prohibited messages sent back, at least from IPv6 hosts */ newstate = PORT_FILTERED; + current_reason = ER_ADMINPROHIBITED; break; case ECONNREFUSED: newstate = PORT_CLOSED; + current_reason = ER_CONREFUSED; break; #ifdef ENOPROTOOPT case ENOPROTOOPT: #endif case EHOSTUNREACH: + current_reason = ER_HOSTUNREACH; + newstate = PORT_FILTERED; + break; case ETIMEDOUT: case EHOSTDOWN: case ENETUNREACH: + /* It could be the host is down, or it could be firewalled. We will go on the safe side & assume port is closed ... on second thought, lets go firewalled! and see if it causes any trouble */ newstate = PORT_FILTERED; + current_reason = ER_NORESPONSE; break; case ENETDOWN: case ENETRESET: @@ -2676,8 +2684,10 @@ static bool do_one_select_round(UltraScanInfo *USI, struct timeval *stime) { if (newstate != PORT_UNKNOWN) { if (probe->isPing()) ultrascan_ping_update(USI, host, probeI, &USI->now); - else + else { ultrascan_port_probe_update(USI, host, probeI, newstate, &USI->now); + host->target->ports.setStateReason(probe->dport(), probe->protocol(), current_reason, 0, 0); + } } } } @@ -2768,6 +2778,7 @@ static bool get_arp_result(UltraScanInfo *USI, struct timeval *stime) { if (!hss) continue; /* Add found HW address for target */ hss->target->setMACAddress(rcvdmac); + hss->target->reason.reason_id = ER_ARPRESPONSE; if (hss->probes_outstanding.empty()) { continue; @@ -2798,6 +2809,7 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { bool timedout = false; struct timeval rcvdtime; struct ip *ip = NULL, *ip2 = NULL; + struct ip *ip_icmp = NULL; struct tcp_hdr *tcp = NULL; struct icmp *icmp = NULL; struct udp_hdr *udp = NULL; @@ -2819,6 +2831,8 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { the icmp probe is made */ static bool protoscanicmphack = false; static struct sockaddr_in protoscanicmphackaddy; + reason_t current_reason = ER_NORESPONSE; + u32 reason_sip = 0; gettimeofday(&USI->now, NULL); do { @@ -2856,6 +2870,7 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { if (ip->ip_p == IPPROTO_ICMP) { protoscanicmphack = true; protoscanicmphackaddy = sin; + ip_icmp = ip; } else { probeI = hss->probes_outstanding.end(); listsz = hss->num_probes_outstanding(); @@ -2873,6 +2888,7 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { /* We got a packet from the dst host in the protocol we looked for, and it wasn't our probe to ourselves, so it must be open */ newstate = PORT_OPEN; + current_reason = ER_PROTORESPONSE; goodone = true; } } @@ -2953,7 +2969,9 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { if (USI->scantype == SYN_SCAN && (tcp->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { /* Yeah! An open port */ newstate = PORT_OPEN; + current_reason = ER_SYNACK; } else if (tcp->th_flags & TH_RST) { + current_reason = ER_RESETPEER; if (USI->scantype == WINDOW_SCAN ) { newstate = (tcp->th_win)? PORT_OPEN : PORT_CLOSED; } else if (USI->scantype == ACK_SCAN) { @@ -3082,6 +3100,7 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { sizeof(struct ip)); break; } + current_reason = icmp->icmp_code+ER_ICMPCODE_MOD; if (newstate == PORT_UNKNOWN) break; goodone = true; } @@ -3125,16 +3144,25 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { continue; /* We saw the packet we ourselves sent */ newstate = PORT_OPEN; + current_reason = ER_UDPRESPONSE; goodone = true; } } else continue; /* Unexpected protocol */ } while (!goodone && !timedout); if (goodone) { + reason_sip = (ip->ip_src.s_addr == hss->target->v4hostip()->s_addr) ? 0 : ip->ip_src.s_addr; if (probe->isPing()) ultrascan_ping_update(USI, hss, probeI, &rcvdtime); - else + else { ultrascan_port_probe_update(USI, hss, probeI, newstate, &rcvdtime); + if(USI->prot_scan) + hss->target->ports.setStateReason(probe->protocol(), IPPROTO_IP, + current_reason, ip->ip_ttl, reason_sip); + else + hss->target->ports.setStateReason(probe->dport(), probe->protocol(), + current_reason, ip->ip_ttl, reason_sip); + } } /* If protoicmphack is true, we are doing an IP proto scan and @@ -3155,8 +3183,17 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { if (probe->protocol() == IPPROTO_ICMP) { if (probe->isPing()) ultrascan_ping_update(USI, hss, probeI, NULL); - else + else { ultrascan_port_probe_update(USI, hss, probeI, PORT_OPEN, NULL); + icmp = (struct icmp *) ((char *)ip_icmp + 4 * ip_icmp->ip_hl); + reason_sip = (ip_icmp->ip_src.s_addr == protoscanicmphackaddy.sin_addr.s_addr) ? 0 : ip_icmp->ip_src.s_addr; + if(!icmp->icmp_code && !icmp->icmp_type) + hss->target->ports.setStateReason(IPPROTO_ICMP, IPPROTO_IP, ER_ECHOREPLY, + ip_icmp->ip_ttl, reason_sip); + else + hss->target->ports.setStateReason(IPPROTO_ICMP, IPPROTO_IP, icmp->icmp_type+ER_ICMPCODE_MOD, + ip_icmp->ip_ttl, reason_sip); + } if (!goodone) goodone = true; break; } diff --git a/targets.cc b/targets.cc index 85c0f3f10..050df867a 100644 --- a/targets.cc +++ b/targets.cc @@ -415,6 +415,7 @@ static int get_ping_results(int sd, pcap_t *pd, Target *hostbatch[], unsigned long tmpl; unsigned short sportbase; struct link_header linkhdr; + reason_t currentr = ER_NORESPONSE; FD_ZERO(&fd_r); FD_ZERO(&fd_x); @@ -484,6 +485,10 @@ static int get_ping_results(int sd, pcap_t *pd, Target *hostbatch[], error("Supposed ping packet is only %d bytes long!", bytes); continue; } + + if((currentr = (ping->type+ER_ICMPTYPE_MOD)) == ER_DESTUNREACH) + currentr = ping->type+ER_ICMPCODE_MOD; + /* Echo reply, Timestamp reply, or Address Mask Reply */ if ( (ping->type == 0 || ping->type == 14 || ping->type == 18) && !ping->code && ping->id == id) { @@ -731,10 +736,16 @@ static int get_ping_results(int sd, pcap_t *pd, Target *hostbatch[], if (pingtype & PINGTYPE_TCP_USE_SYN) { if (tcp->th_flags & TH_RST) { newportstate = PORT_CLOSED; + currentr = ER_RESETPEER; } else if ((tcp->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { newportstate = PORT_OPEN; + currentr = ER_SYNACK; } } + else if(pingtype & PINGTYPE_TCP_USE_ACK) { + if(tcp->th_flags & TH_RST) + currentr = ER_RESETPEER; + } } else if (ip->ip_p == IPPROTO_UDP) { if (!ptech->rawudpscan) { @@ -763,6 +774,7 @@ static int get_ping_results(int sd, pcap_t *pd, Target *hostbatch[], } sequence = hostnum * pt->max_tries + trynum; + currentr = ER_UDPRESPONSE; if (o.debugging) log_write(LOG_STDOUT, "In response to UDP-ping, we got UDP packet back from %s port %hi (hostnum = %d trynum = %d\n", inet_ntoa(ip->ip_src), htons(udp->uh_sport), hostnum, trynum); @@ -779,6 +791,11 @@ static int get_ping_results(int sd, pcap_t *pd, Target *hostbatch[], trynum, to, &time[sequence], &rcvdtime, pt, NULL, pingstyle); if (newstate == HOST_UP && ip && bytes >= 20) setTargetMACIfAvailable(hostbatch[hostnum], &linkhdr, ip, 0); + + hostbatch[hostnum]->reason.reason_id = currentr; + hostbatch[hostnum]->reason.ttl = ip->ip_ttl; + if(ip->ip_src.s_addr != hostbatch[hostnum]->v4host().s_addr) + hostbatch[hostnum]->reason.ip_addr.s_addr = ip->ip_src.s_addr; } if (newport && newportstate != PORT_UNKNOWN) { /* OK, we can add it, but that is only appropriate if this is one @@ -1164,6 +1181,9 @@ while(pt->block_unaccounted) { int sock_err = socket_errno(); switch(sock_err) { case ECONNREFUSED: + foundsomething = 1; + newstate = HOST_UP; + hostbatch[hostindex]->reason.reason_id = ER_CONREFUSED; case EAGAIN: #ifdef WIN32 case WSAENOTCONN: @@ -1173,14 +1193,24 @@ while(pt->block_unaccounted) { } foundsomething = 1; newstate = HOST_UP; + hostbatch[hostindex]->reason.reason_id = ER_CONACCEPT; break; case ENETDOWN: case ENETUNREACH: + hostbatch[hostindex]->reason.reason_id = ER_NETUNREACH; + foundsomething = 1; + newstate = HOST_DOWN; + break; + case EHOSTUNREACH: + hostbatch[hostindex]->reason.reason_id = ER_HOSTUNREACH; + foundsomething = 1; + newstate = HOST_DOWN; + break; case ENETRESET: case ECONNABORTED: case ETIMEDOUT: case EHOSTDOWN: - case EHOSTUNREACH: + hostbatch[hostindex]->reason.reason_id = ER_NORESPONSE; foundsomething = 1; newstate = HOST_DOWN; break; @@ -1190,6 +1220,7 @@ while(pt->block_unaccounted) { break; } } else { + hostbatch[hostindex]->reason.reason_id = ER_SYNACK; foundsomething = 1; newstate = HOST_UP; if (o.verbose) { @@ -1825,6 +1856,7 @@ if (hs->randomize) { if (!hs->hostbatch[i]->timedOut(&now)) { initialize_timeout_info(&hs->hostbatch[i]->to); hs->hostbatch[i]->flags |= HOST_UP; /*hostbatch[i].up = 1;*/ + hs->hostbatch[i]->reason.reason_id = ER_LOCALHOST; } } } else if (!arpping_done) diff --git a/tcpip.cc b/tcpip.cc index f8fef5e9d..6d56f9f6e 100644 --- a/tcpip.cc +++ b/tcpip.cc @@ -102,6 +102,7 @@ #ifdef WIN32 #include "nmap_winconfig.h" #endif +#include "reason.h" #include #include "tcpip.h" #include "NmapOps.h" diff --git a/traceroute.cc b/traceroute.cc index 0d3eaaca9..406a0de06 100644 --- a/traceroute.cc +++ b/traceroute.cc @@ -1314,7 +1314,7 @@ TraceGroup::setHopDistance (u8 hop_distance, u8 ttl) { if (this->hopDistance && ttl) this->hopDistance -= ttl; - else if(!this->hopDistance && ttl) + else if(!this->hopDistance && ttl) this->hopDistance = ttl; else this->hopDistance = hop_distance;
Port State ServiceReason Product Version Extra info   + + from + + +         + + from + + +         + + from + + +         + + from + + +