mirror of
https://github.com/nmap/nmap.git
synced 2026-01-06 06:29:03 +00:00
Add a defer buffer to HostGroupState.
This allows some targets to be skipped over yet remembered so they can
be dealt with later. The idea is that because ping groups are not
allowed
to have duplicate IPs, we continue searching for non-duplicates in order
to fill up a ping group, then return to what were formerly duplicates.
This prevents potentially large ping groups from being split into small
groups.
For example, if the list of targets is
A B C D A B E A F G
the ping groups used to be
(A B C D) (A B E) (A F G)
but now they are
(A B C D E F G) (A B) (A]
A similar thing can be done for port scan hostgroups, but this already
does most of the work because ping groups are generally bigger than
hostgroups and have pretty much the same restrictions.
This commit is contained in:
154
targets.cc
154
targets.cc
@@ -327,13 +327,6 @@ int TargetGroup::parse_expr(const char *target_expr, int af) {
|
||||
fills in ss if successful. ss must point to a pre-allocated
|
||||
sockaddr_storage structure */
|
||||
int TargetGroup::get_next_host(struct sockaddr_storage *ss, size_t *sslen) {
|
||||
if (this->pushback.ss_family != AF_UNSPEC) {
|
||||
*ss = this->pushback;
|
||||
*sslen = sizeof(*ss);
|
||||
this->pushback.ss_family = AF_UNSPEC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this->netblock == NULL)
|
||||
return -1;
|
||||
|
||||
@@ -359,15 +352,6 @@ int TargetGroup::get_next_host(struct sockaddr_storage *ss, size_t *sslen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Returns the given host, so that it will be given the next time
|
||||
get_next_host is called. Does nothing if ss is NULL. */
|
||||
void TargetGroup::return_host(const struct sockaddr_storage *ss) {
|
||||
if (ss == NULL)
|
||||
return;
|
||||
assert(this->pushback.ss_family == AF_UNSPEC);
|
||||
this->pushback = *ss;
|
||||
}
|
||||
|
||||
/* Returns true iff the given address is the one that was resolved to create
|
||||
this target group; i.e., not one of the addresses derived from it with a
|
||||
netmask. */
|
||||
@@ -405,6 +389,8 @@ HostGroupState::HostGroupState(int lookahead, int rnd, int argc, const char **ar
|
||||
this->argc = argc;
|
||||
this->argv = argv;
|
||||
hostbatch = (Target **) safe_zalloc(sizeof(Target *) * lookahead);
|
||||
defer_buffer = std::list<Target *>();
|
||||
undeferred = std::list<Target *>();
|
||||
max_batch_sz = lookahead;
|
||||
current_batch_sz = 0;
|
||||
next_batch_no = 0;
|
||||
@@ -415,6 +401,15 @@ HostGroupState::~HostGroupState() {
|
||||
free(hostbatch);
|
||||
}
|
||||
|
||||
bool HostGroupState::defer(Target *t) {
|
||||
this->defer_buffer.push_back(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
void HostGroupState::undefer() {
|
||||
this->undeferred.splice(this->undeferred.end(), this->defer_buffer);
|
||||
}
|
||||
|
||||
const char *HostGroupState::next_expression() {
|
||||
static char buf[1024];
|
||||
|
||||
@@ -525,74 +520,83 @@ bail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Target *nexthost(HostGroupState *hs, const addrset *exclude_group,
|
||||
struct scan_lists *ports, int pingtype) {
|
||||
int i;
|
||||
static Target *next_target(HostGroupState *hs, const addrset *exclude_group,
|
||||
struct scan_lists *ports, int pingtype) {
|
||||
struct sockaddr_storage ss;
|
||||
size_t sslen;
|
||||
Target *t;
|
||||
|
||||
/* First handle targets deferred in the last batch. */
|
||||
if (!hs->undeferred.empty()) {
|
||||
t = hs->undeferred.front();
|
||||
hs->undeferred.pop_front();
|
||||
return t;
|
||||
}
|
||||
|
||||
tryagain:
|
||||
|
||||
if (hs->current_group.get_next_host(&ss, &sslen) != 0) {
|
||||
const char *expr;
|
||||
/* We are going to have to pop in another expression. */
|
||||
for (;;) {
|
||||
expr = hs->next_expression();
|
||||
if (expr == NULL)
|
||||
/* That's the last of them. */
|
||||
return NULL;
|
||||
if (hs->current_group.parse_expr(expr, o.af()) == 0)
|
||||
break;
|
||||
else
|
||||
log_bogus_target(expr);
|
||||
}
|
||||
goto tryagain;
|
||||
}
|
||||
|
||||
/* If we are resuming from a previous scan, we have already finished scanning
|
||||
up to o.resume_ip. */
|
||||
if (ss.ss_family == AF_INET && o.resume_ip.s_addr) {
|
||||
if (o.resume_ip.s_addr == ((struct sockaddr_in *) &ss)->sin_addr.s_addr)
|
||||
/* We will continue starting with the next IP. */
|
||||
o.resume_ip.s_addr = 0;
|
||||
goto tryagain;
|
||||
}
|
||||
|
||||
/* Check exclude list. */
|
||||
if (hostInExclude((struct sockaddr *) &ss, sslen, exclude_group))
|
||||
goto tryagain;
|
||||
|
||||
t = setup_target(hs, &ss, sslen, pingtype);
|
||||
if (t == NULL)
|
||||
goto tryagain;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void refresh_hostbatch(HostGroupState *hs, const addrset *exclude_group,
|
||||
struct scan_lists *ports, int pingtype) {
|
||||
int i;
|
||||
bool arpping_done = false;
|
||||
struct timeval now;
|
||||
|
||||
if (hs->next_batch_no < hs->current_batch_sz) {
|
||||
/* Woop! This is easy -- we just pass back the next host struct */
|
||||
return hs->hostbatch[hs->next_batch_no++];
|
||||
}
|
||||
|
||||
/* Doh, we need to refresh our array */
|
||||
hs->current_batch_sz = hs->next_batch_no = 0;
|
||||
for (;;) {
|
||||
/* Grab anything we have in our current_group */
|
||||
while (hs->current_batch_sz < hs->max_batch_sz &&
|
||||
hs->current_group.get_next_host(&ss, &sslen) == 0) {
|
||||
Target *t;
|
||||
hs->undefer();
|
||||
while (hs->current_batch_sz < hs->max_batch_sz) {
|
||||
Target *t;
|
||||
|
||||
/* If we are resuming from a previous scan, we have already finished
|
||||
scans up to o.resume_ip. */
|
||||
if (ss.ss_family == AF_INET && o.resume_ip.s_addr) {
|
||||
if (o.resume_ip.s_addr == ((struct sockaddr_in *) &ss)->sin_addr.s_addr)
|
||||
o.resume_ip.s_addr = 0; /* So that we will KEEP the next one */
|
||||
continue; /* Try again */
|
||||
}
|
||||
t = next_target(hs, exclude_group, ports, pingtype);
|
||||
if (t == NULL)
|
||||
break;
|
||||
|
||||
if (hostInExclude((struct sockaddr *)&ss, sslen, exclude_group)) {
|
||||
continue; /* Skip any hosts the user asked to exclude */
|
||||
}
|
||||
t = setup_target(hs, &ss, sslen, pingtype);
|
||||
if (t == NULL)
|
||||
/* Does this target need to go in a separate host group? */
|
||||
if (target_needs_new_hostgroup(hs, t)) {
|
||||
if (hs->defer(t))
|
||||
continue;
|
||||
|
||||
/* Does this target need to go in a separate host group? */
|
||||
if (target_needs_new_hostgroup(hs, t)) {
|
||||
/* Cancel everything! This guy must go in the next group and we are
|
||||
out of here */
|
||||
hs->current_group.return_host(t->TargetSockAddr());
|
||||
delete t;
|
||||
goto batchfull;
|
||||
}
|
||||
|
||||
hs->hostbatch[hs->current_batch_sz++] = t;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (hs->current_batch_sz < hs->max_batch_sz) {
|
||||
const char *expr;
|
||||
/* We are going to have to pop in another expression. */
|
||||
for (;;) {
|
||||
expr = hs->next_expression();
|
||||
if (expr == NULL)
|
||||
goto batchfull;
|
||||
if (hs->current_group.parse_expr(expr, o.af()) != 0)
|
||||
log_bogus_target(expr);
|
||||
else
|
||||
break;
|
||||
}
|
||||
} else break;
|
||||
hs->hostbatch[hs->current_batch_sz++] = t;
|
||||
}
|
||||
|
||||
batchfull:
|
||||
|
||||
if (hs->current_batch_sz == 0)
|
||||
return NULL;
|
||||
|
||||
/* OK, now we have our complete batch of entries. The next step is to
|
||||
randomize them (if requested) */
|
||||
if (hs->randomize) {
|
||||
@@ -654,6 +658,14 @@ batchfull:
|
||||
|
||||
if (!o.noresolve)
|
||||
nmap_mass_rdns(hs->hostbatch, hs->current_batch_sz);
|
||||
}
|
||||
|
||||
Target *nexthost(HostGroupState *hs, const addrset *exclude_group,
|
||||
struct scan_lists *ports, int pingtype) {
|
||||
if (hs->next_batch_no >= hs->current_batch_sz)
|
||||
refresh_hostbatch(hs, exclude_group, ports, pingtype);
|
||||
if (hs->next_batch_no >= hs->current_batch_sz)
|
||||
return NULL;
|
||||
|
||||
return hs->hostbatch[hs->next_batch_no++];
|
||||
}
|
||||
|
||||
17
targets.h
17
targets.h
@@ -123,11 +123,9 @@
|
||||
class TargetGroup {
|
||||
public:
|
||||
NetBlock *netblock;
|
||||
struct sockaddr_storage pushback;
|
||||
|
||||
TargetGroup() {
|
||||
this->netblock = NULL;
|
||||
this->pushback.ss_family = AF_UNSPEC;
|
||||
}
|
||||
|
||||
~TargetGroup() {
|
||||
@@ -144,9 +142,6 @@ public:
|
||||
fills in ss if successful. ss must point to a pre-allocated
|
||||
sockaddr_storage structure */
|
||||
int get_next_host(struct sockaddr_storage *ss, size_t *sslen);
|
||||
/* Returns the given host, so that it will be given the next time
|
||||
get_next_host is called. Does nothing if ss is NULL. */
|
||||
void return_host(const struct sockaddr_storage *ss);
|
||||
/* Returns true iff the given address is the one that was resolved to create
|
||||
this target group; i.e., not one of the addresses derived from it with a
|
||||
netmask. */
|
||||
@@ -165,6 +160,15 @@ public:
|
||||
HostGroupState(int lookahead, int randomize, int argc, const char *argv[]);
|
||||
~HostGroupState();
|
||||
Target **hostbatch;
|
||||
|
||||
/* The defer_buffer is a place to store targets that have previously been
|
||||
returned but that can't be used right now. They wait in defer_buffer until
|
||||
HostGroupState::undefer is called, at which point they all move to the end
|
||||
of the undeferred list. HostGroupState::next_target always pulls from the
|
||||
undeferred list before returning anything new. */
|
||||
std::list<Target *> defer_buffer;
|
||||
std::list<Target *> undeferred;
|
||||
|
||||
int argc;
|
||||
const char **argv;
|
||||
int max_batch_sz; /* The size of the hostbatch[] array */
|
||||
@@ -176,7 +180,10 @@ public:
|
||||
at a time to the client program */
|
||||
TargetGroup current_group; /* For batch chunking -- targets in queue */
|
||||
|
||||
bool defer(Target *t);
|
||||
void undefer();
|
||||
const char *next_expression();
|
||||
Target *next_target();
|
||||
};
|
||||
|
||||
/* Ports is the list of ports the user asked to be scanned (0 terminated),
|
||||
|
||||
Reference in New Issue
Block a user