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 | } | ||