722 lines
19 KiB
C
722 lines
19 KiB
C
|
/*
|
||
|
for tracking IP/port ranges
|
||
|
*/
|
||
|
#include "massip-rangesv6.h"
|
||
|
#include "massip-rangesv4.h"
|
||
|
#include "util-malloc.h"
|
||
|
#include "util-logger.h"
|
||
|
#include "massip.h"
|
||
|
#include "massip-parse.h"
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <ctype.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <stdint.h>
|
||
|
|
||
|
#define BUCKET_COUNT 16
|
||
|
|
||
|
#define REGRESS(i,x) if (!(x)) return (fprintf(stderr, "[-] %u: regression failed %s:%d\n", (unsigned)i, __FILE__, __LINE__)|1)
|
||
|
#ifndef false
|
||
|
#define false 0
|
||
|
#endif
|
||
|
#ifndef true
|
||
|
#define true 1
|
||
|
#endif
|
||
|
|
||
|
#define EQUAL(x,y) ipv6address_is_equal(x,y)
|
||
|
|
||
|
static inline ipv6address
|
||
|
_int128_add(ipv6address x, ipv6address y)
|
||
|
{
|
||
|
ipv6address result;
|
||
|
result.lo = x.lo + y.lo;
|
||
|
result.hi = x.hi + y.hi + (result.lo < x.lo);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static inline ipv6address
|
||
|
_int128_subtract(ipv6address x, ipv6address y)
|
||
|
{
|
||
|
ipv6address result;
|
||
|
result.lo = x.lo - y.lo;
|
||
|
result.hi = x.hi - y.hi - (result.lo > x.lo);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static ipv6address
|
||
|
_int128_add64(const ipv6address lhs, uint64_t rhs)
|
||
|
{
|
||
|
ipv6address result = lhs;
|
||
|
result.lo += rhs;
|
||
|
if (result.lo < lhs.lo)
|
||
|
result.hi++;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static inline massint128_t
|
||
|
_int128_mult64(massint128_t lhs, uint64_t rhs)
|
||
|
{
|
||
|
massint128_t result = {0,0};
|
||
|
uint64_t x;
|
||
|
uint64_t b;
|
||
|
uint64_t a;
|
||
|
|
||
|
/* low-order 32 */
|
||
|
a = (rhs>>0) & 0xFFFFFFFFULL;
|
||
|
b = (lhs.lo>>0) & 0xFFFFFFFFULL;
|
||
|
x = (a * b);
|
||
|
result.lo += x;
|
||
|
|
||
|
b = (lhs.lo>>32ULL) & 0xFFFFFFFFULL;
|
||
|
x = (a * b);
|
||
|
result.lo += x<<32ULL;
|
||
|
result.hi += x>>32ULL;
|
||
|
|
||
|
b = lhs.hi;
|
||
|
x = (a * b);
|
||
|
result.hi += x;
|
||
|
|
||
|
/* next 32 */
|
||
|
a = (rhs>>32ULL) & 0xFFFFFFFFULL;
|
||
|
b = (lhs.lo>>0ULL) & 0xFFFFFFFFULL;
|
||
|
x = (a * b);
|
||
|
result.lo += x<<32ULL;
|
||
|
result.hi += (x>>32ULL) + (result.lo < (x<<32ULL));
|
||
|
|
||
|
b = (lhs.lo>>32ULL) & 0xFFFFFFFFULL;
|
||
|
x = (a * b);
|
||
|
result.hi += x;
|
||
|
|
||
|
b = lhs.hi;
|
||
|
x = (a * b);
|
||
|
result.hi += x<<32ULL;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
LESS(const ipv6address lhs, const ipv6address rhs)
|
||
|
{
|
||
|
if (lhs.hi < rhs.hi)
|
||
|
return 1;
|
||
|
else if (lhs.hi == rhs.hi && lhs.lo < rhs.lo)
|
||
|
return 1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
#define GREATEREQ(x,y) (!LESS(x,y))
|
||
|
|
||
|
static int
|
||
|
LESSEQ(const ipv6address lhs, const ipv6address rhs)
|
||
|
{
|
||
|
if (lhs.hi < rhs.hi)
|
||
|
return 1;
|
||
|
if (lhs.hi > rhs.hi)
|
||
|
return 0;
|
||
|
|
||
|
if (lhs.lo <= rhs.lo)
|
||
|
return 1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int range6_is_bad_address(const struct Range6 *range)
|
||
|
{
|
||
|
return LESS(range->end, range->begin);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
_int128_is_equals(const ipv6address lhs, const ipv6address rhs)
|
||
|
{
|
||
|
return lhs.hi == rhs.hi && lhs.lo == rhs.lo;
|
||
|
}
|
||
|
|
||
|
static ipv6address
|
||
|
MINUS_ONE(const ipv6address ip)
|
||
|
{
|
||
|
ipv6address result;
|
||
|
|
||
|
if (ip.lo == 0) {
|
||
|
result.hi = ip.hi - 1;
|
||
|
result.lo = ~0ULL;
|
||
|
} else {
|
||
|
result.hi = ip.hi;
|
||
|
result.lo = ip.lo - 1;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static ipv6address PLUS_ONE(const ipv6address ip)
|
||
|
{
|
||
|
ipv6address result;
|
||
|
|
||
|
if (ip.lo == ~0) {
|
||
|
result.hi = ip.hi + 1;
|
||
|
result.lo = 0;
|
||
|
} else {
|
||
|
result.hi = ip.hi;
|
||
|
result.lo = ip.lo + 1;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
massint128_t
|
||
|
massip_range(struct MassIP *massip)
|
||
|
{
|
||
|
massint128_t result;
|
||
|
|
||
|
|
||
|
result = range6list_count(&massip->ipv6);
|
||
|
result = _int128_add64(result, rangelist_count(&massip->ipv4));
|
||
|
result = _int128_mult64(result, rangelist_count(&massip->ports));
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
int
|
||
|
range6list_is_contains(const struct Range6List *targets, const ipv6address ip)
|
||
|
{
|
||
|
unsigned i;
|
||
|
|
||
|
for (i=0; i<targets->count; i++) {
|
||
|
struct Range6 *range = &targets->list[i];
|
||
|
|
||
|
if (LESSEQ(range->begin, ip) && LESSEQ(ip, range->end))
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
* ???
|
||
|
***************************************************************************/
|
||
|
static void
|
||
|
todo_remove_at(struct Range6List *targets, unsigned index)
|
||
|
{
|
||
|
memmove(&targets->list[index],
|
||
|
&targets->list[index+1],
|
||
|
(targets->count - index) * sizeof(targets->list[index])
|
||
|
);
|
||
|
targets->count--;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* Test if two ranges overlap.
|
||
|
* This is easiest done by testing that they don't overlap, and inverting
|
||
|
* the result.
|
||
|
* Note that adjacent addresses overlap.
|
||
|
***************************************************************************/
|
||
|
static int
|
||
|
range6_is_overlap(const struct Range6 lhs, const struct Range6 rhs)
|
||
|
{
|
||
|
static const ipv6address FFFF = {~0ULL, ~0ULL};
|
||
|
|
||
|
if (LESS(lhs.begin, rhs.begin)) {
|
||
|
if (EQUAL(lhs.end, FFFF) || GREATEREQ(PLUS_ONE(lhs.end), rhs.begin))
|
||
|
return 1;
|
||
|
}
|
||
|
if (GREATEREQ(lhs.begin, rhs.begin)) {
|
||
|
if (LESSEQ(lhs.end, rhs.end))
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (LESS(rhs.begin, lhs.begin)) {
|
||
|
if (EQUAL(rhs.end, FFFF) || GREATEREQ(PLUS_ONE(rhs.end), lhs.begin))
|
||
|
return 1;
|
||
|
}
|
||
|
if (GREATEREQ(rhs.begin, lhs.begin)) {
|
||
|
if (LESSEQ(rhs.end, lhs.end))
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
#if 0
|
||
|
static const ipv6address zero = {0, 0};
|
||
|
ipv6address lhs_endm = MINUS_ONE(lhs.end);
|
||
|
ipv6address rhs_endm = MINUS_ONE(rhs.end);
|
||
|
|
||
|
/* llll rrrr */
|
||
|
if (LESS(zero, lhs.end) && LESS(lhs_endm, rhs.begin))
|
||
|
return 0;
|
||
|
|
||
|
/* rrrr llll */
|
||
|
if (LESS(zero, rhs.end) && LESS(rhs_endm, lhs.begin))
|
||
|
return 0;
|
||
|
|
||
|
return 1;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* Combine two ranges, such as when they overlap.
|
||
|
***************************************************************************/
|
||
|
static void
|
||
|
range6_combine(struct Range6 *lhs, const struct Range6 rhs)
|
||
|
{
|
||
|
if (LESSEQ(rhs.begin, lhs->begin))
|
||
|
lhs->begin = rhs.begin;
|
||
|
if (LESSEQ(lhs->end, rhs.end))
|
||
|
lhs->end = rhs.end;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* Callback for qsort() for comparing two ranges
|
||
|
***************************************************************************/
|
||
|
static int
|
||
|
range6_compare(const void *lhs, const void *rhs)
|
||
|
{
|
||
|
struct Range6 *left = (struct Range6 *)lhs;
|
||
|
struct Range6 *right = (struct Range6 *)rhs;
|
||
|
|
||
|
if (ipv6address_is_equal(left->begin, right->begin))
|
||
|
return 0;
|
||
|
else if (LESS(left->begin, right->begin))
|
||
|
return -1;
|
||
|
else
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
void
|
||
|
range6list_sort(struct Range6List *targets)
|
||
|
{
|
||
|
size_t i;
|
||
|
struct Range6List newlist = {0};
|
||
|
size_t original_count = targets->count;
|
||
|
|
||
|
/* Empty lists are, of course, sorted. We need to set this
|
||
|
* to avoid an error later on in the code which asserts that
|
||
|
* the lists are sorted */
|
||
|
if (targets->count == 0) {
|
||
|
targets->is_sorted = 1;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* If it's already sorted, then skip this */
|
||
|
if (targets->is_sorted) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* First, sort the list */
|
||
|
LOG(3, "[+] range6:sort: sorting...\n");
|
||
|
qsort( targets->list, /* the array to sort */
|
||
|
targets->count, /* number of elements to sort */
|
||
|
sizeof(targets->list[0]), /* size of element */
|
||
|
range6_compare);
|
||
|
|
||
|
|
||
|
/* Second, combine all overlapping ranges. We do this by simply creating
|
||
|
* a new list from a sorted list, so we don't have to remove things in the
|
||
|
* middle when collapsing overlapping entries together, which is painfully
|
||
|
* slow. */
|
||
|
LOG(3, "[+] range:sort: combining...\n");
|
||
|
for (i=0; i<targets->count; i++) {
|
||
|
range6list_add_range(&newlist, targets->list[i].begin, targets->list[i].end);
|
||
|
}
|
||
|
|
||
|
LOG(3, "[+] range:sort: combined from %u elements to %u elements\n", original_count, newlist.count);
|
||
|
free(targets->list);
|
||
|
targets->list = newlist.list;
|
||
|
targets->count = newlist.count;
|
||
|
newlist.list = 0;
|
||
|
|
||
|
LOG(2, "[+] range:sort: done...\n");
|
||
|
|
||
|
targets->is_sorted = 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
range6list_add_range(struct Range6List *targets, ipv6address begin, ipv6address end)
|
||
|
{
|
||
|
struct Range6 range;
|
||
|
|
||
|
range.begin = begin;
|
||
|
range.end = end;
|
||
|
|
||
|
/* auto-expand the list if necessary */
|
||
|
if (targets->count + 1 >= targets->max) {
|
||
|
targets->max = targets->max * 2 + 1;
|
||
|
targets->list = REALLOCARRAY(targets->list, targets->max, sizeof(targets->list[0]));
|
||
|
}
|
||
|
|
||
|
/* If empty list, then add this one */
|
||
|
if (targets->count == 0) {
|
||
|
targets->list[0] = range;
|
||
|
targets->count++;
|
||
|
targets->is_sorted = 1;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* If new range overlaps the last range in the list, then combine it
|
||
|
* rather than appending it. This is an optimization for the fact that
|
||
|
* we often read in sequential addresses */
|
||
|
if (range6_is_overlap(targets->list[targets->count - 1], range)) {
|
||
|
range6_combine(&targets->list[targets->count - 1], range);
|
||
|
targets->is_sorted = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* append to the end of our list */
|
||
|
targets->list[targets->count] = range;
|
||
|
targets->count++;
|
||
|
targets->is_sorted = 0;
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
void
|
||
|
range6list_remove_all(struct Range6List *targets)
|
||
|
{
|
||
|
if (targets->list)
|
||
|
free(targets->list);
|
||
|
if (targets->picker)
|
||
|
free(targets->picker);
|
||
|
memset(targets, 0, sizeof(*targets));
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
void
|
||
|
range6list_merge(struct Range6List *list1, const struct Range6List *list2)
|
||
|
{
|
||
|
unsigned i;
|
||
|
|
||
|
for (i=0; i<list2->count; i++) {
|
||
|
range6list_add_range(list1, list2->list[i].begin, list2->list[i].end);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
void
|
||
|
range6list_remove_range(struct Range6List *targets, const ipv6address begin, const ipv6address end)
|
||
|
{
|
||
|
unsigned i;
|
||
|
struct Range6 x;
|
||
|
|
||
|
x.begin = begin;
|
||
|
x.end = end;
|
||
|
|
||
|
/* See if the range overlaps any exist range already in the
|
||
|
* list */
|
||
|
for (i = 0; i < targets->count; i++) {
|
||
|
if (!range6_is_overlap(targets->list[i], x))
|
||
|
continue;
|
||
|
|
||
|
/* If the removal-range wholly covers the range, delete
|
||
|
* it completely */
|
||
|
if (LESSEQ(begin, targets->list[i].begin) && LESSEQ(targets->list[i].end, end)) {
|
||
|
todo_remove_at(targets, i);
|
||
|
i--;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* If the removal-range bisects the target-rage, truncate
|
||
|
* the lower end and add a new high-end */
|
||
|
if (LESSEQ(targets->list[i].begin, begin) && LESSEQ(end, targets->list[i].end)) {
|
||
|
struct Range6 newrange;
|
||
|
|
||
|
newrange.begin = PLUS_ONE(end);
|
||
|
newrange.end = targets->list[i].end;
|
||
|
|
||
|
|
||
|
targets->list[i].end = MINUS_ONE(begin);
|
||
|
|
||
|
range6list_add_range(targets, newrange.begin, newrange.end);
|
||
|
i--;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* If overlap on the lower side */
|
||
|
if (LESSEQ(targets->list[i].begin, end) && LESSEQ(end, targets->list[i].end)) {
|
||
|
targets->list[i].begin = PLUS_ONE(end);
|
||
|
}
|
||
|
|
||
|
/* If overlap on the upper side */
|
||
|
if (LESSEQ(targets->list[i].begin, begin) && LESSEQ(begin, targets->list[i].end)) {
|
||
|
targets->list[i].end = MINUS_ONE(begin);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
range6list_remove_range2(struct Range6List *targets, struct Range6 range)
|
||
|
{
|
||
|
range6list_remove_range(targets, range.begin, range.end);
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
ipv6address
|
||
|
range6list_exclude( struct Range6List *targets,
|
||
|
const struct Range6List *excludes)
|
||
|
{
|
||
|
ipv6address count = {0,0};
|
||
|
unsigned i;
|
||
|
|
||
|
for (i=0; i<excludes->count; i++) {
|
||
|
struct Range6 range = excludes->list[i];
|
||
|
ipv6address x;
|
||
|
|
||
|
x = _int128_subtract(range.end, range.begin);
|
||
|
x = _int128_add64(x, 1);
|
||
|
|
||
|
count = _int128_add(count, x);
|
||
|
range6list_remove_range(targets, range.begin, range.end);
|
||
|
}
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
massint128_t
|
||
|
range6list_count(const struct Range6List *targets)
|
||
|
{
|
||
|
unsigned i;
|
||
|
ipv6address result = {0,0};
|
||
|
|
||
|
for (i=0; i<targets->count; i++) {
|
||
|
ipv6address x;
|
||
|
|
||
|
x = _int128_subtract(targets->list[i].end, targets->list[i].begin);
|
||
|
if (x.hi == ~0ULL && x.lo == ~0ULL)
|
||
|
return x; /* overflow */
|
||
|
x = _int128_add64(x, 1);
|
||
|
result = _int128_add(result, x);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
ipv6address
|
||
|
range6list_pick(const struct Range6List *targets, uint64_t index)
|
||
|
{
|
||
|
size_t maxmax = targets->count;
|
||
|
size_t min = 0;
|
||
|
size_t max = targets->count;
|
||
|
size_t mid;
|
||
|
const size_t *picker = targets->picker;
|
||
|
|
||
|
if (picker == NULL) {
|
||
|
fprintf(stderr, "[-] ipv6 picker is null\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
for (;;) {
|
||
|
mid = min + (max-min)/2;
|
||
|
if (index < picker[mid]) {
|
||
|
max = mid;
|
||
|
continue;
|
||
|
} if (index >= picker[mid]) {
|
||
|
if (mid + 1 == maxmax)
|
||
|
break;
|
||
|
else if (index < picker[mid+1])
|
||
|
break;
|
||
|
else
|
||
|
min = mid+1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return _int128_add64(targets->list[mid].begin, (index - picker[mid]));
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* The normal "pick" function is a linear search, which is slow when there
|
||
|
* are a lot of ranges. Therefore, the "pick2" creates sort of binary
|
||
|
* search that'll be a lot faster. We choose "binary search" because
|
||
|
* it's the most cache-efficient, having the least overhead to fit within
|
||
|
* the cache.
|
||
|
***************************************************************************/
|
||
|
void
|
||
|
range6list_optimize(struct Range6List *targets)
|
||
|
{
|
||
|
size_t *picker;
|
||
|
size_t i;
|
||
|
ipv6address total = {0,0};
|
||
|
|
||
|
if (targets->count == 0)
|
||
|
return;
|
||
|
|
||
|
/* This technique only works when the targets are in
|
||
|
* ascending order */
|
||
|
if (!targets->is_sorted)
|
||
|
range6list_sort(targets);
|
||
|
|
||
|
if (targets->picker)
|
||
|
free(targets->picker);
|
||
|
|
||
|
picker = REALLOCARRAY(NULL, targets->count, sizeof(*picker));
|
||
|
|
||
|
for (i=0; i<targets->count; i++) {
|
||
|
ipv6address x;
|
||
|
picker[i] = (size_t)total.lo;
|
||
|
x = _int128_subtract(targets->list[i].end, targets->list[i].begin);
|
||
|
x = _int128_add64(x, 1);
|
||
|
total = _int128_add(total, x);
|
||
|
}
|
||
|
|
||
|
targets->picker = picker;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* Provide my own rand() simply to avoid static-analysis warning me that
|
||
|
* 'rand()' is unrandom, when in fact we want the non-random properties of
|
||
|
* rand() for regression testing.
|
||
|
***************************************************************************/
|
||
|
static unsigned
|
||
|
r_rand(unsigned *seed)
|
||
|
{
|
||
|
static const unsigned a = 214013;
|
||
|
static const unsigned c = 2531011;
|
||
|
|
||
|
*seed = (*seed) * a + c;
|
||
|
return (*seed)>>16 & 0x7fff;
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
***************************************************************************/
|
||
|
static int
|
||
|
regress_pick2()
|
||
|
{
|
||
|
unsigned i;
|
||
|
unsigned seed = 0;
|
||
|
|
||
|
/*
|
||
|
*/
|
||
|
for (i=0; i<65536; i++)
|
||
|
{
|
||
|
ipv6address a;
|
||
|
ipv6address b;
|
||
|
ipv6address c;
|
||
|
ipv6address d;
|
||
|
|
||
|
a.hi = r_rand(&seed);
|
||
|
a.lo = (unsigned long long)r_rand(&seed)<<49ULL;
|
||
|
b.hi = r_rand(&seed);
|
||
|
b.lo = 0x8765432100000000ULL;
|
||
|
|
||
|
c = _int128_add(a, b);
|
||
|
d = _int128_subtract(c, b);
|
||
|
|
||
|
if (!_int128_is_equals(a, d)) {
|
||
|
fprintf(stderr, "[-] %s:%d: test failed (%u)\n", __FILE__, __LINE__, (unsigned)i);
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Run 100 randomized regression tests
|
||
|
*/
|
||
|
for (i=3; i<100; i++) {
|
||
|
unsigned j;
|
||
|
unsigned num_targets;
|
||
|
ipv6address begin = {0};
|
||
|
ipv6address end = {0};
|
||
|
struct Range6List targets[1];
|
||
|
struct Range6List duplicate[1];
|
||
|
uint64_t range;
|
||
|
ipv6address x;
|
||
|
|
||
|
seed = i;
|
||
|
|
||
|
/* Create a new target list */
|
||
|
memset(targets, 0, sizeof(targets[0]));
|
||
|
|
||
|
/* fill the target list with random ranges */
|
||
|
num_targets = r_rand(&seed)%5 + 1;
|
||
|
for (j=0; j<num_targets; j++) {
|
||
|
begin.lo += r_rand(&seed)%10;
|
||
|
end.lo = begin.lo + r_rand(&seed)%10;
|
||
|
|
||
|
range6list_add_range(targets, begin, end);
|
||
|
}
|
||
|
|
||
|
/* Optimize for faster 'picking' addresses from an index */
|
||
|
range6list_optimize(targets);
|
||
|
|
||
|
|
||
|
/* Duplicate the targetlist using the picker */
|
||
|
memset(duplicate, 0, sizeof(duplicate[0]));
|
||
|
x = range6list_count(targets);
|
||
|
if (x.hi) {
|
||
|
fprintf(stderr, "[-] range6: range too big\n");
|
||
|
return 1;
|
||
|
}
|
||
|
range = x.lo;
|
||
|
for (j=0; j<range; j++) {
|
||
|
ipv6address addr;
|
||
|
|
||
|
addr = range6list_pick(targets, j);
|
||
|
range6list_add_range(duplicate, addr, addr);
|
||
|
}
|
||
|
|
||
|
/* at this point, the two range lists should be identical */
|
||
|
REGRESS(i, targets->count == duplicate->count);
|
||
|
REGRESS(i, memcmp(targets->list, duplicate->list, targets->count*sizeof(targets->list[0])) == 0);
|
||
|
|
||
|
range6list_remove_all(targets);
|
||
|
range6list_remove_all(duplicate);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* Called during "make regress" to run a regression test over this module.
|
||
|
***************************************************************************/
|
||
|
int
|
||
|
ranges6_selftest(void)
|
||
|
{
|
||
|
struct Range6 r;
|
||
|
struct Range6List targets[1];
|
||
|
int err;
|
||
|
|
||
|
REGRESS(0, regress_pick2() == 0);
|
||
|
|
||
|
memset(targets, 0, sizeof(targets[0]));
|
||
|
#define ERROR() fprintf(stderr, "selftest: failed %s:%u\n", __FILE__, __LINE__);
|
||
|
|
||
|
err = massip_parse_range("2001:0db8:85a3:0000:0000:8a2e:0370:7334", 0, 0, 0, &r);
|
||
|
if (err != Ipv6_Address)
|
||
|
ERROR();
|
||
|
|
||
|
/* test for the /0 CIDR block, since we'll be using that a lot to scan the entire
|
||
|
* Internet */
|
||
|
if (r.begin.hi != 0x20010db885a30000ULL)
|
||
|
return 1;
|
||
|
if (r.begin.lo != 0x00008a2e03707334ULL)
|
||
|
return 1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|