diff --git a/scan_engine.cc b/scan_engine.cc index 5c45e7b62..2a58dabb5 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -2639,6 +2639,16 @@ static void processData(UltraScanInfo *USI) { probe = *probeI; unsigned long to_us = host->probeTimeout(); +#ifdef WIN32 + if (USI->scantype == CONNECT_SCAN || USI->ptech.connecttcpscan) { + // Have to adjust to_us up because of TCP_MAXRT granularity + if (USI->has_tcp_maxrtms) { + to_us += (1000 - to_us % 1000); + } else { + to_us += (1000000 - to_us % 1000000); + } + } +#endif long probe_age_us = TIMEVAL_SUBTRACT(USI->now, probe->sent); // give up completely after this long expire_us = host->probeExpireTime(probe, to_us); diff --git a/scan_engine.h b/scan_engine.h index 5fbdfd15a..491e29fa3 100644 --- a/scan_engine.h +++ b/scan_engine.h @@ -557,6 +557,9 @@ public: bool ping_scan_arp; /* ONLY includes arp ping scan */ bool ping_scan_nd; /* ONLY includes ND ping scan */ bool noresp_open_scan; /* Whether no response means a port is open */ +#ifdef WIN32 + bool has_tcp_maxrtms; /* Whether TCP_MAXRTMS socket option is available */ +#endif /* massping state. */ /* If ping_scan is true (unless ping_scan_arp is also true), this is the set diff --git a/scan_engine_connect.cc b/scan_engine_connect.cc index 014824715..7f89f800e 100644 --- a/scan_engine_connect.cc +++ b/scan_engine_connect.cc @@ -71,6 +71,10 @@ #include +#ifdef WIN32 +#include +#endif + extern NmapOps o; /* Sets this UltraProbe as type UP_CONNECT, preparing to connect to given @@ -215,7 +219,7 @@ static void handleConnectResult(UltraScanInfo *USI, HostScanStats *hss, bool adjust_timing = true; int newportstate = PORT_UNKNOWN; int newhoststate = HOST_UNKNOWN; - reason_t current_reason = ER_NORESPONSE; + reason_t current_reason = ER_UNKNOWN; UltraProbe *probe = *probeI; struct sockaddr_storage local; socklen_t local_len = sizeof(struct sockaddr_storage); @@ -311,7 +315,10 @@ static void handleConnectResult(UltraScanInfo *USI, HostScanStats *hss, error("Strange read error from %s (%d - '%s')", hss->target->targetipstr(), connect_errno, strerror(connect_errno)); break; } - if (probe->isPing() && newhoststate != HOST_UNKNOWN ) { + if (current_reason == ER_NORESPONSE) { + hss->markProbeTimedout(probeI); + } + else if (probe->isPing() && newhoststate != HOST_UNKNOWN ) { ultrascan_ping_update(USI, hss, probeI, &USI->now, adjust_timing); } else if (USI->ping_scan && newhoststate != HOST_UNKNOWN) { ultrascan_host_probe_update(USI, hss, probeI, newhoststate, &USI->now, adjust_timing); @@ -369,7 +376,7 @@ static void handleConnectResult(UltraScanInfo *USI, HostScanStats *hss, /* Set the socket lingering so we will RST connections instead of wasting bandwidth with the four-step close. Set the source address if needed. Bind to a specific interface if needed. */ -static void init_socket(int sd) { +static void init_socket(int sd, const HostScanStats *hss, UltraScanInfo *USI) { static int bind_failed = 0; struct linger l; struct sockaddr_storage ss; @@ -382,6 +389,47 @@ static void init_socket(int sd) { error("Problem setting socket SO_LINGER, errno: %d", socket_errno()); perror("setsockopt"); } +#ifdef WIN32 + DWORD dwVal; + unsigned long to_us = hss->probeTimeout(); +#ifdef TCP_FAIL_CONNECT_ON_ICMP_ERROR + // return WSAEHOSTUNREACH on ICMP error. Default is to ignore! + dwVal = 1; + if (setsockopt(sd, IPPROTO_TCP, TCP_FAIL_CONNECT_ON_ICMP_ERROR, (const char *) &dwVal, sizeof(dwVal)) != 0) { + error("Problem setting socket TCP_FAIL_CONNECT_ON_ICMP_ERROR, errno: %d", socket_errno()); + perror("setsockopt"); + } +#endif + + int err, opt; + do { + err = ERROR_SUCCESS; + if (USI->has_tcp_maxrtms) { + opt = TCP_MAXRTMS; + dwVal = to_us / 1000; // connect timeout in milliseconds + } + else { + opt = TCP_MAXRT; + dwVal = to_us / 1000000; // connect timeout in seconds + } + dwVal = MAX(dwVal, 1); + if (setsockopt(sd, IPPROTO_TCP, opt, (const char*)&dwVal, sizeof(dwVal)) != 0) { + err = socket_errno(); + error("Problem setting socket TCP_MAXRT (%d), errno: %d", opt, err); + perror("setsockopt"); + USI->has_tcp_maxrtms = false; + } + } while (err == WSAENOPROTOOPT && opt == TCP_MAXRTMS); + + dwVal = 0; + TCP_INITIAL_RTO_PARAMETERS params = { 1000 /* ms RTT */, + TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS }; + if (WSAIoctl(sd, SIO_TCP_INITIAL_RTO, ¶ms, sizeof(params), NULL, 0, &dwVal, NULL, NULL)) { + error("Problem setting SIO_TCP_INITIAL_RTO, errno: %d", socket_errno()); + perror("WSAIoctl"); + } +#endif + if (o.spoofsource && !bind_failed) { o.SourceSockAddr(&ss, &sslen); if (::bind(sd, (struct sockaddr*)&ss, sslen) != 0) { @@ -426,7 +474,7 @@ UltraProbe *sendConnectScanProbe(UltraScanInfo *USI, HostScanStats *hss, CP->sd = CSI->getSocket(); assert(CP->sd > 0); unblock_socket(CP->sd); - init_socket(CP->sd); + init_socket(CP->sd, hss, USI); set_ttl(CP->sd, o.ttl); if (o.ipoptionslen) set_ipoptions(CP->sd, o.ipoptions, o.ipoptionslen);