mirror of
https://github.com/nmap/nmap.git
synced 2025-12-08 13:41:29 +00:00
Don't increase the congestion window increment scaling factor until a probe is
replied to or times out. Previously the scaling factor was increased as soon a s a probe was sent. So if you sent 10 probes right away at the beginning of the scan, the first reply that came back would be scaled by 10 (= 10/1, and the next by 9/2, etc.). Now if every probe is replied to then the scaling factor will be exactly 1 throughout the scan.
This commit is contained in:
110
scan_engine.cc
110
scan_engine.cc
@@ -156,7 +156,15 @@ struct ultra_timing_vals {
|
|||||||
double cwnd; /* Congestion window - in probes */
|
double cwnd; /* Congestion window - in probes */
|
||||||
int ssthresh; /* The threshold above which mode is changed from slow start
|
int ssthresh; /* The threshold above which mode is changed from slow start
|
||||||
to congestion avoidance */
|
to congestion avoidance */
|
||||||
int num_updates; /* Number of updates to this utv (generally packet receipts ) */
|
/* The number of replies we would expect if every probe produced a reply. This
|
||||||
|
is almost like the total number of probes sent but it is not incremented
|
||||||
|
until a reply is received or a probe times out. This and
|
||||||
|
num_replies_received are used to scale congestion window increments. */
|
||||||
|
int num_replies_expected;
|
||||||
|
/* The number of replies we've received to probes of any type. */
|
||||||
|
int num_replies_received;
|
||||||
|
/* Number of updates to this timing structure (generally packet receipts). */
|
||||||
|
int num_updates;
|
||||||
/* Last time values were adjusted for a drop (you usually only want
|
/* Last time values were adjusted for a drop (you usually only want
|
||||||
to adjust again based on probes sent after that adjustment so a
|
to adjust again based on probes sent after that adjustment so a
|
||||||
sudden batch of drops doesn't destroy timing. Init to now */
|
sudden batch of drops doesn't destroy timing. Init to now */
|
||||||
@@ -323,11 +331,9 @@ public:
|
|||||||
int numprobes; /* Number of probes/ports scanned on each host */
|
int numprobes; /* Number of probes/ports scanned on each host */
|
||||||
/* The last time waitForResponses finished (initialized to GSS creation time */
|
/* The last time waitForResponses finished (initialized to GSS creation time */
|
||||||
int probes_sent; /* Number of probes sent in total. This DOES include pings and retransmissions */
|
int probes_sent; /* Number of probes sent in total. This DOES include pings and retransmissions */
|
||||||
int probes_replied_to; /* The number of probes for which we've received
|
|
||||||
responses. Used for scaling congestion window increments. */
|
|
||||||
|
|
||||||
/* Returns the scaling factor to use when incrementing the congestion window.
|
/* Returns the scaling factor to use when incrementing the congestion
|
||||||
This is the minimum of probes_sent / probes_replied_to and cc_scale_max. */
|
window. */
|
||||||
double cc_scale();
|
double cc_scale();
|
||||||
|
|
||||||
/* The most recently received probe response time -- initialized to scan
|
/* The most recently received probe response time -- initialized to scan
|
||||||
@@ -546,16 +552,11 @@ public:
|
|||||||
bool tryno_mayincrease;
|
bool tryno_mayincrease;
|
||||||
int ports_finished; /* The number of ports of this host that have been determined */
|
int ports_finished; /* The number of ports of this host that have been determined */
|
||||||
int numprobes_sent; /* Number of port probes (not counting pings, but counting retransmits) sent to this host */
|
int numprobes_sent; /* Number of port probes (not counting pings, but counting retransmits) sent to this host */
|
||||||
int numpings_sent;
|
/* Returns the scaling factor to use when incrementing the congestion
|
||||||
|
window. */
|
||||||
|
double cc_scale();
|
||||||
/* Boost the scan delay for this host, usually because too many packet
|
/* Boost the scan delay for this host, usually because too many packet
|
||||||
drops were detected. */
|
drops were detected. */
|
||||||
int numprobes_replied_to; /* The number of probes for which we've received
|
|
||||||
responses. Used for scaling congestion window increments. */
|
|
||||||
/* Returns the scaling factor to use when incrementing the congestion window.
|
|
||||||
This is the minimum of
|
|
||||||
(numprobes_sent + numpings_sent) / numprobes_replied_to and
|
|
||||||
cc_scale_max. */
|
|
||||||
double cc_scale();
|
|
||||||
void boostScanDelay();
|
void boostScanDelay();
|
||||||
struct send_delay_nfo sdn;
|
struct send_delay_nfo sdn;
|
||||||
struct rate_limit_detection_nfo rld;
|
struct rate_limit_detection_nfo rld;
|
||||||
@@ -876,7 +877,6 @@ GroupScanStats::GroupScanStats(UltraScanInfo *UltraSI) {
|
|||||||
CSI = new ConnectScanInfo;
|
CSI = new ConnectScanInfo;
|
||||||
else CSI = NULL;
|
else CSI = NULL;
|
||||||
probes_sent = probes_sent_at_last_wait = 0;
|
probes_sent = probes_sent_at_last_wait = 0;
|
||||||
probes_replied_to = 0;
|
|
||||||
lastping_sent = lastrcvd = USI->now;
|
lastping_sent = lastrcvd = USI->now;
|
||||||
send_no_earlier_than = USI->now;
|
send_no_earlier_than = USI->now;
|
||||||
send_no_later_than = USI->now;
|
send_no_later_than = USI->now;
|
||||||
@@ -1002,14 +1002,13 @@ bool GroupScanStats::sendOK(struct timeval *when) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the scaling factor to use when incrementing the congestion window.
|
/* Returns the scaling factor to use when incrementing the congestion window.
|
||||||
This is the minimum of probes_sent / probes_replied_to and cc_scale_max. */
|
This is the minimum of num_replies_expected / num_replies_received and
|
||||||
|
cc_scale_max. */
|
||||||
double GroupScanStats::cc_scale() {
|
double GroupScanStats::cc_scale() {
|
||||||
double ratio;
|
double ratio;
|
||||||
|
|
||||||
if (probes_replied_to == 0)
|
assert(timing.num_replies_received > 0);
|
||||||
return USI->perf.cc_scale_max;
|
ratio = (double) timing.num_replies_expected / timing.num_replies_received;
|
||||||
|
|
||||||
ratio = (double) probes_sent / probes_replied_to;
|
|
||||||
|
|
||||||
return MIN(ratio, USI->perf.cc_scale_max);
|
return MIN(ratio, USI->perf.cc_scale_max);
|
||||||
}
|
}
|
||||||
@@ -1088,8 +1087,6 @@ HostScanStats::HostScanStats(Target *t, UltraScanInfo *UltraSI) {
|
|||||||
tryno_mayincrease = true;
|
tryno_mayincrease = true;
|
||||||
ports_finished = 0;
|
ports_finished = 0;
|
||||||
numprobes_sent = 0;
|
numprobes_sent = 0;
|
||||||
numpings_sent = 0;
|
|
||||||
numprobes_replied_to = 0;
|
|
||||||
memset(&completiontime, 0, sizeof(completiontime));
|
memset(&completiontime, 0, sizeof(completiontime));
|
||||||
init_ultra_timing_vals(&timing, TIMING_HOST, 1, &(USI->perf), &USI->now);
|
init_ultra_timing_vals(&timing, TIMING_HOST, 1, &(USI->perf), &USI->now);
|
||||||
bench_tryno = 0;
|
bench_tryno = 0;
|
||||||
@@ -1813,6 +1810,8 @@ static void init_ultra_timing_vals(ultra_timing_vals *timing,
|
|||||||
struct timeval *now) {
|
struct timeval *now) {
|
||||||
timing->cwnd = (utt == TIMING_HOST)? perf->host_initial_cwnd : perf->group_initial_cwnd;
|
timing->cwnd = (utt == TIMING_HOST)? perf->host_initial_cwnd : perf->group_initial_cwnd;
|
||||||
timing->ssthresh = perf->initial_ssthresh; /* Will be reduced if any packets are dropped anyway */
|
timing->ssthresh = perf->initial_ssthresh; /* Will be reduced if any packets are dropped anyway */
|
||||||
|
timing->num_replies_expected = 0;
|
||||||
|
timing->num_replies_received = 0;
|
||||||
timing->num_updates = 0;
|
timing->num_updates = 0;
|
||||||
if (now)
|
if (now)
|
||||||
timing->last_drop = *now;
|
timing->last_drop = *now;
|
||||||
@@ -2047,15 +2046,17 @@ static void ultrascan_adjust_timing(UltraScanInfo *USI, HostScanStats *hss,
|
|||||||
struct timeval *rcvdtime) {
|
struct timeval *rcvdtime) {
|
||||||
int ping_magnifier = (probe->isPing())? USI->perf.ping_magnifier : 1;
|
int ping_magnifier = (probe->isPing())? USI->perf.ping_magnifier : 1;
|
||||||
|
|
||||||
hss->timing.num_updates++;
|
USI->gstats->timing.num_replies_expected++;
|
||||||
USI->gstats->timing.num_updates++;
|
USI->gstats->timing.num_updates++;
|
||||||
|
|
||||||
USI->gstats->probes_replied_to++;
|
hss->timing.num_replies_expected++;
|
||||||
hss->numprobes_replied_to++;
|
hss->timing.num_updates++;
|
||||||
|
|
||||||
/* Adjust window */
|
if ((probe->tryno > 0 && rcvdtime != NULL)
|
||||||
if (probe->tryno > 0 || !rcvdtime) {
|
|| (probe->isPing() && rcvdtime == NULL)) {
|
||||||
/* A previous probe must have been lost ... */
|
/* We consider it a drop if
|
||||||
|
1. We get a positive response to a retransmitted probe, or
|
||||||
|
2. We get no response to a timing print probe. */
|
||||||
if (o.debugging > 1)
|
if (o.debugging > 1)
|
||||||
log_write(LOG_PLAIN, "Ultrascan DROPPED %sprobe packet to %s detected\n", probe->isPing()? "PING " : "", hss->target->targetipstr());
|
log_write(LOG_PLAIN, "Ultrascan DROPPED %sprobe packet to %s detected\n", probe->isPing()? "PING " : "", hss->target->targetipstr());
|
||||||
// Drops often come in big batches, but we only want one decrease per batch.
|
// Drops often come in big batches, but we only want one decrease per batch.
|
||||||
@@ -2069,20 +2070,11 @@ static void ultrascan_adjust_timing(UltraScanInfo *USI, HostScanStats *hss,
|
|||||||
USI->gstats->timing.ssthresh = (int) MAX(USI->gstats->num_probes_active / USI->perf.group_drop_ssthresh_divisor, 2);
|
USI->gstats->timing.ssthresh = (int) MAX(USI->gstats->num_probes_active / USI->perf.group_drop_ssthresh_divisor, 2);
|
||||||
USI->gstats->timing.last_drop = USI->now;
|
USI->gstats->timing.last_drop = USI->now;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (rcvdtime != NULL) {
|
||||||
/* Good news -- got a response to first try. Increase window as
|
/* Good news -- got a response to first try. Increase window as
|
||||||
appropriate. */
|
appropriate. */
|
||||||
if (hss->timing.cwnd < hss->timing.ssthresh) {
|
USI->gstats->timing.num_replies_received++;
|
||||||
/* In slow start mode */
|
hss->timing.num_replies_received++;
|
||||||
hss->timing.cwnd += ping_magnifier * USI->perf.slow_incr * hss->cc_scale();
|
|
||||||
if (hss->timing.cwnd > hss->timing.ssthresh)
|
|
||||||
hss->timing.cwnd = hss->timing.ssthresh;
|
|
||||||
} else {
|
|
||||||
/* Congestion avoidance mode */
|
|
||||||
hss->timing.cwnd += ping_magnifier * USI->perf.ca_incr / hss->timing.cwnd * hss->cc_scale();
|
|
||||||
}
|
|
||||||
if (hss->timing.cwnd > USI->perf.max_cwnd)
|
|
||||||
hss->timing.cwnd = USI->perf.max_cwnd;
|
|
||||||
|
|
||||||
if (USI->gstats->timing.cwnd < USI->gstats->timing.ssthresh) {
|
if (USI->gstats->timing.cwnd < USI->gstats->timing.ssthresh) {
|
||||||
/* In slow start mode */
|
/* In slow start mode */
|
||||||
@@ -2095,7 +2087,20 @@ static void ultrascan_adjust_timing(UltraScanInfo *USI, HostScanStats *hss,
|
|||||||
}
|
}
|
||||||
if (USI->gstats->timing.cwnd > USI->perf.max_cwnd)
|
if (USI->gstats->timing.cwnd > USI->perf.max_cwnd)
|
||||||
USI->gstats->timing.cwnd = USI->perf.max_cwnd;
|
USI->gstats->timing.cwnd = USI->perf.max_cwnd;
|
||||||
|
|
||||||
|
if (hss->timing.cwnd < hss->timing.ssthresh) {
|
||||||
|
/* In slow start mode */
|
||||||
|
hss->timing.cwnd += 1.0 * hss->cc_scale();
|
||||||
|
if (hss->timing.cwnd > hss->timing.ssthresh)
|
||||||
|
hss->timing.cwnd = hss->timing.ssthresh;
|
||||||
|
} else {
|
||||||
|
/* Congestion avoidance mode */
|
||||||
|
hss->timing.cwnd += 1.0 / hss->timing.cwnd * hss->cc_scale();
|
||||||
}
|
}
|
||||||
|
if (hss->timing.cwnd > USI->perf.max_cwnd)
|
||||||
|
hss->timing.cwnd = USI->perf.max_cwnd;
|
||||||
|
}
|
||||||
|
/* If probe->tryno == 0 and rcvdtime == NULL, do nothing. */
|
||||||
|
|
||||||
/* If packet drops are particularly bad, enforce a delay between
|
/* If packet drops are particularly bad, enforce a delay between
|
||||||
packet sends (useful for cases such as UDP scan where responses
|
packet sends (useful for cases such as UDP scan where responses
|
||||||
@@ -2103,8 +2108,8 @@ static void ultrascan_adjust_timing(UltraScanInfo *USI, HostScanStats *hss,
|
|||||||
|
|
||||||
/* First we decide whether this packet counts as a drop for send
|
/* First we decide whether this packet counts as a drop for send
|
||||||
delay calculation purposes. This statement means if (a ping since last boost failed, or the previous packet was both sent after the last boost and dropped) */
|
delay calculation purposes. This statement means if (a ping since last boost failed, or the previous packet was both sent after the last boost and dropped) */
|
||||||
if ((!rcvdtime && TIMEVAL_AFTER(probe->sent, hss->sdn.last_boost)) ||
|
if ((probe->isPing() && rcvdtime == NULL && TIMEVAL_AFTER(probe->sent, hss->sdn.last_boost)) ||
|
||||||
(probe->tryno > 0 && TIMEVAL_AFTER(probe->prevSent, hss->sdn.last_boost))) {
|
(probe->tryno > 0 && rcvdtime != NULL && TIMEVAL_AFTER(probe->prevSent, hss->sdn.last_boost))) {
|
||||||
hss->sdn.droppedRespSinceDelayChanged++;
|
hss->sdn.droppedRespSinceDelayChanged++;
|
||||||
// printf("SDELAY: increasing drops to %d (good: %d; tryno: %d, sent: %.4fs; prevSent: %.4fs, last_boost: %.4fs\n", hss->sdn.droppedRespSinceDelayChanged, hss->sdn.goodRespSinceDelayChanged, probe->tryno, o.TimeSinceStartMS(&probe->sent) / 1000.0, o.TimeSinceStartMS(&probe->prevSent) / 1000.0, o.TimeSinceStartMS(&hss->sdn.last_boost) / 1000.0);
|
// printf("SDELAY: increasing drops to %d (good: %d; tryno: %d, sent: %.4fs; prevSent: %.4fs, last_boost: %.4fs\n", hss->sdn.droppedRespSinceDelayChanged, hss->sdn.goodRespSinceDelayChanged, probe->tryno, o.TimeSinceStartMS(&probe->sent) / 1000.0, o.TimeSinceStartMS(&probe->prevSent) / 1000.0, o.TimeSinceStartMS(&hss->sdn.last_boost) / 1000.0);
|
||||||
} else if (rcvdtime) {
|
} else if (rcvdtime) {
|
||||||
@@ -2137,11 +2142,10 @@ void HostScanStats::markProbeTimedout(list<UltraProbe *>::iterator probeI) {
|
|||||||
num_probes_active--;
|
num_probes_active--;
|
||||||
assert(USI->gstats->num_probes_active > 0);
|
assert(USI->gstats->num_probes_active > 0);
|
||||||
USI->gstats->num_probes_active--;
|
USI->gstats->num_probes_active--;
|
||||||
if (probe->isPing()) {
|
|
||||||
ultrascan_adjust_timing(USI, this, probe, NULL);
|
ultrascan_adjust_timing(USI, this, probe, NULL);
|
||||||
/* I'll leave it in the queue in case some response ever does
|
if (!probe->isPing())
|
||||||
come */
|
/* I'll leave it in the queue in case some response ever does come */
|
||||||
} else num_probes_waiting_retransmit++;
|
num_probes_waiting_retransmit++;
|
||||||
|
|
||||||
if (probe->type == UltraProbe::UP_CONNECT && probe->CP()->sd >= 0 ) {
|
if (probe->type == UltraProbe::UP_CONNECT && probe->CP()->sd >= 0 ) {
|
||||||
/* Free the socket as that is a valuable resource, though it is a shame
|
/* Free the socket as that is a valuable resource, though it is a shame
|
||||||
@@ -2448,15 +2452,13 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the scaling factor to use when incrementing the congestion window.
|
/* Returns the scaling factor to use when incrementing the congestion window.
|
||||||
This is the minimum of
|
This is the minimum of num_replies_expected / num_replies_received and
|
||||||
(numprobes_sent + numpings_sent) / numprobes_replied_to and cc_scale_max. */
|
cc_scale_max. */
|
||||||
double HostScanStats::cc_scale() {
|
double HostScanStats::cc_scale() {
|
||||||
double ratio;
|
double ratio;
|
||||||
|
|
||||||
if (numprobes_replied_to == 0)
|
assert(timing.num_replies_received > 0);
|
||||||
return USI->perf.cc_scale_max;
|
ratio = (double) timing.num_replies_expected / timing.num_replies_received;
|
||||||
|
|
||||||
ratio = (double) (numprobes_sent + numpings_sent) / numprobes_replied_to;
|
|
||||||
|
|
||||||
return MIN(ratio, USI->perf.cc_scale_max);
|
return MIN(ratio, USI->perf.cc_scale_max);
|
||||||
}
|
}
|
||||||
@@ -2587,7 +2589,7 @@ static void ultrascan_host_probe_update(UltraScanInfo *USI, HostScanStats *hss,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ultrascan_adjust_timeouts(USI, hss, probe, rcvdtime);
|
ultrascan_adjust_timeouts(USI, hss, probe, rcvdtime);
|
||||||
if (adjust_timing && rcvdtime != NULL)
|
if (adjust_timing)
|
||||||
ultrascan_adjust_timing(USI, hss, probe, rcvdtime);
|
ultrascan_adjust_timing(USI, hss, probe, rcvdtime);
|
||||||
|
|
||||||
ultrascan_host_pspec_update(USI, hss, probe->pspec(), newstate);
|
ultrascan_host_pspec_update(USI, hss, probe->pspec(), newstate);
|
||||||
@@ -2644,9 +2646,6 @@ static void ultrascan_port_probe_update(UltraScanInfo *USI, HostScanStats *hss,
|
|||||||
ultrascan_adjust_timeouts(USI, hss, probe, rcvdtime);
|
ultrascan_adjust_timeouts(USI, hss, probe, rcvdtime);
|
||||||
|
|
||||||
if (adjust_timing &&
|
if (adjust_timing &&
|
||||||
/* The rcvdtime check is because this func is called that way when
|
|
||||||
we give up on a probe because of too many retransmissions. */
|
|
||||||
rcvdtime &&
|
|
||||||
/* If we are not in "noresp_open_scan" and got something back and the
|
/* If we are not in "noresp_open_scan" and got something back and the
|
||||||
* newstate is PORT_FILTERED then we got ICMP error response.
|
* newstate is PORT_FILTERED then we got ICMP error response.
|
||||||
* ICMP errors are often rate-limited (RFC1812) and/or generated by
|
* ICMP errors are often rate-limited (RFC1812) and/or generated by
|
||||||
@@ -3120,7 +3119,6 @@ static void sendPingProbe(UltraScanInfo *USI, HostScanStats *hss) {
|
|||||||
} else {
|
} else {
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
hss->numpings_sent++;
|
|
||||||
USI->gstats->probes_sent++;
|
USI->gstats->probes_sent++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user