1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-25 08:59:01 +00:00

Merge the minimum-rate scanning feature (--min-rate) from

/nmap-exp/david/nmap-fixed-rate.
This commit is contained in:
david
2008-03-26 02:41:32 +00:00
parent dd220398b1
commit feab94ebd3
8 changed files with 351 additions and 14 deletions

View File

@@ -346,8 +346,9 @@ public:
struct sockaddr_storage latestip;
GroupScanStats(UltraScanInfo *UltraSI);
~GroupScanStats();
void probeSent();
/* Returns true if the GLOBAL system says that sending is OK. */
bool sendOK();
bool sendOK(struct timeval *when);
/* Total # of probes outstanding (active) for all Hosts */
int num_probes_active;
UltraScanInfo *USI; /* The USI which contains this GSS. Use for at least
@@ -373,6 +374,9 @@ public:
/* Value of numprobes_sent at lastping_sent time -- to ensure that we don't
send too many pings when probes are going slowly. */
int lastping_sent_numprobes;
/* When to send the next probe, to keep the minimum up. Used only when a
minimum sending rate (o.min_packet_send_rate) is set. */
struct timeval send_no_later_than;
/* The host to which global pings are sent. This is kept updated to be the
most recent host that was found up. */
@@ -653,6 +657,7 @@ public:
list<HostScanStats *> completedHosts;
ScanProgressMeter *SPM;
RateMeter send_rate_meter;
struct scan_lists *ports;
int rawsd; /* raw socket descriptor */
pcap_t *pd;
@@ -874,6 +879,7 @@ GroupScanStats::GroupScanStats(UltraScanInfo *UltraSI) {
probes_sent = probes_sent_at_last_wait = 0;
probes_replied_to = 0;
lastping_sent = lastrcvd = USI->now;
send_no_later_than = USI->now;
lastping_sent_numprobes = 0;
pinghost = NULL;
gettimeofday(&last_wait, NULL);
@@ -884,10 +890,27 @@ GroupScanStats::~GroupScanStats() {
delete CSI;
}
void GroupScanStats::probeSent() {
/* Find the next scheduled send time for minimum-rate scanning. */
if (TIMEVAL_SUBTRACT(send_no_later_than, USI->now) > 0) {
/* The next scheduled send is in the future. That means we're ahead of
schedule, but it also means there's slack time during which the sending
rate could drop. Reschedule the send to keep that from happening. */
send_no_later_than = USI->now;
}
TIMEVAL_ADD(send_no_later_than, send_no_later_than,
(time_t) (1000000.0 / o.min_packet_send_rate));
}
/* Returns true if the GLOBAL system says that sending is OK.*/
bool GroupScanStats::sendOK() {
bool GroupScanStats::sendOK(struct timeval *when) {
int recentsends;
/* In case it's not okay to send, arbitrarily say to check back in one
second. */
if (when)
TIMEVAL_MSEC_ADD(*when, USI->now, 1000);
if ((USI->scantype == CONNECT_SCAN || USI->ptech.connecttcpscan)
&& CSI->numSDs >= CSI->maxSocketsAllowed)
return false;
@@ -914,13 +937,34 @@ bool GroupScanStats::sendOK() {
if (recentsends >= 50)
return false;
/* Enforce a minimum scanning rate, if necessary. If we're ahead of schedule,
record the time of the next scheduled send. If we're behind schedule,
return true to indicate that we need to send now, regardless of any
congestion control. */
if (o.min_packet_send_rate != 0.0) {
if (TIMEVAL_SUBTRACT(send_no_later_than, USI->now) > 0) {
if (when)
*when = send_no_later_than;
} else {
if (when)
*when = USI->now;
return true;
}
}
/* When there is only one target left, let the host congestion
stuff deal with it. */
if (USI->numIncompleteHostsLessThan(2))
if (USI->numIncompleteHostsLessThan(2)) {
if (when)
*when = USI->now;
return true;
}
if (timing.cwnd >= num_probes_active + 0.5)
if (timing.cwnd >= num_probes_active + 0.5) {
if (when)
*when = USI->now;
return true;
}
return false;
}
@@ -1053,6 +1097,16 @@ bool HostScanStats::sendOK(struct timeval *when) {
struct timeval probe_to, earliest_to, sendTime;
long tdiff;
/* If the group stats say we need to send a probe to enforce a minimum
scanning rate, then we need to step up and send a probe. */
if (o.min_packet_send_rate != 0.0) {
if (TIMEVAL_SUBTRACT(USI->gstats->send_no_later_than, USI->now) <= 0) {
if (when)
*when = USI->now;
return true;
}
}
if (target->timedOut(&USI->now) || completed()) {
if (when) *when = USI->now;
return false;
@@ -1293,6 +1347,7 @@ void UltraScanInfo::Init(vector<Target *> &Targets, struct scan_lists *pts, styp
seqmask = get_random_u32();
scantype = scantp;
SPM = new ScanProgressMeter(scantype2str(scantype));
send_rate_meter.start(&now);
tcp_scan = udp_scan = prot_scan = ping_scan = noresp_open_scan = false;
ping_scan_arp = false;
memset((char *) &ptech, 0, sizeof(ptech));
@@ -1447,11 +1502,12 @@ bool UltraScanInfo::sendOK(struct timeval *when) {
bool hgood = false;
bool thisHostGood = false;
bool foundgood = false;
ggood = gstats->sendOK();
ggood = gstats->sendOK(when);
if (!ggood) {
if (when) {
TIMEVAL_MSEC_ADD(lowhtime, now, 1000);
lowhtime = *when;
// Can't do anything until global is OK - means packet receipt
// or probe timeout.
for(host = incompleteHosts.begin(); host != incompleteHosts.end();
@@ -1482,6 +1538,13 @@ bool UltraScanInfo::sendOK(struct timeval *when) {
assert(foundgood);
}
/* Defer to the group stats if they need a shorter delay to enforce a minimum
packet sending rate. */
if (o.min_packet_send_rate != 0.0) {
if (TIMEVAL_MSEC_SUBTRACT(gstats->send_no_later_than, lowhtime) < 0)
lowhtime = gstats->send_no_later_than;
}
if (TIMEVAL_MSEC_SUBTRACT(lowhtime, now) < 0)
lowhtime = now;
@@ -2483,11 +2546,14 @@ static UltraProbe *sendConnectScanProbe(UltraScanInfo *USI, HostScanStats *hss,
else sin6->sin6_port = htons(probe->pspec()->pd.tcp.dport);
#endif
hss->lastprobe_sent = probe->sent = USI->now;
USI->gstats->probeSent();
rc = connect(CP->sd, (struct sockaddr *)&sock, socklen);
gettimeofday(&USI->now, NULL);
if (rc == -1) connect_errno = socket_errno();
PacketTrace::traceConnect(IPPROTO_TCP, (sockaddr *) &sock, socklen, rc,
connect_errno, &USI->now);
/* We don't record a byte count for connect probes. */
USI->send_rate_meter.record(0, &USI->now);
/* This counts as probe being sent, so update structures */
hss->probes_outstanding.push_back(probe);
probeI = hss->probes_outstanding.end();
@@ -2579,11 +2645,13 @@ static UltraProbe *sendArpScanProbe(UltraScanInfo *USI, HostScanStats *hss,
ETH_ADDR_BROADCAST, *hss->target->v4hostip());
gettimeofday(&USI->now, NULL);
hss->lastprobe_sent = probe->sent = USI->now;
USI->gstats->probeSent();
if ((rc = eth_send(USI->ethsd, frame, sizeof(frame))) != sizeof(frame)) {
int err = socket_errno();
error("WARNING: eth_send of ARP packet returned %i rather than expected %d (errno=%i: %s)", rc, (int) sizeof(frame), err, strerror(err));
}
PacketTrace::traceArp(PacketTrace::SENT, (u8 *) frame, sizeof(frame), &USI->now);
USI->send_rate_meter.record(sizeof(frame), &USI->now);
probe->tryno = tryno;
probe->pingseq = pingseq;
/* First build the probe */
@@ -2656,6 +2724,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->setIP(packet, packetlen, pspec);
hss->lastprobe_sent = probe->sent = USI->now;
}
USI->gstats->probeSent();
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
free(packet);
}
@@ -2671,6 +2740,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->setIP(packet, packetlen, pspec);
hss->lastprobe_sent = probe->sent = USI->now;
}
USI->gstats->probeSent();
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
free(packet);
}
@@ -2726,6 +2796,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->setIP(packet, packetlen, pspec);
hss->lastprobe_sent = probe->sent = USI->now;
}
USI->gstats->probeSent();
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
free(packet);
}
@@ -2748,10 +2819,12 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
probe->setIP(packet, packetlen, pspec);
hss->lastprobe_sent = probe->sent = USI->now;
}
USI->gstats->probeSent();
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
free(packet);
}
} else assert(0); /* TODO: Maybe RPC scan and the like */
USI->send_rate_meter.record(packetlen, &USI->now);
/* Now that the probe has been sent, add it to the Queue for this host */
hss->probes_outstanding.push_back(probe);
USI->gstats->num_probes_active++;
@@ -2811,7 +2884,7 @@ static void doAnyNewProbes(UltraScanInfo *USI) {
sending a probe. */
unableToSend = NULL;
hss = USI->nextIncompleteHost();
while (hss != NULL && hss != unableToSend && USI->gstats->sendOK()) {
while (hss != NULL && hss != unableToSend && USI->gstats->sendOK(NULL)) {
if (hss->freshPortsLeft() && hss->sendOK(NULL)) {
sendNextScanProbe(USI, hss);
unableToSend = NULL;
@@ -2834,7 +2907,7 @@ static void doAnyRetryStackRetransmits(UltraScanInfo *USI) {
sending a probe. */
unableToSend = NULL;
hss = USI->nextIncompleteHost();
while (hss != NULL && hss != unableToSend && USI->gstats->sendOK()) {
while (hss != NULL && hss != unableToSend && USI->gstats->sendOK(NULL)) {
if (!hss->retry_stack.empty() && hss->sendOK(NULL)) {
sendNextRetryStackProbe(USI, hss);
unableToSend = NULL;
@@ -2901,7 +2974,7 @@ static void doAnyPings(UltraScanInfo *USI) {
hss->numprobes_sent >= hss->lastping_sent_numprobes + 10 &&
TIMEVAL_SUBTRACT(USI->now, hss->lastrcvd) > USI->perf.pingtime &&
TIMEVAL_SUBTRACT(USI->now, hss->lastping_sent) > USI->perf.pingtime &&
USI->gstats->sendOK() && hss->sendOK(NULL)) {
USI->gstats->sendOK(NULL) && hss->sendOK(NULL)) {
sendPingProbe(USI, hss);
hss->lastping_sent = USI->now;
hss->lastping_sent_numprobes = hss->numprobes_sent;
@@ -2914,7 +2987,7 @@ static void doAnyPings(UltraScanInfo *USI) {
USI->gstats->probes_sent >= USI->gstats->lastping_sent_numprobes + 20 &&
TIMEVAL_SUBTRACT(USI->now, USI->gstats->lastrcvd) > USI->perf.pingtime &&
TIMEVAL_SUBTRACT(USI->now, USI->gstats->lastping_sent) > USI->perf.pingtime &&
USI->gstats->sendOK()) {
USI->gstats->sendOK(NULL)) {
sendGlobalPingProbe(USI);
USI->gstats->lastping_sent = USI->now;
USI->gstats->lastping_sent_numprobes = USI->gstats->probes_sent;
@@ -2966,6 +3039,12 @@ static void doAnyOutstandingRetransmits(UltraScanInfo *USI) {
int retrans = 0; /* Number of retransmissions during a loop */
unsigned int maxtries;
struct timeval tv_start = {0};
if (o.debugging) {
gettimeofday(&USI->now, NULL);
tv_start = USI->now;
}
gettimeofday(&USI->now, NULL);
/* Loop until we get through all the hosts without a retransmit or we're not
@@ -2973,7 +3052,7 @@ static void doAnyOutstandingRetransmits(UltraScanInfo *USI) {
do {
retrans = 0;
for (hostI = USI->incompleteHosts.begin();
hostI != USI->incompleteHosts.end() && USI->gstats->sendOK();
hostI != USI->incompleteHosts.end() && USI->gstats->sendOK(NULL);
hostI++) {
host = *hostI;
/* Skip this host if it has nothing to send. */
@@ -3006,7 +3085,14 @@ static void doAnyOutstandingRetransmits(UltraScanInfo *USI) {
}
} while (probeI != host->probes_outstanding.begin());
}
} while (USI->gstats->sendOK() && retrans != 0);
} while (USI->gstats->sendOK(NULL) && retrans != 0);
if (o.debugging) {
long tv_diff;
gettimeofday(&USI->now, NULL);
tv_diff = TIMEVAL_MSEC_SUBTRACT(USI->now, tv_start);
if (tv_diff > 30) log_write(LOG_PLAIN, "%s took %lims\n", __func__, tv_diff);
}
}
/* Print occasional remaining time estimates, as well as
@@ -3041,6 +3127,13 @@ static void printAnyStats(UltraScanInfo *USI) {
hss->target->to.rttvar);
}
}
log_write(LOG_PLAIN, "Current sending rates: %.2f packets / s, %.2f bytes / s.\n",
USI->send_rate_meter.getCurrentPacketRate(),
USI->send_rate_meter.getCurrentByteRate());
log_write(LOG_PLAIN, "Overall sending rates: %.2f packets / s, %.2f bytes / s.\n",
USI->send_rate_meter.getOverallPacketRate(),
USI->send_rate_meter.getOverallByteRate());
}
/* Now time to figure out how close we are to completion ... */
@@ -4694,12 +4787,20 @@ void ultra_scan(vector<Target *> &Targets, struct scan_lists *ports,
avgdone /= USI->gstats->numtargets;
USI->SPM->printStats(avgdone, NULL); // This prints something like SYN Stealth Scan Timing: About 1.14% done; ETC: 15:01 (0:43:23 remaining);
/* Don't update when getting the current rates, otherwise we can get
anomalies (rates are too low) from having just done a potentially long
waitForResponses without sending any packets. */
log_write(LOG_STDOUT, "Current sending rates: %.2f packets / s, %.2f bytes / s.\n",
USI->send_rate_meter.getCurrentPacketRate(&USI->now, false),
USI->send_rate_meter.getCurrentByteRate(&USI->now, false));
log_flush(LOG_STDOUT);
}
}
USI->send_rate_meter.stop(&USI->now);
/* Save the computed timeouts. */
if (to != NULL)
*to = USI->gstats->to;
@@ -4718,6 +4819,9 @@ void ultra_scan(vector<Target *> &Targets, struct scan_lists *ports,
USI->gstats->num_hosts_timedout,
(USI->gstats->num_hosts_timedout == 1)? "host" : "hosts");
USI->SPM->endTask(NULL, additional_info);
log_write(LOG_STDOUT, "Overall sending rates: %.2f packets / s, %.2f bytes / s.\n",
USI->send_rate_meter.getOverallPacketRate(),
USI->send_rate_meter.getOverallByteRate());
}
if (o.debugging > 2 && USI->pd != NULL)