check_icmp.c 57 KB

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