/scan_engine.cc
C++ | 5982 lines | 4366 code | 577 blank | 1039 comment | 1703 complexity | 3a58e591348b4976ae70c3d885b87bb6 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.0, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /***************************************************************************
- * scan_engine.cc -- Includes much of the "engine" functions for scanning, *
- * such as ultra_scan. It also includes dependant functions such as those *
- * for collecting SYN/connect scan responses. *
- * *
- ***********************IMPORTANT NMAP LICENSE TERMS************************
- * *
- * The Nmap Security Scanner is (C) 1996-2013 Insecure.Com LLC. Nmap is *
- * also a registered trademark of Insecure.Com LLC. This program is free *
- * software; you may redistribute and/or modify it under the terms of the *
- * GNU General Public License as published by the Free Software *
- * Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE CLARIFICATIONS *
- * AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your right to use, *
- * modify, and redistribute this software under certain conditions. If *
- * you wish to embed Nmap technology into proprietary software, we sell *
- * alternative licenses (contact sales@nmap.com). Dozens of software *
- * vendors already license Nmap technology such as host discovery, port *
- * scanning, OS detection, version detection, and the Nmap Scripting *
- * Engine. *
- * *
- * Note that the GPL places important restrictions on "derivative works", *
- * yet it does not provide a detailed definition of that term. To avoid *
- * misunderstandings, we interpret that term as broadly as copyright law *
- * allows. For example, we consider an application to constitute a *
- * derivative work for the purpose of this license if it does any of the *
- * following with any software or content covered by this license *
- * ("Covered Software"): *
- * *
- * o Integrates source code from Covered Software. *
- * *
- * o Reads or includes copyrighted data files, such as Nmap's nmap-os-db *
- * or nmap-service-probes. *
- * *
- * o Is designed specifically to execute Covered Software and parse the *
- * results (as opposed to typical shell or execution-menu apps, which will *
- * execute anything you tell them to). *
- * *
- * o Includes Covered Software in a proprietary executable installer. The *
- * installers produced by InstallShield are an example of this. Including *
- * Nmap with other software in compressed or archival form does not *
- * trigger this provision, provided appropriate open source decompression *
- * or de-archiving software is widely available for no charge. For the *
- * purposes of this license, an installer is considered to include Covered *
- * Software even if it actually retrieves a copy of Covered Software from *
- * another source during runtime (such as by downloading it from the *
- * Internet). *
- * *
- * o Links (statically or dynamically) to a library which does any of the *
- * above. *
- * *
- * o Executes a helper program, module, or script to do any of the above. *
- * *
- * This list is not exclusive, but is meant to clarify our interpretation *
- * of derived works with some common examples. Other people may interpret *
- * the plain GPL differently, so we consider this a special exception to *
- * the GPL that we apply to Covered Software. Works which meet any of *
- * these conditions must conform to all of the terms of this license, *
- * particularly including the GPL Section 3 requirements of providing *
- * source code and allowing free redistribution of the work as a whole. *
- * *
- * As another special exception to the GPL terms, Insecure.Com LLC grants *
- * permission to link the code of this program with any version of the *
- * OpenSSL library which is distributed under a license identical to that *
- * listed in the included docs/licenses/OpenSSL.txt file, and distribute *
- * linked combinations including the two. *
- * *
- * Any redistribution of Covered Software, including any derived works, *
- * must obey and carry forward all of the terms of this license, including *
- * obeying all GPL rules and restrictions. For example, source code of *
- * the whole work must be provided and free redistribution must be *
- * allowed. All GPL references to "this License", are to be treated as *
- * including the terms and conditions of this license text as well. *
- * *
- * Because this license imposes special exceptions to the GPL, Covered *
- * Work may not be combined (even as part of a larger work) with plain GPL *
- * software. The terms, conditions, and exceptions of this license must *
- * be included as well. This license is incompatible with some other open *
- * source licenses as well. In some cases we can relicense portions of *
- * Nmap or grant special permissions to use it in other open source *
- * software. Please contact fyodor@nmap.org with any such requests. *
- * Similarly, we don't incorporate incompatible open source software into *
- * Covered Software without special permission from the copyright holders. *
- * *
- * If you have any questions about the licensing restrictions on using *
- * Nmap in other works, are happy to help. As mentioned above, we also *
- * offer alternative license to integrate Nmap into proprietary *
- * applications and appliances. These contracts have been sold to dozens *
- * of software vendors, and generally include a perpetual license as well *
- * as providing for priority support and updates. They also fund the *
- * continued development of Nmap. Please email sales@nmap.com for further *
- * information. *
- * *
- * If you have received a written license agreement or contract for *
- * Covered Software stating terms other than these, you may choose to use *
- * and redistribute Covered Software under those terms instead of these. *
- * *
- * Source is provided to this software because we believe users have a *
- * right to know exactly what a program is going to do before they run it. *
- * This also allows you to audit the software for security holes (none *
- * have been found so far). *
- * *
- * Source code also allows you to port Nmap to new platforms, fix bugs, *
- * and add new features. You are highly encouraged to send your changes *
- * to the dev@nmap.org mailing list for possible incorporation into the *
- * main distribution. By sending these changes to Fyodor or one of the *
- * Insecure.Org development mailing lists, or checking them into the Nmap *
- * source code repository, it is understood (unless you specify otherwise) *
- * that you are offering the Nmap Project (Insecure.Com LLC) the *
- * unlimited, non-exclusive right to reuse, modify, and relicense the *
- * code. Nmap will always be available Open Source, but this is important *
- * because the inability to relicense code has caused devastating problems *
- * for other Free Software projects (such as KDE and NASM). We also *
- * occasionally relicense the code to third parties as discussed above. *
- * If you wish to specify special license conditions of your *
- * contributions, just say so when you send them. *
- * *
- * This program is distributed in the hope that it will be useful, but *
- * WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Nmap *
- * license file for more details (it's in a COPYING file included with *
- * Nmap, and also available from https://svn.nmap.org/nmap/COPYING *
- * *
- ***************************************************************************/
- /* $Id$ */
- #ifdef WIN32
- #include "nmap_winconfig.h"
- #endif
- #include "portreasons.h"
- #include <dnet.h>
- #include "scan_engine.h"
- #include "timing.h"
- #include "NmapOps.h"
- #include "nmap_tty.h"
- #include "payload.h"
- #include "Target.h"
- #include "targets.h"
- #include "utils.h"
- #include "struct_ip.h"
- #include <math.h>
- #include <list>
- #include <map>
- extern NmapOps o;
- class UltraScanInfo;
- /* 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
- true--then we honor the requested source port.) The tryno and pingseq are
- encoded as offsets from base_port, a base source port number (see
- sport_encode and sport_decode). To avoid interpreting a late response from a
- previous invocation of ultra_scan as a response for the same port in the
- current invocation, we increase base_port by a healthy amount designed to be
- greater than any offset likely to be used by a probe, each time ultra_scan is
- run.
- If we don't increase the base port, then there is the risk of something like
- the following happening:
- 1. Nmap sends an ICMP echo and a TCP ACK probe to port 80 for host discovery.
- 2. Nmap receives an ICMP echo reply and marks the host up.
- 3. Nmap sends a TCP SYN probe to port 80 for port scanning.
- 4. Nmap finally receives a delayed TCP RST in response to its earlier ACK
- probe, and wrongly marks port 80 as closed. */
- static u16 base_port;
- /* Clamp n to the range [min, max) in a modular fashion. */
- static int mod_offset(int n, int min, int max) {
- assert(min < max);
- n = (n - min) % (max - min);
- if (n < 0)
- n += max - min;
- return n + min;
- }
- /* Change base_port to a new number in a safe port range that is unlikely to
- conflict with nearby past or future invocations of ultra_scan. */
- static void increment_base_port() {
- static bool initialized = false;
- if (!initialized) {
- base_port = mod_offset(get_random_uint(), 33000, 65536 - 256);
- initialized = true;
- } else {
- base_port = mod_offset(base_port + 256, 33000, 65536 - 256);
- }
- }
- /* 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;
- ping_magnifier = 3;
- pingtime = 1250000;
- tryno_cap = o.getMaxRetransmissions();
- }
- };
- static const char *pspectype2ascii(int type) {
- switch (type) {
- case PS_NONE:
- return "NONE";
- case PS_TCP:
- return "TCP";
- case PS_UDP:
- return "UDP";
- case PS_SCTP:
- return "SCTP";
- case PS_PROTO:
- return "IP Proto";
- case PS_ICMP:
- return "ICMP";
- case PS_ARP:
- return "ARP";
- case PS_ICMPV6:
- return "ICMPv6";
- case PS_ND:
- return "ND";
- case PS_CONNECTTCP:
- return "connect";
- default:
- fatal("%s: Unknown type: %d", __func__, 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 {
- u16 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 relevent 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 */
- }
- u16 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 posative 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 relevent
- 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<UltraProbe *>::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<UltraProbe *>::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<UltraProbe *> 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 benh members is bench_tryno. If the maximum tryno
- increases, everyone on the bench is moved to the retry_stack.
- */
- std::vector<probespec> 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<probespec> 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<u8> 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<UltraProbe *>::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 dealth 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<Target *> &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<Target *> &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<HostScanStats *> 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<HostScanStats *> 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<HostScanStats *>::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 */
- static void init_ultra_timing_vals(ultra_timing_vals *timing,
- enum ultra_timing_type utt,
- int num_hosts_in_group,
- struct ultra_scan_performance_vars *perf,
- struct timeval *now);
- /* Take a buffer, buf, of size bufsz (64 bytes is sufficient) and
- writes a short description of the probe (arg1) into buf. It also returns
- buf. */
- static char *probespec2ascii(const probespec *pspec, char *buf, unsigned int bufsz) {
- char flagbuf[32];
- char *f;
- switch (pspec->type) {
- case PS_TCP:
- if (!pspec->pd.tcp.flags) {
- Strncpy(flagbuf, "(none)", sizeof(flagbuf));
- } else {
- f = flagbuf;
- if (pspec->pd.tcp.flags & TH_SYN)
- *f++ = 'S';
- if (pspec->pd.tcp.flags & TH_FIN)
- *f++ = 'F';
- if (pspec->pd.tcp.flags & TH_RST)
- *f++ = 'R';
- if (pspec->pd.tcp.flags & TH_PUSH)
- *f++ = 'P';
- if (pspec->pd.tcp.flags & TH_ACK)
- *f++ = 'A';
- if (pspec->pd.tcp.flags & TH_URG)
- *f++ = 'U';
- if (pspec->pd.tcp.flags & TH_ECE)
- *f++ = 'E'; /* rfc 2481/3168 */
- if (pspec->pd.tcp.flags & TH_CWR)
- *f++ = 'C'; /* rfc 2481/3168 */
- *f++ = '\0';
- }
- Snprintf(buf, bufsz, "tcp to port %hu; flags: %s", pspec->pd.tcp.dport, flagbuf);
- break;
- case PS_UDP:
- Snprintf(buf, bufsz, "udp to port %hu", pspec->pd.udp.dport);
- break;
- case PS_SCTP:
- switch (pspec->pd.sctp.chunktype) {
- case SCTP_INIT:
- Strncpy(flagbuf, "INIT", sizeof(flagbuf));
- break;
- case SCTP_COOKIE_ECHO:
- Strncpy(flagbuf, "COOKIE-ECHO", sizeof(flagbuf));
- break;
- default:
- Strncpy(flagbuf, "(unknown)", sizeof(flagbuf));
- }
- Snprintf(buf, bufsz, "sctp to port %hu; chunk: %s", pspec->pd.sctp.dport,
- flagbuf);
- break;
- case PS_PROTO:
- Snprintf(buf, bufsz, "protocol %u", (unsigned int) pspec->proto);
- break;
- case PS_ICMP:
- Snprintf(buf, bufsz, "icmp type %d code %d",
- pspec->pd.icmp.type, pspec->pd.icmp.code);
- break;
- case PS_ARP:
- Snprintf(buf, bufsz, "ARP");
- break;
- case PS_ICMPV6:
- Snprintf(buf, bufsz, "icmpv6 type %d code %d",
- pspec->pd.icmpv6.type, pspec->pd.icmpv6.code);
- break;
- case PS_ND:
- Snprintf(buf, bufsz, "ND");
- break;
- case PS_CONNECTTCP:
- Snprintf(buf, bufsz, "connect to port %hu", pspec->pd.tcp.dport);
- break;
- default:
- fatal("Unexpected %s type encountered", __func__);
- break;
- }
- return buf;
- }
- ConnectProbe::ConnectProbe() {
- sd = -1;
- }
- ConnectProbe::~ConnectProbe() {
- if (sd > 0)
- close(sd);
- sd = -1;
- }
- UltraProbe::UltraProbe() {
- type = UP_UNSET;
- tryno = 0;
- timedout = false;
- retransmitted = false;
- pingseq = 0;
- mypspec.type = PS_NONE;
- memset(&sent, 0, sizeof(prevSent));
- memset(&prevSent, 0, sizeof(prevSent));
- }
- UltraProbe::~UltraProbe() {
- if (type == UP_CONNECT)
- delete probes.CP;
- }
- /* Pass an arp packet, including ethernet header. Must be 42bytes */
- void UltraProbe::setARP(u8 *arppkt, u32 arplen) {
- type = UP_ARP;
- mypspec.type = PS_ARP;
- return;
- }
- void UltraProbe::setND(u8 *ndpkt, u32 ndlen) {
- type = UP_ND;
- mypspec.type = PS_ND;
- return;
- }
- /* Sets this UltraProbe as type UP_IP and creates & initializes the
- internal IPProbe. The relevent 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 UltraProbe::setIP(u8 *ippacket, u32 len, const probespec *pspec) {
- struct ip *ip = (struct ip *) ippacket;
- struct tcp_hdr *tcp = NULL;
- struct udp_hdr *udp = NULL;
- struct sctp_hdr *sctp = NULL;
- struct ppkt *icmp = NULL;
- const void *data;
- u8 hdr;
- type = UP_IP;
- if (ip->ip_v == 4) {
- data = ipv4_get_data(ip, &len);
- assert(data != NULL);
- assert(len + ip->ip_hl * 4 == (u32) ntohs(ip->ip_len));
- probes.IP.ipid = ntohs(ip->ip_id);
- hdr = ip->ip_p;
- } else if (ip->ip_v == 6) {
- const struct ip6_hdr *ip6 = (struct ip6_hdr *) ippacket;
- data = ipv6_get_data_any(ip6, &len, &hdr);
- assert(data != NULL);
- assert(len == (u32) ntohs(ip6->ip6_plen));
- probes.IP.ipid = ntohl(ip6->ip6_flow & IP6_FLOWLABEL_MASK) & 0xFFFF;
- hdr = ip6->ip6_nxt;
- } else {
- fatal("Bogus packet passed to %s -- only IP packets allowed", __func__);
- }
- if (hdr == IPPROTO_TCP) {
- assert(len >= 20);
- tcp = (struct tcp_hdr *) data;
- probes.IP.pd.tcp.sport = ntohs(tcp->th_sport);
- probes.IP.pd.tcp.seq = ntohl(tcp->th_seq);
- } else if (hdr == IPPROTO_UDP) {
- assert(len >= 8);
- udp = (struct udp_hdr *) data;
- probes.IP.pd.udp.sport = ntohs(udp->uh_sport);
- } else if (hdr == IPPROTO_SCTP) {
- assert(len >= 12);
- sctp = (struct sctp_hdr *) data;
- probes.IP.pd.sctp.sport = ntohs(sctp->sh_sport);
- probes.IP.pd.sctp.vtag = ntohl(sctp->sh_vtag);
- } else if (hdr == IPPROTO_ICMP) {
- icmp = (struct ppkt *) data;
- probes.IP.pd.icmp.ident = ntohs(icmp->id);
- }
- mypspec = *pspec;
- return;
- }
- u16 UltraProbe::icmpid() const {
- assert(mypspec.proto == IPPROTO_ICMP);
- return probes.IP.pd.icmp.ident;
- }
- u32 UltraProbe::tcpseq() const {
- if (mypspec.proto == IPPROTO_TCP)
- return probes.IP.pd.tcp.seq;
- else
- fatal("Bogus seq number request to %s -- type is %s", __func__,
- pspectype2ascii(mypspec.type));
- return 0; // Unreached
- }
- u32 UltraProbe::sctpvtag() const {
- assert(mypspec.proto == IPPROTO_SCTP);
- return probes.IP.pd.sctp.vtag;
- }
- /* Sets this UltraProbe as type UP_CONNECT, preparing to connect to given
- port number*/
- void UltraProbe::setConnect(u16 portno) {
- type = UP_CONNECT;
- probes.CP = new ConnectProbe();
- mypspec.type = PS_CONNECTTCP;
- mypspec.proto = IPPROTO_TCP;
- mypspec.pd.tcp.dport = portno;
- mypspec.pd.tcp.flags = TH_SYN;
- }
- ConnectScanInfo::ConnectScanInfo() {
- maxValidSD = -1;
- numSDs = 0;
- if (o.max_parallelism > 0) {
- maxSocketsAllowed = o.max_parallelism;
- } else {
- /* Subtracting 10 from max_sd accounts for
- stdin
- stdout
- stderr
- /dev/tty
- /var/run/utmpx, which is opened on Mac OS X at least
- -oG log file
- -oN log file
- -oS log file
- -oX log file
- perhaps another we've forgotten. */
- maxSocketsAllowed = max_sd() - 10;
- if (maxSocketsAllowed < 5)
- maxSocketsAllowed = 5;
- }
- maxSocketsAllowed = MIN(maxSocketsAllowed, FD_SETSIZE - 10);
- FD_ZERO(&fds_read);
- FD_ZERO(&fds_write);
- FD_ZERO(&fds_except);
- }
- /* Nothing really to do here. */
- 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 ConnectScanInfo::watchSD(int sd) {
- assert(sd >= 0);
- if (!FD_ISSET(sd, &fds_read)) {
- CHECKED_FD_SET(sd, &fds_read);
- CHECKED_FD_SET(sd, &fds_write);
- CHECKED_FD_SET(sd, &fds_except);
- numSDs++;
- if (sd > maxValidSD)
- maxValidSD = sd;
- return true;
- } else {
- return false;
- }
- }
- /* 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 ConnectScanInfo::clearSD(int sd) {
- assert(sd >= 0);
- if (FD_ISSET(sd, &fds_read)) {
- CHECKED_FD_CLR(sd, &fds_read);
- CHECKED_FD_CLR(sd, &fds_write);
- CHECKED_FD_CLR(sd, &fds_except);
- assert(numSDs > 0);
- numSDs--;
- if (sd == maxValidSD)
- maxValidSD--;
- return true;
- } else {
- return false;
- }
- }
- GroupScanStats::GroupScanStats(UltraScanInfo *UltraSI) {
- memset(&latestip, 0, sizeof(latestip));
- memset(&timeout, 0, sizeof(timeout));
- USI = UltraSI;
- init_ultra_timing_vals(&timing, TIMING_GROUP, USI->numIncompleteHosts(), &(USI->perf), &USI->now);
- initialize_timeout_info(&to);
- /* Default timout should be much lower for arp */
- if (USI->ping_scan_arp)
- to.timeout = MAX(o.minRttTimeout(), MIN(o.initialRttTimeout(), INITIAL_ARP_RTT_TIMEOUT)) * 1000;
- num_probes_active = 0;
- numtargets = USI->numIncompleteHosts(); // They are all incomplete at the beginning
- numprobes = USI->numProbesPerHost();
- if (USI->scantype == CONNECT_SCAN || USI->ptech.connecttcpscan)
- CSI = new ConnectScanInfo;
- else CSI = NULL;
- probes_sent = probes_sent_at_last_wait = 0;
- lastping_sent = lastrcvd = USI->now;
- send_no_earlier_than = USI->now;
- send_no_later_than = USI->now;
- lastping_sent_numprobes = 0;
- pinghost = NULL;
- gettimeofday(&last_wait, NULL);
- num_hosts_timedout = 0;
- }
- GroupScanStats::~GroupScanStats() {
- delete CSI;
- }
- /* Called whenever a probe is sent to any host. Should only be called by
- HostScanStats::probeSent. */
- void GroupScanStats::probeSent(unsigned int nbytes) {
- USI->send_rate_meter.update(nbytes, &USI->now);
- /* Find a new scheduling interval for minimum- and maximum-rate sending.
- Recall that these have effect only when --min-rate or --max-rate is
- given. */
- TIMEVAL_ADD(send_no_earlier_than, send_no_earlier_than,
- (time_t) (1000000.0 / o.max_packet_send_rate));
- /* Allow send_no_earlier_than to slip into the past. This allows the sending
- scheduler to catch up and make up for delays in other parts of the scan
- engine. If we were to update send_no_earlier_than to the present the
- sending rate could be much less than the maximum requested, even if the
- connection is capable of the maximum. */
- if (TIMEVAL_SUBTRACT(send_no_later_than, USI->now) > 0) {
- /* The next scheduled send is in the future. That means there's slack time
- during which the sending rate could drop. Pull the time back to the
- present to prevent that. */
- send_no_later_than = USI->now;
- }
- TIMEVAL_ADD(send_no_later_than, send_no_later_than,
- (time_t) (1000000.0 / o.min_packet_send_rate));
- }
- /* Returns true if the GLOBAL system says that sending is OK.*/
- bool GroupScanStats::sendOK(struct timeval *when) {
- int recentsends;
- /* In case it's not okay to send, arbitrarily say to check back in one
- second. */
- if (when)
- TIMEVAL_MSEC_ADD(*when, USI->now, 1000);
- if ((USI->scantype == CONNECT_SCAN || USI->ptech.connecttcpscan)
- && CSI->numSDs >= CSI->maxSocketsAllowed)
- return false;
- /* We need to stop sending if it has been a long time since
- the last listen call, at least for systems such as Windoze that
- don't give us a proper pcap time. Also for connect scans, since
- we don't get an exact response time with them either. */
- recentsends = USI->gstats->probes_sent - USI->gstats->probes_sent_at_last_wait;
- if (recentsends > 0 &&
- (USI->scantype == CONNECT_SCAN || USI->ptech.connecttcpscan || !pcap_recv_timeval_valid())) {
- int to_ms = (int) MAX(to.srtt * .75 / 1000, 50);
- if (TIMEVAL_MSEC_SUBTRACT(USI->now, last_wait) > to_ms)
- return false;
- }
- /* Enforce a maximum scanning rate, if necessary. If it's too early to send,
- return false. If not, mark now as a good time to send and allow the
- congestion control to override it. */
- if (o.max_packet_send_rate != 0.0) {
- if (TIMEVAL_SUBTRACT(send_no_earlier_than, USI->now) > 0) {
- if (when)
- *when = send_no_earlier_than;
- return false;
- } else {
- if (when)
- *when = USI->now;
- }
- }
- /* Enforce a minimum scanning rate, if necessary. If we're ahead of schedule,
- record the time of the next scheduled send and submit to congestion
- control. If we're behind schedule, return true to indicate that we need to
- send right now. */
- if (o.min_packet_send_rate != 0.0) {
- if (TIMEVAL_SUBTRACT(send_no_later_than, USI->now) > 0) {
- if (when)
- *when = send_no_later_than;
- } else {
- if (when)
- *when = USI->now;
- return true;
- }
- }
- /* There are good arguments for limiting the number of probes sent
- between waits even when we do get appropriate receive times. For
- example, overflowing the pcap receive buffer with responses is no
- fun. On one of my Linux boxes, it seems to hold about 113
- responses when I scan localhost. And half of those are the @#$#
- sends being received. I think I'll put a limit of 50 sends per
- wait */
- if (recentsends >= 50)
- return false;
- /* In case the user specifically asked for no group congestion control */
- if (o.nogcc) {
- if (when)
- *when = USI->now;
- return true;
- }
- /* When there is only one target left, let the host congestion
- stuff deal with it. */
- if (USI->numIncompleteHostsLessThan(2)) {
- if (when)
- *when = USI->now;
- return true;
- }
- if (timing.cwnd >= num_probes_active + 0.5) {
- if (when)
- *when = USI->now;
- return true;
- }
- return false;
- }
- /* Return true if pingprobe is an appropriate ping probe for the currently
- running scan. Because ping probes persist between host discovery and port
- scanning stages, it's possible to have a ping probe that is not relevant for
- the scan type, or won't be caught by the pcap filters. Examples of
- inappropriate ping probes are an ARP ping for a TCP scan, or a raw SYN ping
- for a connect scan. */
- static bool pingprobe_is_appropriate(const UltraScanInfo *USI,
- const probespec *pingprobe) {
- switch (pingprobe->type) {
- case(PS_NONE):
- return true;
- case(PS_CONNECTTCP):
- return USI->scantype == CONNECT_SCAN || (USI->ping_scan && USI->ptech.connecttcpscan);
- case(PS_TCP):
- case(PS_UDP):
- case(PS_SCTP):
- return (USI->tcp_scan && USI->scantype != CONNECT_SCAN) ||
- USI->udp_scan ||
- USI->sctp_scan ||
- (USI->ping_scan && (USI->ptech.rawtcpscan || USI->ptech.rawudpscan || USI->ptech.rawsctpscan));
- case(PS_PROTO):
- return USI->prot_scan || (USI->ping_scan && USI->ptech.rawprotoscan);
- case(PS_ICMP):
- return ((USI->ping_scan && !USI->ping_scan_arp ) || pingprobe->pd.icmp.type == 3);
- case(PS_ARP):
- return USI->ping_scan_arp;
- case(PS_ND):
- return USI->ping_scan_nd;
- }
- return false;
- }
- HostScanStats::HostScanStats(Target *t, UltraScanInfo *UltraSI) {
- target = t;
- USI = UltraSI;
- next_portidx = 0;
- sent_arp = false;
- next_ackportpingidx = 0;
- next_synportpingidx = 0;
- next_udpportpingidx = 0;
- next_sctpportpingidx = 0;
- next_protoportpingidx = 0;
- sent_icmp_ping = false;
- sent_icmp_mask = false;
- sent_icmp_ts = false;
- retry_capped_warned = false;
- num_probes_active = 0;
- num_probes_waiting_retransmit = 0;
- lastping_sent = lastprobe_sent = lastrcvd = USI->now;
- lastping_sent_numprobes = 0;
- nxtpseq = 1;
- max_successful_tryno = 0;
- tryno_mayincrease = true;
- ports_finished = 0;
- numprobes_sent = 0;
- memset(&completiontime, 0, sizeof(completiontime));
- init_ultra_timing_vals(&timing, TIMING_HOST, 1, &(USI->perf), &USI->now);
- bench_tryno = 0;
- memset(&sdn, 0, sizeof(sdn));
- sdn.last_boost = USI->now;
- sdn.delayms = o.scan_delay;
- rld.max_tryno_sent = 0;
- rld.rld_waiting = false;
- rld.rld_waittime = USI->now;
- if (!pingprobe_is_appropriate(USI, &target->pingprobe)) {
- if (o.debugging > 1)
- log_write(LOG…
Large files files are truncated, but you can click here to view the full file