From 9d80f880eef4d3138f1bc1c084fdf4814c9003e1 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 29 May 2020 11:39:40 +0200 Subject: [PATCH 1/2] Add option to ping all target addresses (v4+v6) returned by DNS. This renames the ping_host_add() function to ping_host_add_multi() and adds an extra argument to it, specifying how many addresses to add from what getaddrinfo() returns. ping_host_add() is now a small wrapper that calls "ping_host_add_multi()" with "max = 1" to get the previous behaviour. The callers (oping/noping) default to "max = 1" unless a new option, "-a" is specified. In that case, all IPv4+IPv6 addresses returned by getaddrinfo() are added (-4 / -6 restricts this to "all IPv4 / IPv6 addresses", respectively). Technically, the change is fairly straightforward: ping_host_add() (now ping_host_add_multi()): - new argument "max_hosts" - move the allocation of "ph" to inside the "for (ai_ptr...)" loop - move adding of the found object to the "obj->" chain inside the loop - do not exit the loop until "enough" hosts have been found (or the list of results is exhausted) - return the number of hosts added (0..N) the callers need to be adjusted to learn the number added, because otherwise the graphical display in "noping" does not get extra lines. Signed-off-by: Gert Doering --- src/liboping.c | 127 +++++++++++++++++++++---------------- src/mans/ping_host_add.pod | 16 ++++- src/oping.c | 17 +++-- src/oping.h | 1 + 4 files changed, 99 insertions(+), 62 deletions(-) diff --git a/src/liboping.c b/src/liboping.c index bf9e059..efed2c1 100644 --- a/src/liboping.c +++ b/src/liboping.c @@ -1550,13 +1550,23 @@ static pinghost_t *ping_host_search (pinghost_t *ph, const char *host) return (ph); } +/* wrapper around ping_host_add_multi() to preserve existing + * calling / return convention + */ int ping_host_add (pingobj_t *obj, const char *host) +{ + int n = ping_host_add_multi( obj, host, 1 ); + return n < 0 ? n: 0; +} + +int ping_host_add_multi (pingobj_t *obj, const char *host, int max_hosts) { pinghost_t *ph; struct addrinfo ai_hints; struct addrinfo *ai_list, *ai_ptr; int ai_return; + int hosts_added = 0; if ((obj == NULL) || (host == NULL)) return (-1); @@ -1577,37 +1587,6 @@ int ping_host_add (pingobj_t *obj, const char *host) ai_hints.ai_family = obj->addrfamily; ai_hints.ai_socktype = SOCK_RAW; - if ((ph = ping_alloc ()) == NULL) - { - dprintf ("Out of memory!\n"); - return (-1); - } - - if ((ph->username = strdup (host)) == NULL) - { - dprintf ("Out of memory!\n"); - ping_set_errno (obj, errno); - ping_free (ph); - return (-1); - } - - if ((ph->hostname = strdup (host)) == NULL) - { - dprintf ("Out of memory!\n"); - ping_set_errno (obj, errno); - ping_free (ph); - return (-1); - } - - /* obj->data is not garuanteed to be != NULL */ - if ((ph->data = strdup (obj->data == NULL ? PING_DEF_DATA : obj->data)) == NULL) - { - dprintf ("Out of memory!\n"); - ping_set_errno (obj, errno); - ping_free (ph); - return (-1); - } - if ((ai_return = getaddrinfo (host, NULL, &ai_hints, &ai_list)) != 0) { #if defined(EAI_SYSTEM) @@ -1620,7 +1599,6 @@ int ping_host_add (pingobj_t *obj, const char *host) ? sstrerror (errno, errbuf, sizeof (errbuf)) : #endif gai_strerror (ai_return)); - ping_free (ph); return (-1); } @@ -1629,6 +1607,29 @@ int ping_host_add (pingobj_t *obj, const char *host) for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) { + if ((ph = ping_alloc ()) == NULL) + { + dprintf ("Out of memory!\n"); + return (-1); + } + + if ((ph->username = strdup (host)) == NULL) + { + dprintf ("Out of memory!\n"); + ping_set_errno (obj, errno); + ping_free (ph); + return (-1); + } + + /* obj->data is not garuanteed to be != NULL */ + if ((ph->data = strdup (obj->data == NULL ? PING_DEF_DATA : obj->data)) == NULL) + { + dprintf ("Out of memory!\n"); + ping_set_errno (obj, errno); + ping_free (ph); + return (-1); + } + if (ai_ptr->ai_family == AF_INET) { ai_ptr->ai_socktype = SOCK_RAW; @@ -1648,9 +1649,18 @@ int ping_host_add (pingobj_t *obj, const char *host) dprintf ("%s", errmsg); ping_set_error (obj, "getaddrinfo", errmsg); + ping_free (ph); continue; } + if ((ph->hostname = strdup (host)) == NULL) + { + dprintf ("Out of memory!\n"); + ping_set_errno (obj, errno); + ping_free (ph); + return (-1); + } + assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen); memset (ph->addr, '\0', sizeof (struct sockaddr_storage)); memcpy (ph->addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen); @@ -1678,35 +1688,42 @@ int ping_host_add (pingobj_t *obj, const char *host) } } #endif /* AI_CANONNAME */ - } /* for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) */ - freeaddrinfo (ai_list); + /* + * Adding in the front is much easier, but then the iterator will + * return the host that was added last as first host. That's just not + * nice. -octo + */ + if (obj->head == NULL) + { + obj->head = ph; + } + else + { + pinghost_t *hptr; - /* - * Adding in the front is much easier, but then the iterator will - * return the host that was added last as first host. That's just not - * nice. -octo - */ - if (obj->head == NULL) - { - obj->head = ph; - } - else - { - pinghost_t *hptr; + hptr = obj->head; + while (hptr->next != NULL) + hptr = hptr->next; - hptr = obj->head; - while (hptr->next != NULL) - hptr = hptr->next; + assert ((hptr != NULL) && (hptr->next == NULL)); + hptr->next = ph; + } - assert ((hptr != NULL) && (hptr->next == NULL)); - hptr->next = ph; - } + ph->table_next = obj->table[ph->ident % PING_TABLE_LEN]; + obj->table[ph->ident % PING_TABLE_LEN] = ph; + hosts_added++; - ph->table_next = obj->table[ph->ident % PING_TABLE_LEN]; - obj->table[ph->ident % PING_TABLE_LEN] = ph; + if ( max_hosts > 0 && hosts_added >= max_hosts ) + { + break; + } - return (0); + } /* for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) */ + + freeaddrinfo (ai_list); + + return (hosts_added); } /* int ping_host_add */ int ping_host_remove (pingobj_t *obj, const char *host) diff --git a/src/mans/ping_host_add.pod b/src/mans/ping_host_add.pod index f874771..3a3f44a 100644 --- a/src/mans/ping_host_add.pod +++ b/src/mans/ping_host_add.pod @@ -6,8 +6,9 @@ ping_host_add - Add a host to a liboping object #include - int ping_host_add (pingobj_t *obj, const char *host); - int ping_host_remove (pingobj_t *obj, const char *host); + int ping_host_add (pingobj_t *obj, const char *host); + int ping_host_add_multi (pingobj_t *obj, const char *host, int max_hosts); + int ping_host_remove (pingobj_t *obj, const char *host); =head1 DESCRIPTION @@ -21,6 +22,13 @@ The I parameter is a '\0' terminated string which is interpreted as a hostname or an IP address. Depending on the address family setting, set with L, the hostname is resolved to an IPv4 or IPv6 address. +If more than one result is returned by DNS, only the first result is used. + +The B extends the B function to +permit adding up to I DNS results (IPv4 and IPv6, or multiple +IPv4 / IPv6 records) to the liboping object. If I is 0, there +is no limit = add all records returned by DNS. + The B method looks for I within I and remove it if found. It will close the socket and deallocate the memory, too. @@ -33,6 +41,10 @@ If B succeeds it returns zero. If an error occurs a value less than zero is returned and the last error is saved internally. You can receive the error message using L. +If B succeeds it returns the number of hosts added. If +an error occurs a value less than zero is returned and the last error is +saved internally. You can receive the error message using L. + B returns zero upon success and less than zero if it failed. Currently the only reason for failure is that the host isn't found, but this is subject to change. Use L to receive the error message. diff --git a/src/oping.c b/src/oping.c index c087c80..683a1b2 100644 --- a/src/oping.c +++ b/src/oping.c @@ -220,6 +220,7 @@ static int opt_utf8 = 0; #endif static char *opt_outfile = NULL; static int opt_bell = 0; +static int opt_max_hosts = 1; static int host_num = 0; static FILE *outfile = NULL; @@ -682,7 +683,7 @@ static int read_options (int argc, char **argv) /* {{{ */ while (1) { - optchar = getopt (argc, argv, "46c:hi:I:t:Q:f:D:Z:O:P:m:w:b" + optchar = getopt (argc, argv, "46c:hi:I:t:Q:f:D:Z:O:P:m:w:ba" #if USE_NCURSES "uUg:H:" #endif @@ -855,6 +856,10 @@ static int read_options (int argc, char **argv) /* {{{ */ break; } + case 'a': + opt_max_hosts = -1; /* all */ + break; + case 'h': usage_exit (argv[0], 0); break; @@ -1944,7 +1949,8 @@ int main (int argc, char **argv) /* {{{ */ if ((host[0] == 0) || (host[0] == '#')) continue; - if (ping_host_add(ping, host) < 0) + int n = ping_host_add_multi(ping, host, opt_max_hosts); + if (n < 0) { const char *errmsg = ping_get_error (ping); @@ -1953,7 +1959,7 @@ int main (int argc, char **argv) /* {{{ */ } else { - host_num++; + host_num+=n; } } @@ -1984,7 +1990,8 @@ int main (int argc, char **argv) /* {{{ */ for (i = optind; i < argc; i++) { - if (ping_host_add (ping, argv[i]) < 0) + int n = ping_host_add_multi (ping, argv[i], opt_max_hosts); + if (n < 0) { const char *errmsg = ping_get_error (ping); @@ -1993,7 +2000,7 @@ int main (int argc, char **argv) /* {{{ */ } else { - host_num++; + host_num+=n; } } diff --git a/src/oping.h b/src/oping.h index ff144e8..2ed8630 100644 --- a/src/oping.h +++ b/src/oping.h @@ -71,6 +71,7 @@ int ping_setopt (pingobj_t *obj, int option, void *value); int ping_send (pingobj_t *obj); int ping_host_add (pingobj_t *obj, const char *host); +int ping_host_add_multi (pingobj_t *obj, const char *host, int max_hosts); int ping_host_remove (pingobj_t *obj, const char *host); pingobj_iter_t *ping_iterator_get (pingobj_t *obj); From 2164f89ebbeddceba98b514923024c1b09c98c53 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 29 May 2020 11:57:10 +0200 Subject: [PATCH 2/2] Attach /v4 or /v6 to visible hostnames. With the "multiping" patch, you end up seeing a hostname multiple times in the "noping" graphical display, and it's not easy to see right away whether the IPv4 or IPv6 address has loss. So, extend hostnames with "/v4" or "/v6" to make this visible. No option to turn this on or off has been implemented so far, but it could be made dependant on "-4"/"-6" (no suffix needed) or on an extra option. Signed-off-by: Gert Doering --- src/liboping.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/liboping.c b/src/liboping.c index efed2c1..1d44571 100644 --- a/src/liboping.c +++ b/src/liboping.c @@ -1630,15 +1630,18 @@ int ping_host_add_multi (pingobj_t *obj, const char *host, int max_hosts) return (-1); } + char * afi_str = NULL; if (ai_ptr->ai_family == AF_INET) { ai_ptr->ai_socktype = SOCK_RAW; ai_ptr->ai_protocol = IPPROTO_ICMP; + afi_str = "v4"; } else if (ai_ptr->ai_family == AF_INET6) { ai_ptr->ai_socktype = SOCK_RAW; ai_ptr->ai_protocol = IPPROTO_ICMPV6; + afi_str = "v6"; } else { @@ -1653,13 +1656,14 @@ int ping_host_add_multi (pingobj_t *obj, const char *host, int max_hosts) continue; } - if ((ph->hostname = strdup (host)) == NULL) + if ((ph->hostname = malloc ( strlen(host)+4) ) == NULL) { dprintf ("Out of memory!\n"); ping_set_errno (obj, errno); ping_free (ph); return (-1); } + sprintf( ph->hostname, "%s/%s", host, afi_str ); assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen); memset (ph->addr, '\0', sizeof (struct sockaddr_storage)); @@ -1677,13 +1681,15 @@ int ping_host_add_multi (pingobj_t *obj, const char *host, int max_hosts) ph->hostname, ai_ptr->ai_canonname); old_hostname = ph->hostname; - if ((ph->hostname = strdup (ai_ptr->ai_canonname)) == NULL) + if ((ph->hostname = malloc( strlen(ai_ptr->ai_canonname)+4 )) == NULL) { /* strdup failed, falling back to old hostname */ ph->hostname = old_hostname; } - else if (old_hostname != NULL) + else { + sprintf( ph->hostname, "%s/%s", + ai_ptr->ai_canonname, afi_str ); free (old_hostname); } }