Combine tryno and pingseq

UltraProbe's tryno and pingseq attributes were mutually exclusive,
encoded in the same places in packets, and did not need more than 7 bits
to store. This change combines them into a bitfield. This simplifies
some logic, since they do not need to be distinguished from each other.

Additionally, in cases where the tryno is encoded in the source port
number, no further checks or decoding need to happen beyond comparing
the destination port of the response to the source port of the probe.
This commit is contained in:
dmiller 2021-08-06 02:47:57 +00:00
parent 01c1e00b83
commit 180c716ca5
6 changed files with 152 additions and 175 deletions

View file

@ -245,10 +245,9 @@ static char *probespec2ascii(const probespec *pspec, char *buf, unsigned int buf
UltraProbe::UltraProbe() {
type = UP_UNSET;
tryno = 0;
tryno.opaque = 0;
timedout = false;
retransmitted = false;
pingseq = 0;
mypspec.type = PS_NONE;
memset(&sent, 0, sizeof(prevSent));
memset(&prevSent, 0, sizeof(prevSent));
@ -687,7 +686,7 @@ unsigned int HostScanStats::allowedTryno(bool *capped, bool *mayincrease) const
probeI != probes_outstanding.end(); probeI++) {
probe = *probeI;
assert(probe->timedout);
if (!probe->retransmitted && !probe->isPing() && probe->tryno < maxval) {
if (!probe->retransmitted && !probe->isPing() && probe->get_tryno() < maxval) {
/* Needs at least one more retransmit. */
allfinished = false;
break;
@ -1640,8 +1639,9 @@ static void ultrascan_adjust_timing(UltraScanInfo *USI, HostScanStats *hss,
1) We get a response to a retransmitted probe (meaning the first reply was
dropped), or
2) We got no response to a timing ping. */
if ((probe->tryno > 0 && rcvdtime != NULL)
|| (probe->isPing() && rcvdtime == NULL)) {
bool is_drop = (!probe->isPing() && probe->get_tryno() > 0 && rcvdtime != NULL)
|| (probe->isPing() && rcvdtime == NULL);
if (is_drop) {
if (o.debugging > 1)
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.
@ -1665,8 +1665,7 @@ static void ultrascan_adjust_timing(UltraScanInfo *USI, HostScanStats *hss,
/* 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) */
if ((probe->isPing() && rcvdtime == NULL && TIMEVAL_AFTER(probe->sent, hss->sdn.last_boost)) ||
(probe->tryno > 0 && rcvdtime != NULL && TIMEVAL_AFTER(probe->prevSent, hss->sdn.last_boost))) {
if (is_drop && TIMEVAL_AFTER(probe->sent, hss->sdn.last_boost)) {
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);
} else if (rcvdtime) {
@ -1976,9 +1975,9 @@ void HostScanStats::retransmitBench() {
void HostScanStats::moveProbeToBench(std::list<UltraProbe *>::iterator probeI) {
UltraProbe *probe = *probeI;
if (!probe_bench.empty())
assert(bench_tryno == probe->tryno);
assert(bench_tryno == probe->get_tryno());
else {
bench_tryno = probe->tryno;
bench_tryno = probe->get_tryno();
probe_bench.reserve(128);
}
probe_bench.push_back(*probe->pspec());
@ -2061,7 +2060,7 @@ void ultrascan_host_probe_update(UltraScanInfo *USI, HostScanStats *hss,
struct timeval tv;
gettimeofday(&tv, NULL);
log_write(LOG_STDOUT, "%s called for machine %s state %s -> %s (trynum %d time: %ld)\n", __func__, hss->target->targetipstr(), readhoststate(hss->target->flags), readhoststate(newstate), probe->tryno, (long) TIMEVAL_SUBTRACT(tv, probe->sent));
log_write(LOG_STDOUT, "%s called for machine %s state %s -> %s (trynum %d time: %ld)\n", __func__, hss->target->targetipstr(), readhoststate(hss->target->flags), readhoststate(newstate), probe->get_tryno(), (long) TIMEVAL_SUBTRACT(tv, probe->sent));
}
ultrascan_host_pspec_update(USI, hss, probe->pspec(), newstate);
@ -2076,10 +2075,10 @@ void ultrascan_host_probe_update(UltraScanInfo *USI, HostScanStats *hss,
/* If we got a response that meant "down" or "unknown", then it was an ICMP error. These
are often rate-limited (RFC 1812) or generated by a different host. We only
allow such responses to increase, not decrease, scanning speed by
disallowing drops (probe->tryno > 0), and we don't allow changing the ping
disallowing drops (probe->get_tryno() > 0), and we don't allow changing the ping
probe to something that's likely to get dropped. */
if (rcvdtime != NULL && newstate != HOST_UP) {
if (probe->tryno > 0) {
if (probe->get_tryno() > 0) {
if (adjust_timing && o.debugging > 1)
log_write(LOG_PLAIN, "Response for %s means new state is down; not adjusting timing.\n", hss->target->targetipstr());
adjust_timing = false;
@ -2133,10 +2132,10 @@ void ultrascan_port_probe_update(UltraScanInfo *USI, HostScanStats *hss,
/* If we got a response that meant "filtered", then it was an ICMP error.
These are often rate-limited (RFC 1812) or generated by a different host.
We only allow such responses to increase, not decrease, scanning speed by
not considering drops (probe->tryno > 0), and we don't allow changing the
not considering drops (probe->get_tryno() > 0), and we don't allow changing the
ping probe to something that's likely to get dropped. */
if (rcvdtime != NULL && newstate == PORT_FILTERED && !USI->noresp_open_scan) {
if (probe->tryno > 0) {
if (probe->get_tryno() > 0) {
if (adjust_timing && o.debugging > 1)
log_write(LOG_PLAIN, "Response for %s means new state is filtered; not adjusting timing.\n", hss->target->targetipstr());
adjust_timing = false;
@ -2153,7 +2152,7 @@ void ultrascan_port_probe_update(UltraScanInfo *USI, HostScanStats *hss,
if (rcvdtime != NULL
&& o.defeat_rst_ratelimit && newstate == PORT_CLOSED
&& !USI->noresp_open_scan) {
if (probe->tryno > 0)
if (probe->get_tryno() > 0)
adjust_timing = false;
adjust_ping = false;
}
@ -2172,7 +2171,7 @@ void ultrascan_port_probe_update(UltraScanInfo *USI, HostScanStats *hss,
&& o.defeat_icmp_ratelimit
&& (newstate == PORT_CLOSED || newstate == PORT_FILTERED)
&& USI->udp_scan) {
if (probe->tryno > 0)
if (probe->get_tryno() > 0)
adjust_timing = false;
adjust_ping = false;
}
@ -2180,9 +2179,9 @@ void ultrascan_port_probe_update(UltraScanInfo *USI, HostScanStats *hss,
if (adjust_timing) {
ultrascan_adjust_timing(USI, hss, probe, rcvdtime);
if (rcvdtime != NULL && probe->tryno > hss->max_successful_tryno) {
if (rcvdtime != NULL && probe->get_tryno() > hss->max_successful_tryno) {
/* We got a positive response to a higher tryno than we've seen so far. */
hss->max_successful_tryno = probe->tryno;
hss->max_successful_tryno = probe->get_tryno();
if (o.debugging)
log_write(LOG_STDOUT, "Increased max_successful_tryno for %s to %d (packet drop)\n", hss->target->targetipstr(), hss->max_successful_tryno);
if (hss->max_successful_tryno > ((o.timing_level >= 4) ? 4 : 3)) {
@ -2214,6 +2213,7 @@ void ultrascan_port_probe_update(UltraScanInfo *USI, HostScanStats *hss,
static void sendNextScanProbe(UltraScanInfo *USI, HostScanStats *hss) {
probespec pspec;
tryno_t tryno = {.opaque=0};
if (get_next_target_probe(USI, hss, &pspec) == -1) {
fatal("%s: No more probes! Error in Nmap.", __func__);
@ -2221,15 +2221,15 @@ static void sendNextScanProbe(UltraScanInfo *USI, HostScanStats *hss) {
hss->numprobes_sent++;
USI->gstats->probes_sent++;
if (pspec.type == PS_ARP)
sendArpScanProbe(USI, hss, 0, 0);
sendArpScanProbe(USI, hss, tryno);
else if (pspec.type == PS_ND)
sendNDScanProbe(USI, hss, 0, 0);
sendNDScanProbe(USI, hss, tryno);
else if (pspec.type == PS_CONNECTTCP)
sendConnectScanProbe(USI, hss, pspec.pd.tcp.dport, 0, 0);
sendConnectScanProbe(USI, hss, pspec.pd.tcp.dport, tryno);
else if (pspec.type == PS_TCP || pspec.type == PS_UDP
|| pspec.type == PS_SCTP || pspec.type == PS_PROTO
|| pspec.type == PS_ICMP || pspec.type == PS_ICMPV6)
sendIPScanProbe(USI, hss, &pspec, 0, 0);
sendIPScanProbe(USI, hss, &pspec, tryno);
else
assert(0);
}
@ -2246,11 +2246,14 @@ static void sendNextRetryStackProbe(UltraScanInfo *USI, HostScanStats *hss) {
pspec_tries = hss->retry_stack_tries.back();
hss->retry_stack_tries.pop_back();
tryno_t tryno = {.opaque=0};
tryno.fields.seqnum = pspec_tries + 1;
if (pspec.type == PS_CONNECTTCP)
sendConnectScanProbe(USI, hss, pspec.pd.tcp.dport, pspec_tries + 1, 0);
sendConnectScanProbe(USI, hss, pspec.pd.tcp.dport, tryno);
else {
assert(pspec.type != PS_ARP && pspec.type != PS_ND);
sendIPScanProbe(USI, hss, &pspec, pspec_tries + 1, 0);
sendIPScanProbe(USI, hss, &pspec, tryno);
}
}
@ -2305,24 +2308,35 @@ static void doAnyRetryStackRetransmits(UltraScanInfo *USI) {
checked that sending is OK w/congestion control and that pingprobe is
available */
static void sendPingProbe(UltraScanInfo *USI, HostScanStats *hss) {
tryno_t tryno = {.opaque=0};
tryno.fields.isPing = 1;
tryno.fields.seqnum = hss->nextPingSeq();
probespec *pingprobe = &hss->target->pingprobe;
switch (pingprobe->type) {
case PS_CONNECTTCP:
sendConnectScanProbe(USI, hss, pingprobe->pd.tcp.dport, tryno);
break;
case PS_TCP:
case PS_UDP:
case PS_SCTP:
case PS_PROTO:
case PS_ICMP:
sendIPScanProbe(USI, hss, pingprobe, tryno);
break;
case PS_ARP:
sendArpScanProbe(USI, hss, tryno);
break;
case PS_ND:
sendNDScanProbe(USI, hss, tryno);
break;
default:
assert(0);
}
if (o.debugging > 1) {
char tmpbuf[64];
log_write(LOG_PLAIN, "Ultrascan PING SENT to %s [%s]\n", hss->target->targetipstr(),
probespec2ascii(&hss->target->pingprobe, tmpbuf, sizeof(tmpbuf)));
}
if (hss->target->pingprobe.type == PS_CONNECTTCP) {
sendConnectScanProbe(USI, hss, hss->target->pingprobe.pd.tcp.dport, 0,
hss->nextPingSeq(true));
} else if (hss->target->pingprobe.type == PS_TCP || hss->target->pingprobe.type == PS_UDP
|| hss->target->pingprobe.type == PS_SCTP || hss->target->pingprobe.type == PS_PROTO
|| hss->target->pingprobe.type == PS_ICMP) {
sendIPScanProbe(USI, hss, &hss->target->pingprobe, 0, hss->nextPingSeq(true));
} else if (hss->target->pingprobe.type == PS_ARP) {
sendArpScanProbe(USI, hss, 0, hss->nextPingSeq(true));
} else if (hss->target->pingprobe.type == PS_ND) {
sendNDScanProbe(USI, hss, 0, hss->nextPingSeq(true));
} else {
assert(0);
probespec2ascii(pingprobe, tmpbuf, sizeof(tmpbuf)));
}
USI->gstats->probes_sent++;
}
@ -2381,26 +2395,28 @@ static void doAnyPings(UltraScanInfo *USI) {
static void retransmitProbe(UltraScanInfo *USI, HostScanStats *hss,
UltraProbe *probe) {
UltraProbe *newProbe = NULL;
tryno_t tryno = probe->tryno;
tryno.fields.seqnum++;
if (probe->type == UltraProbe::UP_IP) {
if (USI->prot_scan || USI->ptech.rawprotoscan)
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), probe->tryno + 1, 0);
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), tryno);
else if (probe->protocol() == IPPROTO_TCP) {
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), probe->tryno + 1, 0);
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), tryno);
} else if (probe->protocol() == IPPROTO_UDP) {
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), probe->tryno + 1, 0);
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), tryno);
} else if (probe->protocol() == IPPROTO_SCTP) {
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), probe->tryno + 1, 0);
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), tryno);
} else if (probe->protocol() == IPPROTO_ICMP || probe->protocol() == IPPROTO_ICMPV6) {
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), probe->tryno + 1, 0);
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), tryno);
} else {
assert(0);
}
} else if (probe->type == UltraProbe::UP_CONNECT) {
newProbe = sendConnectScanProbe(USI, hss, probe->pspec()->pd.tcp.dport, probe->tryno + 1, 0);
newProbe = sendConnectScanProbe(USI, hss, probe->pspec()->pd.tcp.dport, tryno);
} else if (probe->type == UltraProbe::UP_ARP) {
newProbe = sendArpScanProbe(USI, hss, probe->tryno + 1, 0);
newProbe = sendArpScanProbe(USI, hss, tryno);
} else if (probe->type == UltraProbe::UP_ND) {
newProbe = sendNDScanProbe(USI, hss, probe->tryno + 1, 0);
newProbe = sendNDScanProbe(USI, hss, tryno);
} else {
/* TODO: Support any other probe types */
fatal("%s: unsupported probe type %d", __func__, probe->type);
@ -2465,12 +2481,12 @@ static void doAnyOutstandingRetransmits(UltraScanInfo *USI) {
continue;
}
// Retransmit if timed out and there are still tries remaining
if (probe->timedout && maxtries > probe->tryno) {
if (probe->timedout && maxtries > probe->get_tryno()) {
/* For rate limit detection, we delay the first time a new tryno
is seen, as long as we are scanning at least 2 ports */
if (probe->tryno + 1 > (int) host->rld.max_tryno_sent &&
if (probe->get_tryno() + 1 > (int) host->rld.max_tryno_sent &&
(USI->gstats->numprobes > 1 || USI->ping_scan_arp || USI->ping_scan_nd)) {
host->rld.max_tryno_sent = probe->tryno + 1;
host->rld.max_tryno_sent = probe->get_tryno() + 1;
host->rld.rld_waiting = true;
TIMEVAL_MSEC_ADD(host->rld.rld_waittime, USI->now, RLD_TIME_MS);
} else {
@ -2637,11 +2653,11 @@ static void processData(UltraScanInfo *USI) {
}
if (!probe->isPing() && probe->timedout && !probe->retransmitted) {
if (!tryno_mayincrease && probe->tryno >= maxtries) {
if (!tryno_mayincrease && probe->get_tryno() >= maxtries) {
if (tryno_capped && !host->retry_capped_warned) {
log_write(LOG_PLAIN, "Warning: %s giving up on port because"
" retransmission cap hit (%d).\n", host->target->targetipstr(),
probe->tryno);
probe->get_tryno());
host->retry_capped_warned = true;
}
if (USI->ping_scan) {
@ -2655,9 +2671,9 @@ static void processData(UltraScanInfo *USI) {
host->destroyOutstandingProbe(probeI);
}
continue;
} else if (probe->tryno >= maxtries &&
} else if (probe->get_tryno() >= maxtries &&
TIMEVAL_SUBTRACT(USI->now, probe->sent) > expire_us) {
assert(probe->tryno == maxtries);
assert(probe->get_tryno() == maxtries);
/* Move it to the bench until it is needed (maxtries
increases or is capped */
host->moveProbeToBench(probeI);

View file

@ -140,6 +140,15 @@ struct IPExtraProbeData {
} pd;
};
union _tryno_u {
struct {
u8 isPing : 1; // Is this a ping, not a scanprobe?
u8 seqnum : 7; // Sequence number, 0-127
} fields;
u8 opaque;
};
typedef union _tryno_u tryno_t;
/* At least for now, I'll just use this like a struct and access
all the data members directly */
class UltraProbe {
@ -187,14 +196,13 @@ public:
return &mypspec;
}
/* Returns true if the given tryno and pingseq match those within this
probe. */
bool check_tryno_pingseq(unsigned int tryno, unsigned int pingseq) const {
return (pingseq == 0 && tryno == this->tryno) || (pingseq > 0 && pingseq == this->pingseq);
/* Returns true if the given tryno matches this probe. */
bool check_tryno(u8 tryno) const {
return tryno == this->tryno.opaque;
}
u8 tryno; /* Try (retransmission) number of this probe */
u8 pingseq; /* 0 if this is not a scanping. Otherwise a positive ping seq#. */
/* tryno/pingseq, depending on what type of probe this is (ping vs scanprobe) */
tryno_t tryno; /* Try (retransmission) number of this probe */
/* If true, probe is considered no longer active due to timeout, but it
may be kept around a while, just in case a reply comes late */
bool timedout;
@ -206,7 +214,10 @@ public:
/* Time the previous probe was sent, if this is a retransmit (tryno > 0) */
struct timeval prevSent;
bool isPing() const {
return pingseq > 0;
return tryno.fields.isPing;
}
u8 get_tryno() const {
return tryno.fields.seqnum;
}
private:
@ -468,19 +479,12 @@ public:
which have reached the given limit may be dealt with. */
unsigned int allowedTryno(bool *capped, bool *mayincrease) const;
/* Provides the next ping sequence number. This starts at one, goes
up to 255, then wraps around back to 1. If inc is true, it is
incremented. Otherwise you just get a peek at what the next one
will be. */
u8 nextPingSeq(bool inc = true) {
u8 ret = nxtpseq;
if (inc) {
nxtpseq++;
if (nxtpseq == 0)
nxtpseq++;
}
return ret;
/* Provides the next ping sequence number. This starts at zero, goes
up to 127, then wraps around back to 0. */
u8 nextPingSeq() {
// Has to fit in 7 bits: tryno.fields.seqnum
nxtpseq = (nxtpseq + 1) % 0x80;
return nxtpseq;
}
/* This is the highest try number that has produced useful results
(such as port status change). */

View file

@ -354,10 +354,10 @@ static void init_socket(int sd) {
}
}
/* If this is NOT a ping probe, set pingseq to 0. Otherwise it will be the
/* If this is NOT a ping probe, set tryno.fields.isPing to 0. Otherwise it will be the
ping sequence number (they start at 1). The probe sent is returned. */
UltraProbe *sendConnectScanProbe(UltraScanInfo *USI, HostScanStats *hss,
u16 destport, u8 tryno, u8 pingseq) {
u16 destport, tryno_t tryno) {
UltraProbe *probe = new UltraProbe();
std::list<UltraProbe *>::iterator probeI;
@ -372,7 +372,6 @@ UltraProbe *sendConnectScanProbe(UltraScanInfo *USI, HostScanStats *hss,
ConnectProbe *CP;
probe->tryno = tryno;
probe->pingseq = pingseq;
/* First build the probe */
probe->setConnect(destport);
CP = probe->CP();

View file

@ -71,7 +71,7 @@ class UltraScanInfo;
class HostScanStats;
UltraProbe *sendConnectScanProbe(UltraScanInfo *USI, HostScanStats *hss,
u16 destport, u8 tryno, u8 pingseq);
u16 destport, tryno_t tryno);
bool do_one_select_round(UltraScanInfo *USI, struct timeval *stime);
#endif

View file

@ -230,16 +230,15 @@ void increment_base_port() {
base_port = 33000 + (base_port - 33000 + 256) % PRIME_32K;
}
/* The try number or ping sequence number can be encoded into a TCP SEQ or ACK
field. This returns a 32-bit number which encodes both of these values along
/* The try number can be encoded into a TCP SEQ or ACK
field. This returns a 32-bit number which encodes this value along
with a simple checksum. Decoding is done by seq32_decode. */
static u32 seq32_encode(UltraScanInfo *USI, unsigned int trynum,
unsigned int pingseq) {
static u32 seq32_encode(UltraScanInfo *USI, tryno_t trynum) {
u32 seq;
u16 nfo;
u8 nfo;
/* We'll let trynum and pingseq each be 8 bits. */
nfo = (pingseq << 8) + trynum;
/* tryno is 8 bits */
nfo = trynum.opaque;
/* Mirror the data to ensure it is reconstructed correctly. */
seq = (nfo << 16) + nfo;
/* Obfuscate it a little */
@ -251,11 +250,9 @@ static u32 seq32_encode(UltraScanInfo *USI, unsigned int trynum,
/* Undoes seq32_encode. This extracts a try number and a port number from a
32-bit value. Returns true if the checksum is correct, false otherwise. */
static bool seq32_decode(const UltraScanInfo *USI, u32 seq,
unsigned int *trynum, unsigned int *pingseq) {
tryno_t *trynum) {
if (trynum)
*trynum = 0;
if (pingseq)
*pingseq = 0;
trynum->opaque = 0;
/* Undo the mask xor. */
seq = seq ^ USI->seqmask;
@ -264,63 +261,41 @@ static bool seq32_decode(const UltraScanInfo *USI, u32 seq,
return false;
if (trynum)
*trynum = seq & 0xFF;
if (pingseq)
*pingseq = (seq & 0xFF00) >> 8;
trynum->opaque = seq & 0xFF;
return true;
}
/* The try number or ping sequence number can be encoded in the source port
number. This returns a new port number that contains a try number or ping
sequence number encoded into the given port number. trynum and pingseq may
not both be non-zero. Decoding is done by sport_decode. */
static u16 sport_encode(UltraScanInfo *USI, u16 base_portno, unsigned int trynum,
unsigned int pingseq) {
u16 portno;
/* trynum and pingseq both being non-zero is not currently supported. */
assert(trynum == 0 || pingseq == 0);
portno = base_portno;
if (pingseq > 0) {
/* Encode the pingseq. trynum = 0. */
portno += USI->perf.tryno_cap + pingseq;
} else {
/* Encode the trynum. pingseq = 0. */
portno += trynum;
}
return portno;
/* The try number can be encoded in the source port number. This returns a new
port number that contains a try number encoded into the given port number.
Decoding is done by sport_decode. */
static u16 sport_encode(u16 base_portno, tryno_t trynum) {
return base_portno + trynum.opaque;
}
/* We don't actually decode the port number, since we already compare the
* destination port number of the response with the source port of the probe.
*/
#if 0
/* Undoes sport_encode. This extracts a try number and ping sequence number from
a port number given a "base" port number (the one given to
sport_encode). Returns true if the decoded values seem reasonable, false
otherwise. */
static bool sport_decode(const UltraScanInfo *USI, u16 base_portno, u16 portno,
unsigned int *trynum, unsigned int *pingseq) {
static bool sport_decode(u16 base_portno, u16 portno,
tryno_t *trynum) {
unsigned int t;
t = portno - base_portno;
if (t > USI->perf.tryno_cap + 256) {
if (t > 0xff) {
return false;
} else if (t > USI->perf.tryno_cap) {
/* The ping sequence number was encoded. */
if (pingseq)
*pingseq = t - USI->perf.tryno_cap;
if (trynum)
*trynum = 0;
} else {
/* The try number was encoded. */
if (pingseq)
*pingseq = 0;
if (trynum)
*trynum = t;
trynum->opaque = t;
}
return true;
}
#endif
@ -371,7 +346,7 @@ static bool tcp_probe_match(const UltraScanInfo *USI, const UltraProbe *probe,
const struct probespec_tcpdata *probedata;
struct sockaddr_storage srcaddr;
size_t srcaddr_len;
unsigned int tryno, pingseq;
tryno_t tryno = {0};
bool goodseq;
if (probe->protocol() != IPPROTO_TCP)
@ -385,10 +360,10 @@ static bool tcp_probe_match(const UltraScanInfo *USI, const UltraProbe *probe,
|| sockaddr_storage_cmp(&srcaddr, dst) != 0)
return false;
tryno = 0;
pingseq = 0;
// If magic port is *not* set, then tryno is in the source port, and we
// already checked that it matches.
if (o.magic_port_set) {
/* We are looking to recover the tryno and pingseq of the probe, which are
/* We are looking to recover the tryno of the probe, which are
encoded in the ACK field for probes with the ACK flag set and in the SEQ
field for all other probes. According to RFC 793, section 3.9, under
"SEGMENT ARRIVES", it's supposed to work like this: If our probe had ACK
@ -399,28 +374,24 @@ static bool tcp_probe_match(const UltraScanInfo *USI, const UltraProbe *probe,
However, nmap-os-db shows that these assumptions can't be relied on, so
we try all three possibilities for each probe. */
goodseq = seq32_decode(USI, ntohl(tcp->th_ack) - 1, &tryno, &pingseq)
|| seq32_decode(USI, ntohl(tcp->th_ack), &tryno, &pingseq)
|| seq32_decode(USI, ntohl(tcp->th_seq), &tryno, &pingseq);
} else {
/* Get the values from the destination port (our source port). */
sport_decode(USI, base_port, ntohs(tcp->th_dport), &tryno, &pingseq);
goodseq = true;
}
goodseq = seq32_decode(USI, ntohl(tcp->th_ack) - 1, &tryno)
|| seq32_decode(USI, ntohl(tcp->th_ack), &tryno)
|| seq32_decode(USI, ntohl(tcp->th_seq), &tryno);
if (!goodseq) {
/* Connection info matches, but there was a nonsensical tryno. */
if (o.debugging)
log_write(LOG_PLAIN, "Bad Sequence number from host %s.\n", inet_ntop_ez(src, sizeof(*src)));
return false;
}
if (!goodseq) {
/* Connection info matches, but there was a nonsensical tryno/pingseq. */
if (o.debugging)
log_write(LOG_PLAIN, "Bad Sequence number from host %s.\n", inet_ntop_ez(src, sizeof(*src)));
return false;
}
/* Make sure that tryno matches the values in the probe. */
if (!probe->check_tryno(tryno.opaque))
return false;
/* Make sure that trynum and pingseq match the values in the probe. */
if (!probe->check_tryno_pingseq(tryno, pingseq))
return false;
}
/* Make sure we are matching up the right kind of probe, otherwise just the
ports, address, tryno, and pingseq can be ambiguous, between a SYN and an
ports, address, and tryno can be ambiguous, between a SYN and an
ACK probe during a -PS80 -PA80 scan for example. A SYN/ACK can only be
matched to a SYN probe. */
probedata = &probe->pspec()->pd.tcp;
@ -457,7 +428,6 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
HostScanStats *hss = NULL;
std::list<UltraProbe *>::iterator probeI;
UltraProbe *probe = NULL;
unsigned int trynum = 0;
int newstate = HOST_UNKNOWN;
unsigned int probenum;
unsigned int listsz;
@ -760,7 +730,7 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
}
if (o.debugging)
log_write(LOG_STDOUT, "We got a TCP ping packet back from %s port %hu (trynum = %d)\n", inet_ntop_ez(&hdr.src, sizeof(hdr.src)), ntohs(tcp->th_sport), trynum);
log_write(LOG_STDOUT, "We got a TCP ping packet back from %s port %hu (trynum = %d)\n", inet_ntop_ez(&hdr.src, sizeof(hdr.src)), ntohs(tcp->th_sport), probe->get_tryno());
}
} else if (hdr.proto == IPPROTO_UDP && USI->ptech.rawudpscan) {
const struct udp_hdr *udp = (struct udp_hdr *) data;
@ -788,13 +758,6 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
sockaddr_storage_cmp(&target_src, &hdr.dst) != 0)
continue;
/* Replace this with a call to probe_check_trynum_pingseq or similar. */
if (o.magic_port_set) {
trynum = probe->tryno;
} else {
sport_decode(USI, base_port, ntohs(udp->uh_dport), &trynum, NULL);
}
/* Sometimes we get false results when scanning localhost with
-p- because we scan localhost with src port = dst port and
see our outgoing packet and think it is a response. */
@ -808,7 +771,7 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
current_reason = ER_UDPRESPONSE;
if (o.debugging)
log_write(LOG_STDOUT, "In response to UDP-ping, we got UDP packet back from %s port %hu (trynum = %d)\n", inet_ntop_ez(&hdr.src, sizeof(hdr.src)), htons(udp->uh_sport), trynum);
log_write(LOG_STDOUT, "In response to UDP-ping, we got UDP packet back from %s port %hu (trynum = %d)\n", inet_ntop_ez(&hdr.src, sizeof(hdr.src)), htons(udp->uh_sport), probe->get_tryno());
}
} else if (hdr.proto == IPPROTO_SCTP && USI->ptech.rawsctpscan) {
const struct sctp_hdr *sctp = (struct sctp_hdr *) data;
@ -1049,10 +1012,9 @@ void begin_sniffer(UltraScanInfo *USI, std::vector<Target *> &Targets) {
return;
}
/* If this is NOT a ping probe, set pingseq to 0. Otherwise it will be the
ping sequence number (they start at 1). The probe sent is returned. */
/* The probe sent is returned. */
UltraProbe *sendArpScanProbe(UltraScanInfo *USI, HostScanStats *hss,
u8 tryno, u8 pingseq) {
tryno_t tryno) {
int rc;
UltraProbe *probe = new UltraProbe();
@ -1076,7 +1038,6 @@ UltraProbe *sendArpScanProbe(UltraScanInfo *USI, HostScanStats *hss,
}
PacketTrace::traceArp(PacketTrace::SENT, (u8 *) frame + ETH_HDR_LEN, sizeof(frame) - ETH_HDR_LEN, &USI->now);
probe->tryno = tryno;
probe->pingseq = pingseq;
/* First build the probe */
probe->setARP(frame, sizeof(frame));
@ -1090,7 +1051,7 @@ UltraProbe *sendArpScanProbe(UltraScanInfo *USI, HostScanStats *hss,
}
UltraProbe *sendNDScanProbe(UltraScanInfo *USI, HostScanStats *hss,
u8 tryno, u8 pingseq) {
tryno_t tryno) {
UltraProbe *probe = new UltraProbe();
struct eth_nfo eth;
struct eth_nfo *ethptr = NULL;
@ -1143,7 +1104,6 @@ UltraProbe *sendNDScanProbe(UltraScanInfo *USI, HostScanStats *hss,
send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), packet, packetlen);
probe->tryno = tryno;
probe->pingseq = pingseq;
/* First build the probe */
probe->setND(packet, packetlen);
@ -1270,15 +1230,14 @@ static u8 *build_protoscan_packet(const struct sockaddr_storage *src,
return packet;
}
/* If this is NOT a ping probe, set pingseq to 0. Otherwise it will be the
ping sequence number (they start at 1). The probe sent is returned.
/* The probe sent is returned.
This function also handles the sending of decoys. There is no fine-grained
control of this; all decoys are sent at once on one call of this function.
This means that decoys do not honor any scan delay and may violate congestion
control limits. */
UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
const probespec *pspec, u8 tryno, u8 pingseq) {
const probespec *pspec, tryno_t tryno) {
u8 *packet = NULL;
u32 packetlen = 0;
UltraProbe *probe = new UltraProbe();
@ -1308,22 +1267,21 @@ UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
if (o.magic_port_set)
sport = o.magic_port;
else
sport = sport_encode(USI, base_port, tryno, pingseq);
sport = sport_encode(USI->base_port, tryno);
probe->tryno = tryno;
probe->pingseq = pingseq;
/* First build the probe */
if (pspec->type == PS_TCP) {
assert(USI->scantype != CONNECT_SCAN);
/* Normally we encode the tryno and pingseq in the SEQ field, because that
/* Normally we encode the tryno in the SEQ field, because that
comes back (possibly incremented) in the ACK field of responses. But if
our probe has the ACK flag set, the response reflects our own ACK number
instead. */
if (pspec->pd.tcp.flags & TH_ACK)
ack = seq32_encode(USI, tryno, pingseq);
ack = seq32_encode(USI, tryno);
else
seq = seq32_encode(USI, tryno, pingseq);
seq = seq32_encode(USI, tryno);
if (pspec->pd.tcp.flags & TH_SYN) {
tcpops = (u8 *) TCP_SYN_PROBE_OPTIONS;

View file

@ -77,11 +77,11 @@ void increment_base_port();
int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime);
void begin_sniffer(UltraScanInfo *USI, std::vector<Target *> &Targets);
UltraProbe *sendArpScanProbe(UltraScanInfo *USI, HostScanStats *hss,
u8 tryno, u8 pingseq);
tryno_t tryno);
UltraProbe *sendNDScanProbe(UltraScanInfo *USI, HostScanStats *hss,
u8 tryno, u8 pingseq);
tryno_t tryno);
UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
const probespec *pspec, u8 tryno, u8 pingseq);
const probespec *pspec, tryno_t tryno);
bool get_arp_result(UltraScanInfo *USI, struct timeval *stime);
bool get_ns_result(UltraScanInfo *USI, struct timeval *stime);
bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime);