X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fliboping.c;h=65b2ef529dd81cff07b7948f2d8f47eeb76e76c1;hb=11970f14b437d4f8f62040f5913ecc4d5f4fbb53;hp=c64060c0ba2ad7ef27bd1e30a13c43e2ef88e616;hpb=cee84ecd1462a7756ca5a10568ce269775cbe84e;p=liboping.git diff --git a/src/liboping.c b/src/liboping.c index c64060c..65b2ef5 100644 --- a/src/liboping.c +++ b/src/liboping.c @@ -112,6 +112,7 @@ struct pinghost struct timeval *timer; double latency; uint32_t dropped; + int recv_ttl; char *data; void *context; @@ -126,7 +127,7 @@ struct pingobj int addrfamily; char *data; - struct sockaddr_storage *srcaddr; + struct sockaddr *srcaddr; socklen_t srcaddrlen; char errmsg[PING_ERRMSG_LEN]; @@ -187,8 +188,7 @@ static void ping_set_error (pingobj_t *obj, const char *function, obj->errmsg[sizeof (obj->errmsg) - 1] = 0; } -static void ping_set_errno (pingobj_t *obj, const char *function, - int error_number) +static void ping_set_errno (pingobj_t *obj, int error_number) { sstrerror (error_number, obj->errmsg, sizeof (obj->errmsg)); } @@ -423,21 +423,40 @@ static pinghost_t *ping_receive_ipv6 (pinghost_t *ph, char *buffer, size_t buffe static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now) { - char buffer[4096]; - ssize_t buffer_len; - struct timeval diff; - pinghost_t *host = NULL; - - struct sockaddr_storage sa; - socklen_t sa_len; - - sa_len = sizeof (sa); - - buffer_len = recvfrom (fd, buffer, sizeof (buffer), 0, - (struct sockaddr *) &sa, &sa_len); - if (buffer_len < 0) + int family; + int recv_ttl; + + /* + * Set up the receive buffer.. + */ + struct msghdr msghdr; + struct cmsghdr *cmsg; + char payload_buffer[4096]; + ssize_t payload_buffer_len; + char control_buffer[4096]; + struct iovec payload_iovec; + + memset (&payload_iovec, 0, sizeof (payload_iovec)); + payload_iovec.iov_base = payload_buffer; + payload_iovec.iov_len = sizeof (payload_buffer); + + memset (&msghdr, 0, sizeof (msghdr)); + /* unspecified source address */ + msghdr.msg_name = NULL; + msghdr.msg_namelen = 0; + /* output buffer vector, see readv(2) */ + msghdr.msg_iov = &payload_iovec; + msghdr.msg_iovlen = 1; + /* output buffer for control messages */ + msghdr.msg_control = control_buffer; + msghdr.msg_controllen = sizeof (control_buffer); + /* flags; this is an output only field.. */ + msghdr.msg_flags = 0; + + payload_buffer_len = recvmsg (fd, &msghdr, /* flags = */ 0); + if (payload_buffer_len < 0) { #if WITH_DEBUG char errbuf[PING_ERRMSG_LEN]; @@ -446,19 +465,71 @@ static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now) #endif return (-1); } + dprintf ("Read %zi bytes from fd = %i\n", payload_buffer_len, fd); + + /* Iterate over all auxiliary data in msghdr */ + family = -1; + recv_ttl = -1; + for (cmsg = CMSG_FIRSTHDR (&msghdr); /* {{{ */ + cmsg != NULL; + cmsg = CMSG_NXTHDR (&msghdr, cmsg)) + { + if (cmsg->cmsg_level == IPPROTO_IP) /* {{{ */ + { + family = AF_INET; + if (cmsg->cmsg_type == IP_TTL) + { + memcpy (&recv_ttl, CMSG_DATA (cmsg), + sizeof (recv_ttl)); + dprintf ("TTLv4 = %i;\n", recv_ttl); + } + else + { + dprintf ("Not handling option %i.\n", + cmsg->cmsg_type); + } + } /* }}} */ + else if (cmsg->cmsg_level == IPPROTO_IPV6) /* {{{ */ + { + family = AF_INET6; + if (cmsg->cmsg_type == IPV6_HOPLIMIT) + { + memcpy (&recv_ttl, CMSG_DATA (cmsg), + sizeof (recv_ttl)); + dprintf ("TTLv6 = %i;\n", recv_ttl); + } + else + { + dprintf ("Not handling option %i.\n", + cmsg->cmsg_type); + } + } /* }}} */ + else + { + dprintf ("Don't know how to handle " + "unknown protocol %i.\n", + cmsg->cmsg_level); + } + } /* }}} for (cmsg) */ - dprintf ("Read %zi bytes from fd = %i\n", buffer_len, fd); - - if (sa.ss_family == AF_INET) + if (family == AF_INET) { - if ((host = ping_receive_ipv4 (ph, buffer, buffer_len)) == NULL) + host = ping_receive_ipv4 (ph, payload_buffer, payload_buffer_len); + if (host == NULL) return (-1); } - else if (sa.ss_family == AF_INET6) + else if (family == AF_INET6) { - if ((host = ping_receive_ipv6 (ph, buffer, buffer_len)) == NULL) + host = ping_receive_ipv6 (ph, payload_buffer, payload_buffer_len); + if (host == NULL) return (-1); } + else + { + dprintf ("ping_receive_one: Unknown address family %i.\n", + family); + return (-1); + } dprintf ("rcvd: %12i.%06i\n", (int) now->tv_sec, @@ -480,6 +551,8 @@ static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now) host->latency = ((double) diff.tv_usec) / 1000.0; host->latency += ((double) diff.tv_sec) * 1000.0; + host->recv_ttl = recv_ttl; + timerclear (host->timer); return (0); @@ -509,7 +582,7 @@ static int ping_receive_all (pingobj_t *obj) if (gettimeofday (&nowtime, NULL) == -1) { - ping_set_errno (obj, "gettimeofday", errno); + ping_set_errno (obj, errno); return (-1); } @@ -546,7 +619,7 @@ static int ping_receive_all (pingobj_t *obj) if (gettimeofday (&nowtime, NULL) == -1) { - ping_set_errno (obj, "gettimeofday", errno); + ping_set_errno (obj, errno); return (-1); } @@ -561,7 +634,7 @@ static int ping_receive_all (pingobj_t *obj) if (gettimeofday (&nowtime, NULL) == -1) { - ping_set_errno (obj, "gettimeofday", errno); + ping_set_errno (obj, errno); return (-1); } @@ -630,7 +703,7 @@ static ssize_t ping_sendto (pingobj_t *obj, pinghost_t *ph, if (errno == ENETUNREACH) return (0); #endif - ping_set_errno (obj, "sendto", errno); + ping_set_errno (obj, errno); } return (ret); @@ -799,11 +872,15 @@ static int ping_set_ttl (pinghost_t *ph, int ttl) if (ph->addrfamily == AF_INET) { - ret = setsockopt (ph->fd, IPPROTO_IP, IP_TTL, &ttl, sizeof (ttl)); + dprintf ("Setting TTLv4 to %i\n", ttl); + ret = setsockopt (ph->fd, IPPROTO_IP, IP_TTL, + &ttl, sizeof (ttl)); } else if (ph->addrfamily == AF_INET6) { - ret = setsockopt (ph->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof (ttl)); + dprintf ("Setting TTLv6 to %i\n", ttl); + ret = setsockopt (ph->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, + &ttl, sizeof (ttl)); } return (ret); @@ -1032,16 +1109,16 @@ int ping_setopt (pingobj_t *obj, int option, void *value) if (obj->srcaddr == NULL) { obj->srcaddrlen = 0; - obj->srcaddr = (struct sockaddr_storage *) malloc (sizeof (struct sockaddr_storage)); + obj->srcaddr = malloc (sizeof (struct sockaddr_storage)); if (obj->srcaddr == NULL) { - ping_set_errno (obj, "malloc", errno); + ping_set_errno (obj, errno); ret = -1; freeaddrinfo (ai_list); break; } } - memset ((void *) obj->srcaddr, '\0', sizeof (struct sockaddr_storage)); + 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); @@ -1090,9 +1167,6 @@ int ping_host_add (pingobj_t *obj, const char *host) { pinghost_t *ph; - struct sockaddr_storage sockaddr; - socklen_t sockaddr_len; - struct addrinfo ai_hints; struct addrinfo *ai_list, *ai_ptr; int ai_return; @@ -1122,7 +1196,7 @@ int ping_host_add (pingobj_t *obj, const char *host) if ((ph->username = strdup (host)) == NULL) { dprintf ("Out of memory!\n"); - ping_set_errno (obj, "strdup", errno); + ping_set_errno (obj, errno); ping_free (ph); return (-1); } @@ -1130,7 +1204,7 @@ int ping_host_add (pingobj_t *obj, const char *host) if ((ph->hostname = strdup (host)) == NULL) { dprintf ("Out of memory!\n"); - ping_set_errno (obj, "strdup", errno); + ping_set_errno (obj, errno); ping_free (ph); return (-1); } @@ -1139,7 +1213,7 @@ int ping_host_add (pingobj_t *obj, const char *host) if ((ph->data = strdup (obj->data == NULL ? PING_DEF_DATA : obj->data)) == NULL) { dprintf ("Out of memory!\n"); - ping_set_errno (obj, "strdup", errno); + ping_set_errno (obj, errno); ping_free (ph); return (-1); } @@ -1167,30 +1241,13 @@ int ping_host_add (pingobj_t *obj, const char *host) { ph->fd = -1; - sockaddr_len = sizeof (sockaddr); - memset (&sockaddr, '\0', sockaddr_len); - if (ai_ptr->ai_family == AF_INET) { - struct sockaddr_in *si; - - si = (struct sockaddr_in *) &sockaddr; - si->sin_family = AF_INET; - si->sin_port = htons (ph->ident); - si->sin_addr.s_addr = htonl (INADDR_ANY); - ai_ptr->ai_socktype = SOCK_RAW; ai_ptr->ai_protocol = IPPROTO_ICMP; } else if (ai_ptr->ai_family == AF_INET6) { - struct sockaddr_in6 *si; - - si = (struct sockaddr_in6 *) &sockaddr; - si->sin6_family = AF_INET6; - si->sin6_port = htons (ph->ident); - si->sin6_addr = in6addr_any; - ai_ptr->ai_socktype = SOCK_RAW; ai_ptr->ai_protocol = IPPROTO_ICMPV6; } @@ -1216,7 +1273,7 @@ int ping_host_add (pingobj_t *obj, const char *host) dprintf ("socket: %s\n", sstrerror (errno, errbuf, sizeof (errbuf))); #endif - ping_set_errno (obj, "socket", errno); + ping_set_errno (obj, errno); continue; } @@ -1225,14 +1282,14 @@ int ping_host_add (pingobj_t *obj, const char *host) assert (obj->srcaddrlen > 0); assert (obj->srcaddrlen <= sizeof (struct sockaddr_storage)); - if (bind (ph->fd, (struct sockaddr *) obj->srcaddr, obj->srcaddrlen) == -1) + if (bind (ph->fd, obj->srcaddr, obj->srcaddrlen) == -1) { #if WITH_DEBUG char errbuf[PING_ERRMSG_LEN]; dprintf ("bind: %s\n", sstrerror (errno, errbuf, sizeof (errbuf))); #endif - ping_set_errno (obj, "bind", errno); + ping_set_errno (obj, errno); close (ph->fd); ph->fd = -1; continue; @@ -1267,6 +1324,21 @@ int ping_host_add (pingobj_t *obj, const char *host) } #endif /* AI_CANONNAME */ + if (ph->addrfamily == AF_INET) + { + int opt = 1; + + setsockopt (ph->fd, IPPROTO_IP, IP_RECVTTL, + &opt, sizeof (opt)); + } + else if (ph->addrfamily == AF_INET6) + { + int opt = 1; + + setsockopt (ph->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, + &opt, sizeof (opt)); + } + break; } @@ -1302,7 +1374,7 @@ int ping_host_add (pingobj_t *obj, const char *host) ping_set_ttl (ph, obj->ttl); return (0); -} +} /* int ping_host_add */ int ping_host_remove (pingobj_t *obj, const char *host) { @@ -1456,6 +1528,15 @@ int ping_iterator_get_info (pingobj_iter_t *iter, int info, strncpy ((char *) buffer, iter->data, orig_buffer_len); ret = 0; break; + + case PING_INFO_RECV_TTL: + ret = ENOMEM; + *buffer_len = sizeof (int); + if (orig_buffer_len < sizeof (int)) + break; + *((int *) buffer) = iter->recv_ttl; + ret = 0; + break; } return (ret);