X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fliboping.c;h=22ab3a8672167b4d53248c4b92b9646ab82c05ee;hb=4c83ef784bdc0d14fd2b1c20853b678ccc4e18ee;hp=6131107a03509c320168e0c36d9cffd0edcc2fff;hpb=a7dd6052cd081f88e8a5defe9f72df5e1c155f0d;p=liboping.git diff --git a/src/liboping.c b/src/liboping.c index 6131107..22ab3a8 100644 --- a/src/liboping.c +++ b/src/liboping.c @@ -1,11 +1,11 @@ /** * Object oriented C module to send ICMP and ICMPv6 `echo's. - * Copyright (C) 2006 Florian octo Forster + * Copyright (C) 2006-2008 Florian octo Forster * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation; only version 2 of the License is + * applicable. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -97,6 +97,9 @@ struct pinghost { + /* username: name passed in by the user */ + char *username; + /* hostname: name returned by the reverse lookup */ char *hostname; struct sockaddr_storage *addr; socklen_t addrlen; @@ -115,14 +118,17 @@ struct pinghost struct pingobj { - double timeout; - int ttl; - int addrfamily; - char *data; + double timeout; + int ttl; + int addrfamily; + char *data; + + struct sockaddr_storage *srcaddr; + socklen_t srcaddrlen; - char errmsg[PING_ERRMSG_LEN]; + char errmsg[PING_ERRMSG_LEN]; - pinghost_t *head; + pinghost_t *head; }; /* @@ -285,6 +291,22 @@ static pinghost_t *ping_receive_ipv4 (pinghost_t *ph, char *buffer, size_t buffe return (ptr); } +#ifndef ICMP6_ECHO_REQUEST +# ifdef ICMP6_ECHO /* AIX netinet/ip6_icmp.h */ +# define ICMP6_ECHO_REQUEST ICMP6_ECHO +# else +# define ICMP6_ECHO_REQUEST 128 +# endif +#endif + +#ifndef ICMP6_ECHO_REPLY +# ifdef ICMP6_ECHOREPLY /* AIX netinet/ip6_icmp.h */ +# define ICMP6_ECHO_REPLY ICMP6_ECHOREPLY +# else +# define ICMP6_ECHO_REPLY 129 +# endif +#endif + static pinghost_t *ping_receive_ipv6 (pinghost_t *ph, char *buffer, size_t buffer_len) { struct icmp6_hdr *icmp_hdr; @@ -537,7 +559,17 @@ static ssize_t ping_sendto (pingobj_t *obj, pinghost_t *ph, (struct sockaddr *) ph->addr, ph->addrlen); if (ret < 0) + { +#if defined(EHOSTUNREACH) + if (errno == EHOSTUNREACH) + return (0); +#endif +#if defined(ENETUNREACH) + if (errno == ENETUNREACH) + return (0); +#endif ping_set_error (obj, "sendto", strerror (errno)); + } return (ret); } @@ -765,6 +797,7 @@ static pinghost_t *ping_alloc (void) ph->addr = (struct sockaddr_storage *) (ph->timer + 1); ph->addrlen = sizeof (struct sockaddr_storage); + ph->fd = -1; ph->latency = -1.0; ph->ident = ping_get_ident () & 0xFFFF; @@ -773,6 +806,12 @@ static pinghost_t *ping_alloc (void) static void ping_free (pinghost_t *ph) { + if (ph->fd >= 0) + close (ph->fd); + + if (ph->username != NULL) + free (ph->username); + if (ph->hostname != NULL) free (ph->hostname); @@ -824,6 +863,9 @@ void ping_destroy (pingobj_t *obj) if (obj->data != NULL) free (obj->data); + if (obj->srcaddr != NULL) + free (obj->srcaddr); + free (obj); return; @@ -862,6 +904,11 @@ int ping_setopt (pingobj_t *obj, int option, void *value) obj->addrfamily = PING_DEF_AF; ret = -1; } + if (obj->srcaddr != NULL) + { + free (obj->srcaddr); + obj->srcaddr = NULL; + } break; case PING_OPT_DATA: @@ -873,6 +920,65 @@ int ping_setopt (pingobj_t *obj, int option, void *value) obj->data = strdup ((const char *) value); break; + case PING_OPT_SOURCE: + { + char *hostname = (char *) value; + struct addrinfo ai_hints; + struct addrinfo *ai_list; + int status; +#if WITH_DEBUG + if (obj->addrfamily != AF_UNSPEC) + { + dprintf ("Resetting obj->addrfamily to AF_UNSPEC.\n"); + } +#endif + memset ((void *) &ai_hints, '\0', sizeof (ai_hints)); + ai_hints.ai_family = obj->addrfamily = AF_UNSPEC; +#if defined(AI_ADDRCONFIG) + ai_hints.ai_flags = AI_ADDRCONFIG; +#endif + status = getaddrinfo (hostname, NULL, &ai_hints, &ai_list); + if (status != 0) + { + ping_set_error (obj, "getaddrinfo", +#if defined(EAI_SYSTEM) + (status == EAI_SYSTEM) + ? strerror (errno) : +#endif + gai_strerror (status)); + ret = -1; + break; + } +#if WITH_DEBUG + if (ai_list->ai_next != NULL) + { + dprintf ("hostname = `%s' is ambiguous.\n", hostname); + } +#endif + if (obj->srcaddr == NULL) + { + obj->srcaddrlen = 0; + obj->srcaddr = (struct sockaddr_storage *) malloc (sizeof (struct sockaddr_storage)); + if (obj->srcaddr == NULL) + { + ping_set_error (obj, "malloc", + strerror (errno)); + ret = -1; + freeaddrinfo (ai_list); + break; + } + } + memset ((void *) obj->srcaddr, '\0', sizeof (struct sockaddr_storage)); + assert (ai_list->ai_addrlen <= sizeof (struct sockaddr_storage)); + memcpy ((void *) obj->srcaddr, (const void *) ai_list->ai_addr, + ai_list->ai_addrlen); + obj->srcaddrlen = ai_list->ai_addrlen; + obj->addrfamily = ai_list->ai_family; + + freeaddrinfo (ai_list); + } /* case PING_OPT_SOURCE */ + break; + default: ret = -2; } /* switch (option) */ @@ -898,7 +1004,7 @@ static pinghost_t *ping_host_search (pinghost_t *ph, const char *host) { while (ph != NULL) { - if (strcasecmp (ph->hostname, host) == 0) + if (strcasecmp (ph->username, host) == 0) break; ph = ph->next; @@ -940,6 +1046,14 @@ int ping_host_add (pingobj_t *obj, const char *host) return (-1); } + if ((ph->username = strdup (host)) == NULL) + { + dprintf ("Out of memory!\n"); + ping_set_error (obj, "strdup", strerror (errno)); + ping_free (ph); + return (-1); + } + if ((ph->hostname = strdup (host)) == NULL) { dprintf ("Out of memory!\n"); @@ -961,9 +1075,11 @@ int ping_host_add (pingobj_t *obj, const char *host) { dprintf ("getaddrinfo failed\n"); ping_set_error (obj, "getaddrinfo", - (ai_return == EAI_SYSTEM) - ? strerror (errno) - : gai_strerror (ai_return)); +#if defined(EAI_SYSTEM) + (ai_return == EAI_SYSTEM) + ? strerror (errno) : +#endif + gai_strerror (ai_return)); ping_free (ph); return (-1); } @@ -1024,21 +1140,20 @@ int ping_host_add (pingobj_t *obj, const char *host) continue; } -/* - * The majority vote of operating systems has decided that you don't need to - * bind here. This code should be reactivated to bind to a specific address, - * though. See the `-I' option of `ping(1)' (GNU). -octo - */ -#if 0 - if (bind (ph->fd, (struct sockaddr *) &sockaddr, sockaddr_len) == -1) + if (obj->srcaddr != NULL) { - dprintf ("bind: %s\n", strerror (errno)); - ping_set_error (obj, "bind", strerror (errno)); - close (ph->fd); - ph->fd = -1; - continue; + assert (obj->srcaddrlen > 0); + assert (obj->srcaddrlen <= sizeof (struct sockaddr_storage)); + + if (bind (ph->fd, (struct sockaddr *) obj->srcaddr, obj->srcaddrlen) == -1) + { + dprintf ("bind: %s\n", strerror (errno)); + ping_set_error (obj, "bind", strerror (errno)); + close (ph->fd); + ph->fd = -1; + continue; + } } -#endif assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen); memset (ph->addr, '\0', sizeof (struct sockaddr_storage)); @@ -1075,8 +1190,7 @@ int ping_host_add (pingobj_t *obj, const char *host) if (ph->fd < 0) { - free (ph->hostname); - free (ph); + ping_free (ph); return (-1); } @@ -1115,7 +1229,7 @@ int ping_host_remove (pingobj_t *obj, const char *host) while (cur != NULL) { - if (strcasecmp (host, cur->hostname)) + if (strcasecmp (host, cur->username) == 0) break; pre = cur; @@ -1133,9 +1247,6 @@ int ping_host_remove (pingobj_t *obj, const char *host) else pre->next = cur->next; - if (cur->fd >= 0) - close (cur->fd); - ping_free (cur); return (0); @@ -1160,9 +1271,21 @@ int ping_iterator_get_info (pingobj_iter_t *iter, int info, switch (info) { + case PING_INFO_USERNAME: + ret = ENOMEM; + *buffer_len = strlen (iter->username) + 1; + if (orig_buffer_len <= *buffer_len) + break; + /* Since (orig_buffer_len > *buffer_len) `strncpy' + * will copy `*buffer_len' and pad the rest of + * `buffer' with null-bytes */ + strncpy (buffer, iter->username, orig_buffer_len); + ret = 0; + break; + case PING_INFO_HOSTNAME: ret = ENOMEM; - *buffer_len = strlen (iter->hostname); + *buffer_len = strlen (iter->hostname) + 1; if (orig_buffer_len <= *buffer_len) break; /* Since (orig_buffer_len > *buffer_len) `strncpy' @@ -1187,9 +1310,10 @@ int ping_iterator_get_info (pingobj_iter_t *iter, int info, #endif ) ret = ENOMEM; +#if defined(EAI_SYSTEM) else if (ret == EAI_SYSTEM) - /* XXX: Not thread-safe! */ ret = errno; +#endif else ret = EINVAL; }