diff --git a/CHANGELOG b/CHANGELOG index c7ae48c07..617c27b1d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,10 @@ #Nmap Changelog ($Id$); -*-text-*- +o Nmap no longer considers an ICMP Host Unreachable as confirmation that a + target is down, in accordance with RFC 1122 which says these errors may be + transient. Instead, the probe will be destroyed and other probes used to + determine aliveness. [Daniel Miller] + o [NSE][GH#711] New script openflow-info gathers preferred and supported protocol versions from OpenFlow devices [Jay Smith, Mak Kolybabi] diff --git a/scan_engine.cc b/scan_engine.cc index 33836aa10..cec3064cf 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -2014,8 +2014,8 @@ static bool ultrascan_host_pspec_update(UltraScanInfo *USI, HostScanStats *hss, int oldstate = hss->target->flags; /* If the host is already up, ignore any further updates. */ if (hss->target->flags != HOST_UP) { - assert(newstate == HOST_UP || newstate == HOST_DOWN); - hss->target->flags = newstate; + // don't allow HOST_UNKNOWN to override a known state. + hss->target->flags = (newstate == HOST_UNKNOWN ? oldstate : newstate); /* For port scans (not -sn) where output may be delayed until more scan * phases are done, emit a hosthint element during host discovery when a * target is found to be up. */ @@ -2066,12 +2066,12 @@ void ultrascan_host_probe_update(UltraScanInfo *USI, HostScanStats *hss, bool adjust_timing = adjust_timing_hint; bool adjust_ping = adjust_timing_hint; - /* If we got a response that meant "down", then it was an ICMP error. These + /* If we got a response that meant "down" or "unknown", then it was an ICMP error. These are often rate-limited (RFC 1812) or generated by a different host. We only allow such responses to increase, not decrease, scanning speed by disallowing drops (probe->tryno > 0), and we don't allow changing the ping probe to something that's likely to get dropped. */ - if (rcvdtime != NULL && newstate == HOST_DOWN) { + if (rcvdtime != NULL && newstate != HOST_UP) { if (probe->tryno > 0) { if (adjust_timing && o.debugging > 1) log_write(LOG_PLAIN, "Response for %s means new state is down; not adjusting timing.\n", hss->target->targetipstr()); diff --git a/scan_engine_raw.cc b/scan_engine_raw.cc index 8eb3d093a..b31a4e667 100644 --- a/scan_engine_raw.cc +++ b/scan_engine_raw.cc @@ -666,23 +666,34 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { if (probenum >= listsz) continue; + /* Destination unreachable. */ if ((hdr.proto == IPPROTO_ICMP && ping->type == 3) || (hdr.proto == IPPROTO_ICMPV6 && ping->type == 1)) { - /* Destination unreachable. */ - if (sockaddr_storage_cmp(&target_dst, &hdr.src) == 0) { + // If it's Port or Proto unreachable and the address matches, it's up. + if (((hdr.proto == IPPROTO_ICMP && (ping->code == 2 || ping->code == 3)) + || (hdr.proto == IPPROTO_ICMPV6 && ping->code == 4)) + && sockaddr_storage_cmp(&target_dst, &hdr.src) == 0) { /* The ICMP or ICMPv6 error came directly from the target, so it's up. */ goodone = true; newstate = HOST_UP; - } else { - goodone = true; - newstate = HOST_DOWN; + if (o.debugging) { + log_write(LOG_STDOUT, "Got port/proto unreachable for %s\n", hss->target->targetipstr()); + } } - if (o.debugging) { - if ((hdr.proto == IPPROTO_ICMP && ping->code == 3) - || (hdr.proto == IPPROTO_ICMPV6 && ping->code == 4)) - log_write(LOG_STDOUT, "Got port unreachable for %s\n", hss->target->targetipstr()); - else + else { + /* For other codes, see RFC 1122: + * A Destination Unreachable message that is received with code + * 0 (Net), 1 (Host), or 5 (Bad Source Route) may result from a + * routing transient and MUST therefore be interpreted as only + * a hint, not proof, that the specified destination is unreachable + */ + // Still, it's a response so we should destroy the matching probe. + goodone = true; + newstate = HOST_UNKNOWN; + adjust_timing = false; + if (o.debugging) { log_write(LOG_STDOUT, "Got destination unreachable for %s\n", hss->target->targetipstr()); + } } } else if ((hdr.proto == IPPROTO_ICMP && ping->type == 11) || (hdr.proto == IPPROTO_ICMPV6 && ping->type == 3)) { @@ -692,22 +703,26 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { newstate = HOST_DOWN; /* I don't want anything to do with timing this. */ adjust_timing = false; - } else if (hdr.proto == IPPROTO_ICMP && ping->type == 4) { - if (o.debugging) - log_write(LOG_STDOUT, "Got ICMP source quench\n"); - usleep(50000); - } else if (hdr.proto == IPPROTO_ICMPV6 && ping->type == 4) { - if (o.debugging) - log_write(LOG_STDOUT, "Got ICMPv6 Parameter Problem\n"); } else if (hdr.proto == IPPROTO_ICMP) { - if (o.debugging) { - log_write(LOG_STDOUT, "Got ICMP message type %d code %d\n", - ping->type, ping->code); + if (ping->type == 4) { + if (o.debugging) + log_write(LOG_STDOUT, "Got ICMP source quench\n"); + usleep(50000); + } else { + if (o.debugging) { + log_write(LOG_STDOUT, "Got ICMP message type %d code %d\n", + ping->type, ping->code); + } } } else if (hdr.proto == IPPROTO_ICMPV6) { - if (o.debugging) - log_write(LOG_STDOUT, "Got ICMPv6 message type %d code %d\n", - ping->type, ping->code); + if (ping->type == 4) { + if (o.debugging) + log_write(LOG_STDOUT, "Got ICMPv6 Parameter Problem\n"); + } else { + if (o.debugging) + log_write(LOG_STDOUT, "Got ICMPv6 message type %d code %d\n", + ping->type, ping->code); + } } } } else if (hdr.proto == IPPROTO_TCP && USI->ptech.rawtcpscan) {