diff --git a/TargetGroup.cc b/TargetGroup.cc index 84ecfa503..d66b198a6 100644 --- a/TargetGroup.cc +++ b/TargetGroup.cc @@ -116,6 +116,18 @@ public: virtual std::string str() const = 0; }; +class NetBlockRandomIPv4 : public NetBlock { +public: + NetBlockRandomIPv4(); + + bool next(struct sockaddr_storage *ss, size_t *sslen); + void apply_netmask(int bits) {} + std::string str() const {return "Random IPv4 addresses";} + +private: + struct sockaddr_in base; +}; + class NetBlockIPv4Ranges : public NetBlock { public: octet_bitvector octets[4]; @@ -325,6 +337,20 @@ bool NetBlock::is_resolved_address(const struct sockaddr_storage *ss) const { return false; } +NetBlockRandomIPv4::NetBlockRandomIPv4() { + memset(&base, 0, sizeof(base)); + base.sin_family = AF_INET; +} + +bool NetBlockRandomIPv4::next(struct sockaddr_storage *ss, size_t *sslen) { + do { + base.sin_addr.s_addr = get_random_unique_u32(); + } while (ip_is_reserved(&base.sin_addr)); + memcpy(ss, &base, sizeof(base)); + *sslen = sizeof(base); + return true; +} + NetBlockIPv4Ranges::NetBlockIPv4Ranges() { unsigned int i; @@ -777,6 +803,11 @@ int TargetGroup::parse_expr(const char *target_expr, int af) { return 1; } +void TargetGroup::generate_random_ips() { + assert(this->netblock == NULL); + this->netblock = new NetBlockRandomIPv4(); +} + /* Grab the next host from this expression (if any) and updates its internal state to reflect that the IP was given out. Returns 0 and fills in ss if successful. ss must point to a pre-allocated diff --git a/TargetGroup.h b/TargetGroup.h index 3bdd1747e..2430bba61 100644 --- a/TargetGroup.h +++ b/TargetGroup.h @@ -101,6 +101,7 @@ public: const std::list &get_unscanned_addrs(void) const; /* is the current expression a named host */ int get_namedhost() const; + void generate_random_ips(); }; #endif /* TARGETGROUP_H */ diff --git a/libnetutil/netutil.cc b/libnetutil/netutil.cc index 011d24987..da8d6bdfc 100644 --- a/libnetutil/netutil.cc +++ b/libnetutil/netutil.cc @@ -4673,19 +4673,12 @@ size_t read_host_from_file(FILE *fp, char *buf, size_t n) /* Return next target host specification from the supplied stream. - * if parameter "random" is set to true, then the function will - * return a random, non-reserved, IP address in decimal-dot notation */ -const char *grab_next_host_spec(FILE *inputfd, bool random, int argc, const char **argv) { + */ +const char *grab_next_host_spec(FILE *inputfd, int argc, const char **argv) { static char host_spec[1024]; - struct in_addr ip; size_t n; - if (random) { - do { - ip.s_addr = get_random_unique_u32(); - } while (ip_is_reserved(&ip)); - Strncpy(host_spec, inet_ntoa(ip), sizeof(host_spec)); - } else if (!inputfd) { + if (!inputfd) { return( (optind < argc)? argv[optind++] : NULL); } else { n = read_host_from_file(inputfd, host_spec, sizeof(host_spec)); diff --git a/libnetutil/netutil.h b/libnetutil/netutil.h index 0df5c3a35..05334a7db 100644 --- a/libnetutil/netutil.h +++ b/libnetutil/netutil.h @@ -533,9 +533,8 @@ int read_reply_pcap(pcap_t *pd, long to_usec, size_t read_host_from_file(FILE *fp, char *buf, size_t n); /* Return next target host specification from the supplied stream. - * if parameter "random" is set to true, then the function will - * return a random, non-reserved, IP address in decimal-dot notation */ -const char *grab_next_host_spec(FILE *inputfd, bool random, int argc, const char **fakeargv); + */ +const char *grab_next_host_spec(FILE *inputfd, int argc, const char **fakeargv); #ifdef WIN32 /* Convert a dnet interface name into the long pcap style. This also caches the diff --git a/nmap.cc b/nmap.cc index 881032bb1..523bce16c 100644 --- a/nmap.cc +++ b/nmap.cc @@ -2078,7 +2078,8 @@ int nmap_main(int argc, char *argv[]) { if (o.ping_group_sz < o.minHostGroupSz()) o.ping_group_sz = o.minHostGroupSz(); - HostGroupState hstate(o.ping_group_sz, o.randomize_hosts, argc, (const char **) argv); + HostGroupState hstate(o.ping_group_sz, o.randomize_hosts, + o.generate_random_ips ? o.max_ips_to_scan : 0, argc, (const char **) argv); do { ideal_scan_group_sz = determineScanGroupSize(o.numhosts_scanned, &ports); diff --git a/nping/ArgParser.cc b/nping/ArgParser.cc index 09585b886..37110ea4b 100644 --- a/nping/ArgParser.cc +++ b/nping/ArgParser.cc @@ -1119,7 +1119,7 @@ int ArgParser::parseArguments(int argc, char *argv[]) { * through calls to getNextTarget(); * */ const char *next_spec=NULL; - while ( (next_spec= grab_next_host_spec(NULL, false, argc, (const char **) argv)) != NULL ) + while ( (next_spec= grab_next_host_spec(NULL, argc, (const char **) argv)) != NULL ) o.targets.addSpec( (char *) next_spec ); return OP_SUCCESS; diff --git a/targets.cc b/targets.cc index 40f901e7d..96361744e 100644 --- a/targets.cc +++ b/targets.cc @@ -285,7 +285,7 @@ bool target_needs_new_hostgroup(Target **targets, int targets_sz, const Target * The target_expressions array MUST REMAIN VALID IN MEMORY as long as this class instance is used -- the array is NOT copied. */ -HostGroupState::HostGroupState(int lookahead, int rnd, int argc, const char **argv) { +HostGroupState::HostGroupState(int lookahead, int rnd, int num_random, int argc, const char **argv) { assert(lookahead > 0); this->argc = argc; this->argv = argv; @@ -296,6 +296,10 @@ HostGroupState::HostGroupState(int lookahead, int rnd, int argc, const char **ar current_batch_sz = 0; next_batch_no = 0; randomize = rnd; + this->num_random = num_random; + if (num_random > 0) { + current_group.generate_random_ips(); + } } HostGroupState::~HostGroupState() { @@ -315,7 +319,7 @@ void HostGroupState::undefer() { const char *HostGroupState::next_expression() { if (o.max_ips_to_scan == 0 || o.numhosts_scanned + this->current_batch_sz < o.max_ips_to_scan) { const char *expr; - expr = grab_next_host_spec(o.inputfd, o.generate_random_ips, this->argc, this->argv); + expr = grab_next_host_spec(o.inputfd, this->argc, this->argv); if (expr != NULL) return expr; } @@ -427,6 +431,7 @@ static Target *next_target(HostGroupState *hs, struct addrset *exclude_group, struct sockaddr_storage ss; size_t sslen; Target *t; + int num_queued = o.numhosts_scanned + hs->current_batch_sz; /* First handle targets deferred in the last batch. */ if (!hs->undeferred.empty()) { @@ -435,6 +440,9 @@ static Target *next_target(HostGroupState *hs, struct addrset *exclude_group, return t; } + if (o.max_ips_to_scan > 0 && num_queued >= (int)o.max_ips_to_scan) { + return NULL; + } tryagain: if (hs->current_group.get_next_host(&ss, &sslen) != 0) { diff --git a/targets.h b/targets.h index 172f83858..308642cd7 100644 --- a/targets.h +++ b/targets.h @@ -74,7 +74,7 @@ public: /* The maximum number of entries we want to allow storing in defer_buffer. */ static const unsigned int DEFER_LIMIT = 64; - HostGroupState(int lookahead, int randomize, int argc, const char *argv[]); + HostGroupState(int lookahead, int randomize, int num_random, int argc, const char *argv[]); ~HostGroupState(); Target **hostbatch; @@ -102,6 +102,8 @@ public: void undefer(); const char *next_expression(); Target *next_target(); + private: + int num_random; }; /* ports is used to pass information about what ports to use for host discovery */