1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-09 22:21:29 +00:00

Better handling for ICMP Host Unreachable

This commit is contained in:
dmiller
2020-10-29 23:02:30 +00:00
parent 15726a0be1
commit 9ac591f9db
3 changed files with 47 additions and 27 deletions

View File

@@ -1,5 +1,10 @@
#Nmap Changelog ($Id$); -*-text-*- #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 o [NSE][GH#711] New script openflow-info gathers preferred and supported
protocol versions from OpenFlow devices [Jay Smith, Mak Kolybabi] protocol versions from OpenFlow devices [Jay Smith, Mak Kolybabi]

View File

@@ -2014,8 +2014,8 @@ static bool ultrascan_host_pspec_update(UltraScanInfo *USI, HostScanStats *hss,
int oldstate = hss->target->flags; int oldstate = hss->target->flags;
/* If the host is already up, ignore any further updates. */ /* If the host is already up, ignore any further updates. */
if (hss->target->flags != HOST_UP) { if (hss->target->flags != HOST_UP) {
assert(newstate == HOST_UP || newstate == HOST_DOWN); // don't allow HOST_UNKNOWN to override a known state.
hss->target->flags = newstate; hss->target->flags = (newstate == HOST_UNKNOWN ? oldstate : newstate);
/* For port scans (not -sn) where output may be delayed until more scan /* 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 * phases are done, emit a hosthint element during host discovery when a
* target is found to be up. */ * 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_timing = adjust_timing_hint;
bool adjust_ping = 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 are often rate-limited (RFC 1812) or generated by a different host. We only
allow such responses to increase, not decrease, scanning speed by allow such responses to increase, not decrease, scanning speed by
disallowing drops (probe->tryno > 0), and we don't allow changing the ping disallowing drops (probe->tryno > 0), and we don't allow changing the ping
probe to something that's likely to get dropped. */ 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 (probe->tryno > 0) {
if (adjust_timing && o.debugging > 1) 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()); log_write(LOG_PLAIN, "Response for %s means new state is down; not adjusting timing.\n", hss->target->targetipstr());

View File

@@ -666,23 +666,34 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
if (probenum >= listsz) if (probenum >= listsz)
continue; continue;
/* Destination unreachable. */
if ((hdr.proto == IPPROTO_ICMP && ping->type == 3) if ((hdr.proto == IPPROTO_ICMP && ping->type == 3)
|| (hdr.proto == IPPROTO_ICMPV6 && ping->type == 1)) { || (hdr.proto == IPPROTO_ICMPV6 && ping->type == 1)) {
/* Destination unreachable. */ // If it's Port or Proto unreachable and the address matches, it's up.
if (sockaddr_storage_cmp(&target_dst, &hdr.src) == 0) { 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. */ /* The ICMP or ICMPv6 error came directly from the target, so it's up. */
goodone = true; goodone = true;
newstate = HOST_UP; newstate = HOST_UP;
} else { if (o.debugging) {
goodone = true; log_write(LOG_STDOUT, "Got port/proto unreachable for %s\n", hss->target->targetipstr());
newstate = HOST_DOWN; }
} }
if (o.debugging) { else {
if ((hdr.proto == IPPROTO_ICMP && ping->code == 3) /* For other codes, see RFC 1122:
|| (hdr.proto == IPPROTO_ICMPV6 && ping->code == 4)) * A Destination Unreachable message that is received with code
log_write(LOG_STDOUT, "Got port unreachable for %s\n", hss->target->targetipstr()); * 0 (Net), 1 (Host), or 5 (Bad Source Route) may result from a
else * 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()); log_write(LOG_STDOUT, "Got destination unreachable for %s\n", hss->target->targetipstr());
}
} }
} else if ((hdr.proto == IPPROTO_ICMP && ping->type == 11) } else if ((hdr.proto == IPPROTO_ICMP && ping->type == 11)
|| (hdr.proto == IPPROTO_ICMPV6 && ping->type == 3)) { || (hdr.proto == IPPROTO_ICMPV6 && ping->type == 3)) {
@@ -692,22 +703,26 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
newstate = HOST_DOWN; newstate = HOST_DOWN;
/* I don't want anything to do with timing this. */ /* I don't want anything to do with timing this. */
adjust_timing = false; 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) { } else if (hdr.proto == IPPROTO_ICMP) {
if (o.debugging) { if (ping->type == 4) {
log_write(LOG_STDOUT, "Got ICMP message type %d code %d\n", if (o.debugging)
ping->type, ping->code); 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) { } else if (hdr.proto == IPPROTO_ICMPV6) {
if (o.debugging) if (ping->type == 4) {
log_write(LOG_STDOUT, "Got ICMPv6 message type %d code %d\n", if (o.debugging)
ping->type, ping->code); 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) { } else if (hdr.proto == IPPROTO_TCP && USI->ptech.rawtcpscan) {