diff --git a/CHANGELOG b/CHANGELOG
index e3a4c851f..ff9ce2351 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,10 @@
# Nmap Changelog ($Id$); -*-text-*-
+o [GH#353] New option --defeat-icmp-ratelimit dramatically reduces UDP scan
+ times in exchange for labeling unresponsive (and possibly open) ports as
+ "closed|filtered". Ports which give a UDP protocol response to one of Nmap's
+ scanning payloads will be marked "open". [Sergey Khegay]
+
o [NSE] Script cics-enum enumerates CICS transaction IDs, mapping to screens in
TN3270 services. [Soldier of Fortran]
diff --git a/NmapOps.cc b/NmapOps.cc
index 6e9e2b686..1f6ffe3fa 100644
--- a/NmapOps.cc
+++ b/NmapOps.cc
@@ -323,6 +323,7 @@ void NmapOps::Initialize() {
open_only = false;
scanflags = -1;
defeat_rst_ratelimit = 0;
+ defeat_icmp_ratelimit = 0;
resume_ip.s_addr = 0;
osscan_limit = 0;
osscan_guess = 0;
@@ -554,7 +555,11 @@ dialog where you can start NPF if you have administrator privileges.";
servicescan = 0;
if (defeat_rst_ratelimit && !synscan) {
- fatal("Option --defeat-rst-ratelimit works only with a SYN scan (-sS)");
+ fatal("Option --defeat-rst-ratelimit works only with a SYN scan (-sS)");
+ }
+
+ if (defeat_icmp_ratelimit && !udpscan) {
+ fatal("Option --defeat-icmp-ratelimit works only with a UDP scan (-sU)");
}
if (resume_ip.s_addr && generate_random_ips)
diff --git a/NmapOps.h b/NmapOps.h
index c4de002a1..ba376dd7c 100644
--- a/NmapOps.h
+++ b/NmapOps.h
@@ -304,6 +304,11 @@ class NmapOps {
slow against it. If we don't distinguish between closed and filtered ports,
we can get the list of open ports very fast */
+ int defeat_icmp_ratelimit; /* If a host rate-limits ICMP responses, then scanning
+ is very slow against it. This option prevents Nmap to adjust timing
+ when it changes the port's state because of ICMP response, as the latter
+ might be rate-limited. Doing so we can get scan results faster. */
+
struct in_addr resume_ip; /* The last IP in the log file if user
requested --restore . Otherwise
restore_ip.s_addr == 0. Also
diff --git a/docs/refguide.xml b/docs/refguide.xml
index 6c05742cc..683c8eb54 100644
--- a/docs/refguide.xml
+++ b/docs/refguide.xml
@@ -2940,6 +2940,25 @@ worth the extra time.
+
+
+
+
+
+Similar to , the
+ option trades accuracy for speed,
+ increasing UDP scanning speed against hosts that rate-limit ICMP error
+ messages. Because this option causes Nmap to not delay in order to receive
+ the port unreachable messages, a non-responsive port will be labeled
+ closed|filtered instead of the default
+ open|filtered. This has the effect of only treating ports
+ which actually respond via UDP as open. Since many UDP
+ services do not respond in this way, the chance for inaccuracy is greater
+ with this option than with .
+
+
+
+
diff --git a/nmap.cc b/nmap.cc
index 0f61049e6..28215cefb 100644
--- a/nmap.cc
+++ b/nmap.cc
@@ -585,6 +585,8 @@ void parse_options(int argc, char **argv) {
{"scanflags", required_argument, 0, 0},
{"defeat_rst_ratelimit", no_argument, 0, 0},
{"defeat-rst-ratelimit", no_argument, 0, 0},
+ {"defeat_icmp_ratelimit", no_argument, 0, 0},
+ {"defeat-icmp-ratelimit", no_argument, 0, 0},
{"host_timeout", required_argument, 0, 0},
{"host-timeout", required_argument, 0, 0},
{"scan_delay", required_argument, 0, 0},
@@ -835,6 +837,8 @@ void parse_options(int argc, char **argv) {
delayed_options.pre_scan_delay = l;
} else if (optcmp(long_options[option_index].name, "defeat-rst-ratelimit") == 0) {
o.defeat_rst_ratelimit = 1;
+ } else if (optcmp(long_options[option_index].name, "defeat-icmp-ratelimit") == 0) {
+ o.defeat_icmp_ratelimit = 1;
} else if (optcmp(long_options[option_index].name, "max-scan-delay") == 0) {
l = tval2msecs(optarg);
if (l < 0)
diff --git a/output.cc b/output.cc
index 69f7a81ce..04135b736 100644
--- a/output.cc
+++ b/output.cc
@@ -2543,6 +2543,9 @@ void printfinaloutput() {
log_write(LOG_PLAIN, "OS detection performed. Please report any incorrect results at https://nmap.org/submit/ .\n");
else if (o.servicescan)
log_write(LOG_PLAIN, "Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .\n");
+ else if (o.udpscan && o.defeat_icmp_ratelimit)
+ log_write(LOG_PLAIN, "WARNING: Some ports marked closed|filtered may actually be open. For more accurate results, do not use --defeat-icmp-ratelimit .\n");
+
}
log_write(LOG_STDOUT | LOG_SKID,
diff --git a/scan_engine.cc b/scan_engine.cc
index cdb586548..42077dc78 100644
--- a/scan_engine.cc
+++ b/scan_engine.cc
@@ -865,7 +865,8 @@ static void set_default_port_state(std::vector &targets, stype scantyp
(*target)->ports.setDefaultPortState(IPPROTO_TCP, PORT_OPENFILTERED);
break;
case UDP_SCAN:
- (*target)->ports.setDefaultPortState(IPPROTO_UDP, PORT_OPENFILTERED);
+ (*target)->ports.setDefaultPortState(IPPROTO_UDP,
+ o.defeat_icmp_ratelimit ? PORT_CLOSEDFILTERED : PORT_OPENFILTERED);
break;
case IPPROT_SCAN:
(*target)->ports.setDefaultPortState(IPPROTO_IP, PORT_OPENFILTERED);
@@ -2125,6 +2126,25 @@ void ultrascan_port_probe_update(UltraScanInfo *USI, HostScanStats *hss,
adjust_timing = false;
adjust_ping = false;
}
+ /* Do not slow down if
+ 1) we are in --defeat-icmp-ratelimit mode
+ 2) the new state is closed or filtered
+ 3) this is a UDP scan
+ We don't want to adjust timing when we get ICMP response, as the host might
+ be ratelimiting them. E.g. the port is actually closed, but the host ratelimiting
+ ICMP responses so we had to retransmit the probe several times in order to
+ match the (slow) rate limit that the target is using for responses. We
+ do not want to waste time on such ports.
+ On the other hand if the port is detected to be open it is a good idea to
+ adjust timing as we could have done retransmissions due to conjested network */
+ if (rcvdtime != NULL
+ && o.defeat_icmp_ratelimit
+ && (newstate == PORT_CLOSED || newstate == PORT_FILTERED)
+ && USI->udp_scan) {
+ if (probe->tryno > 0)
+ adjust_timing = false;
+ adjust_ping = false;
+ }
if (adjust_timing) {
ultrascan_adjust_timing(USI, hss, probe, rcvdtime);