From b516c73b71d82f4174c3c9c46c45035ec17da413 Mon Sep 17 00:00:00 2001
From: Erik Auerswald <auerswal@unix-ag.uni-kl.de>
Date: Sun, 1 May 2022 11:50:12 +0200
Subject: [PATCH 3/8] refactor IPv4 address generation and limit CIDR

Both functions add_cidr() and add_range() end with the same code.
Extract this code into a new function add_addr_range_ipv4() and
use it.  Additionally, move the check to limit the number of
generated addresses to a compile time constant (MAX_GENERATE+1)
into the new function.

This is a change in "fping -g" behavior, because now both forms
of invoking the address generator use the MAX_GENERATE+1 limit.
Before, only "fping -g START END" would use this limit, but
"fping -g CIDR" would not.

Add a test to check if the MAX_GENERATE+1 limit is applied when
using "fping -g CIDR".
---
 ci/test-06-options-f-h.pl | 10 +++++++++-
 doc/fping.pod             |  3 +++
 src/fping.c               | 15 +++++++--------
 3 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/ci/test-06-options-f-h.pl b/ci/test-06-options-f-h.pl
index 4f26b9e..2bfde36 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 => 45;
+use Test::Command tests => 48;
 use File::Temp;
 
 #  -f file    read list of targets from a file ( - means stdin) (only if no -g specified)
@@ -124,6 +124,14 @@ $cmd->stdout_is_eq("");
 $cmd->stderr_is_eq("fping: netmask must be between 1 and 32 (is: 0)\n");
 }
 
+# fping -g (cidr - too many addresses)
+{
+my $cmd = Test::Command->new(cmd => "fping -g 127.0.0.2/8");
+$cmd->exit_is_num(1);
+$cmd->stdout_is_eq("");
+$cmd->stderr_is_eq("fping: -g parameter generates too many addresses\n");
+}
+
 # fping -H
 {
 my $cmd = Test::Command->new(cmd => "fping -H 1 127.0.0.1");
diff --git a/doc/fping.pod b/doc/fping.pod
index 7702df1..45fc101 100644
--- a/doc/fping.pod
+++ b/doc/fping.pod
@@ -273,6 +273,9 @@ 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 a compile-time constant.
+
 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 af44a6c..2e69f2b 100644
--- a/src/fping.c
+++ b/src/fping.c
@@ -388,6 +388,7 @@ struct event *ev_dequeue(struct event_queue *queue);
 void ev_remove(struct event_queue *queue, struct event *event);
 void add_cidr(char*);
 void add_range(char*, char*);
+void add_addr_range_ipv4(unsigned long, unsigned long);
 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);
@@ -1227,14 +1228,7 @@ void add_cidr(char* addr)
         net_addr++;
     }
 
-    /* add all hosts in that network (net_addr and net_last inclusive) */
-    for (; net_addr <= net_last; net_addr++) {
-        struct in_addr in_addr_tmp;
-        char buffer[20];
-        in_addr_tmp.s_addr = htonl(net_addr);
-        inet_ntop(AF_INET, &in_addr_tmp, buffer, sizeof(buffer));
-        add_name(buffer);
-    }
+    add_addr_range_ipv4(net_addr, net_last);
 }
 
 void add_range(char* start, char* end)
@@ -1278,6 +1272,11 @@ 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);
+}
+
+void add_addr_range_ipv4(unsigned long start_long, unsigned long end_long)
+{
     if (end_long > start_long + MAX_GENERATE) {
         fprintf(stderr, "%s: -g parameter generates too many addresses\n", prog);
         exit(1);
-- 
2.25.1

