check_icmp.c 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180
  1. /*****************************************************************************
  2. *
  3. * Nagios check_icmp plugin
  4. *
  5. * License: GPL
  6. * Copyright (c) 2005-2008 Nagios Plugins Development Team
  7. * Original Author : Andreas Ericsson
  8. * Jitter, MOS and Score support added by Alessandro Ren
  9. * IPv6 / ICMPv6 support added by Troy Lea aka Box293
  10. * Credit for IPv6 / ICMPv6 code is given to Lars Michelsen as per the GitHib
  11. * commit ec656bf4b3747c0987815d2f3b4ef96bce5613b6.
  12. *
  13. * * Description:
  14. *
  15. * This file contains the check_icmp plugin
  16. *
  17. * Relevant RFC's: 792 (ICMP), 4443 (ICMPv6), 791 (IP), 2460 (IPv6)
  18. *
  19. * This program was modeled somewhat after the check_icmp program,
  20. * which was in turn a hack of fping (www.fping.org) but has been
  21. * completely rewritten since to generate higher precision rta values,
  22. * and support several different modes as well as setting ttl to control.
  23. * redundant routes. The only remainders of fping is currently a few
  24. * function names.
  25. *
  26. *
  27. * This program is free software: you can redistribute it and/or modify
  28. * it under the terms of the GNU General Public License as published by
  29. * the Free Software Foundation, either version 3 of the License, or
  30. * (at your option) any later version.
  31. *
  32. * This program is distributed in the hope that it will be useful,
  33. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  34. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  35. * GNU General Public License for more details.
  36. *
  37. * You should have received a copy of the GNU General Public License
  38. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  39. *
  40. *
  41. *****************************************************************************/
  42. char *progname;
  43. const char *copyright = "2005-2018";
  44. const char *email = "devel@nagios-plugins.org";
  45. #ifdef __sun
  46. #define _XPG4_2
  47. #endif
  48. /* nagios plugins basic includes */
  49. #include "common.h"
  50. #include "netutils.h"
  51. #include "utils.h"
  52. #if HAVE_SYS_SOCKIO_H
  53. #include <sys/sockio.h>
  54. #endif
  55. #include <arpa/inet.h>
  56. #include <ctype.h>
  57. #include <errno.h>
  58. #include <float.h>
  59. #include <net/if.h>
  60. #include <netdb.h>
  61. #include <netinet/icmp6.h>
  62. #include <netinet/in.h>
  63. #include <netinet/in_systm.h>
  64. #include <netinet/ip.h>
  65. #include <netinet/ip6.h>
  66. #include <netinet/ip_icmp.h>
  67. #include <signal.h>
  68. #include <stdarg.h>
  69. #include <stddef.h>
  70. #include <stdio.h>
  71. #include <stdlib.h>
  72. #include <string.h>
  73. #include <sys/ioctl.h>
  74. #include <sys/socket.h>
  75. #include <sys/time.h>
  76. #include <sys/types.h>
  77. #include <unistd.h>
  78. /* sometimes undefined system macros (quite a few, actually) */
  79. #ifndef MAXTTL
  80. #define MAXTTL 255
  81. #endif
  82. #ifndef INADDR_NONE
  83. #define INADDR_NONE (in_addr_t)(-1)
  84. #endif
  85. #ifndef SOL_IP
  86. #define SOL_IP 0
  87. #endif
  88. /* we bundle these in one #ifndef, since they're all from BSD */
  89. /* Put individual #ifndef's around those that bother you */
  90. #ifndef ICMP_UNREACH_NET_UNKNOWN
  91. #define ICMP_UNREACH_NET_UNKNOWN 6
  92. #define ICMP_UNREACH_HOST_UNKNOWN 7
  93. #define ICMP_UNREACH_ISOLATED 8
  94. #define ICMP_UNREACH_NET_PROHIB 9
  95. #define ICMP_UNREACH_HOST_PROHIB 10
  96. #define ICMP_UNREACH_TOSNET 11
  97. #define ICMP_UNREACH_TOSHOST 12
  98. #endif
  99. /* tru64 has the ones above, but not these */
  100. #ifndef ICMP_UNREACH_FILTER_PROHIB
  101. #define ICMP_UNREACH_FILTER_PROHIB 13
  102. #define ICMP_UNREACH_HOST_PRECEDENCE 14
  103. #define ICMP_UNREACH_PRECEDENCE_CUTOFF 15
  104. #endif
  105. #ifndef DBL_MAX
  106. #define DBL_MAX 9.9999999999e999
  107. #endif
  108. typedef unsigned short range_t; /* type for get_range() -- unimplemented */
  109. typedef struct rta_host {
  110. unsigned short id; /* id in **table, and icmp pkts */
  111. char *name; /* arg used for adding this host */
  112. char *msg; /* icmp error message, if any */
  113. struct sockaddr_storage saddr_in; /* the address of this host */
  114. struct sockaddr_storage error_addr; /* stores address of error replies */
  115. unsigned long long time_waited; /* total time waited, in usecs */
  116. unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */
  117. unsigned char icmp_type, icmp_code; /* type and code from errors */
  118. unsigned short flags; /* control/status flags */
  119. double rta; /* measured RTA */
  120. int rta_status;
  121. double rtmax; /* max rtt */
  122. double rtmin; /* min rtt */
  123. double jitter; /* measured jitter */
  124. int jitter_status;
  125. double jitter_max; /* jitter rtt */
  126. double jitter_min; /* jitter rtt */
  127. double EffectiveLatency;
  128. double mos; /* Mean opinion score */
  129. int mos_status;
  130. double score; /* score */
  131. int score_status;
  132. u_int last_tdiff;
  133. u_int last_icmp_seq; /* Last ICMP_SEQ to check out of order pkts */
  134. unsigned char pl; /* measured packet loss */
  135. int pl_status;
  136. struct rta_host *next; /* linked list */
  137. int order_status;
  138. } rta_host;
  139. #define FLAG_LOST_CAUSE 0x01 /* decidedly dead target. */
  140. /* threshold structure. all values are maximum allowed, exclusive */
  141. typedef struct threshold {
  142. unsigned char pl; /* max allowed packet loss in percent */
  143. unsigned int rta; /* roundtrip time average, microseconds */
  144. double jitter; /* jitter time average, microseconds */
  145. double mos; /* MOS */
  146. double score; /* Score */
  147. } threshold;
  148. /* the data structure */
  149. typedef struct icmp_ping_data {
  150. struct timeval stime; /* timestamp (saved in protocol struct as well) */
  151. unsigned short ping_id;
  152. } icmp_ping_data;
  153. typedef union ip_hdr {
  154. struct ip ip;
  155. struct ip6_hdr ip6;
  156. } ip_hdr;
  157. typedef union icmp_packet {
  158. void *buf;
  159. struct icmp *icp;
  160. struct icmp6_hdr *icp6;
  161. u_short *cksum_in;
  162. } icmp_packet;
  163. /* the different modes of this program are as follows:
  164. * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping)
  165. * MODE_HOSTCHECK: Return immediately upon any sign of life
  166. * In addition, sends packets to ALL addresses assigned
  167. * to this host (as returned by gethostbyname() or
  168. * gethostbyaddr() and expects one host only to be checked at
  169. * a time. Therefore, any packet response what so ever will
  170. * count as a sign of life, even when received outside
  171. * crit.rta limit. Do not misspell any additional IP's.
  172. * MODE_ALL: Requires packets from ALL requested IP to return OK (default).
  173. * MODE_ICMP: implement something similar to check_icmp (MODE_RTA without
  174. * tcp and udp args does this)
  175. */
  176. #define MODE_RTA 0
  177. #define MODE_HOSTCHECK 1
  178. #define MODE_ALL 2
  179. #define MODE_ICMP 3
  180. /* the different ping types we can do */
  181. /* TODO: investigate ARP ping as well */
  182. #define HAVE_ICMP 1
  183. #define HAVE_UDP 2
  184. #define HAVE_TCP 4
  185. #define HAVE_ARP 8
  186. #define MIN_PING_DATA_SIZE sizeof(struct icmp_ping_data)
  187. #define MAX_IP_PKT_SIZE 65536 /* (theoretical) max IP packet size */
  188. #define IP_HDR_SIZE 20
  189. #define MAX_PING_DATA (MAX_IP_PKT_SIZE - IP_HDR_SIZE - ICMP_MINLEN)
  190. #define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA_SIZE + 44)
  191. /* various target states */
  192. #define TSTATE_INACTIVE 0x01 /* don't ping this host anymore */
  193. #define TSTATE_WAITING 0x02 /* unanswered packets on the wire */
  194. #define TSTATE_ALIVE 0x04 /* target is alive (has answered something) */
  195. #define TSTATE_UNREACH 0x08
  196. /* prototypes */
  197. void print_help(void);
  198. void print_usage(void);
  199. static u_int get_timevar(const char *);
  200. static u_int get_timevaldiff(struct timeval *, struct timeval *);
  201. static in_addr_t get_ip_address(const char *);
  202. static int wait_for_reply(int, u_int);
  203. static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *,
  204. struct timeval *);
  205. static int send_icmp_ping(int, struct rta_host *);
  206. static int get_threshold(char *str, threshold *th);
  207. static int get_threshold2(char *str, threshold *, threshold *, int type);
  208. static void run_checks(void);
  209. static void set_source_ip(char *);
  210. static int add_target(char *);
  211. static int add_target_ip(char *, struct sockaddr_storage *);
  212. static int handle_random_icmp(unsigned char *, struct sockaddr_storage *);
  213. static unsigned short icmp_checksum(unsigned short *, int);
  214. static void finish(int);
  215. static void crash(const char *, ...);
  216. /* external */
  217. extern int optind, opterr, optopt;
  218. extern char *optarg;
  219. extern char **environ;
  220. /* global variables */
  221. static struct rta_host **table, *cursor, *list;
  222. static threshold crit = {80, 500000}, warn = {40, 200000};
  223. static int mode, protocols, sockets, debug = 0, timeout = 10, perfdata_num=-1, ttl = 0;
  224. static char *perfdata_sep = NULL;
  225. static unsigned short icmp_data_size = DEFAULT_PING_DATA_SIZE;
  226. static unsigned short icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN;
  227. static unsigned int icmp_sent = 0, icmp_recv = 0, icmp_lost = 0;
  228. #define icmp_pkts_en_route (icmp_sent - (icmp_recv + icmp_lost))
  229. static unsigned short targets_down = 0, targets = 0, packets = 0;
  230. #define targets_alive (targets - targets_down)
  231. static unsigned int retry_interval, pkt_interval, target_interval;
  232. static int icmp_sock, tcp_sock, udp_sock, status = STATE_OK;
  233. static pid_t pid;
  234. static struct timezone tz;
  235. static struct timeval prog_start;
  236. static unsigned long long max_completion_time = 0;
  237. static unsigned int warn_down = 1,
  238. crit_down = 1; /* host down threshold values */
  239. static int min_hosts_alive = -1;
  240. float pkt_backoff_factor = 1.5;
  241. float target_backoff_factor = 1.5;
  242. int rta_mode = 0;
  243. int pl_mode = 0;
  244. int jitter_mode = 0;
  245. int score_mode = 0;
  246. int mos_mode = 0;
  247. int order_mode = 0;
  248. /* code start */
  249. static void crash(const char *fmt, ...) {
  250. va_list ap;
  251. printf("%s: ", progname);
  252. va_start(ap, fmt);
  253. vprintf(fmt, ap);
  254. va_end(ap);
  255. if (errno) {
  256. printf(": %s", strerror(errno));
  257. }
  258. puts("");
  259. exit(3);
  260. }
  261. static const char *get_icmp_error_msg(unsigned char icmp_type,
  262. unsigned char icmp_code) {
  263. const char *msg = "unreachable";
  264. if (debug > 1) {
  265. printf("get_icmp_error_msg(%u, %u)\n", icmp_type, icmp_code);
  266. }
  267. switch (icmp_type) {
  268. case ICMP_UNREACH:
  269. switch (icmp_code) {
  270. case ICMP_UNREACH_NET:
  271. msg = "Net unreachable";
  272. break;
  273. case ICMP_UNREACH_HOST:
  274. msg = "Host unreachable";
  275. break;
  276. case ICMP_UNREACH_PROTOCOL:
  277. msg = "Protocol unreachable (firewall?)";
  278. break;
  279. case ICMP_UNREACH_PORT:
  280. msg = "Port unreachable (firewall?)";
  281. break;
  282. case ICMP_UNREACH_NEEDFRAG:
  283. msg = "Fragmentation needed";
  284. break;
  285. case ICMP_UNREACH_SRCFAIL:
  286. msg = "Source route failed";
  287. break;
  288. case ICMP_UNREACH_ISOLATED:
  289. msg = "Source host isolated";
  290. break;
  291. case ICMP_UNREACH_NET_UNKNOWN:
  292. msg = "Unknown network";
  293. break;
  294. case ICMP_UNREACH_HOST_UNKNOWN:
  295. msg = "Unknown host";
  296. break;
  297. case ICMP_UNREACH_NET_PROHIB:
  298. msg = "Network denied (firewall?)";
  299. break;
  300. case ICMP_UNREACH_HOST_PROHIB:
  301. msg = "Host denied (firewall?)";
  302. break;
  303. case ICMP_UNREACH_TOSNET:
  304. msg = "Bad TOS for network (firewall?)";
  305. break;
  306. case ICMP_UNREACH_TOSHOST:
  307. msg = "Bad TOS for host (firewall?)";
  308. break;
  309. case ICMP_UNREACH_FILTER_PROHIB:
  310. msg = "Prohibited by filter (firewall)";
  311. break;
  312. case ICMP_UNREACH_HOST_PRECEDENCE:
  313. msg = "Host precedence violation";
  314. break;
  315. case ICMP_UNREACH_PRECEDENCE_CUTOFF:
  316. msg = "Precedence cutoff";
  317. break;
  318. default:
  319. msg = "Invalid code";
  320. break;
  321. }
  322. break;
  323. case ICMP_TIMXCEED:
  324. /* really 'out of reach', or non-existant host behind a router serving */
  325. /* two different subnets */
  326. switch (icmp_code) {
  327. case ICMP_TIMXCEED_INTRANS:
  328. msg = "Time to live exceeded in transit";
  329. break;
  330. case ICMP_TIMXCEED_REASS:
  331. msg = "Fragment reassembly time exceeded";
  332. break;
  333. default:
  334. msg = "Invalid code";
  335. break;
  336. }
  337. break;
  338. case ICMP_SOURCEQUENCH:
  339. msg = "Transmitting too fast";
  340. break;
  341. case ICMP_REDIRECT:
  342. msg = "Redirect (change route)";
  343. break;
  344. case ICMP_PARAMPROB:
  345. msg = "Bad IP header (required option absent)";
  346. break;
  347. /* the following aren't error messages, so ignore */
  348. case ICMP_TSTAMP:
  349. case ICMP_TSTAMPREPLY:
  350. case ICMP_IREQ:
  351. case ICMP_IREQREPLY:
  352. case ICMP_MASKREQ:
  353. case ICMP_MASKREPLY:
  354. default:
  355. msg = "";
  356. break;
  357. }
  358. return msg;
  359. }
  360. static int handle_random_icmp(unsigned char *packet,
  361. struct sockaddr_storage *addr) {
  362. struct icmp p, sent_icmp;
  363. struct rta_host *host = NULL;
  364. memcpy(&p, packet, sizeof(p));
  365. if (p.icmp_type == ICMP_ECHO && ntohs(p.icmp_id) == pid) {
  366. /* echo request from us to us (pinging localhost) */
  367. return 0;
  368. }
  369. if (debug) {
  370. printf("handle_random_icmp(%p, %p)\n", (void *)&p, (void *)addr);
  371. }
  372. /* only handle a few types, since others can't possibly be replies to
  373. * us in a sane network (if it is anyway, it will be counted as lost
  374. * at summary time, but not as quickly as a proper response */
  375. /* TIMXCEED can be an unreach from a router with multiple IP's which
  376. * serves two different subnets on the same interface and a dead host
  377. * on one net is pinged from the other. The router will respond to
  378. * itself and thus set TTL=0 so as to not loop forever. Even when
  379. * TIMXCEED actually sends a proper icmp response we will have passed
  380. * too many hops to have a hope of reaching it later, in which case it
  381. * indicates overconfidence in the network, poor routing or both. */
  382. if (p.icmp_type != ICMP_UNREACH && p.icmp_type != ICMP_TIMXCEED &&
  383. p.icmp_type != ICMP_SOURCEQUENCH && p.icmp_type != ICMP_PARAMPROB) {
  384. return 0;
  385. }
  386. /* might be for us. At least it holds the original package (according
  387. * to RFC 792). If it isn't, just ignore it */
  388. memcpy(&sent_icmp, packet + 28, sizeof(sent_icmp));
  389. if (sent_icmp.icmp_type != ICMP_ECHO || ntohs(sent_icmp.icmp_id) != pid ||
  390. ntohs(sent_icmp.icmp_seq) >= targets * packets) {
  391. if (debug) {
  392. printf("Packet is no response to a packet we sent\n");
  393. }
  394. return 0;
  395. }
  396. /* it is indeed a response for us */
  397. host = table[ntohs(sent_icmp.icmp_seq) / packets];
  398. if (debug) {
  399. char address[address_length(address_family)];
  400. parse_address_string(address_family, addr, address, sizeof(address));
  401. printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n",
  402. get_icmp_error_msg(p.icmp_type, p.icmp_code), address, host->name);
  403. }
  404. icmp_lost++;
  405. host->icmp_lost++;
  406. /* don't spend time on lost hosts any more */
  407. if (host->flags & FLAG_LOST_CAUSE) {
  408. return 0;
  409. }
  410. /* source quench means we're sending too fast, so increase the */
  411. /* interval and mark this packet lost */
  412. if (p.icmp_type == ICMP_SOURCEQUENCH) {
  413. pkt_interval *= pkt_backoff_factor;
  414. target_interval *= target_backoff_factor;
  415. } else {
  416. targets_down++;
  417. host->flags |= FLAG_LOST_CAUSE;
  418. }
  419. host->icmp_type = p.icmp_type;
  420. host->icmp_code = p.icmp_code;
  421. host->error_addr = *addr;
  422. return 0;
  423. }
  424. int main(int argc, char **argv) {
  425. int i;
  426. char *ptr;
  427. char *bind_address = NULL;
  428. long int arg;
  429. int icmp_sockerrno, udp_sockerrno, tcp_sockerrno;
  430. int result;
  431. struct rta_host *host;
  432. #ifdef HAVE_SIGACTION
  433. struct sigaction sig_action;
  434. #endif
  435. #ifdef SO_TIMESTAMP
  436. int on = 1;
  437. #endif
  438. setlocale(LC_ALL, "");
  439. bindtextdomain(PACKAGE, LOCALEDIR);
  440. textdomain(PACKAGE);
  441. /* print a helpful error message if geteuid != 0 */
  442. np_warn_if_not_root();
  443. /* Set default address_family to AF_INET (IPv4) */
  444. /* It will be changed to AF_INET6 later if required */
  445. address_family = AF_INET;
  446. /* Set default ip_protocol to IPPROTO_ICMP (IPv4) */
  447. /* It will be changed to IPPROTO_ICMPV6 later if required */
  448. int ip_protocol = IPPROTO_ICMP;
  449. /* we only need to be setsuid when we get the sockets, so do
  450. * that before pointer magic (esp. on network data) */
  451. icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0;
  452. /* get calling name the old-fashioned way for portability instead
  453. * of relying on the glibc-ism __progname */
  454. ptr = strrchr(argv[0], '/');
  455. if (ptr) {
  456. progname = &ptr[1];
  457. } else {
  458. progname = argv[0];
  459. }
  460. /* now set defaults. Use progname to set them initially (allows for
  461. * superfast check_host program when target host is up */
  462. cursor = list = NULL;
  463. table = NULL;
  464. mode = MODE_RTA;
  465. /* Default critical thresholds */
  466. crit.rta = 500000;
  467. crit.pl = 80;
  468. crit.jitter = 50;
  469. crit.mos = 3;
  470. crit.score = 70;
  471. /* Default warning thresholds */
  472. warn.rta = 200000;
  473. warn.pl = 40;
  474. warn.jitter = 40;
  475. warn.mos = 3.5;
  476. warn.score = 80;
  477. protocols = HAVE_ICMP | HAVE_UDP | HAVE_TCP;
  478. pkt_interval = 80000; /* 80 msec packet interval by default */
  479. packets = 5;
  480. if (!strcmp(progname, "check_icmp") || !strcmp(progname, "check_ping")) {
  481. mode = MODE_ICMP;
  482. protocols = HAVE_ICMP;
  483. } else if (!strcmp(progname, "check_host")) {
  484. mode = MODE_HOSTCHECK;
  485. pkt_interval = 1000000;
  486. packets = 5;
  487. crit.rta = warn.rta = 1000000;
  488. crit.pl = warn.pl = 100;
  489. } else if (!strcmp(progname, "check_rta_multi")) {
  490. mode = MODE_ALL;
  491. target_interval = 0;
  492. pkt_interval = 50000;
  493. packets = 5;
  494. }
  495. /* parse the arguments */
  496. for (i = 1; i < argc; i++) {
  497. while ((arg = getopt(argc, argv,
  498. "vhVw:c:n:p:t:H:s:i:b:f:F:I:l:m:P:R:J:S:M:O:64")) != EOF) {
  499. long size;
  500. switch (arg) {
  501. case 'v':
  502. debug++;
  503. break;
  504. case 'b':
  505. size = strtol(optarg, NULL, 0);
  506. if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) &&
  507. size < MAX_PING_DATA) {
  508. icmp_data_size = size;
  509. icmp_pkt_size = size + ICMP_MINLEN;
  510. } else {
  511. usage_va("ICMP data length must be between: %d and %d",
  512. sizeof(struct icmp) + sizeof(struct icmp_ping_data),
  513. MAX_PING_DATA - 1);
  514. }
  515. break;
  516. case 'f':
  517. perfdata_sep = optarg;
  518. break;
  519. case 'F':
  520. perfdata_num = strtoul(optarg, NULL, 0);
  521. break;
  522. case 'i':
  523. pkt_interval = get_timevar(optarg);
  524. break;
  525. case 'I':
  526. target_interval = get_timevar(optarg);
  527. break;
  528. case 'w':
  529. get_threshold(optarg, &warn);
  530. break;
  531. case 'c':
  532. get_threshold(optarg, &crit);
  533. break;
  534. case 'n':
  535. case 'p':
  536. packets = strtoul(optarg, NULL, 0);
  537. break;
  538. case 't':
  539. timeout = strtoul(optarg, NULL, 0);
  540. if (!timeout) {
  541. timeout = 10;
  542. }
  543. break;
  544. case '4':
  545. address_family = AF_INET;
  546. ip_protocol = IPPROTO_ICMP;
  547. break;
  548. case '6':
  549. #ifdef USE_IPV6
  550. address_family = AF_INET6;
  551. ip_protocol = IPPROTO_ICMPV6;
  552. #else
  553. usage(_("IPv6 support not available\n"));
  554. #endif
  555. break;
  556. case 'H':
  557. add_target(optarg);
  558. break;
  559. case 'l':
  560. ttl = (int)strtoul(optarg, NULL, 0);
  561. break;
  562. case 'm':
  563. min_hosts_alive = (int)strtoul(optarg, NULL, 0);
  564. break;
  565. case 'd':
  566. /* implement later, for cluster checks */
  567. warn_down = (unsigned char)strtoul(optarg, &ptr, 0);
  568. if (ptr) {
  569. crit_down = (unsigned char)strtoul(ptr + 1, NULL, 0);
  570. }
  571. break;
  572. case 's':
  573. /* specify source IP address */
  574. bind_address = optarg;
  575. break;
  576. case 'V':
  577. /* version */
  578. print_revision(progname, NP_VERSION);
  579. exit(STATE_OK);
  580. case 'h':
  581. /* help */
  582. print_help();
  583. exit(STATE_OK);
  584. case 'R':
  585. /* RTA mode */
  586. get_threshold2(optarg, &warn, &crit, 1);
  587. rta_mode = 1;
  588. break;
  589. case 'P':
  590. /* packet loss mode */
  591. get_threshold2(optarg, &warn, &crit, 2);
  592. pl_mode = 1;
  593. break;
  594. case 'J':
  595. /* packet loss mode */
  596. get_threshold2(optarg, &warn, &crit, 3);
  597. jitter_mode = 1;
  598. break;
  599. case 'M':
  600. /* MOS mode */
  601. get_threshold2(optarg, &warn, &crit, 4);
  602. mos_mode = 1;
  603. break;
  604. case 'S':
  605. /* score mode */
  606. get_threshold2(optarg, &warn, &crit, 5);
  607. score_mode = 1;
  608. break;
  609. case 'O':
  610. /* out of order mode */
  611. order_mode = 1;
  612. break;
  613. }
  614. }
  615. }
  616. if ((icmp_sock = socket(address_family, SOCK_RAW, ip_protocol)) != -1) {
  617. sockets |= HAVE_ICMP;
  618. } else {
  619. icmp_sockerrno = errno;
  620. }
  621. if (bind_address != NULL) {
  622. set_source_ip(bind_address);
  623. }
  624. /* now drop privileges (no effect if not setsuid or geteuid() == 0) */
  625. if (setuid(getuid()) == -1) {
  626. crash("dropping privileges failed");
  627. }
  628. #ifdef SO_TIMESTAMP
  629. if (setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) {
  630. if (debug) {
  631. printf("Warning: no SO_TIMESTAMP support\n");
  632. }
  633. }
  634. #endif /* SO_TIMESTAMP */
  635. /* POSIXLY_CORRECT might break things, so unset it (the portable way) */
  636. environ = NULL;
  637. /* use the pid to mark packets as ours */
  638. /* Some systems have 32-bit pid_t so mask off only 16 bits */
  639. pid = getpid() & 0xffff;
  640. /* printf("pid = %u\n", pid); */
  641. /* Parse extra opts if any */
  642. argv = np_extra_opts(&argc, argv, progname);
  643. /* support "--help" and "--version" */
  644. if (argc == 2) {
  645. if (!strcmp(argv[1], "--help")) {
  646. strcpy(argv[1], "-h");
  647. }
  648. if (!strcmp(argv[1], "--version")) {
  649. strcpy(argv[1], "-V");
  650. }
  651. }
  652. if (debug) {
  653. printf("address_family: %i (IPv4 = 2; IPv6 = 10)\n", address_family);
  654. }
  655. argv = &argv[optind];
  656. while (*argv) {
  657. add_target(*argv);
  658. argv++;
  659. }
  660. if (!targets) {
  661. errno = 0;
  662. crash("No hosts to check");
  663. exit(3);
  664. }
  665. if (!sockets) {
  666. if (icmp_sock == -1) {
  667. errno = icmp_sockerrno;
  668. crash("Failed to obtain ICMP socket");
  669. return -1;
  670. }
  671. /* if(udp_sock == -1) { */
  672. /* errno = icmp_sockerrno; */
  673. /* crash("Failed to obtain UDP socket"); */
  674. /* return -1; */
  675. /* } */
  676. /* if(tcp_sock == -1) { */
  677. /* errno = icmp_sockerrno; */
  678. /* crash("Failed to obtain TCP socket"); */
  679. /* return -1; */
  680. /* } */
  681. }
  682. if (!ttl) {
  683. ttl = 64;
  684. }
  685. if (icmp_sock) {
  686. result = setsockopt(icmp_sock, SOL_IP, IP_TTL, &ttl, sizeof(ttl));
  687. if (debug) {
  688. if (result == -1) {
  689. printf("setsockopt failed\n");
  690. } else {
  691. printf("ttl set to %u\n", ttl);
  692. }
  693. }
  694. }
  695. /* Users should be able to give whatever thresholds they want */
  696. /* (nothing will break if they do), but some plugin maintainer */
  697. /* will probably add some printf() thing here later, so it might be */
  698. /* best to at least show them where to do it */
  699. if (warn.pl > crit.pl) {
  700. warn.pl = crit.pl;
  701. }
  702. if (warn.rta > crit.rta) {
  703. warn.rta = crit.rta;
  704. }
  705. if (warn_down > crit_down) {
  706. crit_down = warn_down;
  707. }
  708. if (warn.jitter > crit.jitter) {
  709. crit.jitter = warn.jitter;
  710. }
  711. if (warn.mos < crit.mos) {
  712. warn.mos = crit.mos;
  713. }
  714. if (warn.score < crit.score) {
  715. warn.score = crit.score;
  716. }
  717. #ifdef HAVE_SIGACTION
  718. sig_action.sa_sigaction = NULL;
  719. sig_action.sa_handler = finish;
  720. sigfillset(&sig_action.sa_mask);
  721. sig_action.sa_flags = SA_NODEFER | SA_RESTART;
  722. sigaction(SIGINT, &sig_action, NULL);
  723. sigaction(SIGHUP, &sig_action, NULL);
  724. sigaction(SIGTERM, &sig_action, NULL);
  725. sigaction(SIGALRM, &sig_action, NULL);
  726. #else /* HAVE_SIGACTION */
  727. signal(SIGINT, finish);
  728. signal(SIGHUP, finish);
  729. signal(SIGTERM, finish);
  730. signal(SIGALRM, finish);
  731. #endif /* HAVE_SIGACTION */
  732. if (debug) {
  733. printf("Setting alarm timeout to %u seconds\n", timeout);
  734. }
  735. alarm(timeout);
  736. /* make sure we don't wait any longer than necessary */
  737. gettimeofday(&prog_start, &tz);
  738. max_completion_time =
  739. ((targets * packets * pkt_interval) + (targets * target_interval)) +
  740. (targets * packets * crit.rta) + crit.rta;
  741. if (debug) {
  742. printf("packets: %u, targets: %u\n"
  743. "target_interval: %0.3f, pkt_interval %0.3f\n"
  744. "crit.rta: %0.3f\n"
  745. "max_completion_time: %0.3f\n",
  746. packets, targets, (float)target_interval / 1000,
  747. (float)pkt_interval / 1000, (float)crit.rta / 1000,
  748. (float)max_completion_time / 1000);
  749. }
  750. if (debug) {
  751. if (max_completion_time > (u_int)timeout * 1000000) {
  752. printf("max_completion_time: %llu timeout: %u\n", max_completion_time,
  753. timeout);
  754. printf("Timout must be at least %llu\n",
  755. max_completion_time / 1000000 + 1);
  756. }
  757. }
  758. if (debug) {
  759. printf("crit = {%u, %u%%}, warn = {%u, %u%%}\n", crit.rta, crit.pl,
  760. warn.rta, warn.pl);
  761. printf("pkt_interval: %u target_interval: %u retry_interval: %u\n",
  762. pkt_interval, target_interval, retry_interval);
  763. printf("icmp_pkt_size: %u timeout: %u\n", icmp_pkt_size, timeout);
  764. }
  765. if (packets > 20) {
  766. errno = 0;
  767. crash("packets is > 20 (%d)", packets);
  768. }
  769. if (min_hosts_alive < -1) {
  770. errno = 0;
  771. crash("minimum alive hosts is negative (%i)", min_hosts_alive);
  772. }
  773. host = list;
  774. table = (struct rta_host **)malloc(sizeof(struct rta_host **) * targets);
  775. i = 0;
  776. while (host) {
  777. host->id = i * packets;
  778. table[i] = host;
  779. host = host->next;
  780. i++;
  781. }
  782. run_checks();
  783. errno = 0;
  784. finish(0);
  785. return (0);
  786. }
  787. static void run_checks() {
  788. u_int i, t, result;
  789. u_int final_wait, time_passed;
  790. /* this loop might actually violate the pkt_interval or target_interval
  791. * settings, but only if there aren't any packets on the wire which
  792. * indicates that the target can handle an increased packet rate */
  793. for (i = 0; i < packets; i++) {
  794. for (t = 0; t < targets; t++) {
  795. /* don't send useless packets */
  796. if (!targets_alive) {
  797. finish(0);
  798. }
  799. if (table[t]->flags & FLAG_LOST_CAUSE) {
  800. if (debug) {
  801. printf("%s is a lost cause. not sending any more\n", table[t]->name);
  802. }
  803. continue;
  804. }
  805. /* we're still in the game, so send next packet */
  806. (void)send_icmp_ping(icmp_sock, table[t]);
  807. result = wait_for_reply(icmp_sock, target_interval);
  808. }
  809. result = wait_for_reply(icmp_sock, pkt_interval * targets);
  810. }
  811. if (icmp_pkts_en_route && targets_alive) {
  812. time_passed = get_timevaldiff(NULL, NULL);
  813. final_wait = max_completion_time - time_passed;
  814. if (debug) {
  815. printf("time_passed: %u final_wait: %u max_completion_time: %llu\n",
  816. time_passed, final_wait, max_completion_time);
  817. }
  818. if (time_passed > max_completion_time) {
  819. if (debug) {
  820. printf("Time passed. Finishing up\n");
  821. }
  822. finish(0);
  823. }
  824. /* catch the packets that might come in within the timeframe, but
  825. * haven't yet */
  826. if (debug) {
  827. printf("Waiting for %u micro-seconds (%0.3f msecs)\n", final_wait,
  828. (float)final_wait / 1000);
  829. }
  830. result = wait_for_reply(icmp_sock, final_wait);
  831. }
  832. }
  833. /* Response Structure: */
  834. /* IPv4: */
  835. /* ip header (total length) : 20 bytes */
  836. /* IPv6: */
  837. /* ip header (payload length) : 40 bytes */
  838. /* Both: */
  839. /* icmp header : 28 bytes */
  840. /* icmp echo reply : the rest */
  841. static int wait_for_reply(int sock, u_int t) {
  842. int n, hlen = 0;
  843. static unsigned char buf[4096];
  844. struct sockaddr_storage resp_addr;
  845. union ip_hdr *ip;
  846. union icmp_packet packet;
  847. struct rta_host *host = NULL;
  848. struct icmp_ping_data data;
  849. struct timeval wait_start, now;
  850. u_int tdiff, i, per_pkt_wait;
  851. double jitter_tmp;
  852. if (!(packet.buf = malloc(icmp_pkt_size))) {
  853. crash("send_icmp_ping(): failed to malloc %d bytes for send buffer",
  854. icmp_pkt_size);
  855. return -1; /* might be reached if we're in debug mode */
  856. }
  857. memset(packet.buf, 0, icmp_pkt_size);
  858. /* if we can't listen or don't have anything to listen to, just return */
  859. if (!t || !icmp_pkts_en_route) {
  860. free(packet.buf);
  861. return 0;
  862. }
  863. gettimeofday(&wait_start, &tz);
  864. i = t;
  865. per_pkt_wait = t / icmp_pkts_en_route;
  866. while (icmp_pkts_en_route && get_timevaldiff(&wait_start, NULL) < i) {
  867. t = per_pkt_wait;
  868. /* wrap up if all targets are declared dead */
  869. if (!targets_alive ||
  870. get_timevaldiff(&prog_start, NULL) >= max_completion_time ||
  871. (mode == MODE_HOSTCHECK && targets_down)) {
  872. finish(0);
  873. }
  874. /* reap responses until we hit a timeout */
  875. n = recvfrom_wto(sock, buf, sizeof(buf), (struct sockaddr *)&resp_addr, &t,
  876. &now);
  877. if (!n) {
  878. if (debug > 1) {
  879. printf("recvfrom_wto() timed out during a %u usecs wait\n",
  880. per_pkt_wait);
  881. }
  882. continue; /* timeout for this one, so keep trying */
  883. }
  884. if (n < 0) {
  885. if (debug) {
  886. printf("recvfrom_wto() returned errors\n");
  887. }
  888. return n;
  889. }
  890. ip = (union ip_hdr *)buf;
  891. if (debug > 1) {
  892. char address[address_length(address_family)];
  893. parse_address_string(address_family, &resp_addr, address,
  894. sizeof(address));
  895. if (address_family == AF_INET) {
  896. printf("received %u bytes from %s\n", ntohs(ip->ip.ip_len), address);
  897. } else if (address_family == AF_INET6) {
  898. printf("received %u bytes from %s\n", ntohs(ip->ip6.ip6_plen), address);
  899. }
  900. }
  901. /* IPv6 doesn't have a header length, it's a payload length */
  902. if (address_family == AF_INET) {
  903. hlen = ip->ip.ip_hl << 2;
  904. } else if (address_family == AF_INET6) {
  905. hlen = 0;
  906. }
  907. if (n < (hlen + ICMP_MINLEN)) {
  908. char address[address_length(address_family)];
  909. parse_address_string(address_family, &resp_addr, address,
  910. sizeof(address));
  911. crash("received packet too short for ICMP (%d bytes, expected %d) from "
  912. "%s\n",
  913. n, hlen + icmp_pkt_size, address);
  914. }
  915. /* check the response */
  916. memcpy(packet.buf, buf + hlen, icmp_pkt_size);
  917. if ((address_family == AF_INET &&
  918. (ntohs(packet.icp->icmp_id) != pid ||
  919. packet.icp->icmp_type != ICMP_ECHOREPLY ||
  920. ntohs(packet.icp->icmp_seq) >= targets * packets)) ||
  921. (address_family == AF_INET6 &&
  922. (ntohs(packet.icp6->icmp6_id) != pid ||
  923. packet.icp6->icmp6_type != ICMP6_ECHO_REPLY ||
  924. ntohs(packet.icp6->icmp6_seq) >= targets * packets))) {
  925. if (debug > 2) {
  926. printf("not a proper ICMP_ECHOREPLY\n");
  927. }
  928. handle_random_icmp(buf + hlen, &resp_addr);
  929. continue;
  930. }
  931. /* this is indeed a valid response */
  932. if (address_family == AF_INET) {
  933. memcpy(&data, packet.icp->icmp_data, sizeof(data));
  934. if (debug > 2) {
  935. printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n",
  936. (unsigned long)sizeof(data), ntohs(packet.icp->icmp_id),
  937. ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum);
  938. }
  939. host = table[ntohs(packet.icp->icmp_seq) / packets];
  940. } else if (address_family == AF_INET6) {
  941. memcpy(&data, &packet.icp6->icmp6_dataun.icmp6_un_data8[4], sizeof(data));
  942. if (debug > 2) {
  943. printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n",
  944. (unsigned long)sizeof(data), ntohs(packet.icp6->icmp6_id),
  945. ntohs(packet.icp6->icmp6_seq), packet.icp6->icmp6_cksum);
  946. }
  947. host = table[ntohs(packet.icp6->icmp6_seq) / packets];
  948. }
  949. tdiff = get_timevaldiff(&data.stime, &now);
  950. if (host->last_tdiff > 0) {
  951. /* Calculate jitter */
  952. if (host->last_tdiff > tdiff) {
  953. jitter_tmp = host->last_tdiff - tdiff;
  954. } else {
  955. jitter_tmp = tdiff - host->last_tdiff;
  956. }
  957. if (host->jitter == 0) {
  958. host->jitter = jitter_tmp;
  959. host->jitter_max = jitter_tmp;
  960. host->jitter_min = jitter_tmp;
  961. } else {
  962. host->jitter += jitter_tmp;
  963. if (jitter_tmp < host->jitter_min) {
  964. host->jitter_min = jitter_tmp;
  965. }
  966. if (jitter_tmp > host->jitter_max) {
  967. host->jitter_max = jitter_tmp;
  968. }
  969. }
  970. /* Check if packets in order */
  971. if (host->last_icmp_seq >= packet.icp->icmp_seq) {
  972. host->order_status = STATE_CRITICAL;
  973. }
  974. }
  975. host->last_tdiff = tdiff;
  976. host->last_icmp_seq = packet.icp->icmp_seq;
  977. host->time_waited += tdiff;
  978. host->icmp_recv++;
  979. icmp_recv++;
  980. if (tdiff > (int)host->rtmax) {
  981. host->rtmax = tdiff;
  982. }
  983. if (tdiff < (int)host->rtmin) {
  984. host->rtmin = tdiff;
  985. }
  986. if (debug) {
  987. char address[address_length(address_family)];
  988. parse_address_string(address_family, &resp_addr, address,
  989. sizeof(address));
  990. printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u, max: "
  991. "%0.3f, min: %0.3f\n",
  992. (float)tdiff / 1000, address, ttl, ip->ip.ip_ttl,
  993. (float)host->rtmax / 1000, (float)host->rtmin / 1000);
  994. }
  995. /* if we're in hostcheck mode, exit with limited printouts */
  996. if (mode == MODE_HOSTCHECK) {
  997. printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|"
  998. "pkt=%u;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n",
  999. host->name, icmp_recv, (float)tdiff / 1000, icmp_recv, packets,
  1000. (float)tdiff / 1000, (float)warn.rta / 1000,
  1001. (float)crit.rta / 1000);
  1002. exit(STATE_OK);
  1003. }
  1004. }
  1005. return 0;
  1006. }
  1007. /* the ping functions */
  1008. static int send_icmp_ping(int sock, struct rta_host *host) {
  1009. long int len;
  1010. struct icmp_ping_data data;
  1011. struct msghdr hdr;
  1012. struct iovec iov;
  1013. struct timeval tv;
  1014. size_t addrlen;
  1015. void *buf = NULL;
  1016. if (sock == -1) {
  1017. errno = 0;
  1018. crash("Attempt to send on bogus socket");
  1019. return -1;
  1020. }
  1021. if (!buf) {
  1022. if (!(buf = malloc(icmp_pkt_size))) {
  1023. crash("send_icmp_ping(): failed to malloc %d bytes for send buffer",
  1024. icmp_pkt_size);
  1025. return -1; /* might be reached if we're in debug mode */
  1026. }
  1027. }
  1028. memset(buf, 0, icmp_pkt_size);
  1029. if ((gettimeofday(&tv, &tz)) == -1) {
  1030. free(buf);
  1031. return -1;
  1032. }
  1033. data.ping_id = 10; /* host->icmp.icmp_sent; */
  1034. memcpy(&data.stime, &tv, sizeof(tv));
  1035. if (address_family == AF_INET) {
  1036. struct icmp *icp = (struct icmp *)buf;
  1037. addrlen = sizeof(struct sockaddr_in);
  1038. memcpy(&icp->icmp_data, &data, sizeof(data));
  1039. icp->icmp_type = ICMP_ECHO;
  1040. icp->icmp_code = 0;
  1041. icp->icmp_cksum = 0;
  1042. icp->icmp_id = htons(pid);
  1043. icp->icmp_seq = htons(host->id++);
  1044. icp->icmp_cksum = icmp_checksum((unsigned short *)buf, icmp_pkt_size);
  1045. if (debug > 2) {
  1046. printf("Sending ICMPv4 echo-request of len %lu, id %u, seq %u, cksum "
  1047. "0x%X to host %s\n",
  1048. (unsigned long)sizeof(data), ntohs(icp->icmp_id),
  1049. ntohs(icp->icmp_seq), icp->icmp_cksum, host->name);
  1050. }
  1051. } else if (address_family == AF_INET6) {
  1052. struct icmp6_hdr *icp6 = (struct icmp6_hdr *)buf;
  1053. addrlen = sizeof(struct sockaddr_in6);
  1054. memcpy(&icp6->icmp6_dataun.icmp6_un_data8[4], &data, sizeof(data));
  1055. icp6->icmp6_type = ICMP6_ECHO_REQUEST;
  1056. icp6->icmp6_code = 0;
  1057. icp6->icmp6_cksum = 0;
  1058. icp6->icmp6_id = htons(pid);
  1059. icp6->icmp6_seq = htons(host->id++);
  1060. /* checksum is calculated automatically */
  1061. if (debug > 2) {
  1062. printf("Sending ICMPv6 echo-request of len %lu, id %u, seq %u, cksum "
  1063. "0x%X to host %s\n",
  1064. (unsigned long)sizeof(data), ntohs(icp6->icmp6_id),
  1065. ntohs(icp6->icmp6_seq), icp6->icmp6_cksum, host->name);
  1066. }
  1067. }
  1068. memset(&iov, 0, sizeof(iov));
  1069. iov.iov_base = buf;
  1070. iov.iov_len = icmp_pkt_size;
  1071. memset(&hdr, 0, sizeof(hdr));
  1072. hdr.msg_name = (struct sockaddr *)&host->saddr_in;
  1073. hdr.msg_namelen = addrlen;
  1074. hdr.msg_iov = &iov;
  1075. hdr.msg_iovlen = 1;
  1076. errno = 0;
  1077. /* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15,
  1078. * see send(2) */
  1079. #ifdef MSG_CONFIRM
  1080. len = sendmsg(sock, &hdr, MSG_CONFIRM);
  1081. #else
  1082. len = sendmsg(sock, &hdr, 0);
  1083. #endif
  1084. free(buf);
  1085. if (len < 0 || (unsigned int)len != icmp_pkt_size) {
  1086. if (debug) {
  1087. char address[address_length(address_family)];
  1088. parse_address_string(address_family,
  1089. (struct sockaddr_storage *)&host->saddr_in, address,
  1090. sizeof(address));
  1091. printf("Failed to send ping to %s = %s\n", address, strerror(errno));
  1092. }
  1093. errno = 0;
  1094. return -1;
  1095. }
  1096. icmp_sent++;
  1097. host->icmp_sent++;
  1098. return 0;
  1099. }
  1100. static int recvfrom_wto(int sock, void *buf, unsigned int len,
  1101. struct sockaddr *saddr, u_int *timo,
  1102. struct timeval *tv) {
  1103. u_int slen;
  1104. int n, ret;
  1105. struct timeval to, then, now;
  1106. fd_set rd, wr;
  1107. char ans_data[4096];
  1108. struct msghdr hdr;
  1109. struct iovec iov;
  1110. #ifdef SO_TIMESTAMP
  1111. struct cmsghdr *chdr;
  1112. #endif
  1113. if (!*timo) {
  1114. if (debug)
  1115. printf("*timo is not\n");
  1116. return 0;
  1117. }
  1118. to.tv_sec = *timo / 1000000;
  1119. to.tv_usec = (*timo - (to.tv_sec * 1000000));
  1120. FD_ZERO(&rd);
  1121. FD_ZERO(&wr);
  1122. FD_SET(sock, &rd);
  1123. errno = 0;
  1124. gettimeofday(&then, &tz);
  1125. n = select(sock + 1, &rd, &wr, NULL, &to);
  1126. if (n < 0) {
  1127. crash("select() in recvfrom_wto");
  1128. }
  1129. gettimeofday(&now, &tz);
  1130. *timo = get_timevaldiff(&then, &now);
  1131. if (!n) {
  1132. /* timeout */
  1133. return 0;
  1134. }
  1135. slen = sizeof(struct sockaddr_storage);
  1136. memset(&iov, 0, sizeof(iov));
  1137. iov.iov_base = buf;
  1138. iov.iov_len = len;
  1139. memset(&hdr, 0, sizeof(hdr));
  1140. hdr.msg_name = saddr;
  1141. hdr.msg_namelen = slen;
  1142. hdr.msg_iov = &iov;
  1143. hdr.msg_iovlen = 1;
  1144. #ifdef HAVE_MSGHDR_MSG_CONTROL
  1145. hdr.msg_control = ans_data;
  1146. hdr.msg_controllen = sizeof(ans_data);
  1147. #endif
  1148. ret = recvmsg(sock, &hdr, 0);
  1149. #ifdef SO_TIMESTAMP
  1150. for (chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) {
  1151. if (chdr->cmsg_level == SOL_SOCKET && chdr->cmsg_type == SO_TIMESTAMP &&
  1152. chdr->cmsg_len >= CMSG_LEN(sizeof(struct timeval))) {
  1153. memcpy(tv, CMSG_DATA(chdr), sizeof(*tv));
  1154. break;
  1155. }
  1156. }
  1157. #endif /* SO_TIMESTAMP */
  1158. if (!chdr) {
  1159. gettimeofday(tv, &tz);
  1160. }
  1161. return (ret);
  1162. }
  1163. static void finish(int sig) {
  1164. u_int i = 0;
  1165. unsigned char pl;
  1166. double rta;
  1167. struct rta_host *host;
  1168. const char *status_string[] = {"OK", "WARNING", "CRITICAL", "UNKNOWN",
  1169. "DEPENDENT"};
  1170. int hosts_ok = 0;
  1171. int hosts_warn = 0;
  1172. int this_status;
  1173. double R;
  1174. alarm(0);
  1175. if (debug > 1) {
  1176. printf("finish(%d) called\n", sig);
  1177. }
  1178. if (icmp_sock != -1) {
  1179. close(icmp_sock);
  1180. }
  1181. if (udp_sock != -1) {
  1182. close(udp_sock);
  1183. }
  1184. if (tcp_sock != -1) {
  1185. close(tcp_sock);
  1186. }
  1187. if (debug) {
  1188. printf("icmp_sent: %u icmp_recv: %u icmp_lost: %u\n", icmp_sent,
  1189. icmp_recv, icmp_lost);
  1190. printf("targets: %u targets_alive: %u\n", targets, targets_alive);
  1191. }
  1192. /* iterate thrice to calculate values, give output, and print perfparse */
  1193. status = STATE_OK;
  1194. host = list;
  1195. while (host) {
  1196. this_status = STATE_OK;
  1197. if (!host->icmp_recv) {
  1198. /* rta 0 is ofcourse not entirely correct, but will still show up
  1199. * conspicuosly as missing entries in perfparse and cacti */
  1200. pl = 100;
  1201. rta = 0;
  1202. status = STATE_CRITICAL;
  1203. /* up the down counter if not already counted */
  1204. if (!(host->flags & FLAG_LOST_CAUSE) && targets_alive) {
  1205. targets_down++;
  1206. }
  1207. } else {
  1208. pl = ((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent;
  1209. rta = (double)host->time_waited / host->icmp_recv;
  1210. }
  1211. if (host->icmp_recv > 1) {
  1212. host->jitter = (host->jitter / (host->icmp_recv - 1) / 1000);
  1213. host->EffectiveLatency = (rta / 1000) + host->jitter * 2 + 10;
  1214. if (host->EffectiveLatency < 160) {
  1215. R = 93.2 - (host->EffectiveLatency / 40);
  1216. } else {
  1217. R = 93.2 - ((host->EffectiveLatency - 120) / 10);
  1218. }
  1219. R = R - (pl * 2.5);
  1220. if (R < 0) {
  1221. R = 0;
  1222. }
  1223. host->score = R;
  1224. host->mos = 1 + ((0.035) * R) + ((.000007) * R * (R - 60) * (100 - R));
  1225. } else {
  1226. host->jitter = 0;
  1227. host->jitter_min = 0;
  1228. host->jitter_max = 0;
  1229. host->mos = 0;
  1230. }
  1231. host->pl = pl;
  1232. host->rta = rta;
  1233. /* if no new mode selected, use old schema */
  1234. if (!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode &&
  1235. !order_mode) {
  1236. rta_mode = 1;
  1237. pl_mode = 1;
  1238. }
  1239. /* Check which mode is on and do the warn / Crit stuff */
  1240. if (rta_mode) {
  1241. if (rta >= crit.rta) {
  1242. this_status = STATE_CRITICAL;
  1243. status = STATE_CRITICAL;
  1244. host->rta_status = STATE_CRITICAL;
  1245. } else if (status != STATE_CRITICAL && (rta >= warn.rta)) {
  1246. this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
  1247. status = STATE_WARNING;
  1248. host->rta_status = STATE_WARNING;
  1249. }
  1250. }
  1251. if (pl_mode) {
  1252. if (pl >= crit.pl) {
  1253. this_status = STATE_CRITICAL;
  1254. status = STATE_CRITICAL;
  1255. host->pl_status = STATE_CRITICAL;
  1256. } else if (status != STATE_CRITICAL && (pl >= warn.pl)) {
  1257. this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
  1258. status = STATE_WARNING;
  1259. host->pl_status = STATE_WARNING;
  1260. }
  1261. }
  1262. if (jitter_mode) {
  1263. if (host->jitter >= crit.jitter) {
  1264. this_status = STATE_CRITICAL;
  1265. status = STATE_CRITICAL;
  1266. host->jitter_status = STATE_CRITICAL;
  1267. } else if (status != STATE_CRITICAL && (host->jitter >= warn.jitter)) {
  1268. this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
  1269. status = STATE_WARNING;
  1270. host->jitter_status = STATE_WARNING;
  1271. }
  1272. }
  1273. if (mos_mode) {
  1274. if (host->mos <= crit.mos) {
  1275. this_status = STATE_CRITICAL;
  1276. status = STATE_CRITICAL;
  1277. host->mos_status = STATE_CRITICAL;
  1278. } else if (status != STATE_CRITICAL && (host->mos <= warn.mos)) {
  1279. this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
  1280. status = STATE_WARNING;
  1281. host->mos_status = STATE_WARNING;
  1282. }
  1283. }
  1284. if (score_mode) {
  1285. if (host->score <= crit.score) {
  1286. this_status = STATE_CRITICAL;
  1287. status = STATE_CRITICAL;
  1288. host->score_status = STATE_CRITICAL;
  1289. } else if (status != STATE_CRITICAL && (host->score <= warn.score)) {
  1290. this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
  1291. status = STATE_WARNING;
  1292. host->score_status = STATE_WARNING;
  1293. }
  1294. }
  1295. if (this_status == STATE_WARNING) {
  1296. hosts_warn++;
  1297. }
  1298. else if (this_status == STATE_OK) {
  1299. hosts_ok++;
  1300. }
  1301. host = host->next;
  1302. }
  1303. /* this is inevitable */
  1304. if (!targets_alive) {
  1305. status = STATE_CRITICAL;
  1306. }
  1307. if (min_hosts_alive > -1) {
  1308. if (hosts_ok >= min_hosts_alive) {
  1309. status = STATE_OK;
  1310. } else if ((hosts_ok + hosts_warn) >= min_hosts_alive) {
  1311. status = STATE_WARNING;
  1312. }
  1313. }
  1314. printf("%s - ", status_string[status]);
  1315. host = list;
  1316. while (host) {
  1317. if (debug) {
  1318. puts("");
  1319. }
  1320. if (i) {
  1321. if (i < targets) {
  1322. printf(" :: ");
  1323. } else {
  1324. printf("\n");
  1325. }
  1326. }
  1327. i++;
  1328. if (!host->icmp_recv) {
  1329. status = STATE_CRITICAL;
  1330. host->rtmin = 0;
  1331. host->jitter_min = 0;
  1332. if (host->flags & FLAG_LOST_CAUSE) {
  1333. char address[address_length(address_family)];
  1334. parse_address_string(address_family, &host->error_addr, address,
  1335. sizeof(address));
  1336. printf("%s: %s @ %s. rta nan, lost %d%%", host->name,
  1337. get_icmp_error_msg(host->icmp_type, host->icmp_code), address,
  1338. 100);
  1339. } else {
  1340. /* not marked as lost cause, so we have no flags for it */
  1341. printf("%s: rta nan, lost 100%%", host->name);
  1342. }
  1343. } else {
  1344. /* !icmp_recv */
  1345. printf("%s:", host->name);
  1346. /* rta text output */
  1347. if (rta_mode) {
  1348. if (status == STATE_OK) {
  1349. printf(" rta %0.3fms", host->rta / 1000);
  1350. } else if (status == STATE_WARNING && host->rta_status == status) {
  1351. printf(" rta %0.3fms >= %0.3fms", (float)host->rta / 1000,
  1352. (float)warn.rta / 1000);
  1353. } else if (status == STATE_CRITICAL && host->rta_status == status) {
  1354. printf(" rta %0.3fms >= %0.3fms", (float)host->rta / 1000,
  1355. (float)crit.rta / 1000);
  1356. }
  1357. }
  1358. /* pl text output */
  1359. if (pl_mode) {
  1360. if (status == STATE_OK) {
  1361. printf(" lost %u%%", host->pl);
  1362. } else if (status == STATE_WARNING && host->pl_status == status) {
  1363. printf(" lost %u%% >= %u%%", host->pl, warn.pl);
  1364. } else if (status == STATE_CRITICAL && host->pl_status == status) {
  1365. printf(" lost %u%% >= %u%%", host->pl, crit.pl);
  1366. }
  1367. }
  1368. /* jitter text output */
  1369. if (jitter_mode) {
  1370. if (status == STATE_OK) {
  1371. printf(" jitter %0.3fms", (float)host->jitter);
  1372. } else if (status == STATE_WARNING && host->jitter_status == status) {
  1373. printf(" jitter %0.3fms >= %0.3fms", (float)host->jitter, warn.jitter);
  1374. } else if (status == STATE_CRITICAL && host->jitter_status == status) {
  1375. printf(" jitter %0.3fms >= %0.3fms", (float)host->jitter, crit.jitter);
  1376. }
  1377. }
  1378. /* mos text output */
  1379. if (mos_mode) {
  1380. if (status == STATE_OK) {
  1381. printf(" MOS %0.1f", (float)host->mos);
  1382. } else if (status == STATE_WARNING && host->mos_status == status) {
  1383. printf(" MOS %0.1f <= %0.1f", (float)host->mos, (float)warn.mos);
  1384. } else if (status == STATE_CRITICAL && host->mos_status == status) {
  1385. printf(" MOS %0.1f <= %0.1f", (float)host->mos, (float)crit.mos);
  1386. }
  1387. }
  1388. /* score text output */
  1389. if (score_mode) {
  1390. if (status == STATE_OK) {
  1391. printf(" Score %u", (int)host->score);
  1392. } else if (status == STATE_WARNING && host->score_status == status) {
  1393. printf(" Score %u <= %u", (int)host->score, (int)warn.score);
  1394. } else if (status == STATE_CRITICAL && host->score_status == status) {
  1395. printf(" Score %u <= %u", (int)host->score, (int)crit.score);
  1396. }
  1397. }
  1398. /* order statis text output */
  1399. if (order_mode) {
  1400. if (status == STATE_OK) {
  1401. printf(" Packets in order");
  1402. } else if (status == STATE_CRITICAL && host->order_status == status) {
  1403. printf(" Packets out of order");
  1404. }
  1405. }
  1406. }
  1407. host = host->next;
  1408. }
  1409. /* iterate once more for pretty perfparse output */
  1410. if (!(!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode &&
  1411. order_mode)) {
  1412. printf("|");
  1413. }
  1414. i = 0;
  1415. host = list;
  1416. while (host) {
  1417. i++;
  1418. if (i > perfdata_num && perfdata_num > -1)
  1419. break;
  1420. if (debug) {
  1421. puts("");
  1422. }
  1423. if (rta_mode) {
  1424. printf("%s%srta=%0.3fms;%0.3f;%0.3f;0; ",
  1425. (targets > 1 || perfdata_sep != NULL) ? host->name : "",
  1426. (perfdata_sep != NULL) ? perfdata_sep : "",
  1427. (float)host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000);
  1428. }
  1429. if (pl_mode) {
  1430. printf("%s%spl=%u%%;%u;%u;0;100 ",
  1431. (targets > 1 || perfdata_sep != NULL) ? host->name : "",
  1432. (perfdata_sep != NULL) ? perfdata_sep : "",
  1433. host->pl, warn.pl, crit.pl);
  1434. }
  1435. if (rta_mode) {
  1436. printf("%s%srtmax=%0.3fms;;;; %s%srtmin=%0.3fms;;;; ",
  1437. (targets > 1 || perfdata_sep != NULL) ? host->name : "",
  1438. (perfdata_sep != NULL) ? perfdata_sep : "",
  1439. (float)host->rtmax / 1000,
  1440. (targets > 1 || perfdata_sep != NULL) ? host->name : "",
  1441. (perfdata_sep != NULL) ? perfdata_sep : "",
  1442. (float)host->rtmin / 1000);
  1443. }
  1444. if (jitter_mode) {
  1445. printf("%s%sjitter_avg=%0.3fms;%0.3f;%0.3f;0; %s%sjitter_max=%0.3fms;;;; "
  1446. "%s%sjitter_min=%0.3fms;;;; ",
  1447. (targets > 1 || perfdata_sep != NULL) ? host->name : "",
  1448. (perfdata_sep != NULL) ? perfdata_sep : "",
  1449. (float)host->jitter, (float)warn.jitter, (float)crit.jitter,
  1450. (targets > 1 || perfdata_sep != NULL) ? host->name : "",
  1451. (perfdata_sep != NULL) ? perfdata_sep : "",
  1452. (float)host->jitter_max / 1000,
  1453. (targets > 1 || perfdata_sep != NULL) ? host->name : "",
  1454. (perfdata_sep != NULL) ? perfdata_sep : "",
  1455. (float)host->jitter_min / 1000);
  1456. }
  1457. if (mos_mode) {
  1458. printf("%s%smos=%0.1f;%0.1f;%0.1f;0;5 ",
  1459. (targets > 1 || perfdata_sep != NULL) ? host->name : "",
  1460. (perfdata_sep != NULL) ? perfdata_sep : "",
  1461. (float)host->mos, (float)warn.mos, (float)crit.mos);
  1462. }
  1463. if (score_mode) {
  1464. printf("%s%sscore=%u;%u;%u;0;100 ",
  1465. (targets > 1 || perfdata_sep != NULL) ? host->name : "",
  1466. (perfdata_sep != NULL) ? perfdata_sep : "",
  1467. (int)host->score, (int)warn.score, (int)crit.score);
  1468. }
  1469. host = host->next;
  1470. }
  1471. if (min_hosts_alive > -1) {
  1472. if (hosts_ok >= min_hosts_alive) {
  1473. status = STATE_OK;
  1474. } else if ((hosts_ok + hosts_warn) >= min_hosts_alive) {
  1475. status = STATE_WARNING;
  1476. }
  1477. }
  1478. /* finish with an empty line */
  1479. puts("");
  1480. if (debug) {
  1481. printf("targets: %u, targets_alive: %u, hosts_ok: %u, hosts_warn: %u, "
  1482. "min_hosts_alive: %i\n",
  1483. targets, targets_alive, hosts_ok, hosts_warn, min_hosts_alive);
  1484. }
  1485. exit(status);
  1486. }
  1487. static u_int get_timevaldiff(struct timeval *early, struct timeval *later) {
  1488. u_int ret;
  1489. struct timeval now;
  1490. if (!later) {
  1491. gettimeofday(&now, &tz);
  1492. later = &now;
  1493. }
  1494. if (!early)
  1495. early = &prog_start;
  1496. /* if early > later we return 0 so as to indicate a timeout */
  1497. if (early->tv_sec > later->tv_sec ||
  1498. (early->tv_sec == later->tv_sec && early->tv_usec > later->tv_usec)) {
  1499. return 0;
  1500. }
  1501. ret = (later->tv_sec - early->tv_sec) * 1000000;
  1502. ret += later->tv_usec - early->tv_usec;
  1503. return ret;
  1504. }
  1505. static int add_target_ip(char *arg, struct sockaddr_storage *in) {
  1506. struct rta_host *host;
  1507. struct sockaddr_in *sin = NULL, *host_sin;
  1508. struct sockaddr_in6 *sin6 = NULL, *host_sin6;
  1509. if (address_family == AF_INET) {
  1510. sin = (struct sockaddr_in *)in;
  1511. } else {
  1512. sin6 = (struct sockaddr_in6 *)in;
  1513. }
  1514. /* disregard some addresses */
  1515. if (((address_family == AF_INET && (sin->sin_addr.s_addr == INADDR_NONE ||
  1516. sin->sin_addr.s_addr == INADDR_ANY))) ||
  1517. (address_family == AF_INET6 &&
  1518. sin6->sin6_addr.s6_addr == in6addr_any.s6_addr)) {
  1519. return -1;
  1520. }
  1521. /* no point in adding two identical IP's, so don't. ;) */
  1522. host = list;
  1523. while (host) {
  1524. host_sin = (struct sockaddr_in *)&host->saddr_in;
  1525. host_sin6 = (struct sockaddr_in6 *)&host->saddr_in;
  1526. if ((address_family == AF_INET &&
  1527. host_sin->sin_addr.s_addr == sin->sin_addr.s_addr) ||
  1528. (address_family == AF_INET6 &&
  1529. host_sin6->sin6_addr.s6_addr == sin6->sin6_addr.s6_addr)) {
  1530. if (debug) {
  1531. printf("Identical IP already exists. Not adding %s\n", arg);
  1532. }
  1533. return -1;
  1534. }
  1535. host = host->next;
  1536. }
  1537. /* add the fresh ip */
  1538. host = (struct rta_host *)malloc(sizeof(struct rta_host));
  1539. if (!host) {
  1540. char address[address_length(address_family)];
  1541. parse_address_string(address_family, (struct sockaddr_storage *)&in,
  1542. address, sizeof(address));
  1543. crash("add_target_ip(%s, %s): malloc(%d) failed", arg, address,
  1544. sizeof(struct rta_host));
  1545. }
  1546. memset(host, 0, sizeof(struct rta_host));
  1547. /* set the values. use calling name for output */
  1548. host->name = strdup(arg);
  1549. /* fill out the sockaddr_storage struct */
  1550. if (address_family == AF_INET) {
  1551. host_sin = (struct sockaddr_in *)&host->saddr_in;
  1552. host_sin->sin_family = AF_INET;
  1553. host_sin->sin_addr.s_addr = sin->sin_addr.s_addr;
  1554. } else if (address_family == AF_INET6) {
  1555. host_sin6 = (struct sockaddr_in6 *)&host->saddr_in;
  1556. host_sin6->sin6_family = AF_INET6;
  1557. memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr,
  1558. sizeof host_sin6->sin6_addr.s6_addr);
  1559. }
  1560. host->rtmin = DBL_MAX;
  1561. host->rtmax = 0;
  1562. host->jitter = 0;
  1563. host->jitter_max = 0;
  1564. host->jitter_min = DBL_MAX;
  1565. host->last_tdiff = 0;
  1566. host->order_status = STATE_OK;
  1567. host->last_icmp_seq = 0;
  1568. host->rta_status = 0;
  1569. host->pl_status = 0;
  1570. host->jitter_status = 0;
  1571. host->mos_status = 0;
  1572. host->score_status = 0;
  1573. host->pl_status = 0;
  1574. if (!list) {
  1575. list = cursor = host;
  1576. } else {
  1577. cursor->next = host;
  1578. }
  1579. cursor = host;
  1580. targets++;
  1581. return 0;
  1582. }
  1583. /* wrapper for add_target_ip */
  1584. static int add_target(char *arg) {
  1585. int error, result;
  1586. struct sockaddr_storage ip;
  1587. struct addrinfo hints, *res, *p;
  1588. struct sockaddr_in *sin;
  1589. struct sockaddr_in6 *sin6;
  1590. switch (address_family) {
  1591. case AF_INET:
  1592. sin = (struct sockaddr_in *)&ip;
  1593. result = inet_pton(address_family, arg, &sin->sin_addr);
  1594. break;
  1595. case AF_INET6:
  1596. sin6 = (struct sockaddr_in6 *)&ip;
  1597. result = inet_pton(address_family, arg, &sin6->sin6_addr);
  1598. break;
  1599. default:
  1600. crash("Address family not supported");
  1601. }
  1602. /* don't resolve if we don't have to */
  1603. if (result == 1) {
  1604. /* don't add all ip's if we were given a specific one */
  1605. return add_target_ip(arg, &ip);
  1606. } else {
  1607. errno = 0;
  1608. memset(&hints, 0, sizeof(hints));
  1609. hints.ai_family = address_family == AF_INET ? PF_INET : PF_INET6;
  1610. hints.ai_socktype = SOCK_RAW;
  1611. if ((error = getaddrinfo(arg, NULL, &hints, &res)) != 0) {
  1612. errno = 0;
  1613. crash("Failed to resolve %s: %s", arg, gai_strerror(error));
  1614. return -1;
  1615. }
  1616. }
  1617. /* possibly add all the IP's as targets */
  1618. for (p = res; p != NULL; p = p->ai_next) {
  1619. memcpy(&ip, p->ai_addr, p->ai_addrlen);
  1620. add_target_ip(arg, &ip);
  1621. /* this is silly, but it works */
  1622. if (mode == MODE_HOSTCHECK || mode == MODE_ALL) {
  1623. if (debug > 2) {
  1624. printf("mode: %d\n", mode);
  1625. }
  1626. continue;
  1627. }
  1628. break;
  1629. }
  1630. freeaddrinfo(res);
  1631. return 0;
  1632. }
  1633. static void set_source_ip(char *arg) {
  1634. struct sockaddr_storage src;
  1635. int result;
  1636. void *address_offset;
  1637. memset(&src, 0, sizeof(src));
  1638. src.ss_family = address_family;
  1639. if (address_family == AF_INET) {
  1640. struct sockaddr_in *src_ipv4 = (struct sockaddr_in *) &src;
  1641. address_offset = (void *) &src_ipv4->sin_addr.s_addr;
  1642. }
  1643. else if (address_family == AF_INET6) {
  1644. struct sockaddr_in6 *src_ipv6 = (struct sockaddr_in6 *) &src;
  1645. /* Note: s6_addr is already an array, unlike s_addr */
  1646. address_offset = (void *) src_ipv6->sin6_addr.s6_addr;
  1647. }
  1648. result = inet_pton(address_family, arg, address_offset);
  1649. if (result != 1) {
  1650. struct sockaddr_in *src_ipv4 = (struct sockaddr_in *) &src;
  1651. src_ipv4->sin_addr.s_addr = get_ip_address(arg);
  1652. }
  1653. if (bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1) {
  1654. crash("Cannot bind to IP address %s", arg);
  1655. }
  1656. }
  1657. /* TODO: Move this to netutils.c and also change check_dhcp to use that. */
  1658. static in_addr_t get_ip_address(const char *ifname) {
  1659. #if defined(SIOCGIFADDR)
  1660. struct ifreq ifr;
  1661. struct sockaddr_in ip;
  1662. strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
  1663. ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
  1664. if (ioctl(icmp_sock, SIOCGIFADDR, &ifr) == -1) {
  1665. crash("Cannot determine IP address of interface %s", ifname);
  1666. }
  1667. memcpy(&ip, &ifr.ifr_addr, sizeof(ip));
  1668. return ip.sin_addr.s_addr;
  1669. #else
  1670. errno = 0;
  1671. crash("Cannot get interface IP address on this platform.");
  1672. #endif
  1673. }
  1674. /*
  1675. * u = micro
  1676. * m = milli
  1677. * s = seconds
  1678. * return value is in microseconds
  1679. */
  1680. static u_int get_timevar(const char *str) {
  1681. char p, u, *ptr;
  1682. size_t len;
  1683. u_int i, d; /* integer and decimal, respectively */
  1684. u_int factor = 1000; /* default to milliseconds */
  1685. if (!str) {
  1686. return 0;
  1687. }
  1688. len = strlen(str);
  1689. if (!len) {
  1690. return 0;
  1691. }
  1692. /* unit might be given as ms|m (millisec),
  1693. * us|u (microsec) or just plain s, for seconds */
  1694. p = '\0';
  1695. u = str[len - 1];
  1696. if (len >= 2 && !isdigit((int)str[len - 2])) {
  1697. p = str[len - 2];
  1698. }
  1699. if (p && u == 's') {
  1700. u = p;
  1701. } else if (!p) {
  1702. p = u;
  1703. }
  1704. if (debug > 2) {
  1705. printf("evaluating %s, u: %c, p: %c\n", str, u, p);
  1706. }
  1707. if (u == 'u') {
  1708. /* microseconds */
  1709. factor = 1;
  1710. } else if (u == 'm') {
  1711. /* milliseconds */
  1712. factor = 1000;
  1713. } else if (u == 's') {
  1714. /* seconds */
  1715. factor = 1000000;
  1716. }
  1717. if (debug > 2) {
  1718. printf("factor is %u\n", factor);
  1719. }
  1720. i = strtoul(str, &ptr, 0);
  1721. if (!ptr || *ptr != '.' || strlen(ptr) < 2 || factor == 1) {
  1722. return i * factor;
  1723. }
  1724. /* time specified in usecs can't have decimal points, so ignore them */
  1725. if (factor == 1) {
  1726. return i;
  1727. }
  1728. d = strtoul(ptr + 1, NULL, 0);
  1729. /* d is decimal, so get rid of excess digits */
  1730. while (d >= factor)
  1731. d /= 10;
  1732. /* the last parenthesis avoids floating point exceptions. */
  1733. return ((i * factor) + (d * (factor / 10)));
  1734. }
  1735. /* not too good at checking errors, but it'll do (main() should barfe on -1) */
  1736. static int get_threshold(char *str, threshold *th) {
  1737. char *p = NULL, i = 0;
  1738. if (!str || !strlen(str) || !th) {
  1739. return -1;
  1740. }
  1741. /* pointer magic slims code by 10 lines. i is bof-stop on stupid libc's */
  1742. p = &str[strlen(str) - 1];
  1743. while (p != &str[1]) {
  1744. if (*p == '%') {
  1745. *p = '\0';
  1746. } else if (*p == ',' && i) {
  1747. *p = '\0'; /* reset it so get_timevar(str) works nicely later */
  1748. th->pl = (unsigned char)strtoul(p + 1, NULL, 0);
  1749. break;
  1750. }
  1751. i = 1;
  1752. p--;
  1753. }
  1754. th->rta = get_timevar(str);
  1755. if (!th->rta) {
  1756. return -1;
  1757. }
  1758. if (th->rta > MAXTTL * 1000000) {
  1759. th->rta = MAXTTL * 1000000;
  1760. }
  1761. if (th->pl > 100) {
  1762. th->pl = 100;
  1763. }
  1764. return 0;
  1765. }
  1766. /* not too good at checking errors, but it'll do (main() should barfe on -1) */
  1767. static int get_threshold2(char *str, threshold *warn, threshold *crit,
  1768. int type) {
  1769. char *p = NULL, i = 0;
  1770. if (!str || !strlen(str) || !warn || !crit) {
  1771. return -1;
  1772. }
  1773. /* pointer magic slims code by 10 lines. i is bof-stop on stupid libc's */
  1774. p = &str[strlen(str) - 1];
  1775. while (p != &str[0]) {
  1776. if ((*p == 'm') || (*p == '%')) {
  1777. *p = '\0';
  1778. } else if (*p == ',' && i) {
  1779. *p = '\0'; /* reset it so get_timevar(str) works nicely later */
  1780. if (type == 1) {
  1781. crit->rta = atof(p + 1) * 1000;
  1782. } else if (type == 2) {
  1783. crit->pl = (unsigned char)strtoul(p + 1, NULL, 0);
  1784. } else if (type == 3) {
  1785. crit->jitter = atof(p + 1);
  1786. } else if (type == 4) {
  1787. crit->mos = atof(p + 1);
  1788. } else if (type == 5) {
  1789. crit->score = atof(p + 1);
  1790. }
  1791. }
  1792. i = 1;
  1793. p--;
  1794. }
  1795. if (type == 1) {
  1796. warn->rta = atof(p) * 1000;
  1797. } else if (type == 2) {
  1798. warn->pl = (unsigned char)strtoul(p, NULL, 0);
  1799. }
  1800. if (type == 3) {
  1801. warn->jitter = atof(p);
  1802. } else if (type == 4) {
  1803. warn->mos = atof(p);
  1804. } else if (type == 5) {
  1805. warn->score = atof(p);
  1806. }
  1807. return 0;
  1808. }
  1809. unsigned short icmp_checksum(unsigned short *p, int n) {
  1810. unsigned short cksum;
  1811. long sum = 0;
  1812. while (n > 2) {
  1813. sum += *p++;
  1814. n -= sizeof(unsigned short);
  1815. }
  1816. /* mop up the occasional odd byte */
  1817. if (n == 1) {
  1818. sum += (unsigned char)*p;
  1819. }
  1820. sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
  1821. sum += (sum >> 16); /* add carry */
  1822. cksum = ~sum; /* ones-complement, trunc to 16 bits */
  1823. return cksum;
  1824. }
  1825. void print_help(void) {
  1826. print_revision(progname, NP_VERSION);
  1827. printf(COPYRIGHT, copyright, email);
  1828. print_usage();
  1829. printf(UT_HELP_VRSN);
  1830. printf(UT_EXTRA_OPTS);
  1831. printf(" %s\n", "-w");
  1832. printf(" %s", _("warning threshold (currently "));
  1833. printf("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl);
  1834. printf(" %s\n", "-c");
  1835. printf(" %s", _("critical threshold (currently "));
  1836. printf("%0.3fms,%u%%)\n", (float)crit.rta / 1000, crit.pl);
  1837. printf(" %s\n", "-R");
  1838. printf(" %s\n", _("RTA, round trip average, mode warning,critical, ex. "
  1839. "100ms,200ms unit in ms"));
  1840. printf(" %s\n", "-P");
  1841. printf(" %s\n", _("packet loss mode, ex. 40%,50% , unit in %"));
  1842. printf(" %s\n", "-J");
  1843. printf(
  1844. " %s\n",
  1845. _("jitter mode warning,critical, ex. 40.000ms,50.000ms , unit in ms "));
  1846. printf(" %s\n", "-M");
  1847. printf(" %s\n",
  1848. _("MOS mode, between 0 and 4.4 warning,critical, ex. 3.5,3.0"));
  1849. printf(" %s\n", "-S");
  1850. printf(" %s\n",
  1851. _("score mode, max value 100 warning,critical, ex. 80,70 "));
  1852. printf(" %s\n", "-O");
  1853. printf(" %s\n", _("detect out of order ICMP packts "));
  1854. printf(" %s\n", "-4");
  1855. printf(" %s\n", _("target address(es) are IPv4 and packets are ICMPv4"));
  1856. printf(" %s\n", "-6");
  1857. printf(" %s\n", _("target address(es) are IPv6 and packets are ICMPv6"));
  1858. printf(" %s\n", "-H");
  1859. printf(" %s\n", _("specify a target"));
  1860. printf(" %s\n", "-s");
  1861. printf(" %s\n", _("specify a source IP address or device name"));
  1862. printf(" %s\n", "-n");
  1863. printf(" %s", _("number of packets to send (currently "));
  1864. printf("%u)\n", packets);
  1865. printf(" %s\n", "-p");
  1866. printf(" %s", _("number of packets to send (currently "));
  1867. printf("%u)\n", packets);
  1868. printf(" %s\n", "-i");
  1869. printf(" %s", _("max packet interval (currently "));
  1870. printf("%0.3fms)\n", (float)pkt_interval / 1000);
  1871. printf(" %s\n", "-I");
  1872. printf(" %s", _("max target interval (currently "));
  1873. printf("%0.3fms)\n", (float)target_interval / 1000);
  1874. printf(" %s\n", "-m");
  1875. printf(" %s", _("number of alive hosts required for success"));
  1876. printf("\n");
  1877. printf(" %s\n", "-l");
  1878. printf(" %s", _("TTL on outgoing packets (currently "));
  1879. printf("%u)\n", ttl);
  1880. printf(" %s\n", "-t");
  1881. printf(" %s", _("timeout value (seconds, currently "));
  1882. printf("%u)\n", timeout);
  1883. printf(" %s\n", "-b");
  1884. printf(" %s\n", _("Number of icmp data bytes to send"));
  1885. printf(" %s %u + %d)\n",
  1886. _("Packet size will be data bytes + icmp header (currently"),
  1887. icmp_data_size, ICMP_MINLEN);
  1888. printf(" %s\n", "-f");
  1889. printf(" %s\n", _("separator for perfdata instance"));
  1890. printf(" %s\n", "-F");
  1891. printf(" %s\n", _("number of instances to output perfdata for"));
  1892. printf(" %s\n", "-v");
  1893. printf(" %s\n", _("verbose"));
  1894. printf("\n");
  1895. printf("%s\n", _("Notes:"));
  1896. printf(" %s\n", _("If not mode R,P,J,M,S or O is informed, default icmp "
  1897. "behavior, RTA and packet loss"));
  1898. printf("\n");
  1899. printf(" %s\n", _("The -H switch is optional. Naming a host (or several) to "
  1900. "check is not."));
  1901. printf("\n");
  1902. printf(" %s\n", _("When defining multiple addresses they must be provided as "
  1903. "the last argument."));
  1904. printf("\n");
  1905. printf(" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 "
  1906. "msec RTA and 60%"));
  1907. printf(
  1908. " %s\n",
  1909. _("packet loss. The default values should work well for most users."));
  1910. printf(" %s\n", _("You can specify different RTA factors using the "
  1911. "standardized abbreviations"));
  1912. printf(" %s\n", _("us (microseconds), ms (milliseconds, default) or just "
  1913. "plain s for seconds."));
  1914. /* -d not yet implemented */
  1915. /* printf ("%s\n", _("Threshold format for -d is warn,crit. 12,14 means
  1916. WARNING if >= 12 hops")); printf ("%s\n", _("are spent and CRITICAL if >= 14
  1917. hops are spent.")); printf ("%s\n\n", _("NOTE: Some systems decrease TTL
  1918. when forming ICMP_ECHOREPLY, others do not."));*/
  1919. printf("\n");
  1920. printf(" %s\n", _("The -v switch can be specified several times for "
  1921. "increased verbosity."));
  1922. /* printf ("%s\n", _("Long options are currently unsupported."));*/
  1923. /* printf ("%s\n", _("Options marked with * require an argument"));*/
  1924. printf(UT_SUPPORT);
  1925. }
  1926. void print_usage(void) {
  1927. printf("%s\n", _("Usage:"));
  1928. printf(" %s [options] [-H] host1 host2 hostN\n", progname);
  1929. }