diff options
Diffstat (limited to 'plugins-root/check_icmp.c')
-rw-r--r-- | plugins-root/check_icmp.c | 93 |
1 files changed, 75 insertions, 18 deletions
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 8b563e40..9ed12ba1 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c @@ -184,7 +184,7 @@ static u_int get_timevar(const char *); static u_int get_timevaldiff(struct timeval *, struct timeval *); static in_addr_t get_ip_address(const char *); static int wait_for_reply(int, u_int); -static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *); +static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *, struct timeval*); static int send_icmp_ping(int, struct rta_host *); static int get_threshold(char *str, threshold *th); static void run_checks(void); @@ -378,6 +378,9 @@ main(int argc, char **argv) int icmp_sockerrno, udp_sockerrno, tcp_sockerrno; int result; struct rta_host *host; +#ifdef SO_TIMESTAMP + int on = 1; +#endif setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); @@ -402,6 +405,11 @@ main(int argc, char **argv) /* now drop privileges (no effect if not setsuid or geteuid() == 0) */ setuid(getuid()); +#ifdef SO_TIMESTAMP + if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) + if(debug) printf("Warning: no SO_TIMESTAMP support\n"); +#endif // SO_TIMESTAMP + /* POSIXLY_CORRECT might break things, so unset it (the portable way) */ environ = NULL; @@ -462,13 +470,13 @@ main(int argc, char **argv) /* parse the arguments */ for(i = 1; i < argc; i++) { while((arg = getopt(argc, argv, "vhVw:c:n:p:t:H:s:i:b:I:l:m:")) != EOF) { - long size; + unsigned short size; switch(arg) { case 'v': debug++; break; case 'b': - size = strtol(optarg,NULL,0); + size = (unsigned short)strtol(optarg,NULL,0); if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) && size < MAX_PING_DATA) { icmp_data_size = size; @@ -518,10 +526,10 @@ main(int argc, char **argv) break; case 'V': /* version */ print_revision (progname, NP_VERSION); - exit (STATE_OK); + exit (STATE_UNKNOWN); case 'h': /* help */ print_help (); - exit (STATE_OK); + exit (STATE_UNKNOWN); } } } @@ -727,7 +735,7 @@ wait_for_reply(int sock, u_int t) /* reap responses until we hit a timeout */ n = recvfrom_wto(sock, buf, sizeof(buf), - (struct sockaddr *)&resp_addr, &t); + (struct sockaddr *)&resp_addr, &t, &now); if(!n) { if(debug > 1) { printf("recvfrom_wto() timed out during a %u usecs wait\n", @@ -777,11 +785,11 @@ wait_for_reply(int sock, u_int t) /* this is indeed a valid response */ memcpy(&data, icp.icmp_data, sizeof(data)); if (debug > 2) - printf("ICMP echo-reply of len %u, id %u, seq %u, cksum 0x%X\n", - sizeof(data), ntohs(icp.icmp_id), ntohs(icp.icmp_seq), icp.icmp_cksum); + printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", + (unsigned long)sizeof(data), ntohs(icp.icmp_id), + ntohs(icp.icmp_seq), icp.icmp_cksum); host = table[ntohs(icp.icmp_seq)/packets]; - gettimeofday(&now, &tz); tdiff = get_timevaldiff(&data.stime, &now); host->time_waited += tdiff; @@ -823,6 +831,8 @@ send_icmp_ping(int sock, struct rta_host *host) } packet = { NULL }; long int len; struct icmp_ping_data data; + struct msghdr hdr; + struct iovec iov; struct timeval tv; struct sockaddr *addr; @@ -855,11 +865,27 @@ send_icmp_ping(int sock, struct rta_host *host) packet.icp->icmp_cksum = icmp_checksum(packet.cksum_in, icmp_pkt_size); if (debug > 2) - printf("Sending ICMP echo-request of len %u, id %u, seq %u, cksum 0x%X to host %s\n", - sizeof(data), ntohs(packet.icp->icmp_id), ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum, host->name); - - len = sendto(sock, packet.buf, icmp_pkt_size, 0, (struct sockaddr *)addr, - sizeof(struct sockaddr)); + printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", + (unsigned long)sizeof(data), ntohs(packet.icp->icmp_id), + ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum, + host->name); + + memset(&iov, 0, sizeof(iov)); + iov.iov_base = packet.buf; + iov.iov_len = icmp_pkt_size; + + memset(&hdr, 0, sizeof(hdr)); + hdr.msg_name = addr; + hdr.msg_namelen = sizeof(struct sockaddr); + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + +/* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */ +#ifdef MSG_CONFIRM + len = sendmsg(sock, &hdr, MSG_CONFIRM); +#else + len = sendmsg(sock, &hdr, 0); +#endif if(len < 0 || (unsigned int)len != icmp_pkt_size) { if(debug) printf("Failed to send ping to %s\n", @@ -875,12 +901,18 @@ send_icmp_ping(int sock, struct rta_host *host) static int recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, - u_int *timo) + u_int *timo, struct timeval* tv) { u_int slen; - int n; + int n, ret; struct timeval to, then, now; fd_set rd, wr; + char ans_data[4096]; + struct msghdr hdr; + struct iovec iov; +#ifdef SO_TIMESTAMP + struct cmsghdr* chdr; +#endif if(!*timo) { if(debug) printf("*timo is not\n"); @@ -904,7 +936,32 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, slen = sizeof(struct sockaddr); - return recvfrom(sock, buf, len, 0, saddr, &slen); + memset(&iov, 0, sizeof(iov)); + iov.iov_base = buf; + iov.iov_len = len; + + memset(&hdr, 0, sizeof(hdr)); + hdr.msg_name = saddr; + hdr.msg_namelen = slen; + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + hdr.msg_control = ans_data; + hdr.msg_controllen = sizeof(ans_data); + + ret = recvmsg(sock, &hdr, 0); +#ifdef SO_TIMESTAMP + for(chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) { + if(chdr->cmsg_level == SOL_SOCKET + && chdr->cmsg_type == SO_TIMESTAMP + && chdr->cmsg_len >= CMSG_LEN(sizeof(struct timeval))) { + memcpy(tv, CMSG_DATA(chdr), sizeof(*tv)); + break ; + } + } + if (!chdr) +#endif // SO_TIMESTAMP + gettimeofday(tv, &tz); + return (ret); } static void @@ -1183,7 +1240,7 @@ static u_int get_timevar(const char *str) { char p, u, *ptr; - unsigned int len; + size_t len; u_int i, d; /* integer and decimal, respectively */ u_int factor = 1000; /* default to milliseconds */ |