mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
Merge r30416:30527 from /nmap-exp/david/ipv6-ranges.
This is a refactoring of target parsing that stores different types of target specifications as different classes. The eventual intention is to allow easy iteration over each specification for the purpose of IPv6 multicast host discovery.
This commit is contained in:
884
TargetGroup.cc
884
TargetGroup.cc
@@ -101,23 +101,16 @@
|
||||
#include "global_structures.h"
|
||||
#include "libnetutil/netutil.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#define BITVECTOR_BITS (sizeof(bitvector_t) * CHAR_BIT)
|
||||
#define BIT_SET(v, n) ((v)[(n) / BITVECTOR_BITS] |= 1UL << ((n) % BITVECTOR_BITS))
|
||||
#define BIT_IS_SET(v, n) (((v)[(n) / BITVECTOR_BITS] & 1UL << ((n) % BITVECTOR_BITS)) != 0)
|
||||
|
||||
extern NmapOps o;
|
||||
|
||||
NewTargets *NewTargets::new_targets;
|
||||
|
||||
TargetGroup::TargetGroup() {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
// Bring back (or start with) original state
|
||||
void TargetGroup::Initialize() {
|
||||
targets_type = TYPE_NONE;
|
||||
memset(addresses, 0, sizeof(addresses));
|
||||
memset(current, 0, sizeof(current));
|
||||
memset(last, 0, sizeof(last));
|
||||
exhausted = true;
|
||||
}
|
||||
|
||||
/* Return a newly allocated string containing the part of expr up to the last
|
||||
'/' (or a copy of the whole string if there is no slash). *bits will contain
|
||||
the number after the slash, or -1 if there was no slash. In case of error
|
||||
@@ -142,6 +135,346 @@ static char *split_netmask(const char *expr, int *bits) {
|
||||
return mkstr(expr, slash);
|
||||
}
|
||||
|
||||
/* Parse an IPv4 address with optional ranges and wildcards into bit vectors.
|
||||
Each octet must match the regular expression '(\*|#?(-#?)?(,#?(-#?)?)*)',
|
||||
where '#' stands for an integer between 0 and 255. Return 0 on success, -1 on
|
||||
error. */
|
||||
static int parse_ipv4_ranges(octet_bitvector octets[4], const char *spec) {
|
||||
const char *p;
|
||||
int octet_index, i;
|
||||
|
||||
p = spec;
|
||||
octet_index = 0;
|
||||
while (*p != '\0' && octet_index < 4) {
|
||||
if (*p == '*') {
|
||||
for (i = 0; i < 256; i++)
|
||||
BIT_SET(octets[octet_index], i);
|
||||
p++;
|
||||
} else {
|
||||
for (;;) {
|
||||
long start, end;
|
||||
char *tail;
|
||||
|
||||
errno = 0;
|
||||
start = parse_long(p, &tail);
|
||||
/* Is this a range open on the left? */
|
||||
if (tail == p) {
|
||||
if (*p == '-')
|
||||
start = 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
if (errno != 0 || start < 0 || start > 255)
|
||||
return -1;
|
||||
p = tail;
|
||||
|
||||
/* Look for a range. */
|
||||
if (*p == '-') {
|
||||
p++;
|
||||
errno = 0;
|
||||
end = parse_long(p, &tail);
|
||||
/* Is this range open on the right? */
|
||||
if (tail == p)
|
||||
end = 255;
|
||||
if (errno != 0 || end < 0 || end > 255 || end < start)
|
||||
return -1;
|
||||
p = tail;
|
||||
} else {
|
||||
end = start;
|
||||
}
|
||||
|
||||
/* Fill in the range in the bit vector. */
|
||||
for (i = start; i <= end; i++)
|
||||
BIT_SET(octets[octet_index], i);
|
||||
|
||||
if (*p != ',')
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
octet_index++;
|
||||
if (octet_index < 4) {
|
||||
if (*p != '.')
|
||||
return -1;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
if (*p != '\0' || octet_index < 4)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static NetBlock *parse_expr_without_netmask(const char *hostexp, int af) {
|
||||
struct sockaddr_storage ss;
|
||||
size_t sslen;
|
||||
|
||||
if (af == AF_INET) {
|
||||
NetBlockIPv4Ranges *netblock_ranges;
|
||||
|
||||
/* Check if this is an IPv4 address, with optional ranges and wildcards. */
|
||||
netblock_ranges = new NetBlockIPv4Ranges();
|
||||
if (parse_ipv4_ranges(netblock_ranges->octets, hostexp) == 0)
|
||||
return netblock_ranges;
|
||||
delete netblock_ranges;
|
||||
}
|
||||
|
||||
sslen = sizeof(ss);
|
||||
if (resolve_numeric(hostexp, 0, &ss, &sslen, AF_INET6) == 0) {
|
||||
NetBlockIPv6Netmask *netblock_ipv6;
|
||||
|
||||
netblock_ipv6 = new NetBlockIPv6Netmask();
|
||||
netblock_ipv6->set_addr((struct sockaddr_in6 *) &ss);
|
||||
return netblock_ipv6;
|
||||
}
|
||||
|
||||
return new NetBlockHostname(hostexp, af);
|
||||
}
|
||||
|
||||
/* Parses an expression such as 192.168.0.0/16, 10.1.0-5.1-254, or
|
||||
fe80::202:e3ff:fe14:1102/112 and returns a newly allocated NetBlock. The af
|
||||
parameter is AF_INET or AF_INET6. Returns NULL in case of error. */
|
||||
NetBlock *NetBlock::parse_expr(const char *target_expr, int af) {
|
||||
NetBlock *netblock;
|
||||
char *hostexp;
|
||||
int bits;
|
||||
|
||||
hostexp = split_netmask(target_expr, &bits);
|
||||
if (hostexp == NULL) {
|
||||
error("Unable to split netmask from target expression: \"%s\"", target_expr);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (af == AF_INET && bits > 32) {
|
||||
error("Illegal netmask in \"%s\". Assuming /32 (one host)", target_expr);
|
||||
bits = -1;
|
||||
}
|
||||
|
||||
netblock = parse_expr_without_netmask(hostexp, af);
|
||||
if (netblock == NULL)
|
||||
goto bail;
|
||||
netblock->apply_netmask(bits);
|
||||
|
||||
free(hostexp);
|
||||
return netblock;
|
||||
|
||||
bail:
|
||||
free(hostexp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool NetBlock::is_resolved_address(const struct sockaddr_storage *ss) const {
|
||||
if (this->resolvedaddrs.empty())
|
||||
return false;
|
||||
return sockaddr_storage_equal(&*this->resolvedaddrs.begin(), ss);
|
||||
}
|
||||
|
||||
bool NetBlockIPv4Ranges::next(struct sockaddr_storage *ss) {
|
||||
struct sockaddr_in *sin;
|
||||
unsigned int i;
|
||||
|
||||
/* This first time this is called, the current values of this->counter
|
||||
probably do not point to set bits (they point to 0.0.0.0). Find the first
|
||||
set bit in each bitvector. If any overflow occurs, it means that there is
|
||||
not bit set for one of the octets and therefore there are not addresses
|
||||
overall. */
|
||||
for (i = 0; i < 4; i++) {
|
||||
while (this->counter[i] < 256 && !BIT_IS_SET(this->octets[i], this->counter[i]))
|
||||
this->counter[i]++;
|
||||
if (this->counter[i] >= 256)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Assign the returned address based on current counters. */
|
||||
sin = (struct sockaddr_in *) ss;
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_port = 0;
|
||||
#if HAVE_SOCKADDR_SA_LEN
|
||||
sin->sin_len = sizeof(*ss);
|
||||
#endif
|
||||
sin->sin_addr.s_addr = htonl((this->counter[0] << 24) | (this->counter[1] << 16) | (this->counter[2] << 8) | this->counter[3]);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
bool carry;
|
||||
|
||||
carry = false;
|
||||
do {
|
||||
this->counter[3 - i] = (this->counter[3 - i] + 1) % 256;
|
||||
if (this->counter[3 - i] == 0)
|
||||
carry = true;
|
||||
} while (!BIT_IS_SET(this->octets[3 - i], this->counter[3 - i]));
|
||||
if (!carry)
|
||||
break;
|
||||
}
|
||||
if (i >= 4) {
|
||||
/* We cycled all counters. Mark them invalid for the next call. */
|
||||
this->counter[0] = 256;
|
||||
this->counter[1] = 256;
|
||||
this->counter[2] = 256;
|
||||
this->counter[3] = 256;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Expand a single-octet bit vector to include any additional addresses that
|
||||
result when mask is applied. */
|
||||
static void apply_ipv4_netmask_octet(octet_bitvector bits, uint8_t mask) {
|
||||
unsigned int i, j;
|
||||
uint32_t chunk_size;
|
||||
|
||||
/* Process the bit vector in chunks, first of size 1, then of size 2, up to
|
||||
size 128. Check the next bit of the mask. If it is 1, do nothing.
|
||||
Otherwise, pair up the chunks (first with the second, third with the
|
||||
fourth, etc.). For each pair of chunks, set a bit in one chunk if it is
|
||||
set in the other. chunk_size also serves as an index into the mask. */
|
||||
for (chunk_size = 1; chunk_size < 256; chunk_size <<= 1) {
|
||||
if ((mask & chunk_size) != 0)
|
||||
continue;
|
||||
for (i = 0; i < 256; i += chunk_size * 2) {
|
||||
for (j = 0; j < chunk_size; j++) {
|
||||
if (BIT_IS_SET(bits, i + j))
|
||||
BIT_SET(bits, i + j + chunk_size);
|
||||
else if (BIT_IS_SET(bits, i + j + chunk_size))
|
||||
BIT_SET(bits, i + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Expand IPv4 bit vectors to include any additional addresses that result when
|
||||
the given netmask is applied. The mask is in host byte order. */
|
||||
static void apply_ipv4_netmask(octet_bitvector octets[4], uint32_t mask) {
|
||||
/* Apply the mask one octet at a time. It's done this way because ranges
|
||||
span exactly one octet. */
|
||||
apply_ipv4_netmask_octet(octets[0], (mask & 0xFF000000) >> 24);
|
||||
apply_ipv4_netmask_octet(octets[1], (mask & 0x00FF0000) >> 16);
|
||||
apply_ipv4_netmask_octet(octets[2], (mask & 0x0000FF00) >> 8);
|
||||
apply_ipv4_netmask_octet(octets[3], (mask & 0x000000FF));
|
||||
}
|
||||
|
||||
/* Expand IPv4 bit vectors to include any additional addresses that result from
|
||||
the application of a CIDR-style netmask with the given number of bits. If
|
||||
bits is negative it is taken to be 32. */
|
||||
void NetBlockIPv4Ranges::apply_netmask(int bits) {
|
||||
uint32_t mask;
|
||||
|
||||
if (bits > 32)
|
||||
return;
|
||||
if (bits < 0)
|
||||
bits = 32;
|
||||
|
||||
if (bits == 0)
|
||||
mask = 0x00000000;
|
||||
else
|
||||
mask = 0xFFFFFFFF << (32 - bits);
|
||||
|
||||
apply_ipv4_netmask(this->octets, mask);
|
||||
}
|
||||
|
||||
static std::string bitvector_to_range_string(const octet_bitvector v) {
|
||||
unsigned int i, j;
|
||||
std::ostringstream result;
|
||||
|
||||
i = 0;
|
||||
while (i < 256) {
|
||||
while (i < 256 && !BIT_IS_SET(v, i))
|
||||
i++;
|
||||
if (i >= 256)
|
||||
break;
|
||||
j = i + 1;
|
||||
while (j < 256 && BIT_IS_SET(v, j))
|
||||
j++;
|
||||
|
||||
if (result.tellp() > 0)
|
||||
result << ",";
|
||||
if (i == j - 1)
|
||||
result << i;
|
||||
else if (i + 1 == j - 1)
|
||||
result << i << "," << (j - 1);
|
||||
else
|
||||
result << i << "-" << (j - 1);
|
||||
|
||||
i = j;
|
||||
}
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
std::string NetBlockIPv4Ranges::str() const {
|
||||
std::ostringstream result;
|
||||
|
||||
result << bitvector_to_range_string(this->octets[0]);
|
||||
result << ".";
|
||||
result << bitvector_to_range_string(this->octets[1]);
|
||||
result << ".";
|
||||
result << bitvector_to_range_string(this->octets[2]);
|
||||
result << ".";
|
||||
result << bitvector_to_range_string(this->octets[3]);
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
void NetBlockIPv6Netmask::set_addr(const struct sockaddr_in6 *addr) {
|
||||
this->exhausted = false;
|
||||
this->start = addr->sin6_addr;
|
||||
this->cur = addr->sin6_addr;
|
||||
this->end = addr->sin6_addr;
|
||||
}
|
||||
|
||||
/* Get the sin6_scope_id member of a sockaddr_in6, based on a device name. This
|
||||
is used to assign scope to all addresses that otherwise lack a scope id when
|
||||
the -e option is used. */
|
||||
static int get_scope_id(const char *devname) {
|
||||
struct interface_info *ii;
|
||||
|
||||
if (devname == NULL || devname[0] == '\0')
|
||||
return 0;
|
||||
ii = getInterfaceByName(devname, AF_INET6);
|
||||
if (ii != NULL)
|
||||
return ii->ifindex;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ipv6_equal(const struct in6_addr *a, const struct in6_addr *b) {
|
||||
return memcmp(a->s6_addr, b->s6_addr, 16) == 0;
|
||||
}
|
||||
|
||||
bool NetBlockIPv6Netmask::next(struct sockaddr_storage *ss) {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
if (this->exhausted)
|
||||
return false;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *) ss;
|
||||
memset(sin6, 0, sizeof(*sin6));
|
||||
|
||||
sin6->sin6_family = AF_INET6;
|
||||
#ifdef SIN_LEN
|
||||
sin6->sin6_len = sizeof(*sin6);
|
||||
#endif
|
||||
|
||||
if (this->addr.sin6_scope_id != 0)
|
||||
sin6->sin6_scope_id = this->addr.sin6_scope_id;
|
||||
else
|
||||
sin6->sin6_scope_id = get_scope_id(o.device);
|
||||
|
||||
sin6->sin6_addr = this->cur;
|
||||
|
||||
if (ipv6_equal(&this->cur, &this->end))
|
||||
exhausted = true;
|
||||
|
||||
/* Increment current address. */
|
||||
for (int i = 15; i >= 0; i--) {
|
||||
this->cur.s6_addr[i]++;
|
||||
if (this->cur.s6_addr[i] > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Fill in an in6_addr with a CIDR-style netmask with the given number of bits. */
|
||||
static void make_ipv6_netmask(struct in6_addr *mask, int bits) {
|
||||
unsigned int i;
|
||||
@@ -171,419 +504,141 @@ static void ipv6_or_mask(struct in6_addr *a, const struct in6_addr *mask, const
|
||||
a->s6_addr[i] = (a->s6_addr[i] & mask->s6_addr[i]) | (b->s6_addr[i] & ~mask->s6_addr[i]);
|
||||
}
|
||||
|
||||
/* Initializes (or reinitializes) the object with a new expression, such
|
||||
as 192.168.0.0/16 , 10.1.0-5.1-254 , or fe80::202:e3ff:fe14:1102 .
|
||||
Returns 0 for success */
|
||||
int TargetGroup::parse_expr(const char *target_expr, int af) {
|
||||
void NetBlockIPv6Netmask::apply_netmask(int bits) {
|
||||
const struct in6_addr zeros = { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} } };
|
||||
const struct in6_addr ones = { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} } };
|
||||
struct in6_addr mask;
|
||||
|
||||
int i = 0, j = 0, k = 0;
|
||||
int start, end;
|
||||
char *r, *s;
|
||||
char *addy[5];
|
||||
char *hostexp;
|
||||
int bits;
|
||||
namedhost = 0;
|
||||
if (bits > 128)
|
||||
return;
|
||||
if (bits < 0)
|
||||
bits = 128;
|
||||
|
||||
if (targets_type != TYPE_NONE)
|
||||
Initialize();
|
||||
|
||||
resolvedaddrs.clear();
|
||||
|
||||
hostexp = split_netmask(target_expr, &bits);
|
||||
if (hostexp == NULL) {
|
||||
error("Unable to split netmask from target expression: \"%s\"", target_expr);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (af == AF_INET) {
|
||||
|
||||
if (strchr(hostexp, ':')) {
|
||||
error("Invalid host expression: %s -- colons only allowed in IPv6 addresses, and then you need the -6 switch", hostexp);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*struct in_addr current_in;*/
|
||||
addy[0] = addy[1] = addy[2] = addy[3] = addy[4] = NULL;
|
||||
addy[0] = r = hostexp;
|
||||
|
||||
/* Check the netmask. */
|
||||
if (bits == -1) {
|
||||
netmask = 32;
|
||||
} else if (0 <= bits && bits <= 32) {
|
||||
netmask = bits;
|
||||
} else {
|
||||
error("Illegal netmask value, must be /0 - /32 . Assuming /32 (one host)");
|
||||
netmask = 32;
|
||||
}
|
||||
|
||||
resolvedname = hostexp;
|
||||
for (i = 0; hostexp[i]; i++)
|
||||
if (isupper((int) (unsigned char) hostexp[i]) ||
|
||||
islower((int) (unsigned char) hostexp[i])) {
|
||||
namedhost = 1;
|
||||
break;
|
||||
}
|
||||
if (netmask != 32 || namedhost) {
|
||||
struct addrinfo *addrs, *addr;
|
||||
struct sockaddr_storage ss;
|
||||
size_t sslen;
|
||||
|
||||
targets_type = IPV4_NETMASK;
|
||||
addrs = resolve_all(hostexp, AF_INET);
|
||||
for (addr = addrs; addr != NULL; addr = addr->ai_next) {
|
||||
if (addr->ai_family != AF_INET)
|
||||
continue;
|
||||
if (addr->ai_addrlen < sizeof(ss)) {
|
||||
memcpy(&ss, addr->ai_addr, addr->ai_addrlen);
|
||||
resolvedaddrs.push_back(ss);
|
||||
}
|
||||
}
|
||||
if (addrs != NULL)
|
||||
freeaddrinfo(addrs);
|
||||
|
||||
if (resolvedaddrs.empty()) {
|
||||
error("Failed to resolve given hostname/IP: %s. Note that you can't use '/mask' AND '1-4,7,100-' style IP ranges. If the machine only has an IPv6 address, add the Nmap -6 flag to scan that.", hostexp);
|
||||
goto bail;
|
||||
} else {
|
||||
ss = *resolvedaddrs.begin();
|
||||
sslen = sizeof(ss);
|
||||
}
|
||||
|
||||
if (resolvedaddrs.size() > 1 && o.verbose > 1)
|
||||
error("Warning: Hostname %s resolves to %lu IPs. Using %s.", hostexp, (unsigned long)resolvedaddrs.size(), inet_ntop_ez(&ss, sslen));
|
||||
|
||||
if (netmask) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
|
||||
unsigned long longtmp = ntohl(sin->sin_addr.s_addr);
|
||||
startaddr.s_addr = longtmp & (unsigned long) (0 - (1 << (32 - netmask)));
|
||||
endaddr.s_addr = longtmp | (unsigned long) ((1 << (32 - netmask)) - 1);
|
||||
} else {
|
||||
/* The above calculations don't work for a /0 netmask, though at first
|
||||
* glance it appears that they would
|
||||
*/
|
||||
startaddr.s_addr = 0;
|
||||
endaddr.s_addr = 0xffffffff;
|
||||
}
|
||||
currentaddr = startaddr;
|
||||
if (startaddr.s_addr <= endaddr.s_addr)
|
||||
goto done;
|
||||
fprintf(stderr, "Host specification invalid");
|
||||
goto bail;
|
||||
} else {
|
||||
targets_type = IPV4_RANGES;
|
||||
i = 0;
|
||||
|
||||
while (*r) {
|
||||
if (*r == '.' && ++i < 4) {
|
||||
*r = '\0';
|
||||
addy[i] = r + 1;
|
||||
} else if (*r != '*' && *r != ',' && *r != '-' && !isdigit((int) (unsigned char) *r)) {
|
||||
error("Invalid character in host specification: %s. Note in particular that square brackets [] are no longer allowed. They were redundant and can simply be removed.", hostexp);
|
||||
goto bail;
|
||||
}
|
||||
r++;
|
||||
}
|
||||
if (i != 3) {
|
||||
error("Invalid target host specification: %s", hostexp);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
j = 0;
|
||||
do {
|
||||
s = strchr(addy[i], ',');
|
||||
if (s) *s = '\0';
|
||||
if (*addy[i] == '*') {
|
||||
start = 0;
|
||||
end = 255;
|
||||
} else if (*addy[i] == '-') {
|
||||
start = 0;
|
||||
if (*(addy[i] + 1) == '\0') end = 255;
|
||||
else end = atoi(addy[i] + 1);
|
||||
} else {
|
||||
start = end = atoi(addy[i]);
|
||||
if ((r = strchr(addy[i], '-')) && *(r + 1) ) end = atoi(r + 1);
|
||||
else if (r && !*(r + 1)) end = 255;
|
||||
}
|
||||
/* if (o.debugging > 2)
|
||||
* log_write(LOG_STDOUT, "The first host is %d, and the last one is %d\n", start, end); */
|
||||
if (start < 0 || start > end || start > 255 || end > 255) {
|
||||
error("Your host specifications are illegal!");
|
||||
goto bail;
|
||||
}
|
||||
if (j + (end - start) > 255) {
|
||||
error("Your host specifications are illegal!");
|
||||
goto bail;
|
||||
}
|
||||
for (k = start; k <= end; k++)
|
||||
addresses[i][j++] = k;
|
||||
last[i] = j - 1;
|
||||
if (s) addy[i] = s + 1;
|
||||
} while (s);
|
||||
}
|
||||
}
|
||||
memset((char *)current, 0, sizeof(current));
|
||||
} else {
|
||||
#if HAVE_IPV6
|
||||
struct addrinfo *addrs, *addr;
|
||||
struct sockaddr_storage ss;
|
||||
size_t sslen;
|
||||
|
||||
assert(af == AF_INET6);
|
||||
|
||||
/* Check the netmask. */
|
||||
if (bits == -1) {
|
||||
netmask = 128;
|
||||
} else if (0 <= bits && bits <= 128) {
|
||||
netmask = bits;
|
||||
} else {
|
||||
error("Illegal netmask value, must be /0 - /128 . Assuming /128 (one host)");
|
||||
netmask = 128;
|
||||
}
|
||||
resolvedname = hostexp;
|
||||
if (strchr(hostexp, ':') == NULL)
|
||||
namedhost = 1;
|
||||
|
||||
targets_type = IPV6_NETMASK;
|
||||
addrs = resolve_all(hostexp, AF_INET6);
|
||||
for (addr = addrs; addr != NULL; addr = addr->ai_next) {
|
||||
if (addr->ai_family != AF_INET6)
|
||||
continue;
|
||||
if (addr->ai_addrlen < sizeof(ss)) {
|
||||
memcpy(&ss, addr->ai_addr, addr->ai_addrlen);
|
||||
resolvedaddrs.push_back(ss);
|
||||
}
|
||||
}
|
||||
if (addrs != NULL)
|
||||
freeaddrinfo(addrs);
|
||||
|
||||
if (resolvedaddrs.empty()) {
|
||||
error("Failed to resolve given IPv6 hostname/IP: %s. Note that you can't use '/mask' or '[1-4,7,100-]' style ranges for IPv6.", hostexp);
|
||||
goto bail;
|
||||
} else {
|
||||
ss = *resolvedaddrs.begin();
|
||||
sslen = sizeof(ss);
|
||||
}
|
||||
|
||||
if (resolvedaddrs.size() > 1 && o.verbose > 1)
|
||||
error("Warning: Hostname %s resolves to %lu IPs. Using %s.", hostexp, (unsigned long)resolvedaddrs.size(), inet_ntop_ez(&ss, sslen));
|
||||
|
||||
assert(sizeof(ip6) <= sslen);
|
||||
memcpy(&ip6, &ss, sizeof(ip6));
|
||||
|
||||
const struct in6_addr zeros = { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} } };
|
||||
const struct in6_addr ones = { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} } };
|
||||
|
||||
struct in6_addr mask;
|
||||
make_ipv6_netmask(&mask, netmask);
|
||||
|
||||
startaddr6 = ((struct sockaddr_in6 *) &ss)->sin6_addr;
|
||||
ipv6_or_mask(&startaddr6, &mask, &zeros);
|
||||
endaddr6 = ((struct sockaddr_in6 *) &ss)->sin6_addr;
|
||||
ipv6_or_mask(&endaddr6, &mask, &ones);
|
||||
|
||||
currentaddr6 = startaddr6;
|
||||
#else // HAVE_IPV6
|
||||
fatal("IPv6 not supported on your platform");
|
||||
#endif // HAVE_IPV6
|
||||
}
|
||||
|
||||
done:
|
||||
free(hostexp);
|
||||
exhausted = false;
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
free(hostexp);
|
||||
exhausted = true;
|
||||
return 1;
|
||||
this->exhausted = false;
|
||||
make_ipv6_netmask(&mask, bits);
|
||||
ipv6_or_mask(&this->start, &mask, &zeros);
|
||||
ipv6_or_mask(&this->end, &mask, &ones);
|
||||
this->cur = this->start;
|
||||
}
|
||||
|
||||
/* Get the sin6_scope_id member of a sockaddr_in6, based on a device name. This
|
||||
is used to assign scope to all addresses that otherwise lack a scope id when
|
||||
the -e option is used. */
|
||||
static int get_scope_id(const char *devname) {
|
||||
struct interface_info *ii;
|
||||
/* a = a & ~b */
|
||||
static void recover_ipv6_netmask(struct in6_addr *a, const struct in6_addr *b) {
|
||||
unsigned int i;
|
||||
|
||||
if (devname == NULL || devname[0] == '\0')
|
||||
return 0;
|
||||
ii = getInterfaceByName(devname, AF_INET6);
|
||||
if (ii != NULL)
|
||||
return ii->ifindex;
|
||||
else
|
||||
return 0;
|
||||
for (i = 0; i < sizeof(a->s6_addr) / sizeof(*a->s6_addr); i++)
|
||||
a->s6_addr[i] = a->s6_addr[i] & ~b->s6_addr[i];
|
||||
}
|
||||
|
||||
/* 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
|
||||
sockaddr_storage structure */
|
||||
int TargetGroup::get_next_host(struct sockaddr_storage *ss, size_t *sslen) {
|
||||
static unsigned int count_ipv6_bits(const struct in6_addr *a) {
|
||||
unsigned int i, n;
|
||||
unsigned char mask;
|
||||
|
||||
int octet;
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *) ss;
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ss;
|
||||
startover: /* to handle nmap --resume where I have already
|
||||
* scanned many of the IPs */
|
||||
assert(ss);
|
||||
assert(sslen);
|
||||
|
||||
|
||||
if (exhausted)
|
||||
return -1;
|
||||
|
||||
if (targets_type == IPV4_NETMASK) {
|
||||
memset(sin, 0, sizeof(struct sockaddr_in));
|
||||
sin->sin_family = AF_INET;
|
||||
*sslen = sizeof(struct sockaddr_in);
|
||||
#if HAVE_SOCKADDR_SA_LEN
|
||||
sin->sin_len = *sslen;
|
||||
#endif
|
||||
|
||||
if (currentaddr.s_addr == endaddr.s_addr)
|
||||
exhausted = true;
|
||||
if (currentaddr.s_addr <= endaddr.s_addr) {
|
||||
sin->sin_addr.s_addr = htonl(currentaddr.s_addr++);
|
||||
} else {
|
||||
error("Bogus target structure passed to %s", __func__);
|
||||
exhausted = true;
|
||||
return -1;
|
||||
n = 0;
|
||||
for (i = 0; i < sizeof(a->s6_addr) / sizeof(*a->s6_addr); i++) {
|
||||
for (mask = 0x80; mask != 0; mask >>= 1) {
|
||||
if ((a->s6_addr[i] & mask) != 0)
|
||||
n++;
|
||||
}
|
||||
} else if (targets_type == IPV4_RANGES) {
|
||||
memset(sin, 0, sizeof(struct sockaddr_in));
|
||||
sin->sin_family = AF_INET;
|
||||
*sslen = sizeof(struct sockaddr_in);
|
||||
#if HAVE_SOCKADDR_SA_LEN
|
||||
sin->sin_len = *sslen;
|
||||
#endif
|
||||
if (o.debugging > 2) {
|
||||
log_write(LOG_STDOUT, "doing %d.%d.%d.%d = %d.%d.%d.%d\n", current[0], current[1], current[2], current[3], addresses[0][current[0]], addresses[1][current[1]], addresses[2][current[2]], addresses[3][current[3]]);
|
||||
}
|
||||
/* Set the IP to the current value of everything */
|
||||
sin->sin_addr.s_addr = htonl(addresses[0][current[0]] << 24 |
|
||||
addresses[1][current[1]] << 16 |
|
||||
addresses[2][current[2]] << 8 |
|
||||
addresses[3][current[3]]);
|
||||
|
||||
/* Now we nudge up to the next IP */
|
||||
for (octet = 3; octet >= 0; octet--) {
|
||||
if (current[octet] < last[octet]) {
|
||||
/* OK, this is the column I have room to nudge upwards */
|
||||
current[octet]++;
|
||||
break;
|
||||
} else {
|
||||
/* This octet is finished so I reset it to the beginning */
|
||||
current[octet] = 0;
|
||||
}
|
||||
}
|
||||
if (octet == -1) {
|
||||
/* It didn't find anything to bump up, I must have taken the last IP */
|
||||
exhausted = true;
|
||||
/* So I set current to last with the very final octet up one ... */
|
||||
/* Note that this may make current[3] == 256 */
|
||||
current[0] = last[0];
|
||||
current[1] = last[1];
|
||||
current[2] = last[2];
|
||||
current[3] = last[3] + 1;
|
||||
} else {
|
||||
assert(!exhausted); /* There must be at least one more IP left */
|
||||
}
|
||||
} else {
|
||||
assert(targets_type == IPV6_NETMASK);
|
||||
#if HAVE_IPV6
|
||||
*sslen = sizeof(struct sockaddr_in6);
|
||||
memset(sin6, 0, *sslen);
|
||||
sin6->sin6_family = AF_INET6;
|
||||
#ifdef SIN_LEN
|
||||
sin6->sin6_len = *sslen;
|
||||
#endif /* SIN_LEN */
|
||||
|
||||
if (memcmp(currentaddr6.s6_addr, endaddr6.s6_addr, 16) == 0)
|
||||
exhausted = true;
|
||||
|
||||
sin6->sin6_addr = currentaddr6;
|
||||
if (ip6.sin6_scope_id == 0)
|
||||
sin6->sin6_scope_id = get_scope_id(o.device);
|
||||
else
|
||||
sin6->sin6_scope_id = ip6.sin6_scope_id;
|
||||
|
||||
/* Increment current address. */
|
||||
for (int i = 15; i >= 0; i--) {
|
||||
currentaddr6.s6_addr[i]++;
|
||||
if (currentaddr6.s6_addr[i] > 0)
|
||||
break;
|
||||
}
|
||||
#else
|
||||
fatal("IPV6 not supported on this platform");
|
||||
#endif // HAVE_IPV6
|
||||
}
|
||||
|
||||
/* If we are resuming from a previous scan, we have already finished
|
||||
scans up to o.resume_ip. */
|
||||
if (sin->sin_family == AF_INET && o.resume_ip.s_addr) {
|
||||
if (o.resume_ip.s_addr == sin->sin_addr.s_addr)
|
||||
o.resume_ip.s_addr = 0; /* So that we will KEEP the next one */
|
||||
goto startover; /* Try again */
|
||||
}
|
||||
|
||||
return 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Returns the last given host, so that it will be given again next
|
||||
time get_next_host is called. Obviously, you should only call
|
||||
this if you have fetched at least 1 host since parse_expr() was
|
||||
called */
|
||||
int TargetGroup::return_last_host() {
|
||||
int octet;
|
||||
std::string NetBlockIPv6Netmask::str() const {
|
||||
std::ostringstream result;
|
||||
unsigned int bits;
|
||||
struct in6_addr a;
|
||||
|
||||
exhausted = false;
|
||||
if (targets_type == IPV4_NETMASK) {
|
||||
assert(currentaddr.s_addr > startaddr.s_addr);
|
||||
currentaddr.s_addr--;
|
||||
} else if (targets_type == IPV4_RANGES) {
|
||||
for (octet = 3; octet >= 0; octet--) {
|
||||
if (current[octet] > 0) {
|
||||
/* OK, this is the column I have room to nudge downwards */
|
||||
current[octet]--;
|
||||
break;
|
||||
} else {
|
||||
/* This octet is already at the beginning, so I set it to the end */
|
||||
current[octet] = last[octet];
|
||||
}
|
||||
}
|
||||
assert(octet != -1);
|
||||
} else {
|
||||
assert(targets_type == IPV6_NETMASK);
|
||||
}
|
||||
return 0;
|
||||
a = this->start;
|
||||
recover_ipv6_netmask(&a, &this->end);
|
||||
bits = count_ipv6_bits(&a);
|
||||
|
||||
result << inet_ntop_ez((struct sockaddr_storage *) &this->addr, sizeof(this->addr)) << "/" << bits;
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
bool TargetGroup::is_resolved_address(const struct sockaddr_storage *ss) {
|
||||
struct sockaddr_storage resolvedaddr;
|
||||
NetBlock *NetBlockHostname::resolve() const {
|
||||
struct addrinfo *addrs, *addr;
|
||||
std::list<struct sockaddr_storage> resolvedaddrs;
|
||||
NetBlock *netblock;
|
||||
struct sockaddr_storage ss;
|
||||
size_t sslen;
|
||||
|
||||
addrs = resolve_all(this->hostname.c_str(), this->af);
|
||||
for (addr = addrs; addr != NULL; addr = addr->ai_next) {
|
||||
if (addr->ai_addrlen < sizeof(ss)) {
|
||||
memcpy(&ss, addr->ai_addr, addr->ai_addrlen);
|
||||
resolvedaddrs.push_back(ss);
|
||||
}
|
||||
}
|
||||
if (addrs != NULL)
|
||||
freeaddrinfo(addrs);
|
||||
|
||||
if (resolvedaddrs.empty())
|
||||
return false;
|
||||
/* We only have a single distinguished address for these target types.
|
||||
IPV4_RANGES doesn't, for example. */
|
||||
if (!(targets_type == IPV4_NETMASK || targets_type == IPV6_NETMASK))
|
||||
return false;
|
||||
resolvedaddr = *resolvedaddrs.begin();
|
||||
return NULL;
|
||||
|
||||
return sockaddr_storage_equal(&resolvedaddr, ss);
|
||||
ss = *resolvedaddrs.begin();
|
||||
sslen = sizeof(ss);
|
||||
|
||||
if (resolvedaddrs.size() > 1 && o.verbose > 1) {
|
||||
error("Warning: Hostname %s resolves to %lu IPs. Using %s.", this->hostname.c_str(),
|
||||
(unsigned long) resolvedaddrs.size(), inet_ntop_ez(&ss, sslen));
|
||||
}
|
||||
|
||||
netblock = NULL;
|
||||
if (ss.ss_family == AF_INET) {
|
||||
NetBlockIPv4Ranges *netblock_ranges;
|
||||
uint32_t ip;
|
||||
|
||||
ip = ntohl(((struct sockaddr_in *) &ss)->sin_addr.s_addr);
|
||||
netblock_ranges = new NetBlockIPv4Ranges();
|
||||
BIT_SET(netblock_ranges->octets[0], (ip & 0xFF000000) >> 24);
|
||||
BIT_SET(netblock_ranges->octets[1], (ip & 0x00FF0000) >> 16);
|
||||
BIT_SET(netblock_ranges->octets[2], (ip & 0x0000FF00) >> 8);
|
||||
BIT_SET(netblock_ranges->octets[3], (ip & 0x000000FF));
|
||||
netblock = netblock_ranges;
|
||||
} else if (ss.ss_family == AF_INET6) {
|
||||
NetBlockIPv6Netmask *netblock_ipv6;
|
||||
|
||||
netblock_ipv6 = new NetBlockIPv6Netmask();
|
||||
netblock_ipv6->set_addr((struct sockaddr_in6 *) &ss);
|
||||
netblock = netblock_ipv6;
|
||||
}
|
||||
|
||||
if (netblock == NULL)
|
||||
return NULL;
|
||||
|
||||
netblock->hostname = this->hostname;
|
||||
netblock->resolvedaddrs = resolvedaddrs;
|
||||
netblock->apply_netmask(this->bits);
|
||||
|
||||
return netblock;
|
||||
}
|
||||
|
||||
/* Return a string of the name or address that was resolved for this group. */
|
||||
const char *TargetGroup::get_resolved_name(void) {
|
||||
return resolvedname.c_str();
|
||||
NetBlockHostname::NetBlockHostname(const char *hostname, int af) {
|
||||
this->hostname = hostname;
|
||||
this->af = af;
|
||||
this->bits = -1;
|
||||
}
|
||||
|
||||
/* Return the list of addresses that the name for this group resolved to, if
|
||||
it came from a name resolution. */
|
||||
const std::list<struct sockaddr_storage> &TargetGroup::get_resolved_addrs(void) {
|
||||
return resolvedaddrs;
|
||||
bool NetBlockHostname::next(struct sockaddr_storage *ss) {
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetBlockHostname::apply_netmask(int bits) {
|
||||
this->bits = bits;
|
||||
}
|
||||
|
||||
std::string NetBlockHostname::str() const {
|
||||
std::ostringstream result;
|
||||
|
||||
result << this->hostname;
|
||||
if (this->bits >= 0)
|
||||
result << "/" << this->bits;
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
/* debug level for the adding target is: 3 */
|
||||
@@ -686,26 +741,3 @@ unsigned long NewTargets::insert (const char *target) {
|
||||
|
||||
return new_targets->push(target);
|
||||
}
|
||||
|
||||
/* Lookahead is the number of hosts that can be
|
||||
checked (such as ping scanned) in advance. Randomize causes each
|
||||
group of up to lookahead hosts to be internally shuffled around.
|
||||
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,
|
||||
char *expr[], int numexpr) {
|
||||
assert(lookahead > 0);
|
||||
hostbatch = (Target **) safe_zalloc(sizeof(Target *) * lookahead);
|
||||
max_batch_sz = lookahead;
|
||||
current_batch_sz = 0;
|
||||
next_batch_no = 0;
|
||||
randomize = rnd;
|
||||
target_expressions = expr;
|
||||
num_expressions = numexpr;
|
||||
next_expression = 0;
|
||||
}
|
||||
|
||||
HostGroupState::~HostGroupState() {
|
||||
free(hostbatch);
|
||||
}
|
||||
|
||||
151
TargetGroup.h
151
TargetGroup.h
@@ -97,6 +97,8 @@
|
||||
#ifndef TARGETGROUP_H
|
||||
#define TARGETGROUP_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
@@ -104,85 +106,70 @@
|
||||
|
||||
#include "nmap.h"
|
||||
|
||||
class TargetGroup {
|
||||
/* We use bit vectors to represent what values are allowed in an IPv4 octet.
|
||||
Each vector is built up of an array of bitvector_t (any convenient integer
|
||||
type). */
|
||||
typedef unsigned long bitvector_t;
|
||||
/* A 256-element bit vector, representing legal values for one octet. */
|
||||
typedef bitvector_t octet_bitvector[(256 - 1) / (sizeof(unsigned long) * CHAR_BIT) + 1];
|
||||
|
||||
class NetBlock {
|
||||
public:
|
||||
/* used by get_target_types */
|
||||
enum _targets_types { TYPE_NONE, IPV4_NETMASK, IPV4_RANGES, IPV6_NETMASK };
|
||||
/* used as input to skip range */
|
||||
enum _octet_nums { FIRST_OCTET, SECOND_OCTET, THIRD_OCTET };
|
||||
TargetGroup();
|
||||
|
||||
/* Initializes (or reinitializes) the object with a new expression,
|
||||
such as 192.168.0.0/16 , 10.1.0-5.1-254 , or
|
||||
fe80::202:e3ff:fe14:1102 . The af parameter is AF_INET or
|
||||
AF_INET6 Returns 0 for success */
|
||||
int parse_expr(const char *target_expr, int af);
|
||||
/* Grab the next host from this expression (if any). Returns 0 and
|
||||
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 last given host, so that it will be given again next
|
||||
time get_next_host is called. Obviously, you should only call
|
||||
this if you have fetched at least 1 host since parse_expr() was
|
||||
called */
|
||||
int return_last_host();
|
||||
/* 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. */
|
||||
bool is_resolved_address(const struct sockaddr_storage *ss);
|
||||
/* Return a string of the name or address that was resolved for this group. */
|
||||
const char *get_resolved_name(void);
|
||||
/* Return the list of addresses that the name for this group resolved to, if
|
||||
it came from a name resolution. */
|
||||
const std::list<struct sockaddr_storage> &get_resolved_addrs(void);
|
||||
/* return the target type */
|
||||
char get_targets_type() {
|
||||
return targets_type;
|
||||
};
|
||||
/* get the netmask */
|
||||
int get_mask() {
|
||||
return netmask;
|
||||
};
|
||||
/* is the current expression a named host */
|
||||
int get_namedhost() {
|
||||
return namedhost;
|
||||
};
|
||||
|
||||
private:
|
||||
enum _targets_types targets_type;
|
||||
void Initialize();
|
||||
|
||||
virtual ~NetBlock() {}
|
||||
std::string hostname;
|
||||
std::list<struct sockaddr_storage> resolvedaddrs;
|
||||
|
||||
u32 netmask;
|
||||
std::string resolvedname;
|
||||
/* Parses an expression such as 192.168.0.0/16, 10.1.0-5.1-254, or
|
||||
fe80::202:e3ff:fe14:1102/112 and returns a newly allocated NetBlock. The af
|
||||
parameter is AF_INET or AF_INET6. Returns NULL in case of error. */
|
||||
static NetBlock *parse_expr(const char *target_expr, int af);
|
||||
|
||||
/* These are used for the '/mask' style of specifying target
|
||||
net (IPV4_NETMASK) */
|
||||
struct in_addr startaddr;
|
||||
struct in_addr currentaddr;
|
||||
struct in_addr endaddr;
|
||||
bool is_resolved_address(const struct sockaddr_storage *ss) const;
|
||||
|
||||
// These three are for the '138.1-7,16,91-95,200-.12.1' style (IPV4_RANGES)
|
||||
u8 addresses[4][256];
|
||||
unsigned int current[4];
|
||||
u8 last[4];
|
||||
virtual bool next(struct sockaddr_storage *ss) = 0;
|
||||
virtual void apply_netmask(int bits) = 0;
|
||||
virtual std::string str() const = 0;
|
||||
};
|
||||
|
||||
#if HAVE_IPV6
|
||||
/* These are used for the '/mask' style of specifying target
|
||||
net (IPV6_NETMASK) */
|
||||
struct sockaddr_in6 ip6;
|
||||
struct in6_addr startaddr6;
|
||||
struct in6_addr currentaddr6;
|
||||
struct in6_addr endaddr6;
|
||||
#endif
|
||||
class NetBlockIPv4Ranges : public NetBlock {
|
||||
public:
|
||||
octet_bitvector octets[4];
|
||||
|
||||
/* Is set to true iff all the addresses in this group have already been
|
||||
returned. */
|
||||
bool next(struct sockaddr_storage *ss);
|
||||
void apply_netmask(int bits);
|
||||
std::string str() const;
|
||||
|
||||
private:
|
||||
unsigned int counter[4];
|
||||
};
|
||||
|
||||
class NetBlockIPv6Netmask : public NetBlock {
|
||||
public:
|
||||
void set_addr(const struct sockaddr_in6 *addr);
|
||||
|
||||
bool next(struct sockaddr_storage *ss);
|
||||
void apply_netmask(int bits);
|
||||
std::string str() const;
|
||||
|
||||
private:
|
||||
bool exhausted;
|
||||
struct sockaddr_in6 addr;
|
||||
struct in6_addr start;
|
||||
struct in6_addr cur;
|
||||
struct in6_addr end;
|
||||
};
|
||||
|
||||
/* is the current target expression a named host? */
|
||||
int namedhost;
|
||||
class NetBlockHostname : public NetBlock {
|
||||
public:
|
||||
NetBlockHostname(const char *hostname, int af);
|
||||
int af;
|
||||
int bits;
|
||||
|
||||
NetBlock *resolve() const;
|
||||
|
||||
bool next(struct sockaddr_storage *ss);
|
||||
void apply_netmask(int bits);
|
||||
std::string str() const;
|
||||
};
|
||||
|
||||
/* Adding new targets is for NSE scripts */
|
||||
@@ -229,28 +216,4 @@ protected:
|
||||
static NewTargets *new_targets;
|
||||
};
|
||||
|
||||
class HostGroupState {
|
||||
public:
|
||||
HostGroupState(int lookahead, int randomize, char *target_expressions[],
|
||||
int num_expressions);
|
||||
~HostGroupState();
|
||||
Target **hostbatch;
|
||||
int max_batch_sz; /* The size of the hostbatch[] array */
|
||||
int current_batch_sz; /* The number of VALID members of hostbatch[] */
|
||||
int next_batch_no; /* The index of the next hostbatch[] member to be given
|
||||
back to the user */
|
||||
int randomize; /* Whether each batch should be "shuffled" prior to the ping
|
||||
scan (they will also be out of order when given back one
|
||||
at a time to the client program */
|
||||
char **target_expressions; /* An array of target expression strings, passed
|
||||
to us by the client (client is also in charge
|
||||
of deleting it AFTER it is done with the
|
||||
hostgroup_state */
|
||||
int num_expressions; /* The number of valid expressions in
|
||||
target_expressions member above */
|
||||
int next_expression; /* The index of the next expression we have
|
||||
to handle */
|
||||
TargetGroup current_expression; /* For batch chunking -- targets in queue */
|
||||
};
|
||||
|
||||
#endif /* TARGETGROUP_H */
|
||||
|
||||
@@ -4514,7 +4514,7 @@ 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 */
|
||||
char *grab_next_host_spec(FILE *inputfd, bool random, int argc, char **fakeargv) {
|
||||
const char *grab_next_host_spec(FILE *inputfd, bool random, int argc, const char **fakeargv) {
|
||||
static char host_spec[1024];
|
||||
struct in_addr ip;
|
||||
size_t n;
|
||||
|
||||
@@ -545,7 +545,7 @@ 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 */
|
||||
char *grab_next_host_spec(FILE *inputfd, bool random, int argc, char **fakeargv);
|
||||
const char *grab_next_host_spec(FILE *inputfd, bool random, int argc, const char **fakeargv);
|
||||
|
||||
#ifdef WIN32
|
||||
/* Convert a dnet interface name into the long pcap style. This also caches the
|
||||
|
||||
69
nmap.cc
69
nmap.cc
@@ -1576,12 +1576,8 @@ int nmap_main(int argc, char *argv[]) {
|
||||
/* Pre-Scan and Post-Scan script results datastructure */
|
||||
ScriptResults *script_scan_results = NULL;
|
||||
#endif
|
||||
char **host_exp_group;
|
||||
int num_host_exp_groups;
|
||||
HostGroupState *hstate = NULL;
|
||||
unsigned int ideal_scan_group_sz = 0;
|
||||
Target *currenths;
|
||||
char *host_spec = NULL;
|
||||
char myname[MAXHOSTNAMELEN + 1];
|
||||
int sourceaddrwarning = 0; /* Have we warned them yet about unguessable
|
||||
source addresses? */
|
||||
@@ -1818,61 +1814,15 @@ int nmap_main(int argc, char *argv[]) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Time to create a hostgroup state object filled with all the requested
|
||||
machines. The list is initially empty. It is refilled inside the loop
|
||||
whenever it is empty. */
|
||||
host_exp_group = (char **) safe_malloc(o.ping_group_sz * sizeof(char *));
|
||||
num_host_exp_groups = 0;
|
||||
|
||||
hstate = new HostGroupState(o.ping_group_sz, o.randomize_hosts,
|
||||
host_exp_group, num_host_exp_groups);
|
||||
HostGroupState hstate(o.ping_group_sz, o.randomize_hosts, argc, (const char **) fakeargv);
|
||||
|
||||
do {
|
||||
ideal_scan_group_sz = determineScanGroupSize(o.numhosts_scanned, &ports);
|
||||
while (Targets.size() < ideal_scan_group_sz) {
|
||||
o.current_scantype = HOST_DISCOVERY;
|
||||
currenths = nexthost(hstate, &exclude_group, &ports, o.pingtype);
|
||||
if (!currenths) {
|
||||
/* Try to refill with any remaining expressions */
|
||||
/* First free the old ones */
|
||||
for (i = 0; i < num_host_exp_groups; i++)
|
||||
free(host_exp_group[i]);
|
||||
num_host_exp_groups = 0;
|
||||
/* Now grab any new expressions */
|
||||
while (num_host_exp_groups < o.ping_group_sz &&
|
||||
(!o.max_ips_to_scan || o.max_ips_to_scan > o.numhosts_scanned + (int) Targets.size() + num_host_exp_groups) &&
|
||||
(host_spec = grab_next_host_spec(o.inputfd, o.generate_random_ips, argc, fakeargv))) {
|
||||
// For purposes of random scan
|
||||
host_exp_group[num_host_exp_groups++] = strdup(host_spec);
|
||||
}
|
||||
#ifndef NOLUA
|
||||
/* Add the new NSE discovered targets to the scan queue */
|
||||
if (o.script) {
|
||||
if (new_targets != NULL) {
|
||||
while (new_targets->get_queued() > 0 && num_host_exp_groups < o.ping_group_sz) {
|
||||
std::string target_spec = new_targets->read();
|
||||
if (target_spec.length())
|
||||
host_exp_group[num_host_exp_groups++] = strdup(target_spec.c_str());
|
||||
}
|
||||
|
||||
if (o.debugging > 3)
|
||||
log_write(LOG_PLAIN,
|
||||
"New targets in the scanned cache: %ld, pending ones: %ld.\n",
|
||||
new_targets->get_scanned(), new_targets->get_queued());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (num_host_exp_groups == 0)
|
||||
break;
|
||||
delete hstate;
|
||||
hstate = new HostGroupState(o.ping_group_sz, o.randomize_hosts, host_exp_group,
|
||||
num_host_exp_groups);
|
||||
|
||||
/* Try one last time -- with new expressions */
|
||||
currenths = nexthost(hstate, &exclude_group, &ports, o.pingtype);
|
||||
if (!currenths)
|
||||
break;
|
||||
}
|
||||
currenths = nexthost(&hstate, &exclude_group, &ports, o.pingtype);
|
||||
if (!currenths)
|
||||
break;
|
||||
|
||||
if (currenths->flags & HOST_UP && !o.listscan)
|
||||
o.numhosts_up++;
|
||||
@@ -1945,7 +1895,7 @@ int nmap_main(int argc, char *argv[]) {
|
||||
the next group if necessary. See target_needs_new_hostgroup for the
|
||||
details of when we need to split. */
|
||||
if (target_needs_new_hostgroup(Targets, currenths)) {
|
||||
returnhost(hstate);
|
||||
returnhost(&hstate);
|
||||
o.numhosts_up--;
|
||||
break;
|
||||
}
|
||||
@@ -2111,16 +2061,7 @@ int nmap_main(int argc, char *argv[]) {
|
||||
}
|
||||
#endif
|
||||
|
||||
delete hstate;
|
||||
|
||||
addrset_free(&exclude_group);
|
||||
hstate = NULL;
|
||||
|
||||
/* Free host expressions */
|
||||
for (i = 0; i < num_host_exp_groups; i++)
|
||||
free(host_exp_group[i]);
|
||||
num_host_exp_groups = 0;
|
||||
free(host_exp_group);
|
||||
|
||||
if (o.inputfd != NULL)
|
||||
fclose(o.inputfd);
|
||||
|
||||
@@ -1176,9 +1176,9 @@ char errstr[256];
|
||||
* class NpingTargets, that stores the specs and will provide the targets
|
||||
* through calls to getNextTarget();
|
||||
* */
|
||||
char *next_spec=NULL;
|
||||
while ( (next_spec= grab_next_host_spec(NULL, false, argc, argv)) != NULL )
|
||||
o.targets.addSpec( next_spec );
|
||||
const char *next_spec=NULL;
|
||||
while ( (next_spec= grab_next_host_spec(NULL, false, argc, (const char **) argv)) != NULL )
|
||||
o.targets.addSpec( (char *) next_spec );
|
||||
|
||||
return OP_SUCCESS;
|
||||
} /* End of parseArguments() */
|
||||
|
||||
291
targets.cc
291
targets.cc
@@ -309,6 +309,147 @@ static bool target_needs_new_hostgroup(const HostGroupState *hs, const Target *t
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Initializes (or reinitializes) the object with a new expression, such
|
||||
as 192.168.0.0/16 , 10.1.0-5.1-254 , or fe80::202:e3ff:fe14:1102 .
|
||||
Returns 0 for success */
|
||||
int TargetGroup::parse_expr(const char *target_expr, int af) {
|
||||
if (this->netblock != NULL)
|
||||
delete this->netblock;
|
||||
this->netblock = NetBlock::parse_expr(target_expr, af);
|
||||
if (this->netblock != NULL)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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
|
||||
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;
|
||||
|
||||
/* If all we have at this point is a hostname and netmask, resolve into
|
||||
something where we know the address. If we ever have to use strictly the
|
||||
hostname, without doing local DNS resolution (like with a proxy scan), this
|
||||
has to be made conditional (and perhaps an error if the netmask doesn't
|
||||
limit it to exactly one address). */
|
||||
NetBlockHostname *netblock_hostname;
|
||||
netblock_hostname = dynamic_cast<NetBlockHostname *>(this->netblock);
|
||||
if (netblock_hostname != NULL) {
|
||||
this->netblock = netblock_hostname->resolve();
|
||||
if (this->netblock == NULL) {
|
||||
error("Failed to resolve \"%s\".", netblock_hostname->hostname.c_str());
|
||||
return -1;
|
||||
}
|
||||
delete netblock_hostname;
|
||||
}
|
||||
|
||||
*sslen = sizeof(*ss);
|
||||
if (this->netblock->next(ss))
|
||||
return 0;
|
||||
else
|
||||
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. */
|
||||
bool TargetGroup::is_resolved_address(const struct sockaddr_storage *ss) const {
|
||||
return this->netblock->is_resolved_address(ss);
|
||||
}
|
||||
|
||||
/* Return a string of the name or address that was resolved for this group. */
|
||||
const char *TargetGroup::get_resolved_name(void) const {
|
||||
if (this->netblock->hostname.empty())
|
||||
return NULL;
|
||||
else
|
||||
return this->netblock->hostname.c_str();
|
||||
}
|
||||
|
||||
/* Return the list of addresses that the name for this group resolved to, if
|
||||
it came from a name resolution. */
|
||||
const std::list<struct sockaddr_storage> &TargetGroup::get_resolved_addrs(void) const {
|
||||
return this->netblock->resolvedaddrs;
|
||||
}
|
||||
|
||||
/* is the current expression a named host */
|
||||
int TargetGroup::get_namedhost() const {
|
||||
return this->get_resolved_name() != NULL;
|
||||
};
|
||||
|
||||
/* Lookahead is the number of hosts that can be
|
||||
checked (such as ping scanned) in advance. Randomize causes each
|
||||
group of up to lookahead hosts to be internally shuffled around.
|
||||
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) {
|
||||
assert(lookahead > 0);
|
||||
this->argc = argc;
|
||||
this->argv = argv;
|
||||
hostbatch = (Target **) safe_zalloc(sizeof(Target *) * lookahead);
|
||||
max_batch_sz = lookahead;
|
||||
current_batch_sz = 0;
|
||||
next_batch_no = 0;
|
||||
randomize = rnd;
|
||||
}
|
||||
|
||||
HostGroupState::~HostGroupState() {
|
||||
free(hostbatch);
|
||||
}
|
||||
|
||||
const char *HostGroupState::next_expression() {
|
||||
static char buf[1024];
|
||||
|
||||
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);
|
||||
if (expr != NULL)
|
||||
return expr;
|
||||
}
|
||||
|
||||
#ifndef NOLUA
|
||||
/* Add any new NSE discovered targets to the scan queue */
|
||||
|
||||
NewTargets *new_targets = NewTargets::get();
|
||||
if (o.script && new_targets != NULL) {
|
||||
if (new_targets->get_queued() > 0) {
|
||||
std::string expr_string;
|
||||
expr_string = new_targets->read().c_str();
|
||||
if (o.debugging > 3) {
|
||||
log_write(LOG_PLAIN,
|
||||
"New targets in the scanned cache: %ld, pending ones: %ld.\n",
|
||||
new_targets->get_scanned(), new_targets->get_queued());
|
||||
}
|
||||
if (!expr_string.empty()) {
|
||||
Strncpy(buf, expr_string.c_str(), sizeof(buf));
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add a <target> element to the XML stating that a target specification was
|
||||
ignored. This can be because of, for example, a DNS resolution failure, or a
|
||||
syntax error. */
|
||||
@@ -321,12 +462,75 @@ static void log_bogus_target(const char *expr) {
|
||||
xml_newline();
|
||||
}
|
||||
|
||||
/* Returns a newly allocated Target with the given address. Handles all the
|
||||
details like setting the Target's address and next hop. */
|
||||
static Target *setup_target(const HostGroupState *hs,
|
||||
const struct sockaddr_storage *ss, size_t sslen,
|
||||
int pingtype) {
|
||||
struct route_nfo rnfo;
|
||||
Target *t;
|
||||
|
||||
t = new Target();
|
||||
|
||||
t->setTargetSockAddr(ss, sslen);
|
||||
|
||||
/* Special handling for the resolved address (for example whatever
|
||||
scanme.nmap.org resolves to in scanme.nmap.org/24). */
|
||||
if (hs->current_group.is_resolved_address(ss)) {
|
||||
if (hs->current_group.get_namedhost())
|
||||
t->setTargetName(hs->current_group.get_resolved_name());
|
||||
t->resolved_addrs = hs->current_group.get_resolved_addrs();
|
||||
}
|
||||
|
||||
/* We figure out the source IP/device IFF
|
||||
1) We are r00t AND
|
||||
2) We are doing tcp or udp pingscan OR
|
||||
3) We are doing a raw-mode portscan or osscan or traceroute OR
|
||||
4) We are on windows and doing ICMP ping */
|
||||
if (o.isr00t &&
|
||||
((pingtype & (PINGTYPE_TCP|PINGTYPE_UDP|PINGTYPE_SCTP_INIT|PINGTYPE_PROTO|PINGTYPE_ARP)) || o.RawScan()
|
||||
#ifdef WIN32
|
||||
|| (pingtype & (PINGTYPE_ICMP_PING|PINGTYPE_ICMP_MASK|PINGTYPE_ICMP_TS))
|
||||
#endif // WIN32
|
||||
)) {
|
||||
if (!nmap_route_dst(ss, &rnfo)) {
|
||||
log_bogus_target(inet_ntop_ez(ss, sslen));
|
||||
error("%s: failed to determine route to %s", __func__, t->NameIP());
|
||||
goto bail;
|
||||
}
|
||||
if (rnfo.direct_connect) {
|
||||
t->setDirectlyConnected(true);
|
||||
} else {
|
||||
t->setDirectlyConnected(false);
|
||||
t->setNextHop(&rnfo.nexthop, sizeof(rnfo.nexthop));
|
||||
}
|
||||
t->setIfType(rnfo.ii.device_type);
|
||||
if (rnfo.ii.device_type == devt_ethernet) {
|
||||
if (o.spoofMACAddress())
|
||||
t->setSrcMACAddress(o.spoofMACAddress());
|
||||
else
|
||||
t->setSrcMACAddress(rnfo.ii.mac);
|
||||
}
|
||||
t->setSourceSockAddr(&rnfo.srcaddr, sizeof(rnfo.srcaddr));
|
||||
if (hs->current_batch_sz == 0) /* Because later ones can have different src addy and be cut off group */
|
||||
o.decoys[o.decoyturn] = t->v4source();
|
||||
t->setDeviceNames(rnfo.ii.devname, rnfo.ii.devfullname);
|
||||
t->setMTU(rnfo.ii.mtu);
|
||||
// printf("Target %s %s directly connected, goes through local iface %s, which %s ethernet\n", t->NameIP(), t->directlyConnected()? "IS" : "IS NOT", t->deviceName(), (t->ifType() == devt_ethernet)? "IS" : "IS NOT");
|
||||
}
|
||||
|
||||
return t;
|
||||
|
||||
bail:
|
||||
delete t;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Target *nexthost(HostGroupState *hs, const addrset *exclude_group,
|
||||
struct scan_lists *ports, int pingtype) {
|
||||
int i;
|
||||
struct sockaddr_storage ss;
|
||||
size_t sslen;
|
||||
struct route_nfo rnfo;
|
||||
bool arpping_done = false;
|
||||
struct timeval now;
|
||||
|
||||
@@ -334,73 +538,35 @@ Target *nexthost(HostGroupState *hs, const addrset *exclude_group,
|
||||
/* 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 */
|
||||
/* for (i=0; i < hs->max_batch_sz; i++) hs->hostbatch[i] = new Target(); */
|
||||
|
||||
/* Doh, we need to refresh our array */
|
||||
hs->current_batch_sz = hs->next_batch_no = 0;
|
||||
do {
|
||||
/* Grab anything we have in our current_expression */
|
||||
for (;;) {
|
||||
/* Grab anything we have in our current_group */
|
||||
while (hs->current_batch_sz < hs->max_batch_sz &&
|
||||
hs->current_expression.get_next_host(&ss, &sslen) == 0) {
|
||||
hs->current_group.get_next_host(&ss, &sslen) == 0) {
|
||||
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 */
|
||||
}
|
||||
|
||||
if (hostInExclude((struct sockaddr *)&ss, sslen, exclude_group)) {
|
||||
continue; /* Skip any hosts the user asked to exclude */
|
||||
}
|
||||
t = new Target();
|
||||
t->setTargetSockAddr(&ss, sslen);
|
||||
|
||||
/* Special handling for the resolved address (for example whatever
|
||||
scanme.nmap.org resolves to in scanme.nmap.org/24). */
|
||||
if (hs->current_expression.is_resolved_address(&ss)) {
|
||||
if (hs->current_expression.get_namedhost())
|
||||
t->setTargetName(hs->current_expression.get_resolved_name());
|
||||
t->resolved_addrs = hs->current_expression.get_resolved_addrs();
|
||||
}
|
||||
|
||||
/* We figure out the source IP/device IFF
|
||||
1) We are r00t AND
|
||||
2) We are doing tcp or udp pingscan OR
|
||||
3) We are doing a raw-mode portscan or osscan or traceroute OR
|
||||
4) We are on windows and doing ICMP ping */
|
||||
if (o.isr00t &&
|
||||
((pingtype & (PINGTYPE_TCP|PINGTYPE_UDP|PINGTYPE_SCTP_INIT|PINGTYPE_PROTO|PINGTYPE_ARP)) || o.RawScan()
|
||||
#ifdef WIN32
|
||||
|| (pingtype & (PINGTYPE_ICMP_PING|PINGTYPE_ICMP_MASK|PINGTYPE_ICMP_TS))
|
||||
#endif // WIN32
|
||||
)) {
|
||||
t->TargetSockAddr(&ss, &sslen);
|
||||
if (!nmap_route_dst(&ss, &rnfo)) {
|
||||
log_bogus_target(inet_ntop_ez(&ss, sslen));
|
||||
error("%s: failed to determine route to %s", __func__, t->NameIP());
|
||||
continue;
|
||||
}
|
||||
if (rnfo.direct_connect) {
|
||||
t->setDirectlyConnected(true);
|
||||
} else {
|
||||
t->setDirectlyConnected(false);
|
||||
t->setNextHop(&rnfo.nexthop, sizeof(rnfo.nexthop));
|
||||
}
|
||||
t->setIfType(rnfo.ii.device_type);
|
||||
if (rnfo.ii.device_type == devt_ethernet) {
|
||||
if (o.spoofMACAddress())
|
||||
t->setSrcMACAddress(o.spoofMACAddress());
|
||||
else
|
||||
t->setSrcMACAddress(rnfo.ii.mac);
|
||||
}
|
||||
t->setSourceSockAddr(&rnfo.srcaddr, sizeof(rnfo.srcaddr));
|
||||
if (hs->current_batch_sz == 0) /* Because later ones can have different src addy and be cut off group */
|
||||
o.decoys[o.decoyturn] = t->v4source();
|
||||
t->setDeviceNames(rnfo.ii.devname, rnfo.ii.devfullname);
|
||||
t->setMTU(rnfo.ii.mtu);
|
||||
// printf("Target %s %s directly connected, goes through local iface %s, which %s ethernet\n", t->NameIP(), t->directlyConnected()? "IS" : "IS NOT", t->deviceName(), (t->ifType() == devt_ethernet)? "IS" : "IS NOT");
|
||||
}
|
||||
t = setup_target(hs, &ss, sslen, pingtype);
|
||||
if (t == NULL)
|
||||
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_expression.return_last_host();
|
||||
hs->current_group.return_host(t->TargetSockAddr());
|
||||
delete t;
|
||||
goto batchfull;
|
||||
}
|
||||
@@ -408,19 +574,20 @@ Target *nexthost(HostGroupState *hs, const addrset *exclude_group,
|
||||
hs->hostbatch[hs->current_batch_sz++] = t;
|
||||
}
|
||||
|
||||
if (hs->current_batch_sz < hs->max_batch_sz &&
|
||||
hs->next_expression < hs->num_expressions) {
|
||||
if (hs->current_batch_sz < hs->max_batch_sz) {
|
||||
const char *expr;
|
||||
/* We are going to have to pop in another expression. */
|
||||
while (hs->next_expression < hs->num_expressions) {
|
||||
const char *expr;
|
||||
expr = hs->target_expressions[hs->next_expression++];
|
||||
if (hs->current_expression.parse_expr(expr, o.af()) != 0)
|
||||
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;
|
||||
} while(1);
|
||||
}
|
||||
|
||||
batchfull:
|
||||
|
||||
|
||||
60
targets.h
60
targets.h
@@ -118,8 +118,66 @@
|
||||
|
||||
#include "nmap.h"
|
||||
#include "global_structures.h"
|
||||
#include "TargetGroup.h"
|
||||
|
||||
class HostGroupState;
|
||||
class TargetGroup {
|
||||
public:
|
||||
NetBlock *netblock;
|
||||
struct sockaddr_storage pushback;
|
||||
|
||||
TargetGroup() {
|
||||
this->netblock = NULL;
|
||||
this->pushback.ss_family = AF_UNSPEC;
|
||||
}
|
||||
|
||||
~TargetGroup() {
|
||||
if (this->netblock != NULL)
|
||||
delete this->netblock;
|
||||
}
|
||||
|
||||
/* Initializes (or reinitializes) the object with a new expression,
|
||||
such as 192.168.0.0/16 , 10.1.0-5.1-254 , or
|
||||
fe80::202:e3ff:fe14:1102 . The af parameter is AF_INET or
|
||||
AF_INET6 Returns 0 for success */
|
||||
int parse_expr(const char *target_expr, int af);
|
||||
/* Grab the next host from this expression (if any). Returns 0 and
|
||||
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. */
|
||||
bool is_resolved_address(const struct sockaddr_storage *ss) const;
|
||||
/* Return a string of the name or address that was resolved for this group. */
|
||||
const char *get_resolved_name(void) const;
|
||||
/* Return the list of addresses that the name for this group resolved to, if
|
||||
it came from a name resolution. */
|
||||
const std::list<struct sockaddr_storage> &get_resolved_addrs(void) const;
|
||||
/* is the current expression a named host */
|
||||
int get_namedhost() const;
|
||||
};
|
||||
|
||||
class HostGroupState {
|
||||
public:
|
||||
HostGroupState(int lookahead, int randomize, int argc, const char *argv[]);
|
||||
~HostGroupState();
|
||||
Target **hostbatch;
|
||||
int argc;
|
||||
const char **argv;
|
||||
int max_batch_sz; /* The size of the hostbatch[] array */
|
||||
int current_batch_sz; /* The number of VALID members of hostbatch[] */
|
||||
int next_batch_no; /* The index of the next hostbatch[] member to be given
|
||||
back to the user */
|
||||
int randomize; /* Whether each batch should be "shuffled" prior to the ping
|
||||
scan (they will also be out of order when given back one
|
||||
at a time to the client program */
|
||||
TargetGroup current_group; /* For batch chunking -- targets in queue */
|
||||
|
||||
const char *next_expression();
|
||||
};
|
||||
|
||||
/* Ports is the list of ports the user asked to be scanned (0 terminated),
|
||||
you can just pass NULL (it is only a stupid optimization that needs it) */
|
||||
|
||||
Reference in New Issue
Block a user