diff options
Diffstat (limited to 'web/attachments/121773-check_icmp-bundled.diff')
| -rw-r--r-- | web/attachments/121773-check_icmp-bundled.diff | 742 |
1 files changed, 742 insertions, 0 deletions
diff --git a/web/attachments/121773-check_icmp-bundled.diff b/web/attachments/121773-check_icmp-bundled.diff new file mode 100644 index 0000000..4bb56b4 --- /dev/null +++ b/web/attachments/121773-check_icmp-bundled.diff | |||
| @@ -0,0 +1,742 @@ | |||
| 1 | diff -urN ../plugins/plugins/check_icmp.c ./plugins/check_icmp.c | ||
| 2 | --- ../plugins/plugins/check_icmp.c 2005-02-01 15:31:11.000000000 +0100 | ||
| 3 | +++ ./plugins/check_icmp.c 2005-02-18 15:57:08.000000000 +0100 | ||
| 4 | @@ -1,5 +1,5 @@ | ||
| 5 | /* | ||
| 6 | - * $Id: check_icmp.c,v 1.5 2005/02/01 07:33:13 stanleyhopcroft Exp $ | ||
| 7 | + * $Id: check_icmp.c,v 1.12 2005/01/29 23:23:23 exon Exp $ | ||
| 8 | * | ||
| 9 | * Author: Andreas Ericsson <ae@op5.se> | ||
| 10 | * | ||
| 11 | @@ -14,6 +14,15 @@ | ||
| 12 | * redundant routes. The only remainders of fping is currently a few | ||
| 13 | * function names. | ||
| 14 | * | ||
| 15 | + * Kudos to; | ||
| 16 | + * Joe Rhett | ||
| 17 | + * Wickus Botha | ||
| 18 | + * Aaron Carr | ||
| 19 | + * Harper Mann | ||
| 20 | + * Phil Costelloe | ||
| 21 | + * Carsten Schmitz | ||
| 22 | + * for lending me system resources, testing and feedback | ||
| 23 | + * | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <sys/time.h> | ||
| 27 | @@ -84,7 +93,7 @@ | ||
| 28 | char *msg; /* icmp error message, if any */ | ||
| 29 | struct sockaddr_in saddr_in; /* the address of this host */ | ||
| 30 | struct in_addr error_addr; /* stores address of error replies */ | ||
| 31 | - unsigned long long time_waited; /* total time waited, in usecs */ | ||
| 32 | + unsigned long int time_waited; /* total time waited, in usecs */ | ||
| 33 | unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */ | ||
| 34 | unsigned char icmp_type, icmp_code; /* type and code from errors */ | ||
| 35 | unsigned short flags; /* control/status flags */ | ||
| 36 | @@ -137,18 +146,19 @@ | ||
| 37 | #define IP_HDR_SIZE 20 | ||
| 38 | #define MAX_PING_DATA (MAX_IP_PKT_SIZE - IP_HDR_SIZE - ICMP_MINLEN) | ||
| 39 | #define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA_SIZE + 44) | ||
| 40 | +#define DEFAULT_TTL 64 | ||
| 41 | |||
| 42 | -/* various target states */ | ||
| 43 | -#define TSTATE_INACTIVE 0x01 /* don't ping this host anymore */ | ||
| 44 | -#define TSTATE_WAITING 0x02 /* unanswered packets on the wire */ | ||
| 45 | -#define TSTATE_ALIVE 0x04 /* target is alive (has answered something) */ | ||
| 46 | -#define TSTATE_UNREACH 0x08 | ||
| 47 | +#define MIN_PKT_INTERVAL 25000 /* min pkt_interval, microsecs */ | ||
| 48 | +#define NOFORCE_WAIT 0 | ||
| 49 | +#define FORCE_WAIT 1 | ||
| 50 | |||
| 51 | /** prototypes **/ | ||
| 52 | -static void usage(unsigned char, char *); | ||
| 53 | +static void usage(unsigned char, char *, ...); | ||
| 54 | static u_int get_timevar(const char *); | ||
| 55 | static u_int get_timevaldiff(struct timeval *, struct timeval *); | ||
| 56 | -static int wait_for_reply(int, u_int); | ||
| 57 | +static int reap_replies(int, u_int, int); | ||
| 58 | +void u_sleep(u_int u_sec); | ||
| 59 | +static u_int wait_for_reply(int, u_int); | ||
| 60 | static int recvfrom_wto(int, char *, unsigned int, struct sockaddr *, u_int *); | ||
| 61 | static int send_icmp_ping(int, struct rta_host *); | ||
| 62 | static int get_threshold(char *str, threshold *th); | ||
| 63 | @@ -162,6 +172,7 @@ | ||
| 64 | |||
| 65 | /** external **/ | ||
| 66 | extern int optind, opterr, optopt; | ||
| 67 | +/* extern int h_errno; */ | ||
| 68 | extern char *optarg; | ||
| 69 | extern char **environ; | ||
| 70 | |||
| 71 | @@ -173,15 +184,15 @@ | ||
| 72 | static unsigned short icmp_pkt_size, icmp_data_size = DEFAULT_PING_DATA_SIZE; | ||
| 73 | static unsigned int icmp_sent = 0, icmp_recv = 0, icmp_lost = 0; | ||
| 74 | #define icmp_pkts_en_route (icmp_sent - (icmp_recv + icmp_lost)) | ||
| 75 | -static unsigned short targets_down = 0, targets = 0, packets = 0; | ||
| 76 | +static unsigned int targets_down = 0, targets = 0, packets = 0; | ||
| 77 | #define targets_alive (targets - targets_down) | ||
| 78 | static unsigned int retry_interval, pkt_interval, target_interval; | ||
| 79 | static int icmp_sock, tcp_sock, udp_sock, status = STATE_OK; | ||
| 80 | static pid_t pid; | ||
| 81 | static struct timezone tz; | ||
| 82 | static struct timeval prog_start; | ||
| 83 | -static unsigned long long max_completion_time = 0; | ||
| 84 | -static unsigned char ttl = 0; /* outgoing ttl */ | ||
| 85 | +static unsigned long int max_completion_time = 0; | ||
| 86 | +static unsigned char ttl = 64; /* outgoing ttl */ | ||
| 87 | static unsigned int warn_down = 1, crit_down = 1; /* host down threshold values */ | ||
| 88 | float pkt_backoff_factor = 1.5; | ||
| 89 | float target_backoff_factor = 1.5; | ||
| 90 | @@ -210,7 +221,8 @@ | ||
| 91 | { | ||
| 92 | char *msg = "unreachable"; | ||
| 93 | |||
| 94 | - if(debug > 1) printf("get_icmp_error_msg(%u, %u)\n", icmp_type, icmp_code); | ||
| 95 | + if(debug > 3) printf("get_icmp_error_msg(%u, %u) called\n", | ||
| 96 | + icmp_type, icmp_code); | ||
| 97 | switch(icmp_type) { | ||
| 98 | case ICMP_UNREACH: | ||
| 99 | switch(icmp_code) { | ||
| 100 | @@ -269,7 +281,7 @@ | ||
| 101 | unsigned char *ptr; | ||
| 102 | |||
| 103 | if(p->icmp_type == ICMP_ECHO && p->icmp_id == pid) { | ||
| 104 | - /* echo request from us to us (pinging localhost) */ | ||
| 105 | + if(debug > 2) printf("echo request from us to us (pinging localhost)\n"); | ||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | @@ -286,9 +298,13 @@ | ||
| 110 | * TIMXCEED actually sends a proper icmp response we will have passed | ||
| 111 | * too many hops to have a hope of reaching it later, in which case it | ||
| 112 | * indicates overconfidence in the network, poor routing or both. */ | ||
| 113 | + if(debug > 2) printf("random ICMP response type: %u, code: %u\n", | ||
| 114 | + p->icmp_type, p->icmp_code); | ||
| 115 | if(p->icmp_type != ICMP_UNREACH && p->icmp_type != ICMP_TIMXCEED && | ||
| 116 | p->icmp_type != ICMP_SOURCEQUENCH && p->icmp_type != ICMP_PARAMPROB) | ||
| 117 | { | ||
| 118 | + if(debug > 1) printf("Unsafe to handle unknown type %u, returning\n", | ||
| 119 | + p->icmp_type); | ||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | @@ -298,7 +314,7 @@ | ||
| 124 | if(sent_icmp->icmp_type != ICMP_ECHO || sent_icmp->icmp_id != pid || | ||
| 125 | sent_icmp->icmp_seq >= targets) | ||
| 126 | { | ||
| 127 | - if(debug) printf("Packet is no response to a packet we sent\n"); | ||
| 128 | + if(debug) printf("not a response to a packet we sent, or target failed to duplicate request\n"); | ||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | @@ -394,12 +410,12 @@ | ||
| 133 | } | ||
| 134 | else if(!strcmp(progname, "check_host")) { | ||
| 135 | mode = MODE_HOSTCHECK; | ||
| 136 | - pkt_interval = 1000000; | ||
| 137 | + pkt_interval = 200000; | ||
| 138 | packets = 5; | ||
| 139 | crit.rta = warn.rta = 1000000; | ||
| 140 | crit.pl = warn.pl = 100; | ||
| 141 | } | ||
| 142 | - else if(!strcmp(progname, "check_rta_multi")) { | ||
| 143 | + else if(!strcmp(progname, "check_icmp_multi")) { | ||
| 144 | mode = MODE_ALL; | ||
| 145 | target_interval = 0; | ||
| 146 | pkt_interval = 50000; | ||
| 147 | @@ -408,6 +424,8 @@ | ||
| 148 | |||
| 149 | /* parse the arguments */ | ||
| 150 | for(i = 1; i < argc; i++) { | ||
| 151 | + /* the leading '-' of the optstring makes non-argument options | ||
| 152 | + * return with arg 1, meaning it's */ | ||
| 153 | while((arg = getopt(argc, argv, "vhVw:c:n:p:t:H:i:b:I:l:")) != EOF) { | ||
| 154 | switch(arg) { | ||
| 155 | case 'v': | ||
| 156 | @@ -436,7 +454,8 @@ | ||
| 157 | timeout = strtoul(optarg, NULL, 0); | ||
| 158 | if(!timeout) timeout = 10; | ||
| 159 | break; | ||
| 160 | - case 'H': | ||
| 161 | + case 'H': case 1: /* 1 is default for non-option arguments */ | ||
| 162 | + /* printf("arg: %ld, optarg: %s\n", arg, optarg); */ | ||
| 163 | add_target(optarg); | ||
| 164 | break; | ||
| 165 | case 'l': | ||
| 166 | @@ -460,11 +479,10 @@ | ||
| 167 | add_target(*argv); | ||
| 168 | argv++; | ||
| 169 | } | ||
| 170 | - if(!targets) { | ||
| 171 | - errno = 0; | ||
| 172 | - crash("No hosts to check"); | ||
| 173 | - exit(3); | ||
| 174 | - } | ||
| 175 | + if(!targets) usage('h', "No hosts to check"); | ||
| 176 | + | ||
| 177 | + if(getuid() && pkt_interval < MIN_PKT_INTERVAL) | ||
| 178 | + pkt_interval = MIN_PKT_INTERVAL; | ||
| 179 | |||
| 180 | if(!sockets) { | ||
| 181 | if(icmp_sock == -1) { | ||
| 182 | @@ -486,10 +504,12 @@ | ||
| 183 | if(!ttl) ttl = 64; | ||
| 184 | |||
| 185 | if(icmp_sock) { | ||
| 186 | + errno = 0; | ||
| 187 | result = setsockopt(icmp_sock, SOL_IP, IP_TTL, &ttl, sizeof(ttl)); | ||
| 188 | if(debug) { | ||
| 189 | - if(result == -1) printf("setsockopt failed\n"); | ||
| 190 | - else printf("ttl set to %u\n", ttl); | ||
| 191 | + printf("setsockopt(icmp_sock, SOL_IP, IP_TTL, %u) = %d (%s)\n", | ||
| 192 | + ttl, result, strerror(errno)); | ||
| 193 | + if(result != -1) printf("outgoing ttl set to %u\n", ttl); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | @@ -505,7 +525,7 @@ | ||
| 198 | signal(SIGHUP, finish); | ||
| 199 | signal(SIGTERM, finish); | ||
| 200 | signal(SIGALRM, finish); | ||
| 201 | - if(debug) printf("Setting alarm timeout to %u seconds\n", timeout); | ||
| 202 | + if(debug > 1) printf("Setting alarm timeout to %u seconds\n", timeout); | ||
| 203 | alarm(timeout); | ||
| 204 | |||
| 205 | /* make sure we don't wait any longer than necessary */ | ||
| 206 | @@ -514,10 +534,9 @@ | ||
| 207 | ((targets * packets * pkt_interval) + (targets * target_interval)) + | ||
| 208 | (targets * packets * crit.rta) + crit.rta; | ||
| 209 | |||
| 210 | - if(debug) { | ||
| 211 | + if(debug > 1) { | ||
| 212 | printf("packets: %u, targets: %u\n" | ||
| 213 | - "target_interval: %0.3f, pkt_interval %0.3f\n" | ||
| 214 | - "crit.rta: %0.3f\n" | ||
| 215 | + "target_interval: %0.3f, pkt_interval %0.3f, crit.rta: %0.3f\n" | ||
| 216 | "max_completion_time: %0.3f\n", | ||
| 217 | packets, targets, | ||
| 218 | (float)target_interval / 1000, (float)pkt_interval / 1000, | ||
| 219 | @@ -527,9 +546,9 @@ | ||
| 220 | |||
| 221 | if(debug) { | ||
| 222 | if(max_completion_time > (u_int)timeout * 1000000) { | ||
| 223 | - printf("max_completion_time: %llu timeout: %u\n", | ||
| 224 | + printf("max_completion_time: %lu timeout: %u\n", | ||
| 225 | max_completion_time, timeout); | ||
| 226 | - printf("Timout must be at lest %llu\n", | ||
| 227 | + printf("Timout must be at lest %lu\n", | ||
| 228 | max_completion_time / 1000000 + 1); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | @@ -579,24 +598,27 @@ | ||
| 232 | u_int i, t, result; | ||
| 233 | u_int final_wait, time_passed; | ||
| 234 | |||
| 235 | - /* this loop might actually violate the pkt_interval or target_interval | ||
| 236 | - * settings, but only if there aren't any packets on the wire which | ||
| 237 | - * indicates that the target can handle an increased packet rate */ | ||
| 238 | - for(i = 0; i < packets; i++) { | ||
| 239 | - for(t = 0; t < targets; t++) { | ||
| 240 | + /* send the packets */ | ||
| 241 | + for(t = 0; t < targets; t++) { | ||
| 242 | + for(i = 0; i < packets; i++) { | ||
| 243 | + | ||
| 244 | /* don't send useless packets */ | ||
| 245 | - if(!targets_alive) finish(0); | ||
| 246 | if(table[t]->flags & FLAG_LOST_CAUSE) { | ||
| 247 | if(debug) printf("%s is a lost cause. not sending any more\n", | ||
| 248 | table[t]->name); | ||
| 249 | continue; | ||
| 250 | } | ||
| 251 | - | ||
| 252 | + | ||
| 253 | /* we're still in the game, so send next packet */ | ||
| 254 | (void)send_icmp_ping(icmp_sock, table[t]); | ||
| 255 | - result = wait_for_reply(icmp_sock, target_interval); | ||
| 256 | + | ||
| 257 | + /* pause for a while so we don't flood the network */ | ||
| 258 | + result = reap_replies(icmp_sock, pkt_interval, FORCE_WAIT); | ||
| 259 | } | ||
| 260 | - result = wait_for_reply(icmp_sock, pkt_interval * targets); | ||
| 261 | + | ||
| 262 | + /* wait for all incoming packets from all hosts */ | ||
| 263 | + if(target_interval > pkt_interval) | ||
| 264 | + result = reap_replies(icmp_sock, target_interval - pkt_interval, FORCE_WAIT); | ||
| 265 | } | ||
| 266 | |||
| 267 | if(icmp_pkts_en_route && targets_alive) { | ||
| 268 | @@ -604,7 +626,7 @@ | ||
| 269 | final_wait = max_completion_time - time_passed; | ||
| 270 | |||
| 271 | if(debug) { | ||
| 272 | - printf("time_passed: %u final_wait: %u max_completion_time: %llu\n", | ||
| 273 | + printf("time_passed: %u final_wait: %u max_completion_time: %lu\n", | ||
| 274 | time_passed, final_wait, max_completion_time); | ||
| 275 | } | ||
| 276 | if(time_passed > max_completion_time) { | ||
| 277 | @@ -616,8 +638,61 @@ | ||
| 278 | * haven't yet */ | ||
| 279 | if(debug) printf("Waiting for %u micro-seconds (%0.3f msecs)\n", | ||
| 280 | final_wait, (float)final_wait / 1000); | ||
| 281 | - result = wait_for_reply(icmp_sock, final_wait); | ||
| 282 | + result = reap_replies(icmp_sock, final_wait, NOFORCE_WAIT); | ||
| 283 | + } | ||
| 284 | +} | ||
| 285 | + | ||
| 286 | +/* | ||
| 287 | + * select() is posix, so we expect it to be around | ||
| 288 | + */ | ||
| 289 | +void | ||
| 290 | +u_sleep(u_int u_sec) | ||
| 291 | +{ | ||
| 292 | + int nfound; | ||
| 293 | + struct timeval to; | ||
| 294 | + fd_set readset, writeset; | ||
| 295 | + | ||
| 296 | + if(debug > 3) printf("sleeping for %u microseconds\n", u_sec); | ||
| 297 | + if(!u_sec) return; | ||
| 298 | + | ||
| 299 | + to.tv_sec = u_sec / 1000000; | ||
| 300 | + to.tv_usec = u_sec % 1000000; | ||
| 301 | + FD_ZERO(&writeset); | ||
| 302 | + FD_ZERO(&readset); | ||
| 303 | + nfound = select(0, &readset, &writeset, NULL, &to); | ||
| 304 | + if(nfound < 0) | ||
| 305 | + crash("select() in u_sleep"); | ||
| 306 | + | ||
| 307 | + return; | ||
| 308 | +} /* u_sleep() */ | ||
| 309 | + | ||
| 310 | +static int | ||
| 311 | +reap_replies(int sock, u_int t, int wait_forced) | ||
| 312 | +{ | ||
| 313 | + /* wrap up if all targets are declared dead */ | ||
| 314 | + if(debug > 3) printf("reap_replies(%d, %u, %d) called\n", sock, t, wait_forced); | ||
| 315 | + | ||
| 316 | + if(!targets_alive || | ||
| 317 | + get_timevaldiff(&prog_start, NULL) >= max_completion_time) | ||
| 318 | + { | ||
| 319 | + finish(0); | ||
| 320 | + } | ||
| 321 | + | ||
| 322 | + /* listen til timeout while there are packets en route (rhymes!) ;) */ | ||
| 323 | + while(t && icmp_pkts_en_route) { | ||
| 324 | + t = wait_for_reply(sock, t); | ||
| 325 | + | ||
| 326 | + /* the dead won't sing to us */ | ||
| 327 | + if(!targets_alive) finish(0); | ||
| 328 | } | ||
| 329 | + | ||
| 330 | + if(icmp_recv == (targets_alive * (int)packets)) finish(0); | ||
| 331 | + | ||
| 332 | + if(!t || !wait_forced) return 0; | ||
| 333 | + | ||
| 334 | + u_sleep(t); | ||
| 335 | + | ||
| 336 | + return 0; | ||
| 337 | } | ||
| 338 | |||
| 339 | /* response structure: | ||
| 340 | @@ -625,126 +700,98 @@ | ||
| 341 | * icmp header : 28 bytes | ||
| 342 | * icmp echo reply : the rest | ||
| 343 | */ | ||
| 344 | -static int | ||
| 345 | +static u_int | ||
| 346 | wait_for_reply(int sock, u_int t) | ||
| 347 | { | ||
| 348 | int n, hlen; | ||
| 349 | static char buf[4096]; | ||
| 350 | struct sockaddr_in resp_addr; | ||
| 351 | struct ip *ip; | ||
| 352 | - struct icmp *icp, *sent_icmp; | ||
| 353 | + struct icmp *icp; | ||
| 354 | struct rta_host *host; | ||
| 355 | struct icmp_ping_data *data; | ||
| 356 | struct timeval wait_start, now; | ||
| 357 | - u_int tdiff, i, per_pkt_wait; | ||
| 358 | - | ||
| 359 | - /* if we can't listen or don't have anything to listen to, just return */ | ||
| 360 | - if(!t || !icmp_pkts_en_route) return 0; | ||
| 361 | + u_int tdiff, timo = t; | ||
| 362 | |||
| 363 | gettimeofday(&wait_start, &tz); | ||
| 364 | |||
| 365 | - i = t; | ||
| 366 | - per_pkt_wait = t / icmp_pkts_en_route; | ||
| 367 | - while(icmp_pkts_en_route && get_timevaldiff(&wait_start, NULL) < i) { | ||
| 368 | - t = per_pkt_wait; | ||
| 369 | - | ||
| 370 | - /* wrap up if all targets are declared dead */ | ||
| 371 | - if(!targets_alive || | ||
| 372 | - get_timevaldiff(&prog_start, NULL) >= max_completion_time || | ||
| 373 | - (mode == MODE_HOSTCHECK && targets_down)) | ||
| 374 | - { | ||
| 375 | - finish(0); | ||
| 376 | - } | ||
| 377 | + n = recvfrom_wto(sock, buf, sizeof(buf), (struct sockaddr *)&resp_addr, &timo); | ||
| 378 | + if(!n) { /* timeout */ | ||
| 379 | + if(debug > 2) printf("recvfrom_wto() timed out during a %u usecs wait\n", t); | ||
| 380 | + return 0; /* no time left, so return just that */ | ||
| 381 | + } | ||
| 382 | |||
| 383 | - /* reap responses until we hit a timeout */ | ||
| 384 | - n = recvfrom_wto(sock, buf, sizeof(buf), | ||
| 385 | - (struct sockaddr *)&resp_addr, &t); | ||
| 386 | - if(!n) { | ||
| 387 | - if(debug > 1) { | ||
| 388 | - printf("recvfrom_wto() timed out during a %u usecs wait\n", | ||
| 389 | - per_pkt_wait); | ||
| 390 | - } | ||
| 391 | - continue; /* timeout for this one, so keep trying */ | ||
| 392 | - } | ||
| 393 | - if(n < 0) { | ||
| 394 | - if(debug) printf("recvfrom_wto() returned errors\n"); | ||
| 395 | - return n; | ||
| 396 | - } | ||
| 397 | + gettimeofday(&now, &tz); | ||
| 398 | + tdiff = get_timevaldiff(&wait_start, &now); | ||
| 399 | + /* make sure we can return time left */ | ||
| 400 | + if(t > tdiff) t -= tdiff; | ||
| 401 | + else t = 0; | ||
| 402 | |||
| 403 | - ip = (struct ip *)buf; | ||
| 404 | - if(debug > 1) printf("received %u bytes from %s\n", | ||
| 405 | + ip = (struct ip *)buf; | ||
| 406 | + if(debug > 1) printf("received %u bytes from %s\n", | ||
| 407 | ntohs(ip->ip_len), inet_ntoa(resp_addr.sin_addr)); | ||
| 408 | |||
| 409 | -/* obsolete. alpha on tru64 provides the necessary defines, but isn't broken */ | ||
| 410 | +/* obsolete, or at least not globally applicable */ | ||
| 411 | /* #if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ ) */ | ||
| 412 | /* alpha headers are decidedly broken. Using an ansi compiler, | ||
| 413 | * they provide ip_vhl instead of ip_hl and ip_v, so we mask | ||
| 414 | * off the bottom 4 bits */ | ||
| 415 | /* hlen = (ip->ip_vhl & 0x0f) << 2; */ | ||
| 416 | /* #else */ | ||
| 417 | - hlen = ip->ip_hl << 2; | ||
| 418 | + hlen = ip->ip_hl << 2; | ||
| 419 | /* #endif */ | ||
| 420 | |||
| 421 | - if(n < (hlen + ICMP_MINLEN)) { | ||
| 422 | - crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n", | ||
| 423 | - n, hlen + icmp_pkt_size, inet_ntoa(resp_addr.sin_addr)); | ||
| 424 | - } | ||
| 425 | - /* else if(debug) { */ | ||
| 426 | - /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */ | ||
| 427 | - /* hlen, ntohs(ip->ip_len) - hlen, */ | ||
| 428 | - /* sizeof(struct ip), icmp_pkt_size); */ | ||
| 429 | - /* } */ | ||
| 430 | - | ||
| 431 | - /* check the response */ | ||
| 432 | - icp = (struct icmp *)(buf + hlen); | ||
| 433 | - sent_icmp = (struct icmp *)(buf + hlen + ICMP_MINLEN); | ||
| 434 | - /* printf("buf: %p, icp: %p, distance: %u (expected %u)\n", */ | ||
| 435 | - /* buf, icp, */ | ||
| 436 | - /* (u_int)icp - (u_int)buf, hlen); */ | ||
| 437 | - /* printf("buf: %p, sent_icmp: %p, distance: %u (expected %u)\n", */ | ||
| 438 | - /* buf, sent_icmp, */ | ||
| 439 | - /* (u_int)sent_icmp - (u_int)buf, hlen + ICMP_MINLEN); */ | ||
| 440 | - | ||
| 441 | - if(icp->icmp_id != pid) { | ||
| 442 | - handle_random_icmp(icp, &resp_addr); | ||
| 443 | - continue; | ||
| 444 | - } | ||
| 445 | - | ||
| 446 | - if(icp->icmp_type != ICMP_ECHOREPLY || icp->icmp_seq >= targets) { | ||
| 447 | - if(debug > 2) printf("not a proper ICMP_ECHOREPLY\n"); | ||
| 448 | - handle_random_icmp(icp, &resp_addr); | ||
| 449 | - continue; | ||
| 450 | - } | ||
| 451 | - | ||
| 452 | - /* this is indeed a valid response */ | ||
| 453 | - data = (struct icmp_ping_data *)(icp->icmp_data); | ||
| 454 | - | ||
| 455 | - host = table[icp->icmp_seq]; | ||
| 456 | - gettimeofday(&now, &tz); | ||
| 457 | - tdiff = get_timevaldiff(&data->stime, &now); | ||
| 458 | + if(n < (hlen + ICMP_MINLEN)) { | ||
| 459 | + crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n", | ||
| 460 | + n, hlen + icmp_pkt_size, inet_ntoa(resp_addr.sin_addr)); | ||
| 461 | + } | ||
| 462 | + else if(debug > 2) { | ||
| 463 | + printf("ip header size: %u, packet size: %u (expected %u, %u)\n", | ||
| 464 | + hlen, ntohs(ip->ip_len) - hlen, | ||
| 465 | + sizeof(struct ip), (u_int)icmp_pkt_size); | ||
| 466 | + } | ||
| 467 | |||
| 468 | - host->time_waited += tdiff; | ||
| 469 | - host->icmp_recv++; | ||
| 470 | - icmp_recv++; | ||
| 471 | + /* check the response */ | ||
| 472 | + icp = (struct icmp *)(buf + hlen); | ||
| 473 | |||
| 474 | + if(icp->icmp_id != pid || icp->icmp_type != ICMP_ECHOREPLY || icp->icmp_seq >= targets) { | ||
| 475 | if(debug) { | ||
| 476 | - printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u\n", | ||
| 477 | - (float)tdiff / 1000, inet_ntoa(resp_addr.sin_addr), | ||
| 478 | - ttl, ip->ip_ttl); | ||
| 479 | - } | ||
| 480 | + printf("inbound packet is:\n"); | ||
| 481 | + if(icp->icmp_id != pid) printf("\tnot marked by me\n"); | ||
| 482 | + if(icp->icmp_type != ICMP_ECHOREPLY) printf("\tnot an echo reply\n"); | ||
| 483 | + if(icp->icmp_seq >= targets) printf("\ttagged with a too high seq number\n"); | ||
| 484 | + } | ||
| 485 | + handle_random_icmp(icp, &resp_addr); | ||
| 486 | + return t; | ||
| 487 | + } | ||
| 488 | + if(debug > 2) puts("inbound packet is a valid ICMP_ECHOREPLY to a packet we sent"); | ||
| 489 | + | ||
| 490 | + /* this is indeed a valid response */ | ||
| 491 | + data = (struct icmp_ping_data *)(icp->icmp_data); | ||
| 492 | + host = table[icp->icmp_seq]; | ||
| 493 | + tdiff = get_timevaldiff(&data->stime, &now); | ||
| 494 | + | ||
| 495 | + host->time_waited += tdiff; | ||
| 496 | + host->icmp_recv++; | ||
| 497 | + icmp_recv++; | ||
| 498 | |||
| 499 | - /* if we're in hostcheck mode, exit with limited printouts */ | ||
| 500 | - if(mode == MODE_HOSTCHECK) { | ||
| 501 | - printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|" | ||
| 502 | - "pkt=%u;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n", | ||
| 503 | - host->name, icmp_recv, (float)tdiff / 1000, | ||
| 504 | - icmp_recv, packets, (float)tdiff / 1000, | ||
| 505 | - (float)warn.rta / 1000, (float)crit.rta / 1000); | ||
| 506 | - exit(STATE_OK); | ||
| 507 | - } | ||
| 508 | + if(debug) { | ||
| 509 | + printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u\n", | ||
| 510 | + (float)tdiff / 1000, inet_ntoa(resp_addr.sin_addr), | ||
| 511 | + ttl, ip->ip_ttl); | ||
| 512 | + } | ||
| 513 | + | ||
| 514 | + /* if we're in hostcheck mode, exit with limited printouts */ | ||
| 515 | + if(mode == MODE_HOSTCHECK) { | ||
| 516 | + printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|" | ||
| 517 | + "pkt=%u;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n", | ||
| 518 | + host->name, icmp_recv, (float)tdiff / 1000, | ||
| 519 | + icmp_recv, packets, (float)tdiff / 1000, | ||
| 520 | + (float)warn.rta / 1000, (float)crit.rta / 1000); | ||
| 521 | + exit(STATE_OK); | ||
| 522 | } | ||
| 523 | |||
| 524 | - return 0; | ||
| 525 | + return t; | ||
| 526 | } | ||
| 527 | |||
| 528 | /* the ping functions */ | ||
| 529 | @@ -776,8 +823,6 @@ | ||
| 530 | } | ||
| 531 | memset(buf, 0, icmp_pkt_size + sizeof(struct ip)); | ||
| 532 | |||
| 533 | - if((gettimeofday(&tv, &tz)) == -1) return -1; | ||
| 534 | - | ||
| 535 | icp = (struct icmp *)buf; | ||
| 536 | icp->icmp_type = ICMP_ECHO; | ||
| 537 | icp->icmp_code = 0; | ||
| 538 | @@ -785,7 +830,9 @@ | ||
| 539 | icp->icmp_id = pid; | ||
| 540 | icp->icmp_seq = host->id; | ||
| 541 | data = (struct icmp_ping_data *)icp->icmp_data; | ||
| 542 | - data->ping_id = 10; /* host->icmp.icmp_sent; */ | ||
| 543 | + data->ping_id = host->icmp_sent; | ||
| 544 | + | ||
| 545 | + if((gettimeofday(&tv, &tz)) == -1) return -1; | ||
| 546 | memcpy(&data->stime, &tv, sizeof(struct timeval)); | ||
| 547 | icp->icmp_cksum = icmp_checksum((u_short *)icp, icmp_pkt_size); | ||
| 548 | |||
| 549 | @@ -798,6 +845,7 @@ | ||
| 550 | return -1; | ||
| 551 | } | ||
| 552 | |||
| 553 | + /* increment the counters */ | ||
| 554 | icmp_sent++; | ||
| 555 | host->icmp_sent++; | ||
| 556 | |||
| 557 | @@ -809,7 +857,7 @@ | ||
| 558 | u_int *timo) | ||
| 559 | { | ||
| 560 | u_int slen; | ||
| 561 | - int n; | ||
| 562 | + int n, result; | ||
| 563 | struct timeval to, then, now; | ||
| 564 | fd_set rd, wr; | ||
| 565 | |||
| 566 | @@ -835,7 +883,10 @@ | ||
| 567 | |||
| 568 | slen = sizeof(struct sockaddr); | ||
| 569 | |||
| 570 | - return recvfrom(sock, buf, len, 0, saddr, &slen); | ||
| 571 | + result = recvfrom(sock, buf, len, 0, saddr, &slen); | ||
| 572 | + if(result < 0) crash("recvfrom in recvfrom_wto"); | ||
| 573 | + | ||
| 574 | + return result; | ||
| 575 | } | ||
| 576 | |||
| 577 | static void | ||
| 578 | @@ -849,7 +900,7 @@ | ||
| 579 | {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"}; | ||
| 580 | |||
| 581 | alarm(0); | ||
| 582 | - if(debug > 1) printf("finish(%d) called\n", sig); | ||
| 583 | + if(debug > 2) printf("finish(%d) called\n", sig); | ||
| 584 | |||
| 585 | if(icmp_sock != -1) close(icmp_sock); | ||
| 586 | if(udp_sock != -1) close(udp_sock); | ||
| 587 | @@ -1016,23 +1067,20 @@ | ||
| 588 | struct hostent *he; | ||
| 589 | struct in_addr *in, ip; | ||
| 590 | |||
| 591 | - /* don't resolve if we don't have to */ | ||
| 592 | - if((ip.s_addr = inet_addr(arg)) != INADDR_NONE) { | ||
| 593 | - /* don't add all ip's if we were given a specific one */ | ||
| 594 | - return add_target_ip(arg, &ip); | ||
| 595 | - /* he = gethostbyaddr((char *)in, sizeof(struct in_addr), AF_INET); */ | ||
| 596 | - /* if(!he) return add_target_ip(arg, in); */ | ||
| 597 | - } | ||
| 598 | - else { | ||
| 599 | - errno = 0; | ||
| 600 | + /* don't resolve if we don't have to, don't add all ip's if we were | ||
| 601 | + * given a specific one, even if we're in hostcheck mode */ | ||
| 602 | + if(inet_aton(arg, &ip)) return add_target_ip(arg, &ip); | ||
| 603 | + | ||
| 604 | + /* not an IP, so resolve */ | ||
| 605 | + errno = 0; | ||
| 606 | + he = gethostbyname(arg); | ||
| 607 | + if(!he && h_errno == TRY_AGAIN) { | ||
| 608 | + u_sleep(500000); | ||
| 609 | he = gethostbyname(arg); | ||
| 610 | - if(!he) { | ||
| 611 | - errno = 0; | ||
| 612 | - crash("Failed to resolve %s", arg); | ||
| 613 | - return -1; | ||
| 614 | - } | ||
| 615 | } | ||
| 616 | |||
| 617 | + if(!he) usage(0, "Failed to resolve %s: %s", arg, hstrerror(h_errno)); | ||
| 618 | + | ||
| 619 | /* possibly add all the IP's as targets */ | ||
| 620 | for(i = 0; he->h_addr_list[i]; i++) { | ||
| 621 | in = (struct in_addr *)he->h_addr_list[i]; | ||
| 622 | @@ -1040,7 +1088,7 @@ | ||
| 623 | |||
| 624 | /* this is silly, but it works */ | ||
| 625 | if(mode == MODE_HOSTCHECK || mode == MODE_ALL) { | ||
| 626 | - printf("mode: %d\n", mode); | ||
| 627 | + if(debug) printf("mode: %d\n", mode); | ||
| 628 | continue; | ||
| 629 | } | ||
| 630 | break; | ||
| 631 | @@ -1048,6 +1096,7 @@ | ||
| 632 | |||
| 633 | return 0; | ||
| 634 | } | ||
| 635 | + | ||
| 636 | /* | ||
| 637 | * u = micro | ||
| 638 | * m = milli | ||
| 639 | @@ -1073,12 +1122,12 @@ | ||
| 640 | if(len >= 2 && !isdigit((int)str[len - 2])) p = str[len - 2]; | ||
| 641 | if(p && u == 's') u = p; | ||
| 642 | else if(!p) p = u; | ||
| 643 | - if(debug > 2) printf("evaluating %s, u: %c, p: %c\n", str, u, p); | ||
| 644 | + if(debug > 3) printf("evaluating %s, u: %c, p: %c\n", str, u, p); | ||
| 645 | |||
| 646 | if(u == 'u') factor = 1; /* microseconds */ | ||
| 647 | else if(u == 'm') factor = 1000; /* milliseconds */ | ||
| 648 | else if(u == 's') factor = 1000000; /* seconds */ | ||
| 649 | - if(debug > 2) printf("factor is %u\n", factor); | ||
| 650 | + if(debug > 3) printf("factor is %u\n", factor); | ||
| 651 | |||
| 652 | i = strtoul(str, &ptr, 0); | ||
| 653 | if(!ptr || *ptr != '.' || strlen(ptr) < 2 || factor == 1) | ||
| 654 | @@ -1149,51 +1198,58 @@ | ||
| 655 | |||
| 656 | /* make core plugin developers happy (silly, really) */ | ||
| 657 | static void | ||
| 658 | -usage(unsigned char arg, char *msg) | ||
| 659 | +usage(unsigned char arg, char *fmt, ...) | ||
| 660 | { | ||
| 661 | - if(msg) printf("%s: %s\n", progname, msg); | ||
| 662 | + if(fmt) { | ||
| 663 | + va_list ap; | ||
| 664 | + | ||
| 665 | + printf("%s: ", progname); | ||
| 666 | + | ||
| 667 | + va_start(ap, fmt); | ||
| 668 | + vprintf(fmt, ap); | ||
| 669 | + va_end(ap); | ||
| 670 | + puts("\n"); | ||
| 671 | + } | ||
| 672 | |||
| 673 | if(arg == 'V') { | ||
| 674 | - printf("$Id: check_icmp.c,v 1.5 2005/02/01 07:33:13 stanleyhopcroft Exp $\n"); | ||
| 675 | + printf("$Id: check_icmp.c,v 1.12 2005/01/29 23:23:23 exon Exp $\n"); | ||
| 676 | exit(STATE_UNKNOWN); | ||
| 677 | } | ||
| 678 | |||
| 679 | printf("Usage: %s [options] [-H] host1 host2 hostn\n\n", progname); | ||
| 680 | |||
| 681 | - if(arg != 'h') exit(3); | ||
| 682 | + if(arg != 'h') { | ||
| 683 | + printf("%s -h for details\n", progname); | ||
| 684 | + exit(3); | ||
| 685 | + } | ||
| 686 | |||
| 687 | printf("Where options are any combination of:\n" | ||
| 688 | - " * -H | --host specify a target\n" | ||
| 689 | - " * -w | --warn warning threshold (currently %0.3fms,%u%%)\n" | ||
| 690 | - " * -c | --crit critical threshold (currently %0.3fms,%u%%)\n" | ||
| 691 | - " * -n | --packets number of packets to send (currently %u)\n" | ||
| 692 | - " * -i | --interval max packet interval (currently %0.3fms)\n" | ||
| 693 | - " * -I | --hostint max target interval (currently %0.3fms)\n" | ||
| 694 | - " * -l | --ttl TTL on outgoing packets (currently %u)\n" | ||
| 695 | - " * -t | --timeout timeout value (seconds, currently %u)\n" | ||
| 696 | - " * -b | --bytes icmp packet size (currenly ignored)\n" | ||
| 697 | - " -v | --verbose verbosity++\n" | ||
| 698 | - " -h | --help this cruft\n", | ||
| 699 | + " * -H | --host specify a target\n" | ||
| 700 | + " * -w | --warn warning threshold (currently %0.3fms,%u%%)\n" | ||
| 701 | + " * -c | --crit critical threshold (currently %0.3fms,%u%%)\n" | ||
| 702 | + " * -n | --packets number of packets to send (currently %u)\n" | ||
| 703 | + " * -i | --interval max packet interval (currently %0.3fms)\n" | ||
| 704 | + " * -I | --hostint max target interval (currently %0.3fms)\n", | ||
| 705 | (float)warn.rta / 1000, warn.pl, (float)crit.rta / 1000, crit.pl, | ||
| 706 | packets, | ||
| 707 | - (float)pkt_interval / 1000, (float)target_interval / 1000, | ||
| 708 | + (float)pkt_interval / 1000, (float)target_interval / 1000); | ||
| 709 | + | ||
| 710 | + printf(" * -l | --ttl outgoing TTL (currently %u, not supported on all platforms)\n" | ||
| 711 | + " * -t | --timeout timeout value (seconds, currently %u)\n" | ||
| 712 | + " * -b | --bytes icmp packet size (currenly ignored)\n" | ||
| 713 | + " -v | --verbose verbosity++ (4 is sort of max)\n" | ||
| 714 | + " -h | --help this cruft\n", | ||
| 715 | ttl, timeout); | ||
| 716 | |||
| 717 | - puts("\nThe -H switch is optional. Naming a host (or several) to check is not.\n\n" | ||
| 718 | - "Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%\n" | ||
| 719 | - "packet loss. The default values should work well for most users.\n" | ||
| 720 | + puts("\nThreshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%\n" | ||
| 721 | + "packet loss. All threshold values match inclusively.\n" | ||
| 722 | "You can specify different RTA factors using the standardized abbreviations\n" | ||
| 723 | - "us (microseconds), ms (milliseconds, default) or just plain s for seconds.\n\n" | ||
| 724 | - "Threshold format for -d is warn,crit. 12,14 means WARNING if >= 12 hops\n" | ||
| 725 | - "are spent and CRITICAL if >= 14 hops are spent.\n" | ||
| 726 | - "NOTE: Some systems decrease TTL when forming ICMP_ECHOREPLY, others do not.\n\n" | ||
| 727 | - "The -v switch can be specified several times for increased verbosity.\n\n" | ||
| 728 | - "Long options are currently unsupported.\n\n" | ||
| 729 | - "Options marked with * require an argument\n"); | ||
| 730 | - | ||
| 731 | - puts("The latest version of this plugin can be found at http://oss.op5.se/nagios\n" | ||
| 732 | - "or https://devel.op5.se/oss until the day it is included in the official\n" | ||
| 733 | - "plugin distribution.\n"); | ||
| 734 | + "us (microseconds), ms (milliseconds, default) or just plain s for seconds.\n"); | ||
| 735 | + puts("Long options are currently unsupported.\n"); | ||
| 736 | + puts("Options marked with * require an argument\n"); | ||
| 737 | + puts("If this program is invoked as check_host (with a symlink, preferrably), it will exit with status\n" | ||
| 738 | + "OK upon the first properly received ICMP_ECHOREPLY, making it ideal\n" | ||
| 739 | + "for hostchecks (less network load and much, much faster on OK)\n"); | ||
| 740 | |||
| 741 | exit(3); | ||
| 742 | } | ||
