diff --git a/scan_engine.cc b/scan_engine.cc index f5c5a320f..a1dd77ddd 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -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::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); diff --git a/scan_engine.h b/scan_engine.h index 9b51ea366..ad77dec0a 100644 --- a/scan_engine.h +++ b/scan_engine.h @@ -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). */ diff --git a/scan_engine_connect.cc b/scan_engine_connect.cc index 076853dd5..9fcc1e6f9 100644 --- a/scan_engine_connect.cc +++ b/scan_engine_connect.cc @@ -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::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(); diff --git a/scan_engine_connect.h b/scan_engine_connect.h index ac98d930c..a350faebc 100644 --- a/scan_engine_connect.h +++ b/scan_engine_connect.h @@ -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 diff --git a/scan_engine_raw.cc b/scan_engine_raw.cc index 48fdd6fa1..a9ab6c603 100644 --- a/scan_engine_raw.cc +++ b/scan_engine_raw.cc @@ -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::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 &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; diff --git a/scan_engine_raw.h b/scan_engine_raw.h index c0ac632bd..80159cab5 100644 --- a/scan_engine_raw.h +++ b/scan_engine_raw.h @@ -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 &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);