1 /*
2  *  Alarm Pinger (c) 2002 Jacek Konieczny <jajcus@pld.org.pl>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License version 2 as published
6  *  by the Free Software Foundation.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
16  *  USA
17  *
18  *  $Id: apinger.c,v 1.40 2003/03/26 11:24:59 cvs-jajcus Exp $
19  */
20 
21 #include "config.h"
22 #include "apinger.h"
23 
24 #include <stdio.h>
25 #ifdef HAVE_STDLIB_H
26 # include <stdlib.h>
27 #endif
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31 #ifdef HAVE_STRING_H
32 # include <string.h>
33 #endif
34 #ifdef HAVE_SYS_WAIT_H
35 # include <sys/wait.h>
36 #endif
37 #ifdef HAVE_SYS_POLL_H
38 # include <sys/poll.h>
39 #endif
40 #ifdef HAVE_ARPA_INET_H
41 # include <arpa/inet.h>
42 #endif
43 
44 #include "debug.h"
45 #include "tv_macros.h"
46 #include "rrd.h"
47 
48 #ifdef HAVE_ASSERT_H
49 # include <assert.h>
50 #else
51 # define assert(cond)
52 #endif
53 
54 #define MIN(a,b) (((a)<(b))?(a):(b))
55 
56 struct delayed_report {
57 	int on;
58 	char *msgid;
59 	char *lastmsgid;
60 	struct alarm_cfg *a;
61 	struct target t;
62 	struct timeval timestamp;
63 	struct delayed_report *next;
64 };
65 
66 struct delayed_report *delayed_reports=NULL;
67 
68 struct timeval operation_started;
69 
70 
is_alarm_on(struct target * t,struct alarm_cfg * a)71 int is_alarm_on(struct target *t,struct alarm_cfg *a){
72 struct active_alarm_list *al;
73 
74 	for(al=t->active_alarms;al;al=al->next)
75 		if (al->alarm==a)
76 			return 1;
77 	return 0;
78 }
79 
80 static char msgid_buf[1024];
81 static char hostnamebuf[256]="-";
82 
gen_msgid(struct target * t,char * suff)83 char *gen_msgid(struct target *t,char *suff){
84 struct timeval cur_time;
85 
86 	gettimeofday(&cur_time,NULL);
87 
88 	gethostname(hostnamebuf,sizeof(hostnamebuf));
89 	sprintf(msgid_buf,"<%p.%li.%s@%s>",
90 				t,(long int)(cur_time.tv_usec/1000+cur_time.tv_sec*1000),
91 				suff,hostnamebuf);
92 	return strdup(msgid_buf);
93 }
94 
alarm_on(struct target * t,struct alarm_cfg * a)95 char *alarm_on(struct target *t,struct alarm_cfg *a){
96 struct active_alarm_list *al;
97 struct timeval cur_time,tv;
98 
99 	gettimeofday(&cur_time,NULL);
100 	al=NEW(struct active_alarm_list,1);
101 	al->next=t->active_alarms;
102 	al->alarm=a;
103 	al->msgid=gen_msgid(t,"on");
104 	al->num_repeats=0;
105 	if (a->repeat_interval){
106 		tv.tv_sec=a->repeat_interval/1000;
107 		tv.tv_usec=(a->repeat_interval%1000)*1000;
108 		timeradd(&cur_time,&tv,&al->next_repeat);
109 	}
110 	t->active_alarms=al;
111 	return strdup(al->msgid);
112 }
113 
alarm_off(struct target * t,struct alarm_cfg * a)114 char *alarm_off(struct target *t,struct alarm_cfg *a){
115 struct active_alarm_list *al,*pa,*na;
116 char *msgid;
117 
118 	pa=NULL;
119 	for(al=t->active_alarms;al;al=na){
120 		na=al->next;
121 		if (al->alarm==a){
122 			if (pa!=NULL)
123 				pa->next=na;
124 			else
125 				t->active_alarms=na;
126 			msgid=al->msgid;
127 			free(al);
128 			return msgid;
129 		}
130 		else pa=al;
131 	}
132 	logit("Alarm '%s' not found in '%s'",a->name,t->name);
133 	return NULL;
134 }
135 
136 static char *macros_buf=NULL;
137 static int macros_buf_l=0;
subst_macros(const char * string,struct target * t,struct alarm_cfg * a,int on)138 const char * subst_macros(const char *string,struct target *t,struct alarm_cfg *a,int on){
139 char *p;
140 int nmacros=0;
141 int i,sl,l,n;
142 char **values;
143 char ps[16],pr[16],al[16],ad[16],ts[100];
144 time_t tim;
145 
146 	if (string==NULL || string[0]=='\000') return "";
147 	for(i=0;string[i]!='\000';i++){
148 		if (string[i]!='%') continue;
149 		nmacros++;
150 		i++;
151 		if (string[i]=='\000') break;
152 	}
153 	if (nmacros==0) return string;
154 	values=NEW(char *,(nmacros+1));
155 	assert(values!=NULL);
156 	l=sl=strlen(string);
157 	n=0;
158 	for(i=0;i<sl;i++){
159 		if (string[i]!='%') continue;
160 		i++;
161 		switch(string[i]){
162 		case 't':
163 			values[n]=t->name;
164 			break;
165 		case 'T':
166 			values[n]=t->description;
167 			break;
168 		case 'a':
169 			if (a)
170 				values[n]=a->name;
171 			else
172 				values[n]="?";
173 			break;
174 		case 'A':
175 			if (a)
176 				switch(a->type){
177 				case AL_DOWN:
178 					values[n]="down";
179 					break;
180 				case AL_LOSS:
181 					values[n]="loss";
182 					break;
183 				case AL_DELAY:
184 					values[n]="delay";
185 					break;
186 				default:
187 					values[n]="unknown";
188 					break;
189 				}
190 			else
191 				values[n]="?";
192 			break;
193 		case 'r':
194 			switch(on){
195 			case -1:
196 				values[n]="alarm canceled (config reload)";
197 				break;
198 			case 0:
199 				values[n]="alarm canceled";
200 				break;
201 			default:
202 				values[n]="ALARM";
203 				break;
204 			}
205 			break;
206 		case 'p':
207 			sprintf(ps,"%i",t->last_sent);
208 			values[n]=ps;
209 			break;
210 		case 'P':
211 			sprintf(pr,"%i",t->received);
212 			values[n]=pr;
213 			break;
214 		case 'l':
215 			if (AVG_LOSS_KNOWN(t)){
216 				sprintf(al,"%0.1f%%",AVG_LOSS(t));
217 				values[n]=al;
218 			}
219 			else values[n]="n/a";
220 			break;
221 		case 'd':
222 			if (AVG_DELAY_KNOWN(t)){
223 				sprintf(ad,"%0.3fms",AVG_DELAY(t));
224 				values[n]=ad;
225 			}
226 			else values[n]="n/a";
227 			break;
228 		case 's':
229 			tim=time(NULL);
230 			strftime(ts,100,config->timestamp_format,localtime(&tim));
231 			values[n]=ts;
232 			break;
233 		case '%':
234 			values[n]="%";
235 			break;
236 		default:
237 			values[n]="";
238 			break;
239 		}
240 		l+=strlen(values[n])-1;
241 		n++;
242 	}
243 	values[n]=NULL;
244 	l+=2;
245 	if (macros_buf == NULL){
246 		macros_buf=NEW(char,l);
247 		macros_buf_l=l;
248 	}else if (macros_buf_l < l){
249 		macros_buf=(char *)realloc(macros_buf,l);
250 		macros_buf_l=l;
251 	}
252 	assert(macros_buf!=NULL);
253 	p=macros_buf;
254 	n=0;
255 	for(i=0;i<sl;i++){
256 		if (string[i]!='%'){
257 			*p++=string[i];
258 			continue;
259 		}
260 		strcpy(p,values[n]);
261 		p+=strlen(values[n]);
262 		n++;
263 		i++;
264 	}
265 	free(values);
266 	*p='\000';
267 	return macros_buf;
268 }
269 
write_report(FILE * f,struct target * t,struct alarm_cfg * a,int on)270 void write_report(FILE *f,struct target *t,struct alarm_cfg *a,int on){
271 time_t tm;
272 
273 	tm=time(NULL);
274 	fprintf(f,"%s",ctime(&tm));
275 	if (on)
276 		fprintf(f,"ALARM went off: %s\n",a->name);
277 	else
278 		fprintf(f,"alarm canceled: %s\n",a->name);
279 	fprintf(f,"Target: %s\n",t->name);
280 	fprintf(f,"Description: %s\n",t->description);
281 	fprintf(f,"Probes sent: %i\n",t->last_sent+1);
282 	fprintf(f,"Replies received: %i\n",t->received);
283 	fprintf(f,"Last reply received: #%i %s",t->last_received,
284 			ctime(&t->last_received_tv.tv_sec));
285 	if (AVG_DELAY_KNOWN(t)){
286 		fprintf(f,"Recent avg. delay: %4.3fms\n",AVG_DELAY(t));
287 	}
288 	if (AVG_LOSS_KNOWN(t)){
289 		fprintf(f,"Recent avg. packet loss: %5.1f%%\n",AVG_LOSS(t));
290 	}
291 }
292 
make_reports(struct target * t,struct alarm_cfg * a,int on,char * thisid,char * lastid)293 void make_reports(struct target *t,struct alarm_cfg *a,int on,char* thisid,char* lastid){
294 FILE *p;
295 char buf[1024];
296 char *mailto,*mailfrom,*mailenvfrom;
297 int ret;
298 const char *command;
299 
300 	mailto=a->mailto;
301 	mailenvfrom=a->mailenvfrom;
302 	if (mailenvfrom!=NULL && strpbrk(mailenvfrom,"\\'")!=0)
303 		mailenvfrom=NULL;
304 	mailfrom=a->mailfrom;
305 	if (mailto){
306 		if (mailenvfrom){
307 			snprintf(buf,1024,"%s -f'%s'",config->mailer,mailenvfrom);
308 		}
309 		else{
310 			snprintf(buf,1024,"%s",config->mailer);
311 		}
312 		debug("Popening: %s",buf);
313 		p=popen(buf,"w");
314 		if (!p){
315 			myperror("Couldn't send mail, popen:");
316 			return;
317 		}
318 		fprintf(p,"Subject: %s\n",subst_macros(a->mailsubject,t,a,on));
319 		fprintf(p,"To: %s\n",subst_macros(mailto,t,a,on));
320 		if (mailfrom) {
321 			fprintf(p,"From: %s\n",subst_macros(mailfrom,t,a,on));
322 		}
323 		if (thisid!=NULL)
324 			fprintf(p,"Message-Id: %s\n",thisid);
325 		if (lastid!=NULL && lastid[0]!='\000')
326 			fprintf(p,"References: %s\n",lastid);
327 
328 		fprintf(p,"\n");
329 		write_report(p,t,a,on);
330 		ret=pclose(p);
331 		if (!WIFEXITED(ret)){
332 			logit("Error while sending mail.\n");
333 			logit("sendmail terminated abnormally.\n");
334 		}
335 		else if (WEXITSTATUS(ret)!=0){
336 			logit("Error while sending mail.\n");
337 			logit("sendmail exited with status: %i\n",WEXITSTATUS(ret));
338 		}
339 	}
340 	if (on>0) command=a->pipe_on;
341 	else command=a->pipe_off;
342 	if (command){
343 		command=subst_macros(command,t,a,on);
344 		debug("Popening: %s",command);
345 		p=popen(command,"w");
346 		if (!p){
347 			logit("Couldn't pipe report through %s",command);
348 			myperror("popen");
349 		}
350 		else {
351 			write_report(p,t,a,on);
352 			ret=pclose(p);
353 			if (!WIFEXITED(ret)){
354 				logit("Error while piping report.");
355 				logit("command (%s) terminated abnormally.",command);
356 			}
357 			else if (WEXITSTATUS(ret)!=0){
358 				logit("Error while piping report.");
359 				logit("command (%s) exited with status: %i",command,WEXITSTATUS(ret));
360 			}
361 		}
362 	}
363 	if (on>0) command=a->command_on;
364 	else command=a->command_off;
365 	if (command){
366 		command=subst_macros(command,t,a,on);
367 		debug("Starting: %s",command);
368 		ret=system(command);
369 		if (!WIFEXITED(ret)){
370 			logit("Error while starting command.");
371 			logit("command (%s) terminated abnormally.",command);
372 		}
373 		else if (WEXITSTATUS(ret)!=0){
374 			logit("Error while starting command.");
375 			logit("command (%s) exited with status: %i",command,WEXITSTATUS(ret));
376 		}
377 	}
378 }
379 
make_delayed_reports(void)380 void make_delayed_reports(void){
381 struct alarm_cfg *alarm;
382 struct target target;
383 int on;
384 char *msgid,*references;
385 struct delayed_report *dr,*pdr,*ndr;
386 int names_len,descriptions_len,references_len;
387 char *names,*descriptions;
388 
389 
390 	if (delayed_reports==NULL) return;
391 	on=delayed_reports->on;
392 	msgid=strdup(delayed_reports->msgid);
393 	alarm=delayed_reports->a;
394 	target=delayed_reports->t;
395 	names_len=descriptions_len=references_len=0;
396 	for(dr=delayed_reports;dr;dr=dr->next){
397 		if (dr->a==alarm && dr->on==on){
398 			names_len+=strlen(dr->t.name)+1;
399 			descriptions_len+=strlen(dr->t.description)+1;
400 			if (dr->lastmsgid){
401 				references_len+=strlen(dr->lastmsgid)+1;
402 			}
403 		}
404 	}
405 
406 	names=NEW(char,names_len+1);
407 	names[0]='\000';
408 	descriptions=NEW(char,descriptions_len+1);
409 	descriptions[0]='\000';
410 	references=NEW(char,references_len+1);
411 	references[0]='\000';
412 
413 	pdr=NULL;
414 	for(dr=delayed_reports;dr;dr=ndr){
415 		ndr=dr->next;
416 		if (dr->a==alarm && dr->on==on){
417 			if (on){
418 				struct active_alarm_list *al;
419 				struct target *t;
420 				for(t=targets;t;t=t->next){
421 					if (strcmp(dr->t.name,t->name)) continue;
422 					for(al=t->active_alarms;al;al=al->next){
423 						if (al->alarm==alarm){
424 							if (al->msgid!=NULL) free(al->msgid);
425 							al->msgid=strdup(msgid);
426 						}
427 					}
428 					break;
429 				}
430 			}
431 			if (names[0]!='\000') strcat(names,",");
432 			strcat(names,dr->t.name);
433 			if (descriptions[0]!='\000') strcat(descriptions,",");
434 			strcat(descriptions,dr->t.description);
435 			if (dr->lastmsgid){
436 				if (references[0]!='\000') strcat(references," ");
437 				strcat(references,dr->lastmsgid);
438 			}
439 			if (pdr!=NULL)
440 				pdr->next=ndr;
441 			else
442 				delayed_reports=ndr;
443 			free(dr->msgid);
444 			free(dr->lastmsgid);
445 			free(dr);
446 		}
447 		else pdr=dr;
448 	}
449 
450 	target.name=names;
451 	target.description=descriptions;
452 
453 	make_reports(&target,alarm,on,msgid,references);
454 
455 	free(msgid);
456 	free(names);
457 	free(descriptions);
458 	free(references);
459 }
460 
toggle_alarm(struct target * t,struct alarm_cfg * a,int on)461 void toggle_alarm(struct target *t,struct alarm_cfg *a,int on){
462 char *thisid=NULL,*lastid=NULL;
463 struct delayed_report *dr,*tdr;
464 
465 	if (on>0){
466 		logit("ALARM: %s(%s)  *** %s ***",t->description,t->name,a->name);
467 		thisid=alarm_on(t,a);
468 	}
469 	else{
470 		lastid=alarm_off(t,a);
471 		thisid=gen_msgid(t,"off");
472 		if (on==0)
473 			logit("alarm canceled: %s(%s)  *** %s ***",t->description,t->name,a->name);
474 		else
475 			logit("alarm canceled (config reload): %s(%s)  *** %s ***",t->description,t->name,a->name);
476 	}
477 
478 	if (a->combine_interval>0){
479 		for(tdr=delayed_reports;tdr!=NULL && tdr->next!=NULL;tdr=tdr->next){
480 			if (strcmp(tdr->t.name,t->name)==0 && tdr->a==a && tdr->on==on) return;
481 		}
482 		if (tdr!=NULL && strcmp(tdr->t.name,t->name)==0 && tdr->a==a && tdr->on==on) return;
483 		dr=NEW(struct delayed_report,1);
484 		assert(dr!=NULL);
485 		dr->t=*t;
486 		dr->a=a;
487 		dr->msgid=strdup(thisid);
488 		if (lastid) dr->lastmsgid=strdup(lastid);
489 		else dr->lastmsgid=NULL;
490 		dr->on=on;
491 		gettimeofday(&dr->timestamp,NULL);
492 		dr->next=NULL;
493 		if (tdr==NULL)
494 			delayed_reports=dr;
495 		else
496 			tdr->next=dr;
497 	}
498 	else make_reports(t,a,on,thisid,lastid);
499 	free(thisid);
500 	free(lastid);
501 }
502 
503 /* if a time came for the next event schedule next one in given interval and return 1 */
scheduled_event(struct timeval * next_event,struct timeval * cur_time,int interval)504 int scheduled_event(struct timeval *next_event,struct timeval *cur_time,int interval){
505 struct timeval ct,tv;
506 int ret;
507 
508 	if (cur_time==NULL){
509 		gettimeofday(&ct,NULL);
510 		cur_time=&ct;
511 	}
512 	if (!timerisset(next_event) || timercmp(next_event,cur_time,<)){
513 		if (!timerisset(next_event)){
514 			*next_event=*cur_time;
515 		}
516 		tv.tv_sec=interval/1000;
517 		tv.tv_usec=(interval%1000)*1000;
518 		timeradd(cur_time,&tv,next_event);
519 		ret=1;
520 	}
521 	else {
522 		ret=0;
523 	}
524 	if (!timerisset(&next_probe) || timercmp(next_event,&next_probe,<))
525 		next_probe=*next_event;
526 	return ret;
527 }
528 
send_probe(struct target * t)529 void send_probe(struct target *t){
530 int i,i1;
531 char buf[100];
532 int seq;
533 
534 	seq=++t->last_sent;
535 	debug("Sending ping #%i to %s (%s)",seq,t->description,t->name);
536 	strftime(buf,100,"%b %d %H:%M:%S",localtime(&t->next_probe.tv_sec));
537 	debug("Next one scheduled for %s",buf);
538 	if (t->addr.addr.sa_family==AF_INET) send_icmp_probe(t,seq);
539 #ifdef HAVE_IPV6
540 	else if (t->addr.addr.sa_family==AF_INET6) send_icmp6_probe(t,seq);
541 #endif
542 
543 	i=t->last_sent%(t->config->avg_loss_delay_samples+t->config->avg_loss_samples);
544 	if (t->last_sent>t->config->avg_loss_delay_samples+t->config->avg_loss_samples){
545 		if (!t->queue[i]) t->recently_lost--;
546 	}
547 	t->queue[i]=0;
548 
549 	if (t->last_sent>t->config->avg_loss_delay_samples){
550 		i1=(t->last_sent-t->config->avg_loss_delay_samples)
551 			%(t->config->avg_loss_delay_samples+t->config->avg_loss_samples);
552 		if (!t->queue[i1]) t->recently_lost++;
553 			debug("Recently lost packets: %i",t->recently_lost);
554 	}
555 
556 	t->upsent++;
557 }
558 
559 
analyze_reply(struct timeval time_recv,int icmp_seq,struct trace_info * ti)560 void analyze_reply(struct timeval time_recv,int icmp_seq,struct trace_info *ti){
561 struct target *t;
562 struct timeval tv;
563 double delay,avg_delay,avg_loss;
564 double tmp;
565 int i;
566 int previous_received;
567 struct alarm_list *al;
568 struct active_alarm_list *aal,*paa,*naa;
569 struct alarm_cfg *a;
570 
571 	if (icmp_seq!=(ti->seq%65536)){
572 		debug("Sequence number mismatch.");
573 		return;
574 	}
575 
576 	for(t=targets;t!=NULL;t=t->next){
577 		if (t==ti->target_id) break;
578 	}
579 	if (t==NULL){
580 		logit("Couldn't match any target to the echo reply.\n");
581 		return;
582 	}
583 	previous_received=t->last_received;
584 	if (ti->seq>t->last_received) t->last_received=ti->seq;
585 	t->last_received_tv=time_recv;
586 	timersub(&time_recv,&ti->timestamp,&tv);
587 	delay=tv.tv_sec*1000.0+((double)tv.tv_usec)/1000.0;
588 	debug("#%i from %s(%s) delay: %4.3fms",ti->seq,t->description,t->name,delay);
589 	if (t->received>t->config->avg_delay_samples)
590 		tmp=t->rbuf[t->received%t->config->avg_delay_samples];
591 	else
592 		tmp=0;
593 	t->rbuf[t->received%t->config->avg_delay_samples]=delay;
594 	t->delay_sum+=delay-tmp;
595 	t->received++;
596 
597 	avg_delay=AVG_DELAY(t);
598 	debug("(avg: %4.3fms)",avg_delay);
599 
600 	i=ti->seq%(t->config->avg_loss_delay_samples+t->config->avg_loss_samples);
601 	if (!t->queue[i] && ti->seq<=t->last_sent-t->config->avg_loss_delay_samples)
602 		t->recently_lost--;
603 	t->queue[i]=1;
604 
605 	if (AVG_LOSS_KNOWN(t)){
606 		avg_loss=AVG_LOSS(t);
607 	}else
608 		avg_loss=0;
609 
610 	debug("(avg. loss: %5.1f%%)",avg_loss);
611 
612 	paa=NULL;
613 	for(aal=t->active_alarms;aal;aal=naa){
614 		naa=aal->next;
615 		a=aal->alarm;
616 		if (a->type==AL_DOWN){
617 			t->upsent=0;
618 			avg_loss=0;
619 		}
620 		if ((a->type==AL_DOWN)
621 		   || (a->type==AL_DELAY && avg_delay<a->p.lh.low)
622 		   || (a->type==AL_LOSS && avg_loss<a->p.lh.low) ){
623 			toggle_alarm(t,a,0);
624 		}
625 	}
626 
627 	for(al=t->config->alarms;al;al=al->next){
628 		a=al->alarm;
629 		if (is_alarm_on(t,a)) continue;
630 		switch(a->type){
631 		case AL_DELAY:
632 			if (AVG_DELAY_KNOWN(t) && avg_delay>a->p.lh.high )
633 				toggle_alarm(t,a,1);
634 			break;
635 		case AL_LOSS:
636 			if ( avg_loss > a->p.lh.high )
637 				toggle_alarm(t,a,1);
638 			break;
639 		default:
640 			break;
641 		}
642 	}
643 }
644 
configure_targets(void)645 void configure_targets(void){
646 struct target *t,*pt,*nt;
647 struct target_cfg *tc;
648 struct active_alarm_list *al,*nal;
649 union addr addr;
650 int r;
651 int l;
652 
653 	/* delete all not configured targets */
654 	pt=NULL;
655 	for(t=targets;t;t=nt){
656 		for(tc=config->targets;tc;tc=tc->next)
657 			if (strcmp(tc->name,t->name)==0)
658 				break;
659 		nt=t->next;
660 		if (tc==NULL){
661 			if (pt==NULL)
662 				targets=t;
663 			else
664 				pt->next=nt;
665 			for(al=t->active_alarms;al;al=nal){
666 				nal=al->next;
667 				free(al);
668 			}
669 			free(t->queue);
670 			free(t->rbuf);
671 			free(t->name);
672 			free(t->description);
673 			free(t);
674 		}
675 		else pt=t;
676 	}
677 
678 	/* Update target configuration */
679 	for(tc=config->targets;tc;tc=tc->next){
680 		for(t=targets;t;t=t->next)
681 			if (!strcmp(t->name,tc->name))
682 				break;
683 		if (t==NULL) { /* new target */
684 			memset(&addr,0,sizeof(addr));
685 			r=inet_pton(AF_INET,tc->name,&addr.addr4.sin_addr);
686 			if (r){
687 				if (icmp_sock<0){
688 					logit("Sorry, IPv4 is not available\n");
689 					logit("Ignoring target %s\n",tc->name);
690 					continue;
691 				}
692 				addr.addr.sa_family=AF_INET;
693 			}else{
694 #ifdef HAVE_IPV6
695 				r=inet_pton(AF_INET6,tc->name,&addr.addr6.sin6_addr);
696 				if (r==0){
697 #endif
698 					logit("Bad host address: %s\n",tc->name);
699 					logit("Ignoring target %s\n",tc->name);
700 					continue;
701 #ifdef HAVE_IPV6
702 				}
703 				if (icmp6_sock<0){
704 					logit("Sorry, IPv6 is not available\n");
705 					logit("Ignoring target %s\n",tc->name);
706 					continue;
707 				}
708 				addr.addr.sa_family=AF_INET6;
709 #endif
710 			}
711 			t=NEW(struct target,1);
712 			memset(t,0,sizeof(struct target));
713 			t->name=strdup(tc->name);
714 			t->description=strdup(tc->description);
715 			t->addr=addr;
716 			t->next=targets;
717 			targets=t;
718 		}
719 		t->config=tc;
720 		l=tc->avg_loss_delay_samples+tc->avg_loss_samples;
721 		if (t->queue)
722 			t->queue=(char *)realloc(t->queue,l);
723 		else
724 			t->queue=NEW(char,l);
725 		assert(t->queue!=NULL);
726 		memset(t->queue,0,l);
727 		/* t->recently_lost=tc->avg_loss_samples; */
728 		l=tc->avg_delay_samples;
729 		if (t->rbuf)
730 			t->rbuf=(double *)realloc(t->rbuf,l);
731 		else
732 			t->rbuf=NEW(double,l);
733 		assert(t->rbuf!=NULL);
734 		memset(t->rbuf,0,l);
735 	}
736 	if (targets==NULL){
737 		logit("No usable targets found, exiting");
738 		exit(1);
739 	}
740 	gettimeofday(&operation_started,NULL);
741 	if (config->rrd_interval)
742 		rrd_create();
743 }
744 
free_targets(void)745 void free_targets(void){
746 struct target *t,*nt;
747 struct active_alarm_list *al,*nal;
748 
749 	/* delete all not configured targets */
750 	for(t=targets;t;t=nt){
751 		nt=t->next;
752 		for(al=t->active_alarms;al;al=nal){
753 			nal=al->next;
754 			free(al);
755 		}
756 		free(t->queue);
757 		free(t->rbuf);
758 		free(t->name);
759 		free(t->description);
760 		free(t);
761 	}
762 }
763 
764 
reload_config(void)765 void reload_config(void){
766 struct target *t;
767 struct active_alarm_list *al,*an;
768 struct alarm_cfg *a;
769 int r;
770 
771 	while(delayed_reports!=NULL) make_delayed_reports();
772 	for(t=targets;t;t=t->next)
773 		for(al=t->active_alarms;al;al=an){
774 			an=al->next;
775 			a=al->alarm;
776 			toggle_alarm(t,a,-1);
777 		}
778 	r=load_config(config_file);
779 	if (r==0) configure_targets();
780 }
781 
write_status(void)782 void write_status(void){
783 FILE *f;
784 struct target *t;
785 struct active_alarm_list *al;
786 struct alarm_cfg *a;
787 time_t tm;
788 int i,qp,really_lost;
789 char *buf1,*buf2;
790 int err=0;
791 
792 	if (config->status_file==NULL) return;
793 
794 	f=fopen(config->status_file,"w");
795 	if (f==NULL){
796 		logit("Couldn't open status file");
797 		myperror(config->status_file);
798 		return;
799 	}
800 	tm=time(NULL);
801 	fprintf(f,"%s\n",ctime(&tm));
802 	for(t=targets;t;t=t->next){
803 		fprintf(f,"Target: %s\n",t->name);
804 		fprintf(f,"Description: %s\n",t->description);
805 		fprintf(f,"Last reply received: #%i %s",t->last_received,
806 			ctime(&t->last_received_tv.tv_sec));
807 		fprintf(f,"Average delay: %0.3fms\n",AVG_DELAY(t));
808 		if (AVG_LOSS_KNOWN(t)){
809 			fprintf(f,"Average packet loss: %0.1f%%\n",AVG_LOSS(t));
810 		}
811 		fprintf(f,"Active alarms:");
812 		if (t->active_alarms){
813 			for(al=t->active_alarms;al;al=al->next){
814 				a=al->alarm;
815 				fprintf(f," \"%s\"",a->name);
816 			}
817 			fprintf(f,"\n");
818 		}
819 		else fprintf(f," None\n");
820 
821 		buf1=NEW(char,t->config->avg_loss_delay_samples+1);
822 		buf2=NEW(char,t->config->avg_loss_samples+1);
823 		i=t->last_sent%(t->config->avg_loss_delay_samples+t->config->avg_loss_samples);
824 		for(i=0;i<t->config->avg_loss_delay_samples;i++){
825 			if (i>=t->last_sent){
826 				buf1[t->config->avg_loss_delay_samples-i-1]='-';
827 				continue;
828 			}
829 			qp=(t->last_sent-i)%(t->config->avg_loss_delay_samples+
830 							t->config->avg_loss_samples);
831 			if (t->queue[qp])
832 				buf1[t->config->avg_loss_delay_samples-i-1]='#';
833 			else
834 				buf1[t->config->avg_loss_delay_samples-i-1]='.';
835 		}
836 		buf1[i]=0;
837 		really_lost=0;
838 		for(i=0;i<t->config->avg_loss_samples;i++){
839 			if (i>=t->last_sent-t->config->avg_loss_delay_samples){
840 				buf2[t->config->avg_loss_samples-i-1]='-';
841 				continue;
842 			}
843 			qp=(t->last_sent-i-t->config->avg_loss_delay_samples)
844 				%(t->config->avg_loss_delay_samples+t->config->avg_loss_samples);
845 			if (t->queue[qp])
846 				buf2[t->config->avg_loss_samples-i-1]='#';
847 			else{
848 				buf2[t->config->avg_loss_samples-i-1]='.';
849 				really_lost++;
850 			}
851 		}
852 		buf2[i]=0;
853 		fprintf(f,"Received packets buffer: %s %s\n",buf2,buf1);
854 		if (t->recently_lost!=really_lost){
855 			fprintf(f,"   lost packet count mismatch (%i!=%i)!\n",t->recently_lost,really_lost);
856 			logit("%s: Lost packet count mismatch (%i!=%i)!",t->name,t->recently_lost,really_lost);
857 			logit("%s: Received packets buffer: %s %s\n",t->name,buf2,buf1);
858 			err=1;
859 		}
860 		free(buf1);
861 		free(buf2);
862 
863 		fprintf(f,"\n");
864 	}
865 	fclose(f);
866 	if (err) abort();
867 }
868 
869 #ifdef FORKED_RECEIVER
870 int receiver_pipe=0;
871 
pipe_reply(struct timeval time_recv,int icmp_seq,struct trace_info * ti)872 void pipe_reply(struct timeval time_recv,int icmp_seq,struct trace_info *ti){
873 struct piped_info pi;
874 
875 	pi.recv_timestamp=time_recv;
876 	pi.icmp_seq=icmp_seq;
877 	pi.ti=*ti;
878 	write(receiver_pipe,&pi,sizeof(pi));
879 }
880 
receiver_loop(void)881 void receiver_loop(void){
882 struct pollfd pfd[2];
883 int npfd=0;
884 int i;
885 
886 	signal(SIGTERM,SIG_DFL);
887 	signal(SIGINT,SIG_DFL);
888 	signal(SIGHUP,SIG_DFL);
889 	signal(SIGUSR1,SIG_DFL);
890 	signal(SIGPIPE,SIG_DFL);
891 
892 	if (icmp_sock){
893 		pfd[npfd].events=POLLIN|POLLERR|POLLHUP|POLLNVAL;
894 		pfd[npfd].revents=0;
895 		pfd[npfd++].fd=icmp_sock;
896 	}
897 	if (icmp6_sock){
898 		pfd[npfd].events=POLLIN|POLLERR|POLLHUP|POLLNVAL;
899 		pfd[npfd++].fd=icmp6_sock;
900 		pfd[npfd].revents=0;
901 	}
902 	while(1){
903 		poll(pfd,npfd,-1);
904 		for(i=0;i<npfd;i++){
905 			if (!pfd[i].revents&POLLIN) continue;
906 			if (pfd[i].fd==icmp_sock) recv_icmp();
907 			else if (pfd[i].fd==icmp6_sock) recv_icmp6();
908 			pfd[i].revents=0;
909 		}
910 	};
911 }
912 #endif
913 
main_loop(void)914 void main_loop(void){
915 struct target *t;
916 struct timeval cur_time,next_status={0,0},tv,next_report={0,0},next_rrd_update={0,0};
917 struct pollfd pfd[2];
918 int timeout;
919 int npfd=0;
920 int i;
921 char buf[100];
922 int downtime;
923 struct alarm_list *al,*nal;
924 struct active_alarm_list *aal;
925 struct alarm_cfg *a;
926 #ifdef FORKED_RECEIVER
927 int recv_pipe[2];
928 int pid,r;
929 struct piped_info pi;
930 #endif
931 
932 	configure_targets();
933 #ifdef FORKED_RECEIVER
934 	r=pipe(recv_pipe);
935 	if (r){
936 		myperror("pipe");
937 		exit(1);
938 	}
939 	pid=fork();
940 	if (pid==-1){
941 		myperror("pipe");
942 		exit(1);
943 	}
944 	else if (pid==0){
945 		close(recv_pipe[0]);
946 		receiver_pipe=recv_pipe[1];
947 		receiver_loop();
948 		exit(0);
949 	}
950 	close(recv_pipe[1]);
951 	pfd[npfd].events=POLLIN|POLLERR|POLLHUP|POLLNVAL;
952 	pfd[npfd].revents=0;
953 	pfd[npfd++].fd=recv_pipe[0];
954 #else
955 	if (icmp_sock){
956 		pfd[npfd].events=POLLIN|POLLERR|POLLHUP|POLLNVAL;
957 		pfd[npfd].revents=0;
958 		pfd[npfd++].fd=icmp_sock;
959 	}
960 	if (icmp6_sock){
961 		pfd[npfd].events=POLLIN|POLLERR|POLLHUP|POLLNVAL;
962 		pfd[npfd++].fd=icmp6_sock;
963 		pfd[npfd].revents=0;
964 	}
965 #endif
966 	if (config->status_interval){
967 		gettimeofday(&cur_time,NULL);
968 		tv.tv_sec=config->status_interval/1000;
969 		tv.tv_usec=(config->status_interval%1000)*1000;
970 		timeradd(&cur_time,&tv,&next_status);
971 	}
972 	while(!interrupted_by){
973 		gettimeofday(&cur_time,NULL);
974 		if ( !timercmp(&next_probe,&cur_time,>) )
975 			timerclear(&next_probe);
976 		for(t=targets;t;t=t->next){
977 			for(al=t->config->alarms;al;al=nal){
978 				a=al->alarm;
979 				nal=al->next;
980 				if (a->type!=AL_DOWN || is_alarm_on(t,a)) continue;
981 				if (timerisset(&t->last_received_tv)){
982 					timersub(&cur_time,&t->last_received_tv,&tv);
983 				}
984 				else {
985 					timersub(&cur_time,&operation_started,&tv);
986 				}
987 				downtime=tv.tv_sec*1000+tv.tv_usec/1000;
988 				if ( downtime > a->p.val)
989 					toggle_alarm(t,a,1);
990 			}
991 			if (scheduled_event(&(t->next_probe),&cur_time,t->config->interval)){
992 				send_probe(t);
993 			}
994 			for(aal=t->active_alarms;aal;aal=aal->next){
995 				char *msgid;
996 				char buf[100];
997 				a=aal->alarm;
998 				if (a->repeat_interval<=0)
999 					continue;
1000 				if (!scheduled_event(&aal->next_repeat,&cur_time,a->repeat_interval))
1001 					continue;
1002 				if (a->repeat_max && aal->num_repeats>=a->repeat_max)
1003 					continue;
1004 				aal->num_repeats++;
1005 				debug("Repeating reports...");
1006 				sprintf(buf,"%i",aal->num_repeats);
1007 				msgid=gen_msgid(t,buf);
1008 				make_reports(t,a,1,msgid,aal->msgid);
1009 				free(msgid);
1010 			}
1011 		}
1012 		if (config->status_interval){
1013 			if (scheduled_event(&next_status,&cur_time,config->status_interval)){
1014 				if (config->status_file) write_status();
1015 				status_request=0;
1016 			}
1017 		}
1018 		if (config->rrd_interval){
1019 			if (scheduled_event(&next_rrd_update,&cur_time,config->rrd_interval)){
1020 				rrd_update();
1021 			}
1022 		}
1023 		if (delayed_reports){
1024 			if (timerisset(&next_report) && timercmp(&next_report,&cur_time,<)){
1025 				make_delayed_reports();
1026 				timerclear(&next_report);
1027 			}
1028 		}
1029 		if (delayed_reports){
1030 			if (!timerisset(&next_report)){
1031 				tv.tv_sec=delayed_reports->a->combine_interval/1000;
1032 				tv.tv_usec=(delayed_reports->a->combine_interval%1000)*1000;
1033 				timeradd(&delayed_reports->timestamp,&tv,&next_report);
1034 			}
1035 			if (!timerisset(&next_probe) || timercmp(&next_report,&next_probe,<))
1036 				next_probe=next_report;
1037 		}
1038 		strftime(buf,100,"%b %d %H:%M:%S",localtime(&next_probe.tv_sec));
1039 		debug("Next event scheduled for %s",buf);
1040 		gettimeofday(&cur_time,NULL);
1041 		if (timercmp(&next_probe,&cur_time,<)){
1042 			timeout=0;
1043 		}
1044 		else{
1045 			timersub(&next_probe,&cur_time,&tv);
1046 			timeout=tv.tv_usec/1000+tv.tv_sec*1000;
1047 		}
1048 		debug("Polling, timeout: %5.3fs",((double)timeout)/1000);
1049 		poll(pfd,npfd,timeout);
1050 		for(i=0;i<npfd;i++){
1051 			if (!pfd[i].revents&POLLIN) continue;
1052 #ifdef FORKED_RECEIVER
1053 			if (pfd[i].fd==recv_pipe[0]){
1054 				r=read(recv_pipe[0],&pi,sizeof(pi));
1055 				if (r==sizeof(pi))
1056 					analyze_reply(pi.recv_timestamp,pi.icmp_seq,&pi.ti);
1057 			}
1058 #else
1059 			if (pfd[i].fd==icmp_sock) recv_icmp();
1060 			else if (pfd[i].fd==icmp6_sock) recv_icmp6();
1061 #endif
1062 			pfd[i].revents=0;
1063 		}
1064 		if (status_request){
1065 			status_request=0;
1066 			if (config->status_file){
1067 				logit("SIGUSR1 received, writting status.");
1068 				write_status();
1069 			}
1070 		}
1071 		if (reload_request){
1072 			reload_request=0;
1073 			logit("SIGHUP received, reloading configuration.");
1074 			reload_config();
1075 		}
1076 	}
1077 #ifdef FORKED_RECEIVER
1078 	kill(pid,SIGTERM);
1079 #endif
1080 	while(delayed_reports!=NULL) make_delayed_reports();
1081 	free_targets();
1082 	if (macros_buf!=NULL) free(macros_buf);
1083 }
1084 
1085