From b6b92f6564ad58084ca927f76938b3a6f184b89a Mon Sep 17 00:00:00 2001 From: d33tah Date: Wed, 3 Sep 2014 14:27:04 +0000 Subject: [PATCH] Move most (if not all) data structure declarations from scan_engine.cc to scan_engine.h. Some method definitions remain in the header files and should be moved to .cc later. --- scan_engine.cc | 588 ++----------------------------------------------- scan_engine.h | 558 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 578 insertions(+), 568 deletions(-) diff --git a/scan_engine.cc b/scan_engine.cc index fdc56b156..4abf69b48 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -145,7 +145,20 @@ #include extern NmapOps o; -class UltraScanInfo; + +void UltraScanInfo::log_overall_rates(int logt) { + log_write(logt, "Overall sending rates: %.2f packets / s", send_rate_meter.getOverallPacketRate(&now)); + if (send_rate_meter.getNumBytes() > 0) + log_write(logt, ", %.2f bytes / s", send_rate_meter.getOverallByteRate(&now)); + log_write(logt, ".\n"); +} + +void UltraScanInfo::log_current_rates(int logt, bool update) { + log_write(logt, "Current sending rates: %.2f packets / s", send_rate_meter.getCurrentPacketRate(&now, update)); + if (send_rate_meter.getNumBytes() > 0) + log_write(logt, ", %.2f bytes / s", send_rate_meter.getCurrentByteRate(&now)); + log_write(logt, ".\n"); +} /* We encode per-probe information like the tryno and pingseq in the source port, for protocols that use ports. (Except when o.magic_port_set is @@ -186,24 +199,12 @@ static void increment_base_port() { } } -/* A few extra performance tuning parameters specific to ultra_scan. */ -struct ultra_scan_performance_vars : public scan_performance_vars { - /* When a successful ping response comes back, it counts as this many - "normal" responses, because the fact that pings are necessary means - we aren't getting much input. */ - int ping_magnifier; - /* Try to send a scanping if no response has been received from a target host - in this many usecs */ - int pingtime; - unsigned int tryno_cap; /* The maximum trynumber (starts at zero) allowed */ - - void init() { - scan_performance_vars::init(); - ping_magnifier = 3; - pingtime = 1250000; - tryno_cap = o.getMaxRetransmissions(); - } -}; +void ultra_scan_performance_vars::init() { + scan_performance_vars::init(); + ping_magnifier = 3; + pingtime = 1250000; + tryno_cap = o.getMaxRetransmissions(); +} static const char *pspectype2ascii(int type) { switch (type) { @@ -233,555 +234,6 @@ static const char *pspectype2ascii(int type) { return ""; // Unreached } -struct ppkt { /* Beginning of ICMP Echo/Timestamp header */ - u8 type; - u8 code; - u16 checksum; - u16 id; - u16 seq; -}; - -class ConnectProbe { -public: - ConnectProbe(); - ~ConnectProbe(); - int sd; /* Socket descriptor used for connection. -1 if not valid. */ -}; - -struct IPExtraProbeData_icmp { - u16 ident; -}; - -struct IPExtraProbeData_tcp { - u16 sport; - u32 seq; /* host byte order (like the other fields */ -}; - -struct IPExtraProbeData_udp { - u16 sport; -}; - -struct IPExtraProbeData_sctp { - u16 sport; - u32 vtag; -}; - -struct IPExtraProbeData { - u32 ipid; /* host byte order */ - union { - struct IPExtraProbeData_icmp icmp; - struct IPExtraProbeData_tcp tcp; - struct IPExtraProbeData_udp udp; - struct IPExtraProbeData_sctp sctp; - } pd; -}; - -/* At least for now, I'll just use this like a struct and access - all the data members directly */ -class UltraProbe { -public: - UltraProbe(); - ~UltraProbe(); - enum UPType { UP_UNSET, UP_IP, UP_CONNECT, UP_ARP, UP_ND } type; /* The type of probe this is */ - - /* Sets this UltraProbe as type UP_IP and creates & initializes the - internal IPProbe. The relevant probespec is necessary for setIP - because pspec.type is ambiguous with just the ippacket (e.g. a - tcp packet could be PS_PROTO or PS_TCP). */ - void setIP(u8 *ippacket, u32 iplen, const probespec *pspec); - /* Sets this UltraProbe as type UP_CONNECT, preparing to connect to given - port number*/ - void setConnect(u16 portno); - /* Pass an arp packet, including ethernet header. Must be 42bytes */ - void setARP(u8 *arppkt, u32 arplen); - void setND(u8 *ndpkt, u32 ndlen); - // The 4 accessors below all return in HOST BYTE ORDER - // source port used if TCP, UDP or SCTP - u16 sport() const { - switch (mypspec.proto) { - case IPPROTO_TCP: - return probes.IP.pd.tcp.sport; - case IPPROTO_UDP: - return probes.IP.pd.udp.sport; - case IPPROTO_SCTP: - return probes.IP.pd.sctp.sport; - default: - return 0; - } - /* not reached */ - } - // destination port used if TCP, UDP or SCTP - u16 dport() const { - switch (mypspec.proto) { - case IPPROTO_TCP: - return mypspec.pd.tcp.dport; - case IPPROTO_UDP: - return mypspec.pd.udp.dport; - case IPPROTO_SCTP: - return mypspec.pd.sctp.dport; - default: - /* dport() can get called for other protos if we - * get ICMP responses during IP proto scans. */ - return 0; - } - /* not reached */ - } - u32 ipid() const { - return probes.IP.ipid; - } - u16 icmpid() const; // ICMP ident if protocol is ICMP - u32 tcpseq() const; // TCP sequence number if protocol is TCP - u32 sctpvtag() const; // SCTP vtag if protocol is SCTP - /* Number, such as IPPROTO_TCP, IPPROTO_UDP, etc. */ - u8 protocol() const { - return mypspec.proto; - } - ConnectProbe *CP() { - return probes.CP; // if type == UP_CONNECT - } - // Arpprobe removed because not used. - // ArpProbe *AP() { return probes.AP; } // if UP_ARP - // Returns the protocol number, such as IPPROTO_TCP, or IPPROTO_UDP, by - // reading the appropriate fields of the probespec. - - /* Get general details about the probe */ - const probespec *pspec() const { - 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); - } - - u8 tryno; /* Try (retransmission) number of this probe */ - u8 pingseq; /* 0 if this is not a scanping. Otherwise a positive ping seq#. */ - /* 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; - /* A packet may be timedout for a while before being retransmitted due to - packet sending rate limitations */ - bool retransmitted; - - struct timeval sent; - /* Time the previous probe was sent, if this is a retransmit (tryno > 0) */ - struct timeval prevSent; - bool isPing() { - return pingseq > 0; - } - -private: - probespec mypspec; /* Filled in by the appropriate set* function */ - union { - IPExtraProbeData IP; - ConnectProbe *CP; - // ArpProbe *AP; - } probes; -}; - -/* Global info for the connect scan */ -class ConnectScanInfo { -public: - ConnectScanInfo(); - ~ConnectScanInfo(); - - /* Watch a socket descriptor (add to fd_sets and maxValidSD). Returns - true if the SD was absent from the list, false if you tried to - watch an SD that was already being watched. */ - bool watchSD(int sd); - - /* Clear SD from the fd_sets and maxValidSD. Returns true if the SD - was in the list, false if you tried to clear an sd that wasn't - there in the first place. */ - bool clearSD(int sd); - int maxValidSD; /* The maximum socket descriptor in any of the fd_sets */ - fd_set fds_read; - fd_set fds_write; - fd_set fds_except; - int numSDs; /* Number of socket descriptors being watched */ - int maxSocketsAllowed; /* No more than this many sockets may be created @once */ -}; - -class HostScanStats; - -/* These are ultra_scan() statistics for the whole group of Targets */ -class GroupScanStats { -public: - struct timeval timeout; /* The time at which we abort the scan */ - /* Most recent host tested for sendability */ - struct sockaddr_storage latestip; - GroupScanStats(UltraScanInfo *UltraSI); - ~GroupScanStats(); - void probeSent(unsigned int nbytes); - /* Returns true if the GLOBAL system says that sending is OK. */ - 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 - getting the current time w/o gettimeofday() */ - struct ultra_timing_vals timing; - struct timeout_info to; /* Group-wide packet rtt/timeout info */ - int numtargets; /* Total # of targets scanned -- includes finished and incomplete hosts */ - int numprobes; /* Number of probes/ports scanned on each host */ - /* 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 */ - - /* The most recently received probe response time -- initialized to scan - start time. */ - struct timeval lastrcvd; - /* The time the most recent ping was sent (initialized to scan begin time) */ - struct timeval lastping_sent; - /* 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; - - /* These two variables control minimum- and maximum-rate sending (--min-rate - and --max-rate). send_no_earlier_than is for --max-rate and - send_no_later_than is for --min-rate; they have effect only when the - respective command-line option is given. An attempt is made to keep the - sending rate within the interval, however for send_no_later_than it is not - guaranteed. */ - struct timeval send_no_earlier_than; - 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. */ - HostScanStats *pinghost; - - struct timeval last_wait; - int probes_sent_at_last_wait; - // number of hosts that timed out during scan, or were already timedout - int num_hosts_timedout; - ConnectScanInfo *CSI; -}; - -struct send_delay_nfo { - unsigned int delayms; /* Milliseconds to delay between probes */ - /* The number of successful and dropped probes since the last time the delay - was changed. The ratio controls when the rate drops. */ - unsigned int goodRespSinceDelayChanged; - unsigned int droppedRespSinceDelayChanged; - struct timeval last_boost; /* Most recent time of increase to delayms. Init to creation time. */ -}; - -/* To test for rate limiting, there is a delay in sending the first packet - of a certain retransmission number. These values help track that. */ -struct rate_limit_detection_nfo { - unsigned int max_tryno_sent; /* What is the max tryno we have sent so far (starts at 0) */ - bool rld_waiting; /* Are we currently waiting due to RLD? */ - struct timeval rld_waittime; /* if RLD waiting, when can we send? */ -}; - -/* The ultra_scan() statistics that apply to individual target hosts in a - group */ -class HostScanStats { -public: - Target *target; /* A copy of the Target that these stats refer to. */ - HostScanStats(Target *t, UltraScanInfo *UltraSI); - ~HostScanStats(); - int freshPortsLeft(); /* Returns the number of ports remaining to probe */ - int next_portidx; /* Index of the next port to probe in the relevant - ports array in USI.ports */ - bool sent_arp; /* Has an ARP probe been sent for the target yet? */ - - /* massping state. */ - /* The index of the next ACK port in o.ping_ackprobes to probe during ping - scan. */ - int next_ackportpingidx; - /* The index of the next SYN port in o.ping_synprobes to probe during ping - scan. */ - int next_synportpingidx; - /* The index of the next UDP port in o.ping_udpprobes to probe during ping - scan. */ - int next_udpportpingidx; - /* The index of the next SCTP port in o.ping_protoprobes to probe during ping - scan. */ - int next_sctpportpingidx; - /* The index of the next IP protocol in o.ping_protoprobes to probe during ping - scan. */ - int next_protoportpingidx; - /* Whether we have sent an ICMP echo request. */ - bool sent_icmp_ping; - /* Whether we have sent an ICMP address mask request. */ - bool sent_icmp_mask; - /* Whether we have sent an ICMP timestamp request. */ - bool sent_icmp_ts; - - /* Have we warned that we've given up on a port for this host yet? Only one - port per host is reported. */ - bool retry_capped_warned; - - void probeSent(unsigned int nbytes); - - /* How long I am currently willing to wait for a probe response - before considering it timed out. Uses the host values from - target if they are available, otherwise from gstats. Results - returned in MICROseconds. */ - unsigned long probeTimeout(); - - /* How long I'll wait until completely giving up on a probe. - Timedout probes are often marked as such (and sometimes - considered a drop), but kept in the list juts in case they come - really late. But after probeExpireTime(), I don't waste time - keeping them around. Give in MICROseconds */ - unsigned long probeExpireTime(const UltraProbe *probe); - /* Returns OK if sending a new probe to this host is OK (to avoid - flooding). If when is non-NULL, fills it with the time that sending - will be OK assuming no pending probes are resolved by responses - (call it again if they do). when will become now if it returns - true. */ - bool sendOK(struct timeval *when); - - /* If there are pending probe timeouts, fills in when with the time of - the earliest one and returns true. Otherwise returns false and - puts now in when. */ - bool nextTimeout(struct timeval *when); - UltraScanInfo *USI; /* The USI which contains this HSS */ - - /* Removes a probe from probes_outstanding, adjusts HSS and USS - active probe stats accordingly, then deletes the probe. */ - void destroyOutstandingProbe(std::list::iterator probeI); - - /* Removes all probes from probes_outstanding using - destroyOutstandingProbe. This is used in ping scan to quit waiting - for responses once a host is known to be up. Invalidates iterators - pointing into probes_outstanding. */ - void destroyAllOutstandingProbes(); - - /* Mark an outstanding probe as timedout. Adjusts stats - accordingly. For connect scans, this closes the socket. */ - void markProbeTimedout(std::list::iterator probeI); - - /* New (active) probes are appended to the end of this list. When a - host times out, it will be marked as such, but may hang around on - the list for a while just in case a response comes in. So use - num_probes_active to learn how many active (not timed out) probes - are outstanding. Probes on the bench (reached the current - maximum tryno and expired) are not counted in - probes_outstanding. */ - std::list probes_outstanding; - /* The number of probes in probes_outstanding, minus the inactive (timed out) ones */ - unsigned int num_probes_active; - /* Probes timed out but not yet retransmitted because of congestion - control limits or because more retransmits may not be - necessary. Note that probes on probe_bench are not included - in this value. */ - unsigned int num_probes_waiting_retransmit; - unsigned int num_probes_outstanding() { - return probes_outstanding.size(); - } - - /* The bench is a stock of probes (compacted into just the - probespec) that have met the current maximum tryno, and are on - ice until that tryno increases (so we can retransmit again), or - solidifies (so we can mark the port firewalled or whatever). The - tryno of bench members is bench_tryno. If the maximum tryno - increases, everyone on the bench is moved to the retry_stack. - */ - std::vector probe_bench; - unsigned int bench_tryno; /* # tryno of probes on the bench */ - /* The retry_stack are probespecs that were on the bench but are now - slated to be retried. It is kept sorted such that probes with highest - retry counts are on top, ready to be taken first. */ - std::vector retry_stack; - /* retry_stack_tries MUST BE KEPT IN SYNC WITH retry_stack. - retry_stack_tries[i] is the number of completed retries for the - probe in retry_stack[i] */ - std::vector retry_stack_tries; - /* tryno of probes on the retry queue */ - /* Moves the given probe from the probes_outstanding list, to - probe_bench, and decrements num_probes_waiting_retransmit accordingly */ - void moveProbeToBench(std::list::iterator probeI); - /* Dismiss all probe attempts on bench -- the ports are marked - 'filtered' or whatever is appropriate for having no response */ - void dismissBench(); - /* Move all members of bench to retry_stack for probe retransmission */ - void retransmitBench(); - - bool completed(); /* Whether or not the scan of this Target has completed */ - struct timeval completiontime; /* When this Target completed */ - - /* This function provides the proper cwnd and ssthresh to use. It - may differ from versions in timing member var because when no - responses have been received for this host, may look at others in - the group. For CHANGING this host's timing, use the timing - memberval instead. */ - void getTiming(struct ultra_timing_vals *tmng); - struct ultra_timing_vals timing; - /* The most recently received probe response time -- initialized to scan start time. */ - struct timeval lastrcvd; - struct timeval lastping_sent; /* The time the most recent ping was sent (initialized to scan begin time) */ - - /* 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; - struct timeval lastprobe_sent; /* Most recent probe send (including pings) by host. Init to scan begin time. */ - /* gives the maximum try number (try numbers start at zero and - increments for each retransmission) that may be used, based on - the scan type, observed network reliability, timing mode, etc. - This may change during the scan based on network traffic. If - capped is not null, it will be filled with true if the tryno is - at its upper limit. That often calls for a warning to be issued, - and marking of remaining timedout ports firewalled or whatever is - appropriate. If mayincrease is non-NULL, it is set to whether - the allowedTryno may increase again. If it is false, any probes - which have reached the given limit may be dealt with. */ - unsigned int allowedTryno(bool *capped, bool *mayincrease); - - - /* 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; - } - /* This is the highest try number that has produced useful results - (such as port status change). */ - unsigned int max_successful_tryno; - /* This starts as true because tryno may increase based on results, but - it becomes false if it becomes clear that tryno will not increase - further during the scan */ - bool tryno_mayincrease; - 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 */ - /* Boost the scan delay for this host, usually because too many packet - drops were detected. */ - void boostScanDelay(); - struct send_delay_nfo sdn; - struct rate_limit_detection_nfo rld; - -private: - u8 nxtpseq; /* the next scanping sequence number to use */ -}; - -class UltraScanInfo { -public: - UltraScanInfo(); - UltraScanInfo(std::vector &Targets, struct scan_lists *pts, stype scantype) { - Init(Targets, pts, scantype); - } - ~UltraScanInfo(); - /* Must call Init if you create object with default constructor */ - void Init(std::vector &Targets, struct scan_lists *pts, stype scantp); - - unsigned int numProbesPerHost(); - - /* Consults with the group stats, and the hstats for every - incomplete hosts to determine whether any probes may be sent. - Returns true if they can be sent immediately. If when is non-NULL, - it is filled with the next possible time that probes can be sent - (which will be now, if the function returns true */ - bool sendOK(struct timeval *tv); - stype scantype; - bool tcp_scan; /* scantype is a type of TCP scan */ - bool udp_scan; - bool sctp_scan; /* scantype is a type of SCTP scan */ - bool prot_scan; - bool ping_scan; /* Includes trad. ping scan & arp scan */ - bool ping_scan_arp; /* ONLY includes arp ping scan */ - bool ping_scan_nd; /* ONLY includes ND ping scan */ - bool noresp_open_scan; /* Whether no response means a port is open */ - - /* massping state. */ - /* If ping_scan is true (unless ping_scan_arp is also true), this is the set - of ping techniques to use (ICMP, raw ICMP, TCP connect, raw TCP, or raw - UDP). */ - struct { - unsigned int rawicmpscan: 1, - connecttcpscan: 1, - rawtcpscan: 1, - rawudpscan: 1, - rawsctpscan: 1, - rawprotoscan: 1; - } ptech; - - bool isRawScan(); - - struct timeval now; /* Updated after potentially meaningful delays. This can - be used to save a call to gettimeofday() */ - GroupScanStats *gstats; - struct ultra_scan_performance_vars perf; - /* A circular buffer of the incompleteHosts. nextIncompleteHost() gives - the next one. The first time it is called, it will give the - first host in the list. If incompleteHosts is empty, returns - NULL. */ - HostScanStats *nextIncompleteHost(); - /* Removes any hosts that have completed their scans from the incompleteHosts - list, and remove any hosts from completedHosts which have exceeded their - lifetime. Returns the number of hosts removed. */ - int removeCompletedHosts(); - /* Find a HostScanStats by its IP address in the incomplete and completed - lists. Returns NULL if none are found. */ - HostScanStats *findHost(struct sockaddr_storage *ss); - - double getCompletionFraction(); - - unsigned int numIncompleteHosts() { - return incompleteHosts.size(); - } - /* Call this instead of checking for numIncompleteHosts() == 0 because it - avoids a potential traversal of the list to find the size. */ - bool incompleteHostsEmpty() { - return incompleteHosts.empty(); - } - bool numIncompleteHostsLessThan(unsigned int n); - - unsigned int numInitialHosts() { - return numInitialTargets; - } - - void log_overall_rates(int logt) { - log_write(logt, "Overall sending rates: %.2f packets / s", send_rate_meter.getOverallPacketRate(&now)); - if (send_rate_meter.getNumBytes() > 0) - log_write(logt, ", %.2f bytes / s", send_rate_meter.getOverallByteRate(&now)); - log_write(logt, ".\n"); - } - - void log_current_rates(int logt, bool update = true) { - log_write(logt, "Current sending rates: %.2f packets / s", send_rate_meter.getCurrentPacketRate(&now, update)); - if (send_rate_meter.getNumBytes() > 0) - log_write(logt, ", %.2f bytes / s", send_rate_meter.getCurrentByteRate(&now)); - log_write(logt, ".\n"); - } - - /* Any function which messes with (removes elements from) - incompleteHosts may have to manipulate nextI */ - std::list incompleteHosts; - /* Hosts are moved from incompleteHosts to completedHosts as they are - completed. We keep them around because sometimes responses come back very - late, after we consider a host completed. */ - std::list completedHosts; - /* How long (in msecs) we keep a host in completedHosts */ - unsigned int completedHostLifetime; - /* The last time we went through completedHosts to remove hosts */ - struct timeval lastCompletedHostRemoval; - - ScanProgressMeter *SPM; - PacketRateMeter send_rate_meter; - struct scan_lists *ports; - int rawsd; /* raw socket descriptor */ - pcap_t *pd; - eth_t *ethsd; - u32 seqmask; /* This mask value is used to encode values in sequence - numbers. It is set randomly in UltraScanInfo::Init() */ -private: - - unsigned int numInitialTargets; - std::list::iterator nextI; - -}; - -/* Whether this is storing timing stats for a whole group or an - individual host */ -enum ultra_timing_type { TIMING_HOST, TIMING_GROUP }; /* Initialize the ultra_timing_vals structure timing. The utt must be TIMING_HOST or TIMING_GROUP. If you happen to have the current time handy, pass it as now, otherwise pass NULL */ diff --git a/scan_engine.h b/scan_engine.h index 04f65c35a..d4b464b3a 100644 --- a/scan_engine.h +++ b/scan_engine.h @@ -129,6 +129,9 @@ #include "nmap.h" #include "global_structures.h" +#include "timing.h" +#include "tcpip.h" +#include #include struct probespec_tcpdata { @@ -199,5 +202,560 @@ void ultra_scan(std::vector &Targets, struct scan_lists *ports, int determineScanGroupSize(int hosts_scanned_so_far, struct scan_lists *ports); +class UltraScanInfo; + +struct ppkt { /* Beginning of ICMP Echo/Timestamp header */ + u8 type; + u8 code; + u16 checksum; + u16 id; + u16 seq; +}; + +class ConnectProbe { +public: + ConnectProbe(); + ~ConnectProbe(); + int sd; /* Socket descriptor used for connection. -1 if not valid. */ +}; + +struct IPExtraProbeData_icmp { + u16 ident; +}; + +struct IPExtraProbeData_tcp { + u16 sport; + u32 seq; /* host byte order (like the other fields */ +}; + +struct IPExtraProbeData_udp { + u16 sport; +}; + +struct IPExtraProbeData_sctp { + u16 sport; + u32 vtag; +}; + +struct IPExtraProbeData { + u32 ipid; /* host byte order */ + union { + struct IPExtraProbeData_icmp icmp; + struct IPExtraProbeData_tcp tcp; + struct IPExtraProbeData_udp udp; + struct IPExtraProbeData_sctp sctp; + } pd; +}; + +/* At least for now, I'll just use this like a struct and access + all the data members directly */ +class UltraProbe { +public: + UltraProbe(); + ~UltraProbe(); + enum UPType { UP_UNSET, UP_IP, UP_CONNECT, UP_ARP, UP_ND } type; /* The type of probe this is */ + + /* Sets this UltraProbe as type UP_IP and creates & initializes the + internal IPProbe. The relevant probespec is necessary for setIP + because pspec.type is ambiguous with just the ippacket (e.g. a + tcp packet could be PS_PROTO or PS_TCP). */ + void setIP(u8 *ippacket, u32 iplen, const probespec *pspec); + /* Sets this UltraProbe as type UP_CONNECT, preparing to connect to given + port number*/ + void setConnect(u16 portno); + /* Pass an arp packet, including ethernet header. Must be 42bytes */ + void setARP(u8 *arppkt, u32 arplen); + void setND(u8 *ndpkt, u32 ndlen); + // The 4 accessors below all return in HOST BYTE ORDER + // source port used if TCP, UDP or SCTP + u16 sport() const { + switch (mypspec.proto) { + case IPPROTO_TCP: + return probes.IP.pd.tcp.sport; + case IPPROTO_UDP: + return probes.IP.pd.udp.sport; + case IPPROTO_SCTP: + return probes.IP.pd.sctp.sport; + default: + return 0; + } + /* not reached */ + } + // destination port used if TCP, UDP or SCTP + u16 dport() const { + switch (mypspec.proto) { + case IPPROTO_TCP: + return mypspec.pd.tcp.dport; + case IPPROTO_UDP: + return mypspec.pd.udp.dport; + case IPPROTO_SCTP: + return mypspec.pd.sctp.dport; + default: + /* dport() can get called for other protos if we + * get ICMP responses during IP proto scans. */ + return 0; + } + /* not reached */ + } + u32 ipid() const { + return probes.IP.ipid; + } + u16 icmpid() const; // ICMP ident if protocol is ICMP + u32 tcpseq() const; // TCP sequence number if protocol is TCP + u32 sctpvtag() const; // SCTP vtag if protocol is SCTP + /* Number, such as IPPROTO_TCP, IPPROTO_UDP, etc. */ + u8 protocol() const { + return mypspec.proto; + } + ConnectProbe *CP() { + return probes.CP; // if type == UP_CONNECT + } + // Arpprobe removed because not used. + // ArpProbe *AP() { return probes.AP; } // if UP_ARP + // Returns the protocol number, such as IPPROTO_TCP, or IPPROTO_UDP, by + // reading the appropriate fields of the probespec. + + /* Get general details about the probe */ + const probespec *pspec() const { + 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); + } + + u8 tryno; /* Try (retransmission) number of this probe */ + u8 pingseq; /* 0 if this is not a scanping. Otherwise a positive ping seq#. */ + /* 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; + /* A packet may be timedout for a while before being retransmitted due to + packet sending rate limitations */ + bool retransmitted; + + struct timeval sent; + /* Time the previous probe was sent, if this is a retransmit (tryno > 0) */ + struct timeval prevSent; + bool isPing() { + return pingseq > 0; + } + +private: + probespec mypspec; /* Filled in by the appropriate set* function */ + union { + IPExtraProbeData IP; + ConnectProbe *CP; + // ArpProbe *AP; + } probes; +}; + +/* Global info for the connect scan */ +class ConnectScanInfo { +public: + ConnectScanInfo(); + ~ConnectScanInfo(); + + /* Watch a socket descriptor (add to fd_sets and maxValidSD). Returns + true if the SD was absent from the list, false if you tried to + watch an SD that was already being watched. */ + bool watchSD(int sd); + + /* Clear SD from the fd_sets and maxValidSD. Returns true if the SD + was in the list, false if you tried to clear an sd that wasn't + there in the first place. */ + bool clearSD(int sd); + int maxValidSD; /* The maximum socket descriptor in any of the fd_sets */ + fd_set fds_read; + fd_set fds_write; + fd_set fds_except; + int numSDs; /* Number of socket descriptors being watched */ + int maxSocketsAllowed; /* No more than this many sockets may be created @once */ +}; + +class HostScanStats; + +/* These are ultra_scan() statistics for the whole group of Targets */ +class GroupScanStats { +public: + struct timeval timeout; /* The time at which we abort the scan */ + /* Most recent host tested for sendability */ + struct sockaddr_storage latestip; + GroupScanStats(UltraScanInfo *UltraSI); + ~GroupScanStats(); + void probeSent(unsigned int nbytes); + /* Returns true if the GLOBAL system says that sending is OK. */ + 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 + getting the current time w/o gettimeofday() */ + struct ultra_timing_vals timing; + struct timeout_info to; /* Group-wide packet rtt/timeout info */ + int numtargets; /* Total # of targets scanned -- includes finished and incomplete hosts */ + int numprobes; /* Number of probes/ports scanned on each host */ + /* 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 */ + + /* The most recently received probe response time -- initialized to scan + start time. */ + struct timeval lastrcvd; + /* The time the most recent ping was sent (initialized to scan begin time) */ + struct timeval lastping_sent; + /* 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; + + /* These two variables control minimum- and maximum-rate sending (--min-rate + and --max-rate). send_no_earlier_than is for --max-rate and + send_no_later_than is for --min-rate; they have effect only when the + respective command-line option is given. An attempt is made to keep the + sending rate within the interval, however for send_no_later_than it is not + guaranteed. */ + struct timeval send_no_earlier_than; + 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. */ + HostScanStats *pinghost; + + struct timeval last_wait; + int probes_sent_at_last_wait; + // number of hosts that timed out during scan, or were already timedout + int num_hosts_timedout; + ConnectScanInfo *CSI; +}; + +struct send_delay_nfo { + unsigned int delayms; /* Milliseconds to delay between probes */ + /* The number of successful and dropped probes since the last time the delay + was changed. The ratio controls when the rate drops. */ + unsigned int goodRespSinceDelayChanged; + unsigned int droppedRespSinceDelayChanged; + struct timeval last_boost; /* Most recent time of increase to delayms. Init to creation time. */ +}; + +/* To test for rate limiting, there is a delay in sending the first packet + of a certain retransmission number. These values help track that. */ +struct rate_limit_detection_nfo { + unsigned int max_tryno_sent; /* What is the max tryno we have sent so far (starts at 0) */ + bool rld_waiting; /* Are we currently waiting due to RLD? */ + struct timeval rld_waittime; /* if RLD waiting, when can we send? */ +}; + +/* The ultra_scan() statistics that apply to individual target hosts in a + group */ +class HostScanStats { +public: + Target *target; /* A copy of the Target that these stats refer to. */ + HostScanStats(Target *t, UltraScanInfo *UltraSI); + ~HostScanStats(); + int freshPortsLeft(); /* Returns the number of ports remaining to probe */ + int next_portidx; /* Index of the next port to probe in the relevant + ports array in USI.ports */ + bool sent_arp; /* Has an ARP probe been sent for the target yet? */ + + /* massping state. */ + /* The index of the next ACK port in o.ping_ackprobes to probe during ping + scan. */ + int next_ackportpingidx; + /* The index of the next SYN port in o.ping_synprobes to probe during ping + scan. */ + int next_synportpingidx; + /* The index of the next UDP port in o.ping_udpprobes to probe during ping + scan. */ + int next_udpportpingidx; + /* The index of the next SCTP port in o.ping_protoprobes to probe during ping + scan. */ + int next_sctpportpingidx; + /* The index of the next IP protocol in o.ping_protoprobes to probe during ping + scan. */ + int next_protoportpingidx; + /* Whether we have sent an ICMP echo request. */ + bool sent_icmp_ping; + /* Whether we have sent an ICMP address mask request. */ + bool sent_icmp_mask; + /* Whether we have sent an ICMP timestamp request. */ + bool sent_icmp_ts; + + /* Have we warned that we've given up on a port for this host yet? Only one + port per host is reported. */ + bool retry_capped_warned; + + void probeSent(unsigned int nbytes); + + /* How long I am currently willing to wait for a probe response + before considering it timed out. Uses the host values from + target if they are available, otherwise from gstats. Results + returned in MICROseconds. */ + unsigned long probeTimeout(); + + /* How long I'll wait until completely giving up on a probe. + Timedout probes are often marked as such (and sometimes + considered a drop), but kept in the list juts in case they come + really late. But after probeExpireTime(), I don't waste time + keeping them around. Give in MICROseconds */ + unsigned long probeExpireTime(const UltraProbe *probe); + /* Returns OK if sending a new probe to this host is OK (to avoid + flooding). If when is non-NULL, fills it with the time that sending + will be OK assuming no pending probes are resolved by responses + (call it again if they do). when will become now if it returns + true. */ + bool sendOK(struct timeval *when); + + /* If there are pending probe timeouts, fills in when with the time of + the earliest one and returns true. Otherwise returns false and + puts now in when. */ + bool nextTimeout(struct timeval *when); + UltraScanInfo *USI; /* The USI which contains this HSS */ + + /* Removes a probe from probes_outstanding, adjusts HSS and USS + active probe stats accordingly, then deletes the probe. */ + void destroyOutstandingProbe(std::list::iterator probeI); + + /* Removes all probes from probes_outstanding using + destroyOutstandingProbe. This is used in ping scan to quit waiting + for responses once a host is known to be up. Invalidates iterators + pointing into probes_outstanding. */ + void destroyAllOutstandingProbes(); + + /* Mark an outstanding probe as timedout. Adjusts stats + accordingly. For connect scans, this closes the socket. */ + void markProbeTimedout(std::list::iterator probeI); + + /* New (active) probes are appended to the end of this list. When a + host times out, it will be marked as such, but may hang around on + the list for a while just in case a response comes in. So use + num_probes_active to learn how many active (not timed out) probes + are outstanding. Probes on the bench (reached the current + maximum tryno and expired) are not counted in + probes_outstanding. */ + std::list probes_outstanding; + /* The number of probes in probes_outstanding, minus the inactive (timed out) ones */ + unsigned int num_probes_active; + /* Probes timed out but not yet retransmitted because of congestion + control limits or because more retransmits may not be + necessary. Note that probes on probe_bench are not included + in this value. */ + unsigned int num_probes_waiting_retransmit; + unsigned int num_probes_outstanding() { + return probes_outstanding.size(); + } + + /* The bench is a stock of probes (compacted into just the + probespec) that have met the current maximum tryno, and are on + ice until that tryno increases (so we can retransmit again), or + solidifies (so we can mark the port firewalled or whatever). The + tryno of bench members is bench_tryno. If the maximum tryno + increases, everyone on the bench is moved to the retry_stack. + */ + std::vector probe_bench; + unsigned int bench_tryno; /* # tryno of probes on the bench */ + /* The retry_stack are probespecs that were on the bench but are now + slated to be retried. It is kept sorted such that probes with highest + retry counts are on top, ready to be taken first. */ + std::vector retry_stack; + /* retry_stack_tries MUST BE KEPT IN SYNC WITH retry_stack. + retry_stack_tries[i] is the number of completed retries for the + probe in retry_stack[i] */ + std::vector retry_stack_tries; + /* tryno of probes on the retry queue */ + /* Moves the given probe from the probes_outstanding list, to + probe_bench, and decrements num_probes_waiting_retransmit accordingly */ + void moveProbeToBench(std::list::iterator probeI); + /* Dismiss all probe attempts on bench -- the ports are marked + 'filtered' or whatever is appropriate for having no response */ + void dismissBench(); + /* Move all members of bench to retry_stack for probe retransmission */ + void retransmitBench(); + + bool completed(); /* Whether or not the scan of this Target has completed */ + struct timeval completiontime; /* When this Target completed */ + + /* This function provides the proper cwnd and ssthresh to use. It + may differ from versions in timing member var because when no + responses have been received for this host, may look at others in + the group. For CHANGING this host's timing, use the timing + memberval instead. */ + void getTiming(struct ultra_timing_vals *tmng); + struct ultra_timing_vals timing; + /* The most recently received probe response time -- initialized to scan start time. */ + struct timeval lastrcvd; + struct timeval lastping_sent; /* The time the most recent ping was sent (initialized to scan begin time) */ + + /* 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; + struct timeval lastprobe_sent; /* Most recent probe send (including pings) by host. Init to scan begin time. */ + /* gives the maximum try number (try numbers start at zero and + increments for each retransmission) that may be used, based on + the scan type, observed network reliability, timing mode, etc. + This may change during the scan based on network traffic. If + capped is not null, it will be filled with true if the tryno is + at its upper limit. That often calls for a warning to be issued, + and marking of remaining timedout ports firewalled or whatever is + appropriate. If mayincrease is non-NULL, it is set to whether + the allowedTryno may increase again. If it is false, any probes + which have reached the given limit may be dealt with. */ + unsigned int allowedTryno(bool *capped, bool *mayincrease); + + + /* 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; + } + /* This is the highest try number that has produced useful results + (such as port status change). */ + unsigned int max_successful_tryno; + /* This starts as true because tryno may increase based on results, but + it becomes false if it becomes clear that tryno will not increase + further during the scan */ + bool tryno_mayincrease; + 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 */ + /* Boost the scan delay for this host, usually because too many packet + drops were detected. */ + void boostScanDelay(); + struct send_delay_nfo sdn; + struct rate_limit_detection_nfo rld; + +private: + u8 nxtpseq; /* the next scanping sequence number to use */ +}; + +/* A few extra performance tuning parameters specific to ultra_scan. */ +struct ultra_scan_performance_vars : public scan_performance_vars { + /* When a successful ping response comes back, it counts as this many + "normal" responses, because the fact that pings are necessary means + we aren't getting much input. */ + int ping_magnifier; + /* Try to send a scanping if no response has been received from a target host + in this many usecs */ + int pingtime; + unsigned int tryno_cap; /* The maximum trynumber (starts at zero) allowed */ + + void init(); +}; + +class UltraScanInfo { +public: + UltraScanInfo(); + UltraScanInfo(std::vector &Targets, struct scan_lists *pts, stype scantype) { + Init(Targets, pts, scantype); + } + ~UltraScanInfo(); + /* Must call Init if you create object with default constructor */ + void Init(std::vector &Targets, struct scan_lists *pts, stype scantp); + + unsigned int numProbesPerHost(); + + /* Consults with the group stats, and the hstats for every + incomplete hosts to determine whether any probes may be sent. + Returns true if they can be sent immediately. If when is non-NULL, + it is filled with the next possible time that probes can be sent + (which will be now, if the function returns true */ + bool sendOK(struct timeval *tv); + stype scantype; + bool tcp_scan; /* scantype is a type of TCP scan */ + bool udp_scan; + bool sctp_scan; /* scantype is a type of SCTP scan */ + bool prot_scan; + bool ping_scan; /* Includes trad. ping scan & arp scan */ + bool ping_scan_arp; /* ONLY includes arp ping scan */ + bool ping_scan_nd; /* ONLY includes ND ping scan */ + bool noresp_open_scan; /* Whether no response means a port is open */ + + /* massping state. */ + /* If ping_scan is true (unless ping_scan_arp is also true), this is the set + of ping techniques to use (ICMP, raw ICMP, TCP connect, raw TCP, or raw + UDP). */ + struct { + unsigned int rawicmpscan: 1, + connecttcpscan: 1, + rawtcpscan: 1, + rawudpscan: 1, + rawsctpscan: 1, + rawprotoscan: 1; + } ptech; + + bool isRawScan(); + + struct timeval now; /* Updated after potentially meaningful delays. This can + be used to save a call to gettimeofday() */ + GroupScanStats *gstats; + struct ultra_scan_performance_vars perf; + /* A circular buffer of the incompleteHosts. nextIncompleteHost() gives + the next one. The first time it is called, it will give the + first host in the list. If incompleteHosts is empty, returns + NULL. */ + HostScanStats *nextIncompleteHost(); + /* Removes any hosts that have completed their scans from the incompleteHosts + list, and remove any hosts from completedHosts which have exceeded their + lifetime. Returns the number of hosts removed. */ + int removeCompletedHosts(); + /* Find a HostScanStats by its IP address in the incomplete and completed + lists. Returns NULL if none are found. */ + HostScanStats *findHost(struct sockaddr_storage *ss); + + double getCompletionFraction(); + + unsigned int numIncompleteHosts() { + return incompleteHosts.size(); + } + /* Call this instead of checking for numIncompleteHosts() == 0 because it + avoids a potential traversal of the list to find the size. */ + bool incompleteHostsEmpty() { + return incompleteHosts.empty(); + } + bool numIncompleteHostsLessThan(unsigned int n); + + unsigned int numInitialHosts() { + return numInitialTargets; + } + + void log_overall_rates(int logt); + void log_current_rates(int logt, bool update = true); + + /* Any function which messes with (removes elements from) + incompleteHosts may have to manipulate nextI */ + std::list incompleteHosts; + /* Hosts are moved from incompleteHosts to completedHosts as they are + completed. We keep them around because sometimes responses come back very + late, after we consider a host completed. */ + std::list completedHosts; + /* How long (in msecs) we keep a host in completedHosts */ + unsigned int completedHostLifetime; + /* The last time we went through completedHosts to remove hosts */ + struct timeval lastCompletedHostRemoval; + + ScanProgressMeter *SPM; + PacketRateMeter send_rate_meter; + struct scan_lists *ports; + int rawsd; /* raw socket descriptor */ + pcap_t *pd; + eth_t *ethsd; + u32 seqmask; /* This mask value is used to encode values in sequence + numbers. It is set randomly in UltraScanInfo::Init() */ +private: + + unsigned int numInitialTargets; + std::list::iterator nextI; + +}; + +/* Whether this is storing timing stats for a whole group or an + individual host */ +enum ultra_timing_type { TIMING_HOST, TIMING_GROUP }; + #endif /* SCAN_ENGINE_H */