summaryrefslogtreecommitdiffstats
path: root/plugins-root/check_icmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins-root/check_icmp.c')
-rw-r--r--plugins-root/check_icmp.c484
1 files changed, 457 insertions, 27 deletions
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c
index 1d47e9f..e96fa3e 100644
--- a/plugins-root/check_icmp.c
+++ b/plugins-root/check_icmp.c
@@ -43,7 +43,7 @@ const char *copyright = "2005-2008";
43const char *email = "devel@monitoring-plugins.org"; 43const char *email = "devel@monitoring-plugins.org";
44 44
45/** Monitoring Plugins basic includes */ 45/** Monitoring Plugins basic includes */
46#include "common.h" 46#include "../plugins/common.h"
47#include "netutils.h" 47#include "netutils.h"
48#include "utils.h" 48#include "utils.h"
49 49
@@ -109,18 +109,35 @@ typedef struct rta_host {
109 unsigned char icmp_type, icmp_code; /* type and code from errors */ 109 unsigned char icmp_type, icmp_code; /* type and code from errors */
110 unsigned short flags; /* control/status flags */ 110 unsigned short flags; /* control/status flags */
111 double rta; /* measured RTA */ 111 double rta; /* measured RTA */
112 int rta_status;
112 double rtmax; /* max rtt */ 113 double rtmax; /* max rtt */
113 double rtmin; /* min rtt */ 114 double rtmin; /* min rtt */
115 double jitter; /* measured jitter */
116 int jitter_status;
117 double jitter_max; /* jitter rtt */
118 double jitter_min; /* jitter rtt */
119 double EffectiveLatency;
120 double mos; /* Mean opnion score */
121 int mos_status;
122 double score; /* score */
123 int score_status;
124 u_int last_tdiff;
125 u_int last_icmp_seq; /* Last ICMP_SEQ to check out of order pkts */
114 unsigned char pl; /* measured packet loss */ 126 unsigned char pl; /* measured packet loss */
127 int pl_status;
115 struct rta_host *next; /* linked list */ 128 struct rta_host *next; /* linked list */
129 int order_status;
116} rta_host; 130} rta_host;
117 131
118#define FLAG_LOST_CAUSE 0x01 /* decidedly dead target. */ 132#define FLAG_LOST_CAUSE 0x01 /* decidedly dead target. */
119 133
120/* threshold structure. all values are maximum allowed, exclusive */ 134/* threshold structure. all values are maximum allowed, exclusive */
121typedef struct threshold { 135typedef struct threshold {
122 unsigned char pl; /* max allowed packet loss in percent */ 136 unsigned char pl; /* max allowed packet loss in percent */
123 unsigned int rta; /* roundtrip time average, microseconds */ 137 unsigned int rta; /* roundtrip time average, microseconds */
138 double jitter; /* jitter time average, microseconds */
139 double mos; /* MOS */
140 double score; /* Score */
124} threshold; 141} threshold;
125 142
126/* the data structure */ 143/* the data structure */
@@ -159,6 +176,16 @@ typedef union icmp_packet {
159#define MODE_ALL 2 176#define MODE_ALL 2
160#define MODE_ICMP 3 177#define MODE_ICMP 3
161 178
179enum enum_threshold_mode {
180 const_rta_mode,
181 const_packet_loss_mode,
182 const_jitter_mode,
183 const_mos_mode,
184 const_score_mode
185};
186
187typedef enum enum_threshold_mode threshold_mode;
188
162/* the different ping types we can do 189/* the different ping types we can do
163 * TODO: investigate ARP ping as well */ 190 * TODO: investigate ARP ping as well */
164#define HAVE_ICMP 1 191#define HAVE_ICMP 1
@@ -188,6 +215,8 @@ static int wait_for_reply(int, u_int);
188static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *, struct timeval*); 215static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *, struct timeval*);
189static int send_icmp_ping(int, struct rta_host *); 216static int send_icmp_ping(int, struct rta_host *);
190static int get_threshold(char *str, threshold *th); 217static int get_threshold(char *str, threshold *th);
218static bool get_threshold2(char *str, size_t length, threshold *, threshold *, threshold_mode mode);
219static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, threshold_mode mode);
191static void run_checks(void); 220static void run_checks(void);
192static void set_source_ip(char *); 221static void set_source_ip(char *);
193static int add_target(char *); 222static int add_target(char *);
@@ -224,6 +253,12 @@ static unsigned int warn_down = 1, crit_down = 1; /* host down threshold values
224static int min_hosts_alive = -1; 253static int min_hosts_alive = -1;
225float pkt_backoff_factor = 1.5; 254float pkt_backoff_factor = 1.5;
226float target_backoff_factor = 1.5; 255float target_backoff_factor = 1.5;
256bool rta_mode=false;
257bool pl_mode=false;
258bool jitter_mode=false;
259bool score_mode=false;
260bool mos_mode=false;
261bool order_mode=false;
227 262
228/** code start **/ 263/** code start **/
229static void 264static void
@@ -393,12 +428,14 @@ main(int argc, char **argv)
393 int icmp_sockerrno, udp_sockerrno, tcp_sockerrno; 428 int icmp_sockerrno, udp_sockerrno, tcp_sockerrno;
394 int result; 429 int result;
395 struct rta_host *host; 430 struct rta_host *host;
431#ifdef HAVE_SIGACTION
432 struct sigaction sig_action;
433#endif
396#ifdef SO_TIMESTAMP 434#ifdef SO_TIMESTAMP
397 int on = 1; 435 int on = 1;
398#endif 436#endif
399 char *source_ip = NULL; 437 char *source_ip = NULL;
400 char * opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:64"; 438 char * opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64";
401
402 setlocale (LC_ALL, ""); 439 setlocale (LC_ALL, "");
403 bindtextdomain (PACKAGE, LOCALEDIR); 440 bindtextdomain (PACKAGE, LOCALEDIR);
404 textdomain (PACKAGE); 441 textdomain (PACKAGE);
@@ -422,10 +459,19 @@ main(int argc, char **argv)
422 table = NULL; 459 table = NULL;
423 460
424 mode = MODE_RTA; 461 mode = MODE_RTA;
462 /* Default critical thresholds */
425 crit.rta = 500000; 463 crit.rta = 500000;
426 crit.pl = 80; 464 crit.pl = 80;
465 crit.jitter = 50;
466 crit.mos= 3;
467 crit.score=70;
468 /* Default warning thresholds */
427 warn.rta = 200000; 469 warn.rta = 200000;
428 warn.pl = 40; 470 warn.pl = 40;
471 warn.jitter = 40;
472 warn.mos= 3.5;
473 warn.score=80;
474
429 protocols = HAVE_ICMP | HAVE_UDP | HAVE_TCP; 475 protocols = HAVE_ICMP | HAVE_UDP | HAVE_TCP;
430 pkt_interval = 80000; /* 80 msec packet interval by default */ 476 pkt_interval = 80000; /* 80 msec packet interval by default */
431 packets = 5; 477 packets = 5;
@@ -481,7 +527,8 @@ main(int argc, char **argv)
481 /* Reset argument scanning */ 527 /* Reset argument scanning */
482 optind = 1; 528 optind = 1;
483 529
484 unsigned short size; 530 unsigned long size;
531 bool err;
485 /* parse the arguments */ 532 /* parse the arguments */
486 for(i = 1; i < argc; i++) { 533 for(i = 1; i < argc; i++) {
487 while((arg = getopt(argc, argv, opts_str)) != EOF) { 534 while((arg = getopt(argc, argv, opts_str)) != EOF) {
@@ -490,7 +537,7 @@ main(int argc, char **argv)
490 debug++; 537 debug++;
491 break; 538 break;
492 case 'b': 539 case 'b':
493 size = (unsigned short)strtol(optarg,NULL,0); 540 size = strtol(optarg,NULL,0);
494 if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) && 541 if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) &&
495 size < MAX_PING_DATA) { 542 size < MAX_PING_DATA) {
496 icmp_data_size = size; 543 icmp_data_size = size;
@@ -545,6 +592,54 @@ main(int argc, char **argv)
545 print_help (); 592 print_help ();
546 exit (STATE_UNKNOWN); 593 exit (STATE_UNKNOWN);
547 break; 594 break;
595 case 'R': /* RTA mode */
596 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_rta_mode);
597
598 if (!err) {
599 crash("Failed to parse RTA threshold");
600 }
601
602 rta_mode=true;
603 break;
604 case 'P': /* packet loss mode */
605 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_packet_loss_mode);
606
607 if (!err) {
608 crash("Failed to parse packet loss threshold");
609 }
610
611 pl_mode=true;
612 break;
613 case 'J': /* jitter mode */
614 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_jitter_mode);
615
616 if (!err) {
617 crash("Failed to parse jitter threshold");
618 }
619
620 jitter_mode=true;
621 break;
622 case 'M': /* MOS mode */
623 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_mos_mode);
624
625 if (!err) {
626 crash("Failed to parse MOS threshold");
627 }
628
629 mos_mode=true;
630 break;
631 case 'S': /* score mode */
632 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_score_mode);
633
634 if (!err) {
635 crash("Failed to parse score threshold");
636 }
637
638 score_mode=true;
639 break;
640 case 'O': /* out of order mode */
641 order_mode=true;
642 break;
548 } 643 }
549 } 644 }
550 } 645 }
@@ -631,11 +726,25 @@ main(int argc, char **argv)
631 if(warn.pl > crit.pl) warn.pl = crit.pl; 726 if(warn.pl > crit.pl) warn.pl = crit.pl;
632 if(warn.rta > crit.rta) warn.rta = crit.rta; 727 if(warn.rta > crit.rta) warn.rta = crit.rta;
633 if(warn_down > crit_down) crit_down = warn_down; 728 if(warn_down > crit_down) crit_down = warn_down;
634 729 if(warn.jitter > crit.jitter) crit.jitter = warn.jitter;
730 if(warn.mos < crit.mos) warn.mos = crit.mos;
731 if(warn.score < crit.score) warn.score = crit.score;
732
733#ifdef HAVE_SIGACTION
734 sig_action.sa_sigaction = NULL;
735 sig_action.sa_handler = finish;
736 sigfillset(&sig_action.sa_mask);
737 sig_action.sa_flags = SA_NODEFER|SA_RESTART;
738 sigaction(SIGINT, &sig_action, NULL);
739 sigaction(SIGHUP, &sig_action, NULL);
740 sigaction(SIGTERM, &sig_action, NULL);
741 sigaction(SIGALRM, &sig_action, NULL);
742#else /* HAVE_SIGACTION */
635 signal(SIGINT, finish); 743 signal(SIGINT, finish);
636 signal(SIGHUP, finish); 744 signal(SIGHUP, finish);
637 signal(SIGTERM, finish); 745 signal(SIGTERM, finish);
638 signal(SIGALRM, finish); 746 signal(SIGALRM, finish);
747#endif /* HAVE_SIGACTION */
639 if(debug) printf("Setting alarm timeout to %u seconds\n", timeout); 748 if(debug) printf("Setting alarm timeout to %u seconds\n", timeout);
640 alarm(timeout); 749 alarm(timeout);
641 750
@@ -685,7 +794,11 @@ main(int argc, char **argv)
685 } 794 }
686 795
687 host = list; 796 host = list;
688 table = (struct rta_host**)malloc(sizeof(struct rta_host **) * targets); 797 table = malloc(sizeof(struct rta_host *) * targets);
798 if(!table) {
799 crash("main(): malloc failed for host table");
800 }
801
689 i = 0; 802 i = 0;
690 while(host) { 803 while(host) {
691 host->id = i*packets; 804 host->id = i*packets;
@@ -772,6 +885,7 @@ wait_for_reply(int sock, u_int t)
772 struct icmp_ping_data data; 885 struct icmp_ping_data data;
773 struct timeval wait_start, now; 886 struct timeval wait_start, now;
774 u_int tdiff, i, per_pkt_wait; 887 u_int tdiff, i, per_pkt_wait;
888 double jitter_tmp;
775 889
776 if (!(packet.buf = malloc(icmp_pkt_size))) { 890 if (!(packet.buf = malloc(icmp_pkt_size))) {
777 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", 891 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer",
@@ -890,12 +1004,43 @@ wait_for_reply(int sock, u_int t)
890 1004
891 tdiff = get_timevaldiff(&data.stime, &now); 1005 tdiff = get_timevaldiff(&data.stime, &now);
892 1006
1007 if (host->last_tdiff>0) {
1008 /* Calculate jitter */
1009 if (host->last_tdiff > tdiff) {
1010 jitter_tmp = host->last_tdiff - tdiff;
1011 }
1012 else {
1013 jitter_tmp = tdiff - host->last_tdiff;
1014 }
1015 if (host->jitter==0) {
1016 host->jitter=jitter_tmp;
1017 host->jitter_max=jitter_tmp;
1018 host->jitter_min=jitter_tmp;
1019 }
1020 else {
1021 host->jitter+=jitter_tmp;
1022 if (jitter_tmp < host->jitter_min)
1023 host->jitter_min=jitter_tmp;
1024 if (jitter_tmp > host->jitter_max)
1025 host->jitter_max=jitter_tmp;
1026 }
1027
1028 /* Check if packets in order */
1029 if (host->last_icmp_seq >= packet.icp->icmp_seq)
1030 host->order_status=STATE_CRITICAL;
1031 }
1032 host->last_tdiff=tdiff;
1033
1034 host->last_icmp_seq=packet.icp->icmp_seq;
1035
1036 //printf("%d tdiff %d host->jitter %u host->last_tdiff %u\n", icp.icmp_seq, tdiff, host->jitter, host->last_tdiff);
1037
893 host->time_waited += tdiff; 1038 host->time_waited += tdiff;
894 host->icmp_recv++; 1039 host->icmp_recv++;
895 icmp_recv++; 1040 icmp_recv++;
896 if (tdiff > host->rtmax) 1041 if (tdiff > (int)host->rtmax)
897 host->rtmax = tdiff; 1042 host->rtmax = tdiff;
898 if (tdiff < host->rtmin) 1043 if (tdiff < (int)host->rtmin)
899 host->rtmin = tdiff; 1044 host->rtmin = tdiff;
900 1045
901 if(debug) { 1046 if(debug) {
@@ -1094,8 +1239,10 @@ recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr,
1094 hdr.msg_namelen = slen; 1239 hdr.msg_namelen = slen;
1095 hdr.msg_iov = &iov; 1240 hdr.msg_iov = &iov;
1096 hdr.msg_iovlen = 1; 1241 hdr.msg_iovlen = 1;
1242#ifdef HAVE_MSGHDR_MSG_CONTROL
1097 hdr.msg_control = ans_data; 1243 hdr.msg_control = ans_data;
1098 hdr.msg_controllen = sizeof(ans_data); 1244 hdr.msg_controllen = sizeof(ans_data);
1245#endif
1099 1246
1100 ret = recvmsg(sock, &hdr, 0); 1247 ret = recvmsg(sock, &hdr, 0);
1101#ifdef SO_TIMESTAMP 1248#ifdef SO_TIMESTAMP
@@ -1125,6 +1272,8 @@ finish(int sig)
1125 {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"}; 1272 {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"};
1126 int hosts_ok = 0; 1273 int hosts_ok = 0;
1127 int hosts_warn = 0; 1274 int hosts_warn = 0;
1275 int this_status;
1276 double R;
1128 1277
1129 alarm(0); 1278 alarm(0);
1130 if(debug > 1) printf("finish(%d) called\n", sig); 1279 if(debug > 1) printf("finish(%d) called\n", sig);
@@ -1140,9 +1289,11 @@ finish(int sig)
1140 } 1289 }
1141 1290
1142 /* iterate thrice to calculate values, give output, and print perfparse */ 1291 /* iterate thrice to calculate values, give output, and print perfparse */
1292 status=STATE_OK;
1143 host = list; 1293 host = list;
1144 1294
1145 while(host) { 1295 while(host) {
1296 this_status = STATE_OK;
1146 if(!host->icmp_recv) { 1297 if(!host->icmp_recv) {
1147 /* rta 0 is ofcourse not entirely correct, but will still show up 1298 /* rta 0 is ofcourse not entirely correct, but will still show up
1148 * conspicuously as missing entries in perfparse and cacti */ 1299 * conspicuously as missing entries in perfparse and cacti */
@@ -1156,21 +1307,107 @@ finish(int sig)
1156 pl = ((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent; 1307 pl = ((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent;
1157 rta = (double)host->time_waited / host->icmp_recv; 1308 rta = (double)host->time_waited / host->icmp_recv;
1158 } 1309 }
1310 if (host->icmp_recv>1) {
1311 host->jitter=(host->jitter / (host->icmp_recv - 1)/1000);
1312 host->EffectiveLatency = (rta/1000) + host->jitter * 2 + 10;
1313 if (host->EffectiveLatency < 160)
1314 R = 93.2 - (host->EffectiveLatency / 40);
1315 else
1316 R = 93.2 - ((host->EffectiveLatency - 120) / 10);
1317 R = R - (pl * 2.5);
1318 if (R<0) R=0;
1319 host->score = R;
1320 host->mos= 1 + ((0.035) * R) + ((.000007) * R * (R-60) * (100-R));
1321 }
1322 else {
1323 host->jitter=0;
1324 host->jitter_min=0;
1325 host->jitter_max=0;
1326 host->mos=0;
1327 }
1159 host->pl = pl; 1328 host->pl = pl;
1160 host->rta = rta; 1329 host->rta = rta;
1161 if(pl >= crit.pl || rta >= crit.rta) { 1330
1162 status = STATE_CRITICAL; 1331 /* if no new mode selected, use old schema */
1332 if (!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && !order_mode) {
1333 rta_mode=1;
1334 pl_mode=1;
1335 }
1336
1337#define THIS_STATUS_WARNING this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status)
1338 /* Check which mode is on and do the warn / Crit stuff */
1339 if (rta_mode) {
1340 if(rta >= crit.rta) {
1341 this_status = STATE_CRITICAL;
1342 status = STATE_CRITICAL;
1343 host->rta_status=STATE_CRITICAL;
1344 }
1345 else if(status!=STATE_CRITICAL && (rta >= warn.rta)) {
1346 THIS_STATUS_WARNING;
1347 status = STATE_WARNING;
1348 host->rta_status=STATE_WARNING;
1349 }
1350 }
1351 if (pl_mode) {
1352 if(pl >= crit.pl) {
1353 this_status = STATE_CRITICAL;
1354 status = STATE_CRITICAL;
1355 host->pl_status=STATE_CRITICAL;
1356 }
1357 else if(status!=STATE_CRITICAL && (pl >= warn.pl)) {
1358 THIS_STATUS_WARNING;
1359 status = STATE_WARNING;
1360 host->pl_status=STATE_WARNING;
1361 }
1362 }
1363 if (jitter_mode) {
1364 if(host->jitter >= crit.jitter) {
1365 this_status = STATE_CRITICAL;
1366 status = STATE_CRITICAL;
1367 host->jitter_status=STATE_CRITICAL;
1368 }
1369 else if(status!=STATE_CRITICAL && (host->jitter >= warn.jitter)) {
1370 THIS_STATUS_WARNING;
1371 status = STATE_WARNING;
1372 host->jitter_status=STATE_WARNING;
1373 }
1163 } 1374 }
1164 else if(!status && (pl >= warn.pl || rta >= warn.rta)) { 1375 if (mos_mode) {
1165 status = STATE_WARNING; 1376 if(host->mos <= crit.mos) {
1377 this_status = STATE_CRITICAL;
1378 status = STATE_CRITICAL;
1379 host->mos_status=STATE_CRITICAL;
1380 }
1381 else if(status!=STATE_CRITICAL && (host->mos <= warn.mos)) {
1382 THIS_STATUS_WARNING;
1383 status = STATE_WARNING;
1384 host->mos_status=STATE_WARNING;
1385 }
1386 }
1387 if (score_mode) {
1388 if(host->score <= crit.score) {
1389 this_status = STATE_CRITICAL;
1390 status = STATE_CRITICAL;
1391 host->score_status=STATE_CRITICAL;
1392 }
1393 else if(status!=STATE_CRITICAL && (host->score <= warn.score)) {
1394 THIS_STATUS_WARNING;
1395 status = STATE_WARNING;
1396 host->score_status=STATE_WARNING;
1397 }
1398 }
1399
1400 if (this_status == STATE_WARNING) {
1166 hosts_warn++; 1401 hosts_warn++;
1167 } 1402 }
1168 else { 1403 else if (this_status == STATE_OK) {
1169 hosts_ok++; 1404 hosts_ok++;
1170 } 1405 }
1171 1406
1172 host = host->next; 1407 host = host->next;
1173 } 1408 }
1409
1410
1174 /* this is inevitable */ 1411 /* this is inevitable */
1175 if(!targets_alive) status = STATE_CRITICAL; 1412 if(!targets_alive) status = STATE_CRITICAL;
1176 if(min_hosts_alive > -1) { 1413 if(min_hosts_alive > -1) {
@@ -1181,6 +1418,7 @@ finish(int sig)
1181 1418
1182 host = list; 1419 host = list;
1183 while(host) { 1420 while(host) {
1421
1184 if(debug) puts(""); 1422 if(debug) puts("");
1185 if(i) { 1423 if(i) {
1186 if(i < targets) printf(" :: "); 1424 if(i < targets) printf(" :: ");
@@ -1189,6 +1427,8 @@ finish(int sig)
1189 i++; 1427 i++;
1190 if(!host->icmp_recv) { 1428 if(!host->icmp_recv) {
1191 status = STATE_CRITICAL; 1429 status = STATE_CRITICAL;
1430 host->rtmin=0;
1431 host->jitter_min=0;
1192 if(host->flags & FLAG_LOST_CAUSE) { 1432 if(host->flags & FLAG_LOST_CAUSE) {
1193 char address[INET6_ADDRSTRLEN]; 1433 char address[INET6_ADDRSTRLEN];
1194 parse_address(&host->error_addr, address, sizeof(address)); 1434 parse_address(&host->error_addr, address, sizeof(address));
@@ -1203,26 +1443,108 @@ finish(int sig)
1203 } 1443 }
1204 } 1444 }
1205 else { /* !icmp_recv */ 1445 else { /* !icmp_recv */
1206 printf("%s: rta %0.3fms, lost %u%%", 1446 printf("%s", host->name);
1207 host->name, host->rta / 1000, host->pl); 1447 /* rta text output */
1448 if (rta_mode) {
1449 if (status == STATE_OK)
1450 printf(" rta %0.3fms", host->rta / 1000);
1451 else if (status==STATE_WARNING && host->rta_status==status)
1452 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, (float)warn.rta/1000);
1453 else if (status==STATE_CRITICAL && host->rta_status==status)
1454 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, (float)crit.rta/1000);
1455 }
1456 /* pl text output */
1457 if (pl_mode) {
1458 if (status == STATE_OK)
1459 printf(" lost %u%%", host->pl);
1460 else if (status==STATE_WARNING && host->pl_status==status)
1461 printf(" lost %u%% > %u%%", host->pl, warn.pl);
1462 else if (status==STATE_CRITICAL && host->pl_status==status)
1463 printf(" lost %u%% > %u%%", host->pl, crit.pl);
1464 }
1465 /* jitter text output */
1466 if (jitter_mode) {
1467 if (status == STATE_OK)
1468 printf(" jitter %0.3fms", (float)host->jitter);
1469 else if (status==STATE_WARNING && host->jitter_status==status)
1470 printf(" jitter %0.3fms > %0.3fms", (float)host->jitter, warn.jitter);
1471 else if (status==STATE_CRITICAL && host->jitter_status==status)
1472 printf(" jitter %0.3fms > %0.3fms", (float)host->jitter, crit.jitter);
1473 }
1474 /* mos text output */
1475 if (mos_mode) {
1476 if (status == STATE_OK)
1477 printf(" MOS %0.1f", (float)host->mos);
1478 else if (status==STATE_WARNING && host->mos_status==status)
1479 printf(" MOS %0.1f < %0.1f", (float)host->mos, (float)warn.mos);
1480 else if (status==STATE_CRITICAL && host->mos_status==status)
1481 printf(" MOS %0.1f < %0.1f", (float)host->mos, (float)crit.mos);
1482 }
1483 /* score text output */
1484 if (score_mode) {
1485 if (status == STATE_OK)
1486 printf(" Score %u", (int)host->score);
1487 else if (status==STATE_WARNING && host->score_status==status )
1488 printf(" Score %u < %u", (int)host->score, (int)warn.score);
1489 else if (status==STATE_CRITICAL && host->score_status==status )
1490 printf(" Score %u < %u", (int)host->score, (int)crit.score);
1491 }
1492 /* order statis text output */
1493 if (order_mode) {
1494 if (status == STATE_OK)
1495 printf(" Packets in order");
1496 else if (status==STATE_CRITICAL && host->order_status==status)
1497 printf(" Packets out of order");
1498 }
1208 } 1499 }
1209
1210 host = host->next; 1500 host = host->next;
1211 } 1501 }
1212 1502
1213 /* iterate once more for pretty perfparse output */ 1503 /* iterate once more for pretty perfparse output */
1214 printf("|"); 1504 if (!(!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && order_mode)) {
1505 printf("|");
1506 }
1215 i = 0; 1507 i = 0;
1216 host = list; 1508 host = list;
1217 while(host) { 1509 while(host) {
1218 if(debug) puts(""); 1510 if(debug) puts("");
1219 printf("%srta=%0.3fms;%0.3f;%0.3f;0; %spl=%u%%;%u;%u;; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ", 1511 if (rta_mode && host->pl<100) {
1512 printf("%srta=%0.3fms;%0.3f;%0.3f;0; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ",
1220 (targets > 1) ? host->name : "", 1513 (targets > 1) ? host->name : "",
1221 host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000, 1514 host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000,
1222 (targets > 1) ? host->name : "", host->pl, warn.pl, crit.pl,
1223 (targets > 1) ? host->name : "", (float)host->rtmax / 1000, 1515 (targets > 1) ? host->name : "", (float)host->rtmax / 1000,
1224 (targets > 1) ? host->name : "", (host->rtmin < INFINITY) ? (float)host->rtmin / 1000 : (float)0); 1516 (targets > 1) ? host->name : "", (host->rtmin < INFINITY) ? (float)host->rtmin / 1000 : (float)0);
1225 1517 }
1518 if (pl_mode) {
1519 printf("%spl=%u%%;%u;%u;0;100 ", (targets > 1) ? host->name : "", host->pl, warn.pl, crit.pl);
1520 }
1521 if (jitter_mode && host->pl<100) {
1522 printf("%sjitter_avg=%0.3fms;%0.3f;%0.3f;0; %sjitter_max=%0.3fms;;;; %sjitter_min=%0.3fms;;;; ",
1523 (targets > 1) ? host->name : "",
1524 (float)host->jitter,
1525 (float)warn.jitter,
1526 (float)crit.jitter,
1527 (targets > 1) ? host->name : "",
1528 (float)host->jitter_max / 1000, (targets > 1) ? host->name : "",
1529 (float)host->jitter_min / 1000
1530 );
1531 }
1532 if (mos_mode && host->pl<100) {
1533 printf("%smos=%0.1f;%0.1f;%0.1f;0;5 ",
1534 (targets > 1) ? host->name : "",
1535 (float)host->mos,
1536 (float)warn.mos,
1537 (float)crit.mos
1538 );
1539 }
1540 if (score_mode && host->pl<100) {
1541 printf("%sscore=%u;%u;%u;0;100 ",
1542 (targets > 1) ? host->name : "",
1543 (int)host->score,
1544 (int)warn.score,
1545 (int)crit.score
1546 );
1547 }
1226 host = host->next; 1548 host = host->next;
1227 } 1549 }
1228 1550
@@ -1312,6 +1634,7 @@ add_target_ip(char *arg, struct sockaddr_storage *in)
1312 /* set the values. use calling name for output */ 1634 /* set the values. use calling name for output */
1313 host->name = strdup(arg); 1635 host->name = strdup(arg);
1314 1636
1637
1315 /* fill out the sockaddr_storage struct */ 1638 /* fill out the sockaddr_storage struct */
1316 if(address_family == AF_INET) { 1639 if(address_family == AF_INET) {
1317 host_sin = (struct sockaddr_in *)&host->saddr_in; 1640 host_sin = (struct sockaddr_in *)&host->saddr_in;
@@ -1324,7 +1647,22 @@ add_target_ip(char *arg, struct sockaddr_storage *in)
1324 memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, sizeof host_sin6->sin6_addr.s6_addr); 1647 memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, sizeof host_sin6->sin6_addr.s6_addr);
1325 } 1648 }
1326 1649
1650 /* fill out the sockaddr_in struct */
1327 host->rtmin = INFINITY; 1651 host->rtmin = INFINITY;
1652 host->rtmax = 0;
1653 host->jitter=0;
1654 host->jitter_max=0;
1655 host->jitter_min=INFINITY;
1656 host->last_tdiff=0;
1657 host->order_status=STATE_OK;
1658 host->last_icmp_seq=0;
1659 host->rta_status=0;
1660 host->pl_status=0;
1661 host->jitter_status=0;
1662 host->mos_status=0;
1663 host->score_status=0;
1664 host->pl_status=0;
1665
1328 1666
1329 if(!list) list = cursor = host; 1667 if(!list) list = cursor = host;
1330 else cursor->next = host; 1668 else cursor->next = host;
@@ -1472,7 +1810,7 @@ get_timevar(const char *str)
1472 1810
1473 /* unit might be given as ms|m (millisec), 1811 /* unit might be given as ms|m (millisec),
1474 * us|u (microsec) or just plain s, for seconds */ 1812 * us|u (microsec) or just plain s, for seconds */
1475 u = p = '\0'; 1813 p = '\0';
1476 u = str[len - 1]; 1814 u = str[len - 1];
1477 if(len >= 2 && !isdigit((int)str[len - 2])) p = str[len - 2]; 1815 if(len >= 2 && !isdigit((int)str[len - 2])) p = str[len - 2];
1478 if(p && u == 's') u = p; 1816 if(p && u == 's') u = p;
@@ -1530,6 +1868,81 @@ get_threshold(char *str, threshold *th)
1530 return 0; 1868 return 0;
1531} 1869}
1532 1870
1871/*
1872 * This functions receives a pointer to a string which should contain a threshold for the
1873 * rta, packet_loss, jitter, mos or score mode in the form number,number[m|%]* assigns the
1874 * parsed number to the corresponding threshold variable.
1875 * @param[in,out] str String containing the given threshold values
1876 * @param[in] length strlen(str)
1877 * @param[out] warn Pointer to the warn threshold struct to which the values should be assigned
1878 * @param[out] crit Pointer to the crit threshold struct to which the values should be assigned
1879 * @param[in] mode Determines whether this a threshold for rta, packet_loss, jitter, mos or score (exclusively)
1880 */
1881static bool get_threshold2(char *str, size_t length, threshold *warn, threshold *crit, threshold_mode mode) {
1882 if (!str || !length || !warn || !crit) return false;
1883
1884
1885 // p points to the last char in str
1886 char *p = &str[length - 1];
1887
1888 // first_iteration is bof-stop on stupid libc's
1889 bool first_iteration = true;
1890
1891 while(p != &str[0]) {
1892 if( (*p == 'm') || (*p == '%') ) {
1893 *p = '\0';
1894 } else if(*p == ',' && !first_iteration) {
1895 *p = '\0'; /* reset it so get_timevar(str) works nicely later */
1896
1897 char *start_of_value = p + 1;
1898
1899 if (!parse_threshold2_helper(start_of_value, strlen(start_of_value), crit, mode)){
1900 return false;
1901 }
1902
1903 }
1904 first_iteration = false;
1905 p--;
1906 }
1907
1908 return parse_threshold2_helper(p, strlen(p), warn, mode);
1909}
1910
1911static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, threshold_mode mode) {
1912 char *resultChecker = {0};
1913
1914 switch (mode) {
1915 case const_rta_mode:
1916 thr->rta = strtod(s, &resultChecker) * 1000;
1917 break;
1918 case const_packet_loss_mode:
1919 thr->pl = (unsigned char)strtoul(s, &resultChecker, 0);
1920 break;
1921 case const_jitter_mode:
1922 thr->jitter = strtod(s, &resultChecker);
1923
1924 break;
1925 case const_mos_mode:
1926 thr->mos = strtod(s, &resultChecker);
1927 break;
1928 case const_score_mode:
1929 thr->score = strtod(s, &resultChecker);
1930 break;
1931 }
1932
1933 if (resultChecker == s) {
1934 // Failed to parse
1935 return false;
1936 }
1937
1938 if (resultChecker != (s + length)) {
1939 // Trailing symbols
1940 return false;
1941 }
1942
1943 return true;
1944}
1945
1533unsigned short 1946unsigned short
1534icmp_checksum(uint16_t *p, size_t n) 1947icmp_checksum(uint16_t *p, size_t n)
1535{ 1948{
@@ -1555,10 +1968,9 @@ icmp_checksum(uint16_t *p, size_t n)
1555void 1968void
1556print_help(void) 1969print_help(void)
1557{ 1970{
1558
1559 /*print_revision (progname);*/ /* FIXME: Why? */ 1971 /*print_revision (progname);*/ /* FIXME: Why? */
1560
1561 printf ("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n"); 1972 printf ("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n");
1973
1562 printf (COPYRIGHT, copyright, email); 1974 printf (COPYRIGHT, copyright, email);
1563 1975
1564 printf ("\n\n"); 1976 printf ("\n\n");
@@ -1578,11 +1990,29 @@ print_help(void)
1578 printf (" %s\n", "-c"); 1990 printf (" %s\n", "-c");
1579 printf (" %s", _("critical threshold (currently ")); 1991 printf (" %s", _("critical threshold (currently "));
1580 printf ("%0.3fms,%u%%)\n", (float)crit.rta / 1000, crit.pl); 1992 printf ("%0.3fms,%u%%)\n", (float)crit.rta / 1000, crit.pl);
1993
1994 printf (" %s\n", "-R");
1995 printf (" %s\n", _("RTA, round trip average, mode warning,critical, ex. 100ms,200ms unit in ms"));
1996 printf (" %s\n", "-P");
1997 printf (" %s\n", _("packet loss mode, ex. 40%,50% , unit in %"));
1998 printf (" %s\n", "-J");
1999 printf (" %s\n", _("jitter mode warning,critical, ex. 40.000ms,50.000ms , unit in ms "));
2000 printf (" %s\n", "-M");
2001 printf (" %s\n", _("MOS mode, between 0 and 4.4 warning,critical, ex. 3.5,3.0"));
2002 printf (" %s\n", "-S");
2003 printf (" %s\n", _("score mode, max value 100 warning,critical, ex. 80,70 "));
2004 printf (" %s\n", "-O");
2005 printf (" %s\n", _("detect out of order ICMP packts "));
2006 printf (" %s\n", "-H");
2007 printf (" %s\n", _("specify a target"));
1581 printf (" %s\n", "-s"); 2008 printf (" %s\n", "-s");
1582 printf (" %s\n", _("specify a source IP address or device name")); 2009 printf (" %s\n", _("specify a source IP address or device name"));
1583 printf (" %s\n", "-n"); 2010 printf (" %s\n", "-n");
1584 printf (" %s", _("number of packets to send (currently ")); 2011 printf (" %s", _("number of packets to send (currently "));
1585 printf ("%u)\n",packets); 2012 printf ("%u)\n",packets);
2013 printf (" %s\n", "-p");
2014 printf (" %s", _("number of packets to send (currently "));
2015 printf ("%u)\n",packets);
1586 printf (" %s\n", "-i"); 2016 printf (" %s\n", "-i");
1587 printf (" %s", _("max packet interval (currently ")); 2017 printf (" %s", _("max packet interval (currently "));
1588 printf ("%0.3fms)\n",(float)pkt_interval / 1000); 2018 printf ("%0.3fms)\n",(float)pkt_interval / 1000);
@@ -1603,9 +2033,9 @@ print_help(void)
1603 printf (" %s %u + %d)\n", _("Packet size will be data bytes + icmp header (currently"),icmp_data_size, ICMP_MINLEN); 2033 printf (" %s %u + %d)\n", _("Packet size will be data bytes + icmp header (currently"),icmp_data_size, ICMP_MINLEN);
1604 printf (" %s\n", "-v"); 2034 printf (" %s\n", "-v");
1605 printf (" %s\n", _("verbose")); 2035 printf (" %s\n", _("verbose"));
1606
1607 printf ("\n"); 2036 printf ("\n");
1608 printf ("%s\n", _("Notes:")); 2037 printf ("%s\n", _("Notes:"));
2038 printf (" %s\n", _("If none of R,P,J,M,S or O is specified, default behavior is -R -P"));
1609 printf (" %s\n", _("The -H switch is optional. Naming a host (or several) to check is not.")); 2039 printf (" %s\n", _("The -H switch is optional. Naming a host (or several) to check is not."));
1610 printf ("\n"); 2040 printf ("\n");
1611 printf (" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%")); 2041 printf (" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%"));