1 /*----------------------------------------------------------------------------*/
2 /* Xymon monitor network test tool. */
3 /* */
4 /* Copyright (C) 2003-2011 Henrik Storner <henrik@hswn.dk> */
5 /* */
6 /* This program is released under the GNU General Public License (GPL), */
7 /* version 2. See the file "COPYING" for details. */
8 /* */
9 /*----------------------------------------------------------------------------*/
10
11 static char rcsid[] = "$Id: xymonnet.c 8084 2019-08-30 23:01:18Z jccleaver $";
12
13 #include <limits.h>
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <ctype.h>
21 #include <netdb.h>
22 #include <sys/wait.h>
23 #include <rpc/rpc.h>
24 #include <fcntl.h>
25 #include <errno.h>
26
27 #include "libxymon.h"
28
29 #ifdef HAVE_RPCENT_H
30 #include <rpc/rpcent.h>
31 #endif
32
33 #ifdef BROKEN_HPUX_NETDB
34 /*
35 * Some HP-UX include files fail to define RPC functions
36 * and structs that are purely standard. At the same time,
37 * their own docs claim that the DO define them. Go figure ...
38 */
39 struct rpcent {
40 char *r_name; /* name of server for this rpc program */
41 char **r_aliases; /* alias list */
42 int r_number; /* rpc program number */
43 };
44 extern struct rpcent *getrpcbyname(char *);
45 #endif
46
47 #include "libxymon.h"
48 #include "version.h"
49
50 #include "xymonnet.h"
51 #include "dns.h"
52 #include "contest.h"
53 #include "httptest.h"
54 #include "httpresult.h"
55 #include "httpcookies.h"
56 #include "ldaptest.h"
57
58 #define DEFAULT_PING_CHILD_COUNT 1
59 #define MSGBUFSIZE 4096
60
61 char *reqenv[] = {
62 "NONETPAGE",
63 "HOSTSCFG",
64 "XYMONTMP",
65 "XYMONHOME",
66 NULL
67 };
68
69 void * svctree; /* All known services, has service_t records */
70 service_t *pingtest = NULL; /* Identifies the pingtest within svctree list */
71 int pingcount = 0;
72 service_t *dnstest = NULL; /* Identifies the dnstest within svctree list */
73 service_t *httptest = NULL; /* Identifies the httptest within svctree list */
74 service_t *ldaptest = NULL; /* Identifies the ldaptest within svctree list */
75 service_t *rpctest = NULL; /* Identifies the rpctest within svctree list */
76 void * testhosttree; /* All tested hosts, has testedhost_t records */
77 SBUF_DEFINE(nonetpage); /* The "NONETPAGE" env. variable */
78 int dnsmethod = DNS_THEN_IP; /* How to do DNS lookups */
79 int timeout=10; /* The timeout (seconds) for all TCP-tests */
80 char *contenttestname = "content"; /* Name of the content checks column */
81 char *ssltestname = "sslcert"; /* Name of the SSL certificate checks column */
82 char *failtext = "not OK";
83 int sslwarndays = 30; /* If cert expires in fewer days, SSL cert column = yellow */
84 int sslalarmdays = 10; /* If cert expires in fewer days, SSL cert column = red */
85 int mincipherbits = 0; /* If weakest cipher is weaker than this # of buts, SSL cert column = red */
86 int validity = 30;
87 int pingchildcount = DEFAULT_PING_CHILD_COUNT; /* How many ping processes to start */
88 char *location = ""; /* XYMONNETWORK value */
89 int hostcount = 0;
90 int testcount = 0;
91 int notesthostcount = 0;
92 char **selectedhosts;
93 int selectedcount = 0;
94 int testuntagged = 0;
95 time_t frequenttestlimit = 1800; /* Interval (seconds) when failing hosts are retried frequently */
96 int checktcpresponse = 0;
97 int dotraceroute = 0;
98 int fqdn = 1;
99 int dosendflags = 1;
100 SBUF_DEFINE(pingcmd);
101 char pinglog[PATH_MAX];
102 char pingerrlog[PATH_MAX];
103 pid_t *pingpids;
104 int respcheck_color = COL_YELLOW;
105 httpstatuscolor_t *httpstatusoverrides = NULL;
106 int extcmdtimeout = 30;
107 int bigfailure = 0;
108 char *defaultsourceip = NULL;
109 int loadhostsfromxymond = 0;
110 int sslminkeysize = 0;
111 STATIC_SBUF_DEFINE(warnbuf);
112
dump_hostlist(void)113 void dump_hostlist(void)
114 {
115 xtreePos_t handle;
116 testedhost_t *walk;
117
118 for (handle = xtreeFirst(testhosttree); (handle != xtreeEnd(testhosttree)); handle = xtreeNext(testhosttree, handle)) {
119 walk = (testedhost_t *)xtreeData(testhosttree, handle);
120 printf("Hostname: %s\n", textornull(walk->hostname));
121 printf("\tIP : %s\n", textornull(walk->ip));
122 printf("\tHosttype : %s\n", textornull(walk->hosttype));
123
124 printf("\tFlags :");
125 if (walk->testip) printf(" testip");
126 if (walk->dialup) printf(" dialup");
127 if (walk->nosslcert) printf(" nosslcert");
128 if (walk->dodns) printf(" dodns");
129 if (walk->dnserror) printf(" dnserror");
130 if (walk->repeattest) printf(" repeattest");
131 if (walk->noconn) printf(" noconn");
132 if (walk->noping) printf(" noping");
133 if (walk->dotrace) printf(" dotrace");
134 printf("\n");
135
136 printf("\tbadconn : %d:%d:%d\n", walk->badconn[0], walk->badconn[1], walk->badconn[2]);
137 printf("\tdowncount : %d started %s", walk->downcount, ctime(&walk->downstart));
138 printf("\trouterdeps : %s\n", textornull(walk->routerdeps));
139 printf("\tdeprouterdown: %s\n", (walk->deprouterdown ? textornull(walk->deprouterdown->hostname) : ""));
140 printf("\tldapauth : '%s' '%s'\n", textornull(walk->ldapuser), textornull(walk->ldappasswd));
141 printf("\tSSL alerts : %d:%d\n", walk->sslwarndays, walk->sslalarmdays);
142 printf("\n");
143 }
144 }
dump_testitems(void)145 void dump_testitems(void)
146 {
147 xtreePos_t handle;
148 service_t *swalk;
149 testitem_t *iwalk;
150
151 for (handle = xtreeFirst(svctree); handle != xtreeEnd(svctree); handle = xtreeNext(svctree, handle)) {
152 swalk = (service_t *)xtreeData(svctree, handle);
153
154 printf("Service %s, port %d, toolid %d\n", swalk->testname, swalk->portnum, swalk->toolid);
155
156 for (iwalk = swalk->items; (iwalk); iwalk = iwalk->next) {
157 printf("\tHost : %s\n", textornull(iwalk->host->hostname));
158 printf("\ttestspec : %s\n", textornull(iwalk->testspec));
159 printf("\tFlags :");
160 if (iwalk->dialup) printf(" dialup");
161 if (iwalk->reverse) printf(" reverse");
162 if (iwalk->silenttest) printf(" silenttest");
163 if (iwalk->alwaystrue) printf(" alwaystrue");
164 printf("\n");
165 printf("\tOpen : %d\n", iwalk->open);
166 printf("\tBanner : %s\n", textornull(STRBUF(iwalk->banner)));
167 printf("\tcertinfo : %s\n", textornull(iwalk->certinfo));
168 printf("\tDuration : %ld.%06ld\n", (long int)iwalk->duration.tv_sec, (long int)iwalk->duration.tv_nsec / 1000);
169 printf("\tbadtest : %d:%d:%d\n", iwalk->badtest[0], iwalk->badtest[1], iwalk->badtest[2]);
170 printf("\tdowncount : %d started %s", iwalk->downcount, ctime(&iwalk->downstart));
171 printf("\n");
172 }
173
174 printf("\n");
175 }
176 }
177
find_test(char * hostname,char * testname)178 testitem_t *find_test(char *hostname, char *testname)
179 {
180 xtreePos_t handle;
181 testedhost_t *h;
182 service_t *s;
183 testitem_t *t;
184
185 handle = xtreeFind(svctree, testname);
186 if (handle == xtreeEnd(svctree)) return NULL;
187 s = (service_t *)xtreeData(svctree, handle);
188
189 handle = xtreeFind(testhosttree, hostname);
190 if (handle == xtreeEnd(testhosttree)) return NULL;
191 h = (testedhost_t *)xtreeData(testhosttree, handle);
192
193 for (t=s->items; (t && (t->host != h)); t = t->next) ;
194
195 return t;
196 }
197
198
deptest_failed(testedhost_t * host,char * testname)199 char *deptest_failed(testedhost_t *host, char *testname)
200 {
201 static char result[1024];
202
203 char *depcopy;
204 char depitem[MAX_LINE_LEN];
205 char *p, *q;
206 char *dephostname, *deptestname, *nextdep;
207 testitem_t *t;
208
209 if (host->deptests == NULL) return NULL;
210
211 depcopy = strdup(host->deptests);
212 snprintf(depitem, sizeof(depitem), "(%s:", testname);
213 p = strstr(depcopy, depitem);
214 if (p == NULL) { xfree(depcopy); return NULL; }
215
216 result[0] = '\0';
217 dephostname = p+strlen(depitem);
218 q = strchr(dephostname, ')');
219 if (q) *q = '\0';
220
221 /* dephostname now points to a list of "host1/test1,host2/test2" dependent tests. */
222 while (dephostname) {
223 p = strchr(dephostname, '/');
224 if (p) {
225 *p = '\0';
226 deptestname = (p+1);
227 }
228 else deptestname = "";
229
230 p = strchr(deptestname, ',');
231 if (p) {
232 *p = '\0';
233 nextdep = (p+1);
234 }
235 else nextdep = NULL;
236
237 t = find_test(dephostname, deptestname);
238 if (t && !t->open) {
239 if (strlen(result) == 0) {
240 strncpy(result, "\nThis test depends on the following test(s) that failed:\n\n", sizeof(result));
241 }
242
243 if ((strlen(result) + strlen(dephostname) + strlen(deptestname) + 2) < sizeof(result)) {
244 strncat(result, dephostname, (sizeof(result) - strlen(result)));
245 strncat(result, "/", (sizeof(result) - strlen(result)));
246 strncat(result, deptestname, (sizeof(result) - strlen(result)));
247 strncat(result, "\n", (sizeof(result) - strlen(result)));
248 }
249 }
250
251 dephostname = nextdep;
252 }
253
254 xfree(depcopy);
255 if (*result) strncat(result, "\n\n", (sizeof(result) - strlen(result)));
256
257 return (*result ? result : NULL);
258 }
259
260
add_service(char * name,int port,int namelen,int toolid)261 service_t *add_service(char *name, int port, int namelen, int toolid)
262 {
263 xtreePos_t handle;
264 service_t *svc;
265
266 /* Avoid duplicates */
267 handle = xtreeFind(svctree, name);
268 if (handle != xtreeEnd(svctree)) {
269 svc = (service_t *)xtreeData(svctree, handle);
270 return svc;
271 }
272
273 svc = (service_t *) malloc(sizeof(service_t));
274 svc->portnum = port;
275 svc->testname = strdup(name);
276 svc->toolid = toolid;
277 svc->namelen = namelen;
278 svc->items = NULL;
279 xtreeAdd(svctree, svc->testname, svc);
280
281 return svc;
282 }
283
getportnumber(char * svcname)284 int getportnumber(char *svcname)
285 {
286 struct servent *svcinfo;
287 int result = 0;
288
289 result = default_tcp_port(svcname);
290 if (result == 0) {
291 svcinfo = getservbyname(svcname, NULL);
292 if (svcinfo) result = ntohs(svcinfo->s_port);
293 }
294
295 return result;
296 }
297
load_services(void)298 void load_services(void)
299 {
300 char *netsvcs;
301 char *p;
302
303 netsvcs = strdup(init_tcp_services());
304
305 p = strtok(netsvcs, " ");
306 while (p) {
307 add_service(p, getportnumber(p), 0, TOOL_CONTEST);
308 p = strtok(NULL, " ");
309 }
310 xfree(netsvcs);
311
312 /* Save NONETPAGE env. var in ",test1,test2," format for easy and safe grepping */
313 SBUF_MALLOC(nonetpage, strlen(xgetenv("NONETPAGE"))+3);
314 snprintf(nonetpage, nonetpage_buflen, ",%s,", xgetenv("NONETPAGE"));
315 for (p=nonetpage; (*p); p++) if (*p == ' ') *p = ',';
316 }
317
318
init_testedhost(char * hostname)319 testedhost_t *init_testedhost(char *hostname)
320 {
321 testedhost_t *newhost;
322
323 hostcount++;
324 newhost = (testedhost_t *) calloc(1, sizeof(testedhost_t));
325 newhost->hostname = strdup(hostname);
326 newhost->dotrace = dotraceroute;
327 newhost->sslwarndays = sslwarndays;
328 newhost->sslalarmdays = sslalarmdays;
329 newhost->mincipherbits = mincipherbits;
330
331 return newhost;
332 }
333
init_testitem(testedhost_t * host,service_t * service,char * srcip,char * testspec,int dialuptest,int reversetest,int alwaystruetest,int silenttest,int sendasdata)334 testitem_t *init_testitem(testedhost_t *host, service_t *service, char *srcip, char *testspec,
335 int dialuptest, int reversetest, int alwaystruetest, int silenttest,
336 int sendasdata)
337 {
338 testitem_t *newtest;
339
340 testcount++;
341 newtest = (testitem_t *) calloc(1, sizeof(testitem_t));
342 newtest->host = host;
343 newtest->service = service;
344 newtest->dialup = dialuptest;
345 newtest->reverse = reversetest;
346 newtest->alwaystrue = alwaystruetest;
347 newtest->silenttest = silenttest;
348 newtest->senddata = sendasdata;
349 newtest->testspec = (testspec ? strdup(testspec) : NULL);
350 if (srcip)
351 newtest->srcip = strdup(srcip);
352 else if (defaultsourceip)
353 newtest->srcip = defaultsourceip;
354 else
355 newtest->srcip = NULL;
356 newtest->privdata = NULL;
357 newtest->open = 0;
358 newtest->banner = newstrbuffer(0);
359 newtest->certinfo = NULL;
360 newtest->certissuer = NULL;
361 newtest->certexpires = 0;
362 newtest->certkeysz = 0;
363 newtest->mincipherbits = 0;
364 newtest->duration.tv_sec = newtest->duration.tv_nsec = -1;
365 newtest->downcount = 0;
366 newtest->badtest[0] = newtest->badtest[1] = newtest->badtest[2] = 0;
367 newtest->internal = 0;
368 newtest->next = NULL;
369
370 return newtest;
371 }
372
373
wanted_host(void * host,char * netstring)374 int wanted_host(void *host, char *netstring)
375 {
376 char *netlocation = xmh_item(host, XMH_NET);
377
378 if (selectedcount == 0)
379 return ((strlen(netstring) == 0) || /* No XYMONNETWORK = do all */
380 (netlocation && (strcmp(netlocation, netstring) == 0)) || /* XYMONNETWORK && matching NET: tag */
381 (testuntagged && (netlocation == NULL))); /* No NET: tag for this host */
382 else {
383 /* User provided an explicit list of hosts to test */
384 int i;
385
386 for (i=0; (i < selectedcount); i++) {
387 if (strcmp(selectedhosts[i], xmh_item(host, XMH_HOSTNAME)) == 0) return 1;
388 }
389 }
390
391 return 0;
392 }
393
394
load_tests(void)395 void load_tests(void)
396 {
397 char *p;
398 SBUF_DEFINE(routestring);
399 void *hwalk;
400 testedhost_t *h;
401 int badtagsused = 0;
402
403 if (loadhostsfromxymond) {
404 if (load_hostnames("@", NULL, fqdn) != 0) {
405 errprintf("Cannot load host configuration from xymond\n");
406 return;
407 }
408 }
409 else {
410 if (load_hostnames(xgetenv("HOSTSCFG"), "netinclude", fqdn) != 0) {
411 errprintf("Cannot load host configuration from %s\n", xgetenv("HOSTSCFG"));
412 return;
413 }
414 }
415
416 if (first_host() == NULL) {
417 errprintf("Empty configuration from %s\n", (loadhostsfromxymond ? "xymond" : xgetenv("HOSTSCFG")));
418 return;
419 }
420
421 /* Each network test tagged with NET:locationname */
422 if (strlen(location) > 0) {
423 SBUF_MALLOC(routestring, strlen(location)+strlen("route_:")+1);
424 snprintf(routestring, routestring_buflen, "route_%s:", location);
425 }
426
427 for (hwalk = first_host(); (hwalk); hwalk = next_host(hwalk, 0)) {
428 int anytests = 0;
429 int ping_dialuptest = 0, ping_reversetest = 0;
430 char *testspec;
431
432 if (!wanted_host(hwalk, location)) continue;
433
434 h = init_testedhost(xmh_item(hwalk, XMH_HOSTNAME));
435
436 p = xmh_custom_item(hwalk, "badconn:");
437 if (p) {
438 sscanf(p+strlen("badconn:"), "%d:%d:%d", &h->badconn[0], &h->badconn[1], &h->badconn[2]);
439 badtagsused = 1;
440 }
441
442 p = xmh_custom_item(hwalk, "route:");
443 if (p) h->routerdeps = p + strlen("route:");
444 if (routestring) {
445 p = xmh_custom_item(hwalk, routestring);
446 if (p) h->routerdeps = p + strlen(routestring);
447 }
448
449 if (xmh_item(hwalk, XMH_FLAG_NOCONN)) h->noconn = 1;
450 if (xmh_item(hwalk, XMH_FLAG_NOPING)) h->noping = 1;
451 if (xmh_item(hwalk, XMH_FLAG_TRACE)) h->dotrace = 1;
452 if (xmh_item(hwalk, XMH_FLAG_NOTRACE)) h->dotrace = 0;
453 if (xmh_item(hwalk, XMH_FLAG_TESTIP)) h->testip = 1;
454 if (xmh_item(hwalk, XMH_FLAG_DIALUP)) h->dialup = 1;
455 if (xmh_item(hwalk, XMH_FLAG_NOSSLCERT)) h->nosslcert = 1;
456 if (xmh_item(hwalk, XMH_FLAG_LDAPFAILYELLOW)) h->ldapsearchfailyellow = 1;
457 if (xmh_item(hwalk, XMH_FLAG_HIDEHTTP)) h->hidehttp = 1;
458
459 p = xmh_item(hwalk, XMH_SSLDAYS);
460 if (p) sscanf(p, "%d:%d", &h->sslwarndays, &h->sslalarmdays);
461
462 p = xmh_item(hwalk, XMH_SSLMINBITS);
463 if (p) h->mincipherbits = atoi(p);
464
465 p = xmh_item(hwalk, XMH_DEPENDS);
466 if (p) h->deptests = p;
467
468 p = xmh_item(hwalk, XMH_LDAPLOGIN);
469 if (p) {
470 h->ldapuser = strdup(p);
471 h->ldappasswd = (strchr(h->ldapuser, ':'));
472 if (h->ldappasswd) {
473 *h->ldappasswd = '\0';
474 h->ldappasswd++;
475 }
476 }
477
478 p = xmh_item(hwalk, XMH_DESCRIPTION);
479 if (p) {
480 h->hosttype = strdup(p);
481 p = strchr(h->hosttype, ':');
482 if (p) *p = '\0';
483 }
484
485 testspec = xmh_item_walk(hwalk);
486 while (testspec) {
487 service_t *s = NULL;
488 int dialuptest = 0, reversetest = 0, silenttest = 0, sendasdata = 0;
489 char *srcip = NULL;
490 int alwaystruetest = (xmh_item(hwalk, XMH_FLAG_NOCLEAR) != NULL);
491
492 if (xmh_item_idx(testspec) == -1) {
493
494 /* Test prefixes:
495 * - '?' denotes dialup test, i.e. report failures as clear.
496 * - '|' denotes reverse test, i.e. service should be DOWN.
497 * - '~' denotes test that ignores ping result (normally,
498 * TCP tests are reported CLEAR if ping check fails;
499 * with this flag report their true status)
500 */
501 if (*testspec == '?') { dialuptest=1; testspec++; }
502 if (*testspec == '!') { reversetest=1; testspec++; }
503 if (*testspec == '~') { alwaystruetest=1; testspec++; }
504
505 if (pingtest && argnmatch(testspec, pingtest->testname)) {
506 char *p;
507
508 /*
509 * Ping/conn test. Save any modifier flags for later use.
510 */
511 ping_dialuptest = dialuptest;
512 ping_reversetest = reversetest;
513 p = strchr(testspec, '=');
514 if (p) {
515 char *ips;
516
517 /* Extra ping tests - save them for later */
518 h->extrapings = (extraping_t *)malloc(sizeof(extraping_t));
519 h->extrapings->iplist = NULL;
520 if (argnmatch(p, "=worst,")) {
521 h->extrapings->matchtype = MULTIPING_WORST;
522 ips = strdup(p+7);
523 }
524 else if (argnmatch(p, "=best,")) {
525 h->extrapings->matchtype = MULTIPING_BEST;
526 ips = strdup(p+6);
527 }
528 else {
529 h->extrapings->matchtype = MULTIPING_BEST;
530 ips = strdup(p+1);
531 }
532
533 do {
534 ipping_t *newping = (ipping_t *)malloc(sizeof(ipping_t));
535
536 newping->ip = ips;
537 newping->open = 0;
538 newping->banner = newstrbuffer(0);
539 newping->next = h->extrapings->iplist;
540 h->extrapings->iplist = newping;
541 ips = strchr(ips, ',');
542 if (ips) { *ips = '\0'; ips++; }
543 } while (ips && (*ips));
544 }
545 s = NULL; /* Don't add the test now - ping is special (enabled by default) */
546 }
547 else if ((argnmatch(testspec, "ldap://")) || (argnmatch(testspec, "ldaps://"))) {
548 /*
549 * LDAP test. This uses ':' a lot, so save it here.
550 */
551 #ifdef HAVE_LDAP
552 s = ldaptest;
553 add_url_to_dns_queue(testspec);
554 #else
555 errprintf("Host %s: ldap test requested, but xymonnet was built with no ldap support\n", xmh_item(hwalk, XMH_HOSTNAME));
556 #endif
557 }
558 else if ((strcmp(testspec, "http") == 0) || (strcmp(testspec, "https") == 0)) {
559 errprintf("Host %s: http/https tests requires a full URL\n", xmh_item(hwalk, XMH_HOSTNAME));
560 }
561 else if ( argnmatch(testspec, "http") ||
562 argnmatch(testspec, "content=http") ||
563 argnmatch(testspec, "cont;http") ||
564 argnmatch(testspec, "cont=") ||
565 argnmatch(testspec, "nocont;http") ||
566 argnmatch(testspec, "nocont=") ||
567 argnmatch(testspec, "post;http") ||
568 argnmatch(testspec, "post=") ||
569 argnmatch(testspec, "nopost;http") ||
570 argnmatch(testspec, "nopost=") ||
571 argnmatch(testspec, "soap;http") ||
572 argnmatch(testspec, "soap=") ||
573 argnmatch(testspec, "nosoap;http") ||
574 argnmatch(testspec, "nosoap=") ||
575 argnmatch(testspec, "type;http") ||
576 argnmatch(testspec, "type=") ) {
577
578 /* HTTP test. */
579 weburl_t url;
580
581 decode_url(testspec, &url);
582 if (url.desturl->parseerror || (url.proxyurl && url.proxyurl->parseerror)) {
583 s = NULL;
584 errprintf("Host %s: Invalid URL for http test - ignored: %s\n",
585 xmh_item(hwalk, XMH_HOSTNAME), testspec);
586 }
587 else {
588 s = httptest;
589 if (!url.desturl->ip)
590 add_url_to_dns_queue(testspec);
591 }
592 }
593 else if (argnmatch(testspec, "apache") || argnmatch(testspec, "apache=")) {
594 char *userfmt = "cont=apache;%s;.";
595 char *deffmt = "cont=apache;http://%s/server-status?auto;.";
596 STATIC_SBUF_DEFINE(statusurl);
597 char *userurl;
598
599 if (statusurl != NULL) xfree(statusurl);
600
601 userurl = strchr(testspec, '=');
602 if (userurl) {
603 weburl_t url;
604 userurl++;
605
606 decode_url(userurl, &url);
607 if (url.desturl->parseerror || (url.proxyurl && url.proxyurl->parseerror)) {
608 s = NULL;
609 errprintf("Host %s: Invalid URL for apache test - ignored: %s\n", xmh_item(hwalk, XMH_HOSTNAME), testspec);
610 }
611 else {
612 SBUF_MALLOC(statusurl, strlen(userurl) + strlen(userfmt) + 1);
613 snprintf(statusurl, statusurl_buflen, userfmt, userurl);
614 s = httptest;
615 }
616 }
617 else {
618 char *ip = xmh_item(hwalk, XMH_IP);
619 SBUF_MALLOC(statusurl, strlen(deffmt) + strlen(ip) + 1);
620 snprintf(statusurl, statusurl_buflen, deffmt, ip);
621 s = httptest;
622 }
623
624 if (s) {
625 testspec = statusurl;
626 add_url_to_dns_queue(testspec);
627 sendasdata = 1;
628 }
629 }
630 else if (argnmatch(testspec, "rpc")) {
631 /*
632 * rpc check via rpcinfo
633 */
634 s = rpctest;
635 }
636 else if (argnmatch(testspec, "dns=")) {
637 s = dnstest;
638 }
639 else if (argnmatch(testspec, "dig=")) {
640 s = dnstest;
641 }
642 else {
643 /*
644 * Simple TCP connect test.
645 */
646 char *option;
647 xtreePos_t handle;
648
649 /* See if there's a source IP */
650 srcip = strchr(testspec, '@');
651 if (srcip) {
652 *srcip = '\0';
653 srcip++;
654 }
655
656 /* Remove any trailing ":s", ":q", ":Q", ":portnumber" */
657 option = strchr(testspec, ':');
658 if (option) {
659 *option = '\0';
660 option++;
661 }
662
663 /* Find the service */
664 handle = xtreeFind(svctree, testspec);
665 s = ((handle == xtreeEnd(svctree)) ? NULL : (service_t *)xtreeData(svctree, handle));
666 if (option && s) {
667 /*
668 * Check if it is a service with an explicit portnumber.
669 * If it is, then create a new service record named
670 * "SERVICE_PORT" so we can merge tests for this service+port
671 * combination for multiple hosts.
672 *
673 * According to Xymon docs, this type of services must be in
674 * XYMONNETSVCS - so it is known already.
675 */
676 int specialport = 0;
677 SBUF_DEFINE(specialname);
678 char *opt2 = strrchr(option, ':');
679
680 if (opt2) {
681 if (strcmp(opt2, ":s") == 0) {
682 /* option = "portnumber:s" */
683 silenttest = 1;
684 *opt2 = '\0';
685 specialport = atoi(option);
686 *opt2 = ':';
687 }
688 }
689 else if (strcmp(option, "s") == 0) {
690 /* option = "s" */
691 silenttest = 1;
692 specialport = 0;
693 }
694 else {
695 /* option = "portnumber" */
696 specialport = atoi(option);
697 }
698
699 if (specialport) {
700 SBUF_MALLOC(specialname, strlen(s->testname)+10);
701 snprintf(specialname, specialname_buflen,"%s_%d", s->testname, specialport);
702 s = add_service(specialname, specialport, strlen(s->testname), TOOL_CONTEST);
703 xfree(specialname);
704 }
705 }
706
707 if (s) h->dodns = 1;
708 if (option) *(option-1) = ':';
709 }
710
711 if (s) {
712 testitem_t *newtest;
713
714 anytests = 1;
715 newtest = init_testitem(h, s, srcip, testspec, dialuptest, reversetest, alwaystruetest, silenttest, sendasdata);
716 newtest->next = s->items;
717 s->items = newtest;
718
719 if (s == httptest) h->firsthttp = newtest;
720 else if (s == ldaptest) {
721 xtreePos_t handle;
722 service_t *s2 = NULL;
723 testitem_t *newtest2;
724
725 h->firstldap = newtest;
726
727 /*
728 * Add a plain tcp-connect test for the LDAP service.
729 * We don't want the LDAP library to run amok and do
730 * time-consuming connect retries if the service
731 * is down.
732 */
733 handle = xtreeFind(svctree, "ldap");
734 s2 = ((handle == xtreeEnd(svctree)) ? NULL : (service_t *)xtreeData(svctree, handle));
735 if (s2) {
736 newtest2 = init_testitem(h, s2, NULL, "ldap", 0, 0, 0, 0, 1);
737 newtest2->internal = 1;
738 newtest2->next = s2->items;
739 s2->items = newtest2;
740 newtest->privdata = newtest2;
741 }
742 }
743 }
744 }
745
746 testspec = xmh_item_walk(NULL);
747 }
748
749 if (pingtest && !h->noconn) {
750 /* Add the ping check */
751 testitem_t *newtest;
752
753 anytests = 1;
754 newtest = init_testitem(h, pingtest, NULL, NULL, ping_dialuptest, ping_reversetest, 1, 0, 0);
755 newtest->next = pingtest->items;
756 pingtest->items = newtest;
757 h->dodns = 1;
758 }
759
760
761 /*
762 * Setup badXXX values.
763 *
764 * We need to do this last, because the testitem_t records do
765 * not exist until the test has been created.
766 *
767 * So after parsing the badFOO tag, we must find the testitem_t
768 * record created earlier for this test (it may not exist).
769 */
770 testspec = xmh_item_walk(hwalk);
771 while (testspec) {
772 char *testname, *timespec, *badcounts;
773 int badclear, badyellow, badred;
774 int inscope;
775 testitem_t *twalk;
776 service_t *swalk;
777
778 if (strncmp(testspec, "bad", 3) != 0) {
779 /* Not a bad* tag - skip it */
780 testspec = xmh_item_walk(NULL);
781 continue;
782 }
783
784
785 badtagsused = 1;
786 badclear = badyellow = badred = 0;
787 inscope = 1;
788
789 testname = testspec+strlen("bad");
790 badcounts = strchr(testspec, ':');
791 if (badcounts) {
792 if (sscanf(badcounts, ":%d:%d:%d", &badclear, &badyellow, &badred) != 3) {
793 errprintf("Host %s: Incorrect 'bad' counts: '%s'\n", xmh_item(hwalk, XMH_HOSTNAME), badcounts);
794 badcounts = NULL;
795 }
796 }
797 timespec = strchr(testspec, '-');
798 if (timespec) inscope = periodcoversnow(timespec);
799
800 if (strlen(testname) && badcounts && inscope) {
801 char *p;
802 xtreePos_t handle;
803 twalk = NULL;
804
805 p = strchr(testname, ':'); if (p) *p = '\0';
806 handle = xtreeFind(svctree, testname);
807 swalk = ((handle == xtreeEnd(svctree)) ? NULL : (service_t *)xtreeData(svctree, handle));
808 if (p) *p = ':';
809 if (swalk) {
810 if (swalk == httptest) twalk = h->firsthttp;
811 else if (swalk == ldaptest) twalk = h->firstldap;
812 else for (twalk = swalk->items; (twalk && (twalk->host != h)); twalk = twalk->next) ;
813 }
814
815 if (twalk) {
816 twalk->badtest[0] = badclear;
817 twalk->badtest[1] = badyellow;
818 twalk->badtest[2] = badred;
819 }
820 else {
821 dbgprintf("No test for badtest spec host=%s, test=%s\n",
822 h->hostname, testname);
823 }
824 }
825
826 testspec = xmh_item_walk(NULL);
827 }
828
829
830 if (anytests) {
831 xtreeStatus_t res;
832
833 /*
834 * Check for a duplicate host def. Causes all sorts of funny problems.
835 * However, don't drop the second definition - to do this, we will have
836 * to clean up the testitem lists as well, or we get crashes when
837 * tests belong to a non-existing host.
838 */
839
840 res = xtreeAdd(testhosttree, h->hostname, h);
841 if (res == XTREE_STATUS_DUPLICATE_KEY) {
842 errprintf("Host %s appears twice in hosts.cfg! This may cause strange results\n", h->hostname);
843 }
844
845 strncpy(h->ip, xmh_item(hwalk, XMH_IP), sizeof(h->ip));
846 if (!h->testip && (dnsmethod != IP_ONLY)) add_host_to_dns_queue(h->hostname);
847 }
848 else {
849 /* No network tests for this host, so ignore it */
850 dbgprintf("Did not find any network tests for host %s\n", h->hostname);
851 xfree(h);
852 notesthostcount++;
853 }
854
855 }
856
857 if (badtagsused) {
858 errprintf("WARNING: The 'bad<TESTNAME>' syntax has been deprecated, please convert to 'delayred' and/or 'delayyellow' tags\n");
859 }
860
861 return;
862 }
863
ip_to_test(testedhost_t * h)864 char *ip_to_test(testedhost_t *h)
865 {
866 char *dnsresult;
867 int nullip = (strcmp(h->ip, "0.0.0.0") == 0);
868
869 if (!nullip && (h->testip || (dnsmethod == IP_ONLY))) {
870 /* Already have the IP setup */
871 }
872 else if (h->dodns) {
873 dnsresult = dnsresolve(h->hostname);
874
875 if (dnsresult) {
876 strncpy(h->ip, dnsresult, sizeof(h->ip));
877 }
878 else if ((dnsmethod == DNS_THEN_IP) && !nullip) {
879 /* Already have the IP setup */
880 }
881 else {
882 char msg[512];
883 /* Cannot resolve hostname */
884 h->dnserror = 1;
885 /* Make this a warning rather than an error
886 errprintf("xymonnet: Cannot resolve IP for host %s\n", h->hostname);
887 */
888 snprintf(msg, sizeof(msg), "xymonnet: Cannot resolve IP for host %s\n", h->hostname);
889 if (warnbuf == NULL) {
890 SBUF_MALLOC(warnbuf, 8192);
891 *warnbuf = '\0';
892 }
893 else if ((strlen(warnbuf) + strlen(msg)) > warnbuf_buflen) {
894 SBUF_REALLOC(warnbuf, warnbuf_buflen + 8192);
895 }
896 strncat(warnbuf, msg, (warnbuf_buflen - strlen(warnbuf)));
897 }
898 }
899
900 return h->ip;
901 }
902
903
load_ping_status(void)904 void load_ping_status(void)
905 {
906 FILE *statusfd;
907 char statusfn[PATH_MAX];
908 char l[MAX_LINE_LEN];
909 char host[MAX_LINE_LEN];
910 int downcount;
911 time_t downstart;
912 xtreePos_t handle;
913 testedhost_t *h;
914
915 snprintf(statusfn, sizeof(statusfn), "%s/ping.%s.status", xgetenv("XYMONTMP"), location);
916 statusfd = fopen(statusfn, "r");
917 if (statusfd == NULL) return;
918
919 while (fgets(l, sizeof(l), statusfd)) {
920 unsigned int uidownstart;
921 if (sscanf(l, "%s %d %u", host, &downcount, &uidownstart) == 3) {
922 downstart = uidownstart;
923 handle = xtreeFind(testhosttree, host);
924 if (handle != xtreeEnd(testhosttree)) {
925 h = (testedhost_t *)xtreeData(testhosttree, handle);
926 if (!h->noping && !h->noconn) {
927 h->downcount = downcount;
928 h->downstart = downstart;
929 }
930 }
931 }
932 }
933
934 fclose(statusfd);
935 }
936
save_ping_status(void)937 void save_ping_status(void)
938 {
939 FILE *statusfd;
940 char statusfn[PATH_MAX];
941 testitem_t *t;
942 int didany = 0;
943
944 snprintf(statusfn, sizeof(statusfn), "%s/ping.%s.status", xgetenv("XYMONTMP"), location);
945 statusfd = fopen(statusfn, "w");
946 if (statusfd == NULL) return;
947
948 for (t=pingtest->items; (t); t = t->next) {
949 if (t->host->downcount) {
950 fprintf(statusfd, "%s %d %u\n", t->host->hostname, t->host->downcount, (unsigned int)t->host->downstart);
951 didany = 1;
952 t->host->repeattest = ((getcurrenttime(NULL) - t->host->downstart) < frequenttestlimit);
953 }
954 }
955
956 fclose(statusfd);
957 if (!didany) unlink(statusfn);
958 }
959
load_test_status(service_t * test)960 void load_test_status(service_t *test)
961 {
962 FILE *statusfd;
963 char statusfn[PATH_MAX];
964 char l[MAX_LINE_LEN];
965 char host[MAX_LINE_LEN];
966 int downcount;
967 time_t downstart;
968 xtreePos_t handle;
969 testedhost_t *h;
970 testitem_t *walk;
971
972 snprintf(statusfn, sizeof(statusfn), "%s/%s.%s.status", xgetenv("XYMONTMP"), test->testname, location);
973 statusfd = fopen(statusfn, "r");
974 if (statusfd == NULL) return;
975
976 while (fgets(l, sizeof(l), statusfd)) {
977 unsigned int uidownstart;
978 if (sscanf(l, "%s %d %u", host, &downcount, &uidownstart) == 3) {
979 downstart = uidownstart;
980 handle = xtreeFind(testhosttree, host);
981 if (handle != xtreeEnd(testhosttree)) {
982 h = (testedhost_t *)xtreeData(testhosttree, handle);
983 if (test == httptest) walk = h->firsthttp;
984 else if (test == ldaptest) walk = h->firstldap;
985 else for (walk = test->items; (walk && (walk->host != h)); walk = walk->next) ;
986
987 if (walk) {
988 walk->downcount = downcount;
989 walk->downstart = downstart;
990 }
991 }
992 }
993 }
994
995 fclose(statusfd);
996 }
997
save_test_status(service_t * test)998 void save_test_status(service_t *test)
999 {
1000 FILE *statusfd;
1001 char statusfn[PATH_MAX];
1002 testitem_t *t;
1003 int didany = 0;
1004
1005 snprintf(statusfn, sizeof(statusfn), "%s/%s.%s.status", xgetenv("XYMONTMP"), test->testname, location);
1006 statusfd = fopen(statusfn, "w");
1007 if (statusfd == NULL) return;
1008
1009 for (t=test->items; (t); t = t->next) {
1010 if (t->downcount) {
1011 fprintf(statusfd, "%s %d %u\n", t->host->hostname, t->downcount, (unsigned int)t->downstart);
1012 didany = 1;
1013 t->host->repeattest = ((getcurrenttime(NULL) - t->downstart) < frequenttestlimit);
1014 }
1015 }
1016
1017 fclose(statusfd);
1018 if (!didany) unlink(statusfn);
1019 }
1020
1021
save_frequenttestlist(int argc,char * argv[])1022 void save_frequenttestlist(int argc, char *argv[])
1023 {
1024 FILE *fd;
1025 char fn[PATH_MAX];
1026 xtreePos_t handle;
1027 testedhost_t *h;
1028 int didany = 0;
1029 int i;
1030
1031 snprintf(fn, sizeof(fn), "%s/frequenttests.%s", xgetenv("XYMONTMP"), location);
1032 fd = fopen(fn, "w");
1033 if (fd == NULL) return;
1034
1035 for (i=1; (i<argc); i++) {
1036 if (!argnmatch(argv[i], "--report")) fprintf(fd, "%s ", argv[i]);
1037 }
1038 for (handle = xtreeFirst(testhosttree); (handle != xtreeEnd(testhosttree)); handle = xtreeNext(testhosttree, handle)) {
1039 h = (testedhost_t *)xtreeData(testhosttree, handle);
1040 if (h->repeattest) {
1041 fprintf(fd, "%s ", h->hostname);
1042 didany = 1;
1043 }
1044 }
1045
1046 fclose(fd);
1047 if (!didany) unlink(fn);
1048 }
1049
1050
run_nslookup_service(service_t * service)1051 void run_nslookup_service(service_t *service)
1052 {
1053 testitem_t *t;
1054 char *lookup;
1055
1056 for (t=service->items; (t); t = t->next) {
1057 if (!t->host->dnserror) {
1058 if (t->testspec && (lookup = strchr(t->testspec, '='))) {
1059 lookup++;
1060 }
1061 else {
1062 lookup = t->host->hostname;
1063 }
1064
1065 t->open = (dns_test_server(ip_to_test(t->host), lookup, t->banner) == 0);
1066 }
1067 }
1068 }
1069
run_ntp_service(service_t * service)1070 void run_ntp_service(service_t *service)
1071 {
1072 testitem_t *t;
1073 char cmd[PATH_MAX+1024];
1074 char *p;
1075 char cmdpath[PATH_MAX];
1076 int use_sntp = 0;
1077
1078 p = getenv("SNTP"); /* Plain "getenv" as we want to know if it's unset */
1079 use_sntp = (p != NULL);
1080
1081 strncpy(cmdpath, (use_sntp ? xgetenv("SNTP") : xgetenv("NTPDATE")), sizeof(cmdpath));
1082
1083 for (t=service->items; (t); t = t->next) {
1084 /* Do not run NTP test if host does not resolve in DNS or is down */
1085 if (!t->host->dnserror && !t->host->pingerror) {
1086 if (use_sntp) {
1087 snprintf(cmd, sizeof(cmd), "%s %s -d %d %s 2>&1", cmdpath, xgetenv("SNTPOPTS"), extcmdtimeout-1, ip_to_test(t->host));
1088 }
1089 else {
1090 snprintf(cmd, sizeof(cmd), "%s %s %s 2>&1", cmdpath, xgetenv("NTPDATEOPTS"), ip_to_test(t->host));
1091 }
1092
1093 t->open = (run_command(cmd, "no server suitable for synchronization", t->banner, 1, extcmdtimeout) == 0);
1094 }
1095 }
1096 }
1097
1098
run_rpcinfo_service(service_t * service)1099 void run_rpcinfo_service(service_t *service)
1100 {
1101 testitem_t *t;
1102 char cmd[PATH_MAX+1024];
1103 char *p;
1104 char cmdpath[PATH_MAX];
1105
1106 p = xgetenv("RPCINFO");
1107 strncpy(cmdpath, (p ? p : "rpcinfo"), sizeof(cmdpath));
1108 for (t=service->items; (t); t = t->next) {
1109 /* Do not run RPCINFO test if host does not resolve in DNS or is down */
1110 if (!t->host->dnserror && (t->host->downcount == 0) && !t->host->pingerror) {
1111 snprintf(cmd, sizeof(cmd), "%s -p %s 2>&1", cmdpath, ip_to_test(t->host));
1112 t->open = (run_command(cmd, NULL, t->banner, 1, extcmdtimeout) == 0);
1113 }
1114 }
1115 }
1116
1117
start_ping_service(service_t * service)1118 int start_ping_service(service_t *service)
1119 {
1120 testitem_t *t;
1121 char *cmd;
1122 char **cmdargs;
1123 int pfd[2];
1124 int i;
1125 void *iptree;
1126 xtreePos_t handle;
1127
1128 /* We build a tree of the IP's to test, so we only test each IP once */
1129 iptree = xtreeNew(strcmp);
1130 for (t=service->items; (t); t = t->next) {
1131 char *rec;
1132 char ip[IP_ADDR_STRLEN+1];
1133
1134 if (t->host->dnserror || t->host->noping) continue;
1135
1136 strncpy(ip, ip_to_test(t->host), sizeof(ip));
1137 handle = xtreeFind(iptree, ip);
1138 if (handle == xtreeEnd(iptree)) {
1139 rec = strdup(ip);
1140 xtreeAdd(iptree, rec, rec);
1141 }
1142
1143 if (t->host->extrapings) {
1144 ipping_t *walk;
1145
1146 for (walk = t->host->extrapings->iplist; (walk); walk = walk->next) {
1147 handle = xtreeFind(iptree, walk->ip);
1148 if (handle == xtreeEnd(iptree)) {
1149 rec = strdup(walk->ip);
1150 xtreeAdd(iptree, rec, rec);
1151 }
1152 }
1153 }
1154 }
1155
1156 /*
1157 * The idea here is to run ping in a separate process, in parallel
1158 * with some other time-consuming task (the TCP network tests).
1159 * We cannot use the simple "popen()/pclose()" interface, because
1160 * a) ping doesn't start the tests until EOF is reached on stdin
1161 * b) EOF on stdin happens with pclose(), but it will also wait
1162 * for the process to finish.
1163 *
1164 * Therefore this slightly more complex solution, which in essence
1165 * forks a new process running "xymonping 2>&1 1>$XYMONTMP/ping.$$"
1166 * The output is then picked up by the finish_ping_service().
1167 */
1168
1169 pingcount = 0;
1170 pingpids = calloc(pingchildcount, sizeof(pid_t));
1171 SBUF_MALLOC(pingcmd, strlen(xgetenv("FPING")) + strlen(xgetenv("FPINGOPTS")) + 2);
1172 snprintf(pingcmd, pingcmd_buflen, "%s %s", xgetenv("FPING"), xgetenv("FPINGOPTS"));
1173
1174 snprintf(pinglog, sizeof(pinglog), "%s/ping-stdout.%lu", xgetenv("XYMONTMP"), (unsigned long)getpid());
1175 snprintf(pingerrlog, sizeof(pingerrlog), "%s/ping-stderr.%lu", xgetenv("XYMONTMP"), (unsigned long)getpid());
1176
1177 /* Setup command line and arguments */
1178 cmdargs = setup_commandargs(pingcmd, &cmd);
1179
1180 for (i=0; (i < pingchildcount); i++) {
1181 /* Get a pipe FD */
1182 if (pipe(pfd) == -1) {
1183 errprintf("Could not create pipe for xymonping\n");
1184 return -1;
1185 }
1186
1187 /* Now fork off the ping child-process */
1188 pingpids[i] = fork();
1189
1190 if (pingpids[i] < 0) {
1191 errprintf("Could not fork() the ping child\n");
1192 return -1;
1193 }
1194 else if (pingpids[i] == 0) {
1195 /*
1196 * child must have
1197 * - stdin fed from the parent
1198 * - stdout going to a file
1199 * - stderr going to another file. This is important, as
1200 * putting it together with stdout will wreak havoc when
1201 * we start parsing the output later on. We could just
1202 * dump it to /dev/null, but it might be useful to see
1203 * what went wrong.
1204 */
1205 int outfile, errfile;
1206
1207 snprintf(pinglog+strlen(pinglog), (sizeof(pinglog) - strlen(pinglog)), ".%02d", i);
1208 snprintf(pingerrlog+strlen(pingerrlog), (sizeof(pingerrlog) - strlen(pingerrlog)), ".%02d", i);
1209
1210 outfile = open(pinglog, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
1211 if (outfile == -1) errprintf("Cannot create file %s : %s\n", pinglog, strerror(errno));
1212 errfile = open(pingerrlog, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
1213 if (errfile == -1) errprintf("Cannot create file %s : %s\n", pingerrlog, strerror(errno));
1214
1215 if ((outfile == -1) || (errfile == -1)) {
1216 /* Ouch - cannot create our output files. Abort. */
1217 exit(98);
1218 }
1219
1220 dup2(pfd[0], STDIN_FILENO);
1221 dup2(outfile, STDOUT_FILENO);
1222 dup2(errfile, STDERR_FILENO);
1223 close(pfd[0]); close(pfd[1]); close(outfile); close(errfile);
1224
1225 execvp(cmd, cmdargs);
1226
1227 /* Should never go here ... just kill the child */
1228 fprintf(stderr, "Command '%s' failed: %s\n", cmd, strerror(errno));
1229 exit(99);
1230 }
1231 else {
1232 /* parent */
1233 char ip[IP_ADDR_STRLEN+1]; /* Must have room for the \n at the end also */
1234 int hnum, feederror = 0;
1235
1236 close(pfd[0]);
1237
1238 /* Feed the IP's to test to the child */
1239 for (handle = xtreeFirst(iptree), hnum = 0; ((feederror == 0) && (handle != xtreeEnd(iptree))); handle = xtreeNext(iptree, handle), hnum++) {
1240 if ((hnum % pingchildcount) != i) continue;
1241
1242 snprintf(ip, sizeof(ip), "%s\n", xtreeKey(iptree, handle));
1243 if (write(pfd[1], ip, strlen(ip)) != strlen(ip)) {
1244 errprintf("Cannot feed IP to ping tool: %s\n", strerror(errno));
1245 feederror = 1;
1246 continue;
1247 }
1248 pingcount++;
1249 }
1250
1251 close(pfd[1]); /* This is when ping starts doing tests */
1252 }
1253 }
1254
1255 for (handle = xtreeFirst(iptree); handle != xtreeEnd(iptree); handle = xtreeNext(iptree, handle)) {
1256 char *rec = xtreeKey(iptree, handle);
1257 xfree(rec);
1258 }
1259 xtreeDestroy(iptree);
1260
1261 return 0;
1262 }
1263
1264
finish_ping_service(service_t * service)1265 int finish_ping_service(service_t *service)
1266 {
1267 testitem_t *t;
1268 FILE *logfd;
1269 char *p;
1270 char l[MAX_LINE_LEN];
1271 char pingip[MAX_LINE_LEN];
1272 int ip1, ip2, ip3, ip4;
1273 int pingstatus, failed = 0, i;
1274 char fn[PATH_MAX];
1275
1276 /* Load status of previously failed tests */
1277 load_ping_status();
1278
1279 /*
1280 * Wait for the ping child to finish.
1281 * If we're lucky, it will be done already since it has run
1282 * while we were doing tcp tests.
1283 */
1284 for (i = 0; (i < pingchildcount); i++) {
1285 waitpid(pingpids[i], &pingstatus, 0);
1286 switch (WEXITSTATUS(pingstatus)) {
1287 case 0: /* All hosts reachable */
1288 case 1: /* Some hosts unreachable */
1289 case 2: /* Some IP's not found (should not happen) */
1290 break;
1291
1292 case 3: /* Bad command-line args, or not suid-root */
1293 failed = 1;
1294 errprintf("Execution of '%s' failed - program not suid root?\n", pingcmd);
1295 break;
1296
1297 case 98:
1298 failed = 1;
1299 errprintf("xymonping child could not create outputfiles in %s\n", xgetenv("XYMONTMP"));
1300 break;
1301
1302 case 99:
1303 failed = 1;
1304 errprintf("Could not run the command '%s' (exec failed)\n", pingcmd);
1305 break;
1306
1307 default:
1308 failed = 1;
1309 errprintf("Execution of '%s' failed with error-code %d\n",
1310 pingcmd, WEXITSTATUS(pingstatus));
1311 }
1312
1313 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
1314 /* Ignore gcc warnings about truncating filenames when adding a number */
1315 #pragma GCC diagnostic push
1316 #pragma GCC diagnostic ignored "-Wformat-truncation"
1317 #endif // __GNUC__
1318
1319 /* Open the new ping result file */
1320 snprintf(fn, sizeof(fn), "%s.%02d", pinglog, i);
1321 logfd = fopen(fn, "r");
1322 if (logfd == NULL) {
1323 failed = 1;
1324 errprintf("Cannot open ping output file %s\n", fn);
1325 }
1326 if (!debug) unlink(fn); /* We have an open filehandle, so it's ok to delete the file now */
1327
1328 /* Copy error messages to the Xymon logfile */
1329 snprintf(fn, sizeof(fn), "%s.%02d", pingerrlog, i);
1330 if (failed) {
1331 FILE *errfd;
1332 char buf[1024];
1333
1334 errfd = fopen(fn, "r");
1335 if (errfd && fgets(buf, sizeof(buf), errfd)) {
1336 errprintf("%s", buf);
1337 }
1338 if (errfd) fclose(errfd);
1339 }
1340 if (!debug) unlink(fn);
1341 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
1342 #pragma GCC diagnostic pop
1343 #endif // __GNUC__
1344
1345 if (failed) {
1346 /* Flag all ping tests as "undecided" */
1347 bigfailure = 1;
1348 for (t=service->items; (t); t = t->next) t->open = -1;
1349 }
1350 else {
1351 /* The test did run, and we have a result-file. Look at it. */
1352 while (fgets(l, sizeof(l), logfd)) {
1353 p = strchr(l, '\n'); if (p) *p = '\0';
1354 if (sscanf(l, "%d.%d.%d.%d ", &ip1, &ip2, &ip3, &ip4) == 4) {
1355
1356 snprintf(pingip, sizeof(pingip), "%d.%d.%d.%d", ip1, ip2, ip3, ip4);
1357
1358 /*
1359 * Need to loop through all testitems - there may be multiple entries for
1360 * the same IP-address.
1361 */
1362 for (t=service->items; (t); t = t->next) {
1363 if (strcmp(t->host->ip, pingip) == 0) {
1364 if (t->open) dbgprintf("More than one ping result for %s\n", pingip);
1365 t->open = (strstr(l, "is alive") != NULL);
1366 t->banner = dupstrbuffer(l);
1367 }
1368
1369 if (t->host->extrapings) {
1370 ipping_t *walk;
1371 for (walk = t->host->extrapings->iplist; (walk); walk = walk->next) {
1372 if (strcmp(walk->ip, pingip) == 0) {
1373 if (t->open) dbgprintf("More than one ping result for %s\n", pingip);
1374 walk->open = (strstr(l, "is alive") != NULL);
1375 walk->banner = dupstrbuffer(l);
1376 }
1377 }
1378 }
1379 }
1380 }
1381 }
1382 }
1383
1384 if (logfd) fclose(logfd);
1385 }
1386
1387 /*
1388 * Handle the router dependency stuff. I.e. for all hosts
1389 * where the ping test failed, go through the list of router
1390 * dependencies and if one of the dependent hosts also has
1391 * a failed ping test, point the dependency there.
1392 */
1393 for (t=service->items; (t); t = t->next) {
1394 if (!t->open && t->host->routerdeps) {
1395 testitem_t *router;
1396
1397 strncpy(l, t->host->routerdeps, sizeof(l));
1398 p = strtok(l, ",");
1399 while (p && (t->host->deprouterdown == NULL)) {
1400 for (router=service->items;
1401 (router && (strcmp(p, router->host->hostname) != 0));
1402 router = router->next) ;
1403
1404 if (router && !router->open) t->host->deprouterdown = router->host;
1405
1406 p = strtok(NULL, ",");
1407 }
1408 }
1409 }
1410
1411 return 0;
1412 }
1413
1414
decide_color(service_t * service,char * svcname,testitem_t * test,int failgoesclear,char * cause)1415 int decide_color(service_t *service, char *svcname, testitem_t *test, int failgoesclear, char *cause)
1416 {
1417 int color = COL_GREEN;
1418 int countasdown = 0;
1419 char *deptest = NULL;
1420
1421 *cause = '\0';
1422 if (service == pingtest) {
1423 /*
1424 * "noconn" is handled elsewhere.
1425 * "noping" always sends back a status "clear".
1426 * If DNS error, return red and count as down.
1427 */
1428 if (test->open == -1) {
1429 /* Failed to run the ping utility. */
1430 strcpy(cause, "Xymon system failure");
1431 return COL_CLEAR;
1432 }
1433 else if (test->host->noping) {
1434 /* Ping test disabled - go "clear". End of story. */
1435 strcpy(cause, "Ping test disabled (noping)");
1436 return COL_CLEAR;
1437 }
1438 else if (test->host->dnserror) {
1439 strcpy(cause, "DNS lookup failure");
1440 color = COL_RED; countasdown = 1;
1441 }
1442 else {
1443 if (test->host->extrapings == NULL) {
1444 /* Red if (open=0, reverse=0) or (open=1, reverse=1) */
1445 if ((test->open + test->reverse) != 1) {
1446 sprintf(cause, "Host %s respond to ping", (test->open ? "does" : "does not"));
1447 color = COL_RED; countasdown = 1;
1448 }
1449 }
1450 else {
1451 /* Host with many pings */
1452 int totalcount = 1;
1453 int okcount = test->open;
1454 ipping_t *walk;
1455
1456 for (walk = test->host->extrapings->iplist; (walk); walk = walk->next) {
1457 if (walk->open) okcount++;
1458 totalcount++;
1459 }
1460
1461 switch (test->host->extrapings->matchtype) {
1462 case MULTIPING_BEST:
1463 if (okcount == 0) {
1464 color = COL_RED;
1465 countasdown = 1;
1466 sprintf(cause, "Host does not respond to ping on any of %d IP's",
1467 totalcount);
1468 }
1469 break;
1470 case MULTIPING_WORST:
1471 if (okcount < totalcount) {
1472 color = COL_RED;
1473 countasdown = 1;
1474 sprintf(cause, "Host responds to ping on %d of %d IP's",
1475 okcount, totalcount);
1476 }
1477 break;
1478 }
1479 }
1480 }
1481
1482 /* Handle the "route" tag dependencies. */
1483 if ((color == COL_RED) && test->host->deprouterdown) {
1484 char *routertext;
1485
1486 routertext = test->host->deprouterdown->hosttype;
1487 if (routertext == NULL) routertext = xgetenv("XYMONROUTERTEXT");
1488 if (routertext == NULL) routertext = "router";
1489
1490 strcat(cause, "\nIntermediate ");
1491 strcat(cause, routertext);
1492 strcat(cause, " down ");
1493 color = COL_YELLOW;
1494 }
1495
1496 /* Set pingerror for later use by NTP and RPCINFO tests */
1497 test->host->pingerror = (color == COL_RED ? 1 : 0);
1498
1499 /* Handle "badconn" */
1500 if ((color == COL_RED) && (test->host->downcount < test->host->badconn[2])) {
1501 if (test->host->downcount >= test->host->badconn[1]) color = COL_YELLOW;
1502 else if (test->host->downcount >= test->host->badconn[0]) color = COL_CLEAR;
1503 else color = COL_GREEN;
1504 }
1505
1506 /* Run traceroute , but not on dialup or reverse-test hosts */
1507 if ((color == COL_RED) && test->host->dotrace && !test->host->dialup && !test->reverse && !test->dialup) {
1508 char cmd[PATH_MAX];
1509
1510 if (getenv("TRACEROUTEOPTS")) {
1511 /* post 4.3.21 */
1512 snprintf(cmd, sizeof(cmd), "%s %s %s 2>&1", xgetenv("TRACEROUTE"), xgetenv("TRACEROUTEOPTS"), test->host->ip);
1513 }
1514 else {
1515 snprintf(cmd, sizeof(cmd), "%s %s 2>&1", xgetenv("TRACEROUTE"), test->host->ip);
1516 }
1517 test->host->traceroute = newstrbuffer(0);
1518 run_command(cmd, NULL, test->host->traceroute, 0, extcmdtimeout);
1519 }
1520 }
1521 else {
1522 /* TCP test */
1523 if (test->host->dnserror) {
1524 strcpy(cause, "DNS lookup failure");
1525 color = COL_RED; countasdown = 1;
1526 }
1527 else {
1528 if (test->reverse) {
1529 /*
1530 * Reverse tests go RED when open.
1531 * If not open, they may go CLEAR if the ping test failed
1532 */
1533
1534 if (test->open) {
1535 strcpy(cause, "Service responds when it should not");
1536 color = COL_RED; countasdown = 1;
1537 }
1538 else if (failgoesclear && (test->host->downcount != 0) && !test->alwaystrue) {
1539 strcpy(cause, "Host appears to be down");
1540 color = COL_CLEAR; countasdown = 0;
1541 }
1542 }
1543 else {
1544 if (!test->open) {
1545 if (failgoesclear && (test->host->downcount != 0) && !test->alwaystrue) {
1546 strcpy(cause, "Host appears to be down");
1547 color = COL_CLEAR; countasdown = 0;
1548 }
1549 else {
1550 tcptest_t *tcptest = (tcptest_t *)test->privdata;
1551
1552 strcpy(cause, "Service unavailable");
1553 if (tcptest) {
1554 switch (tcptest->errcode) {
1555 case CONTEST_ETIMEOUT:
1556 strcat(cause, " (connect timeout)");
1557 break;
1558 case CONTEST_ENOCONN :
1559 strcat(cause, " (");
1560 strcat(cause, strerror(tcptest->connres));
1561 strcat(cause, ")");
1562 break;
1563 case CONTEST_EDNS :
1564 strcat(cause, " (DNS error)");
1565 break;
1566 case CONTEST_EIO :
1567 strcat(cause, " (I/O error)");
1568 break;
1569 case CONTEST_ESSL :
1570 strcat(cause, " (SSL error)");
1571 break;
1572 }
1573 }
1574 color = COL_RED; countasdown = 1;
1575 }
1576 }
1577 else {
1578 tcptest_t *tcptest = (tcptest_t *)test->privdata;
1579
1580 /* Check if we got the expected data */
1581 if (checktcpresponse && (service->toolid == TOOL_CONTEST) && !tcp_got_expected((tcptest_t *)test->privdata)) {
1582 strcpy(cause, "Unexpected service response");
1583 color = respcheck_color; countasdown = 1;
1584 }
1585
1586 /* Check that other transport issues didn't occur (like SSL) */
1587 if (tcptest && (tcptest->errcode != CONTEST_ENOERROR)) {
1588 switch (tcptest->errcode) {
1589 case CONTEST_ETIMEOUT :
1590 strcpy(cause, "Service listening but unavailable (connect timeout)");
1591 color = COL_RED; countasdown = 1;
1592 break;
1593 case CONTEST_ENOCONN :
1594 strcpy(cause, "Service listening but unavailable (");
1595 strcat(cause, strerror(tcptest->connres));
1596 strcat(cause, ")");
1597 color = COL_RED; countasdown = 1;
1598 break;
1599 case CONTEST_EDNS :
1600 strcpy(cause, "Service listening but unavailable (DNS error)");
1601 color = COL_RED; countasdown = 1;
1602 break;
1603 case CONTEST_EIO :
1604 strcpy(cause, "Service listening but unavailable (I/O error)");
1605 color = COL_RED; countasdown = 1;
1606 break;
1607 case CONTEST_ESSL :
1608 strcpy(cause, "Service listening but unavailable (SSL error)");
1609 color = COL_RED; countasdown = 1;
1610 break;
1611 default :
1612 /* Should not get here */
1613 errprintf("-> TCPtest error %d seen on open connection for %s.%s\n", tcptest->errcode, test->host->hostname, test->service->testname);
1614 color = COL_YELLOW;
1615 break;
1616 }
1617 // color = COL_RED; countasdown = 1;
1618 }
1619
1620 }
1621 }
1622 }
1623
1624 /* Handle test dependencies */
1625 if ( failgoesclear && (color == COL_RED) && !test->alwaystrue && (deptest = deptest_failed(test->host, test->service->testname)) ) {
1626 strcpy(cause, deptest);
1627 color = COL_CLEAR;
1628 }
1629
1630 /* Handle the "badtest" stuff for other tests */
1631 if ((color == COL_RED) && (test->downcount < test->badtest[2])) {
1632 if (test->downcount >= test->badtest[1]) color = COL_YELLOW;
1633 else if (test->downcount >= test->badtest[0]) color = COL_CLEAR;
1634 else color = COL_GREEN;
1635 }
1636 }
1637
1638
1639 /* Dialup hosts and dialup tests report red as clear */
1640 if ( ((color == COL_RED) || (color == COL_YELLOW)) && (test->host->dialup || test->dialup) && !test->reverse) {
1641 strcat(cause, "\nDialup host or service");
1642 color = COL_CLEAR; countasdown = 0;
1643 }
1644
1645 /* If a NOPAGENET service, downgrade RED to YELLOW */
1646 if (color == COL_RED) {
1647 SBUF_DEFINE(nopagename);
1648
1649 /* Check if this service is a NOPAGENET service. */
1650 SBUF_MALLOC(nopagename, strlen(svcname)+3);
1651 snprintf(nopagename, nopagename_buflen, ",%s,", svcname);
1652 if (strstr(nonetpage, nopagename) != NULL) color = COL_YELLOW;
1653 xfree(nopagename);
1654 }
1655
1656 if (service == pingtest) {
1657 if (countasdown) {
1658 test->host->downcount++;
1659 if (test->host->downcount == 1) test->host->downstart = getcurrenttime(NULL);
1660 }
1661 else test->host->downcount = 0;
1662 }
1663 else {
1664 if (countasdown) {
1665 test->downcount++;
1666 if (test->downcount == 1) test->downstart = getcurrenttime(NULL);
1667 }
1668 else test->downcount = 0;
1669 }
1670 return color;
1671 }
1672
1673
send_results(service_t * service,int failgoesclear)1674 void send_results(service_t *service, int failgoesclear)
1675 {
1676 testitem_t *t;
1677 int color;
1678 char msgline[4096];
1679 char msgtext[4096];
1680 char causetext[1024];
1681 char *svcname;
1682
1683 svcname = strdup(service->testname);
1684 if (service->namelen) svcname[service->namelen] = '\0';
1685
1686 dbgprintf("Sending results for service %s\n", svcname);
1687
1688 for (t=service->items; (t); t = t->next) {
1689 char flags[10];
1690 int i;
1691
1692 if (t->internal) continue;
1693
1694 i = 0;
1695 flags[i++] = (t->open ? 'O' : 'o');
1696 flags[i++] = (t->reverse ? 'R' : 'r');
1697 flags[i++] = ((t->dialup || t->host->dialup) ? 'D' : 'd');
1698 flags[i++] = (t->alwaystrue ? 'A' : 'a');
1699 flags[i++] = (t->silenttest ? 'S' : 's');
1700 flags[i++] = (t->host->testip ? 'T' : 't');
1701 flags[i++] = (t->host->dodns ? 'L' : 'l');
1702 flags[i++] = (t->host->dnserror ? 'E' : 'e');
1703 flags[i++] = '\0';
1704
1705 color = decide_color(service, svcname, t, failgoesclear, causetext);
1706
1707 init_status(color);
1708 if (dosendflags)
1709 snprintf(msgline, sizeof(msgline), "status+%d %s.%s %s <!-- [flags:%s] --> %s %s %s ",
1710 validity, commafy(t->host->hostname), svcname, colorname(color),
1711 flags, timestamp,
1712 svcname, ( ((color == COL_RED) || (color == COL_YELLOW)) ? "NOT ok" : "ok"));
1713 else
1714 snprintf(msgline, sizeof(msgline), "status %s.%s %s %s %s %s ",
1715 commafy(t->host->hostname), svcname, colorname(color),
1716 timestamp,
1717 svcname, ( ((color == COL_RED) || (color == COL_YELLOW)) ? "NOT ok" : "ok"));
1718
1719 if (t->host->dnserror) {
1720 strncat(msgline, ": DNS lookup failed", (sizeof(msgline) - strlen(msgline)));
1721 snprintf(msgtext, sizeof(msgtext), "\nUnable to resolve hostname %s\n\n", t->host->hostname);
1722 }
1723 else {
1724 snprintf(msgtext, sizeof(msgtext), "\nService %s on %s is ", svcname, t->host->hostname);
1725 switch (color) {
1726 case COL_GREEN:
1727 strncat(msgtext, "OK ", (sizeof(msgtext) - strlen(msgtext)));
1728 strncat(msgtext, (t->reverse ? "(down)" : "(up)"), (sizeof(msgtext) - strlen(msgtext)));
1729 strncat(msgtext, "\n", (sizeof(msgtext) - strlen(msgtext)));
1730 break;
1731
1732 case COL_RED:
1733 case COL_YELLOW:
1734 if ((service == pingtest) && t->host->deprouterdown) {
1735 char *routertext;
1736
1737 routertext = t->host->deprouterdown->hosttype;
1738 if (routertext == NULL) routertext = xgetenv("XYMONROUTERTEXT");
1739 if (routertext == NULL) routertext = "router";
1740
1741 strncat(msgline, ": Intermediate ", (sizeof(msgline) - strlen(msgline)));
1742 strncat(msgline, routertext, (sizeof(msgline) - strlen(msgline)));
1743 strncat(msgline, " down", (sizeof(msgline) - strlen(msgline)));
1744
1745 snprintf(msgtext+strlen(msgtext), (sizeof(msgtext) - strlen(msgtext)),
1746 "%s.\nThe %s %s (IP:%s) is not reachable, causing this host to be unreachable.\n",
1747 failtext, routertext,
1748 ((testedhost_t *)t->host->deprouterdown)->hostname,
1749 ((testedhost_t *)t->host->deprouterdown)->ip);
1750 }
1751 else {
1752 snprintf(msgtext+strlen(msgtext), (sizeof(msgtext) - strlen(msgtext)), "%s : %s\n", failtext, causetext);
1753 }
1754 break;
1755
1756 case COL_CLEAR:
1757 strncat(msgtext, "OK\n", (sizeof(msgtext) - strlen(msgtext)));
1758 if (service == pingtest) {
1759 if (t->host->deprouterdown) {
1760 char *routertext;
1761
1762 routertext = t->host->deprouterdown->hosttype;
1763 if (routertext == NULL) routertext = xgetenv("XYMONROUTERTEXT");
1764 if (routertext == NULL) routertext = "router";
1765
1766 strncat(msgline, ": Intermediate ", (sizeof(msgline) - strlen(msgline)));
1767 strncat(msgline, routertext, (sizeof(msgline) - strlen(msgline)));
1768 strncat(msgline, " down", (sizeof(msgline) - strlen(msgline)));
1769
1770 strncat(msgtext, "\nThe ", (sizeof(msgtext) - strlen(msgtext)));
1771 strncat(msgtext, routertext, (sizeof(msgtext) - strlen(msgtext))); strncat(msgtext, " ", (sizeof(msgtext) - strlen(msgtext)));
1772 strncat(msgtext, ((testedhost_t *)t->host->deprouterdown)->hostname, (sizeof(msgtext) - strlen(msgtext)));
1773 strncat(msgtext, " (IP:", (sizeof(msgtext) - strlen(msgtext)));
1774 strncat(msgtext, ((testedhost_t *)t->host->deprouterdown)->ip, (sizeof(msgtext) - strlen(msgtext)));
1775 strncat(msgtext, ") is not reachable, causing this host to be unreachable.\n", (sizeof(msgtext) - strlen(msgtext)));
1776 }
1777 else if (t->host->noping) {
1778 strncat(msgline, ": Disabled", (sizeof(msgline) - strlen(msgline)));
1779 strncat(msgtext, "Ping check disabled (noping)\n", (sizeof(msgtext) - strlen(msgtext)));
1780 }
1781 else if (t->host->dialup) {
1782 strncat(msgline, ": Disabled (dialup host)", (sizeof(msgline) - strlen(msgline)));
1783 strncat(msgtext, "Dialup host\n", (sizeof(msgtext) - strlen(msgtext)));
1784 }
1785 else if (t->open == -1) {
1786 strncat(msgline, ": System failure of the ping test", (sizeof(msgline) - strlen(msgline)));
1787 strncat(msgtext, "Xymon system error\n", (sizeof(msgtext) - strlen(msgtext)));
1788 }
1789 /* "clear" due to badconn: no extra text */
1790 }
1791 else {
1792 /* Non-ping test clear: Dialup test or failed ping */
1793 strncat(msgline, ": Ping failed, or dialup host/service", (sizeof(msgline) - strlen(msgline)));
1794 strncat(msgtext, "Dialup host/service, or test depends on another failed test\n", (sizeof(msgtext) - strlen(msgtext)));
1795 strncat(msgtext, causetext, (sizeof(msgtext) - strlen(msgtext)));
1796 }
1797 break;
1798 }
1799 strncat(msgtext, "\n", (sizeof(msgtext) - strlen(msgtext)));
1800 }
1801 strncat(msgline, "\n", (sizeof(msgline) - strlen(msgline)));
1802 addtostatus(msgline);
1803 addtostatus(msgtext);
1804
1805 if ((service == pingtest) && t->host->downcount) {
1806 snprintf(msgtext, sizeof(msgtext), "\nSystem unreachable for %d poll periods (%u seconds)\n",
1807 t->host->downcount, (unsigned int)(getcurrenttime(NULL) - t->host->downstart));
1808 addtostatus(msgtext);
1809 }
1810
1811 if (STRBUFLEN(t->banner)) {
1812 if (service == pingtest) {
1813 snprintf(msgtext, sizeof(msgtext), "\n&%s %s\n", colorname(t->open ? COL_GREEN : COL_RED), STRBUF(t->banner));
1814 addtostatus(msgtext);
1815 if (t->host->extrapings) {
1816 ipping_t *walk;
1817 for (walk = t->host->extrapings->iplist; (walk); walk = walk->next) {
1818 if (STRBUFLEN(walk->banner)) {
1819 snprintf(msgtext, sizeof(msgtext), "&%s %s\n",
1820 colorname(walk->open ? COL_GREEN : COL_RED), STRBUF(walk->banner));
1821 addtostatus(msgtext);
1822 }
1823 }
1824 }
1825 }
1826 else {
1827 addtostatus("\n"); addtostrstatus(t->banner); addtostatus("\n");
1828 }
1829 }
1830
1831 if ((service == pingtest) && t->host->traceroute && (STRBUFLEN(t->host->traceroute) > 0)) {
1832 addtostatus("Traceroute results:\n");
1833 addtostrstatus(t->host->traceroute);
1834 addtostatus("\n");
1835 }
1836
1837 if (t->duration.tv_sec != -1) {
1838 snprintf(msgtext, sizeof(msgtext), "\nSeconds: %u.%.9ld\n",
1839 (unsigned int)t->duration.tv_sec, t->duration.tv_nsec);
1840 addtostatus(msgtext);
1841 }
1842 addtostatus("\n\n");
1843 finish_status();
1844 }
1845 }
1846
1847
send_rpcinfo_results(service_t * service,int failgoesclear)1848 void send_rpcinfo_results(service_t *service, int failgoesclear)
1849 {
1850 testitem_t *t;
1851 int color;
1852 char msgline[2048];
1853 char *msgbuf;
1854 char causetext[1024];
1855
1856 msgbuf = (char *)malloc(MSGBUFSIZE);
1857
1858 for (t=service->items; (t); t = t->next) {
1859 char *wantedrpcsvcs = NULL;
1860 char *p;
1861
1862 /* First see if the rpcinfo command succeeded */
1863 *msgbuf = '\0';
1864
1865 color = decide_color(service, service->testname, t, failgoesclear, causetext);
1866 p = strchr(t->testspec, '=');
1867 if (p) wantedrpcsvcs = strdup(p+1);
1868
1869 if ((color == COL_GREEN) && STRBUFLEN(t->banner) && wantedrpcsvcs) {
1870 char *rpcsvc, *aline;
1871
1872 rpcsvc = strtok(wantedrpcsvcs, ",");
1873 while (rpcsvc) {
1874 struct rpcent *rpcinfo;
1875 int svcfound = 0;
1876 int aprogram;
1877 int aversion;
1878 char aprotocol[10];
1879 int aport;
1880
1881 rpcinfo = getrpcbyname(rpcsvc);
1882 aline = STRBUF(t->banner);
1883 while ((!svcfound) && rpcinfo && aline && (*aline != '\0')) {
1884 p = strchr(aline, '\n');
1885 if (p) *p = '\0';
1886
1887 if (sscanf(aline, "%d %d %s %d", &aprogram, &aversion, aprotocol, &aport) == 4) {
1888 svcfound = (aprogram == rpcinfo->r_number);
1889 }
1890
1891 aline = p;
1892 if (p) {
1893 *p = '\n';
1894 aline++;
1895 }
1896 }
1897
1898 if (svcfound) {
1899 snprintf(msgline, sizeof(msgline), "&%s Service %s (ID: %d) found on port %d\n",
1900 colorname(COL_GREEN), rpcsvc, rpcinfo->r_number, aport);
1901 }
1902 else if (rpcinfo) {
1903 color = COL_RED;
1904 snprintf(msgline, sizeof(msgline), "&%s Service %s (ID: %d) NOT found\n",
1905 colorname(COL_RED), rpcsvc, rpcinfo->r_number);
1906 }
1907 else {
1908 color = COL_RED;
1909 snprintf(msgline, sizeof(msgline), "&%s Unknown RPC service %s\n",
1910 colorname(COL_RED), rpcsvc);
1911 }
1912 strncat(msgbuf, msgline, (MSGBUFSIZE - strlen(msgbuf)));
1913
1914 rpcsvc = strtok(NULL, ",");
1915 }
1916 }
1917
1918 if (wantedrpcsvcs) xfree(wantedrpcsvcs);
1919
1920 init_status(color);
1921 snprintf(msgline, sizeof(msgline), "status+%d %s.%s %s %s %s %s, %s\n\n",
1922 validity, commafy(t->host->hostname), service->testname, colorname(color), timestamp,
1923 service->testname,
1924 ( ((color == COL_RED) || (color == COL_YELLOW)) ? "NOT ok" : "ok"),
1925 causetext);
1926 addtostatus(msgline);
1927
1928 /* The summary of wanted RPC services */
1929 addtostatus(msgbuf);
1930
1931 /* rpcinfo output */
1932 if (t->open) {
1933 if (STRBUFLEN(t->banner)) {
1934 addtostatus("\n\n");
1935 addtostrstatus(t->banner);
1936 }
1937 else {
1938 snprintf(msgline, sizeof(msgline), "\n\nNo output from rpcinfo -p %s\n", t->host->ip);
1939 addtostatus(msgline);
1940 }
1941 }
1942 else {
1943 addtostatus("\n\nCould not connect to the portmapper service\n");
1944 if (STRBUFLEN(t->banner)) addtostrstatus(t->banner);
1945 }
1946 finish_status();
1947 }
1948
1949 xfree(msgbuf);
1950 }
1951
1952
send_sslcert_status(testedhost_t * host)1953 void send_sslcert_status(testedhost_t *host)
1954 {
1955 int color = -1;
1956 xtreePos_t handle;
1957 service_t *s;
1958 testitem_t *t;
1959 char msgline[1024];
1960 strbuffer_t *sslmsg;
1961 time_t now = getcurrenttime(NULL);
1962 char *certowner;
1963
1964 sslmsg = newstrbuffer(0);
1965
1966 for (handle = xtreeFirst(svctree); handle != xtreeEnd(svctree); handle = xtreeNext(svctree, handle)) {
1967 s = (service_t *)xtreeData(svctree, handle);
1968 certowner = s->testname;
1969
1970 for (t=s->items; (t); t=t->next) {
1971 if ((t->host == host) && t->certinfo && (t->certexpires > 0)) {
1972 int sslcolor = COL_GREEN;
1973 int ciphercolor = COL_GREEN;
1974 int keycolor = COL_GREEN;
1975
1976 if (s == httptest) certowner = ((http_data_t *)t->privdata)->url;
1977 else if (s == ldaptest) certowner = t->testspec;
1978
1979 if (t->certexpires < (now+host->sslwarndays*86400)) sslcolor = COL_YELLOW;
1980 if (t->certexpires < (now+host->sslalarmdays*86400)) sslcolor = COL_RED;
1981 if (sslcolor > color) color = sslcolor;
1982
1983 if (host->mincipherbits && (t->mincipherbits < host->mincipherbits)) ciphercolor = COL_RED;
1984 if (ciphercolor > color) color = ciphercolor;
1985
1986 if (sslminkeysize > 0) {
1987 if ((t->certkeysz > 0) && (t->certkeysz < sslminkeysize)) keycolor = COL_YELLOW;
1988 if (keycolor > color) color = keycolor;
1989 }
1990
1991 if (t->certexpires > now) {
1992 snprintf(msgline, sizeof(msgline), "\n&%s SSL certificate for %s expires in %u days\n\n",
1993 colorname(sslcolor), certowner,
1994 (unsigned int)((t->certexpires - now) / 86400));
1995 }
1996 else {
1997 snprintf(msgline, sizeof(msgline), "\n&%s SSL certificate for %s expired %u days ago\n\n",
1998 colorname(sslcolor), certowner,
1999 (unsigned int)((now - t->certexpires) / 86400));
2000 }
2001 addtobuffer(sslmsg, msgline);
2002
2003 if (host->mincipherbits) {
2004 snprintf(msgline, sizeof(msgline), "&%s Minimum available SSL encryption is %d bits (should be %d)\n",
2005 colorname(ciphercolor), t->mincipherbits, host->mincipherbits);
2006 addtobuffer(sslmsg, msgline);
2007 }
2008
2009 if (keycolor != COL_GREEN) {
2010 snprintf(msgline, sizeof(msgline), "&%s Certificate public key size is less than %d bits\n", colorname(keycolor), sslminkeysize);
2011 addtobuffer(sslmsg, msgline);
2012 }
2013 addtobuffer(sslmsg, "\n");
2014
2015 addtobuffer(sslmsg, t->certinfo);
2016 }
2017 }
2018 }
2019
2020 if (color != -1) {
2021 /* Send off the sslcert status report */
2022 init_status(color);
2023 snprintf(msgline, sizeof(msgline), "status+%d %s.%s %s %s\n",
2024 validity, commafy(host->hostname), ssltestname, colorname(color), timestamp);
2025 addtostatus(msgline);
2026 addtostrstatus(sslmsg);
2027 addtostatus("\n\n");
2028 finish_status();
2029 }
2030
2031 freestrbuffer(sslmsg);
2032 }
2033
main(int argc,char * argv[])2034 int main(int argc, char *argv[])
2035 {
2036 xtreePos_t handle;
2037 service_t *s;
2038 testedhost_t *h;
2039 testitem_t *t;
2040 int argi;
2041 int concurrency = 0;
2042 char *pingcolumn = "";
2043 char *egocolumn = NULL;
2044 int failgoesclear = 0; /* IPTEST_2_CLEAR_ON_FAILED_CONN */
2045 int dumpdata = 0;
2046 int runtimewarn; /* 300 = default TASKSLEEP setting */
2047 int servicedumponly = 0;
2048 int pingrunning = 0;
2049 int usebackfeedqueue = 0;
2050
2051 if (init_ldap_library() != 0) {
2052 errprintf("Failed to initialize ldap library\n");
2053 return 1;
2054 }
2055
2056 if (xgetenv("CONNTEST") && (strcmp(xgetenv("CONNTEST"), "FALSE") == 0)) pingcolumn = NULL;
2057 runtimewarn = (xgetenv("TASKSLEEP") ? atol(xgetenv("TASKSLEEP")) : 300);
2058
2059 for (argi=1; (argi < argc); argi++) {
2060 if (argnmatch(argv[argi], "--timeout=")) {
2061 char *p = strchr(argv[argi], '=');
2062 p++; timeout = atoi(p);
2063 }
2064 else if (argnmatch(argv[argi], "--conntimeout=")) {
2065 int newtimeout;
2066 char *p = strchr(argv[argi], '=');
2067 p++; newtimeout = atoi(p);
2068 if (newtimeout > timeout) timeout = newtimeout;
2069 errprintf("Deprecated option '--conntimeout' should not be used\n");
2070 }
2071 else if (argnmatch(argv[argi], "--cmdtimeout=")) {
2072 char *p = strchr(argv[argi], '=');
2073 p++; extcmdtimeout = atoi(p);
2074 }
2075 else if (argnmatch(argv[argi], "--concurrency=")) {
2076 char *p = strchr(argv[argi], '=');
2077 p++; concurrency = atoi(p);
2078 }
2079 else if (argnmatch(argv[argi], "--dns-timeout=") || argnmatch(argv[argi], "--dns-max-all=")) {
2080 char *p = strchr(argv[argi], '=');
2081 p++; dnstimeout = atoi(p);
2082 }
2083 else if (argnmatch(argv[argi], "--dns=")) {
2084 char *p = strchr(argv[argi], '=');
2085 p++;
2086 if (strcmp(p, "only") == 0) dnsmethod = DNS_ONLY;
2087 else if (strcmp(p, "ip") == 0) dnsmethod = IP_ONLY;
2088 else dnsmethod = DNS_THEN_IP;
2089 }
2090 else if (strcmp(argv[argi], "--no-ares") == 0) {
2091 use_ares_lookup = 0;
2092 }
2093 else if (argnmatch(argv[argi], "--maxdnsqueue=")) {
2094 char *p = strchr(argv[argi], '=');
2095 max_dns_per_run = atoi(p+1);
2096 }
2097 else if (argnmatch(argv[argi], "--dnslog=")) {
2098 char *fn = strchr(argv[argi], '=');
2099 dnsfaillog = fopen(fn+1, "w");
2100 }
2101 else if (argnmatch(argv[argi], "--report=") || (strcmp(argv[argi], "--report") == 0)) {
2102 char *p = strchr(argv[argi], '=');
2103 if (p) {
2104 egocolumn = strdup(p+1);
2105 }
2106 else egocolumn = "xymonnet";
2107 timing = 1;
2108 }
2109 else if (strcmp(argv[argi], "--test-untagged") == 0) {
2110 testuntagged = 1;
2111 }
2112 else if (argnmatch(argv[argi], "--frequenttestlimit=")) {
2113 char *p = strchr(argv[argi], '=');
2114 p++; frequenttestlimit = atoi(p);
2115 }
2116 else if (argnmatch(argv[argi], "--timelimit=")) {
2117 char *p = strchr(argv[argi], '=');
2118 p++; runtimewarn = atol(p);
2119 }
2120 else if (argnmatch(argv[argi], "--huge=")) {
2121 char *p = strchr(argv[argi], '=');
2122 p++; warnbytesread = atoi(p);
2123 }
2124 else if (strcmp(argv[argi], "--loadhostsfromxymond") == 0) {
2125 loadhostsfromxymond = 1;
2126 }
2127
2128 /* Options for TCP tests */
2129 else if (strcmp(argv[argi], "--checkresponse") == 0) {
2130 checktcpresponse = 1;
2131 }
2132 else if (argnmatch(argv[argi], "--checkresponse=")) {
2133 char *p = strchr(argv[argi], '=');
2134 checktcpresponse = 1;
2135 respcheck_color = parse_color(p+1);
2136 if (respcheck_color == -1) {
2137 errprintf("Invalid colorname in '%s' - using yellow\n", argv[argi]);
2138 respcheck_color = COL_YELLOW;
2139 }
2140 }
2141 else if (strcmp(argv[argi], "--no-flags") == 0) {
2142 dosendflags = 0;
2143 }
2144 else if (strcmp(argv[argi], "--shuffle") == 0) {
2145 shuffletests = 1;
2146 }
2147 else if (argnmatch(argv[argi], "--source-ip=")) {
2148 char *p = strchr(argv[argi], '=');
2149 struct in_addr aa;
2150 p++;
2151 if (inet_aton(p, &aa))
2152 defaultsourceip = strdup(p);
2153 else
2154 errprintf("Invalid source ip address '%s'\n", argv[argi]);
2155 }
2156
2157 /* Options for PING tests */
2158 else if (argnmatch(argv[argi], "--ping-tasks=")) {
2159 /* Note: must check for this before checking "--ping" option */
2160 char *p = strchr(argv[argi], '=');
2161 pingchildcount = atoi(p+1);
2162 }
2163 else if (argnmatch(argv[argi], "--ping")) {
2164 char *p = strchr(argv[argi], '=');
2165 if (p) {
2166 p++; pingcolumn = p;
2167 }
2168 else pingcolumn = "";
2169 }
2170 else if (strcmp(argv[argi], "--noping") == 0) {
2171 pingcolumn = NULL;
2172 }
2173 else if (strcmp(argv[argi], "--trace") == 0) {
2174 dotraceroute = 1;
2175 }
2176 else if (strcmp(argv[argi], "--notrace") == 0) {
2177 dotraceroute = 0;
2178 }
2179
2180 /* Options for HTTP tests */
2181 else if (argnmatch(argv[argi], "--content=")) {
2182 char *p = strchr(argv[argi], '=');
2183 contenttestname = strdup(p+1);
2184 }
2185 else if (strcmp(argv[argi], "--bb-proxy-syntax") == 0) {
2186 /* Obey the Big Brother format for http proxy listed as part of the URL */
2187 obeybbproxysyntax = 1;
2188 }
2189
2190 /* Options for SSL certificates */
2191 else if (argnmatch(argv[argi], "--ssl=")) {
2192 char *p = strchr(argv[argi], '=');
2193 ssltestname = strdup(p+1);
2194 }
2195 else if (strcmp(argv[argi], "--no-ssl") == 0) {
2196 ssltestname = NULL;
2197 }
2198 else if (argnmatch(argv[argi], "--sslwarn=")) {
2199 char *p = strchr(argv[argi], '=');
2200 p++; sslwarndays = atoi(p);
2201 }
2202 else if (argnmatch(argv[argi], "--sslalarm=")) {
2203 char *p = strchr(argv[argi], '=');
2204 p++; sslalarmdays = atoi(p);
2205 }
2206 else if (argnmatch(argv[argi], "--sslbits=")) {
2207 char *p = strchr(argv[argi], '=');
2208 p++; mincipherbits = atoi(p);
2209 }
2210 else if (argnmatch(argv[argi], "--validity=")) {
2211 char *p = strchr(argv[argi], '=');
2212 p++; validity = atoi(p);
2213 }
2214 else if (argnmatch(argv[argi], "--sslkeysize=")) {
2215 char *p = strchr(argv[argi], '=');
2216 p++; sslminkeysize = atoi(p);
2217 }
2218 else if (argnmatch(argv[argi], "--sni=")) {
2219 char *p = strchr(argv[argi], '=');
2220 p++; snienabled = ( (strcasecmp(p, "yes") == 0) || (strcasecmp(p, "on") == 0) || (strcasecmp(p, "enabled") == 0) || (strcasecmp(p, "true") == 0) || (strcasecmp(p, "1") == 0) );
2221 }
2222 else if (strcmp(argv[argi], "--no-cipherlist") == 0) {
2223 sslincludecipherlist = 0;
2224 }
2225 else if (strcmp(argv[argi], "--showallciphers") == 0) {
2226 sslshowallciphers = 1;
2227 }
2228
2229 /* Debugging options */
2230 else if (strcmp(argv[argi], "--debug") == 0) {
2231 debug = 1;
2232 }
2233 else if (argnmatch(argv[argi], "--dump")) {
2234 char *p = strchr(argv[argi], '=');
2235
2236 if (p) {
2237 if (strcmp(p, "=before") == 0) dumpdata = 1;
2238 else if (strcmp(p, "=after") == 0) dumpdata = 2;
2239 else dumpdata = 3;
2240 }
2241 else dumpdata = 2;
2242
2243 debug = 1;
2244 }
2245 else if (strcmp(argv[argi], "--no-update") == 0) {
2246 dontsendmessages = 1;
2247 }
2248 else if (strcmp(argv[argi], "--timing") == 0) {
2249 timing = 1;
2250 }
2251
2252 /* Informational options */
2253 else if (strcmp(argv[argi], "--services") == 0) {
2254 servicedumponly = 1;
2255 }
2256 else if (strcmp(argv[argi], "--version") == 0) {
2257 printf("xymonnet version %s\n", VERSION);
2258 if (ssl_library_version) printf("SSL library : %s\n", ssl_library_version);
2259 if (ldap_library_version) printf("LDAP library: %s\n", ldap_library_version);
2260 printf("\n");
2261 return 0;
2262 }
2263 else if ((strcmp(argv[argi], "--help") == 0) || (strcmp(argv[argi], "-?") == 0)) {
2264 printf("xymonnet version %s\n\n", VERSION);
2265 printf("Usage: %s [options] [host1 host2 host3 ...]\n", argv[0]);
2266 printf("General options:\n");
2267 printf(" --timeout=N : Timeout (in seconds) for service tests\n");
2268 printf(" --cmdtimeout=N : Timeout for external commands for testing NTP, RPC and traceroute\n");
2269 printf(" --concurrency=N : Number of tests run in parallel\n");
2270 printf(" --dns-timeout=N : DNS lookups timeout and fail after N seconds [30]\n");
2271 printf(" --dns=[only|ip|standard] : How IP's are decided\n");
2272 printf(" --no-ares : Use the system resolver library for hostname lookups\n");
2273 printf(" --dnslog=FILENAME : Log failed hostname lookups to file FILENAME\n");
2274 printf(" --report[=COLUMNNAME] : Send a status report about the running of xymonnet\n");
2275 printf(" --test-untagged : Include hosts without a NET: tag in the test\n");
2276 printf(" --frequenttestlimit=N : Seconds after detecting failures in which we poll frequently\n");
2277 printf(" --timelimit=N : Warns if the complete test run takes longer than N seconds [TASKSLEEP]\n");
2278 printf("\nOptions for simple TCP service tests:\n");
2279 printf(" --checkresponse : Check response from known services\n");
2280 printf(" --no-flags : Don't send extra xymonnet test flags\n");
2281 printf("\nOptions for PING (connectivity) tests:\n");
2282 printf(" --ping[=COLUMNNAME] : Enable ping checking, default columname is \"conn\"\n");
2283 printf(" --noping : Disable ping checking\n");
2284 printf(" --trace : Run traceroute on all hosts where ping fails\n");
2285 printf(" --notrace : Disable traceroute when ping fails (default)\n");
2286 printf(" --ping-tasks=N : Run N ping tasks in parallel (default N=1)\n");
2287 printf("\nOptions for HTTP/HTTPS (Web) tests:\n");
2288 printf(" --content=COLUMNNAME : Define default columnname for CONTENT checks (content)\n");
2289 printf("\nOptions for SSL certificate tests:\n");
2290 printf(" --ssl=COLUMNNAME : Define columnname for SSL certificate checks (sslcert)\n");
2291 printf(" --no-ssl : Disable SSL certificate check\n");
2292 printf(" --sslwarn=N : Go yellow if certificate expires in less than N days (default:30)\n");
2293 printf(" --sslalarm=N : Go red if certificate expires in less than N days (default:10)\n");
2294 printf(" --no-cipherlist : Do not display SSL cipher data in the SSL certificate check\n");
2295 printf(" --showallciphers : List all available ciphers supported by the local SSL library\n");
2296 printf("\nDebugging options:\n");
2297 printf(" --no-update : Send status messages to stdout instead of to Xymon\n");
2298 printf(" --timing : Trace the amount of time spent on each series of tests\n");
2299 printf(" --debug : Output debugging information\n");
2300 printf(" --dump[=before|=after|=all] : Dump internal memory structures before/after tests run\n");
2301 printf(" --maxdnsqueue=N : Only queue N DNS lookups at a time\n");
2302 printf("\nInformational options:\n");
2303 printf(" --services : Dump list of known services and exit\n");
2304 printf(" --version : Show program version and exit\n");
2305 printf(" --help : Show help text and exit\n");
2306
2307 return 0;
2308 }
2309 else if (strncmp(argv[argi], "-", 1) == 0) {
2310 errprintf("Unknown option %s - try --help\n", argv[argi]);
2311 }
2312 else {
2313 /* Must be a hostname */
2314 if (selectedcount == 0) selectedhosts = (char **) malloc(argc*sizeof(char *));
2315 selectedhosts[selectedcount++] = strdup(argv[argi]);
2316 }
2317 }
2318
2319 svctree = xtreeNew(strcasecmp);
2320 testhosttree = xtreeNew(strcasecmp);
2321 cookietree = xtreeNew(strcmp);
2322 init_timestamp();
2323 envcheck(reqenv);
2324 fqdn = get_fqdn();
2325
2326 /* Setup SEGV handler */
2327 setup_signalhandler(egocolumn ? egocolumn : "xymonnet");
2328
2329 if (xgetenv("XYMONNETWORK") && (strlen(xgetenv("XYMONNETWORK")) > 0))
2330 location = strdup(xgetenv("XYMONNETWORK"));
2331 else if (xgetenv("BBLOCATION") && (strlen(xgetenv("BBLOCATION")) > 0))
2332 location = strdup(xgetenv("BBLOCATION"));
2333
2334 if (pingcolumn && (strlen(pingcolumn) == 0)) pingcolumn = xgetenv("PINGCOLUMN");
2335 if (pingcolumn && xgetenv("IPTEST_2_CLEAR_ON_FAILED_CONN")) {
2336 failgoesclear = (strcmp(xgetenv("IPTEST_2_CLEAR_ON_FAILED_CONN"), "TRUE") == 0);
2337 }
2338 if (xgetenv("NETFAILTEXT")) failtext = strdup(xgetenv("NETFAILTEXT"));
2339
2340 if (debug) {
2341 int i;
2342 printf("Command: xymonnet");
2343 for (i=1; (i<argc); i++) printf(" '%s'", argv[i]);
2344 printf("\n");
2345 printf("Environment XYMONNETWORK='%s'\n", textornull(location));
2346 printf("Environment CONNTEST='%s'\n", textornull(xgetenv("CONNTEST")));
2347 printf("Environment IPTEST_2_CLEAR_ON_FAILED_CONN='%s'\n", textornull(xgetenv("IPTEST_2_CLEAR_ON_FAILED_CONN")));
2348 printf("\n");
2349 }
2350
2351 add_timestamp("xymonnet startup");
2352
2353 load_services();
2354 if (servicedumponly) {
2355 dump_tcp_services();
2356 return 0;
2357 }
2358
2359 dnstest = add_service("dns", getportnumber("domain"), 0, TOOL_DNS);
2360 add_service("ntp", getportnumber("ntp"), 0, TOOL_NTP);
2361 rpctest = add_service("rpc", getportnumber("sunrpc"), 0, TOOL_RPCINFO);
2362 httptest = add_service("http", getportnumber("http"), 0, TOOL_HTTP);
2363 ldaptest = add_service("ldapurl", getportnumber("ldap"), strlen("ldap"), TOOL_LDAP);
2364 if (pingcolumn) pingtest = add_service(pingcolumn, 0, 0, TOOL_FPING);
2365 add_timestamp("Service definitions loaded");
2366
2367 usebackfeedqueue = (sendmessage_init_local() > 0);
2368
2369 load_tests();
2370 add_timestamp(use_ares_lookup ? "Tests loaded" : "Tests loaded, hostname lookups done");
2371
2372 flush_dnsqueue();
2373 if (use_ares_lookup) add_timestamp("DNS lookups completed");
2374
2375 if (dumpdata & 1) { dump_hostlist(); dump_testitems(); }
2376
2377 /* Ping checks first */
2378 if (pingtest && pingtest->items) pingrunning = (start_ping_service(pingtest) == 0);
2379
2380 /* Load current status files */
2381 for (handle = xtreeFirst(svctree); handle != xtreeEnd(svctree); handle = xtreeNext(svctree, handle)) {
2382 s = (service_t *)xtreeData(svctree, handle);
2383 if (s != pingtest) load_test_status(s);
2384 }
2385
2386 /* First run the TCP/IP and HTTP tests */
2387 for (handle = xtreeFirst(svctree); handle != xtreeEnd(svctree); handle = xtreeNext(svctree, handle)) {
2388 s = (service_t *)xtreeData(svctree, handle);
2389 if ((s->items) && (s->toolid == TOOL_CONTEST)) {
2390 char tname[128];
2391
2392 for (t = s->items; (t); t = t->next) {
2393 if (!t->host->dnserror) {
2394 strncpy(tname, s->testname, sizeof(tname));
2395 if (s->namelen) tname[s->namelen] = '\0';
2396 t->privdata = (void *)add_tcp_test(ip_to_test(t->host), s->portnum, tname, NULL,
2397 t->srcip,
2398 NULL, t->silenttest, NULL,
2399 NULL, NULL, NULL);
2400 }
2401 }
2402 }
2403 }
2404 for (t = httptest->items; (t); t = t->next) add_http_test(t);
2405 add_timestamp("Test engine setup completed");
2406
2407 do_tcp_tests(timeout, concurrency);
2408 add_timestamp("TCP tests completed");
2409
2410 if (pingrunning) {
2411 char msg[512];
2412
2413 finish_ping_service(pingtest);
2414 snprintf(msg, sizeof(msg), "PING test completed (%d hosts)", pingcount);
2415 add_timestamp(msg);
2416
2417 if (usebackfeedqueue)
2418 combo_start_local();
2419 else
2420 combo_start();
2421
2422 send_results(pingtest, failgoesclear);
2423 if (selectedhosts == 0) save_ping_status();
2424 combo_end();
2425 add_timestamp("PING test results sent");
2426 }
2427
2428 if (debug) {
2429 show_tcp_test_results();
2430 show_http_test_results(httptest);
2431 }
2432
2433 for (handle = xtreeFirst(svctree); handle != xtreeEnd(svctree); handle = xtreeNext(svctree, handle)) {
2434 s = (service_t *)xtreeData(svctree, handle);
2435 if ((s->items) && (s->toolid == TOOL_CONTEST)) {
2436 for (t = s->items; (t); t = t->next) {
2437 /*
2438 * If the test fails due to DNS error, t->privdata is NULL
2439 */
2440 if (t->privdata) {
2441 char *p;
2442 int i;
2443 tcptest_t *testresult = (tcptest_t *)t->privdata;
2444
2445 t->open = testresult->open;
2446 t->banner = dupstrbuffer(testresult->banner);
2447 t->certinfo = testresult->certinfo;
2448 t->certissuer = testresult->certissuer;
2449 t->certexpires = testresult->certexpires;
2450 t->certkeysz = testresult->certkeysz;
2451 t->mincipherbits = testresult->mincipherbits;
2452 t->duration.tv_sec = testresult->duration.tv_sec;
2453 t->duration.tv_nsec = testresult->duration.tv_nsec;
2454
2455 /* Binary data in banner ... */
2456 for (i=0, p=STRBUF(t->banner); (i < STRBUFLEN(t->banner)); i++, p++) {
2457 if (!isprint((int)*p) && !isspace((int)*p)) *p = '.';
2458 }
2459 }
2460 }
2461 }
2462 }
2463 for (t = httptest->items; (t); t = t->next) {
2464 if (t->privdata) {
2465 http_data_t *testresult = (http_data_t *)t->privdata;
2466
2467 t->certinfo = testresult->tcptest->certinfo;
2468 t->certissuer = testresult->tcptest->certissuer;
2469 t->certexpires = testresult->tcptest->certexpires;
2470 t->certkeysz = testresult->tcptest->certkeysz;
2471 t->mincipherbits = testresult->tcptest->mincipherbits;
2472 }
2473 }
2474
2475 add_timestamp("Test result collection completed");
2476
2477
2478 /* Run the ldap tests */
2479 for (t = ldaptest->items; (t); t = t->next) add_ldap_test(t);
2480 add_timestamp("LDAP test engine setup completed");
2481
2482 run_ldap_tests(ldaptest, (ssltestname != NULL), timeout);
2483 add_timestamp("LDAP tests executed");
2484
2485 if (debug) show_ldap_test_results(ldaptest);
2486 for (t = ldaptest->items; (t); t = t->next) {
2487 if (t->privdata) {
2488 ldap_data_t *testresult = (ldap_data_t *)t->privdata;
2489
2490 t->certinfo = testresult->certinfo;
2491 t->certissuer = testresult->certissuer;
2492 t->mincipherbits = testresult->mincipherbits;
2493 t->certexpires = testresult->certexpires;
2494 t->certkeysz = testresult->certkeysz;
2495 }
2496 }
2497 add_timestamp("LDAP tests result collection completed");
2498
2499
2500 /* dns, ntp tests */
2501 for (handle = xtreeFirst(svctree); handle != xtreeEnd(svctree); handle = xtreeNext(svctree, handle)) {
2502 s = (service_t *)xtreeData(svctree, handle);
2503 if (s->items) {
2504 switch(s->toolid) {
2505 case TOOL_DNS:
2506 run_nslookup_service(s);
2507 add_timestamp("DNS tests executed");
2508 break;
2509 case TOOL_NTP:
2510 run_ntp_service(s);
2511 add_timestamp("NTP tests executed");
2512 break;
2513 case TOOL_RPCINFO:
2514 run_rpcinfo_service(s);
2515 add_timestamp("RPC tests executed");
2516 break;
2517 default:
2518 break;
2519 }
2520 }
2521 }
2522
2523 if (usebackfeedqueue)
2524 combo_start_local();
2525 else
2526 combo_start();
2527
2528 for (handle = xtreeFirst(svctree); handle != xtreeEnd(svctree); handle = xtreeNext(svctree, handle)) {
2529 s = (service_t *)xtreeData(svctree, handle);
2530 switch (s->toolid) {
2531 case TOOL_CONTEST:
2532 case TOOL_DNS:
2533 case TOOL_NTP:
2534 send_results(s, failgoesclear);
2535 break;
2536
2537 case TOOL_FPING:
2538 case TOOL_HTTP:
2539 case TOOL_LDAP:
2540 /* These handle result-transmission internally */
2541 break;
2542
2543 case TOOL_RPCINFO:
2544 send_rpcinfo_results(s, failgoesclear);
2545 break;
2546 }
2547 }
2548 for (handle = xtreeFirst(testhosttree); (handle != xtreeEnd(testhosttree)); handle = xtreeNext(testhosttree, handle)) {
2549 h = (testedhost_t *)xtreeData(testhosttree, handle);
2550 send_http_results(httptest, h, h->firsthttp, nonetpage, failgoesclear, usebackfeedqueue);
2551 send_content_results(httptest, h, nonetpage, contenttestname, failgoesclear);
2552 send_ldap_results(ldaptest, h, nonetpage, failgoesclear);
2553 if (ssltestname && !h->nosslcert) send_sslcert_status(h);
2554 }
2555
2556 combo_end();
2557
2558 add_timestamp("Test results transmitted");
2559
2560 /*
2561 * The list of hosts to test frequently because of a failure must
2562 * be saved - it is then picked up by the frequent-test ext script
2563 * that runs xymonnet again with the frequent-test hosts as
2564 * parameter.
2565 *
2566 * Should the retest itself update the frequent-test file ? It
2567 * would allow us to kick hosts from the frequent-test file sooner.
2568 * However, it is simpler (no races) if we just let the normal
2569 * test-engine be alone in updating the file.
2570 * At the worst, we'll re-test a host going up a couple of times
2571 * too much.
2572 *
2573 * So for now update the list only if we ran with no host-parameters.
2574 */
2575 if (selectedcount == 0) {
2576 /* Save current status files */
2577 for (handle = xtreeFirst(svctree); handle != xtreeEnd(svctree); handle = xtreeNext(svctree, handle)) {
2578 s = (service_t *)xtreeData(svctree, handle);
2579 if (s != pingtest) save_test_status(s);
2580 }
2581 /* Save frequent-test list */
2582 save_frequenttestlist(argc, argv);
2583 }
2584
2585 /* Save session cookies - every time */
2586 save_session_cookies();
2587
2588 shutdown_ldap_library();
2589 add_timestamp("xymonnet completed");
2590
2591 if (dumpdata & 2) { dump_hostlist(); dump_testitems(); }
2592
2593 /* Tell about us */
2594 if (egocolumn) {
2595 char msgline[4096];
2596 char *timestamps;
2597 int color;
2598
2599 /* Go yellow if it runs for too long */
2600 if ((runtimewarn > 0) && (total_runtime() > runtimewarn)) {
2601 errprintf("WARNING: Runtime %ld longer than time limit (%ld)\n", total_runtime(), runtimewarn);
2602 }
2603 color = (errbuf ? COL_YELLOW : COL_GREEN);
2604 if (bigfailure) color = COL_RED;
2605
2606 if (usebackfeedqueue) combo_start_local(); else combo_start();
2607 init_status(color);
2608 snprintf(msgline, sizeof(msgline), "status+%d %s.%s %s %s\n\n", validity, xgetenv("MACHINE"), egocolumn, colorname(color), timestamp);
2609 addtostatus(msgline);
2610
2611 snprintf(msgline, sizeof(msgline), "xymonnet version %s\n", VERSION);
2612 addtostatus(msgline);
2613 if (ssl_library_version) {
2614 snprintf(msgline, sizeof(msgline), "SSL library : %s\n", ssl_library_version);
2615 addtostatus(msgline);
2616 }
2617 if (ldap_library_version) {
2618 snprintf(msgline, sizeof(msgline), "LDAP library: %s\n", ldap_library_version);
2619 addtostatus(msgline);
2620 }
2621
2622 snprintf(msgline, sizeof(msgline), "\nStatistics:\n Hosts total : %8d\n Hosts with no tests : %8d\n Total test count : %8d\n Status messages : %8d\n Alert status msgs : %8d\n Transmissions : %8d\n",
2623 hostcount, notesthostcount, testcount, xymonstatuscount, xymonnocombocount, xymonmsgcount);
2624 addtostatus(msgline);
2625 snprintf(msgline, sizeof(msgline), "\nDNS statistics:\n # hostnames resolved : %8d\n # successful : %8d\n # failed : %8d\n # calls to dnsresolve : %8d\n",
2626 dns_stats_total, dns_stats_success, dns_stats_failed, dns_stats_lookups);
2627 addtostatus(msgline);
2628 snprintf(msgline, sizeof(msgline), "\nTCP test statistics:\n # TCP tests total : %8d\n # HTTP tests : %8d\n # Simple TCP tests : %8d\n # Connection attempts : %8d\n # bytes written : %8ld\n # bytes read : %8ld\n",
2629 tcp_stats_total, tcp_stats_http, tcp_stats_plain, tcp_stats_connects,
2630 tcp_stats_written, tcp_stats_read);
2631 addtostatus(msgline);
2632
2633 if (errbuf) {
2634 addtostatus("\n\nError output:\n");
2635 addtostatus(prehtmlquoted(errbuf));
2636 }
2637
2638 if (warnbuf) {
2639 addtostatus("\n\nWarning output:\n");
2640 addtostatus(prehtmlquoted(warnbuf));
2641 }
2642
2643 show_timestamps(×tamps);
2644 addtostatus(timestamps);
2645
2646 finish_status();
2647 combo_end();
2648 }
2649 else show_timestamps(NULL);
2650
2651 if (dnsfaillog) fclose(dnsfaillog);
2652
2653 if (usebackfeedqueue) sendmessage_finish_local();
2654
2655 return 0;
2656 }
2657
2658