diff --git a/CHANGELOG b/CHANGELOG
index 391182e75..36936129b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,9 @@
#Nmap Changelog ($Id$); -*-text-*-
+o [GH#1616] New option --discovery-ignore-rst tells Nmap to ignore TCP RST
+ responses when determining if a target is up. Useful when firewalls are
+ spoofing RST packets. [Tom Sellers]
+
o [Ncat][GH#2087][GH#1927][GH#1928][GH#1974] It is now possible to override
the value of TLS SNI via --ssl-servername [Hank Leininger, nnposter]
diff --git a/NmapOps.cc b/NmapOps.cc
index 341420e08..284f87a30 100644
--- a/NmapOps.cc
+++ b/NmapOps.cc
@@ -398,6 +398,7 @@ void NmapOps::Initialize() {
exclude_portlist = NULL;
proxy_chain = NULL;
resuming = false;
+ discovery_ignore_rst = false;
}
bool NmapOps::SCTPScan() {
diff --git a/NmapOps.h b/NmapOps.h
index a3738cd9f..4d0977554 100644
--- a/NmapOps.h
+++ b/NmapOps.h
@@ -396,6 +396,7 @@ class NmapOps {
char *exclude_portlist; /* exclude-ports list specified by user */
nsock_proxychain proxy_chain;
+ bool discovery_ignore_rst; /* host discovery should not consider TCP RST packet responses as a live asset */
#ifndef NOLUA
bool script;
diff --git a/docs/refguide.xml b/docs/refguide.xml
index 83351639d..8cd8ffce6 100644
--- a/docs/refguide.xml
+++ b/docs/refguide.xml
@@ -871,6 +871,23 @@ content can also be affected with the ,
+
+
+
+
+
+
+
+ In some cases, firewalls may spoof TCP reset (RST) replies in
+ response to probes to unoccupied or disallowed addresses. Since
+ Nmap ordinarily considers RST replies to be proof that the target
+ is up, this can lead to wasted time scanning targets that aren't
+ there. Using the will
+ prevent Nmap from considering these replies during host discovery.
+ You may need to select extra host discovery options to ensure you
+ don't miss targets in this case.
+
+
diff --git a/nmap.cc b/nmap.cc
index e056c8541..e3472b7cd 100644
--- a/nmap.cc
+++ b/nmap.cc
@@ -627,6 +627,7 @@ void parse_options(int argc, char **argv) {
{"nsock-engine", required_argument, 0, 0},
{"proxies", required_argument, 0, 0},
{"proxy", required_argument, 0, 0},
+ {"discovery-ignore-rst", no_argument, 0, 0},
{"osscan-limit", no_argument, 0, 0}, /* skip OSScan if no open ports */
{"osscan-guess", no_argument, 0, 0}, /* More guessing flexibility */
{"fuzzy", no_argument, 0, 0}, /* Alias for osscan_guess */
@@ -846,6 +847,8 @@ void parse_options(int argc, char **argv) {
} else if ((strcmp(long_options[option_index].name, "proxies") == 0) || (strcmp(long_options[option_index].name, "proxy") == 0)) {
if (nsock_proxychain_new(optarg, &o.proxy_chain, NULL) < 0)
fatal("Invalid proxy chain specification");
+ } else if (strcmp(long_options[option_index].name, "discovery-ignore-rst") == 0) {
+ o.discovery_ignore_rst = true;
} else if (strcmp(long_options[option_index].name, "osscan-limit") == 0) {
o.osscan_limit = true;
} else if (strcmp(long_options[option_index].name, "osscan-guess") == 0
diff --git a/scan_engine_connect.cc b/scan_engine_connect.cc
index b52292a96..662b01f93 100644
--- a/scan_engine_connect.cc
+++ b/scan_engine_connect.cc
@@ -272,7 +272,9 @@ static void handleConnectResult(UltraScanInfo *USI, HostScanStats *hss,
/* This can happen on localhost, successful/failing connection immediately
in non-blocking mode. */
case ECONNREFUSED:
- newhoststate = HOST_UP;
+ if (!o.discovery_ignore_rst) {
+ newhoststate = HOST_UP;
+ }
newportstate = PORT_CLOSED;
current_reason = ER_CONREFUSED;
break;
diff --git a/scan_engine_raw.cc b/scan_engine_raw.cc
index 2464868c0..f74974698 100644
--- a/scan_engine_raw.cc
+++ b/scan_engine_raw.cc
@@ -777,9 +777,13 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
} else if (hdr.proto == IPPROTO_TCP && USI->ptech.rawtcpscan) {
struct tcp_hdr *tcp = (struct tcp_hdr *) data;
/* Check that the packet has useful flags. */
- if (!(tcp->th_flags & TH_RST)
- && ((tcp->th_flags & (TH_SYN | TH_ACK)) != (TH_SYN | TH_ACK)))
- continue;
+ if (o.discovery_ignore_rst
+ && (tcp->th_flags & TH_RST))
+ continue;
+ else if (!(tcp->th_flags & TH_RST)
+ && ((tcp->th_flags & (TH_SYN | TH_ACK)) != (TH_SYN | TH_ACK)))
+ continue;
+
/* Now ensure this host is even in the incomplete list */
hss = USI->findHost(&hdr.src);
if (!hss)