1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-26 17:39:03 +00:00

This commit changes two separate but related things, which I found it

inconvenient to change separately.

The first change fixes a logical error in the storage of timing ping
probes. Each target contains a description of a timing ping probe, which
is stored in the two members
  probespec pingprobe;
  int pingprobe_state;
pingprobe is the probe itself, and pingprobe_state is the state of the
port that the probe was sent to (PORT_OPEN, PORT_CLOSED, etc.). A change
in the state of the port was a criterion used in deciding whether to
replace the current ping probe.

The problem with this was that pingprobe_state was used to hold a host
state, not a port state, during host discovery. Therefore it held a
value like HOST_DOWN or HOST_UP. This was fine as long as host discovery
and port scanning were separate, but now that timing pings are shared
between those phases the states were in confict: HOST_UP = 1 = PORT_CLOSED.
THis was fixed by using a value of PORT_UNKNOWN during host discovery.

The second change redoes how timing ping probes are replaced. There is
now an order of preference for timing ping probe types, defined by the
function pingprobe_score (and pingprobe_is_better, which calls it). The
order I have defined, from highest preference to lowest, is
	ARP
	Raw TCP (not SYN to an open port)
	UDP, IP protocol, or ICMP
	Raw TCP (SYN to an open port)
	TCP connect
	Anything else
The port state is considered only in raw TCP SYN to an open port, which
is given a lower preference because of the possibility of SYN flooding.

Better ping probes supersede worse ping probes. So in
	nmap -PS -sA scanme.nmap.org
the ping probe will be SYN to port 80 after host discovery, but then
will change to ACK to an unfiltered port during port scanning. In
	nmap -PA -sS scanme.nmap.org
the ping probe will be ACK to port 80 after host discovery and will
remain that way during port scanning because SYN to an open port is a
worse ping probe. Run with -d2 to see when timing pings change.
This commit is contained in:
david
2008-07-12 02:18:18 +00:00
parent c7f8b5728a
commit 8161f16c0e

View File

@@ -649,7 +649,7 @@ static void init_ultra_timing_vals(ultra_timing_vals *timing,
/* Take a buffer, buf, of size bufsz (32 bytes is sufficient) and
writes a short description of the probe (arg1) into buf. It also returns
buf. */
static char *probespec2ascii(probespec *pspec, char *buf, unsigned int bufsz) {
static char *probespec2ascii(const probespec *pspec, char *buf, unsigned int bufsz) {
char flagbuf[32];
char *f;
switch(pspec->type) {
@@ -2192,6 +2192,56 @@ void HostScanStats::getTiming(struct ultra_timing_vals *tmng) {
return;
}
/* Define a score for a ping probe, for the purposes of deciding whether one
probe should be preferred to another. The order, from most preferred to least
preferred, is
ARP
Raw TCP (not SYN to an open port)
UDP, IP protocol, or ICMP
Raw TCP (SYN to an open port)
TCP connect
Anything else
Raw TCP SYN to an open port is given a low preference because of the risk of
SYN flooding (this is the only case where the port state is considered). The
probe passed to this function is assumed to have received a positive
response, that is, it should not have set a port state just by timing out. */
static unsigned int pingprobe_score(const probespec *pspec, int state) {
unsigned int score;
switch (pspec->type) {
case PS_ARP:
score = 5;
break;
case PS_TCP:
if (pspec->pd.tcp.flags == TH_SYN && (state == PORT_OPEN || state == PORT_UNKNOWN))
score = 2;
else
score = 4;
break;
case PS_UDP:
case PS_PROTO:
case PS_ICMP:
score = 3;
break;
case PS_CONNECTTCP:
score = 1;
break;
case PS_NONE:
default:
score = 0;
break;
}
return score;
}
/* Return true if new_probe and new_state define a better ping probe, as defined
by pingprobe_score, than do old_probe and old_state. */
static bool pingprobe_is_better(const probespec *new_probe, int new_state,
const probespec *old_probe, int old_state) {
return pingprobe_score(new_probe, new_state) > pingprobe_score(old_probe, old_state);
}
static void ultrascan_host_pspec_update(UltraScanInfo *USI, HostScanStats *hss,
const probespec *pspec, int newstate);
@@ -2206,7 +2256,6 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
u8 proto = 0;
int oldstate = PORT_TESTING;
Port *currentp;
bool swappingport = false;
/* Whether no response means a port is open */
bool noresp_open_scan = USI->noresp_open_scan;
@@ -2275,28 +2324,6 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
break;
}
/* Consider changing the ping port */
if (hss->target->pingprobe_state != newstate) {
/* TODO: UDP scan and such will have different preferences -- add them */
if (noresp_open_scan) {
if (newstate == PORT_CLOSED || (hss->target->pingprobe_state == PORT_UNKNOWN && newstate == PORT_FILTERED))
swappingport = true;
} else {
if (hss->target->pingprobe_state == PORT_UNKNOWN &&
(newstate == PORT_OPEN || newstate == PORT_CLOSED || newstate == PORT_UNFILTERED))
swappingport = true;
else if (hss->target->pingprobe_state == PORT_OPEN && (newstate == PORT_CLOSED || newstate == PORT_UNFILTERED))
swappingport = true;
}
if (swappingport) {
if (o.debugging > 1)
log_write(LOG_PLAIN, "Changing ping technique for %s to %s\n", hss->target->targetipstr(), pspectype2ascii(pspec->type));
hss->target->pingprobe = *pspec;
hss->target->pingprobe_state = newstate;
}
}
return oldstate != newstate;
}
@@ -2419,24 +2446,6 @@ static void ultrascan_host_pspec_update(UltraScanInfo *USI, HostScanStats *hss,
hss->target->flags |= HOST_DOWN;
} else assert(0);
}
/* Consider changing the ping port */
if (hss->target->pingprobe_state != newstate) {
if (hss->target->pingprobe_state == PORT_UNKNOWN && newstate == HOST_UP) {
if (o.debugging > 1)
log_write(LOG_PLAIN, "Changing ping technique for %s to %s\n", hss->target->targetipstr(), pspectype2ascii(pspec->type));
hss->target->pingprobe = *pspec;
hss->target->pingprobe_state = newstate;
/* Make this the new global ping host, but only if it's not waiting for
any probes. */
if (USI->gstats->pinghost == NULL
|| USI->gstats->pinghost->probes_outstanding_empty()) {
if (o.debugging > 1)
log_write(LOG_PLAIN, "Changing global ping host to %s.\n", hss->target->targetipstr());
USI->gstats->pinghost = hss;
}
}
}
}
/* Called when a new status is determined for host in hss (eg. it is
@@ -2463,6 +2472,20 @@ static void ultrascan_host_probe_update(UltraScanInfo *USI, HostScanStats *hss,
ultrascan_host_pspec_update(USI, hss, probe->pspec(), newstate);
if (rcvdtime != NULL) {
/* This probe received a positive response. Consider making it the new
timing ping probe. */
if (pingprobe_is_better(probe->pspec(), PORT_UNKNOWN, &hss->target->pingprobe, hss->target->pingprobe_state)) {
if (o.debugging > 1) {
char buf[32];
probespec2ascii(probe->pspec(), buf, sizeof(buf));
log_write(LOG_PLAIN, "Changing ping technique for %s to %s\n", hss->target->targetipstr(), buf);
}
hss->target->pingprobe = *probe->pspec();
hss->target->pingprobe_state = PORT_UNKNOWN;
}
}
hss->destroyOutstandingProbe(probeI);
}
@@ -2484,6 +2507,20 @@ static void ultrascan_port_probe_update(UltraScanInfo *USI, HostScanStats *hss,
changed = ultrascan_port_pspec_update(USI, hss, pspec, newstate);
if (rcvdtime != NULL) {
/* This probe received a positive response. Consider making it the new
timing ping probe. */
if (pingprobe_is_better(probe->pspec(), newstate, &hss->target->pingprobe, hss->target->pingprobe_state)) {
if (o.debugging > 1) {
char buf[32];
probespec2ascii(probe->pspec(), buf, sizeof(buf));
log_write(LOG_PLAIN, "Changing ping technique for %s to %s\n", hss->target->targetipstr(), buf);
}
hss->target->pingprobe = *probe->pspec();
hss->target->pingprobe_state = newstate;
}
}
ultrascan_adjust_timeouts(USI, hss, probe, rcvdtime);
if (adjust_timing &&
@@ -2988,7 +3025,7 @@ static void doAnyPings(UltraScanInfo *USI) {
for(hostI = USI->incompleteHosts.begin();
hostI != USI->incompleteHosts.end(); hostI++) {
hss = *hostI;
if (hss->target->pingprobe_state != PORT_UNKNOWN &&
if (hss->target->pingprobe.type != PS_NONE &&
hss->rld.rld_waiting == false &&
hss->numprobes_sent >= hss->lastping_sent_numprobes + 10 &&
TIMEVAL_SUBTRACT(USI->now, hss->lastrcvd) > USI->perf.pingtime &&