1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-26 01:19:03 +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:
david
2013-01-22 00:01:08 +00:00
parent d04f16eb32
commit e1fba2d663
8 changed files with 813 additions and 652 deletions

View File

@@ -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);
}