X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=plugins-root%2Fcheck_icmp.c;h=2a1b8133757521c83473143bddf0bb052a3d0ddd;hb=9c1aa029c088d6d52c7978198136731925c5f385;hp=2f03552f948538faf0c4ee067520251e8b6c0778;hpb=be7702b4bfa996c8228c3463d57e0449328a461c;p=nagiosplug.git diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c index 2f03552..2a1b813 100644 --- a/plugins-root/check_icmp.c +++ b/plugins-root/check_icmp.c @@ -1,21 +1,56 @@ -/* - * $Id$ - * - * Author: Andreas Ericsson - * - * License: GNU GPL 2.0 or any later version. - * - * Relevant RFC's: 792 (ICMP), 791 (IP) - * - * This program was modeled somewhat after the check_icmp program, - * which was in turn a hack of fping (www.fping.org) but has been - * completely rewritten since to generate higher precision rta values, - * and support several different modes as well as setting ttl to control. - * redundant routes. The only remainders of fping is currently a few - * function names. - * - */ - +/***************************************************************************** +* +* Nagios check_icmp plugin +* +* License: GPL +* Copyright (c) 2005-2008 Nagios Plugins Development Team +* Original Author : Andreas Ericsson +* +* Description: +* +* This file contains the check_icmp plugin +* +* Relevant RFC's: 792 (ICMP), 791 (IP) +* +* This program was modeled somewhat after the check_icmp program, +* which was in turn a hack of fping (www.fping.org) but has been +* completely rewritten since to generate higher precision rta values, +* and support several different modes as well as setting ttl to control. +* redundant routes. The only remainders of fping is currently a few +* function names. +* +* +* 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 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* +*****************************************************************************/ + +/* progname may change */ +/* char *progname = "check_icmp"; */ +char *progname; +const char *copyright = "2005-2008"; +const char *email = "nagiosplug-devel@lists.sourceforge.net"; + +/** nagios plugins basic includes */ +#include "common.h" +#include "netutils.h" +#include "utils.h" + +#if HAVE_SYS_SOCKIO_H +#include +#endif +#include #include #include #include @@ -28,19 +63,22 @@ #include #include #include +#include #include #include #include #include #include #include +#include + /** sometimes undefined system macros (quite a few, actually) **/ #ifndef MAXTTL # define MAXTTL 255 #endif #ifndef INADDR_NONE -# define INADDR_NONE 0xffffffU +# define INADDR_NONE (in_addr_t)(-1) #endif #ifndef SOL_IP @@ -65,16 +103,9 @@ # define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 #endif - -/** typedefs and such **/ -enum states { - STATE_OK = 0, - STATE_WARNING, - STATE_CRITICAL, - STATE_UNKNOWN, - STATE_DEPENDENT, - STATE_OOB -}; +#ifndef DBL_MAX +# define DBL_MAX 9.9999999999e999 +#endif typedef unsigned short range_t; /* type for get_range() -- unimplemented */ @@ -89,6 +120,8 @@ typedef struct rta_host { unsigned char icmp_type, icmp_code; /* type and code from errors */ unsigned short flags; /* control/status flags */ double rta; /* measured RTA */ + double rtmax; /* max rtt */ + double rtmin; /* min rtt */ unsigned char pl; /* measured packet loss */ struct rta_host *next; /* linked list */ } rta_host; @@ -145,17 +178,20 @@ typedef struct icmp_ping_data { #define TSTATE_UNREACH 0x08 /** prototypes **/ -static void usage(unsigned char, char *); +void print_help (void); +void print_usage (void); 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, char *, unsigned int, struct sockaddr *, u_int *); +static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *); static int send_icmp_ping(int, struct rta_host *); static int get_threshold(char *str, threshold *th); static void run_checks(void); +static void set_source_ip(char *); static int add_target(char *); static int add_target_ip(char *, struct in_addr *); -static int handle_random_icmp(struct icmp *, struct sockaddr_in *); +static int handle_random_icmp(unsigned char *, struct sockaddr_in *); static unsigned short icmp_checksum(unsigned short *, int); static void finish(int); static void crash(const char *, ...); @@ -166,11 +202,12 @@ extern char *optarg; extern char **environ; /** global variables **/ -static char *progname; static struct rta_host **table, *cursor, *list; static threshold crit = {80, 500000}, warn = {40, 200000}; static int mode, protocols, sockets, debug = 0, timeout = 10; -static unsigned short icmp_pkt_size, icmp_data_size = DEFAULT_PING_DATA_SIZE; +static unsigned short icmp_data_size = DEFAULT_PING_DATA_SIZE; +static unsigned short icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN; + static unsigned int icmp_sent = 0, icmp_recv = 0, icmp_lost = 0; #define icmp_pkts_en_route (icmp_sent - (icmp_recv + icmp_lost)) static unsigned short targets_down = 0, targets = 0, packets = 0; @@ -183,6 +220,7 @@ static struct timeval prog_start; static unsigned long long max_completion_time = 0; static unsigned char ttl = 0; /* outgoing ttl */ static unsigned int warn_down = 1, crit_down = 1; /* host down threshold values */ +static int min_hosts_alive = -1; float pkt_backoff_factor = 1.5; float target_backoff_factor = 1.5; @@ -205,10 +243,10 @@ crash(const char *fmt, ...) } -static char * +static const char * get_icmp_error_msg(unsigned char icmp_type, unsigned char icmp_code) { - char *msg = "unreachable"; + const char *msg = "unreachable"; if(debug > 1) printf("get_icmp_error_msg(%u, %u)\n", icmp_type, icmp_code); switch(icmp_type) { @@ -262,19 +300,18 @@ get_icmp_error_msg(unsigned char icmp_type, unsigned char icmp_code) } static int -handle_random_icmp(struct icmp *p, struct sockaddr_in *addr) +handle_random_icmp(unsigned char *packet, struct sockaddr_in *addr) { - struct icmp *sent_icmp = NULL; + struct icmp p, sent_icmp; struct rta_host *host = NULL; - unsigned char *ptr; - if(p->icmp_type == ICMP_ECHO && p->icmp_id == pid) { + memcpy(&p, packet, sizeof(p)); + if(p.icmp_type == ICMP_ECHO && ntohs(p.icmp_id) == pid) { /* echo request from us to us (pinging localhost) */ return 0; } - ptr = (unsigned char *)p; - if(debug) printf("handle_random_icmp(%p, %p)\n", (void *)p, (void *)addr); + if(debug) printf("handle_random_icmp(%p, %p)\n", (void *)&p, (void *)addr); /* only handle a few types, since others can't possibly be replies to * us in a sane network (if it is anyway, it will be counted as lost @@ -286,27 +323,27 @@ handle_random_icmp(struct icmp *p, struct sockaddr_in *addr) * TIMXCEED actually sends a proper icmp response we will have passed * too many hops to have a hope of reaching it later, in which case it * indicates overconfidence in the network, poor routing or both. */ - if(p->icmp_type != ICMP_UNREACH && p->icmp_type != ICMP_TIMXCEED && - p->icmp_type != ICMP_SOURCEQUENCH && p->icmp_type != ICMP_PARAMPROB) + if(p.icmp_type != ICMP_UNREACH && p.icmp_type != ICMP_TIMXCEED && + p.icmp_type != ICMP_SOURCEQUENCH && p.icmp_type != ICMP_PARAMPROB) { return 0; } /* might be for us. At least it holds the original package (according * to RFC 792). If it isn't, just ignore it */ - sent_icmp = (struct icmp *)(ptr + 28); - if(sent_icmp->icmp_type != ICMP_ECHO || sent_icmp->icmp_id != pid || - sent_icmp->icmp_seq >= targets) + memcpy(&sent_icmp, packet + 28, sizeof(sent_icmp)); + if(sent_icmp.icmp_type != ICMP_ECHO || ntohs(sent_icmp.icmp_id) != pid || + ntohs(sent_icmp.icmp_seq) >= targets*packets) { if(debug) printf("Packet is no response to a packet we sent\n"); return 0; } /* it is indeed a response for us */ - host = table[sent_icmp->icmp_seq]; + host = table[ntohs(sent_icmp.icmp_seq)/packets]; if(debug) { printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n", - get_icmp_error_msg(p->icmp_type, p->icmp_code), + get_icmp_error_msg(p.icmp_type, p.icmp_code), inet_ntoa(addr->sin_addr), host->name); } @@ -317,7 +354,7 @@ handle_random_icmp(struct icmp *p, struct sockaddr_in *addr) /* source quench means we're sending too fast, so increase the * interval and mark this packet lost */ - if(p->icmp_type == ICMP_SOURCEQUENCH) { + if(p.icmp_type == ICMP_SOURCEQUENCH) { pkt_interval *= pkt_backoff_factor; target_interval *= target_backoff_factor; } @@ -325,8 +362,8 @@ handle_random_icmp(struct icmp *p, struct sockaddr_in *addr) targets_down++; host->flags |= FLAG_LOST_CAUSE; } - host->icmp_type = p->icmp_type; - host->icmp_code = p->icmp_code; + host->icmp_type = p.icmp_type; + host->icmp_code = p.icmp_code; host->error_addr.s_addr = addr->sin_addr.s_addr; return 0; @@ -341,7 +378,14 @@ main(int argc, char **argv) int icmp_sockerrno, udp_sockerrno, tcp_sockerrno; int result; struct rta_host *host; - + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + /* print a helpful error message if geteuid != 0 */ + np_warn_if_not_root(); + /* we only need to be setsuid when we get the sockets, so do * that before pointer magic (esp. on network data) */ icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0; @@ -365,7 +409,8 @@ main(int argc, char **argv) environ = NULL; /* use the pid to mark packets as ours */ - pid = getpid(); + /* Some systems have 32-bit pid_t so mask off only 16 bits */ + pid = getpid() & 0xffff; /* printf("pid = %u\n", pid); */ /* get calling name the old-fashioned way for portability instead @@ -406,15 +451,28 @@ main(int argc, char **argv) packets = 5; } + /* Parse extra opts if any */ + argv=np_extra_opts(&argc, argv, progname); + /* parse the arguments */ for(i = 1; i < argc; i++) { - while((arg = getopt(argc, argv, "vhVw:c:n:p:t:H:i:b:I:l:")) != EOF) { + while((arg = getopt(argc, argv, "vhVw:c:n:p:t:H:s:i:b:I:l:m:")) != EOF) { + long size; switch(arg) { case 'v': debug++; break; case 'b': - /* silently ignored for now */ + size = strtol(optarg,NULL,0); + if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) && + size < MAX_PING_DATA) { + icmp_data_size = size; + icmp_pkt_size = size + ICMP_MINLEN; + } else + usage_va("ICMP data length must be between: %d and %d", + sizeof(struct icmp) + sizeof(struct icmp_ping_data), + MAX_PING_DATA - 1); + break; case 'i': pkt_interval = get_timevar(optarg); @@ -442,15 +500,24 @@ main(int argc, char **argv) case 'l': ttl = (unsigned char)strtoul(optarg, NULL, 0); break; + case 'm': + min_hosts_alive = (int)strtoul(optarg, NULL, 0); + break; case 'd': /* implement later, for cluster checks */ warn_down = (unsigned char)strtoul(optarg, &ptr, 0); if(ptr) { crit_down = (unsigned char)strtoul(ptr + 1, NULL, 0); } break; - case 'h': case 'V': default: - usage(arg, NULL); + case 's': /* specify source IP address */ + set_source_ip(optarg); break; + case 'V': /* version */ + print_revision (progname, NP_VERSION); + exit (STATE_OK); + case 'h': /* help */ + print_help (); + exit (STATE_OK); } } } @@ -534,13 +601,6 @@ main(int argc, char **argv) } } - icmp_pkt_size = icmp_data_size + ICMP_MINLEN; - if(debug > 2) printf("icmp_pkt_size = %u\n", icmp_pkt_size); - if(icmp_pkt_size < sizeof(struct icmp) + sizeof(struct icmp_ping_data)) { - icmp_pkt_size = sizeof(struct icmp) + sizeof(struct icmp_ping_data); - } - if(debug > 2) printf("icmp_pkt_size = %u\n", icmp_pkt_size); - if(debug) { printf("crit = {%u, %u%%}, warn = {%u, %u%%}\n", crit.rta, crit.pl, warn.rta, warn.pl); @@ -555,11 +615,16 @@ main(int argc, char **argv) crash("packets is > 20 (%d)", packets); } + if(min_hosts_alive < -1) { + errno = 0; + crash("minimum alive hosts is negative (%i)", min_hosts_alive); + } + host = list; table = malloc(sizeof(struct rta_host **) * (argc - 1)); i = 0; while(host) { - host->id = i; + host->id = i*packets; table[i] = host; host = host->next; i++; @@ -591,7 +656,7 @@ run_checks() table[t]->name); continue; } - + /* we're still in the game, so send next packet */ (void)send_icmp_ping(icmp_sock, table[t]); result = wait_for_reply(icmp_sock, target_interval); @@ -629,12 +694,12 @@ static int wait_for_reply(int sock, u_int t) { int n, hlen; - static char buf[4096]; + static unsigned char buf[4096]; struct sockaddr_in resp_addr; struct ip *ip; - struct icmp *icp, *sent_icmp; + struct icmp icp; struct rta_host *host; - struct icmp_ping_data *data; + struct icmp_ping_data data; struct timeval wait_start, now; u_int tdiff, i, per_pkt_wait; @@ -696,41 +761,37 @@ wait_for_reply(int sock, u_int t) /* } */ /* check the response */ - icp = (struct icmp *)(buf + hlen); - sent_icmp = (struct icmp *)(buf + hlen + ICMP_MINLEN); - /* printf("buf: %p, icp: %p, distance: %u (expected %u)\n", */ - /* buf, icp, */ - /* (u_int)icp - (u_int)buf, hlen); */ - /* printf("buf: %p, sent_icmp: %p, distance: %u (expected %u)\n", */ - /* buf, sent_icmp, */ - /* (u_int)sent_icmp - (u_int)buf, hlen + ICMP_MINLEN); */ - - if(icp->icmp_id != pid) { - handle_random_icmp(icp, &resp_addr); - continue; - } + memcpy(&icp, buf + hlen, sizeof(icp)); - if(icp->icmp_type != ICMP_ECHOREPLY || icp->icmp_seq >= targets) { + if(ntohs(icp.icmp_id) != pid || icp.icmp_type != ICMP_ECHOREPLY || + ntohs(icp.icmp_seq) >= targets*packets) { if(debug > 2) printf("not a proper ICMP_ECHOREPLY\n"); - handle_random_icmp(icp, &resp_addr); + handle_random_icmp(buf + hlen, &resp_addr); continue; } /* this is indeed a valid response */ - data = (struct icmp_ping_data *)(icp->icmp_data); + 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); - host = table[icp->icmp_seq]; + host = table[ntohs(icp.icmp_seq)/packets]; gettimeofday(&now, &tz); - tdiff = get_timevaldiff(&data->stime, &now); + tdiff = get_timevaldiff(&data.stime, &now); host->time_waited += tdiff; host->icmp_recv++; icmp_recv++; + if (tdiff > host->rtmax) + host->rtmax = tdiff; + if (tdiff < host->rtmin) + host->rtmin = tdiff; if(debug) { - printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u\n", + printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u, max: %0.3f, min: %0.3f\n", (float)tdiff / 1000, inet_ntoa(resp_addr.sin_addr), - ttl, ip->ip_ttl); + ttl, ip->ip_ttl, (float)host->rtmax / 1000, (float)host->rtmin / 1000); } /* if we're in hostcheck mode, exit with limited printouts */ @@ -751,14 +812,16 @@ wait_for_reply(int sock, u_int t) static int send_icmp_ping(int sock, struct rta_host *host) { - static char *buf = NULL; /* re-use so we prevent leaks */ + static union { + void *buf; /* re-use so we prevent leaks */ + struct icmp *icp; + u_short *cksum_in; + } packet = { NULL }; long int len; - struct icmp *icp; - struct icmp_ping_data *data; + struct icmp_ping_data data; struct timeval tv; struct sockaddr *addr; - if(sock == -1) { errno = 0; crash("Attempt to send on bogus socket"); @@ -766,30 +829,32 @@ send_icmp_ping(int sock, struct rta_host *host) } addr = (struct sockaddr *)&host->saddr_in; - if(!buf) { - buf = (char *)malloc(icmp_pkt_size + sizeof(struct ip)); - if(!buf) { + if(!packet.buf) { + if (!(packet.buf = malloc(icmp_pkt_size))) { crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size); return -1; /* might be reached if we're in debug mode */ } } - memset(buf, 0, icmp_pkt_size + sizeof(struct ip)); + memset(packet.buf, 0, icmp_pkt_size); if((gettimeofday(&tv, &tz)) == -1) return -1; - icp = (struct icmp *)buf; - icp->icmp_type = ICMP_ECHO; - icp->icmp_code = 0; - icp->icmp_cksum = 0; - icp->icmp_id = pid; - icp->icmp_seq = host->id; - data = (struct icmp_ping_data *)icp->icmp_data; - data->ping_id = 10; /* host->icmp.icmp_sent; */ - memcpy(&data->stime, &tv, sizeof(struct timeval)); - icp->icmp_cksum = icmp_checksum((u_short *)icp, icmp_pkt_size); - - len = sendto(sock, buf, icmp_pkt_size, 0, (struct sockaddr *)addr, + data.ping_id = 10; /* host->icmp.icmp_sent; */ + memcpy(&data.stime, &tv, sizeof(tv)); + memcpy(&packet.icp->icmp_data, &data, sizeof(data)); + packet.icp->icmp_type = ICMP_ECHO; + packet.icp->icmp_code = 0; + packet.icp->icmp_cksum = 0; + packet.icp->icmp_id = htons(pid); + packet.icp->icmp_seq = htons(host->id++); + 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)); if(len < 0 || (unsigned int)len != icmp_pkt_size) { @@ -805,7 +870,7 @@ send_icmp_ping(int sock, struct rta_host *host) } static int -recvfrom_wto(int sock, char *buf, unsigned int len, struct sockaddr *saddr, +recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, u_int *timo) { u_int slen; @@ -845,8 +910,10 @@ finish(int sig) unsigned char pl; double rta; struct rta_host *host; - char *status_string[] = + const char *status_string[] = {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"}; + int hosts_ok = 0; + int hosts_warn = 0; alarm(0); if(debug > 1) printf("finish(%d) called\n", sig); @@ -879,13 +946,25 @@ finish(int sig) } host->pl = pl; host->rta = rta; - if(!status && (pl >= warn.pl || rta >= warn.rta)) status = STATE_WARNING; - if(pl >= crit.pl || rta >= crit.rta) status = STATE_CRITICAL; + if(pl >= crit.pl || rta >= crit.rta) { + status = STATE_CRITICAL; + } + else if(!status && (pl >= warn.pl || rta >= warn.rta)) { + status = STATE_WARNING; + hosts_warn++; + } + else { + hosts_ok++; + } host = host->next; } /* this is inevitable */ if(!targets_alive) status = STATE_CRITICAL; + if(min_hosts_alive > -1) { + if(hosts_ok >= min_hosts_alive) status = STATE_OK; + else if((hosts_ok + hosts_warn) >= min_hosts_alive) status = STATE_WARNING; + } printf("%s - ", status_string[status]); host = list; @@ -923,19 +1002,25 @@ finish(int sig) host = list; while(host) { if(debug) puts(""); - printf("%srta=%0.3fms;%0.3f;%0.3f;0; %spl=%u%%;%u;%u;; ", + printf("%srta=%0.3fms;%0.3f;%0.3f;0; %spl=%u%%;%u;%u;; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ", (targets > 1) ? host->name : "", host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000, - (targets > 1) ? host->name : "", - host->pl, warn.pl, crit.pl); + (targets > 1) ? host->name : "", host->pl, warn.pl, crit.pl, + (targets > 1) ? host->name : "", (float)host->rtmax / 1000, + (targets > 1) ? host->name : "", (host->rtmin < DBL_MAX) ? (float)host->rtmin / 1000 : (float)0); host = host->next; } + if(min_hosts_alive > -1) { + if(hosts_ok >= min_hosts_alive) status = STATE_OK; + else if((hosts_ok + hosts_warn) >= min_hosts_alive) status = STATE_WARNING; + } + /* finish with an empty line */ puts(""); - if(debug) printf("targets: %u, targets_alive: %u\n", - targets, targets_alive); + if(debug) printf("targets: %u, targets_alive: %u, hosts_ok: %u, hosts_warn: %u, min_hosts_alive: %i\n", + targets, targets_alive, hosts_ok, hosts_warn, min_hosts_alive); exit(status); } @@ -953,7 +1038,7 @@ get_timevaldiff(struct timeval *early, struct timeval *later) if(!early) early = &prog_start; /* if early > later we return 0 so as to indicate a timeout */ - if(early->tv_sec > early->tv_sec || + if(early->tv_sec > later->tv_sec || (early->tv_sec == later->tv_sec && early->tv_usec > later->tv_usec)) { return 0; @@ -999,6 +1084,8 @@ add_target_ip(char *arg, struct in_addr *in) host->saddr_in.sin_family = AF_INET; host->saddr_in.sin_addr.s_addr = in->s_addr; + host->rtmin = DBL_MAX; + if(!list) list = cursor = host; else cursor->next = host; @@ -1040,7 +1127,7 @@ add_target(char *arg) /* this is silly, but it works */ if(mode == MODE_HOSTCHECK || mode == MODE_ALL) { - printf("mode: %d\n", mode); + if(debug > 2) printf("mode: %d\n", mode); continue; } break; @@ -1048,6 +1135,40 @@ add_target(char *arg) return 0; } + +static void +set_source_ip(char *arg) +{ + struct sockaddr_in src; + + memset(&src, 0, sizeof(src)); + src.sin_family = AF_INET; + if((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE) + src.sin_addr.s_addr = get_ip_address(arg); + if(bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1) + crash("Cannot bind to IP address %s", arg); +} + +/* TODO: Move this to netutils.c and also change check_dhcp to use that. */ +static in_addr_t +get_ip_address(const char *ifname) +{ +#if defined(SIOCGIFADDR) + struct ifreq ifr; + struct sockaddr_in ip; + + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); + ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; + if(ioctl(icmp_sock, SIOCGIFADDR, &ifr) == -1) + crash("Cannot determine IP address of interface %s", ifname); + memcpy(&ip, &ifr.ifr_addr, sizeof(ip)); + return ip.sin_addr.s_addr; +#else + errno = 0; + crash("Cannot get interface IP address on this platform."); +#endif +} + /* * u = micro * m = milli @@ -1147,53 +1268,86 @@ icmp_checksum(unsigned short *p, int n) return cksum; } -/* make core plugin developers happy (silly, really) */ -static void -usage(unsigned char arg, char *msg) +void +print_help(void) { - if(msg) printf("%s: %s\n", progname, msg); - if(arg == 'V') { - printf("$Id$\n"); - exit(STATE_UNKNOWN); - } + /*print_revision (progname);*/ /* FIXME: Why? */ + + printf ("Copyright (c) 2005 Andreas Ericsson \n"); + printf (COPYRIGHT, copyright, email); + + printf ("\n\n"); + + print_usage (); + + printf (_(UT_HELP_VRSN)); + printf (_(UT_EXTRA_OPTS)); + + printf (" %s\n", "-H"); + printf (" %s\n", _("specify a target")); + printf (" %s\n", "-w"); + printf (" %s", _("warning threshold (currently ")); + printf ("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl); + printf (" %s\n", "-c"); + printf (" %s", _("critical threshold (currently ")); + printf ("%0.3fms,%u%%)\n", (float)crit.rta / 1000, crit.pl); + printf (" %s\n", "-s"); + printf (" %s\n", _("specify a source IP address or device name")); + printf (" %s\n", "-n"); + printf (" %s", _("number of packets to send (currently ")); + printf ("%u)\n",packets); + printf (" %s\n", "-i"); + printf (" %s", _("max packet interval (currently ")); + printf ("%0.3fms)\n",(float)pkt_interval / 1000); + printf (" %s\n", "-I"); + printf (" %s", _("max target interval (currently ")); + printf ("%0.3fms)\n", (float)target_interval / 1000); + printf (" %s\n", "-m"); + printf (" %s",_("number of alive hosts required for success")); + printf ("\n"); + printf (" %s\n", "-l"); + printf (" %s", _("TTL on outgoing packets (currently ")); + printf ("%u)\n", ttl); + printf (" %s\n", "-t"); + printf (" %s",_("timeout value (seconds, currently ")); + printf ("%u)\n", timeout); + printf (" %s\n", "-b"); + printf (" %s\n", _("Number of icmp data bytes to send")); + printf (" %s %u + %d)\n", _("Packet size will be data bytes + icmp header (currently"),icmp_data_size, ICMP_MINLEN); + printf (" %s\n", "-v"); + printf (" %s\n", _("verbose")); + + printf ("\n"); + printf ("%s\n", _("Notes:")); + printf (" %s\n", _("The -H switch is optional. Naming a host (or several) to check is not.")); + printf ("\n"); + printf (" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%")); + printf (" %s\n", _("packet loss. The default values should work well for most users.")); + printf (" %s\n", _("You can specify different RTA factors using the standardized abbreviations")); + printf (" %s\n", _("us (microseconds), ms (milliseconds, default) or just plain s for seconds.")); +/* -d not yet implemented */ +/* printf ("%s\n", _("Threshold format for -d is warn,crit. 12,14 means WARNING if >= 12 hops")); + printf ("%s\n", _("are spent and CRITICAL if >= 14 hops are spent.")); + printf ("%s\n\n", _("NOTE: Some systems decrease TTL when forming ICMP_ECHOREPLY, others do not."));*/ + printf ("\n"); + printf (" %s\n", _("The -v switch can be specified several times for increased verbosity.")); +/* printf ("%s\n", _("Long options are currently unsupported.")); + printf ("%s\n", _("Options marked with * require an argument")); +*/ +#ifdef NP_EXTRA_OPTS + printf ("\n"); + printf (_(UT_EXTRA_OPTS_NOTES)); +#endif - printf("Usage: %s [options] [-H] host1 host2 hostn\n\n", progname); - - if(arg != 'h') exit(3); - - printf("Where options are any combination of:\n" - " * -H | --host specify a target\n" - " * -w | --warn warning threshold (currently %0.3fms,%u%%)\n" - " * -c | --crit critical threshold (currently %0.3fms,%u%%)\n" - " * -n | --packets number of packets to send (currently %u)\n" - " * -i | --interval max packet interval (currently %0.3fms)\n" - " * -I | --hostint max target interval (currently %0.3fms)\n" - " * -l | --ttl TTL on outgoing packets (currently %u)\n" - " * -t | --timeout timeout value (seconds, currently %u)\n" - " * -b | --bytes icmp packet size (currenly ignored)\n" - " -v | --verbose verbosity++\n" - " -h | --help this cruft\n", - (float)warn.rta / 1000, warn.pl, (float)crit.rta / 1000, crit.pl, - packets, - (float)pkt_interval / 1000, (float)target_interval / 1000, - ttl, timeout); - - puts("\nThe -H switch is optional. Naming a host (or several) to check is not.\n\n" - "Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%\n" - "packet loss. The default values should work well for most users.\n" - "You can specify different RTA factors using the standardized abbreviations\n" - "us (microseconds), ms (milliseconds, default) or just plain s for seconds.\n\n" - "Threshold format for -d is warn,crit. 12,14 means WARNING if >= 12 hops\n" - "are spent and CRITICAL if >= 14 hops are spent.\n" - "NOTE: Some systems decrease TTL when forming ICMP_ECHOREPLY, others do not.\n\n" - "The -v switch can be specified several times for increased verbosity.\n\n" - "Long options are currently unsupported.\n\n" - "Options marked with * require an argument\n"); - - puts("The latest version of this plugin can be found at http://oss.op5.se/nagios\n" - "or https://devel.op5.se/oss until the day it is included in the official\n" - "plugin distribution.\n"); + printf (_(UT_SUPPORT)); +} - exit(3); + + +void +print_usage (void) +{ + printf (_("Usage:")); + printf(" %s [options] [-H] host1 host2 hostN\n", progname); }