diff --git a/CHANGELOG.md b/CHANGELOG.md index 880e7e5..de340bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +Next +==== + +## New features + +- The -g, --generate option now also supports IPv6 addresses + fping 5.3 (2025-01-02) ====================== diff --git a/ci/test-06-options-f-h.pl b/ci/test-06-options-f-h.pl index a354ae5..2a95dcf 100755 --- a/ci/test-06-options-f-h.pl +++ b/ci/test-06-options-f-h.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl -w -use Test::Command tests => 102; +use Test::Command tests => 152; use Test::More; use File::Temp; @@ -208,40 +208,140 @@ $cmd->stderr_like(qr{can't parse address 127\.0\.0\.1:.*(not supported|not known)}); } -# fping -g (range - no IPv6 generator) +# fping -g (range - IPv6) SKIP: { if($ENV{SKIP_IPV6}) { skip 'Skip IPv6 tests', 3; } my $cmd = Test::Command->new(cmd => "fping -g ::1 ::1"); + $cmd->exit_is_num(0); + $cmd->stdout_is_eq("::1 is alive\n"); + $cmd->stderr_is_eq(""); +} + +# fping -g (empty range - IPv6) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -g ::1 ::"); $cmd->exit_is_num(1); $cmd->stdout_is_eq(""); - $cmd->stderr_is_eq("fping: -g works only with IPv4 addresses\n"); + $cmd->stderr_is_eq(""); } -# fping -g (empty range - no IPv6 generator) +# fping -g (empty range - IPv6 - crossing 64 bit boundary) SKIP: { if($ENV{SKIP_IPV6}) { skip 'Skip IPv6 tests', 3; } - my $cmd = Test::Command->new(cmd => "fping -g ::1 ::"); + my $cmd = Test::Command->new(cmd => "fping -g 2001:db8:0:2:: 2001:db8:0:1:ffff:ffff:ffff:ffff"); $cmd->exit_is_num(1); $cmd->stdout_is_eq(""); - $cmd->stderr_is_eq("fping: -g works only with IPv4 addresses\n"); + $cmd->stderr_is_eq(""); } -# fping -6 -g (range - no IPv6 generator) +# fping -6 -g (range - IPv6) SKIP: { if($ENV{SKIP_IPV6}) { skip 'Skip IPv6 tests', 3; } my $cmd = Test::Command->new(cmd => "fping -6 -g ::1 ::1"); + $cmd->exit_is_num(0); + $cmd->stdout_is_eq("::1 is alive\n"); + $cmd->stderr_is_eq(""); +} + +# fping -g (range - scoped IPv6) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 1; + } + my $cmd = Test::Command->new(cmd => "fping -i1 -t10 -r0 -g fe80::47%2 fe80::48%2"); + $cmd->stdout_like(qr{fe80::47%2 is (alive|unreachable)\nfe80::48%2 is (alive|unreachable)\n}); +} + +# fping -g (range - scoped IPv6 - only start address is scoped) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -i1 -t10 -r0 -g fe80::47%2 fe80::48"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq(""); + $cmd->stderr_is_eq("fping: different scopes for start and end addresses\n"); +} + +# fping -g (range - scoped IPv6 - only end address is scoped) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -i1 -t10 -r0 -g fe80::47 fe80::48%2"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq(""); + $cmd->stderr_is_eq("fping: different scopes for start and end addresses\n"); +} + +# fping -g (range - inconsistently scoped IPv6) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -i1 -t10 -r0 -g fe80::47%2 fe80::48%3"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq(""); + $cmd->stderr_is_eq("fping: different scopes for start and end addresses\n"); +} + +# fping -g (range - unreachable documentation addresses) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -t10 -r0 -i1 -g 2001:db8:1:2:3:4:5:6 2001:db8:1:2:3:4:5:7"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq("2001:db8:1:2:3:4:5:6 is unreachable\n2001:db8:1:2:3:4:5:7 is unreachable\n"); + $cmd->stderr_is_eq(""); +} + +# fping -g (range - unreachable documentation addresses - crossing 64 bit boundary) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -t10 -i1 -r0 -g 2001:db8:1:2:ffff:ffff:ffff:fffe 2001:db8:1:3::1"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq("2001:db8:1:2:ffff:ffff:ffff:fffe is unreachable +2001:db8:1:2:ffff:ffff:ffff:ffff is unreachable +2001:db8:1:3:: is unreachable +2001:db8:1:3::1 is unreachable\n"); + $cmd->stderr_is_eq(""); +} + +# fping -g (range - too many addresses - lower 64 bit) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -t10 -i1 -r0 -g 2001:db8:1:2:3:4:0:1 2001:db8:1:2:3:4:ff:ffff"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq(""); + $cmd->stderr_is_eq("fping: -g parameter generates too many addresses\n"); +} + +# fping -g (range - too many addresses - upper 64 bit) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -t10 -i1 -r0 -g 2001:db8:1:2::1 2001:db8:1:3::1"); $cmd->exit_is_num(1); $cmd->stdout_is_eq(""); - $cmd->stderr_is_eq("fping: -g works only with IPv4 addresses\n"); + $cmd->stderr_is_eq("fping: -g parameter generates too many addresses\n"); } -# fping -6 -g (range - no IPv6 generator - start address IPv6) +# fping -6 -g (range - mixed address families - start address IPv6) SKIP: { if($ENV{SKIP_IPV6}) { skip 'Skip IPv6 tests', 3; @@ -249,10 +349,10 @@ my $cmd = Test::Command->new(cmd => "fping -6 -g ::1 127.0.0.1"); $cmd->exit_is_num(1); $cmd->stdout_is_eq(""); - $cmd->stderr_is_eq("fping: -g works only with IPv4 addresses\n"); + $cmd->stderr_like(qr{fping: can't parse address 127\.0\.0\.1: .*\n}); } -# fping -g (range - no IPv6 generator - end address IPv6) +# fping -g (range - mixed address families - end address IPv6) SKIP: { if($ENV{SKIP_IPV6}) { skip 'Skip IPv6 tests', 3; @@ -263,7 +363,7 @@ $cmd->stderr_like(qr{fping: can't parse address ::1: .*\n}); } -# fping -6 -g (range - no IPv6 generator - end address IPv6) +# fping -6 -g (range - mixed address families - end address IPv6) SKIP: { if($ENV{SKIP_IPV6}) { skip 'Skip IPv6 tests', 3; @@ -296,26 +396,125 @@ $cmd->stderr_like(qr{can't parse address 127\.0\.0\.1:.*(not supported|not known)}); } -# fping -g (CIDR - no IPv6 generator) +# fping -g (CIDR - IPv6) SKIP: { if($ENV{SKIP_IPV6}) { skip 'Skip IPv6 tests', 3; } my $cmd = Test::Command->new(cmd => "fping -g ::1/128"); + $cmd->exit_is_num(0); + $cmd->stdout_is_eq("::1 is alive\n"); + $cmd->stderr_is_eq(""); +} + +# fping -6 -g (CIDR - IPv6) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -6 -g ::1/128"); + $cmd->exit_is_num(0); + $cmd->stdout_is_eq("::1 is alive\n"); + $cmd->stderr_is_eq(""); +} + +# fping -g (CIDR - scoped IPv6) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 1; + } + my $cmd = Test::Command->new(cmd => "fping -t10 -r0 -g fe80::4:3:2:1%2/128"); + $cmd->stdout_like(qr{fe80::4:3:2:1%2 is (alive|unreachable)\n}); +} + +# fping -g (CIDR - scoped IPv6 - wrong syntax) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -t10 -r0 -g fe80::4:3:2:1/128%2"); $cmd->exit_is_num(1); $cmd->stdout_is_eq(""); - $cmd->stderr_is_eq("fping: -g works only with IPv4 addresses\n"); + $cmd->stderr_is_eq("fping: address scope must precede prefix length\n"); } -# fping -6 -g (CIDR - no IPv6 generator) +# fping -g (CIDR - IPv6 - unreachable documentation addresses - host prefix) SKIP: { if($ENV{SKIP_IPV6}) { skip 'Skip IPv6 tests', 3; } - my $cmd = Test::Command->new(cmd => "fping -6 -g ::1/128"); + my $cmd = Test::Command->new(cmd => "fping -t10 -r0 -g 2001:db8:abcd:1234:5678:9098:7654:4321/128"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq("2001:db8:abcd:1234:5678:9098:7654:4321 is unreachable\n"); + $cmd->stderr_is_eq(""); +} + +# fping -g (CIDR - IPv6 - unreachable documentation addresses - point-to-point prefix) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -t10 -r0 -g 2001:db8:abcd:1234:5678:9098:7654:4320/127"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq("2001:db8:abcd:1234:5678:9098:7654:4320 is unreachable\n2001:db8:abcd:1234:5678:9098:7654:4321 is unreachable\n"); + $cmd->stderr_is_eq(""); +} + +# fping -g (CIDR - IPv6 - unreachable documentation addresses - normal prefix) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -t10 -i1 -r0 -g 2001:db8:abcd:1234:5678:9098:7654:4320/126"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq("2001:db8:abcd:1234:5678:9098:7654:4321 is unreachable +2001:db8:abcd:1234:5678:9098:7654:4322 is unreachable +2001:db8:abcd:1234:5678:9098:7654:4323 is unreachable\n"); + $cmd->stderr_is_eq(""); +} + +# fping -g (CIDR - IPv6 - prefix too short) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -g 2001:db8::/64"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq(""); + $cmd->stderr_is_eq("fping: netmask must be between 65 and 128 (is: 64)\n"); +} + +# fping -g (CIDR - IPv6 - too many addresses) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -g 2001:db8::/65"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq(""); + $cmd->stderr_is_eq("fping: -g parameter generates too many addresses\n"); +} + +# fping -g (CIDR - IPv6 - too many addresses) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -g 2001:db8::/104"); + $cmd->exit_is_num(1); + $cmd->stdout_is_eq(""); + $cmd->stderr_is_eq("fping: -g parameter generates too many addresses\n"); +} + +# fping -g (CIDR - IPv6 - prefix too long) +SKIP: { + if($ENV{SKIP_IPV6}) { + skip 'Skip IPv6 tests', 3; + } + my $cmd = Test::Command->new(cmd => "fping -g 2001:db8::/129"); $cmd->exit_is_num(1); $cmd->stdout_is_eq(""); - $cmd->stderr_is_eq("fping: -g works only with IPv4 addresses\n"); + $cmd->stderr_is_eq("fping: netmask must be between 65 and 128 (is: 129)\n"); } # fping -H diff --git a/ci/test-issue-58.pl b/ci/test-issue-58.pl index db5161a..3eacfc5 100755 --- a/ci/test-issue-58.pl +++ b/ci/test-issue-58.pl @@ -7,4 +7,4 @@ my $cmd1 = Test::Command->new(cmd => "fping -a -g 2001:db8:120:4161::4/64"); $cmd1->exit_is_num(1); $cmd1->stdout_is_eq(""); -$cmd1->stderr_is_eq("fping: -g works only with IPv4 addresses\n"); +$cmd1->stderr_is_eq("fping: netmask must be between 65 and 128 (is: 64)\n"); diff --git a/doc/fping.pod b/doc/fping.pod index 7709225..0fb630e 100644 --- a/doc/fping.pod +++ b/doc/fping.pod @@ -122,9 +122,12 @@ Read list of targets from a file. Generate a target list from a supplied IP netmask, or a starting and ending IP. Specify the netmask or start/end in the targets portion of the command line. If -a network with netmask is given, the network and broadcast addresses will be -excluded. ex. To ping the network 192.168.1.0/24, the specified command line -could look like either: +an IPv4 network with netmask is given, the network and broadcast addresses will +be excluded. If an IPv6 network with netmask is given, the Subnet-Router anycast +address will be excluded. + +Example: To ping the network 192.168.1.0/24, the specified command line could +look like either: $ fping -g 192.168.1.0/24 @@ -322,8 +325,8 @@ line arguments, and 4 for a system call failure. =head1 RESTRICTIONS The number of addresses that can be generated using the C<-g>, C<--generate> -option is limited to 131070 (the number of host addresses in one 15-bit IPv4 -prefix). +option is limited to 131071 (the number of host addresses in one 111-bit IPv6 +prefix, one address more than the host addresses in one 15-bit IPv4 prefix). If fping was configured with C<--enable-safe-limits>, the following values are not allowed for non-root users: diff --git a/src/fping.c b/src/fping.c index 470d3b9..0633a52 100644 --- a/src/fping.c +++ b/src/fping.c @@ -139,7 +139,7 @@ extern int h_errno; #define SIZE_ICMP_HDR 8 /* from ip_icmp.h */ #define MAX_PING_DATA (MAX_IP_PACKET - SIZE_IP_HDR - SIZE_ICMP_HDR) -#define MAX_GENERATE 131070 /* maximum number of hosts that -g can generate */ +#define MAX_GENERATE 131071 /* maximum number of hosts that -g can generate */ /* sized so as to be like traditional ping */ #define DEFAULT_PING_DATA_SIZE 56 @@ -404,6 +404,12 @@ void add_cidr(char *); void add_cidr_ipv4(unsigned long, unsigned long); void add_range(char *, char *); void add_addr_range_ipv4(unsigned long, unsigned long); +#ifdef IPV6 +uint64_t be_octets_to_uint64(uint8_t*); +void uint64_to_be_octets(uint64_t, uint8_t*); +void add_cidr_ipv6(uint64_t, uint64_t, unsigned long, const char *); +void add_addr_range_ipv6(uint64_t, uint64_t, uint64_t, uint64_t, const char *); +#endif void print_warning(char *fmt, ...); int addr_cmp(struct sockaddr *a, struct sockaddr *b); void host_add_ping_event(HOST_ENTRY *h, int index, int64_t ev_time); @@ -1294,17 +1300,31 @@ void add_cidr(char *addr) struct addrinfo addr_hints; struct addrinfo *addr_res; unsigned long net_addr; +#ifdef IPV6 + uint64_t net_upper, net_lower; + char *scope_str; +#endif /* IPV6 */ /* Split address from mask */ - addr_end = strchr(addr, '/'); + addr_end = strrchr(addr, '/'); if (addr_end == NULL) { usage(1); } - *addr_end = '\0'; mask_str = addr_end + 1; + +#ifdef IPV6 + /* IPv6 addresses can have a scope */ + scope_str = strchr(addr, '%'); + if (scope_str && mask_str < scope_str) { + fprintf(stderr, "%s: address scope must precede prefix length\n", prog); + exit(1); + } +#endif /*IPV6 */ + + *addr_end = '\0'; mask = atoi(mask_str); - /* parse address (IPv4 only) */ + /* parse address */ memset(&addr_hints, 0, sizeof(struct addrinfo)); addr_hints.ai_family = hints_ai_family; addr_hints.ai_flags = AI_NUMERICHOST; @@ -1317,9 +1337,17 @@ void add_cidr(char *addr) net_addr = ntohl(((struct sockaddr_in*)addr_res->ai_addr)->sin_addr.s_addr); freeaddrinfo(addr_res); add_cidr_ipv4(net_addr, mask); +#ifdef IPV6 + } else if (addr_res->ai_family == AF_INET6) { + uint8_t *ipv6_addr = ((struct sockaddr_in6*)addr_res->ai_addr)->sin6_addr.s6_addr; + net_upper = be_octets_to_uint64(ipv6_addr); + net_lower = be_octets_to_uint64(ipv6_addr + 8); + freeaddrinfo(addr_res); + add_cidr_ipv6(net_upper, net_lower, mask, scope_str); +#endif /* IPV6 */ } else { freeaddrinfo(addr_res); - fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog); + fprintf(stderr, "%s: -g does not support this address family\n", prog); exit(1); } } @@ -1352,6 +1380,34 @@ void add_cidr_ipv4(unsigned long net_addr, unsigned long mask) add_addr_range_ipv4(net_addr, net_last); } +#ifdef IPV6 +void add_cidr_ipv6(uint64_t net_upper, uint64_t net_lower, unsigned long mask, const char *scope_str) +{ + uint64_t bitmask_lower; + uint64_t last_lower; + + /* check mask -- 2^63 addresses should suffice for now */ + if (mask < 65 || mask > 128) { + fprintf(stderr, "%s: netmask must be between 65 and 128 (is: %lu)\n", prog, mask); + exit(1); + } + + /* convert mask integer from 65 to 128 to the lower part of a bitmask */ + bitmask_lower = ((uint64_t)-1) << (128 - mask); + + /* calculate network range */ + net_lower &= bitmask_lower; + last_lower = net_lower + ((uint64_t)1 << (128 - mask)) - 1; + + /* exclude Subnet-Router anycast address */ + if (mask < 127) { + net_lower++; + } + + add_addr_range_ipv6(net_upper, net_lower, net_upper, last_lower, scope_str); +} +#endif /* IPV6 */ + void add_range(char *start, char *end) { struct addrinfo addr_hints; @@ -1359,8 +1415,27 @@ void add_range(char *start, char *end) unsigned long start_long; unsigned long end_long; int ret; - - /* parse start address (IPv4 only) */ +#ifdef IPV6 + uint64_t start_upper, start_lower; + uint64_t end_upper, end_lower; + char *start_scope_str, *end_scope_str; + + /* + * The compiler does not know that setting the address family hint to + * ensure that start and end are from the same address family also + * ensures that either start_long and end_long are initialized and used, + * or start_upper, start_lower, end_upper, and end_lower are initialized + * and used. Thus initialize all variables when both IPv4 and IPv6 are + * supported to suppress compiler warnings. + */ + start_long = -1; + end_long = 0; + start_upper = start_lower = -1; + end_upper = end_lower = 0; + start_scope_str = end_scope_str = NULL; +#endif /* IPV6 */ + + /* parse start address */ memset(&addr_hints, 0, sizeof(struct addrinfo)); addr_hints.ai_family = hints_ai_family; addr_hints.ai_flags = AI_NUMERICHOST; @@ -1374,13 +1449,32 @@ void add_range(char *start, char *end) if (addr_res->ai_family == AF_INET) { start_long = ntohl(((struct sockaddr_in*)addr_res->ai_addr)->sin_addr.s_addr); freeaddrinfo(addr_res); +#ifdef IPV6 + } else if (addr_res->ai_family == AF_INET6) { + uint8_t *ipv6_addr = ((struct sockaddr_in6*)addr_res->ai_addr)->sin6_addr.s6_addr; + start_upper = be_octets_to_uint64(ipv6_addr); + start_lower = be_octets_to_uint64(ipv6_addr + 8); + freeaddrinfo(addr_res); +#endif /* IPV6 */ } else { freeaddrinfo(addr_res); - fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog); + fprintf(stderr, "%s: -g does not support this address family\n", prog); exit(1); } - /* parse end address (IPv4 only) */ + /* IPv6 addresses can have a scope */ + if (hints_ai_family == AF_INET6) { + start_scope_str = strchr(start, '%'); + end_scope_str = strchr(end, '%'); + if ((!start_scope_str && end_scope_str) || + (start_scope_str && !end_scope_str) || + (start_scope_str && end_scope_str && strcmp(start_scope_str, end_scope_str) != 0)) { + fprintf(stderr, "%s: different scopes for start and end addresses\n", prog); + exit(1); + } + } + + /* parse end address */ memset(&addr_hints, 0, sizeof(struct addrinfo)); addr_hints.ai_family = hints_ai_family; addr_hints.ai_flags = AI_NUMERICHOST; @@ -1393,9 +1487,17 @@ void add_range(char *start, char *end) end_long = ntohl(((struct sockaddr_in*)addr_res->ai_addr)->sin_addr.s_addr); freeaddrinfo(addr_res); add_addr_range_ipv4(start_long, end_long); +#ifdef IPV6 + } else if (addr_res->ai_family == AF_INET6) { + uint8_t *ipv6_addr = ((struct sockaddr_in6*)addr_res->ai_addr)->sin6_addr.s6_addr; + end_upper = be_octets_to_uint64(ipv6_addr); + end_lower = be_octets_to_uint64(ipv6_addr + 8); + freeaddrinfo(addr_res); + add_addr_range_ipv6(start_upper, start_lower, end_upper, end_lower, start_scope_str); +#endif /* IPV6 */ } else { freeaddrinfo(addr_res); - fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog); + fprintf(stderr, "%s: -g does not support this address family\n", prog); exit(1); } } @@ -1418,6 +1520,63 @@ void add_addr_range_ipv4(unsigned long start_long, unsigned long end_long) } } +#ifdef IPV6 +uint64_t be_octets_to_uint64(uint8_t *be_octets) +{ + int i; + uint64_t ret = 0; + for (i = 0; i < 8; i++) { + ret |= (uint64_t)be_octets[7 - i] << (i * 8); + } + return ret; +} + +void uint64_to_be_octets(uint64_t num, uint8_t *be_octets) +{ + int i; + for (i = 0; i < 8; i++) { + be_octets[7 - i] = (uint8_t)((num >> (i * 8)) & 0xff); + } +} + +void add_addr_range_ipv6(uint64_t start_upper, uint64_t start_lower, + uint64_t end_upper, uint64_t end_lower, + const char *scope_str) +{ + struct in6_addr in6_addr_tmp; + char buffer[100]; + + /* prevent generating too many addresses */ + if ((start_upper + 1 < end_upper) || + (start_upper + 1 == end_upper && end_lower >= start_lower) || + (start_upper + 1 == end_upper && end_lower - MAX_GENERATE >= start_lower) || + (start_upper == end_upper && end_lower - MAX_GENERATE >= start_lower && + start_lower + MAX_GENERATE <= end_lower)) { + fprintf(stderr, "%s: -g parameter generates too many addresses\n", prog); + exit(1); + } + + while ((start_upper < end_upper) || + (start_upper == end_upper && start_lower <= end_lower)) { + uint64_to_be_octets(start_upper, in6_addr_tmp.s6_addr); + uint64_to_be_octets(start_lower, in6_addr_tmp.s6_addr + 8); + inet_ntop(AF_INET6, &in6_addr_tmp, buffer, sizeof(buffer)); + if (scope_str) { + if (strlen(buffer) + strlen(scope_str) + 1 > sizeof(buffer)) { + fprintf(stderr, "%s: scope identifier is too long\n", prog); + exit(1); + } + strncat(buffer, scope_str, sizeof(buffer) - strlen(buffer) - 1); + } + add_name(buffer); + start_lower++; + if (start_lower == 0) { + start_upper++; + } + } +} +#endif /* IPv6 */ + void main_loop() { int64_t lt;