From 2d526a3651f6e789f99b8e4c1c1583b39869972a Mon Sep 17 00:00:00 2001 From: Lucas Castro Date: Thu, 11 Jan 2024 12:07:59 -0300 Subject: New upstream version 1.0.8 --- Makefile | 26 +- README | 14 +- default_script | 4 +- default_script.sample | 2 +- defs.h | 2 +- foolsm.c | 2167 ++++++++++++++++++++++++++++++++++++++++++++ foolsm.conf | 54 ++ foolsm.conf.sample | 142 +++ foolsm.h | 72 ++ foolsm.init | 97 ++ foolsm.service | 14 + foolsm.spec | 951 +++++++++++++++++++ forkexec.c | 24 +- globals.c | 6 +- group_script | 6 +- lsm.c | 2162 ------------------------------------------- lsm.conf | 56 -- lsm.conf.sample | 144 --- lsm.h | 72 -- lsm.init | 97 -- lsm.service | 14 - lsm.spec | 887 ------------------ plugin_export.c | 12 +- plugin_export.h | 2 +- rsyslog-foolsm.conf.sample | 3 + rsyslog-lsm.conf.sample | 3 - save_statuses.c | 2 +- shorewall6_script | 1 - shorewall_script | 1 - usage.c | 4 +- 30 files changed, 3556 insertions(+), 3485 deletions(-) create mode 100644 foolsm.c create mode 100644 foolsm.conf create mode 100644 foolsm.conf.sample create mode 100644 foolsm.h create mode 100644 foolsm.init create mode 100644 foolsm.service create mode 100644 foolsm.spec delete mode 100644 lsm.c delete mode 100644 lsm.conf delete mode 100644 lsm.conf.sample delete mode 100644 lsm.h delete mode 100644 lsm.init delete mode 100644 lsm.service delete mode 100644 lsm.spec create mode 100644 rsyslog-foolsm.conf.sample delete mode 100644 rsyslog-lsm.conf.sample diff --git a/Makefile b/Makefile index cc8de81..2d9f1d3 100644 --- a/Makefile +++ b/Makefile @@ -4,12 +4,12 @@ # License: GPLv2 # -VERSION ?= $(lastword $(shell grep ^Version: lsm.spec)) -PROGS = lsm -PKG = lsm +VERSION ?= $(lastword $(shell grep ^Version: foolsm.spec)) +PROGS = foolsm +PKG = foolsm CC = gcc -override CFLAGS += -Wall -O2 -DLSM_VERSION=\"$(VERSION)\" +override CFLAGS += -Wall -O2 -DFOOLSM_VERSION=\"$(VERSION)\" #override CFLAGS += -D NO_PLUGIN_EXPORT #override CFLAGS += -D NO_PLUGIN_EXPORT_MUNIN #override CFLAGS += -D NO_PLUGIN_EXPORT_STATUS @@ -18,15 +18,15 @@ PREFIX ?= /usr/local DESTDIR ?= BINDIR ?= $(PREFIX)/sbin ifeq ($(PREFIX), /usr) -ETCDIR ?= /etc/lsm +ETCDIR ?= /etc/foolsm else -ETCDIR ?= $(PREFIX)/etc/lsm +ETCDIR ?= $(PREFIX)/etc/foolsm endif -DOCDIR ?= $(PREFIX)/share/doc/lsm +DOCDIR ?= $(PREFIX)/share/doc/foolsm EXAMPLEDIR ?= $(DOCDIR)/examples -SCRIPTDIR ?= $(PREFIX)/libexec/lsm +SCRIPTDIR ?= $(PREFIX)/libexec/foolsm -DOCFILES = README lsm.conf.sample default_script.sample rsyslog-lsm.conf.sample +DOCFILES = README foolsm.conf.sample default_script.sample rsyslog-foolsm.conf.sample SCRIPTS = shorewall_script shorewall6_script default_script group_script override CFLAGS += -D ETCDIR=\"$(ETCDIR)\" @@ -36,7 +36,7 @@ override CFLAGS += -D SCRIPTDIR=\"$(SCRIPTDIR)\" all: $(PROGS) -lsm: lsm.o icmp_t.o icmp6_t.o config.o globals.o cksum.o forkexec.o signal_handler.o timecalc.o plugin_export.o save_statuses.o pidfile.o cmdline.o usage.o +foolsm: foolsm.o icmp_t.o icmp6_t.o config.o globals.o cksum.o forkexec.o signal_handler.o timecalc.o plugin_export.o save_statuses.o pidfile.o cmdline.o usage.o clean distclean: rm -rf *~ .*~ *.o $(PROGS) debugfiles.list debuglinks.list debugsources.list *.orig @@ -57,9 +57,9 @@ rpm: tar install: all install -d $(DESTDIR)$(EXAMPLEDIR) install -d $(DESTDIR)$(SCRIPTDIR) - install -d $(DESTDIR)/var/lib/lsm - install -D -m0644 lsm.conf $(DESTDIR)$(ETCDIR)/lsm.conf - install -D -m0755 lsm $(DESTDIR)$(BINDIR)/lsm + install -d $(DESTDIR)/var/lib/foolsm + install -D -m0644 foolsm.conf $(DESTDIR)$(ETCDIR)/foolsm.conf + install -D -m0755 foolsm $(DESTDIR)$(BINDIR)/foolsm install -m0644 $(DOCFILES) $(DESTDIR)$(EXAMPLEDIR) install -m0755 $(SCRIPTS) $(DESTDIR)$(SCRIPTDIR) diff --git a/README b/README index 70973d6..6c58b30 100644 --- a/README +++ b/README @@ -6,7 +6,7 @@ License: GPLv2 You should be able to find GNU Public License from www.gnu.org. -LSM is a Link Status Monitor which can be used to monitor +Foolsm is a Link Status Monitor which can be used to monitor for example a Linux router/firewall connectivity and if you happen to have multiple connections it can change routing when an up/down event happens by utilizing external @@ -38,9 +38,9 @@ TODO DECISION MAKING =============== -As of lsm v0.27, the detection algorithm works like this: +As of foolsm v0.27, the detection algorithm works like this: -LSM keeps track of +Foolsm keeps track of 1) the result of the most recent pings (up to 100) 2) the number of consecutive lost pings. 3) the number of consecutive received pings. @@ -57,7 +57,7 @@ Else If connection (or group) is DOWN AND ( (A <= min_packet_loss) AND (C > min_successive_pkts_rcved) ) then change the connection (or group) to up. -Note: LSM assumes each connection starts UP. +Note: Foolsm assumes each connection starts UP. DEPENDENCIES @@ -71,7 +71,7 @@ INSTALLING ========== There is now Makefile target install for those of you not using rpms. I use only -rpm based distros so that may not be in sync with lsm.spec which does all what +rpm based distros so that may not be in sync with foolsm.spec which does all what I need. @@ -80,6 +80,4 @@ AUTHORS Mika Ilmaranta -See lsm.spec's changelog section for patch submitters. - -#EOF +See foolsm.spec's changelog section for patch submitters. diff --git a/default_script b/default_script index 2fe3e7c..b736053 100644 --- a/default_script +++ b/default_script @@ -33,7 +33,7 @@ fi DATE=$(date --date=@${TIMESTAMP}) -cat < + +License: GPLv2 + +*/ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "icmp_t.h" +#include "icmp6_t.h" +#include "config.h" +#include "cksum.h" +#include "globals.h" +#include "signal_handler.h" +#include "forkexec.h" +#include "timecalc.h" +#include "foolsm.h" +#ifndef NO_PLUGIN_EXPORT +#include "plugin_export.h" +#endif +#include "save_statuses.h" +#include "pidfile.h" +#include "cmdline.h" +#include "usage.h" + +typedef struct ping_data { + unsigned short id; /* target id */ + long ping_count; /* counts up to -c count or 1 */ + struct timeval ping_ts; /* time sent */ +} PING_DATA; + +static void update_stats(CONFIG *first); +static void dump_statuses(CONFIG *first); +static void decide(CONFIG *first); +static void groups_decide(GROUPS *firstg); +static int wait_for_replies(CONFIG **ctable); +static int ping_send(CONFIG *cur); +static int ping_rcv(CONFIG *first, char *buf, int len, struct sockaddr_in6 *saddr, unsigned int *slen, long usec, CONFIG **arp); +static int event_script_check(const char *path); +static int open_arp_sock(CONFIG *cur); +static int open_icmp_sock(CONFIG *cur); +static int probe_src_ip_addr(CONFIG *cur); +static void init_config_data(CONFIG *first, CONFIG *last, CONFIG ***ctable); +static void free_config_data(CONFIG *first); +#if defined(DEBUG) +static void dump_pkt(const void *buf, size_t len); +#endif + +static int num_hosts = 0; + +/* Main */ +int main(int argc, char *argv[]) { + TARGET *t = NULL; + CONFIG *first = NULL, *last = NULL, *cur; + GROUPS *firstg = NULL, *lastg = NULL; + CONFIG **ctable = NULL; + struct timeval last_sent_time = {0, 0}; + int start = 0; + + openlog("foolsm", LOG_PID, LOG_DAEMON); + + cmdline_parse(argc, argv); + + init_config(); + + if(read_config(get_configfile(), &first, &last, &firstg, &lastg)) { + usage_and_exit(); + } + + if(cfg.debug >= 9) syslog(LOG_INFO, "my ident is %d\n", get_ident()); + + if(!first) { + syslog(LOG_ERR, "no targets found in config file"); + exit(1); + } + + if(cfg.debug >= 9) dump_config(&first, &last, &firstg, &lastg); + + /* check pid file */ + if(pidfile_open() != 0) exit(1); + + /* detach from controlling terminal if nodaemon global is not set */ + if(get_nodaemon() == 0) { + if(daemon(1, 0)) { + syslog(LOG_ERR, "daemon failed while trying to detach"); + return(1); + } + } + + if(pidfile_update() != 0) exit(1); + + set_ident(getpid() & 0xFFFF); + +#ifndef NO_PLUGIN_EXPORT + plugin_export_init(); +#endif + + init_config_data(first, last, &ctable); + + signal(SIGINT, signal_handler); + signal(SIGUSR1, signal_handler); + signal(SIGUSR2, signal_handler); + signal(SIGHUP, signal_handler); + + /* + Create the handler for child signals. This will clean up + any forked child after an event has occured. + */ + create_sigchld_hdl(); + + struct timeval last_decision = {0, 0}; + + /* the main loop */ + while(get_cont()) { + struct timeval tv = {0, 0}; + + if(get_reload_cfg()) { + + save_statuses(first); + + /* reload config */ + free(ctable); + free_config_data(first); + if(reload_config(get_configfile(), &first, &last, &firstg, &lastg)) { + syslog(LOG_ERR, "reload config failed"); + exit(2); + } + init_config_data(first, last, &ctable); + + restore_statuses(first); + + set_reload_cfg(0); + } + + for(cur = first; cur; cur = cur->next) { + struct timeval current_time = {0, 0}; + + if(start) + while(wait_for_replies(ctable)); + + if(gettimeofday(¤t_time, NULL) == -1) { + syslog(LOG_INFO, "gettimeofday failed \"%s\"", strerror(errno)); + sleep(1); + continue; + } + + t = cur->data; + + if(timeval_diff_cmp(¤t_time, &last_sent_time, TIMEVAL_DIFF_CMP_LT, MIN_PERHOST_INTERVAL / 1000000L, MIN_PERHOST_INTERVAL % 1000000L)) continue; + + if(cur->startup_burst_pkts && t->used <= cur->startup_burst_pkts && !timeval_diff_cmp(¤t_time, &(t->last_send_time), TIMEVAL_DIFF_CMP_LT, (cur->startup_burst_interval * 1000) / 1000000L, (cur->startup_burst_interval * 1000) % 1000000L)); + else if(timeval_diff_cmp(¤t_time, &(t->last_send_time), TIMEVAL_DIFF_CMP_LT, (cur->interval_ms * 1000) / 1000000L, (cur->interval_ms * 1000) % 1000000L)) continue; + + if(cur->check_arp) { + open_arp_sock(cur); + } else { + open_icmp_sock(cur); + } + + if(ping_send(cur)) { + if(cfg.debug >= 9) syslog(LOG_INFO, "ping_send failed to %s", cur->name); + } + else { + gettimeofday(&last_sent_time, NULL); + start = 1; + } + } + + gettimeofday(&tv, NULL); + if(timeval_diff_cmp(&tv, &last_decision, TIMEVAL_DIFF_CMP_GT, 1, 0)) { /* make decisions at 1s intervals */ + gettimeofday(&last_decision, NULL); + + update_stats(first); + decide(first); + dump_statuses(first); + + groups_decide(firstg); + +#if defined(DEBUG) + exec_queue_dump(); +#endif + exec_queue_process(); + +#ifndef NO_PLUGIN_EXPORT + plugin_export(first); +#endif + } + } /* while cont */ + + /* if we wrote pid file then close and remove it */ + pidfile_close(); + + free(ctable); + free_config_data(first); + free_config(&first, &last, &firstg, &lastg); + exec_queue_free(); + + closelog(); + + return(0); +} + +static void free_config_data(CONFIG *first) { + CONFIG *cur; + + for(cur = first; cur; cur = cur->next) { + TARGET *t; + + t = cur->data; + if(t->sock != -1) close(t->sock); + free(t); + } +} + +static void update_stats(CONFIG *first) { + struct timeval current_time = {0, 0}; + CONFIG *cur; + + gettimeofday(¤t_time, NULL); + + for(cur = first; cur; cur = cur->next) { + TARGET *t; + int i, seq, ind; + long rtt = 0; + + t = cur->data; + + t->timeout = 0; + t->replied = 0; + t->waiting = 0; + t->reply_late = 0; + t->consecutive_waiting = 0; + t->consecutive_missing = 0; + t->consecutive_rcvd = 0; + + /* check consecutive pkts */ + seq = t->seq % FOLLOWED_PKTS; + + for(i = (seq - 2); i > (seq - 2) - FOLLOWED_PKTS; i--) { + ind = (i >= 0) ? i : i + FOLLOWED_PKTS; + if(!t->sentpkts[ind].flags.used) break; + + if(t->sentpkts[ind].flags.waiting) t->consecutive_waiting++; + else break; + } + + for(i = (seq - 2); i > (seq - 2) - FOLLOWED_PKTS; i--) { + ind = (i >= 0) ? i : i + FOLLOWED_PKTS; + if(!t->sentpkts[ind].flags.used) break; + + if(t->sentpkts[ind].flags.timeout || t->sentpkts[ind].flags.waiting) t->consecutive_missing++; + else break; + } + + for(i = (seq - 2); i > (seq - 2) - FOLLOWED_PKTS; i--) { + ind = (i >= 0) ? i : i + FOLLOWED_PKTS; + if(!t->sentpkts[ind].flags.used) break; + + if(t->sentpkts[ind].flags.replied && !t->sentpkts[ind].flags.timeout) t->consecutive_rcvd++; + else break; + } + + /* count pkt states */ + for(i = 0; i < FOLLOWED_PKTS; i++) { + if(!t->sentpkts[i].flags.used) continue; + + if(timeval_diff_cmp(¤t_time, &t->sentpkts[i].sent_time, TIMEVAL_DIFF_CMP_GT, (cur->timeout_ms * 1000) / 1000000L, (cur->timeout_ms * 1000) % 1000000L) && t->sentpkts[i].flags.waiting) { + t->sentpkts[i].flags.timeout = 1; + } + + if(t->sentpkts[i].flags.replied && t->sentpkts[i].flags.timeout) t->reply_late++; + + if(t->sentpkts[i].flags.replied) { + t->replied++; + rtt += t->sentpkts[i].rtt; /* count rtt sum in usec from replied pkts rtt which is in usec */ + } + if(t->sentpkts[i].flags.timeout) t->timeout++; + if(t->sentpkts[i].flags.waiting) t->waiting++; + } + /* avg_rtt in usec */ + t->avg_rtt = rtt / (t->replied ? t->replied : 1); + + /* update loss max info */ + if(t->timeout > t->timeout_max) t->timeout_max = t->timeout; + if(t->consecutive_missing > t->consecutive_missing_max) t->consecutive_missing_max = t->consecutive_missing; + + if(cfg.debug >= 9) syslog(LOG_INFO, "name = %s, replied = %d, waiting = %d, timeout = %d, late reply = %d, cons rcvd = %d, cons wait = %d, cons miss = %d, avg_rtt = %.3f, seq = %d, status = %s", + cur->name, t->replied, t->waiting, t->timeout, t->reply_late, t->consecutive_rcvd, t->consecutive_waiting, t->consecutive_missing, t->avg_rtt / 1000.0, t->seq, get_status_str(t->status)); + + } +} + +static void dump_statuses(CONFIG *first) { + CONFIG *cur; + + for(cur = first; cur; cur = cur->next) { + TARGET *t; + + t = cur->data; + + if((t->status == DOWN || t->status == LONG_DOWN) && t->downseq == (t->seq % FOLLOWED_PKTS) && t->seq != t->downseqreported && !t->status_change) syslog(LOG_INFO, "link %s still down", cur->name); + + /* dump is controlled by SIGUSR1 and then we should show all statuses anyway */ + if(get_dump() || t->status_change || ((t->status == DOWN || t->status == LONG_DOWN) && t->downseq == (t->seq % FOLLOWED_PKTS) && t->seq != t->downseqreported && !t->status_change)) { + if(cfg.debug >= 6) syslog(LOG_INFO, "name = %s, replied = %d, waiting = %d, timeout = %d, timeout max = %d, late reply = %d, cons rcvd = %d, cons wait = %d, cons miss = %d, cons miss max = %d, avg_rtt = %.3f, seq = %d, status = %s", + cur->name, t->replied, t->waiting, t->timeout, t->timeout_max, t->reply_late, t->consecutive_rcvd, t->consecutive_waiting, t->consecutive_missing, t->consecutive_missing_max, t->avg_rtt / 1000.0, t->seq, get_status_str(t->status)); + + if(cfg.debug >= 7) { + /* 100 should be enough for the comments and such, but I don't care to count */ + char buf[FOLLOWED_PKTS + 100]; + int i, seq; + + seq = t->seq % FOLLOWED_PKTS; + + sprintf(buf, "seq "); + for(i = 0; i < FOLLOWED_PKTS; i++) { + if(i == seq) strcat(buf, "*"); + else strcat(buf, " "); + } + syslog(LOG_INFO, "%s", buf); + + sprintf(buf, "used "); + for(i = 0; i < FOLLOWED_PKTS; i++) { + sprintf(buf + strlen(buf), "%d", t->sentpkts[i].flags.used); + } + syslog(LOG_INFO, "%s", buf); + + sprintf(buf, "wait "); + for(i = 0; i < FOLLOWED_PKTS; i++) { + sprintf(buf + strlen(buf), "%d", t->sentpkts[i].flags.waiting); + } + syslog(LOG_INFO, "%s", buf); + + sprintf(buf, "replied "); + for(i = 0; i < FOLLOWED_PKTS; i++) { + sprintf(buf + strlen(buf), "%d", t->sentpkts[i].flags.replied); + } + syslog(LOG_INFO, "%s", buf); + + sprintf(buf, "timeout "); + for(i = 0; i < FOLLOWED_PKTS; i++) { + sprintf(buf + strlen(buf), "%d", t->sentpkts[i].flags.timeout); + } + syslog(LOG_INFO, "%s", buf); + + sprintf(buf, "error "); + for(i = 0; i < FOLLOWED_PKTS; i++) { + sprintf(buf + strlen(buf), "%d", t->sentpkts[i].flags.error); + } + syslog(LOG_INFO, "%s", buf); + + if(t->status == UP && t->status_change) { + t->timeout_max = 0; + t->consecutive_missing_max = 0; + } + } + + t->downseqreported = t->seq; + } + } + if(get_dump()) set_dump(0); /* if we just dumped then don't dump next time. flags don't change that frequently */ +} + +static void decide(CONFIG *first) { + struct timeval current_time = {0, 0}; + CONFIG *cur; + + gettimeofday(¤t_time, NULL); + + for(cur = first; cur; cur = cur->next) { + TARGET *t; + STATUS prevstatus; + + t = cur->data; + + /* reset any previous connection status_change state */ + t->status_change = 0; + + prevstatus = t->status; + + /* up or unknown */ + if(t->status == UP || t->status == UNKNOWN) { + if(t->timeout >= cur->max_packet_loss || t->consecutive_missing >= cur->max_successive_pkts_lost) { + /* change to down state */ + t->status_change = 1; + t->status = DOWN; + +#if !defined(NO_PLUGIN_EXPORT) && !defined(NO_PLUGIN_EXPORT_STATUS) + plugin_export_status(first); +#endif + + if(cfg.debug >= 8) syslog(LOG_INFO, "link %s down event", cur->name); + if(event_script_check(cur->eventscript)) { + char sbuf[INET6_ADDRSTRLEN]; + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + cur->eventscript, + get_status_str(t->status), + cur->name, + cur->checkip, + cur->device ? cur->device : "", + cur->warn_email ? cur->warn_email : "", + t->replied, + t->waiting, + t->timeout, + t->reply_late, + t->consecutive_rcvd, + t->consecutive_waiting, + t->consecutive_missing, + t->avg_rtt, + cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), + get_status_str(prevstatus), + current_time.tv_sec); + envp = exec_queue_envp(); + + if(cur->queue && *cur->queue) { + exec_queue_add(cur->queue, argv, envp); + } else { + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + } + + if(event_script_check(cur->notifyscript)) { + char sbuf[INET6_ADDRSTRLEN]; + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + cur->notifyscript, + get_status_str(t->status), + cur->name, + cur->checkip, + cur->device ? cur->device : "", + cur->warn_email ? cur->warn_email : "", + t->replied, + t->waiting, + t->timeout, + t->reply_late, + t->consecutive_rcvd, + t->consecutive_waiting, + t->consecutive_missing, + t->avg_rtt, + cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), + get_status_str(prevstatus), + current_time.tv_sec); + + envp = exec_queue_envp(); + + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + + if(gettimeofday(&t->down_timestamp, NULL) == -1) { + syslog(LOG_INFO, "gettimeofday failed \"%s\"", strerror(errno)); + } + t->downseq = t->seq % FOLLOWED_PKTS; + t->downseqreported = 0; + } + } + + /* has it been down long? */ + if(t->status == DOWN && cur->long_down_time) { + if(timeval_diff_cmp(¤t_time, &t->down_timestamp, TIMEVAL_DIFF_CMP_GT, cur->long_down_time, 0)) { + /* special, LONG_DOWN is considered DOWN thus no status_change */ + t->status = LONG_DOWN; + + if(cfg.debug >= 8) syslog(LOG_INFO, "link %s long down event", cur->name); + if(event_script_check(cur->long_down_eventscript)) { + char sbuf[INET6_ADDRSTRLEN]; + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + cur->long_down_eventscript, + get_status_str(t->status), + cur->name, + cur->checkip, + cur->device ? cur->device : "", + cur->long_down_email ? cur->long_down_email : "", + t->replied, + t->waiting, + t->timeout, + t->reply_late, + t->consecutive_rcvd, + t->consecutive_waiting, + t->consecutive_missing, + t->avg_rtt, + cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), + get_status_str(prevstatus), + t->down_timestamp.tv_sec); + + envp = exec_queue_envp(); + + if(cur->queue && *cur->queue) { + exec_queue_add(cur->queue, argv, envp); + } else { + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + } + + if(event_script_check(cur->long_down_notifyscript)) { + char sbuf[INET6_ADDRSTRLEN]; + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + cur->long_down_notifyscript, + get_status_str(t->status), + cur->name, + cur->checkip, + cur->device ? cur->device : "", + cur->long_down_email ? cur->long_down_email : "", + t->replied, + t->waiting, + t->timeout, + t->reply_late, + t->consecutive_rcvd, + t->consecutive_waiting, + t->consecutive_missing, + t->avg_rtt, + cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), + get_status_str(prevstatus), + t->down_timestamp.tv_sec); + + envp = exec_queue_envp(); + + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + } + } + + /* down, long down or unknown */ + if(t->status == DOWN || t->status == LONG_DOWN || t->status == UNKNOWN) { + if((cur->startup_acceleration && t->consecutive_rcvd >= cur->startup_acceleration && (t->consecutive_rcvd + 1) >= t->used) || (t->timeout <= cur->min_packet_loss && t->consecutive_rcvd >= cur->min_successive_pkts_rcvd)) { + + t->status_change = 1; + t->status = UP; + +#if !defined(NO_PLUGIN_EXPORT) && !defined(NO_PLUGIN_EXPORT_STATUS) + plugin_export_status(first); +#endif + + /* report long_down to up */ + if(prevstatus == LONG_DOWN) { + if(event_script_check(cur->long_down_eventscript)) { + char sbuf[INET6_ADDRSTRLEN]; + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + cur->long_down_eventscript, + get_status_str(t->status), + cur->name, + cur->checkip, + cur->device ? cur->device : "", + cur->long_down_email ? cur->long_down_email : "", + t->replied, + t->waiting, + t->timeout, + t->reply_late, + t->consecutive_rcvd, + t->consecutive_waiting, + t->consecutive_missing, + t->avg_rtt, + cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), + get_status_str(prevstatus), + current_time.tv_sec); + + envp = exec_queue_envp(); + + if(cur->queue && *cur->queue) { + exec_queue_add(cur->queue, argv, envp); + } else { + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + } + + if(event_script_check(cur->long_down_notifyscript)) { + char sbuf[INET6_ADDRSTRLEN]; + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + cur->long_down_notifyscript, + get_status_str(t->status), + cur->name, + cur->checkip, + cur->device ? cur->device : "", + cur->long_down_email ? cur->long_down_email : "", + t->replied, + t->waiting, + t->timeout, + t->reply_late, + t->consecutive_rcvd, + t->consecutive_waiting, + t->consecutive_missing, + t->avg_rtt, + cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), + get_status_str(prevstatus), + current_time.tv_sec); + + envp = exec_queue_envp(); + + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + } + + /* change to up state */ + if(cfg.debug >= 8) syslog(LOG_INFO, "link %s up event", cur->name); + if(event_script_check(cur->eventscript)) { + char sbuf[INET6_ADDRSTRLEN]; + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + cur->eventscript, + get_status_str(t->status), + cur->name, + cur->checkip, + cur->device ? cur->device : "", + cur->warn_email ? cur->warn_email : "", + t->replied, + t->waiting, + t->timeout, + t->reply_late, + t->consecutive_rcvd, + t->consecutive_waiting, + t->consecutive_missing, + t->avg_rtt, + cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), + get_status_str(prevstatus), + current_time.tv_sec); + + envp = exec_queue_envp(); + + if(cur->queue && *cur->queue) { + exec_queue_add(cur->queue, argv, envp); + } else { + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + } + + if((cur->unknown_up_notify || t->status != UNKNOWN) && event_script_check(cur->notifyscript)) { + char sbuf[INET6_ADDRSTRLEN]; + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + cur->notifyscript, + get_status_str(t->status), + cur->name, + cur->checkip, + cur->device ? cur->device : "", + cur->warn_email ? cur->warn_email : "", + t->replied, + t->waiting, + t->timeout, + t->reply_late, + t->consecutive_rcvd, + t->consecutive_waiting, + t->consecutive_missing, + t->avg_rtt, + cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), + get_status_str(prevstatus), + current_time.tv_sec); + + envp = exec_queue_envp(); + + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + } + } + } +} + +static void groups_decide(GROUPS *firstg){ + GROUPS *curg; + GROUP_MEMBERS *curgm; + TARGET *t; + STATUS prevstatus; + struct timeval current_time = {0, 0}; + + gettimeofday(¤t_time, NULL); + + curg = firstg; + while(curg) { + prevstatus = curg->status; + curg->status = curg->logic; + + curgm = curg->fgm; + while(curgm) { + if(!curgm->cfg_ptr) break; + + t = curgm->cfg_ptr->data; + + /* if any one group member is in unknown status, group is in unknown status */ + if(t->status == UNKNOWN) { + curg->status = UNKNOWN; + break; + } + + if(!curg->logic) { + curg->status |= (t->status == DOWN || t->status == LONG_DOWN) ? DOWN : t->status; + } else { + curg->status &= (t->status == DOWN || t->status == LONG_DOWN) ? DOWN : t->status; + } + + curgm = curgm->next; + } + if(curg->status != prevstatus) { + if(curg->status == UP) { + /* group up event */ + if(cfg.debug >= 8) syslog(LOG_INFO, "group %s up event", curg->name); + if(event_script_check(curg->eventscript)) { + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + curg->eventscript, + get_status_str(curg->status), + curg->name, + "", + "", + curg->warn_email ? curg->warn_email : "", + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + "", + get_status_str(prevstatus), + current_time.tv_sec); + envp = exec_queue_envp(); + + if(curg->queue && *curg->queue) { + exec_queue_add(curg->queue, argv, envp); + } else { + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + } + if((curg->unknown_up_notify || prevstatus != UNKNOWN) && event_script_check(curg->notifyscript)) { + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + curg->notifyscript, + get_status_str(curg->status), + curg->name, + "", + "", + curg->warn_email ? curg->warn_email : "", + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + "", + get_status_str(prevstatus), + current_time.tv_sec); + envp = exec_queue_envp(); + + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + } + + if(curg->status == DOWN) { + /* group down event */ + if(cfg.debug >= 8) syslog(LOG_INFO, "group %s down event", curg->name); + if(event_script_check(curg->eventscript)) { + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + curg->eventscript, + get_status_str(curg->status), + curg->name, + "", + "", + curg->warn_email ? curg->warn_email : "", + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + "", + get_status_str(prevstatus), + current_time.tv_sec); + envp = exec_queue_envp(); + + if(curg->queue && *curg->queue) { + exec_queue_add(curg->queue, argv, envp); + } else { + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + } + if(event_script_check(curg->notifyscript)) { + char **argv; + char **envp; + + argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", + curg->notifyscript, + get_status_str(curg->status), + curg->name, + "", + "", + curg->warn_email ? curg->warn_email : "", + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + "", + get_status_str(prevstatus), + current_time.tv_sec); + envp = exec_queue_envp(); + + forkexec(argv, envp); + + exec_queue_argv_free(argv); + exec_queue_envp_free(envp); + } + } + } + curg = curg->next; + } +} + +static int wait_for_replies(CONFIG **ctable) { + struct ip *ip; + int hlen = 0; + struct icmp *icp; + struct icmp6_hdr *icp6; + PING_DATA *pdp; + int this_count; + struct timeval sent_time = {0, 0}; + struct timeval current_time = {0, 0}; + long time_diff; + char buf[BUFSIZ]; + union { + struct sockaddr_in6 saddr6; + struct sockaddr_in saddr; + struct sockaddr_ll FROM; + } from_addr; + unsigned int slen; + int result; + TARGET *t; + int seq; + CONFIG *arp; + + slen = sizeof(from_addr); + result = ping_rcv(ctable[0], buf, BUFSIZ, (struct sockaddr_in6 *)&from_addr, &slen, DEFAULT_SELECT_WAIT, &arp); + + if(result <= 0) { + return(0); + } + + gettimeofday(¤t_time, NULL); + + if(arp) { + struct sockaddr_ll *FROM = &from_addr.FROM; + TARGET *t = arp->data; + struct arphdr *ah = (struct arphdr*)buf; + unsigned char *p = (unsigned char *)(ah+1); + struct in_addr src_ip, dst_ip; + int ind; + + /* Filter out wild packets */ + if(FROM->sll_pkttype != PACKET_HOST && + FROM->sll_pkttype != PACKET_BROADCAST && + FROM->sll_pkttype != PACKET_MULTICAST) + return(1); + + /* Only these types are recognised */ +#if 0 + if(ah->ar_op != htons(ARPOP_REQUEST) && + ah->ar_op != htons(ARPOP_REPLY)) + return(1); +#else + if(ah->ar_op != htons(ARPOP_REPLY)) + return(1); +#endif + + /* ARPHRD check and this darned FDDI hack here :-( */ + if(ah->ar_hrd != htons(FROM->sll_hatype) && + (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER))) + return(1); + + /* Protocol must be IP. */ + if(ah->ar_pro != htons(ETH_P_IP)) + return(1); + if(ah->ar_pln != 4) + return(1); + if(ah->ar_hln != t->me.sll_halen) + return(1); + +#if defined(DEBUG) + for(ind = 0; ind < result; ind ++) { + fprintf(stderr, "%02x", (unsigned char)buf[ind]); + if(!((ind + 1) % 2)) fprintf(stderr, " "); + if(!((ind + 1) % 32)) fprintf(stderr, "\n"); + } + fprintf(stderr, "\n"); + for(ind = 0; ind < result; ind ++) { + fprintf(stderr, "%3u", (unsigned char)buf[ind]); + if(!((ind + 1) % 32)) fprintf(stderr, "\n"); + else fprintf(stderr, ","); + } + fprintf(stderr, "\n"); +#endif + + if(result < sizeof(*ah) + 2*(4 + ah->ar_hln)) + return(1); + + memcpy(&src_ip, p+ah->ar_hln, 4); + memcpy(&dst_ip, p+ah->ar_hln+4+ah->ar_hln, 4); + + if(src_ip.s_addr != t->dst.s_addr) + return(1); + if(t->src.s_addr != dst_ip.s_addr) + return(1); + if(memcmp(p+ah->ar_hln+4, &t->me.sll_addr, ah->ar_hln)) + return(1); + + /* update packet log here */ + /* there are no sequence numbers in arp replies so just mark seq - 1 replied */ + ind = ((t->seq - 1) >= 0 ? (t->seq - 1) : (FOLLOWED_PKTS + (t->seq - 1))) % FOLLOWED_PKTS; + t->sentpkts[ind].flags.replied = 1; + t->sentpkts[ind].flags.waiting = 0; + t->sentpkts[ind].replied_time = current_time; + t->sentpkts[ind].rtt = timeval_diff(¤t_time, &t->sentpkts[ind].sent_time); + + return(1); + } + +#if defined(DEBUG) + if(cfg.debug >= 9) { + char sbuf[INET6_ADDRSTRLEN]; + + syslog(LOG_INFO, "not arp: family = %d, AF_INET = %d, AF_INET6 = %d, inet_ntop addr = %s, inet_ntoa addr = %s", from_addr.saddr6.sin6_family, AF_INET, AF_INET6, inet_ntop(from_addr.saddr6.sin6_family, &from_addr.saddr6.sin6_addr, sbuf, INET6_ADDRSTRLEN), inet_ntoa(from_addr.saddr.sin_addr)); + } +#endif + + switch(from_addr.saddr6.sin6_family) { + case AF_INET: +#if defined(DEBUG) + syslog(LOG_INFO, "%s: %s: AF_INET reply", __FILE__, __FUNCTION__); +#endif + ip = (struct ip *)buf; + hlen = ip->ip_hl << 2; + + icp = (struct icmp *)(buf + hlen); + + if(icp->icmp_type == ICMP_ECHO) { + return(1); + } + + if(icp->icmp_type == ICMP_ECHOREPLY) { + if(icp->icmp_id != get_ident()) { + /* fprintf(stderr, "icmp_id = %d funny, got reply from %s to something else ...\n", icp->icmp_id, inet_ntoa(saddr.sin_addr)); */ + return(1); + } + + if(result < sizeof(struct icmp) + sizeof(PING_DATA)) { + /* fprintf(stderr, "too short ping reply\n"); */ + return(1); + } + + pdp = (PING_DATA *)(buf + hlen + sizeof(struct icmp)); + + this_count = pdp->ping_count; + sent_time = pdp->ping_ts; + time_diff = timeval_diff(¤t_time, &sent_time); + + if(pdp->id >= num_hosts) { +#if defined(DEBUG) + syslog(LOG_INFO, "out of range: pdp->id = %d >= num_hosts = %d from %s", pdp->id, num_hosts, inet_ntoa(from_addr.saddr.sin_addr)); + dump_pkt(buf, sizeof(struct ip) + sizeof(struct icmp) + sizeof(PING_DATA)); + set_dump(1); +#endif + return(1); + } + + t = ctable[pdp->id]->data; + + if(memcmp(&ip->ip_src, &t->dst, sizeof(struct in_addr) != 0)) { + return(1); + } + + seq = icp->icmp_seq % FOLLOWED_PKTS; + if(t->sentpkts[seq].seq == icp->icmp_seq) { + t->sentpkts[seq].flags.replied = 1; + t->sentpkts[seq].flags.waiting = 0; + t->sentpkts[seq].replied_time = current_time; + t->sentpkts[seq].rtt = timeval_diff(¤t_time, &t->sentpkts[seq].sent_time); + } + else + if(cfg.debug >= 9) syslog(LOG_INFO, "sentpkts seq != icmp_seq"); + + if(cfg.debug >= 9) syslog(LOG_INFO, "received seq = %d from %s, id = %d, num_sent = %d, target id = %u, time_diff = %ld", icp->icmp_seq, inet_ntoa(from_addr.saddr.sin_addr), icp->icmp_id, this_count, pdp->id, time_diff); + + return(1); + + } else { + struct icmpmsg *msg; + + msg = stricmp(icp->icmp_type, icp->icmp_code); + + if(cfg.debug >= 9) syslog(LOG_INFO, "got odd reply from %s, icmp_type = %d %s, icmp_code = %d %s", inet_ntoa(from_addr.saddr.sin_addr), icp->icmp_type, msg->type_msg, icp->icmp_code, msg->code_msg); + + return(1); + } + break; + case AF_INET6: +#if defined(DEBUG) + syslog(LOG_INFO, "%s: %s: AF_INET6 reply", __FILE__, __FUNCTION__); +#endif + icp6 = (struct icmp6_hdr *)buf; + + if(icp6->icmp6_type == ICMP6_ECHO_REQUEST) { + return(1); + } + + if (icp6->icmp6_type == ICMP6_ECHO_REPLY) { /* v6 reply */ + char sbuf[INET6_ADDRSTRLEN]; +#if defined(DEBUG) + dump_pkt(buf, sizeof(struct icmp6_hdr) + sizeof(PING_DATA)); +#endif + /* syslog(LOG_INFO, "sizeof struct icmp6_hdr = %ld\n", sizeof(struct icmp6_hdr)); */ + + if(icp6->icmp6_id != get_ident()) { + return(1); + } + + if(result < sizeof(struct icmp6_hdr) + sizeof(PING_DATA)) { + return(1); + } + + /* pdp = (PING_DATA *)(buf + hlen + sizeof(struct icmp6_hdr)); */ + /* pdp = (PING_DATA *)(buf + sizeof(struct icmp6_hdr)); */ + pdp = (PING_DATA *)(buf + sizeof(struct icmp6_hdr)); + + this_count = pdp->ping_count; + sent_time = pdp->ping_ts; + time_diff = timeval_diff(¤t_time, &sent_time); + +#if defined(DEBUG) + syslog(LOG_INFO, "%s: %s: this_count = %d, sent_time = %ld,%ld, pdp->id = %d", __FILE__, __FUNCTION__, this_count, sent_time.tv_sec, sent_time.tv_usec, pdp->id); +#endif + + if(pdp->id >= num_hosts) { +#if defined(DEBUG) + syslog(LOG_INFO, "out of range: pdp->id = %d >= num_hosts = %d from %s", pdp->id, num_hosts, inet_ntop(AF_INET6, &from_addr.saddr6.sin6_addr, sbuf, INET6_ADDRSTRLEN)); + dump_pkt(buf, sizeof(struct icmp6_hdr) + sizeof(PING_DATA)); + set_dump(1); +#endif + return(1); + } + + t = ctable[pdp->id]->data; + + if(memcmp(&from_addr.saddr6.sin6_addr, &t->dst6, sizeof(struct in6_addr)) != 0) { + return(1); + } + + seq = ntohs(icp6->icmp6_seq) % FOLLOWED_PKTS; + if(t->sentpkts[seq].seq == ntohs(icp6->icmp6_seq)) { + t->sentpkts[seq].flags.replied = 1; + t->sentpkts[seq].flags.waiting = 0; + t->sentpkts[seq].replied_time = current_time; + t->sentpkts[seq].rtt = timeval_diff(¤t_time, &t->sentpkts[seq].sent_time); + } + else + if (cfg.debug >= 9) syslog(LOG_INFO, "sentpkts seq != icmp_seq"); + + if(cfg.debug >= 9) syslog(LOG_INFO, "received seq = %d from %s, id = %d, num_sent = %d, target id = %u, time_diff = %ld", ntohs(icp6->icmp6_seq), inet_ntop(AF_INET6, &from_addr.saddr6.sin6_addr, sbuf, INET6_ADDRSTRLEN), icp6->icmp6_id, this_count, pdp->id, time_diff); + + return(1); + } else { + char sbuf[INET6_ADDRSTRLEN]; + struct icmp6msg *msg; + + msg = stricmp6(icp6->icmp6_type, icp6->icmp6_code); + + if(cfg.debug >= 9) syslog(LOG_INFO, "got odd reply from %s, icmp_type = %d %s, icmp_code = %d %s", inet_ntop(from_addr.saddr6.sin6_family, &from_addr.saddr6.sin6_addr, sbuf, INET6_ADDRSTRLEN), icp6->icmp6_type, msg->type_msg, icp6->icmp6_code, msg->code_msg); + + return(1); + } + break; + default: + syslog(LOG_INFO, "%s: %s: unknown family reply", __FILE__, __FUNCTION__); + break; + } + + return(1); +} + +static int ping_rcv(CONFIG *first, char *buf, int len, struct sockaddr_in6 *saddr, unsigned int *slen, long usec, CONFIG **arp) { + int nfound, n; + fd_set readset; + struct timeval to = {0, 0}; + int max; + CONFIG *cur; + TARGET *t; + int cnt_targets = 0; + + FD_ZERO(&readset); + max = 0; + + for(cur = first; cur; cur = cur->next) { + t = cur->data; + if(t->sock == -1) continue; + if(t->sock > max) max = t->sock; + FD_SET(t->sock, &readset); + cnt_targets++; + } + + /* no point in calling select if we didn't find any open sockets. so sleep and return ... */ + if(cnt_targets == 0) { + sleep(1); + return(0); + } + + to.tv_sec = usec / 1000000; + to.tv_usec = (usec - (to.tv_sec * 1000000)); + +#if defined(DEBUG) + printf("to.tv_sec = %ld, to.tv_usec = %ld\n", to.tv_sec, to.tv_usec); +#endif + + nfound = select(max + 1, &readset, NULL, NULL, &to); + + if(nfound < 0) { + if(errno != EINTR) syslog(LOG_INFO, "select failed \"%s\"", strerror(errno)); + return(0); + } + + if(nfound == 0) return(-1); + + for(cur = first; cur; cur = cur->next) { + t = cur->data; + if(t->sock == -1) continue; + if(FD_ISSET(t->sock, &readset)) { + if(!cur->check_arp) { + *arp = (CONFIG *)NULL; + } else { + *arp = cur; + } + + n = recvfrom(t->sock, buf, len, 0, (struct sockaddr *)saddr, slen); + + if(n < 0) { + syslog(LOG_INFO, "recvfrom failed with %s \"%s\"\n", cur->name, strerror(errno)); + close(t->sock); + t->sock = -1; + return(0); + } + + return(n); + } + } + return(0); +} + +static int ping_send(CONFIG *cur) { + char buf[BUFSIZ]; + struct icmp *icp; + PING_DATA *pdp; + TARGET *t; + int n; + int ping_pkt_size; + + t = cur->data; + + gettimeofday(&t->last_send_time, NULL); + + if(cur->check_arp) { + int err; + unsigned char buf[256]; + struct arphdr *ah = (struct arphdr*)buf; + unsigned char *p = (unsigned char *)(ah+1); + + if(cur->dstinfo->ai_family == AF_INET6) { + syslog(LOG_ERR, "%s: %s: ipv6 arping not supported", __FILE__, __FUNCTION__); + return(-1); + } + + ah->ar_hrd = htons(t->me.sll_hatype); + if(ah->ar_hrd == htons(ARPHRD_FDDI)) + ah->ar_hrd = htons(ARPHRD_ETHER); + ah->ar_pro = htons(ETH_P_IP); + ah->ar_hln = t->me.sll_halen; + ah->ar_pln = 4; + ah->ar_op = htons(ARPOP_REQUEST); + + memcpy(p, &t->me.sll_addr, ah->ar_hln); + p += t->me.sll_halen; + + memcpy(p, &t->src, 4); + p += 4; + + memcpy(p, &t->he.sll_addr, ah->ar_hln); + p += ah->ar_hln; + + memcpy(p, &t->dst, 4); + p += 4; + +#if defined(DEBUG) + { + int ind; + for(ind = 0; ind < p - buf; ind ++) { + fprintf(stderr, "%02x", (unsigned char)buf[ind]); + if(!((ind + 1) % 2)) fprintf(stderr, " "); + if(!((ind + 1) % 32)) fprintf(stderr, "\n"); + } + fprintf(stderr, "\n"); + for(ind = 0; ind < p - buf; ind ++) { + fprintf(stderr, "%3u", (unsigned char)buf[ind]); + if(!((ind + 1) % 32)) fprintf(stderr, "\n"); + else fprintf(stderr, ","); + } + fprintf(stderr, "\n"); + } +#endif + + if(t->sock != -1) { + err = sendto(t->sock, buf, p - buf, 0, (struct sockaddr*)&t->he, sizeof(t->he)); + if(err < 0) { + if(cfg.debug >= 9) syslog(LOG_ERR, "arping sendto failed to %s on %s reason \"%s\"", cur->name, cur->device, strerror(errno)); + close(t->sock); + t->sock = -1; + } + } else { + if(cfg.debug >= 9) syslog(LOG_INFO, "arping sendto socket not open for %s", cur->name); + err = -1; + } + + { /* we don't care what the error was just advance with seq */ + int seq; + + seq = t->seq % FOLLOWED_PKTS; + t->sentpkts[seq].seq = t->seq; + t->sentpkts[seq].sent_time = t->last_send_time; + t->sentpkts[seq].flags.replied = 0; + t->sentpkts[seq].flags.timeout = 0; + t->sentpkts[seq].flags.waiting = 1; + if(t->sentpkts[seq].flags.used == 0) t->used++; + t->sentpkts[seq].flags.used = 1; + t->sentpkts[seq].flags.error = (err == -1) ? 1 : 0; + + t->seq = (t->seq + 1) % SEQ_LIMITER; /* limit seq so that consecutive missing and received pkt counting doesn't get confused when seq "overflows" */ + t->num_sent++; + + } + if(err == (p - buf)) { + return(0); + } + return(err); + } + + if(cur->dstinfo->ai_family == AF_INET6) { + struct icmp6_hdr *icp6; + + ping_pkt_size = sizeof(struct icmp6_hdr) + sizeof(PING_DATA); + + memset(buf, 0, ping_pkt_size); + + icp6 = (struct icmp6_hdr *)buf; + + icp6->icmp6_type = ICMP6_ECHO_REQUEST; + icp6->icmp6_code = 0; + icp6->icmp6_seq = htons(t->seq); /* I saw a tcpdump suggesting that there is something wrong with seq thus htons() */ + icp6->icmp6_id = get_ident(); + + pdp = (PING_DATA *)(buf + sizeof(struct icmp6_hdr)); + pdp->ping_count = t->num_sent; + pdp->ping_ts = t->last_send_time; + pdp->id = t->id; + + icp6->icmp6_cksum = 0; /* the ipv6 stack calculates the checksum for us */ + + if(t->sock != -1) { + if(cfg.debug >= 9) syslog(LOG_INFO, "cmsglen = %d", t->cmsglen); + + if(t->cmsglen == 0) { + n = sendto(t->sock, buf, ping_pkt_size, 0, (struct sockaddr *)&t->dst_addr6, sizeof(t->dst_addr6)); + if(n < 0) { + if(errno == ENODEV) { + if(cfg.debug >= 9) syslog(LOG_ERR, "connection %s no such device %s \"%s\"", cur->name, cur->device, strerror(errno)); + } else + if (cfg.debug >= 9) syslog(LOG_ERR, "ping6 sendto failed to %s on %s reason \"%s\"", cur->name, cur->device, strerror(errno)); + + if(t->sock != -1) { + close(t->sock); + t->sock = -1; + } + } + } else { + struct msghdr mhdr; + struct iovec iov; + int confirm = 0; + + iov.iov_len = ping_pkt_size; + iov.iov_base = buf; + + mhdr.msg_name = &t->dst_addr6; + mhdr.msg_namelen = sizeof(struct sockaddr_in6); + mhdr.msg_iov = &iov; + mhdr.msg_iovlen = 1; + mhdr.msg_control = t->cmsgbuf; + mhdr.msg_controllen = t->cmsglen; + + n = sendmsg(t->sock, &mhdr, confirm); + if(cfg.debug >= 9 && n < 0) syslog(LOG_INFO, "sendmsg failed for %s %s", cur->name, strerror(errno)); + if(n < 0) { + close(t->sock); + t->sock = -1; + } + } + } else { + if(cfg.debug >= 9) syslog(LOG_INFO, "ping sendto socket not open for %s", cur->name); + n = -1; + } + { + /* we don't care what the error was just advance with seq */ + int seq; + + seq = t->seq % FOLLOWED_PKTS; +#if defined(DEBUG) + fprintf(stderr, "ping_send seq = %d to %s, num_sent = %ld, %ld, pkt_size = %d\n", t->seq, inet_ntoa(t->dst_addr.sin_addr), t->num_sent, pdp->ping_count, ping_pkt_size); +#endif + t->sentpkts[seq].seq = t->seq; + t->sentpkts[seq].sent_time = t->last_send_time; + t->sentpkts[seq].flags.replied = 0; + t->sentpkts[seq].flags.timeout = 0; + t->sentpkts[seq].flags.waiting = 1; + if(t->sentpkts[seq].flags.used == 0) t->used++; + t->sentpkts[seq].flags.used = 1; + t->sentpkts[seq].flags.error = (n < 1) ? 1 : 0; + + t->seq = (t->seq + 1) % SEQ_LIMITER; + /* limit seq so that consecutive missing and received pkt counting doesn't get confused when seq "overflows" */ + t->num_sent++; + } + if(n == ping_pkt_size) { + return(0); + } + + return(n); + } + + /* send a ping packet */ + ping_pkt_size = sizeof(struct icmp) + sizeof(PING_DATA); + + memset(buf, 0, ping_pkt_size); + + icp = (struct icmp *)buf; + + icp->icmp_type = ICMP_ECHO; + icp->icmp_code = 0; + icp->icmp_cksum = 0; + icp->icmp_seq = t->seq; + icp->icmp_id = get_ident(); + + pdp = (PING_DATA *)(buf + sizeof(struct icmp)); + pdp->ping_count = t->num_sent; + pdp->ping_ts = t->last_send_time; + pdp->id = t->id; + + icp->icmp_cksum = in_cksum((u_short *)icp, ping_pkt_size); + + if(t->sock != -1) { + n = sendto(t->sock, buf, ping_pkt_size, 0, (struct sockaddr *)&t->dst_addr, sizeof(struct sockaddr)); + + if(n < 0) { + if(errno == ENODEV) { + if(cfg.debug >= 9) syslog(LOG_ERR, "connection %s no such device %s \"%s\"", cur->name, cur->device, strerror(errno)); + /* exit(2); */ /* commented out. handle this situation like the packet had been sent. see below. */ + } + else + if(cfg.debug >= 9) syslog(LOG_ERR, "ping sendto failed to %s on %s reason \"%s\"", cur->name, cur->device, strerror(errno)); + + if(t->sock != -1) { + close(t->sock); + t->sock = -1; + } + } + } else { + if(cfg.debug >= 9) syslog(LOG_INFO, "ping sendto socket not open for %s", cur->name); + n = -1; + } + + { /* we don't care what the error was just advance with seq */ + int seq; + + seq = t->seq % FOLLOWED_PKTS; +#if defined(DEBUG) + fprintf(stderr, "ping_send seq = %d to %s, num_sent = %ld, %ld, pkt_size = %d\n", t->seq, inet_ntoa(t->dst_addr.sin_addr), t->num_sent, pdp->ping_count, ping_pkt_size); +#endif + t->sentpkts[seq].seq = t->seq; + t->sentpkts[seq].sent_time = t->last_send_time; + t->sentpkts[seq].flags.replied = 0; + t->sentpkts[seq].flags.timeout = 0; + t->sentpkts[seq].flags.waiting = 1; + if(t->sentpkts[seq].flags.used == 0) t->used++; + t->sentpkts[seq].flags.used = 1; + t->sentpkts[seq].flags.error = (n < 1) ? 1 : 0; + + t->seq = (t->seq + 1) % SEQ_LIMITER; /* limit seq so that consecutive missing and received pkt counting doesn't get confused when seq "overflows" */ + t->num_sent++; + } + + if(n == ping_pkt_size) { + return(0); + } + return(n); +} + +static int event_script_check(const char *path) +{ + struct stat statbuf; + + if(!path) { + if(cfg.debug >= 9) syslog(LOG_ERR, "NULL pointer event script"); + return(0); + } + + if(!*path) { + if(cfg.debug >= 9) syslog(LOG_ERR, "null string event script"); + return(0); + } + + /* check that the script is owner executable */ + if(stat(path, &statbuf) == -1) { + syslog(LOG_ERR, "failed to stat event script \"%s\" reason \"%s\"", path, strerror(errno)); + return(0); + } + + if((statbuf.st_mode & S_IXUSR) == 0) { + syslog(LOG_ERR, "event script \"%s\" is not executable by owner, please check permissions", path); + return(0); + } + + return(1); +} + +static void init_config_data(CONFIG *first, CONFIG *last, CONFIG ***ctable) +{ + int i; + CONFIG *cur; + TARGET *t = NULL; + + /* initialize config->data */ + for(cur = first, num_hosts = 0; cur; cur = cur->next, num_hosts++) { + u_int ipaddress; + + if((t = malloc(sizeof(TARGET))) == NULL) { + syslog(LOG_ERR, "main: initializing targets failed to malloc"); + exit(1); + } + memset(t, 0, sizeof(TARGET)); + + cur->data = t; + + /* protocol family independent init */ + t->seq = 0; + t->downseq = 0; + t->downseqreported = 0; + t->last_send_time.tv_sec = 0; + t->last_send_time.tv_usec = 0; + t->num_sent = 0; + t->timeout_max = 0; + t->consecutive_missing_max = 0; + t->used = 0; + + memset(t->cmsgbuf, 0, sizeof(t->cmsgbuf)); + t->cmsglen = 0; + + t->id = num_hosts; + + /* get initial connection state assumption from config */ + t->status = cur->status; + + t->sock = -1; + + if(cur->dstinfo->ai_family == AF_INET6) { + /* ipv6 init */ + if(cur->srcinfo) { + if(inet_pton(AF_INET6, cur->sourceip, &t->src6) != 1) { + syslog(LOG_ERR, "%s: %s: src6 inet_pton failed for %s", __FILE__, __FUNCTION__, cur->name); + } + + t->src_addr6.sin6_family = cur->srcinfo->ai_family; + if(inet_pton(AF_INET6, cur->sourceip, &t->src_addr6.sin6_addr) != 1) { + syslog(LOG_ERR, "%s: %s: src6 inet_pton failed for %s", __FILE__, __FUNCTION__, cur->name); + } + } + + if(inet_pton(AF_INET6, cur->checkip, &t->dst6) != 1) { + syslog(LOG_ERR, "%s: %s: dst6 inet_pton failed for %s", __FILE__, __FUNCTION__, cur->name); + } + + t->dst_addr6.sin6_family = cur->dstinfo->ai_family; + if(inet_pton(AF_INET6, cur->checkip, &t->dst_addr6.sin6_addr) != 1) { + syslog(LOG_ERR, "%s: %s: dst6 inet_pton failed for %s", __FILE__, __FUNCTION__, cur->name); + } + } else { + /* ipv4 init */ + ipaddress = inet_addr(cur->checkip); + t->dst_addr.sin_family = AF_INET; + t->dst_addr.sin_addr = *((struct in_addr *)&ipaddress); + t->dst = *((struct in_addr *)&ipaddress); + if(cur->srcinfo) { + if(inet_pton(AF_INET, cur->sourceip, &t->src) != 1) { + syslog(LOG_ERR, "%s: %s: src inet_pton failed for %s", __FILE__, __FUNCTION__, cur->name); + } + } + } + } + + if(((*ctable) = (CONFIG **)malloc(sizeof(CONFIG *) * num_hosts)) == NULL) { + syslog(LOG_ERR, "main: can't malloc for ctable"); + exit(1); + } + + /* create pointer table */ + for(cur = first, i = 0; cur; cur = cur->next, i++) { + (*ctable)[i] = cur; + } + +} + +static int open_arp_sock(CONFIG *cur) +{ + int ifindex = 0; + TARGET *t = (TARGET *)cur->data; + + if(t->sock != -1) return(0); + + if(cur->dstinfo->ai_family == AF_INET6) { + syslog(LOG_ERR, "%s: %s: protocol family is ipv6?", __FILE__, __FUNCTION__); + return(1); + } + + t->sock = socket(PF_PACKET, SOCK_DGRAM, 0); + if(t->sock < 0) { + syslog(LOG_ERR, "could not open socket for %s arp ping \"%s\"", cur->name, strerror(errno)); + t->sock = -1; + return(1); + } + if(fcntl(t->sock, F_SETFD, FD_CLOEXEC) == -1) { + syslog(LOG_ERR, "failed to set close on exec on socket %s reason \"%s\"", cur->name, strerror(errno)); + } + + if(cur->device && *cur->device) { + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, cur->device, IFNAMSIZ-1); + if(ioctl(t->sock, SIOCGIFINDEX, &ifr) < 0) { + syslog(LOG_ERR, "unknown iface \"%s\"", cur->device); + close(t->sock); + t->sock = -1; + return(2); + } + ifindex = ifr.ifr_ifindex; + + if(ioctl(t->sock, SIOCGIFFLAGS, (char*)&ifr)) { + syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) \"%s\"", strerror(errno)); + close(t->sock); + t->sock = -1; + return(2); + } + if(!(ifr.ifr_flags&IFF_UP)) { + syslog(LOG_ERR, "Interface \"%s\" is down", cur->device); + close(t->sock); + t->sock = -1; + return(2); + } + if(ifr.ifr_flags&(IFF_NOARP|IFF_LOOPBACK)) { + syslog(LOG_ERR, "Interface \"%s\" is not ARPable", cur->device); + close(t->sock); + t->sock = -1; + return(2); + } + } + + if(inet_aton(cur->checkip, &t->dst) != 1) { + struct hostent *hp; + hp = gethostbyname2(cur->checkip, AF_INET); + if(!hp) { + syslog(LOG_ERR, "unknown host %s\n", cur->checkip); + close(t->sock); + t->sock = -1; + return(2); + } + memcpy(&t->dst, hp->h_addr, 4); + } + + if(cur->sourceip && *cur->sourceip) + if(inet_aton(cur->sourceip, &t->src) != 1) { + syslog(LOG_ERR, "invalid source %s\n", cur->sourceip); + close(t->sock); + t->sock = -1; + return(2); + } + + if(probe_src_ip_addr(cur) != 0) { + close(t->sock); + t->sock = -1; + return(2); + } + + t->me.sll_family = AF_PACKET; + t->me.sll_ifindex = ifindex; + t->me.sll_protocol = htons(ETH_P_ARP); + if(bind(t->sock, (struct sockaddr*)&t->me, sizeof(t->me)) == -1) { + syslog(LOG_ERR, "bind \"%s\"", strerror(errno)); + close(t->sock); + t->sock = -1; + return(2); + } + + { + int alen = sizeof(t->me); + if(getsockname(t->sock, (struct sockaddr*)&t->me, (socklen_t*)&alen) == -1) { + syslog(LOG_ERR, "getsockname \"%s\"", strerror(errno)); + close(t->sock); + t->sock = -1; + return(2); + } + } + if(t->me.sll_halen == 0) { + syslog(LOG_ERR, "Interface \"%s\" is not ARPable (no ll address)", cur->device); + close(t->sock); + t->sock = -1; + return(2); + } + + t->he = t->me; + memset(t->he.sll_addr, -1, min(t->he.sll_halen, sizeof t->he.sll_addr)); + +#if 0 + printf("ARPING %s ", inet_ntoa(t->dst)); + printf("from %s %s\n", inet_ntoa(t->src), cur->device ? : ""); +#endif + + if(!t->src.s_addr) { + syslog(LOG_ERR, "no source address for %s", cur->name); + close(t->sock); + t->sock = -1; + return(2); + } + if(cur->ttl) { + int ittl = cur->ttl; + if(setsockopt(t->sock, IPPROTO_IP, IP_MULTICAST_TTL, + &cur->ttl, 1) == -1) { + syslog(LOG_ERR, "can't set multicast time-to-live \"%s\"", strerror(errno)); + close(t->sock); + t->sock = -1; + return(2); + } + if(setsockopt(t->sock, IPPROTO_IP, IP_TTL, + &ittl, sizeof(ittl)) == -1) { + syslog(LOG_ERR, "can't set unicast time-to-live \"%s\"", strerror(errno)); + close(t->sock); + t->sock = -1; + return(2); + } + } + + return(0); +} + +static int open_icmp_sock(CONFIG *cur) +{ + TARGET *t = (TARGET *)cur->data; + struct protoent *proto; + int pf = cur->dstinfo->ai_family; + + if(t->sock != -1) return(0); + + if(pf == AF_INET6) { + if((proto = getprotobyname("ipv6-icmp")) == NULL) { + syslog(LOG_ERR, "no ipv6-icmp proto found"); + return(1); + } + } else { + if((proto = getprotobyname("icmp")) == NULL) { + syslog(LOG_ERR, "no icmp proto found"); + return(1); + } + } + + t->sock = socket(pf, SOCK_RAW, proto->p_proto); + + if(t->sock < 0) { + syslog(LOG_ERR, "could not open socket for ping target \"%s\" reason \"%s\"\n", cur->name, strerror(errno)); + t->sock = -1; + return(1); + } + if(fcntl(t->sock, F_SETFD, FD_CLOEXEC) == -1) { + syslog(LOG_ERR, "failed to set close on exec on socket %s reason \"%s\"", cur->name, strerror(errno)); + } + + if(pf == AF_INET6) { + int opton = 1; + +#ifdef IPV6_RECVHOPOPTS + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(IPV6_RECVHOPOPTS)"); + close(t->sock); + t->sock = -1; + return(2); + } +#else /* old adv. API */ + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_HOPOPTS, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(IPV6_HOPOPTS)"); + close(t->sock); + t->sock = -1; + return(s); + } +#endif +#ifdef IPV6_RECVDSTOPTS + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(IPV6_RECVDSTOPTS)"); + close(t->sock); + t->sock = -1; + return(2); + } +#else /* old adv. API */ + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_DSTOPTS, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(IPV6_DSTOPTS)"); + close(t->sock); + t->sock = -1; + return(2); + } +#endif +#ifdef IPV6_RECVRTHDRDSTOPTS + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(IPV6_RECVRTHDRDSTOPTS)"); + close(t->sock); + t->sock = -1; + return(2); + } +#endif +#ifdef IPV6_RECVRTHDR + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(IPV6_RECVRTHDR)"); + close(t->sock); + t->sock = -1; + return(2); + } +#else /* old adv. API */ + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RTHDR, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(IPV6_RTHDR)"); + close(t->sock); + t->sock = -1; + return(2); + } +#endif +#ifndef USE_SIN6_SCOPE_ID +#ifdef IPV6_RECVPKTINFO + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(IPV6_RECVPKTINFO)"); + close(t->sock); + t->sock = -1; + return(2); + } +#else /* old adv. API */ + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_PKTINFO, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(IPV6_PKTINFO)"); + close(t->sock); + t->sock = -1; + return(2); + } +#endif +#endif /* USE_SIN6_SCOPE_ID */ +#ifdef IPV6_RECVHOPLIMIT + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(IPV6_RECVHOPLIMIT)"); + close(t->sock); + t->sock = -1; + return(2); + } +#else /* old adv. API */ + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(IPV6_HOPLIMIT)"); + close(t->sock); + t->sock = -1; + return(2); + } +#endif +#ifdef IPV6_CHECKSUM +#ifndef SOL_RAW +#define SOL_RAW IPPROTO_IPV6 +#endif + opton = 2; + + if(setsockopt(t->sock, SOL_RAW, IPV6_CHECKSUM, &opton, + sizeof(opton))) { + syslog(LOG_ERR, "setsockopt(SOL_RAW,IPV6_CHECKSUM)"); + close(t->sock); + t->sock = -1; + return(2); + } +#endif + } + + if(pf == AF_INET6) { + int hold = 1; + + ICMP6_FILTER_SETBLOCKALL(&t->filter); + + if (setsockopt(t->sock, SOL_IPV6, IPV6_RECVERR, (char *)&hold, sizeof(hold))) { + syslog(LOG_INFO, "WARNING: your kernel is veeery old. No problems."); + + ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &t->filter); + ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &t->filter); + ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &t->filter); + ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &t->filter); + } + + ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &t->filter); + + if(setsockopt(t->sock, IPPROTO_ICMPV6, ICMP6_FILTER, &t->filter, sizeof(struct icmp6_filter)) < 0) { + syslog(LOG_ERR, "setsockopt(ICMP6_FILTER)"); + return(2); + } + } + + if(cur->ttl) { + if(pf == AF_INET6) { + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &cur->ttl, sizeof(cur->ttl)) == -1) { + syslog(LOG_ERR, "can't set multicast hop limit \"%s\"", strerror(errno)); + close(t->sock); + t->sock = -1; + return(2); + } + if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, + &cur->ttl, sizeof(cur->ttl)) == -1) { + syslog(LOG_ERR, "can't set unicast hop limit \"%s\"", strerror(errno)); + close(t->sock); + t->sock = -1; + return(2); + } + } else if(pf == AF_INET) { /* AF_INET */ + int ittl = cur->ttl; + if(setsockopt(t->sock, IPPROTO_IP, IP_MULTICAST_TTL, + &cur->ttl, 1) == -1) { + syslog(LOG_ERR, "can't set multicast time-to-live \"%s\"", strerror(errno)); + close(t->sock); + t->sock = -1; + return(2); + } + if(setsockopt(t->sock, IPPROTO_IP, IP_TTL, + &ittl, sizeof(ittl)) == -1) { + syslog(LOG_ERR, "can't set unicast time-to-live \"%s\"", strerror(errno)); + close(t->sock); + t->sock = -1; + return(2); + } + } + } + + if(pf == AF_INET && cur->device && *cur->device) { + if(setsockopt(t->sock, SOL_SOCKET, SO_BINDTODEVICE, cur->device, strlen(cur->device) + 1) == -1) { + syslog(LOG_INFO, "failed to bind to ping interface device \"%s\", \"%s\"", cur->device, strerror(errno)); + close(t->sock); + t->sock = -1; + return(2); + } + } + +#if defined(DEBUG) + if(cfg.debug >= 9) syslog(LOG_INFO, "%s: %s: probing for src ip for %s", __FILE__, __FUNCTION__, cur->name); +#endif + if(probe_src_ip_addr(cur) != 0) { + close(t->sock); + t->sock = -1; + return(2); + } +#if defined(DEBUG) + if(cfg.debug >= 9) syslog(LOG_INFO, "%s: %s: probing for src ip for %s done", __FILE__, __FUNCTION__, cur->name); +#endif + if(cur->sourceip && *cur->sourceip) { + if(cur->srcinfo->ai_family == AF_INET) { + struct sockaddr_in addr; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(cur->sourceip); + + if(bind(t->sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) { + syslog(LOG_ERR, "ping can't bind \"%s\"", strerror(errno)); + return(1); + } + } else { + struct sockaddr_in6 addr; +#if defined(DEBUG) + if(cfg.debug >= 9) syslog(LOG_INFO, "%s: %s: setting v6 src addr", __FILE__, __FUNCTION__); +#endif + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + if(inet_pton(AF_INET6, cur->sourceip, &addr.sin6_addr) != 1) { + syslog(LOG_ERR, "ping6 failed to convert connection %s address %s", cur->name, cur->sourceip); + return(1); + } + if(bind(t->sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) { + syslog(LOG_ERR, "ping6 can't bind %s to %s, \"%s\"", cur->name, cur->sourceip, strerror(errno)); + return(1); + } +#if defined(DEBUG) + if(cfg.debug >= 9) syslog(LOG_INFO, "%s: %s: setting v6 src addr done", __FILE__, __FUNCTION__); +#endif + } + } + + if(pf == AF_INET6 && cur->device && *cur->device) { + struct ifreq ifr; + struct cmsghdr *cmsg; + struct in6_pktinfo *ipi; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, cur->device, IFNAMSIZ-1); + if(ioctl(t->sock, SIOCGIFINDEX, &ifr) < 0) { + syslog(LOG_ERR, "ping6 unknown iface %s", cur->device); + return(2); + } + + memset(&t->cmsgbuf, 0, sizeof(t->cmsgbuf)); + t->cmsglen = 0; + + cmsg = (struct cmsghdr *)t->cmsgbuf; + t->cmsglen += CMSG_SPACE(sizeof(*ipi)); + cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi)); + cmsg->cmsg_level = SOL_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + + ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg); + memset(ipi, 0, sizeof(*ipi)); + ipi->ipi6_ifindex = ifr.ifr_ifindex; + } + + return(0); +} + +static int probe_src_ip_addr(CONFIG *cur) +{ /* probe for src ip address */ + TARGET *t = (TARGET *)cur->data; + int probe_fd; + int pf = cur->dstinfo->ai_family; + + probe_fd = socket(pf, SOCK_DGRAM, 0); + + if(probe_fd < 0) { + syslog(LOG_ERR, "ping probe socket for %s failed \"%s\"", cur->name, strerror(errno)); + return(2); + } + if(fcntl(t->sock, F_SETFD, FD_CLOEXEC) == -1) { + syslog(LOG_ERR, "ping probe failed to set close on exec on probe socket for %s reason \"%s\"", cur->name, strerror(errno)); + } + + if(cur->device && *cur->device) { + if(setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, cur->device, strlen(cur->device) + 1) == -1) + syslog(LOG_INFO, "WARNING: ping probe interface \"%s\" is ignored for %s reason \"%s\"", cur->device, cur->name, strerror(errno)); + } + + if(pf == AF_INET) { + struct sockaddr_in saddr; + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + if(t->src.s_addr) { + saddr.sin_addr = t->src; + if(bind(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) { + syslog(LOG_ERR, "ping probe bind failed for %s \"%s\"", cur->name, strerror(errno)); + close(probe_fd); + /* earlier probed src addr is not usable, wipe it */ + memset(&t->src, 0, sizeof(t->src)); + return(2); + } + } + else { + int on = 1; + int alen = sizeof(saddr); + + saddr.sin_port = htons(1025); + saddr.sin_addr = t->dst; + + if(setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, (char*)&on, sizeof(on)) == -1) + syslog(LOG_INFO, "WARNING: ping probe setsockopt(SO_DONTROUTE) \"%s\"", strerror(errno)); + if(connect(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) { + syslog(LOG_ERR, "ping probe connect for %s failed \"%s\"", cur->name, strerror(errno)); + close(probe_fd); + return(2); + } + if(getsockname(probe_fd, (struct sockaddr*)&saddr, (socklen_t*)&alen) == -1) { + syslog(LOG_ERR, "ping probe getsockname for %s failed \"%s\"", cur->name, strerror(errno)); + close(probe_fd); + return(2); + } + t->src = saddr.sin_addr; + } + } else if (pf == AF_INET6) { /* not AF_INET */ + struct sockaddr_in6 saddr; + unsigned char nulladdr[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + memset(&saddr, 0, sizeof(saddr)); + saddr.sin6_family = AF_INET6; + if(memcmp(&t->src6, nulladdr, sizeof(t->src6)) != 0) { /* is not null addr */ + memcpy(&saddr.sin6_addr, &t->src6, sizeof(t->src6)); + if(bind(probe_fd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { + syslog(LOG_ERR, "ping6 probe bind failed for %s \"%s\"", cur->name,strerror(errno)); + close(probe_fd); + /* earlier probed src addr is not usable, wipe it */ + memset(&t->src6, 0, sizeof(t->src6)); + return(2); + } + } else { /* is null addr */ + socklen_t alen = sizeof(saddr); + + saddr.sin6_port = htons(1025); + saddr.sin6_family = cur->dstinfo->ai_family; + memcpy(&saddr.sin6_addr, &t->dst6, sizeof(t->dst6)); +#if 0 + if(setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)) == -1) + syslog(LOG_INFO, "WARNING: ping6 probe setsockopt(SO_DONTROUTE) for %s \"%s\"", cur->name, strerror(errno)); +#endif + if(connect(probe_fd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { + syslog(LOG_ERR, "ping6 probe connect for %s failed \"%s\"", cur->name, strerror(errno)); + close(probe_fd); + return(2); + } + if(getsockname(probe_fd, (struct sockaddr *)&saddr, &alen) == -1) { + syslog(LOG_ERR, "ping6 probe getsockname for %s failed \"%s\"", cur->name, strerror(errno)); + close(probe_fd); + return(2); + } + memcpy(&t->src6, &saddr.sin6_addr, sizeof(saddr.sin6_addr)); + } + } /* if AF_INET */ + + close(probe_fd); + + return(0); +} + +#if defined(DEBUG) +static void dump_pkt(const void *buf, size_t len) +{ + int i; + unsigned char *s; + char obuf[BUFSIZ]; + char *pad; + + memset(obuf, 0, BUFSIZ); + + s = (unsigned char *)buf; + pad = ""; + for(i = 0; i < len && i < BUFSIZ; i++) { + snprintf(obuf + strlen(obuf), BUFSIZ, "%s%02x", pad, s[i]); + pad = " "; + } + + syslog(LOG_INFO, "%s: %s: hexdump %s", __FILE__, __FUNCTION__, obuf); + + memset(obuf, 0, BUFSIZ); + + s = (unsigned char *)buf; + pad = ""; + for(i = 0; i < len && i < BUFSIZ; i++) { + snprintf(obuf + strlen(obuf), BUFSIZ, "%s%03d", pad, s[i]); + pad = " "; + } + + syslog(LOG_INFO, "%s: %s: decdump %s", __FILE__, __FUNCTION__, obuf); +} +#endif + +/* EOF */ diff --git a/foolsm.conf b/foolsm.conf new file mode 100644 index 0000000..0bf5ab6 --- /dev/null +++ b/foolsm.conf @@ -0,0 +1,54 @@ +# +# Copyright (C) 2009-2015 Mika Ilmaranta +# +# License: GPLv2 +# + +# +# Debug level: 0 .. 8 are normal, 9 gives lots of stuff and 100 doesn't +# bother to detach +# +#debug=10 +#debug=9 +#debug=8 + +# +# Defaults for the connection entries +# These are set in the code. You may override any values here. +# +#defaults { +# name=defaults +# checkip=127.0.0.1 +# eventscript= +# notifyscript=/usr/libexec/foolsm/default_script +# max_packet_loss=15 +# max_successive_pkts_lost=7 +# min_packet_loss=5 +# min_successive_pkts_rcvd=10 +# interval_ms=1000 +# timeout_ms=1000 +# warn_email=root +# check_arp=0 +# sourceip= +# if using ping probes for monitoring only then defaults should +# not define a default device for packets to autodiscover their path +# to destination +# device=eth0 +# use system default ttl +# ttl=0 +# assume initial up state at foolsm startup +# (1 = up, 0 = down, 2 = unknown (default)) +# status=1 +# how many packets have to go through before a connection is declared up +# (0 = disabled) +# startup_acceleration=0 +# send first 10 packets in a burst (0 = disabled) with interval 200ms +# startup_burst_pkts=10 +# startup_burst_interval=200 +#} + +# +# Some example connections are found in foolsm.conf.sample +# + +-include /etc/foolsm/local*.conf diff --git a/foolsm.conf.sample b/foolsm.conf.sample new file mode 100644 index 0000000..0d071f6 --- /dev/null +++ b/foolsm.conf.sample @@ -0,0 +1,142 @@ +# +# (C) 2009 Mika Ilmaranta +# +# License: GPLv2 +# + +# +# Debug level: 0 .. 8 are normal, 9 gives lots of stuff and 100 doesn't +# bother to detach +# +#debug=10 +#debug=9 +debug=8 + +# +# Defaults for the connection entries +# +defaults { + name=defaults + checkip=127.0.0.1 + eventscript=/usr/libexec/foolsm/default_script + max_packet_loss=15 + max_successive_pkts_lost=7 + min_packet_loss=5 + min_successive_pkts_rcvd=10 + interval_ms=1000 + timeout_ms=1000 + warn_email=root + check_arp=0 + sourceip= +# if using ping probes for monitoring only then defaults should +# not define a default device for packets to autodiscover their path +# to destination +# device=eth0 +# use system default ttl + ttl=0 +# assume initial up state at foolsm startup (1 = up, 0 = down, 2 = unknown (default)) +# status=1 +} + +# +# Some example connections +# NOTE: don't use any white space in name ... +# +# connection { +# name=connection-1 +# checkip=127.108.68.69 +# eventscript=/usr/libexec/foolsm/conn1 +# max_packet_loss=15 +# max_successive_pkts_lost=7 +# min_packet_loss=5 +# min_successive_pkts_rcvd=10 +# interval_ms=1000 +# timeout_ms=1000 +# warn_email=root1@some.tld +# check_arp=0 +# sourceip= +# device= +# ttl=64 +# } + +# connection { +# name=connection-2 +# checkip=127.108.68.65 +# eventscript=/usr/libexec/foolsm/conn2 +# max_packet_loss=15 +# max_successive_pkts_lost=7 +# min_packet_loss=5 +# min_successive_pkts_rcvd=10 +# interval_ms=1000 +# timeout_ms=1000 +# warn_email=root2@some.tld +# check_arp=0 +# sourceip= +# device= +# ttl=64 +# } + +# connection { +# name=connection-3 +# checkip=127.108.68.68 +# eventscript=/usr/libexec/foolsm/conn3 +# max_packet_loss=15 +# max_successive_pkts_lost=7 +# min_packet_loss=5 +# min_successive_pkts_rcvd=10 +# interval_ms=1000 +# timeout_ms=1000 +# warn_email=root3@some.tld +# check_arp=0 +# sourceip= +# device= +# ttl=64 +# } + +# connection { +# name=connection-4 +# checkip=127.108.68.75 +# } + +# +# Arping example +# +# connection { +# name=connection-5 +# checkip=127.108.68.71 +# check_arp=1 +# # if the remote end is not behind the defaults device +# # then you have to set this +# device=eth0 +# # setting source ip is not mandatory +# sourceip=127.108.68.68 +# # use system default ttl +# ttl=0 +# } + +# +# Group example +# +# connection { +# name=conn-a +# checkip=127.108.68.99 +# eventscript= +# } +# +# connection { +# name=conn-b +# checkip=127.108.68.100 +# eventscript= +# } +# +# group { +# name=conn-group-a +# eventscript=/usr/libexec/lsm/default_script +# warn_email=root@some.domain.tld +# # logic between member connetion statuses +# # logic=0 == or +# # logic=1 == and +# logic=0 +# member-connection=conn-a +# member-connection=conn-b +# } diff --git a/foolsm.h b/foolsm.h new file mode 100644 index 0000000..4a50ad9 --- /dev/null +++ b/foolsm.h @@ -0,0 +1,72 @@ +/* + +(C) 2013 Mika Ilmaranta + +License: GPLv2 + +*/ + +#ifndef __FOOLSM_H__ +#define __FOOLSM_H__ + +#include /* for struct sockaddr_in */ +#include /* for struct sockadd_ll */ +#include /* for struct icmp6_filter */ + +#include "defs.h" + +typedef struct sentpkt { + unsigned short seq; + struct timeval sent_time; + struct timeval replied_time; + unsigned long rtt; + struct { + unsigned replied:1; + unsigned timeout:1; + unsigned waiting:1; + unsigned used:1; + unsigned error:1; + } flags; +} SENTPKT; + +typedef struct target { + unsigned short id; /* target id */ + unsigned short seq; + unsigned short downseq; + unsigned short downseqreported; + struct timeval down_timestamp; + struct sockaddr_in src_addr; + struct sockaddr_in dst_addr; + struct sockaddr_in6 src_addr6; + struct sockaddr_in6 dst_addr6; + struct sockaddr_ll me; /* arping only */ + struct sockaddr_ll he; /* arping only */ + struct in_addr src; + struct in_addr dst; + struct in6_addr src6; + struct in6_addr dst6; + unsigned long num_sent; + struct timeval last_send_time; + STATUS status; + int sock; + unsigned char cmsgbuf[4096]; + int cmsglen; + struct icmp6_filter filter; + SENTPKT sentpkts[FOLLOWED_PKTS]; + int timeout; + int timeout_max; + int replied; + int waiting; + int reply_late; + int used; + int consecutive_waiting; + int consecutive_missing; + int consecutive_missing_max; + int consecutive_rcvd; + long avg_rtt; + int status_change; +} TARGET; + +#endif + +/* EOF */ diff --git a/foolsm.init b/foolsm.init new file mode 100644 index 0000000..e9e12ea --- /dev/null +++ b/foolsm.init @@ -0,0 +1,97 @@ +#!/bin/sh +# +# /etc/init.d/foolsm +# +# This shellscript takes care of starting and stopping foolsm. +# +# chkconfig: - 79 31 +# description: Foolsm, Link Status Monitor +# +### BEGIN INIT INFO +# Provides: foolsm +# Required-Start: $network $syslog +# Required-Stop: +# Default-Stop: 0 1 6 +# Short-Description: Foolsm - link status monitor +# Description: Foolsm is the link status monitor +# Foolsm can ping multiple targets and when up or down event happens +# it will execute user configured external script so it can be used +# as poor man's routing protocol. +### END INIT INFO + +# Source function library. +. /etc/init.d/functions + +# Source networking configuration. +. /etc/sysconfig/network + +# Check that networking is up. +[ ${NETWORKING} = "no" ] && exit 0 + +CONFIGFILE="/etc/foolsm/foolsm.conf" +PIDFILE="/var/run/foolsm.pid" + +[ -f /etc/sysconfig/foolsm ] && . /etc/sysconfig/foolsm +[ -x /usr/sbin/foolsm ] || exit 0 + +RETVAL=0 + +start() { + echo -n $"Starting foolsm: " + daemon --pidfile=${PIDFILE} /usr/sbin/foolsm --config $CONFIGFILE --pidfile $PIDFILE + RETVAL=$? + /bin/usleep 10000 + echo + [ $RETVAL = 0 ] && touch /var/lock/subsys/foolsm + return $RETVAL +} + +stop() { + echo -n $"Stopping foolsm: " + killproc /usr/sbin/foolsm + RETVAL=$? + echo + [ $RETVAL = 0 ] && rm -f /var/lock/subsys/foolsm + return $RETVAL +} + +restart() { + stop + start +} + +reload() { + echo -n $"Reloading foolsm: " + killproc -p ${PIDFILE} /usr/sbin/foolsm -HUP + RETVAL=$? + echo + return $RETVAL +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + restart + ;; + reload) + reload + ;; + condrestart) + [ -f /var/lock/subsys/foolsm ] && restart + ;; + status) + status -p ${PIDFILE} foolsm + RETVAL=$? + ;; + *) + echo "Usage: foolsm {start|stop|restart|condrestart|status}" + RETVAL=2 +esac + +exit $RETVAL diff --git a/foolsm.service b/foolsm.service new file mode 100644 index 0000000..7c74717 --- /dev/null +++ b/foolsm.service @@ -0,0 +1,14 @@ +[Unit] +Description=Foolsm is the link status monitor +Documentation=http://lsm.foobar.fi/ +Wants=network-online.target +After=network-online.target shorewall.service shorewall6.service + +[Service] +Type=simple +ExecStart=/usr/sbin/foolsm --config /etc/foolsm/foolsm.conf --no-fork +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-abort + +[Install] +WantedBy=multi-user.target diff --git a/foolsm.spec b/foolsm.spec new file mode 100644 index 0000000..4e82bd7 --- /dev/null +++ b/foolsm.spec @@ -0,0 +1,951 @@ +#define devel 1 +%if 0%{?rhel} >= 7 || 0%{?fedora} +%bcond_without systemd # enabled +%else +%bcond_with systemd # disabled +%endif + +Summary: The Foobar Link Status Monitor +Name: foolsm +Version: 1.0.8 +Release: 1%{?dist} +License: GPLv2 +URL: http://lsm.foobar.fi/ +Source0: %{name}-%{version}.tar.gz +%if %{with systemd} +Requires(post): systemd-units +Requires(preun): systemd-units +Requires(postun): systemd-units +BuildRequires: systemd +%else +Requires(post): chkconfig +Requires(postun): /sbin/service +Requires(preun): /sbin/service +Requires(preun): chkconfig +%endif +Requires: mailx +%if 0%{?devel} +BuildRequires: ElectricFence +%endif +%if 0%{?rhel} && 0%{?rhel} <= 5 +Group: System Environment/Daemons +%global _sharedstatedir /var/lib +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +%endif +Obsoletes: lsm < 1.0.7-1 +Conflicts: lsm < 1.0.7-1 +Provides: lsm = %{version}-%{release} + +%description +Foolsm is the Foobar Link Status Monitor. + +Foolsm can ping multiple targets and when up or down event happens +it will execute user configured external script so it can be used +as poor man's routing protocol. + +%prep +%setup -q + +%build +EFENCE= +%if 0%{?devel} +# Disable -O2 temporarily +RPM_OPT_FLAGS="$(echo "%{optflags}" | sed 's/-O.\ / /')" +EFENCE="-lefence" +%endif +make PREFIX=%{_prefix} CFLAGS="$RPM_OPT_FLAGS" LDFLAGS=${EFENCE} %{?_smp_mflags} + +%install +rm -rf %{buildroot} + +mkdir -p %{buildroot}%{_sysconfdir}/foolsm +mkdir -p %{buildroot}%{_sbindir} +mkdir -p %{buildroot}%{_libexecdir}/foolsm +mkdir -p %{buildroot}%{_sharedstatedir}/foolsm + +install -m0755 foolsm %{buildroot}%{_sbindir} +install -m0644 foolsm.conf %{buildroot}%{_sysconfdir}/foolsm +install -m0755 default_script group_script shorewall_script shorewall6_script \ + %{buildroot}%{_libexecdir}/foolsm/ + +%if %{with systemd} +mkdir -p %{buildroot}%{_unitdir} +install -m0644 foolsm.service %{buildroot}%{_unitdir}/ +%else +mkdir -p %{buildroot}%{_initrddir} +install -m0755 foolsm.init %{buildroot}%{_initrddir}/foolsm +%endif + +%clean +rm -rf %{buildroot} + +%triggerun -- lsm < 1.0.7-1 +%if %{with systemd} +systemctl --quiet is-enabled lsm.service && \ + touch %{_localstatedir}/lock/subsys/lsm.enabled || : +systemctl --quiet is-active lsm.service && \ + touch %{_localstatedir}/lock/subsys/lsm.started || : +%else +/sbin/chkconfig lsm >/dev/null 2>&1 && \ + touch %{_localstatedir}/lock/subsys/lsm.enabled || : +/sbin/service lsm status >/dev/null 2>&1 && \ + touch %{_localstatedir}/lock/subsys/lsm.started || : +%endif +for config in %{_sysconfdir}/lsm/lsm.conf \ + %{_sysconfdir}/lsm/local*.conf \ + %{_sysconfdir}/lsm/*_script +do + [ -f ${config} ] && \ + cp -p ${config} %{_sysconfdir}/foolsm/ +done +if [ -f %{_sysconfdir}/foolsm/lsm.conf ]; then + mv -f %{_sysconfdir}/foolsm/foolsm.conf \ + %{_sysconfdir}/foolsm/foolsm.conf.rpmnew + echo "warning: %{_sysconfdir}/foolsm/foolsm.conf created as %{_sysconfdir}/foolsm/foolsm.conf.rpmnew" + mv -f %{_sysconfdir}/foolsm/lsm.conf %{_sysconfdir}/foolsm/foolsm.conf +fi +for config in %{_sysconfdir}/foolsm/*.conf; do + sed --in-place=.rpmsave \ + -e 's@/etc/lsm/@/etc/foolsm/@g' \ + -e 's@%{_datadir}/lsm/@%{_libexecdir}/foolsm/@g' \ + -e 's@%{_libexecdir}/lsm/@%{_libexecdir}/foolsm/@g' \ + ${config} >/dev/null 2>&1 || : +done + +%triggerpostun -- lsm < 1.0.7-1 +%if %{with systemd} +if [ -f %{_localstatedir}/lock/subsys/lsm.enabled ]; then + systemctl enable foolsm.service >/dev/null 2>&1 || : + rm -f %{_localstatedir}/lock/subsys/lsm.enabled +fi +if [ -f %{_localstatedir}/lock/subsys/lsm.started ]; then + systemctl start foolsm.service >/dev/null 2>&1 || : + rm -f %{_localstatedir}/lock/subsys/lsm.started +fi +%else +/sbin/chkconfig --add foolsm +if [ -f %{_localstatedir}/lock/subsys/lsm.enabled ]; then + /sbin/chkconfig foolsm on + rm -f %{_localstatedir}/lock/subsys/lsm.enabled +fi +if [ -f %{_localstatedir}/lock/subsys/lsm.started ]; then + /sbin/service foolsm restart >/dev/null 2>&1 + rm -f %{_localstatedir}/lock/subsys/lsm.started +fi +%endif + +%post +%if %{with systemd} +%systemd_post foolsm.service +%else +/sbin/chkconfig --add foolsm +%endif + +%preun +%if %{with systemd} +%systemd_preun foolsm.service +%else +if [ $1 -eq 0 ]; then + /sbin/service foolsm stop >/dev/null 2>&1 || : + /sbin/chkconfig --del foolsm +fi +%endif + +%postun +%if %{with systemd} +%systemd_postun_with_restart foolsm.service +%else +if [ $1 -ge 1 ]; then + /sbin/service foolsm condrestart >/dev/null 2>&1 || : +fi +%endif + + +%files +%defattr(-,root,root,-) +%doc README foolsm.conf.sample default_script.sample rsyslog-foolsm.conf.sample +%if %{with systemd} +%{_unitdir}/foolsm.service +%else +%{_initrddir}/foolsm +%endif +%dir %{_libexecdir}/foolsm +%{_libexecdir}/foolsm/default_script +%{_libexecdir}/foolsm/group_script +%{_libexecdir}/foolsm/shorewall_script +%{_libexecdir}/foolsm/shorewall6_script +%dir %{_sysconfdir}/foolsm +%config(noreplace) %{_sysconfdir}/foolsm/foolsm.conf +%{_sbindir}/foolsm +%dir %{_sharedstatedir}/foolsm + +%changelog +* Wed Sep 9 2016 Mika Ilmaranta - 1.0.8-1 +- foolsm.spec: triggers to move old lsm config for foolsm +- fix forever loop in waitpid while loop + +* Wed Sep 7 2016 Mika Ilmaranta - 1.0.7-1 +- project name changed to foolsm due to conflicting path(s) with + libstoragemgmt + +* Wed Sep 7 2016 Mika Ilmaranta - 1.0.6-1 +- patches from Andrew Timonin, better handling of waitpid, debug message + fixes and ipv4 srcinfo handling + +* Fri May 13 2016 Mika Ilmaranta - 1.0.5-1 +- patches from Lucas de Castro Borges for Debian +- exept for POSIX compliancy scriptdir PREFIX/libexec/lsm + +* Tue Jan 26 2016 Mika Ilmaranta - 1.0.4-1 +- For systemd start after shorewall otherwise shorewall_script + may be executed too early + +* Fri Dec 4 2015 Mika Ilmaranta - 1.0.3-1 +- recursive read_config reported errors many times + +* Fri Dec 4 2015 Mika Ilmaranta - 1.0.2-1 +- call init_config in reload_config + +* Fri Dec 4 2015 Mika Ilmaranta - 1.0.1-1 +- double free() fix? + +* Thu Nov 19 2015 Mika Ilmaranta - 1.0-1 +- script API change. pass empty strings to scripts without converting to + "-" or "NA". +- include and -include now support patterns + +* Tue Nov 17 2015 Mika Ilmaranta - 0.195-1 +- fix dynamic memory handling in sane values in code. + +* Mon Nov 16 2015 Mika Ilmaranta - 0.194-1 +- set sane values in code. overridable in config defaults section as + before. + +* Sat Oct 31 2015 Mika Ilmaranta - 0.193-1 +- use full path for -included file + +* Fri Oct 30 2015 Mika Ilmaranta - 0.192-1 +- default_script: run date after checks + +* Fri Oct 30 2015 Mika Ilmaranta - 0.191-1 +- support for -include aka ignore include errors if file is missing + +* Fri Oct 23 2015 Mika Ilmaranta - 0.190-1 +- fix groups_decide logic when group logic is 'or'. Thanks to + Filippo Carletti for noticing there was a problem. + +* Mon Jun 1 2015 Mika Ilmaranta - 0.189-1 +- update stats must not clear target used count + +* Mon Jun 1 2015 Mika Ilmaranta - 0.188-1 +- moved target used slots book keeping to send function + +* Mon Jun 1 2015 Mika Ilmaranta - 0.187-1 +- update stats after each ping round so that startup burst can use used slot + count + +* Mon Jun 1 2015 Mika Ilmaranta - 0.186-1 +- dump startup acceleration and startup burst config also +- startup acceleration logic fix + +* Mon Jun 1 2015 Mika Ilmaranta - 0.185-1 +- startup burst logic rewrite + +* Mon Jun 1 2015 Mika Ilmaranta - 0.184-1 +- two separate config params for startup burst + +* Sun May 31 2015 Mika Ilmaranta - 0.183-1 +- startup acceleration configurable +- startup burst configurable + +* Sun May 31 2015 Tuomo Soini - 0.182-1 +- add shorewall6_script and group_script +- install scripts to /usr/libexec/lsm +- add compatibility symlinks to /usr/share/lsm + +* Fri May 29 2015 Mika Ilmaranta - 0.181-1 +- accelerate decision at startup, must have received at least one packet + +* Fri May 29 2015 Mika Ilmaranta - 0.180-1 +- accelerate decision at startup + +* Tue Feb 3 2015 Mika Ilmaranta - 0.179-1 +- lsm.service use correct path for the binary + +* Wed Jan 14 2015 Mika Ilmaranta - 0.178-1 +- export status info to separate file +- cleaned up compilation with different sets of NO_PLUGIN_EXPORT defines + +* Mon Jan 12 2015 Mika Ilmaranta - 0.177-1 +- export connection statuses to plugin directory + +* Sun Jan 11 2015 Mika Ilmaranta - 0.176-1 +- log status with other attributes (Luigi Iotti) + +* Sat Sep 13 2014 Mika Ilmaranta - 0.175-1 +- if --no-fork don't write pid file + +* Sat Sep 13 2014 Mika Ilmaranta - 0.174-1 +- systemd support + +* Wed Aug 6 2014 Mika Ilmaranta - 0.173-1 +- fixed -v parameter + +* Wed Aug 6 2014 Mika Ilmaranta - 0.172-1 +- better usage help +- fixed bug in optarg use + +* Wed Aug 6 2014 Mika Ilmaranta - 0.171-1 +- split source for pidfile processing +- real cmdline argument processing with optarg +- support no-daemon cmdline option for integration with systemd +- debug level 100 no longer suppresses daemonization use the above + mentioned cmdline option instead + +* Sun Feb 16 2014 Mika Ilmaranta - 0.170-1 +- Makefile: debian frendlier install target + +* Sun Feb 16 2014 Mika Ilmaranta - 0.169-1 +- Makefile: install target, not guaranteed to work +- README: updated with INSTALL section + +* Fri Nov 22 2013 Mika Ilmaranta - 0.168-1 +- zero timeout_max and consecutive_missing_max in dump_statuses if there is + status_change to up state not in decide + +* Fri Nov 22 2013 Mika Ilmaranta - 0.167-1 +- update timeout_max and consecutive_missing_max regardless of state + +* Fri Nov 22 2013 Mika Ilmaranta - 0.166-1 +- added timeout_max + +* Fri Nov 22 2013 Mika Ilmaranta - 0.165-1 +- drop max_successive_waiting, it delivers no additional info +- renamed max_successive_missing to successive_missing_max + +* Fri Nov 22 2013 Mika Ilmaranta - 0.164-1 +- added max_successive_waiting and max_successive_missing +- cfg.debug controls now how much info is syslogged on dump_status + debug >= 6, log calculated connection status + debug >= 7, log connection probe statuses + +* Fri Aug 9 2013 Mika Ilmaranta - 0.163-1 +- don't suppress all up notifies when unknown_up_notify is off + +* Thu Jul 25 2013 Mika Ilmaranta - 0.162-1 +- option to skip executing notify script on unknown to up event for groups + also + +* Thu Jul 25 2013 Mika Ilmaranta - 0.161-1 +- added option to skip executing notify script on unknown to up event + +* Thu Jul 25 2013 Mika Ilmaranta - 0.160-1 +- moved save/restore statuses to their own file from lsm.c + +* Wed Jul 24 2013 Mika Ilmaranta - 0.159-1 +- updated shorewall_script with new parameters + +* Wed Jul 24 2013 Mika Ilmaranta - 0.158-1 +- clean up munin titles + +* Tue Jul 23 2013 Mika Ilmaranta - 0.157-1 +- use connection names in munin labels + +* Fri Jul 19 2013 Mika Ilmaranta - 0.156-1 +- plugin_export: changed strlower to munin_src_name + +* Thu Jul 18 2013 Mika Ilmaranta - 0.155-1 +- plugin_export: export statistics for munin + +* Wed Jul 17 2013 Mika Ilmaranta - 0.154-1 +- fixed divide error + +* Wed Jul 17 2013 Mika Ilamranta - 0.153-1 +- lsm.c: drop casts and keep avg_rtt in usec, divide by 1000.0 if needed as + float + +* Wed Jul 17 2013 Mika Ilmaranta - 0.152-1 +- lsm.c: cast avg_rtt for fork_exec + +* Wed Jul 17 2013 Mika Ilmaranta - 0.151-1 +- prepare for exporting statistics to zabbix and munin + +* Wed Jul 10 2013 Mika Ilmaranta - 0.150-1 +- lsm.c: change status to up directly from long_down + +* Tue Jul 9 2013 Mika Ilmaranta - 0.149-1 +- default_script: added missing closing curly bracket + +* Mon Jul 8 2013 Mika Ilmaranta - 0.148-1 +- pass event timestamp from lsm to scripts + +* Mon Jul 8 2013 Mika Ilmaranta - 0.147-1 +- pass empty warn_email addr to script as hyphen +- if script gets hyphen for email addr do not send mail + +* Thu Jul 4 2013 Mika Ilmaranta - 0.146-1 +- long_down_to down -> long_down_to_down + +* Thu Jul 4 2013 Mika Ilmaranta - 0.145-1 +- check also for nul-string email addr + +* Mon Jul 1 2013 Mika Ilmaranta - 0.144-1 +- use enum for status +- new config options for reporting only longer down time: +- long_down_time = how many seconds down time is considered long +- long_down_email = where to report long down time +- long_down_notifyscript = script to use when reporting long down time +- long_down_eventscript = script to use when reacting to long down time + +* Fri May 10 2013 Mika Ilmaranta - 0.143-1 +- discard probed src addr if bind fails + +* Thu Mar 28 2013 Mika Ilmaranta - 0.142-1 +- free exec_queue on exit + +* Thu Mar 28 2013 Mika Ilmaranta - 0.141-1 +- make exec_queue_dump activate with -DDEBUG +- rsyslog-lsm.conf.sample by Dimitar Angelov + +* Thu Mar 28 2013 Mika Ilmaranta - 0.140-1 +- debug with exec_queue_dump + +* Thu Mar 28 2013 Mika Ilmaranta - 0.139-1 +- forkexec.c: check that eq is set in exec_queue_process + +* Thu Mar 28 2013 Mika Ilmaranta - 0.138-1 +- config.c: defaults.queue NULL + +* Thu Mar 28 2013 Mika Ilmaranta - 0.137-1 +- exec queue, run event scripts sychronously + +* Thu Oct 11 2012 Mika Ilmaranta - 0.136-1 +- lsm.c: clean up debugging and add check that reply addr matches + original destination addr + +* Thu Oct 11 2012 Mika Ilmaranta - 0.135-1 +- lsm.c: more debugging when pdp->id is out of range + +* Thu Oct 11 2012 Mika Ilmaranta - 0.134-1 +- lsm.c: do bounds check on pdp->id before use as ctable index + +* Mon Aug 13 2012 Mika Ilmaranta - 0.133-1 +- lsm.c: rethought group up/down logic. (original was wrong up event on + transition to unknown state and 0.132 fix reported both up and down + events) + +* Mon Aug 13 2012 Mika Ilmaranta - 0.132-1 +- default_script: better english for timeout packets +- config.c: recognise status for group, use default start status for group +- lsm.c: report group prevstate textually + +* Sat May 12 2012 Mika Ilmaranta - 0.131-1 +- close socket on recvfrom fail + +* Tue May 8 2012 Mika Ilmaranta - 0.130-1 +- initialize cmsgbuf and cmsglen in open_icmp_sock as socket may be + closed and reopened + +* Sun May 6 2012 Mika Ilmaranta - 0.129-1 +- close socket also when sendmsg fails + +* Sun May 6 2012 Mika Ilmaranta - 0.128-1 +- cleanup debugging +- don't SO_BINDTODEVICE for AF_INET6 when device is specified as it uses + sendmsg instead of sendto + +* Sun May 6 2012 Mika Ilmaranta - 0.127-1 +- debug sendmsg a little + +* Sun May 6 2012 Mika Ilmaranta - 0.126-1 +- set v6 filter + +* Sun May 6 2012 Mika Ilmaranta - 0.125-1 +- handle v6 device setting like ping6 does + +* Sat May 5 2012 Mika Ilmaranta - 0.124-1 +- v6 sequence now correct? +- set v6 sockopts also if ttl is not set + +* Thu Apr 19 2012 Mika Ilmaranta - 0.123-1 +- removed unnesessary debugging +- v6 src ip addr autodiscovery works now + +* Thu Apr 19 2012 Mika Ilmaranta - 0.122-1 +- debug memcpy t->src6 results + +* Thu Apr 19 2012 Mika Ilmaranta - 0.121-1 +- check t->src6 contents + +* Thu Apr 19 2012 Mika Ilmaranta - 0.120-1 +- debug v6 getsockname unconditionally + +* Thu Apr 19 2012 Mika Ilmaranta - 0.119-1 +- debug getsockname for v6 conn + +* Thu Apr 19 2012 Mika Ilmaranta - 0.118-1 +- no SO_DONTROUTE for v6 probe + +* Fri Apr 13 2012 Mika Ilmaranta - 0.117-1 +- lsm.c: set more v6 socket options +- TODO: check why probe_src_ip_addr doesn't work for v6 + +* Sat Mar 10 2012 Mika Ilmaranta - 0.116-2 +- fix forkexec format str + +* Sat Mar 10 2012 Mika Ilmaranta - 0.116-1 +- report prevstate as string up/down/unknown + +* Wed Mar 7 2012 Tuomo Soini - 0.115-2 +- fix %%postun not to fail + +* Wed Dec 21 2011 Mika Ilmaranta - 0.115-1 +- forkexec.c: remove space after func name +- lsm.c: free_config_data: don't close t->sock if it is -1 + +* Wed Dec 21 2011 Mika Ilmaranta - 0.114-1 +- moved time calculation functions to their own files + +* Wed Dec 21 2011 Mika Ilmaranta - 0.113-1 +- decode all icmp and icmp6 types and codes + +* Tue Dec 20 2011 Mika Ilmaranta - 0.112-1 +- Andrew Beverley's signal child handler +- made static functions static + +* Tue Dec 20 2011 Mika Ilmaranta - 0.111-1 +- moved children handling from forkexec to main loop + +* Tue Dec 20 2011 Mika Ilmaranta - 0.110-1 +- lsm.c: use t->dst6 in v6 probe not cur->dstinfo + +* Tue Dec 20 2011 Mika Ilmaranta - 0.109-1 +- rebuild with efence + +* Tue Dec 20 2011 Mika Ilmaranta - 0.108-1 +- ipv6 support seems now stable enough + +* Tue Dec 20 2011 Mika Ilmaranta - 0.107-1 +- lsm.c: debug probe_src_ip_addr call + +* Tue Dec 20 2011 Mika Ilmaranta - 0.106-1 +- lsm.c: debug open_icmp_sock socket call removed +- lsm.c: debug setting v6 src addr + +* Tue Dec 20 2011 Mika Ilmaranta - 0.105-1 +- lsm.c: debug open_icmp_sock socket call + +* Tue Dec 20 2011 Mika Ilmaranta - 0.104-1 +- lsm.c: more sin6_family fixes + +* Tue Dec 20 2011 Mika Ilmaranta - 0.103-1 +- lsm.c: set sin6_family and show also v4 addr in debug + +* Tue Dec 20 2011 Mika Ilmaranta - 0.102-1 +- lsm.c: debug reply pkts more + +* Mon Dec 19 2011 Mika Ilmaranta - 0.101-1 +- lsm.c: fix inet_pton parameters + +* Mon Dec 19 2011 Mika Ilmaranta - 0.100-1 +- lsm.c: fail if device can not be bound to by Andrew Beverley +- lsm.c: bind also to ipv6 sourceip + +* Mon Dec 19 2011 Mika Ilmaranta - 0.99-1 +- lsm.c: fix ping6 sendto params + +* Mon Dec 19 2011 Mika Ilmaranta - 0.98-1 +- initial ipv6 support + +* Mon Dec 19 2011 Mika Ilmaranta - 0.97-1 +- include version information in directory name inside tar pkg + +* Mon Dec 19 2011 Mika Ilmaranta - 0.96-1 +- lsm.c: initialize last decision outside main loop. fixes decide call + interval. patch by Andrew Beverley +- config.c: debugging information added for unmatched config option by + Andrew Beverley. strcpy changed to memmove in strip leading space +- lsm.c: show correct usage +- config.c: clean up config file lines harder before parsing + +* Fri Dec 9 2011 Mika Ilmaranta - 0.95-1 +- shorewall_script: removed email notification, use it as eventscript and + default_script as notifyscript for example + +* Fri Dec 9 2011 Mika Ilmaranta - 0.94-1 +- added support for worker script (= eventscript) and notify script + (= notifyscript) differentiation, both are called with same parameters. + new script parameter previous state + +* Thu Dec 8 2011 Mika Ilmaranta - 0.93-1 +- for the following two patches thanks to Pablo Gomez +- lsm.c: use sourceip from config for icmp pkts if set +- lsm.c,config.c: new default state is unknown, which can be overridden in + config. this allows lsm to run event script "on startup" after connection + statuses are discovered. same rules apply as for actual events. + +* Thu Oct 20 2011 Mika Ilmaranta > - 0.92-1 +- report same seq status only once + +* Thu Oct 20 2011 Mika Ilmaranta - 0.91-1 +- dump conn status to syslog every maxseq when status is down only + if no status change + +* Thu Oct 20 2011 Mika Ilmaranta - 0.90-1 +- dump conn status to syslog every maxseq when status is down + +* Tue Sep 27 2011 Mika Ilmaranta - 0.89-1 +- added comment to shrewall_script about shorewall version requirement + +* Tue Sep 27 2011 Mika Ilmaranta - 0.88-1 +- added shorewall_script + +* Fri Jul 15 2011 Mika Ilmaranta - 0.87-1 +- production setting for compilation (no efence and use optimization) + +* Wed Jun 22 2011 Mika Ilmaranta - 0.86-1 +- protect FD_ISSET also from closed socket + +* Wed Jun 22 2011 Mika Ilmaranta - 0.85-1 +- compile with ElectricFence + +* Wed Jun 22 2011 Mika Ilmaranta - 0.84-1 +- revert to v0.64 base +- Makefile: merge v0.83 changeset +- lsm.spec: v0.83 spec +- config: removed reopen_on_enodev and added patch for double free +- lsm.c: removed reopen_on_enodev handling +- lsm.conf: removed reopen_on_enodev +- added cksum files +- lsm.c: use external cksum +- v0.83 forkexec, globals and signal_handler +- lsm.c: separate defs.h, merged fixes from v0.83 +- lsm.c: close socket on fail and reopen just before next ping +- spec: version and changelog + +* Wed Jun 22 2011 Mika Ilmaranta - 0.83-1 +- check that device names match + +* Wed Jun 22 2011 Mika Ilmaranta - 0.82-1 +- compile with ElectricFence depending on devel define + +* Wed Jun 22 2011 Mika Ilmaranta - 0.81-1 +- check arp header differently + +* Tue Jun 21 2011 Mika Ilmaranta - 0.80-1 +- further debugging of disappearing arp replies + +* Tue Jun 21 2011 Mika Ilmaranta - 0.79-1 +- try to find out where arp replies vanish + +* Tue Jun 21 2011 Mika Ilmaranta - 0.78-1 +- config.c: fix double free on warn_email and other group parameters + +* Tue Jun 21 2011 Mika Ilmaranta - 0.77-1 +- fix BuildRequires for -lefence + +* Tue Jun 21 2011 Mika Ilmaranta - 0.76-1 +- compile with -lefence + +* Tue Jun 21 2011 Mika Ilmaranta - 0.75-1 +- check packet from addr to determine which connection it + belongs to + +* Tue Jun 21 2011 Mika Ilmaranta - 0.74-1 +- moved rest of io functions to io.c +- io.c: split icmp and arp reply handling +- io.c: differentiate ping_rcv error logging on find_interface use + +* Tue Jun 21 2011 Mika Ilmaranta - 0.73-1 +- bind SIGUSR2 to signal_handler + +* Tue Jun 21 2011 Mika Ilmaranta - 0.72-1 +- dump interface list on SIGUSR2 + +* Mon Jun 20 2011 Mika Ilmaranta - 0.71-1 +- io.c: due to function splitting add missing gettimeofday call in icmp_send + +* Mon Jun 20 2011 Mika Ilmaranta - 0.70-1 +- timeval_diff_[lt,gt] fix diff_usec calculation + +* Mon Jun 20 2011 Mika Ilmaranta - 0.69-1 +- removed sock from target structure +- added interface handling to interface.c and made other parts use it + +* Fri Jun 17 2011 Mika Ilmaranta - 0.68-1 +- broke timeval_diff_cmp to two functions +- globals.c: check for unset prog +- lsm.c: removed handle_odd_icmp function as it did nothing +- interface.c: made probe for src ip address function probe_addresses + +* Fri Jun 17 2011 Mika Ilmaranta - 0.67-1 +- moved global variable handling to its own block +- moved decision functions to their own block +- moved signal_handler to its own block +- moved ping function to its own file +- lsm.c: reset reload_cfg after reloading config, not before +- Makefile: clean also ~ files starting with dot + +* Fri Jun 17 2011 Mika Ilmaranta - 0.66-1 +- moved structure definitions to lsm.h +- lsm.c: moved socket opening functionality to interface.c +- Makefile: use Makefile.depend +- .gitignore: ignore Makefile.depend, obj files and lsm binary + +* Wed Jun 15 2011 Mika Ilmaranta - 0.65-1 +- started rewrite +- moved forkexec function and defines to their own files +- added interface handling src files +- moved cksum function to its own file +- moved timeval functions to their own files + +* Fri Dec 31 2010 Mika Ilmaranta - 0.64-1 +- fill up target struct src address for ping also + do it at startup (should this be done every time we send ping packet?) + +* Fri Dec 31 2010 Mika Ilmaranta - 0.63-1 +- Added src ip to script parameters + src ip paramater is the last one so that every single old config + doesn't have to be rewritten. + +* Fri Dec 10 2010 Mika Ilmaranta - 0.62-1 +- check for valid ip-address in checkip parameter + +* Fri Dec 10 2010 Mika Ilmaranta - 0.61-1 +- changed lsm.c init_config to init_config_data +- added init_config to config.c which is then called before read_config +- added a warning when checkip is not set + +* Sat Oct 9 2010 Mika Ilmaranta - 0.60-1 +- fix recursive read_config use. set default values only once. +- use cfg.debug only after config is read +- added default_script.sample + +* Mon Sep 27 2010 Mika Ilmaranta - 0.59-1 +- remember connection statuses after config reload + +* Mon Sep 27 2010 Mika Ilmaranta - 0.58-1 +- reopen_on_enodev support. set this to 1 so lsm will try to reopen ping + device when it encounters ENODEV error when sending ping packet + +* Sun Sep 19 2010 Mika Ilmaranta - 0.57-1 +- added defaults status to give initial assumption of the connection status +- added config status for connections. is it assumed down = 0 or up = 1 + at lsm start + +* Sat Sep 18 2010 Mika Ilmaranta - 0.56-1 +- fixed rpmlint-v0.91 warnings. + +* Sat Apr 24 2010 Mika Ilmaranta - 0.53-1 +- added error checking to ftruncate and write so that mock build doesn't + complain +- introduced timeval_diff_cmp function as it seems quite problematic to + really compare times in usec since epoch using integer values. + especially 32bit systems were seeing 99% CPU loads because of this. + +* Thu Apr 22 2010 Mika Ilmaranta - 0.52-1 +- initialize all struct timeval structures to tv_sec = 0 and tv_usec = 0 +- added use of error flag to arping sending + +* Fri Mar 5 2010 Mika Ilmaranta - 0.51-1 +- fix avg rtt calculation comment +- show in the default mail template avg rtt unit [usec] +- in syslog avg rtt is reported in [msec] as of v0.50 like ping does + +* Fri Mar 5 2010 Mika Ilmaranta - 0.50-1 +- report rtt with three decimals accuracy + +* Thu Mar 4 2010 Mika Ilmaranta - 0.49-1 +- count average rtt in milliseconds not in microseconds + +* Thu Mar 4 2010 Mika Ilmaranta - 0.48-1 +- don't count timeouted late replies in cons rcvd + +* Thu Mar 4 2010 Mika Ilmaranta - 0.47-1 +- added some missing fields to lsm.init + +* Thu Mar 4 2010 Mika Ilmaranta - 0.46-1 +- dump all statuses only if requested by SIGUSR1 +- otherwise dump only connection status data of connection whose status changed + +* Wed Mar 3 2010 Mika Ilmaranta - 0.45-1 +- use LOG_PID openlog option + +* Thu Dec 17 2009 Mika Ilmaranta - 0.44-1 +- added some parameter sanity checking. if max_packet_loss <= min_packet_loss then there can be a flip-flop effect + and many many and still a few reports mailed to warn_email address. + +* Mon Nov 9 2009 Mika Ilmaranta - 0.43-1 +- convert all tabs to spaces before processing config line + +* Sun Sep 27 2009 Mika Ilmaranta - 0.42-1 +- changed action script to event script to follow suite with config + +* Sun Sep 27 2009 Mika Ilmaranta - 0.41-1 +- added action_script_check() to check for valid action script + +* Wed Sep 2 2009 Mika Ilmaranta - 0.40-1 +- lseek to start of pid file and ftruncate it to zero size before writing + our new pid. this prevents us having two pids in the file if previous + lsm crashed or exited and did not remove the file (fcntl lock is cleared + by kernel as process dies "prematurely"). + +* Mon Jun 29 2009 Mika Ilmaranta - 0.39-1 +- set close on exec flag for fds and sockets +- call closelog() within forked child before exec + +* Thu Jun 18 2009 Mika Ilmaranta - 0.38-1 +- require mailx for /bin/mail as default_script uses it + +* Thu Jun 18 2009 Mika Ilmaranta - 0.37-1 +- when dumping config log also group's warn_email and logic +- set last previous last group members next to the new last member + +* Thu Jun 18 2009 Mika Ilmaranta - 0.36-1 +- apply sane defaults to group parameters + +* Thu Jun 4 2009 Mika Ilmaranta - 0.35-1 +- only log sendto errors with debug >= 9 + +* Thu Jun 4 2009 Mika Ilmaranta - 0.34-1 +- better sendto error ignore fix +- changed syslog calls for Mandrake + +* Thu Jun 4 2009 Mika Ilmaranta - 0.33-1 +- ping_send: don't care about sendto errors + +* Wed Apr 29 2009 Mika Ilmaranta - 0.32-1 +- split long debug explanation line in lsm.conf + +* Wed Apr 29 2009 Mika Ilmaranta - 0.31-1 +- left only defaults in lsm.conf and moved examples to + lsm.conf.sample + +* Tue Apr 28 2009 Mika Ilmaranta - 0.30-1 +- timeval_diff calculation order change to prevent + long overflow. nobody has encoutered that but just to be + sure +- use default ttl=0 which uses system default ttl + +* Sat Apr 18 2009 Mika Ilmaranta - 0.29-1 +- Added decision making section to README written by Dean Takemori + he suggested to include it in lsm.conf but I thought it was + long enough already + +* Sat Apr 18 2009 Mika Ilmaranta - 0.28-1 +- Tom Eastep's fix for last_sent_time initialization +- added time stamp to default_script mail body + +* Fri Apr 10 2009 Mika Ilmaranta - 0.27-1 +- added checks for missing group members + +* Fri Apr 10 2009 Mika Ilmaranta - 0.26-1 +- added connection grouping + +* Thu Apr 9 2009 Mika Ilmaranta - 0.25-1 +- gettimeofday failure patch from Dean Takemori + +* Sun Apr 5 2009 Mika Ilmaranta - 0.24-1 +- add support for SIGHUP to reload config + +* Tue Mar 24 2009 Mika Ilmaranta - 0.23-1 +- changed ping packets to use own socket for each target. + looks like setsockopt SO_BINDTOINTERFACE is not reversible and + according to documentation I found using it multiple times + may lead to unpredicted results due to kernel caching. + +* Tue Mar 24 2009 Mika Ilmaranta - 0.22-1 +- changed indentation to tabs + +* Mon Mar 16 2009 Mika Ilmaranta - 0.21-1 +- added LSM: to default_script mail subject + +* Tue Mar 10 2009 Mika Ilmaranta - 0.20-1 +- handle ENODEV as if the ping packet was sent, but do barf to syslog + about it. this will eventually cause a down event. added + an error flag which is set if sendto returns with value < 0. +- dump connection statuses to syslog when up/down-event happens. +- moved status dump's "header" -line above the pkt status bits. +- added error flag dumping. + +* Fri Mar 6 2009 Mika Ilmaranta - 0.19-1 +- fix pid file write order + +* Thu Mar 5 2009 Mika Ilmaranta - 0.18-1 +- added pid file handling + +* Thu Mar 5 2009 Mika Ilmaranta - 0.17-1 +- rebuild because of mystical i386 build problems + +* Wed Mar 4 2009 Mika Ilmaranta - 0.16-1 +- pass only LANG, PATH and TERM environment variables to + scripts + +* Wed Mar 4 2009 Mika Ilmaranta - 0.15-1 +- fixed all rpmlint errors reported in binary pkg + which means that default_script is moved to /usr/share/lsm + +* Wed Mar 4 2009 Mika Ilmaranta - 0.14-1 +- added ipv6 support to TODO list +- fixed rpmlint errors in lsm.spec + +* Tue Feb 24 2009 Mika Ilmaranta - 0.13-1 +- typos: lisence -> license +- mention SIGUSR1 behaviour in README +- added a check for ENODEV for ping packets + +* Fri Feb 20 2009 Mika Ilmaranta - 0.12-1 +- don't define device= in defaults + +* Wed Feb 18 2009 Mika Ilmaranta - 0.11-1 +- if device is not specified return NA + +* Wed Feb 18 2009 Mika Ilmaranta - 0.10-1 +- added device to script parameters +- first try on binding ping packets to device + +* Thu Feb 12 2009 Mika Ilmaranta - 0.9-1 +- fixed rtt comments in default_script + +* Thu Feb 12 2009 Mika Ilmaranta - 0.8-1 +- init script reload fix + +* Sat Feb 7 2009 Mika Ilmaranta - 0.7-1 +- fixed typos +- init script reload was missing + +* Sun Feb 1 2009 Mika Ilmaranta - 0.6-1 +- fixed comments and readme to correspond current status + +* Sun Feb 1 2009 Mika Ilmaranta - 0.6-1 +- now each target has its own ttl setting + +* Sat Jan 31 2009 Mika Ilmaranta - 0.5-8 +- check for no targets specified in conf + +* Sat Jan 31 2009 Mika Ilmaranta - 0.5-7 +- all except DEBUG is now syslogged + +* Sat Jan 31 2009 Mika Ilmaranta - 0.5-4 +- added ttl setting handling for ping packets. currently all + ping monitored links share a common ttl value which is + taken from the first config entry's ttl value. +- when SIGUSR1 is received lsm dumps current packet info to + syslog ... + +* Sat Jan 31 2009 Mika Ilmaranta - 0.5-3 +- changed avg rtt calculation so that only replied packets' + rtt is counted + +* Sat Jan 31 2009 Mika Ilmaranta - 0.5-2 +- Added a ping reply packet min size check + +* Fri Jan 30 2009 Mika Ilmaranta - 0.5-1 +- started adding support for arp check which is actually + using arp packets rather than ping packets in case + your gw administrators have blocked ping + +* Thu Jan 29 2009 Mika Ilmaranta - 0.4-1 +- Initial build + +#EOF diff --git a/forkexec.c b/forkexec.c index b1b2cd9..203d1d3 100644 --- a/forkexec.c +++ b/forkexec.c @@ -86,6 +86,8 @@ void create_sigchld_hdl(void) memset (&act, 0, sizeof(act)); act.sa_handler = sigchld_hdl; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART | SA_NOCLDSTOP; if (sigaction(SIGCHLD, &act, 0)) { syslog(LOG_ERR, "%s: %s: %d: failed to set up child signal handler: %s", __FILE__, __FUNCTION__, __LINE__, strerror(errno)); return; @@ -102,16 +104,24 @@ static void sigchld_hdl(int sig) /* Wait for the dead process. * We use a non-blocking call to be sure this signal handler will not * block if a child was cleaned up in another part of the program. */ - int exitval; + int saved_errno = errno; + int script_status; pid_t pid; - if((pid = waitpid(-1, &exitval, WNOHANG)) == -1) { - if(cfg.debug >= 9 && errno != ECHILD) syslog(LOG_ERR, "%s: %s: %d: waitpid failed %s", __FILE__, __FUNCTION__, __LINE__, strerror(errno)); - } else { - if(cfg.debug >= 9 && exitval) syslog(LOG_ERR, "%s: %s: %d: child script with pid %d exited with non null exit value %d", __FILE__, __FUNCTION__, __LINE__, pid, exitval); - else if(cfg.debug >= 9) syslog(LOG_ERR, "%s: %s: %d: child script with pid %d exited successfully", __FILE__, __FUNCTION__, __LINE__, pid); - exec_queue_delete(pid); + while ((pid = waitpid(WAIT_ANY, &script_status, WNOHANG)) != 0) { + if(pid == -1) { + if(cfg.debug >= 9 && errno != ECHILD) + syslog(LOG_ERR, "%s: %s: %d: waitpid failed %s", __FILE__, __FUNCTION__, __LINE__, strerror(errno)); + break; + } else { + if(cfg.debug >= 9 && WEXITSTATUS(script_status)) + syslog(LOG_ERR, "%s: %s: %d: child script with pid %d exited with non null exit value %d", __FILE__, __FUNCTION__, __LINE__, pid, WEXITSTATUS(script_status)); + else if(cfg.debug >= 9) + syslog(LOG_ERR, "%s: %s: %d: child script with pid %d exited successfully", __FILE__, __FUNCTION__, __LINE__, pid); + exec_queue_delete(pid); + } } + errno = saved_errno; } void exec_queue_add(char *queue, char **argv, char **envp) diff --git a/globals.c b/globals.c index 7f2cae0..d37a306 100644 --- a/globals.c +++ b/globals.c @@ -12,7 +12,7 @@ License: GPLv2 #include "globals.h" #include "defs.h" -#define LSM_CONFIG_FILE ETCDIR "/lsm.conf" +#define FOOLSM_CONFIG_FILE ETCDIR "/foolsm.conf" static char *prog = NULL; static int cont = TRUE; @@ -20,8 +20,8 @@ static int dump = FALSE; static int ident = 0; static int reload_cfg = FALSE; static int dump_if_list = FALSE; -static char *configfile = LSM_CONFIG_FILE; -static char *pidfile = "/var/run/lsm.pid"; +static char *configfile = FOOLSM_CONFIG_FILE; +static char *pidfile = "/var/run/foolsm.pid"; static int nodaemon = 0; static char *status_str[] = { "down", "up", "unknown", "long_down" }; diff --git a/group_script b/group_script index 7010492..c50887f 100644 --- a/group_script +++ b/group_script @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (C) 2012,2015 Tuomo Soini +# Copyright (C) 2012-2016 Tuomo Soini # # License: GPLv2 # @@ -32,7 +32,7 @@ fi DATE=$(date --date=@${TIMESTAMP}) -cat < - -License: GPLv2 - -*/ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "icmp_t.h" -#include "icmp6_t.h" -#include "config.h" -#include "cksum.h" -#include "globals.h" -#include "signal_handler.h" -#include "forkexec.h" -#include "timecalc.h" -#include "lsm.h" -#ifndef NO_PLUGIN_EXPORT -#include "plugin_export.h" -#endif -#include "save_statuses.h" -#include "pidfile.h" -#include "cmdline.h" -#include "usage.h" - -typedef struct ping_data { - unsigned short id; /* target id */ - long ping_count; /* counts up to -c count or 1 */ - struct timeval ping_ts; /* time sent */ -} PING_DATA; - -static void update_stats(CONFIG *first); -static void dump_statuses(CONFIG *first); -static void decide(CONFIG *first); -static void groups_decide(GROUPS *firstg); -static int wait_for_replies(CONFIG **ctable); -static int ping_send(CONFIG *cur); -static int ping_rcv(CONFIG *first, char *buf, int len, struct sockaddr_in6 *saddr, unsigned int *slen, long usec, CONFIG **arp); -static int event_script_check(const char *path); -static int open_arp_sock(CONFIG *cur); -static int open_icmp_sock(CONFIG *cur); -static int probe_src_ip_addr(CONFIG *cur); -static void init_config_data(CONFIG *first, CONFIG *last, CONFIG ***ctable); -static void free_config_data(CONFIG *first); -#if defined(DEBUG) -static void dump_pkt(const void *buf, size_t len); -#endif - -static int num_hosts = 0; - -/* Main */ -int main(int argc, char *argv[]) { - TARGET *t = NULL; - CONFIG *first = NULL, *last = NULL, *cur; - GROUPS *firstg = NULL, *lastg = NULL; - CONFIG **ctable = NULL; - struct timeval last_sent_time = {0, 0}; - int start = 0; - - openlog("lsm", LOG_PID, LOG_DAEMON); - - cmdline_parse(argc, argv); - - init_config(); - - if(read_config(get_configfile(), &first, &last, &firstg, &lastg)) { - usage_and_exit(); - } - - if(cfg.debug >= 9) syslog(LOG_INFO, "my ident is %d\n", get_ident()); - - if(!first) { - syslog(LOG_ERR, "no targets found in config file"); - exit(1); - } - - if(cfg.debug >= 9) dump_config(&first, &last, &firstg, &lastg); - - /* check pid file */ - if(pidfile_open() != 0) exit(1); - - /* detach from controlling terminal if nodaemon global is not set */ - if(get_nodaemon() == 0) { - if(daemon(1, 0)) { - syslog(LOG_ERR, "daemon failed while trying to detach"); - return(1); - } - } - - if(pidfile_update() != 0) exit(1); - - set_ident(getpid() & 0xFFFF); - -#ifndef NO_PLUGIN_EXPORT - plugin_export_init(); -#endif - - init_config_data(first, last, &ctable); - - signal(SIGINT, signal_handler); - signal(SIGUSR1, signal_handler); - signal(SIGUSR2, signal_handler); - signal(SIGHUP, signal_handler); - - /* - Create the handler for child signals. This will clean up - any forked child after an event has occured. - */ - create_sigchld_hdl(); - - struct timeval last_decision = {0, 0}; - - /* the main loop */ - while(get_cont()) { - struct timeval tv = {0, 0}; - - if(get_reload_cfg()) { - - save_statuses(first); - - /* reload config */ - free(ctable); - free_config_data(first); - if(reload_config(get_configfile(), &first, &last, &firstg, &lastg)) { - syslog(LOG_ERR, "reload config failed"); - exit(2); - } - init_config_data(first, last, &ctable); - - restore_statuses(first); - - set_reload_cfg(0); - } - - for(cur = first; cur; cur = cur->next) { - struct timeval current_time = {0, 0}; - - if(start) - while(wait_for_replies(ctable)); - - if(gettimeofday(¤t_time, NULL) == -1) { - syslog(LOG_INFO, "gettimeofday failed \"%s\"", strerror(errno)); - sleep(1); - continue; - } - - t = cur->data; - - if(timeval_diff_cmp(¤t_time, &last_sent_time, TIMEVAL_DIFF_CMP_LT, MIN_PERHOST_INTERVAL / 1000000L, MIN_PERHOST_INTERVAL % 1000000L)) continue; - - if(cur->startup_burst_pkts && t->used <= cur->startup_burst_pkts && !timeval_diff_cmp(¤t_time, &(t->last_send_time), TIMEVAL_DIFF_CMP_LT, (cur->startup_burst_interval * 1000) / 1000000L, (cur->startup_burst_interval * 1000) % 1000000L)); - else if(timeval_diff_cmp(¤t_time, &(t->last_send_time), TIMEVAL_DIFF_CMP_LT, (cur->interval_ms * 1000) / 1000000L, (cur->interval_ms * 1000) % 1000000L)) continue; - - if(cur->check_arp) { - open_arp_sock(cur); - } else { - open_icmp_sock(cur); - } - - if(ping_send(cur)) { - if(cfg.debug >= 9) syslog(LOG_INFO, "ping_send failed to %s", cur->name); - } - else { - gettimeofday(&last_sent_time, NULL); - start = 1; - } - } - - gettimeofday(&tv, NULL); - if(timeval_diff_cmp(&tv, &last_decision, TIMEVAL_DIFF_CMP_GT, 1, 0)) { /* make decisions at 1s intervals */ - gettimeofday(&last_decision, NULL); - - update_stats(first); - decide(first); - dump_statuses(first); - - groups_decide(firstg); - -#if defined(DEBUG) - exec_queue_dump(); -#endif - exec_queue_process(); - -#ifndef NO_PLUGIN_EXPORT - plugin_export(first); -#endif - } - } /* while cont */ - - /* if we wrote pid file then close and remove it */ - pidfile_close(); - - free(ctable); - free_config_data(first); - free_config(&first, &last, &firstg, &lastg); - exec_queue_free(); - - closelog(); - - return(0); -} - -static void free_config_data(CONFIG *first) { - CONFIG *cur; - - for(cur = first; cur; cur = cur->next) { - TARGET *t; - - t = cur->data; - if(t->sock != -1) close(t->sock); - free(t); - } -} - -static void update_stats(CONFIG *first) { - struct timeval current_time = {0, 0}; - CONFIG *cur; - - gettimeofday(¤t_time, NULL); - - for(cur = first; cur; cur = cur->next) { - TARGET *t; - int i, seq, ind; - long rtt = 0; - - t = cur->data; - - t->timeout = 0; - t->replied = 0; - t->waiting = 0; - t->reply_late = 0; - t->consecutive_waiting = 0; - t->consecutive_missing = 0; - t->consecutive_rcvd = 0; - - /* check consecutive pkts */ - seq = t->seq % FOLLOWED_PKTS; - - for(i = (seq - 2); i > (seq - 2) - FOLLOWED_PKTS; i--) { - ind = (i >= 0) ? i : i + FOLLOWED_PKTS; - if(!t->sentpkts[ind].flags.used) break; - - if(t->sentpkts[ind].flags.waiting) t->consecutive_waiting++; - else break; - } - - for(i = (seq - 2); i > (seq - 2) - FOLLOWED_PKTS; i--) { - ind = (i >= 0) ? i : i + FOLLOWED_PKTS; - if(!t->sentpkts[ind].flags.used) break; - - if(t->sentpkts[ind].flags.timeout || t->sentpkts[ind].flags.waiting) t->consecutive_missing++; - else break; - } - - for(i = (seq - 2); i > (seq - 2) - FOLLOWED_PKTS; i--) { - ind = (i >= 0) ? i : i + FOLLOWED_PKTS; - if(!t->sentpkts[ind].flags.used) break; - - if(t->sentpkts[ind].flags.replied && !t->sentpkts[ind].flags.timeout) t->consecutive_rcvd++; - else break; - } - - /* count pkt states */ - for(i = 0; i < FOLLOWED_PKTS; i++) { - if(!t->sentpkts[i].flags.used) continue; - - if(timeval_diff_cmp(¤t_time, &t->sentpkts[i].sent_time, TIMEVAL_DIFF_CMP_GT, (cur->timeout_ms * 1000) / 1000000L, (cur->timeout_ms * 1000) % 1000000L) && t->sentpkts[i].flags.waiting) { - t->sentpkts[i].flags.timeout = 1; - } - - if(t->sentpkts[i].flags.replied && t->sentpkts[i].flags.timeout) t->reply_late++; - - if(t->sentpkts[i].flags.replied) { - t->replied++; - rtt += t->sentpkts[i].rtt; /* count rtt sum in usec from replied pkts rtt which is in usec */ - } - if(t->sentpkts[i].flags.timeout) t->timeout++; - if(t->sentpkts[i].flags.waiting) t->waiting++; - } - /* avg_rtt in usec */ - t->avg_rtt = rtt / (t->replied ? t->replied : 1); - - /* update loss max info */ - if(t->timeout > t->timeout_max) t->timeout_max = t->timeout; - if(t->consecutive_missing > t->consecutive_missing_max) t->consecutive_missing_max = t->consecutive_missing; - - if(cfg.debug >= 9) syslog(LOG_INFO, "name = %s, replied = %d, waiting = %d, timeout = %d, late reply = %d, cons rcvd = %d, cons wait = %d, cons miss = %d, avg_rtt = %.3f, seq = %d, status = %s", - cur->name, t->replied, t->waiting, t->timeout, t->reply_late, t->consecutive_rcvd, t->consecutive_waiting, t->consecutive_missing, t->avg_rtt / 1000.0, t->seq, get_status_str(t->status)); - - } -} - -static void dump_statuses(CONFIG *first) { - CONFIG *cur; - - for(cur = first; cur; cur = cur->next) { - TARGET *t; - - t = cur->data; - - if((t->status == DOWN || t->status == LONG_DOWN) && t->downseq == (t->seq % FOLLOWED_PKTS) && t->seq != t->downseqreported && !t->status_change) syslog(LOG_INFO, "link %s still down", cur->name); - - /* dump is controlled by SIGUSR1 and then we should show all statuses anyway */ - if(get_dump() || t->status_change || ((t->status == DOWN || t->status == LONG_DOWN) && t->downseq == (t->seq % FOLLOWED_PKTS) && t->seq != t->downseqreported && !t->status_change)) { - if(cfg.debug >= 6) syslog(LOG_INFO, "name = %s, replied = %d, waiting = %d, timeout = %d, timeout max = %d, late reply = %d, cons rcvd = %d, cons wait = %d, cons miss = %d, cons miss max = %d, avg_rtt = %.3f, seq = %d, status = %s", - cur->name, t->replied, t->waiting, t->timeout, t->timeout_max, t->reply_late, t->consecutive_rcvd, t->consecutive_waiting, t->consecutive_missing, t->consecutive_missing_max, t->avg_rtt / 1000.0, t->seq, get_status_str(t->status)); - - if(cfg.debug >= 7) { - /* 100 should be enough for the comments and such, but I don't care to count */ - char buf[FOLLOWED_PKTS + 100]; - int i, seq; - - seq = t->seq % FOLLOWED_PKTS; - - sprintf(buf, "seq "); - for(i = 0; i < FOLLOWED_PKTS; i++) { - if(i == seq) strcat(buf, "*"); - else strcat(buf, " "); - } - syslog(LOG_INFO, "%s", buf); - - sprintf(buf, "used "); - for(i = 0; i < FOLLOWED_PKTS; i++) { - sprintf(buf + strlen(buf), "%d", t->sentpkts[i].flags.used); - } - syslog(LOG_INFO, "%s", buf); - - sprintf(buf, "wait "); - for(i = 0; i < FOLLOWED_PKTS; i++) { - sprintf(buf + strlen(buf), "%d", t->sentpkts[i].flags.waiting); - } - syslog(LOG_INFO, "%s", buf); - - sprintf(buf, "replied "); - for(i = 0; i < FOLLOWED_PKTS; i++) { - sprintf(buf + strlen(buf), "%d", t->sentpkts[i].flags.replied); - } - syslog(LOG_INFO, "%s", buf); - - sprintf(buf, "timeout "); - for(i = 0; i < FOLLOWED_PKTS; i++) { - sprintf(buf + strlen(buf), "%d", t->sentpkts[i].flags.timeout); - } - syslog(LOG_INFO, "%s", buf); - - sprintf(buf, "error "); - for(i = 0; i < FOLLOWED_PKTS; i++) { - sprintf(buf + strlen(buf), "%d", t->sentpkts[i].flags.error); - } - syslog(LOG_INFO, "%s", buf); - - if(t->status == UP && t->status_change) { - t->timeout_max = 0; - t->consecutive_missing_max = 0; - } - } - - t->downseqreported = t->seq; - } - } - if(get_dump()) set_dump(0); /* if we just dumped then don't dump next time. flags don't change that frequently */ -} - -static void decide(CONFIG *first) { - struct timeval current_time = {0, 0}; - CONFIG *cur; - - gettimeofday(¤t_time, NULL); - - for(cur = first; cur; cur = cur->next) { - TARGET *t; - STATUS prevstatus; - - t = cur->data; - - /* reset any previous connection status_change state */ - t->status_change = 0; - - prevstatus = t->status; - - /* up or unknown */ - if(t->status == UP || t->status == UNKNOWN) { - if(t->timeout >= cur->max_packet_loss || t->consecutive_missing >= cur->max_successive_pkts_lost) { - /* change to down state */ - t->status_change = 1; - t->status = DOWN; - -#if !defined(NO_PLUGIN_EXPORT) && !defined(NO_PLUGIN_EXPORT_STATUS) - plugin_export_status(first); -#endif - - if(cfg.debug >= 8) syslog(LOG_INFO, "link %s down event", cur->name); - if(event_script_check(cur->eventscript)) { - char sbuf[INET6_ADDRSTRLEN]; - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - cur->eventscript, - get_status_str(t->status), - cur->name, - cur->checkip, - cur->device ? cur->device : "", - cur->warn_email ? cur->warn_email : "", - t->replied, - t->waiting, - t->timeout, - t->reply_late, - t->consecutive_rcvd, - t->consecutive_waiting, - t->consecutive_missing, - t->avg_rtt, - cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), - get_status_str(prevstatus), - current_time.tv_sec); - envp = exec_queue_envp(); - - if(cur->queue && *cur->queue) { - exec_queue_add(cur->queue, argv, envp); - } else { - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - } - - if(event_script_check(cur->notifyscript)) { - char sbuf[INET6_ADDRSTRLEN]; - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - cur->notifyscript, - get_status_str(t->status), - cur->name, - cur->checkip, - cur->device ? cur->device : "", - cur->warn_email ? cur->warn_email : "", - t->replied, - t->waiting, - t->timeout, - t->reply_late, - t->consecutive_rcvd, - t->consecutive_waiting, - t->consecutive_missing, - t->avg_rtt, - cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), - get_status_str(prevstatus), - current_time.tv_sec); - - envp = exec_queue_envp(); - - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - - if(gettimeofday(&t->down_timestamp, NULL) == -1) { - syslog(LOG_INFO, "gettimeofday failed \"%s\"", strerror(errno)); - } - t->downseq = t->seq % FOLLOWED_PKTS; - t->downseqreported = 0; - } - } - - /* has it been down long? */ - if(t->status == DOWN && cur->long_down_time) { - if(timeval_diff_cmp(¤t_time, &t->down_timestamp, TIMEVAL_DIFF_CMP_GT, cur->long_down_time, 0)) { - /* special, LONG_DOWN is considered DOWN thus no status_change */ - t->status = LONG_DOWN; - - if(cfg.debug >= 8) syslog(LOG_INFO, "link %s long down event", cur->name); - if(event_script_check(cur->long_down_eventscript)) { - char sbuf[INET6_ADDRSTRLEN]; - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - cur->long_down_eventscript, - get_status_str(t->status), - cur->name, - cur->checkip, - cur->device ? cur->device : "", - cur->long_down_email ? cur->long_down_email : "", - t->replied, - t->waiting, - t->timeout, - t->reply_late, - t->consecutive_rcvd, - t->consecutive_waiting, - t->consecutive_missing, - t->avg_rtt, - cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), - get_status_str(prevstatus), - t->down_timestamp.tv_sec); - - envp = exec_queue_envp(); - - if(cur->queue && *cur->queue) { - exec_queue_add(cur->queue, argv, envp); - } else { - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - } - - if(event_script_check(cur->long_down_notifyscript)) { - char sbuf[INET6_ADDRSTRLEN]; - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - cur->long_down_notifyscript, - get_status_str(t->status), - cur->name, - cur->checkip, - cur->device ? cur->device : "", - cur->long_down_email ? cur->long_down_email : "", - t->replied, - t->waiting, - t->timeout, - t->reply_late, - t->consecutive_rcvd, - t->consecutive_waiting, - t->consecutive_missing, - t->avg_rtt, - cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), - get_status_str(prevstatus), - t->down_timestamp.tv_sec); - - envp = exec_queue_envp(); - - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - } - } - - /* down, long down or unknown */ - if(t->status == DOWN || t->status == LONG_DOWN || t->status == UNKNOWN) { - if((cur->startup_acceleration && t->consecutive_rcvd >= cur->startup_acceleration && (t->consecutive_rcvd + 1) >= t->used) || (t->timeout <= cur->min_packet_loss && t->consecutive_rcvd >= cur->min_successive_pkts_rcvd)) { - - t->status_change = 1; - t->status = UP; - -#if !defined(NO_PLUGIN_EXPORT) && !defined(NO_PLUGIN_EXPORT_STATUS) - plugin_export_status(first); -#endif - - /* report long_down to up */ - if(prevstatus == LONG_DOWN) { - if(event_script_check(cur->long_down_eventscript)) { - char sbuf[INET6_ADDRSTRLEN]; - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - cur->long_down_eventscript, - get_status_str(t->status), - cur->name, - cur->checkip, - cur->device ? cur->device : "", - cur->long_down_email ? cur->long_down_email : "", - t->replied, - t->waiting, - t->timeout, - t->reply_late, - t->consecutive_rcvd, - t->consecutive_waiting, - t->consecutive_missing, - t->avg_rtt, - cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), - get_status_str(prevstatus), - current_time.tv_sec); - - envp = exec_queue_envp(); - - if(cur->queue && *cur->queue) { - exec_queue_add(cur->queue, argv, envp); - } else { - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - } - - if(event_script_check(cur->long_down_notifyscript)) { - char sbuf[INET6_ADDRSTRLEN]; - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - cur->long_down_notifyscript, - get_status_str(t->status), - cur->name, - cur->checkip, - cur->device ? cur->device : "", - cur->long_down_email ? cur->long_down_email : "", - t->replied, - t->waiting, - t->timeout, - t->reply_late, - t->consecutive_rcvd, - t->consecutive_waiting, - t->consecutive_missing, - t->avg_rtt, - cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), - get_status_str(prevstatus), - current_time.tv_sec); - - envp = exec_queue_envp(); - - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - } - - /* change to up state */ - if(cfg.debug >= 8) syslog(LOG_INFO, "link %s up event", cur->name); - if(event_script_check(cur->eventscript)) { - char sbuf[INET6_ADDRSTRLEN]; - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - cur->eventscript, - get_status_str(t->status), - cur->name, - cur->checkip, - cur->device ? cur->device : "", - cur->warn_email ? cur->warn_email : "", - t->replied, - t->waiting, - t->timeout, - t->reply_late, - t->consecutive_rcvd, - t->consecutive_waiting, - t->consecutive_missing, - t->avg_rtt, - cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), - get_status_str(prevstatus), - current_time.tv_sec); - - envp = exec_queue_envp(); - - if(cur->queue && *cur->queue) { - exec_queue_add(cur->queue, argv, envp); - } else { - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - } - - if((cur->unknown_up_notify || t->status != UNKNOWN) && event_script_check(cur->notifyscript)) { - char sbuf[INET6_ADDRSTRLEN]; - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - cur->notifyscript, - get_status_str(t->status), - cur->name, - cur->checkip, - cur->device ? cur->device : "", - cur->warn_email ? cur->warn_email : "", - t->replied, - t->waiting, - t->timeout, - t->reply_late, - t->consecutive_rcvd, - t->consecutive_waiting, - t->consecutive_missing, - t->avg_rtt, - cur->dstinfo->ai_family == AF_INET ? inet_ntoa(t->src) : inet_ntop(AF_INET6, &t->src6, sbuf, INET6_ADDRSTRLEN), - get_status_str(prevstatus), - current_time.tv_sec); - - envp = exec_queue_envp(); - - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - } - } - } -} - -static void groups_decide(GROUPS *firstg){ - GROUPS *curg; - GROUP_MEMBERS *curgm; - TARGET *t; - STATUS prevstatus; - struct timeval current_time = {0, 0}; - - gettimeofday(¤t_time, NULL); - - curg = firstg; - while(curg) { - prevstatus = curg->status; - curg->status = curg->logic; - - curgm = curg->fgm; - while(curgm) { - if(!curgm->cfg_ptr) break; - - t = curgm->cfg_ptr->data; - - /* if any one group member is in unknown status, group is in unknown status */ - if(t->status == UNKNOWN) { - curg->status = UNKNOWN; - break; - } - - if(!curg->logic) { - curg->status |= (t->status == DOWN || t->status == LONG_DOWN) ? DOWN : t->status; - } else { - curg->status &= (t->status == DOWN || t->status == LONG_DOWN) ? DOWN : t->status; - } - - curgm = curgm->next; - } - if(curg->status != prevstatus) { - if(curg->status == UP) { - /* group up event */ - if(cfg.debug >= 8) syslog(LOG_INFO, "group %s up event", curg->name); - if(event_script_check(curg->eventscript)) { - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - curg->eventscript, - get_status_str(curg->status), - curg->name, - "", - "", - curg->warn_email ? curg->warn_email : "", - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - "", - get_status_str(prevstatus), - current_time.tv_sec); - envp = exec_queue_envp(); - - if(curg->queue && *curg->queue) { - exec_queue_add(curg->queue, argv, envp); - } else { - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - } - if((curg->unknown_up_notify || prevstatus != UNKNOWN) && event_script_check(curg->notifyscript)) { - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - curg->notifyscript, - get_status_str(curg->status), - curg->name, - "", - "", - curg->warn_email ? curg->warn_email : "", - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - "", - get_status_str(prevstatus), - current_time.tv_sec); - envp = exec_queue_envp(); - - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - } - - if(curg->status == DOWN) { - /* group down event */ - if(cfg.debug >= 8) syslog(LOG_INFO, "group %s down event", curg->name); - if(event_script_check(curg->eventscript)) { - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - curg->eventscript, - get_status_str(curg->status), - curg->name, - "", - "", - curg->warn_email ? curg->warn_email : "", - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - "", - get_status_str(prevstatus), - current_time.tv_sec); - envp = exec_queue_envp(); - - if(curg->queue && *curg->queue) { - exec_queue_add(curg->queue, argv, envp); - } else { - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - } - if(event_script_check(curg->notifyscript)) { - char **argv; - char **envp; - - argv = exec_queue_argv("%s %s %s %s %s %s %d %d %d %d %d %d %d %d %s %s %d", - curg->notifyscript, - get_status_str(curg->status), - curg->name, - "", - "", - curg->warn_email ? curg->warn_email : "", - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - "", - get_status_str(prevstatus), - current_time.tv_sec); - envp = exec_queue_envp(); - - forkexec(argv, envp); - - exec_queue_argv_free(argv); - exec_queue_envp_free(envp); - } - } - } - curg = curg->next; - } -} - -static int wait_for_replies(CONFIG **ctable) { - struct ip *ip; - int hlen = 0; - struct icmp *icp; - struct icmp6_hdr *icp6; - PING_DATA *pdp; - int this_count; - struct timeval sent_time = {0, 0}; - struct timeval current_time = {0, 0}; - long time_diff; - char buf[BUFSIZ]; - union { - struct sockaddr_in6 saddr6; - struct sockaddr_in saddr; - struct sockaddr_ll FROM; - } from_addr; - unsigned int slen; - int result; - TARGET *t; - int seq; - CONFIG *arp; - - slen = sizeof(from_addr); - result = ping_rcv(ctable[0], buf, BUFSIZ, (struct sockaddr_in6 *)&from_addr, &slen, DEFAULT_SELECT_WAIT, &arp); - - if(result <= 0) { - return(0); - } - - gettimeofday(¤t_time, NULL); - - if(arp) { - struct sockaddr_ll *FROM = &from_addr.FROM; - TARGET *t = arp->data; - struct arphdr *ah = (struct arphdr*)buf; - unsigned char *p = (unsigned char *)(ah+1); - struct in_addr src_ip, dst_ip; - int ind; - - /* Filter out wild packets */ - if(FROM->sll_pkttype != PACKET_HOST && - FROM->sll_pkttype != PACKET_BROADCAST && - FROM->sll_pkttype != PACKET_MULTICAST) - return(1); - - /* Only these types are recognised */ -#if 0 - if(ah->ar_op != htons(ARPOP_REQUEST) && - ah->ar_op != htons(ARPOP_REPLY)) - return(1); -#else - if(ah->ar_op != htons(ARPOP_REPLY)) - return(1); -#endif - - /* ARPHRD check and this darned FDDI hack here :-( */ - if(ah->ar_hrd != htons(FROM->sll_hatype) && - (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER))) - return(1); - - /* Protocol must be IP. */ - if(ah->ar_pro != htons(ETH_P_IP)) - return(1); - if(ah->ar_pln != 4) - return(1); - if(ah->ar_hln != t->me.sll_halen) - return(1); - -#if defined(DEBUG) - for(ind = 0; ind < result; ind ++) { - fprintf(stderr, "%02x", (unsigned char)buf[ind]); - if(!((ind + 1) % 2)) fprintf(stderr, " "); - if(!((ind + 1) % 32)) fprintf(stderr, "\n"); - } - fprintf(stderr, "\n"); - for(ind = 0; ind < result; ind ++) { - fprintf(stderr, "%3u", (unsigned char)buf[ind]); - if(!((ind + 1) % 32)) fprintf(stderr, "\n"); - else fprintf(stderr, ","); - } - fprintf(stderr, "\n"); -#endif - - if(result < sizeof(*ah) + 2*(4 + ah->ar_hln)) - return(1); - - memcpy(&src_ip, p+ah->ar_hln, 4); - memcpy(&dst_ip, p+ah->ar_hln+4+ah->ar_hln, 4); - - if(src_ip.s_addr != t->dst.s_addr) - return(1); - if(t->src.s_addr != dst_ip.s_addr) - return(1); - if(memcmp(p+ah->ar_hln+4, &t->me.sll_addr, ah->ar_hln)) - return(1); - - /* update packet log here */ - /* there are no sequence numbers in arp replies so just mark seq - 1 replied */ - ind = ((t->seq - 1) >= 0 ? (t->seq - 1) : (FOLLOWED_PKTS + (t->seq - 1))) % FOLLOWED_PKTS; - t->sentpkts[ind].flags.replied = 1; - t->sentpkts[ind].flags.waiting = 0; - t->sentpkts[ind].replied_time = current_time; - t->sentpkts[ind].rtt = timeval_diff(¤t_time, &t->sentpkts[ind].sent_time); - - return(1); - } - -#if defined(DEBUG) - if(cfg.debug >= 9) { - char sbuf[INET6_ADDRSTRLEN]; - - syslog(LOG_INFO, "not arp: family = %d, AF_INET = %d, AF_INET6 = %d, inet_ntop addr = %s, inet_ntoa addr = %s", from_addr.saddr6.sin6_family, AF_INET, AF_INET6, inet_ntop(from_addr.saddr6.sin6_family, &from_addr.saddr6.sin6_addr, sbuf, INET6_ADDRSTRLEN), inet_ntoa(from_addr.saddr.sin_addr)); - } -#endif - - switch(from_addr.saddr6.sin6_family) { - case AF_INET: -#if defined(DEBUG) - syslog(LOG_INFO, "%s: %s: AF_INET reply", __FILE__, __FUNCTION__); -#endif - ip = (struct ip *)buf; - hlen = ip->ip_hl << 2; - - icp = (struct icmp *)(buf + hlen); - - if(icp->icmp_type == ICMP_ECHO) { - return(1); - } - - if(icp->icmp_type == ICMP_ECHOREPLY) { - if(icp->icmp_id != get_ident()) { - /* fprintf(stderr, "icmp_id = %d funny, got reply from %s to something else ...\n", icp->icmp_id, inet_ntoa(saddr.sin_addr)); */ - return(1); - } - - if(result < sizeof(struct icmp) + sizeof(PING_DATA)) { - /* fprintf(stderr, "too short ping reply\n"); */ - return(1); - } - - pdp = (PING_DATA *)(buf + hlen + sizeof(struct icmp)); - - this_count = pdp->ping_count; - sent_time = pdp->ping_ts; - time_diff = timeval_diff(¤t_time, &sent_time); - - if(pdp->id >= num_hosts) { -#if defined(DEBUG) - syslog(LOG_INFO, "out of range: pdp->id = %d >= num_hosts = %d from %s", pdp->id, num_hosts, inet_ntoa(from_addr.saddr.sin_addr)); - dump_pkt(buf, sizeof(struct ip) + sizeof(struct icmp) + sizeof(PING_DATA)); - set_dump(1); -#endif - return(1); - } - - t = ctable[pdp->id]->data; - - if(memcmp(&ip->ip_src, &t->dst, sizeof(struct in_addr) != 0)) { - return(1); - } - - seq = icp->icmp_seq % FOLLOWED_PKTS; - if(t->sentpkts[seq].seq == icp->icmp_seq) { - t->sentpkts[seq].flags.replied = 1; - t->sentpkts[seq].flags.waiting = 0; - t->sentpkts[seq].replied_time = current_time; - t->sentpkts[seq].rtt = timeval_diff(¤t_time, &t->sentpkts[seq].sent_time); - } - else - if(cfg.debug >= 9) syslog(LOG_INFO, "sentpkts seq != icmp_seq"); - - if(cfg.debug >= 9) syslog(LOG_INFO, "received seq = %d from %s, id = %d, num_sent = %d, target id = %u, time_diff = %ld", icp->icmp_seq, inet_ntoa(from_addr.saddr.sin_addr), icp->icmp_id, this_count, pdp->id, time_diff); - - return(1); - - } else { - struct icmpmsg *msg; - - msg = stricmp(icp->icmp_type, icp->icmp_code); - - if(cfg.debug >= 9) syslog(LOG_INFO, "got odd reply from %s, icmp_type = %d %s, icmp_code = %d %s", inet_ntoa(from_addr.saddr.sin_addr), icp->icmp_type, msg->type_msg, icp->icmp_code, msg->code_msg); - - return(1); - } - break; - case AF_INET6: -#if defined(DEBUG) - syslog(LOG_INFO, "%s: %s: AF_INET6 reply", __FILE__, __FUNCTION__); -#endif - icp6 = (struct icmp6_hdr *)buf; - - if(icp6->icmp6_type == ICMP6_ECHO_REQUEST) { - return(1); - } - - if (icp6->icmp6_type == ICMP6_ECHO_REPLY) { /* v6 reply */ - char sbuf[INET6_ADDRSTRLEN]; -#if defined(DEBUG) - dump_pkt(buf, sizeof(struct icmp6_hdr) + sizeof(PING_DATA)); -#endif - /* syslog(LOG_INFO, "sizeof struct icmp6_hdr = %ld\n", sizeof(struct icmp6_hdr)); */ - - if(icp6->icmp6_id != get_ident()) { - return(1); - } - - if(result < sizeof(struct icmp6_hdr) + sizeof(PING_DATA)) { - return(1); - } - - /* pdp = (PING_DATA *)(buf + hlen + sizeof(struct icmp6_hdr)); */ - /* pdp = (PING_DATA *)(buf + sizeof(struct icmp6_hdr)); */ - pdp = (PING_DATA *)(buf + sizeof(struct icmp6_hdr)); - - this_count = pdp->ping_count; - sent_time = pdp->ping_ts; - time_diff = timeval_diff(¤t_time, &sent_time); - -#if defined(DEBUG) - syslog(LOG_INFO, "%s: %s: this_count = %d, sent_time = %ld,%ld, pdp->id = %d", __FILE__, __FUNCTION__, this_count, sent_time.tv_sec, sent_time.tv_usec, pdp->id); -#endif - - if(pdp->id >= num_hosts) { -#if defined(DEBUG) - syslog(LOG_INFO, "out of range: pdp->id = %d >= num_hosts = %d from %s", pdp->id, num_hosts, inet_ntop(AF_INET6, &from_addr.saddr6.sin6_addr, sbuf, INET6_ADDRSTRLEN)); - dump_pkt(buf, sizeof(struct icmp6_hdr) + sizeof(PING_DATA)); - set_dump(1); -#endif - return(1); - } - - t = ctable[pdp->id]->data; - - if(memcmp(&from_addr.saddr6.sin6_addr, &t->dst6, sizeof(struct in6_addr)) != 0) { - return(1); - } - - seq = ntohs(icp6->icmp6_seq) % FOLLOWED_PKTS; - if(t->sentpkts[seq].seq == ntohs(icp6->icmp6_seq)) { - t->sentpkts[seq].flags.replied = 1; - t->sentpkts[seq].flags.waiting = 0; - t->sentpkts[seq].replied_time = current_time; - t->sentpkts[seq].rtt = timeval_diff(¤t_time, &t->sentpkts[seq].sent_time); - } - else - if (cfg.debug >= 9) syslog(LOG_INFO, "sentpkts seq != icmp_seq"); - - if(cfg.debug >= 9) syslog(LOG_INFO, "received seq = %d from %s, id = %d, num_sent = %d, target id = %u, time_diff = %ld", ntohs(icp6->icmp6_seq), inet_ntop(AF_INET6, &from_addr.saddr6.sin6_addr, sbuf, INET6_ADDRSTRLEN), icp6->icmp6_id, this_count, pdp->id, time_diff); - - return(1); - } else { - char sbuf[INET6_ADDRSTRLEN]; - struct icmp6msg *msg; - - msg = stricmp6(icp6->icmp6_type, icp6->icmp6_code); - - if(cfg.debug >= 9) syslog(LOG_INFO, "got odd reply from %s, icmp_type = %d %s, icmp_code = %d %s", inet_ntop(from_addr.saddr6.sin6_family, &from_addr.saddr6.sin6_addr, sbuf, INET6_ADDRSTRLEN), icp6->icmp6_type, msg->type_msg, icp6->icmp6_code, msg->code_msg); - - return(1); - } - break; - default: - syslog(LOG_INFO, "%s: %s: unknown family reply", __FILE__, __FUNCTION__); - break; - } - - return(1); -} - -static int ping_rcv(CONFIG *first, char *buf, int len, struct sockaddr_in6 *saddr, unsigned int *slen, long usec, CONFIG **arp) { - int nfound, n; - fd_set readset; - struct timeval to = {0, 0}; - int max; - CONFIG *cur; - TARGET *t; - int cnt_targets = 0; - - FD_ZERO(&readset); - max = 0; - - for(cur = first; cur; cur = cur->next) { - t = cur->data; - if(t->sock == -1) continue; - if(t->sock > max) max = t->sock; - FD_SET(t->sock, &readset); - cnt_targets++; - } - - /* no point in calling select if we didn't find any open sockets. so sleep and return ... */ - if(cnt_targets == 0) { - sleep(1); - return(0); - } - - to.tv_sec = usec / 1000000; - to.tv_usec = (usec - (to.tv_sec * 1000000)); - -#if defined(DEBUG) - printf("to.tv_sec = %ld, to.tv_usec = %ld\n", to.tv_sec, to.tv_usec); -#endif - - nfound = select(max + 1, &readset, NULL, NULL, &to); - - if(nfound < 0) { - if(errno != EINTR) syslog(LOG_INFO, "select failed \"%s\"", strerror(errno)); - return(0); - } - - if(nfound == 0) return(-1); - - for(cur = first; cur; cur = cur->next) { - t = cur->data; - if(t->sock == -1) continue; - if(FD_ISSET(t->sock, &readset)) { - if(!cur->check_arp) { - *arp = (CONFIG *)NULL; - } else { - *arp = cur; - } - - n = recvfrom(t->sock, buf, len, 0, (struct sockaddr *)saddr, slen); - - if(n < 0) { - syslog(LOG_INFO, "recvfrom failed with %s \"%s\"\n", cur->name, strerror(errno)); - close(t->sock); - t->sock = -1; - return(0); - } - - return(n); - } - } - return(0); -} - -static int ping_send(CONFIG *cur) { - char buf[BUFSIZ]; - struct icmp *icp; - PING_DATA *pdp; - TARGET *t; - int n; - int ping_pkt_size; - - t = cur->data; - - gettimeofday(&t->last_send_time, NULL); - - if(cur->check_arp) { - int err; - unsigned char buf[256]; - struct arphdr *ah = (struct arphdr*)buf; - unsigned char *p = (unsigned char *)(ah+1); - - if(cur->dstinfo->ai_family == AF_INET6) { - syslog(LOG_ERR, "%s: %s: ipv6 arping not supported", __FILE__, __FUNCTION__); - return(-1); - } - - ah->ar_hrd = htons(t->me.sll_hatype); - if(ah->ar_hrd == htons(ARPHRD_FDDI)) - ah->ar_hrd = htons(ARPHRD_ETHER); - ah->ar_pro = htons(ETH_P_IP); - ah->ar_hln = t->me.sll_halen; - ah->ar_pln = 4; - ah->ar_op = htons(ARPOP_REQUEST); - - memcpy(p, &t->me.sll_addr, ah->ar_hln); - p += t->me.sll_halen; - - memcpy(p, &t->src, 4); - p += 4; - - memcpy(p, &t->he.sll_addr, ah->ar_hln); - p += ah->ar_hln; - - memcpy(p, &t->dst, 4); - p += 4; - -#if defined(DEBUG) - { - int ind; - for(ind = 0; ind < p - buf; ind ++) { - fprintf(stderr, "%02x", (unsigned char)buf[ind]); - if(!((ind + 1) % 2)) fprintf(stderr, " "); - if(!((ind + 1) % 32)) fprintf(stderr, "\n"); - } - fprintf(stderr, "\n"); - for(ind = 0; ind < p - buf; ind ++) { - fprintf(stderr, "%3u", (unsigned char)buf[ind]); - if(!((ind + 1) % 32)) fprintf(stderr, "\n"); - else fprintf(stderr, ","); - } - fprintf(stderr, "\n"); - } -#endif - - if(t->sock != -1) { - err = sendto(t->sock, buf, p - buf, 0, (struct sockaddr*)&t->he, sizeof(t->he)); - if(err < 0) { - if(cfg.debug >= 9) syslog(LOG_ERR, "arping sendto failed to %s on %s reason \"%s\"", cur->name, cur->device, strerror(errno)); - close(t->sock); - t->sock = -1; - } - } else { - if(cfg.debug >= 9) syslog(LOG_INFO, "arping sendto socket not open for %s", cur->name); - err = -1; - } - - { /* we don't care what the error was just advance with seq */ - int seq; - - seq = t->seq % FOLLOWED_PKTS; - t->sentpkts[seq].seq = t->seq; - t->sentpkts[seq].sent_time = t->last_send_time; - t->sentpkts[seq].flags.replied = 0; - t->sentpkts[seq].flags.timeout = 0; - t->sentpkts[seq].flags.waiting = 1; - if(t->sentpkts[seq].flags.used == 0) t->used++; - t->sentpkts[seq].flags.used = 1; - t->sentpkts[seq].flags.error = (err == -1) ? 1 : 0; - - t->seq = (t->seq + 1) % SEQ_LIMITER; /* limit seq so that consecutive missing and received pkt counting doesn't get confused when seq "overflows" */ - t->num_sent++; - - } - if(err == (p - buf)) { - return(0); - } - return(err); - } - - if(cur->dstinfo->ai_family == AF_INET6) { - struct icmp6_hdr *icp6; - - ping_pkt_size = sizeof(struct icmp6_hdr) + sizeof(PING_DATA); - - memset(buf, 0, ping_pkt_size); - - icp6 = (struct icmp6_hdr *)buf; - - icp6->icmp6_type = ICMP6_ECHO_REQUEST; - icp6->icmp6_code = 0; - icp6->icmp6_seq = htons(t->seq); /* I saw a tcpdump suggesting that there is something wrong with seq thus htons() */ - icp6->icmp6_id = get_ident(); - - pdp = (PING_DATA *)(buf + sizeof(struct icmp6_hdr)); - pdp->ping_count = t->num_sent; - pdp->ping_ts = t->last_send_time; - pdp->id = t->id; - - icp6->icmp6_cksum = 0; /* the ipv6 stack calculates the checksum for us */ - - if(t->sock != -1) { - if(cfg.debug >= 9) syslog(LOG_INFO, "cmsglen = %d", t->cmsglen); - - if(t->cmsglen == 0) { - n = sendto(t->sock, buf, ping_pkt_size, 0, (struct sockaddr *)&t->dst_addr6, sizeof(t->dst_addr6)); - if(n < 0) { - if(errno == ENODEV) { - if(cfg.debug >= 9) syslog(LOG_ERR, "connection %s no such device %s \"%s\"", cur->name, cur->device, strerror(errno)); - } else - if (cfg.debug >= 9) syslog(LOG_ERR, "ping6 sendto failed to %s on %s reason \"%s\"", cur->name, cur->device, strerror(errno)); - - if(t->sock != -1) { - close(t->sock); - t->sock = -1; - } - } - } else { - struct msghdr mhdr; - struct iovec iov; - int confirm = 0; - - iov.iov_len = ping_pkt_size; - iov.iov_base = buf; - - mhdr.msg_name = &t->dst_addr6; - mhdr.msg_namelen = sizeof(struct sockaddr_in6); - mhdr.msg_iov = &iov; - mhdr.msg_iovlen = 1; - mhdr.msg_control = t->cmsgbuf; - mhdr.msg_controllen = t->cmsglen; - - n = sendmsg(t->sock, &mhdr, confirm); - if(cfg.debug >= 9 && n < 0) syslog(LOG_INFO, "sendmsg failed for %s %s", cur->name, strerror(errno)); - if(n < 0) { - close(t->sock); - t->sock = -1; - } - } - } else { - if(cfg.debug >= 9) syslog(LOG_INFO, "ping sendto socket not open for %s", cur->name); - n = -1; - } - { - /* we don't care what the error was just advance with seq */ - int seq; - - seq = t->seq % FOLLOWED_PKTS; -#if defined(DEBUG) - fprintf(stderr, "ping_send seq = %ld to %s, num_sent = %ld, %ld, pkt_size = %d\n", t->seq, inet_ntoa(t->saddr.sin_addr), t->num_sent, pdp->ping_count, ping_pkt_size); -#endif - t->sentpkts[seq].seq = t->seq; - t->sentpkts[seq].sent_time = t->last_send_time; - t->sentpkts[seq].flags.replied = 0; - t->sentpkts[seq].flags.timeout = 0; - t->sentpkts[seq].flags.waiting = 1; - if(t->sentpkts[seq].flags.used == 0) t->used++; - t->sentpkts[seq].flags.used = 1; - t->sentpkts[seq].flags.error = (n < 1) ? 1 : 0; - - t->seq = (t->seq + 1) % SEQ_LIMITER; - /* limit seq so that consecutive missing and received pkt counting doesn't get confused when seq "overflows" */ - t->num_sent++; - } - if(n == ping_pkt_size) { - return(0); - } - - return(n); - } - - /* send a ping packet */ - ping_pkt_size = sizeof(struct icmp) + sizeof(PING_DATA); - - memset(buf, 0, ping_pkt_size); - - icp = (struct icmp *)buf; - - icp->icmp_type = ICMP_ECHO; - icp->icmp_code = 0; - icp->icmp_cksum = 0; - icp->icmp_seq = t->seq; - icp->icmp_id = get_ident(); - - pdp = (PING_DATA *)(buf + sizeof(struct icmp)); - pdp->ping_count = t->num_sent; - pdp->ping_ts = t->last_send_time; - pdp->id = t->id; - - icp->icmp_cksum = in_cksum((u_short *)icp, ping_pkt_size); - - if(t->sock != -1) { - n = sendto(t->sock, buf, ping_pkt_size, 0, (struct sockaddr *)&t->dst_addr, sizeof(struct sockaddr)); - - if(n < 0) { - if(errno == ENODEV) { - if(cfg.debug >= 9) syslog(LOG_ERR, "connection %s no such device %s \"%s\"", cur->name, cur->device, strerror(errno)); - /* exit(2); */ /* commented out. handle this situation like the packet had been sent. see below. */ - } - else - if(cfg.debug >= 9) syslog(LOG_ERR, "ping sendto failed to %s on %s reason \"%s\"", cur->name, cur->device, strerror(errno)); - - if(t->sock != -1) { - close(t->sock); - t->sock = -1; - } - } - } else { - if(cfg.debug >= 9) syslog(LOG_INFO, "ping sendto socket not open for %s", cur->name); - n = -1; - } - - { /* we don't care what the error was just advance with seq */ - int seq; - - seq = t->seq % FOLLOWED_PKTS; -#if defined(DEBUG) - fprintf(stderr, "ping_send seq = %ld to %s, num_sent = %ld, %ld, pkt_size = %d\n", t->seq, inet_ntoa(t->saddr.sin_addr), t->num_sent, pdp->ping_count, ping_pkt_size); -#endif - t->sentpkts[seq].seq = t->seq; - t->sentpkts[seq].sent_time = t->last_send_time; - t->sentpkts[seq].flags.replied = 0; - t->sentpkts[seq].flags.timeout = 0; - t->sentpkts[seq].flags.waiting = 1; - if(t->sentpkts[seq].flags.used == 0) t->used++; - t->sentpkts[seq].flags.used = 1; - t->sentpkts[seq].flags.error = (n < 1) ? 1 : 0; - - t->seq = (t->seq + 1) % SEQ_LIMITER; /* limit seq so that consecutive missing and received pkt counting doesn't get confused when seq "overflows" */ - t->num_sent++; - } - - if(n == ping_pkt_size) { - return(0); - } - return(n); -} - -static int event_script_check(const char *path) -{ - struct stat statbuf; - - if(!path) { - if(cfg.debug >= 9) syslog(LOG_ERR, "NULL pointer event script"); - return(0); - } - - if(!*path) { - if(cfg.debug >= 9) syslog(LOG_ERR, "null string event script"); - return(0); - } - - /* check that the script is owner executable */ - if(stat(path, &statbuf) == -1) { - syslog(LOG_ERR, "failed to stat event script \"%s\" reason \"%s\"", path, strerror(errno)); - return(0); - } - - if((statbuf.st_mode & S_IXUSR) == 0) { - syslog(LOG_ERR, "event script \"%s\" is not executable by owner, please check permissions", path); - return(0); - } - - return(1); -} - -static void init_config_data(CONFIG *first, CONFIG *last, CONFIG ***ctable) -{ - int i; - CONFIG *cur; - TARGET *t = NULL; - - /* initialize config->data */ - for(cur = first, num_hosts = 0; cur; cur = cur->next, num_hosts++) { - u_int ipaddress; - - if((t = malloc(sizeof(TARGET))) == NULL) { - syslog(LOG_ERR, "main: initializing targets failed to malloc"); - exit(1); - } - memset(t, 0, sizeof(TARGET)); - - cur->data = t; - - /* protocol family independent init */ - t->seq = 0; - t->downseq = 0; - t->downseqreported = 0; - t->last_send_time.tv_sec = 0; - t->last_send_time.tv_usec = 0; - t->num_sent = 0; - t->timeout_max = 0; - t->consecutive_missing_max = 0; - t->used = 0; - - memset(t->cmsgbuf, 0, sizeof(t->cmsgbuf)); - t->cmsglen = 0; - - t->id = num_hosts; - - /* get initial connection state assumption from config */ - t->status = cur->status; - - t->sock = -1; - - if(cur->dstinfo->ai_family == AF_INET6) { - /* ipv6 init */ - if(cur->srcinfo) { - if(inet_pton(AF_INET6, cur->sourceip, &t->src6) != 1) { - syslog(LOG_ERR, "%s: %s: src6 inet_pton failed for %s", __FILE__, __FUNCTION__, cur->name); - } - - t->src_addr6.sin6_family = cur->srcinfo->ai_family; - if(inet_pton(AF_INET6, cur->sourceip, &t->src_addr6.sin6_addr) != 1) { - syslog(LOG_ERR, "%s: %s: src6 inet_pton failed for %s", __FILE__, __FUNCTION__, cur->name); - } - } - - if(inet_pton(AF_INET6, cur->checkip, &t->dst6) != 1) { - syslog(LOG_ERR, "%s: %s: dst6 inet_pton failed for %s", __FILE__, __FUNCTION__, cur->name); - } - - t->dst_addr6.sin6_family = cur->dstinfo->ai_family; - if(inet_pton(AF_INET6, cur->checkip, &t->dst_addr6.sin6_addr) != 1) { - syslog(LOG_ERR, "%s: %s: dst6 inet_pton failed for %s", __FILE__, __FUNCTION__, cur->name); - } - } else { - /* ipv4 init */ - ipaddress = inet_addr(cur->checkip); - t->dst_addr.sin_family = AF_INET; - t->dst_addr.sin_addr = *((struct in_addr *)&ipaddress); - t->dst = *((struct in_addr *)&ipaddress); - } - } - - if(((*ctable) = (CONFIG **)malloc(sizeof(CONFIG *) * num_hosts)) == NULL) { - syslog(LOG_ERR, "main: can't malloc for ctable"); - exit(1); - } - - /* create pointer table */ - for(cur = first, i = 0; cur; cur = cur->next, i++) { - (*ctable)[i] = cur; - } - -} - -static int open_arp_sock(CONFIG *cur) -{ - int ifindex = 0; - TARGET *t = (TARGET *)cur->data; - - if(t->sock != -1) return(0); - - if(cur->dstinfo->ai_family == AF_INET6) { - syslog(LOG_ERR, "%s: %s: protocol family is ipv6?", __FILE__, __FUNCTION__); - return(1); - } - - t->sock = socket(PF_PACKET, SOCK_DGRAM, 0); - if(t->sock < 0) { - syslog(LOG_ERR, "could not open socket for %s arp ping \"%s\"", cur->name, strerror(errno)); - t->sock = -1; - return(1); - } - if(fcntl(t->sock, F_SETFD, FD_CLOEXEC) == -1) { - syslog(LOG_ERR, "failed to set close on exec on socket %s reason \"%s\"", cur->name, strerror(errno)); - } - - if(cur->device && *cur->device) { - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, cur->device, IFNAMSIZ-1); - if(ioctl(t->sock, SIOCGIFINDEX, &ifr) < 0) { - syslog(LOG_ERR, "unknown iface \"%s\"", cur->device); - close(t->sock); - t->sock = -1; - return(2); - } - ifindex = ifr.ifr_ifindex; - - if(ioctl(t->sock, SIOCGIFFLAGS, (char*)&ifr)) { - syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) \"%s\"", strerror(errno)); - close(t->sock); - t->sock = -1; - return(2); - } - if(!(ifr.ifr_flags&IFF_UP)) { - syslog(LOG_ERR, "Interface \"%s\" is down", cur->device); - close(t->sock); - t->sock = -1; - return(2); - } - if(ifr.ifr_flags&(IFF_NOARP|IFF_LOOPBACK)) { - syslog(LOG_ERR, "Interface \"%s\" is not ARPable", cur->device); - close(t->sock); - t->sock = -1; - return(2); - } - } - - if(inet_aton(cur->checkip, &t->dst) != 1) { - struct hostent *hp; - hp = gethostbyname2(cur->checkip, AF_INET); - if(!hp) { - syslog(LOG_ERR, "unknown host %s\n", cur->checkip); - close(t->sock); - t->sock = -1; - return(2); - } - memcpy(&t->dst, hp->h_addr, 4); - } - - if(cur->sourceip && *cur->sourceip) - if(inet_aton(cur->sourceip, &t->src) != 1) { - syslog(LOG_ERR, "invalid source %s\n", cur->sourceip); - close(t->sock); - t->sock = -1; - return(2); - } - - if(probe_src_ip_addr(cur) != 0) { - close(t->sock); - t->sock = -1; - return(2); - } - - t->me.sll_family = AF_PACKET; - t->me.sll_ifindex = ifindex; - t->me.sll_protocol = htons(ETH_P_ARP); - if(bind(t->sock, (struct sockaddr*)&t->me, sizeof(t->me)) == -1) { - syslog(LOG_ERR, "bind \"%s\"", strerror(errno)); - close(t->sock); - t->sock = -1; - return(2); - } - - { - int alen = sizeof(t->me); - if(getsockname(t->sock, (struct sockaddr*)&t->me, (socklen_t*)&alen) == -1) { - syslog(LOG_ERR, "getsockname \"%s\"", strerror(errno)); - close(t->sock); - t->sock = -1; - return(2); - } - } - if(t->me.sll_halen == 0) { - syslog(LOG_ERR, "Interface \"%s\" is not ARPable (no ll address)", cur->device); - close(t->sock); - t->sock = -1; - return(2); - } - - t->he = t->me; - memset(t->he.sll_addr, -1, min(t->he.sll_halen, sizeof t->he.sll_addr)); - -#if 0 - printf("ARPING %s ", inet_ntoa(t->dst)); - printf("from %s %s\n", inet_ntoa(t->src), cur->device ? : ""); -#endif - - if(!t->src.s_addr) { - syslog(LOG_ERR, "no source address for %s", cur->name); - close(t->sock); - t->sock = -1; - return(2); - } - if(cur->ttl) { - int ittl = cur->ttl; - if(setsockopt(t->sock, IPPROTO_IP, IP_MULTICAST_TTL, - &cur->ttl, 1) == -1) { - syslog(LOG_ERR, "can't set multicast time-to-live \"%s\"", strerror(errno)); - close(t->sock); - t->sock = -1; - return(2); - } - if(setsockopt(t->sock, IPPROTO_IP, IP_TTL, - &ittl, sizeof(ittl)) == -1) { - syslog(LOG_ERR, "can't set unicast time-to-live \"%s\"", strerror(errno)); - close(t->sock); - t->sock = -1; - return(2); - } - } - - return(0); -} - -static int open_icmp_sock(CONFIG *cur) -{ - TARGET *t = (TARGET *)cur->data; - struct protoent *proto; - int pf = cur->dstinfo->ai_family; - - if(t->sock != -1) return(0); - - if(pf == AF_INET6) { - if((proto = getprotobyname("ipv6-icmp")) == NULL) { - syslog(LOG_ERR, "no ipv6-icmp proto found"); - return(1); - } - } else { - if((proto = getprotobyname("icmp")) == NULL) { - syslog(LOG_ERR, "no icmp proto found"); - return(1); - } - } - - t->sock = socket(pf, SOCK_RAW, proto->p_proto); - - if(t->sock < 0) { - syslog(LOG_ERR, "could not open socket for ping target \"%s\" reason \"%s\"\n", cur->name, strerror(errno)); - t->sock = -1; - return(1); - } - if(fcntl(t->sock, F_SETFD, FD_CLOEXEC) == -1) { - syslog(LOG_ERR, "failed to set close on exec on socket %s reason \"%s\"", cur->name, strerror(errno)); - } - - if(pf == AF_INET6) { - int opton = 1; - -#ifdef IPV6_RECVHOPOPTS - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(IPV6_RECVHOPOPTS)"); - close(t->sock); - t->sock = -1; - return(2); - } -#else /* old adv. API */ - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_HOPOPTS, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(IPV6_HOPOPTS)"); - close(t->sock); - t->sock = -1; - return(s); - } -#endif -#ifdef IPV6_RECVDSTOPTS - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(IPV6_RECVDSTOPTS)"); - close(t->sock); - t->sock = -1; - return(2); - } -#else /* old adv. API */ - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_DSTOPTS, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(IPV6_DSTOPTS)"); - close(t->sock); - t->sock = -1; - return(2); - } -#endif -#ifdef IPV6_RECVRTHDRDSTOPTS - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(IPV6_RECVRTHDRDSTOPTS)"); - close(t->sock); - t->sock = -1; - return(2); - } -#endif -#ifdef IPV6_RECVRTHDR - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(IPV6_RECVRTHDR)"); - close(t->sock); - t->sock = -1; - return(2); - } -#else /* old adv. API */ - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RTHDR, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(IPV6_RTHDR)"); - close(t->sock); - t->sock = -1; - return(2); - } -#endif -#ifndef USE_SIN6_SCOPE_ID -#ifdef IPV6_RECVPKTINFO - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(IPV6_RECVPKTINFO)"); - close(t->sock); - t->sock = -1; - return(2); - } -#else /* old adv. API */ - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_PKTINFO, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(IPV6_PKTINFO)"); - close(t->sock); - t->sock = -1; - return(2); - } -#endif -#endif /* USE_SIN6_SCOPE_ID */ -#ifdef IPV6_RECVHOPLIMIT - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(IPV6_RECVHOPLIMIT)"); - close(t->sock); - t->sock = -1; - return(2); - } -#else /* old adv. API */ - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(IPV6_HOPLIMIT)"); - close(t->sock); - t->sock = -1; - return(2); - } -#endif -#ifdef IPV6_CHECKSUM -#ifndef SOL_RAW -#define SOL_RAW IPPROTO_IPV6 -#endif - opton = 2; - - if(setsockopt(t->sock, SOL_RAW, IPV6_CHECKSUM, &opton, - sizeof(opton))) { - syslog(LOG_ERR, "setsockopt(SOL_RAW,IPV6_CHECKSUM)"); - close(t->sock); - t->sock = -1; - return(2); - } -#endif - } - - if(pf == AF_INET6) { - int hold = 1; - - ICMP6_FILTER_SETBLOCKALL(&t->filter); - - if (setsockopt(t->sock, SOL_IPV6, IPV6_RECVERR, (char *)&hold, sizeof(hold))) { - syslog(LOG_INFO, "WARNING: your kernel is veeery old. No problems."); - - ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &t->filter); - ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &t->filter); - ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &t->filter); - ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &t->filter); - } - - ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &t->filter); - - if(setsockopt(t->sock, IPPROTO_ICMPV6, ICMP6_FILTER, &t->filter, sizeof(struct icmp6_filter)) < 0) { - syslog(LOG_ERR, "setsockopt(ICMP6_FILTER)"); - return(2); - } - } - - if(cur->ttl) { - if(pf == AF_INET6) { - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - &cur->ttl, sizeof(cur->ttl)) == -1) { - syslog(LOG_ERR, "can't set multicast hop limit \"%s\"", strerror(errno)); - close(t->sock); - t->sock = -1; - return(2); - } - if(setsockopt(t->sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, - &cur->ttl, sizeof(cur->ttl)) == -1) { - syslog(LOG_ERR, "can't set unicast hop limit \"%s\"", strerror(errno)); - close(t->sock); - t->sock = -1; - return(2); - } - } else if(pf == AF_INET) { /* AF_INET */ - int ittl = cur->ttl; - if(setsockopt(t->sock, IPPROTO_IP, IP_MULTICAST_TTL, - &cur->ttl, 1) == -1) { - syslog(LOG_ERR, "can't set multicast time-to-live \"%s\"", strerror(errno)); - close(t->sock); - t->sock = -1; - return(2); - } - if(setsockopt(t->sock, IPPROTO_IP, IP_TTL, - &ittl, sizeof(ittl)) == -1) { - syslog(LOG_ERR, "can't set unicast time-to-live \"%s\"", strerror(errno)); - close(t->sock); - t->sock = -1; - return(2); - } - } - } - - if(pf == AF_INET && cur->device && *cur->device) { - if(setsockopt(t->sock, SOL_SOCKET, SO_BINDTODEVICE, cur->device, strlen(cur->device) + 1) == -1) { - syslog(LOG_INFO, "failed to bind to ping interface device \"%s\", \"%s\"", cur->device, strerror(errno)); - close(t->sock); - t->sock = -1; - return(2); - } - } - -#if defined(DEBUG) - if(cfg.debug >= 9) syslog(LOG_INFO, "%s: %s: probing for src ip for %s", __FILE__, __FUNCTION__, cur->name); -#endif - if(probe_src_ip_addr(cur) != 0) { - close(t->sock); - t->sock = -1; - return(2); - } -#if defined(DEBUG) - if(cfg.debug >= 9) syslog(LOG_INFO, "%s: %s: probing for src ip for %s done", __FILE__, __FUNCTION__, cur->name); -#endif - if(cur->sourceip && *cur->sourceip) { - if(cur->srcinfo->ai_family == AF_INET) { - struct sockaddr_in addr; - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr(cur->sourceip); - - if(bind(t->sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) { - syslog(LOG_ERR, "ping can't bind \"%s\"", strerror(errno)); - return(1); - } - } else { - struct sockaddr_in6 addr; -#if defined(DEBUG) - if(cfg.debug >= 9) syslog(LOG_INFO, "%s: %s: setting v6 src addr", __FILE__, __FUNCTION__); -#endif - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - if(inet_pton(AF_INET6, cur->sourceip, &addr.sin6_addr) != 1) { - syslog(LOG_ERR, "ping6 failed to convert connection %s address %s", cur->name, cur->sourceip); - return(1); - } - if(bind(t->sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) { - syslog(LOG_ERR, "ping6 can't bind %s to %s, \"%s\"", cur->name, cur->sourceip, strerror(errno)); - return(1); - } -#if defined(DEBUG) - if(cfg.debug >= 9) syslog(LOG_INFO, "%s: %s: setting v6 src addr done", __FILE__, __FUNCTION__); -#endif - } - } - - if(pf == AF_INET6 && cur->device && *cur->device) { - struct ifreq ifr; - struct cmsghdr *cmsg; - struct in6_pktinfo *ipi; - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, cur->device, IFNAMSIZ-1); - if(ioctl(t->sock, SIOCGIFINDEX, &ifr) < 0) { - syslog(LOG_ERR, "ping6 unknown iface %s", cur->device); - return(2); - } - - memset(&t->cmsgbuf, 0, sizeof(t->cmsgbuf)); - t->cmsglen = 0; - - cmsg = (struct cmsghdr *)t->cmsgbuf; - t->cmsglen += CMSG_SPACE(sizeof(*ipi)); - cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi)); - cmsg->cmsg_level = SOL_IPV6; - cmsg->cmsg_type = IPV6_PKTINFO; - - ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg); - memset(ipi, 0, sizeof(*ipi)); - ipi->ipi6_ifindex = ifr.ifr_ifindex; - } - - return(0); -} - -static int probe_src_ip_addr(CONFIG *cur) -{ /* probe for src ip address */ - TARGET *t = (TARGET *)cur->data; - int probe_fd; - int pf = cur->dstinfo->ai_family; - - probe_fd = socket(pf, SOCK_DGRAM, 0); - - if(probe_fd < 0) { - syslog(LOG_ERR, "ping probe socket for %s failed \"%s\"", cur->name, strerror(errno)); - return(2); - } - if(fcntl(t->sock, F_SETFD, FD_CLOEXEC) == -1) { - syslog(LOG_ERR, "ping probe failed to set close on exec on probe socket for %s reason \"%s\"", cur->name, strerror(errno)); - } - - if(cur->device && *cur->device) { - if(setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, cur->device, strlen(cur->device) + 1) == -1) - syslog(LOG_INFO, "WARNING: ping probe interface \"%s\" is ignored for %s reason \"%s\"", cur->device, cur->name, strerror(errno)); - } - - if(pf == AF_INET) { - struct sockaddr_in saddr; - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - if(t->src.s_addr) { - saddr.sin_addr = t->src; - if(bind(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) { - syslog(LOG_ERR, "ping probe bind failed for %s \"%s\"", cur->name, strerror(errno)); - close(probe_fd); - /* earlier probed src addr is not usable, wipe it */ - memset(&t->src, 0, sizeof(t->src)); - return(2); - } - } - else { - int on = 1; - int alen = sizeof(saddr); - - saddr.sin_port = htons(1025); - saddr.sin_addr = t->dst; - - if(setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, (char*)&on, sizeof(on)) == -1) - syslog(LOG_INFO, "WARNING: ping probe setsockopt(SO_DONTROUTE) \"%s\"", strerror(errno)); - if(connect(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) { - syslog(LOG_ERR, "ping probe connect for %s failed \"%s\"", cur->name, strerror(errno)); - close(probe_fd); - return(2); - } - if(getsockname(probe_fd, (struct sockaddr*)&saddr, (socklen_t*)&alen) == -1) { - syslog(LOG_ERR, "ping probe getsockname for %s failed \"%s\"", cur->name, strerror(errno)); - close(probe_fd); - return(2); - } - t->src = saddr.sin_addr; - } - } else if (pf == AF_INET6) { /* not AF_INET */ - struct sockaddr_in6 saddr; - unsigned char nulladdr[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - - memset(&saddr, 0, sizeof(saddr)); - saddr.sin6_family = AF_INET6; - if(memcmp(&t->src6, nulladdr, sizeof(t->src6)) != 0) { /* is not null addr */ - memcpy(&saddr.sin6_addr, &t->src6, sizeof(t->src6)); - if(bind(probe_fd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { - syslog(LOG_ERR, "ping6 probe bind failed for %s \"%s\"", cur->name,strerror(errno)); - close(probe_fd); - /* earlier probed src addr is not usable, wipe it */ - memset(&t->src6, 0, sizeof(t->src6)); - return(2); - } - } else { /* is null addr */ - socklen_t alen = sizeof(saddr); - - saddr.sin6_port = htons(1025); - saddr.sin6_family = cur->dstinfo->ai_family; - memcpy(&saddr.sin6_addr, &t->dst6, sizeof(t->dst6)); -#if 0 - if(setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)) == -1) - syslog(LOG_INFO, "WARNING: ping6 probe setsockopt(SO_DONTROUTE) for %s \"%s\"", cur->name, strerror(errno)); -#endif - if(connect(probe_fd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { - syslog(LOG_ERR, "ping6 probe connect for %s failed \"%s\"", cur->name, strerror(errno)); - close(probe_fd); - return(2); - } - if(getsockname(probe_fd, (struct sockaddr *)&saddr, &alen) == -1) { - syslog(LOG_ERR, "ping6 probe getsockname for %s failed \"%s\"", cur->name, strerror(errno)); - close(probe_fd); - return(2); - } - memcpy(&t->src6, &saddr.sin6_addr, sizeof(saddr.sin6_addr)); - } - } /* if AF_INET */ - - close(probe_fd); - - return(0); -} - -#if defined(DEBUG) -static void dump_pkt(const void *buf, size_t len) -{ - int i; - unsigned char *s; - char obuf[BUFSIZ]; - char *pad; - - memset(obuf, 0, BUFSIZ); - - s = (unsigned char *)buf; - pad = ""; - for(i = 0; i < len && i < BUFSIZ; i++) { - snprintf(obuf + strlen(obuf), BUFSIZ, "%s%02x", pad, s[i]); - pad = " "; - } - - syslog(LOG_INFO, "%s: %s: hexdump %s", __FILE__, __FUNCTION__, obuf); - - memset(obuf, 0, BUFSIZ); - - s = (unsigned char *)buf; - pad = ""; - for(i = 0; i < len && i < BUFSIZ; i++) { - snprintf(obuf + strlen(obuf), BUFSIZ, "%s%03d", pad, s[i]); - pad = " "; - } - - syslog(LOG_INFO, "%s: %s: decdump %s", __FILE__, __FUNCTION__, obuf); -} -#endif - -/* EOF */ diff --git a/lsm.conf b/lsm.conf deleted file mode 100644 index 14473e0..0000000 --- a/lsm.conf +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright (C) 2009-2015 Mika Ilmaranta -# -# License: GPLv2 -# - -# -# Debug level: 0 .. 8 are normal, 9 gives lots of stuff and 100 doesn't -# bother to detach -# -#debug=10 -#debug=9 -#debug=8 - -# -# Defaults for the connection entries -# These are set in the code. You may override any values here. -# -#defaults { -# name=defaults -# checkip=127.0.0.1 -# eventscript= -# notifyscript=/usr/libexec/lsm/default_script -# max_packet_loss=15 -# max_successive_pkts_lost=7 -# min_packet_loss=5 -# min_successive_pkts_rcvd=10 -# interval_ms=1000 -# timeout_ms=1000 -# warn_email=root -# check_arp=0 -# sourceip= -# if using ping probes for monitoring only then defaults should -# not define a default device for packets to autodiscover their path -# to destination -# device=eth0 -# use system default ttl -# ttl=0 -# assume initial up state at lsm startup -# (1 = up, 0 = down, 2 = unknown (default)) -# status=1 -# how many packets have to go through before a connection is declared up -# (0 = disabled) -# startup_acceleration=0 -# send first 10 packets in a burst (0 = disabled) with interval 200ms -# startup_burst_pkts=10 -# startup_burst_interval=200 -#} - -# -# Some example connections are found in lsm.conf.sample -# - --include /etc/lsm/local*.conf - -#EOF diff --git a/lsm.conf.sample b/lsm.conf.sample deleted file mode 100644 index 9a6f187..0000000 --- a/lsm.conf.sample +++ /dev/null @@ -1,144 +0,0 @@ -# -# (C) 2009 Mika Ilmaranta -# -# License: GPLv2 -# - -# -# Debug level: 0 .. 8 are normal, 9 gives lots of stuff and 100 doesn't -# bother to detach -# -#debug=10 -#debug=9 -debug=8 - -# -# Defaults for the connection entries -# -defaults { - name=defaults - checkip=127.0.0.1 - eventscript=/usr/libexec/lsm/default_script - max_packet_loss=15 - max_successive_pkts_lost=7 - min_packet_loss=5 - min_successive_pkts_rcvd=10 - interval_ms=1000 - timeout_ms=1000 - warn_email=root - check_arp=0 - sourceip= -# if using ping probes for monitoring only then defaults should -# not define a default device for packets to autodiscover their path -# to destination -# device=eth0 -# use system default ttl - ttl=0 -# assume initial up state at lsm startup (1 = up, 0 = down, 2 = unknown (default)) -# status=1 -} - -# -# Some example connections -# NOTE: don't use any white space in name ... -# -# connection { -# name=connection-1 -# checkip=127.108.68.69 -# eventscript=/usr/libexec/lsm/conn1 -# max_packet_loss=15 -# max_successive_pkts_lost=7 -# min_packet_loss=5 -# min_successive_pkts_rcvd=10 -# interval_ms=1000 -# timeout_ms=1000 -# warn_email=root1@some.tld -# check_arp=0 -# sourceip= -# device= -# ttl=64 -# } - -# connection { -# name=connection-2 -# checkip=127.108.68.65 -# eventscript=/usr/libexec/lsm/conn2 -# max_packet_loss=15 -# max_successive_pkts_lost=7 -# min_packet_loss=5 -# min_successive_pkts_rcvd=10 -# interval_ms=1000 -# timeout_ms=1000 -# warn_email=root2@some.tld -# check_arp=0 -# sourceip= -# device= -# ttl=64 -# } - -# connection { -# name=connection-3 -# checkip=127.108.68.68 -# eventscript=/usr/libexec/lsm/conn3 -# max_packet_loss=15 -# max_successive_pkts_lost=7 -# min_packet_loss=5 -# min_successive_pkts_rcvd=10 -# interval_ms=1000 -# timeout_ms=1000 -# warn_email=root3@some.tld -# check_arp=0 -# sourceip= -# device= -# ttl=64 -# } - -# connection { -# name=connection-4 -# checkip=127.108.68.75 -# } - -# -# Arping example -# -# connection { -# name=connection-5 -# checkip=127.108.68.71 -# check_arp=1 -# # if the remote end is not behind the defaults device -# # then you have to set this -# device=eth0 -# # setting source ip is not mandatory -# sourceip=127.108.68.68 -# # use system default ttl -# ttl=0 -# } - -# -# Group example -# -# connection { -# name=conn-a -# checkip=127.108.68.99 -# eventscript= -# } -# -# connection { -# name=conn-b -# checkip=127.108.68.100 -# eventscript= -# } -# -# group { -# name=conn-group-a -# eventscript=/usr/libexec/lsm/default_script -# warn_email=root@some.domain.tld -# # logic between member connetion statuses -# # logic=0 == or -# # logic=1 == and -# logic=0 -# member-connection=conn-a -# member-connection=conn-b -# } - -#EOF diff --git a/lsm.h b/lsm.h deleted file mode 100644 index 1728a3b..0000000 --- a/lsm.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - -(C) 2013 Mika Ilmaranta - -License: GPLv2 - -*/ - -#ifndef __LSM_H__ -#define __LSM_H__ - -#include /* for struct sockaddr_in */ -#include /* for struct sockadd_ll */ -#include /* for struct icmp6_filter */ - -#include "defs.h" - -typedef struct sentpkt { - unsigned short seq; - struct timeval sent_time; - struct timeval replied_time; - unsigned long rtt; - struct { - unsigned replied:1; - unsigned timeout:1; - unsigned waiting:1; - unsigned used:1; - unsigned error:1; - } flags; -} SENTPKT; - -typedef struct target { - unsigned short id; /* target id */ - unsigned short seq; - unsigned short downseq; - unsigned short downseqreported; - struct timeval down_timestamp; - struct sockaddr_in src_addr; - struct sockaddr_in dst_addr; - struct sockaddr_in6 src_addr6; - struct sockaddr_in6 dst_addr6; - struct sockaddr_ll me; /* arping only */ - struct sockaddr_ll he; /* arping only */ - struct in_addr src; - struct in_addr dst; - struct in6_addr src6; - struct in6_addr dst6; - unsigned long num_sent; - struct timeval last_send_time; - STATUS status; - int sock; - unsigned char cmsgbuf[4096]; - int cmsglen; - struct icmp6_filter filter; - SENTPKT sentpkts[FOLLOWED_PKTS]; - int timeout; - int timeout_max; - int replied; - int waiting; - int reply_late; - int used; - int consecutive_waiting; - int consecutive_missing; - int consecutive_missing_max; - int consecutive_rcvd; - long avg_rtt; - int status_change; -} TARGET; - -#endif - -/* EOF */ diff --git a/lsm.init b/lsm.init deleted file mode 100644 index eb4f868..0000000 --- a/lsm.init +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/sh -# -# /etc/init.d/lsm -# -# This shellscript takes care of starting and stopping lsm. -# -# chkconfig: - 79 31 -# description: Lsm, Link Status Monitor -# -### BEGIN INIT INFO -# Provides: lsm -# Required-Start: $network $syslog -# Required-Stop: -# Default-Stop: 0 1 6 -# Short-Description: LSM - link status monitor -# Description: LSM is the link status monitor -# LSM can ping multiple targets and when up or down event happens -# it will execute user configured external script so it can be used -# as poor man's routing protocol. -### END INIT INFO - -# Source function library. -. /etc/init.d/functions - -# Source networking configuration. -. /etc/sysconfig/network - -# Check that networking is up. -[ ${NETWORKING} = "no" ] && exit 0 - -CONFIGFILE="/etc/lsm/lsm.conf" -PIDFILE="/var/run/lsm.pid" - -[ -f /etc/sysconfig/lsm ] && . /etc/sysconfig/lsm -[ -x /usr/sbin/lsm ] || exit 0 - -RETVAL=0 - -start() { - echo -n $"Starting lsm: " - daemon --pidfile=${PIDFILE} /usr/sbin/lsm --config $CONFIGFILE --pidfile $PIDFILE - RETVAL=$? - /bin/usleep 10000 - echo - [ $RETVAL = 0 ] && touch /var/lock/subsys/lsm - return $RETVAL -} - -stop() { - echo -n $"Stopping lsm: " - killproc /usr/sbin/lsm - RETVAL=$? - echo - [ $RETVAL = 0 ] && rm -f /var/lock/subsys/lsm - return $RETVAL -} - -restart() { - stop - start -} - -reload() { - echo -n $"Reloading lsm: " - killproc -p ${PIDFILE} /usr/sbin/lsm -HUP - RETVAL=$? - echo - return $RETVAL -} - -# See how we were called. -case "$1" in - start) - start - ;; - stop) - stop - ;; - restart) - restart - ;; - reload) - reload - ;; - condrestart) - [ -f /var/lock/subsys/lsm ] && restart - ;; - status) - status -p ${PIDFILE} lsm - RETVAL=$? - ;; - *) - echo "Usage: lsm {start|stop|restart|condrestart|status}" - RETVAL=2 -esac - -exit $RETVAL diff --git a/lsm.service b/lsm.service deleted file mode 100644 index 4b3ed8c..0000000 --- a/lsm.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=LSM is the link status monitor -Documentation=http://lsm.foobar.fi/ -Wants=network-online.target -After=network-online.target shorewall.service shorewall6.service - -[Service] -Type=simple -ExecStart=/usr/sbin/lsm --config /etc/lsm/lsm.conf --no-fork -ExecReload=/bin/kill -HUP $MAINPID -Restart=on-abort - -[Install] -WantedBy=multi-user.target diff --git a/lsm.spec b/lsm.spec deleted file mode 100644 index 61e9d90..0000000 --- a/lsm.spec +++ /dev/null @@ -1,887 +0,0 @@ -#define devel 1 - -Summary: The Link Status Monitor -Name: lsm -Version: 1.0.5 -Release: 1%{?dist} -License: GPLv2 -Group: System Environment/Daemons -URL: http://lsm.foobar.fi/ -Source: %{name}-%{version}.tar.gz -%if 0%{?rhel} >= 7 || 0%{?fedora} -%bcond_without systemd # enabled -Requires(post): systemd -Requires(preun): systemd -Requires(postun): systemd -BuildRequires: systemd -%else -%bcond_with systemd # disabled -Requires(post): chkconfig -Requires(postun): /sbin/service -Requires(preun): /sbin/service -Requires(preun): chkconfig -%endif -%if 0%{?rhel} && 0%{?rhel} <= 5 -%global _sharedstatedir /var/lib -%endif -Requires: mailx -%if 0%{?devel} -BuildRequires: ElectricFence -%endif -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -%description -Lsm is the link status monitor. - -Lsm can ping multiple targets and when up or down event happens -it will execute user configured external script so it can be used -as poor man's routing protocol. - -%prep -%setup -q - -%build -EFENCE= -%if 0%{?devel} -# Disable -O2 temporarily -RPM_OPT_FLAGS="$(echo "%{optflags}" | sed 's/-O.\ / /')" -EFENCE="-lefence" -%endif -make PREFIX=%{_prefix} CFLAGS="$RPM_OPT_FLAGS" LDFLAGS=${EFENCE} %{?_smp_mflags} - -%install -rm -rf %{buildroot} - -mkdir -p %{buildroot}%{_sysconfdir}/lsm -mkdir -p %{buildroot}%{_sbindir} -mkdir -p %{buildroot}%{_libexecdir}/lsm -mkdir -p %{buildroot}%{_sharedstatedir}/lsm - -install -m0755 lsm %{buildroot}%{_sbindir} -install -m0644 lsm.conf %{buildroot}%{_sysconfdir}/lsm -install -m0755 default_script group_script shorewall_script shorewall6_script \ - %{buildroot}%{_libexecdir}/lsm/ - -%if %{with systemd} -mkdir -p %{buildroot}%{_unitdir} -install -m0644 lsm.service %{buildroot}%{_unitdir}/ -%else -mkdir -p %{buildroot}%{_initrddir} -install -m0755 lsm.init %{buildroot}%{_initrddir}/lsm -# Compat symlinks for older system versions -mkdir -p %{buildroot}%{_datadir}/lsm -ln -s ../../libexec/lsm/shorewall_script \ - %{buildroot}%{_datadir}/lsm/ -ln -s ../../libexec/lsm/default_script \ - %{buildroot}%{_datadir}/lsm/ -%endif - -%clean -rm -rf %{buildroot} - -%post -%if %{with systemd} -%systemd_post lsm.service -%else -/sbin/chkconfig --add lsm -%endif - -%preun -%if %{with systemd} -%systemd_preun lsm.service -%else -if [ $1 -eq 0 ]; then - /sbin/service lsm stop >/dev/null 2>&1 || : - /sbin/chkconfig --del lsm -fi -%endif - -%postun -%if %{with systemd} -%systemd_postun_with_restart lsm.service -%else -if [ $1 -ge 1 ]; then - /sbin/service lsm condrestart >/dev/null 2>&1 || : -fi -%endif - - -%files -%defattr(-,root,root) -%doc README lsm.conf.sample default_script.sample rsyslog-lsm.conf.sample -%if %{with systemd} -%{_unitdir}/lsm.service -%else -%{_initrddir}/lsm -%dir %{_datadir}/lsm -%{_datadir}/lsm/default_script -%{_datadir}/lsm/shorewall_script -%endif -%dir %{_libexecdir}/lsm -%{_libexecdir}/lsm/default_script -%{_libexecdir}/lsm/group_script -%{_libexecdir}/lsm/shorewall_script -%{_libexecdir}/lsm/shorewall6_script -%dir %{_sysconfdir}/lsm -%config(noreplace) %{_sysconfdir}/lsm/lsm.conf -%{_sbindir}/lsm -%dir %{_sharedstatedir}/lsm - -%changelog -* Fri May 13 2016 Mika Ilmaranta - 1.0.5-1 -- patches from Lucas de Castro Borges for Debian -- exept for POSIX compliancy scriptdir PREFIX/libexec/lsm - -* Tue Jan 26 2016 Mika Ilmaranta - 1.0.4-1 -- For systemd start after shorewall otherwise shorewall_script - may be executed too early - -* Fri Dec 4 2015 Mika Ilmaranta - 1.0.3-1 -- recursive read_config reported errors many times - -* Fri Dec 4 2015 Mika Ilmaranta - 1.0.2-1 -- call init_config in reload_config - -* Fri Dec 4 2015 Mika Ilmaranta - 1.0.1-1 -- double free() fix? - -* Thu Nov 19 2015 Mika Ilmaranta - 1.0-1 -- script API change. pass empty strings to scripts without converting to - "-" or "NA". -- include and -include now support patterns - -* Tue Nov 17 2015 Mika Ilmaranta - 0.195-1 -- fix dynamic memory handling in sane values in code. - -* Mon Nov 16 2015 Mika Ilmaranta - 0.194-1 -- set sane values in code. overridable in config defaults section as - before. - -* Sat Oct 31 2015 Mika Ilmaranta - 0.193-1 -- use full path for -included file - -* Fri Oct 30 2015 Mika Ilmaranta - 0.192-1 -- default_script: run date after checks - -* Fri Oct 30 2015 Mika Ilmaranta - 0.191-1 -- support for -include aka ignore include errors if file is missing - -* Fri Oct 23 2015 Mika Ilmaranta - 0.190-1 -- fix groups_decide logic when group logic is 'or'. Thanks to - Filippo Carletti for noticing there was a problem. - -* Mon Jun 1 2015 Mika Ilmaranta - 0.189-1 -- update stats must not clear target used count - -* Mon Jun 1 2015 Mika Ilmaranta - 0.188-1 -- moved target used slots book keeping to send function - -* Mon Jun 1 2015 Mika Ilmaranta - 0.187-1 -- update stats after each ping round so that startup burst can use used slot - count - -* Mon Jun 1 2015 Mika Ilmaranta - 0.186-1 -- dump startup acceleration and startup burst config also -- startup acceleration logic fix - -* Mon Jun 1 2015 Mika Ilmaranta - 0.185-1 -- startup burst logic rewrite - -* Mon Jun 1 2015 Mika Ilmaranta - 0.184-1 -- two separate config params for startup burst - -* Sun May 31 2015 Mika Ilmaranta - 0.183-1 -- startup acceleration configurable -- startup burst configurable - -* Sun May 31 2015 Tuomo Soini - 0.182-1 -- add shorewall6_script and group_script -- install scripts to /usr/libexec/lsm -- add compatibility symlinks to /usr/share/lsm - -* Fri May 29 2015 Mika Ilmaranta - 0.181-1 -- accelerate decision at startup, must have received at least one packet - -* Fri May 29 2015 Mika Ilmaranta - 0.180-1 -- accelerate decision at startup - -* Tue Feb 3 2015 Mika Ilmaranta - 0.179-1 -- lsm.service use correct path for the binary - -* Wed Jan 14 2015 Mika Ilmaranta - 0.178-1 -- export status info to separate file -- cleaned up compilation with different sets of NO_PLUGIN_EXPORT defines - -* Mon Jan 12 2015 Mika Ilmaranta - 0.177-1 -- export connection statuses to plugin directory - -* Sun Jan 11 2015 Mika Ilmaranta - 0.176-1 -- log status with other attributes (Luigi Iotti) - -* Sat Sep 13 2014 Mika Ilmaranta - 0.175-1 -- if --no-fork don't write pid file - -* Sat Sep 13 2014 Mika Ilmaranta - 0.174-1 -- systemd support - -* Wed Aug 6 2014 Mika Ilmaranta - 0.173-1 -- fixed -v parameter - -* Wed Aug 6 2014 Mika Ilmaranta - 0.172-1 -- better usage help -- fixed bug in optarg use - -* Wed Aug 6 2014 Mika Ilmaranta - 0.171-1 -- split source for pidfile processing -- real cmdline argument processing with optarg -- support no-daemon cmdline option for integration with systemd -- debug level 100 no longer suppresses daemonization use the above - mentioned cmdline option instead - -* Sun Feb 16 2014 Mika Ilmaranta - 0.170-1 -- Makefile: debian frendlier install target - -* Sun Feb 16 2014 Mika Ilmaranta - 0.169-1 -- Makefile: install target, not guaranteed to work -- README: updated with INSTALL section - -* Fri Nov 22 2013 Mika Ilmaranta - 0.168-1 -- zero timeout_max and consecutive_missing_max in dump_statuses if there is - status_change to up state not in decide - -* Fri Nov 22 2013 Mika Ilmaranta - 0.167-1 -- update timeout_max and consecutive_missing_max regardless of state - -* Fri Nov 22 2013 Mika Ilmaranta - 0.166-1 -- added timeout_max - -* Fri Nov 22 2013 Mika Ilmaranta - 0.165-1 -- drop max_successive_waiting, it delivers no additional info -- renamed max_successive_missing to successive_missing_max - -* Fri Nov 22 2013 Mika Ilmaranta - 0.164-1 -- added max_successive_waiting and max_successive_missing -- cfg.debug controls now how much info is syslogged on dump_status - debug >= 6, log calculated connection status - debug >= 7, log connection probe statuses - -* Fri Aug 9 2013 Mika Ilmaranta - 0.163-1 -- don't suppress all up notifies when unknown_up_notify is off - -* Thu Jul 25 2013 Mika Ilmaranta - 0.162-1 -- option to skip executing notify script on unknown to up event for groups - also - -* Thu Jul 25 2013 Mika Ilmaranta - 0.161-1 -- added option to skip executing notify script on unknown to up event - -* Thu Jul 25 2013 Mika Ilmaranta - 0.160-1 -- moved save/restore statuses to their own file from lsm.c - -* Wed Jul 24 2013 Mika Ilmaranta - 0.159-1 -- updated shorewall_script with new parameters - -* Wed Jul 24 2013 Mika Ilmaranta - 0.158-1 -- clean up munin titles - -* Tue Jul 23 2013 Mika Ilmaranta - 0.157-1 -- use connection names in munin labels - -* Fri Jul 19 2013 Mika Ilmaranta - 0.156-1 -- plugin_export: changed strlower to munin_src_name - -* Thu Jul 18 2013 Mika Ilmaranta - 0.155-1 -- plugin_export: export statistics for munin - -* Wed Jul 17 2013 Mika Ilmaranta - 0.154-1 -- fixed divide error - -* Wed Jul 17 2013 Mika Ilamranta - 0.153-1 -- lsm.c: drop casts and keep avg_rtt in usec, divide by 1000.0 if needed as - float - -* Wed Jul 17 2013 Mika Ilmaranta - 0.152-1 -- lsm.c: cast avg_rtt for fork_exec - -* Wed Jul 17 2013 Mika Ilmaranta - 0.151-1 -- prepare for exporting statistics to zabbix and munin - -* Wed Jul 10 2013 Mika Ilmaranta - 0.150-1 -- lsm.c: change status to up directly from long_down - -* Tue Jul 9 2013 Mika Ilmaranta - 0.149-1 -- default_script: added missing closing curly bracket - -* Mon Jul 8 2013 Mika Ilmaranta - 0.148-1 -- pass event timestamp from lsm to scripts - -* Mon Jul 8 2013 Mika Ilmaranta - 0.147-1 -- pass empty warn_email addr to script as hyphen -- if script gets hyphen for email addr do not send mail - -* Thu Jul 4 2013 Mika Ilmaranta - 0.146-1 -- long_down_to down -> long_down_to_down - -* Thu Jul 4 2013 Mika Ilmaranta - 0.145-1 -- check also for nul-string email addr - -* Mon Jul 1 2013 Mika Ilmaranta - 0.144-1 -- use enum for status -- new config options for reporting only longer down time: -- long_down_time = how many seconds down time is considered long -- long_down_email = where to report long down time -- long_down_notifyscript = script to use when reporting long down time -- long_down_eventscript = script to use when reacting to long down time - -* Fri May 10 2013 Mika Ilmaranta - 0.143-1 -- discard probed src addr if bind fails - -* Thu Mar 28 2013 Mika Ilmaranta - 0.142-1 -- free exec_queue on exit - -* Thu Mar 28 2013 Mika Ilmaranta - 0.141-1 -- make exec_queue_dump activate with -DDEBUG -- rsyslog-lsm.conf.sample by Dimitar Angelov - -* Thu Mar 28 2013 Mika Ilmaranta - 0.140-1 -- debug with exec_queue_dump - -* Thu Mar 28 2013 Mika Ilmaranta - 0.139-1 -- forkexec.c: check that eq is set in exec_queue_process - -* Thu Mar 28 2013 Mika Ilmaranta - 0.138-1 -- config.c: defaults.queue NULL - -* Thu Mar 28 2013 Mika Ilmaranta - 0.137-1 -- exec queue, run event scripts sychronously - -* Thu Oct 11 2012 Mika Ilmaranta - 0.136-1 -- lsm.c: clean up debugging and add check that reply addr matches - original destination addr - -* Thu Oct 11 2012 Mika Ilmaranta - 0.135-1 -- lsm.c: more debugging when pdp->id is out of range - -* Thu Oct 11 2012 Mika Ilmaranta - 0.134-1 -- lsm.c: do bounds check on pdp->id before use as ctable index - -* Mon Aug 13 2012 Mika Ilmaranta - 0.133-1 -- lsm.c: rethought group up/down logic. (original was wrong up event on - transition to unknown state and 0.132 fix reported both up and down - events) - -* Mon Aug 13 2012 Mika Ilmaranta - 0.132-1 -- default_script: better english for timeout packets -- config.c: recognise status for group, use default start status for group -- lsm.c: report group prevstate textually - -* Sat May 12 2012 Mika Ilmaranta - 0.131-1 -- close socket on recvfrom fail - -* Tue May 8 2012 Mika Ilmaranta - 0.130-1 -- initialize cmsgbuf and cmsglen in open_icmp_sock as socket may be - closed and reopened - -* Sun May 6 2012 Mika Ilmaranta - 0.129-1 -- close socket also when sendmsg fails - -* Sun May 6 2012 Mika Ilmaranta - 0.128-1 -- cleanup debugging -- don't SO_BINDTODEVICE for AF_INET6 when device is specified as it uses - sendmsg instead of sendto - -* Sun May 6 2012 Mika Ilmaranta - 0.127-1 -- debug sendmsg a little - -* Sun May 6 2012 Mika Ilmaranta - 0.126-1 -- set v6 filter - -* Sun May 6 2012 Mika Ilmaranta - 0.125-1 -- handle v6 device setting like ping6 does - -* Sat May 5 2012 Mika Ilmaranta - 0.124-1 -- v6 sequence now correct? -- set v6 sockopts also if ttl is not set - -* Thu Apr 19 2012 Mika Ilmaranta - 0.123-1 -- removed unnesessary debugging -- v6 src ip addr autodiscovery works now - -* Thu Apr 19 2012 Mika Ilmaranta - 0.122-1 -- debug memcpy t->src6 results - -* Thu Apr 19 2012 Mika Ilmaranta - 0.121-1 -- check t->src6 contents - -* Thu Apr 19 2012 Mika Ilmaranta - 0.120-1 -- debug v6 getsockname unconditionally - -* Thu Apr 19 2012 Mika Ilmaranta - 0.119-1 -- debug getsockname for v6 conn - -* Thu Apr 19 2012 Mika Ilmaranta - 0.118-1 -- no SO_DONTROUTE for v6 probe - -* Fri Apr 13 2012 Mika Ilmaranta - 0.117-1 -- lsm.c: set more v6 socket options -- TODO: check why probe_src_ip_addr doesn't work for v6 - -* Sat Mar 10 2012 Mika Ilmaranta - 0.116-2 -- fix forkexec format str - -* Sat Mar 10 2012 Mika Ilmaranta - 0.116-1 -- report prevstate as string up/down/unknown - -* Wed Mar 7 2012 Tuomo Soini - 0.115-2 -- fix %%postun not to fail - -* Wed Dec 21 2011 Mika Ilmaranta - 0.115-1 -- forkexec.c: remove space after func name -- lsm.c: free_config_data: don't close t->sock if it is -1 - -* Wed Dec 21 2011 Mika Ilmaranta - 0.114-1 -- moved time calculation functions to their own files - -* Wed Dec 21 2011 Mika Ilmaranta - 0.113-1 -- decode all icmp and icmp6 types and codes - -* Tue Dec 20 2011 Mika Ilmaranta - 0.112-1 -- Andrew Beverley's signal child handler -- made static functions static - -* Tue Dec 20 2011 Mika Ilmaranta - 0.111-1 -- moved children handling from forkexec to main loop - -* Tue Dec 20 2011 Mika Ilmaranta - 0.110-1 -- lsm.c: use t->dst6 in v6 probe not cur->dstinfo - -* Tue Dec 20 2011 Mika Ilmaranta - 0.109-1 -- rebuild with efence - -* Tue Dec 20 2011 Mika Ilmaranta - 0.108-1 -- ipv6 support seems now stable enough - -* Tue Dec 20 2011 Mika Ilmaranta - 0.107-1 -- lsm.c: debug probe_src_ip_addr call - -* Tue Dec 20 2011 Mika Ilmaranta - 0.106-1 -- lsm.c: debug open_icmp_sock socket call removed -- lsm.c: debug setting v6 src addr - -* Tue Dec 20 2011 Mika Ilmaranta - 0.105-1 -- lsm.c: debug open_icmp_sock socket call - -* Tue Dec 20 2011 Mika Ilmaranta - 0.104-1 -- lsm.c: more sin6_family fixes - -* Tue Dec 20 2011 Mika Ilmaranta - 0.103-1 -- lsm.c: set sin6_family and show also v4 addr in debug - -* Tue Dec 20 2011 Mika Ilmaranta - 0.102-1 -- lsm.c: debug reply pkts more - -* Mon Dec 19 2011 Mika Ilmaranta - 0.101-1 -- lsm.c: fix inet_pton parameters - -* Mon Dec 19 2011 Mika Ilmaranta - 0.100-1 -- lsm.c: fail if device can not be bound to by Andrew Beverley -- lsm.c: bind also to ipv6 sourceip - -* Mon Dec 19 2011 Mika Ilmaranta - 0.99-1 -- lsm.c: fix ping6 sendto params - -* Mon Dec 19 2011 Mika Ilmaranta - 0.98-1 -- initial ipv6 support - -* Mon Dec 19 2011 Mika Ilmaranta - 0.97-1 -- include version information in directory name inside tar pkg - -* Mon Dec 19 2011 Mika Ilmaranta - 0.96-1 -- lsm.c: initialize last decision outside main loop. fixes decide call - interval. patch by Andrew Beverley -- config.c: debugging information added for unmatched config option by - Andrew Beverley. strcpy changed to memmove in strip leading space -- lsm.c: show correct usage -- config.c: clean up config file lines harder before parsing - -* Fri Dec 9 2011 Mika Ilmaranta - 0.95-1 -- shorewall_script: removed email notification, use it as eventscript and - default_script as notifyscript for example - -* Fri Dec 9 2011 Mika Ilmaranta - 0.94-1 -- added support for worker script (= eventscript) and notify script - (= notifyscript) differentiation, both are called with same parameters. - new script parameter previous state - -* Thu Dec 8 2011 Mika Ilmaranta - 0.93-1 -- for the following two patches thanks to Pablo Gomez -- lsm.c: use sourceip from config for icmp pkts if set -- lsm.c,config.c: new default state is unknown, which can be overridden in - config. this allows lsm to run event script "on startup" after connection - statuses are discovered. same rules apply as for actual events. - -* Thu Oct 20 2011 Mika Ilmaranta > - 0.92-1 -- report same seq status only once - -* Thu Oct 20 2011 Mika Ilmaranta - 0.91-1 -- dump conn status to syslog every maxseq when status is down only - if no status change - -* Thu Oct 20 2011 Mika Ilmaranta - 0.90-1 -- dump conn status to syslog every maxseq when status is down - -* Tue Sep 27 2011 Mika Ilmaranta - 0.89-1 -- added comment to shrewall_script about shorewall version requirement - -* Tue Sep 27 2011 Mika Ilmaranta - 0.88-1 -- added shorewall_script - -* Fri Jul 15 2011 Mika Ilmaranta - 0.87-1 -- production setting for compilation (no efence and use optimization) - -* Wed Jun 22 2011 Mika Ilmaranta - 0.86-1 -- protect FD_ISSET also from closed socket - -* Wed Jun 22 2011 Mika Ilmaranta - 0.85-1 -- compile with ElectricFence - -* Wed Jun 22 2011 Mika Ilmaranta - 0.84-1 -- revert to v0.64 base -- Makefile: merge v0.83 changeset -- lsm.spec: v0.83 spec -- config: removed reopen_on_enodev and added patch for double free -- lsm.c: removed reopen_on_enodev handling -- lsm.conf: removed reopen_on_enodev -- added cksum files -- lsm.c: use external cksum -- v0.83 forkexec, globals and signal_handler -- lsm.c: separate defs.h, merged fixes from v0.83 -- lsm.c: close socket on fail and reopen just before next ping -- spec: version and changelog - -* Wed Jun 22 2011 Mika Ilmaranta - 0.83-1 -- check that device names match - -* Wed Jun 22 2011 Mika Ilmaranta - 0.82-1 -- compile with ElectricFence depending on devel define - -* Wed Jun 22 2011 Mika Ilmaranta - 0.81-1 -- check arp header differently - -* Tue Jun 21 2011 Mika Ilmaranta - 0.80-1 -- further debugging of disappearing arp replies - -* Tue Jun 21 2011 Mika Ilmaranta - 0.79-1 -- try to find out where arp replies vanish - -* Tue Jun 21 2011 Mika Ilmaranta - 0.78-1 -- config.c: fix double free on warn_email and other group parameters - -* Tue Jun 21 2011 Mika Ilmaranta - 0.77-1 -- fix BuildRequires for -lefence - -* Tue Jun 21 2011 Mika Ilmaranta - 0.76-1 -- compile with -lefence - -* Tue Jun 21 2011 Mika Ilmaranta - 0.75-1 -- check packet from addr to determine which connection it - belongs to - -* Tue Jun 21 2011 Mika Ilmaranta - 0.74-1 -- moved rest of io functions to io.c -- io.c: split icmp and arp reply handling -- io.c: differentiate ping_rcv error logging on find_interface use - -* Tue Jun 21 2011 Mika Ilmaranta - 0.73-1 -- bind SIGUSR2 to signal_handler - -* Tue Jun 21 2011 Mika Ilmaranta - 0.72-1 -- dump interface list on SIGUSR2 - -* Mon Jun 20 2011 Mika Ilmaranta - 0.71-1 -- io.c: due to function splitting add missing gettimeofday call in icmp_send - -* Mon Jun 20 2011 Mika Ilmaranta - 0.70-1 -- timeval_diff_[lt,gt] fix diff_usec calculation - -* Mon Jun 20 2011 Mika Ilmaranta - 0.69-1 -- removed sock from target structure -- added interface handling to interface.c and made other parts use it - -* Fri Jun 17 2011 Mika Ilmaranta - 0.68-1 -- broke timeval_diff_cmp to two functions -- globals.c: check for unset prog -- lsm.c: removed handle_odd_icmp function as it did nothing -- interface.c: made probe for src ip address function probe_addresses - -* Fri Jun 17 2011 Mika Ilmaranta - 0.67-1 -- moved global variable handling to its own block -- moved decision functions to their own block -- moved signal_handler to its own block -- moved ping function to its own file -- lsm.c: reset reload_cfg after reloading config, not before -- Makefile: clean also ~ files starting with dot - -* Fri Jun 17 2011 Mika Ilmaranta - 0.66-1 -- moved structure definitions to lsm.h -- lsm.c: moved socket opening functionality to interface.c -- Makefile: use Makefile.depend -- .gitignore: ignore Makefile.depend, obj files and lsm binary - -* Wed Jun 15 2011 Mika Ilmaranta - 0.65-1 -- started rewrite -- moved forkexec function and defines to their own files -- added interface handling src files -- moved cksum function to its own file -- moved timeval functions to their own files - -* Fri Dec 31 2010 Mika Ilmaranta - 0.64-1 -- fill up target struct src address for ping also - do it at startup (should this be done every time we send ping packet?) - -* Fri Dec 31 2010 Mika Ilmaranta - 0.63-1 -- Added src ip to script parameters - src ip paramater is the last one so that every single old config - doesn't have to be rewritten. - -* Fri Dec 10 2010 Mika Ilmaranta - 0.62-1 -- check for valid ip-address in checkip parameter - -* Fri Dec 10 2010 Mika Ilmaranta - 0.61-1 -- changed lsm.c init_config to init_config_data -- added init_config to config.c which is then called before read_config -- added a warning when checkip is not set - -* Sat Oct 9 2010 Mika Ilmaranta - 0.60-1 -- fix recursive read_config use. set default values only once. -- use cfg.debug only after config is read -- added default_script.sample - -* Mon Sep 27 2010 Mika Ilmaranta - 0.59-1 -- remember connection statuses after config reload - -* Mon Sep 27 2010 Mika Ilmaranta - 0.58-1 -- reopen_on_enodev support. set this to 1 so lsm will try to reopen ping - device when it encounters ENODEV error when sending ping packet - -* Sun Sep 19 2010 Mika Ilmaranta - 0.57-1 -- added defaults status to give initial assumption of the connection status -- added config status for connections. is it assumed down = 0 or up = 1 - at lsm start - -* Sat Sep 18 2010 Mika Ilmaranta - 0.56-1 -- fixed rpmlint-v0.91 warnings. - -* Sat Apr 24 2010 Mika Ilmaranta - 0.53-1 -- added error checking to ftruncate and write so that mock build doesn't - complain -- introduced timeval_diff_cmp function as it seems quite problematic to - really compare times in usec since epoch using integer values. - especially 32bit systems were seeing 99% CPU loads because of this. - -* Thu Apr 22 2010 Mika Ilmaranta - 0.52-1 -- initialize all struct timeval structures to tv_sec = 0 and tv_usec = 0 -- added use of error flag to arping sending - -* Fri Mar 5 2010 Mika Ilmaranta - 0.51-1 -- fix avg rtt calculation comment -- show in the default mail template avg rtt unit [usec] -- in syslog avg rtt is reported in [msec] as of v0.50 like ping does - -* Fri Mar 5 2010 Mika Ilmaranta - 0.50-1 -- report rtt with three decimals accuracy - -* Thu Mar 4 2010 Mika Ilmaranta - 0.49-1 -- count average rtt in milliseconds not in microseconds - -* Thu Mar 4 2010 Mika Ilmaranta - 0.48-1 -- don't count timeouted late replies in cons rcvd - -* Thu Mar 4 2010 Mika Ilmaranta - 0.47-1 -- added some missing fields to lsm.init - -* Thu Mar 4 2010 Mika Ilmaranta - 0.46-1 -- dump all statuses only if requested by SIGUSR1 -- otherwise dump only connection status data of connection whose status changed - -* Wed Mar 3 2010 Mika Ilmaranta - 0.45-1 -- use LOG_PID openlog option - -* Thu Dec 17 2009 Mika Ilmaranta - 0.44-1 -- added some parameter sanity checking. if max_packet_loss <= min_packet_loss then there can be a flip-flop effect - and many many and still a few reports mailed to warn_email address. - -* Mon Nov 9 2009 Mika Ilmaranta - 0.43-1 -- convert all tabs to spaces before processing config line - -* Sun Sep 27 2009 Mika Ilmaranta - 0.42-1 -- changed action script to event script to follow suite with config - -* Sun Sep 27 2009 Mika Ilmaranta - 0.41-1 -- added action_script_check() to check for valid action script - -* Wed Sep 2 2009 Mika Ilmaranta - 0.40-1 -- lseek to start of pid file and ftruncate it to zero size before writing - our new pid. this prevents us having two pids in the file if previous - lsm crashed or exited and did not remove the file (fcntl lock is cleared - by kernel as process dies "prematurely"). - -* Mon Jun 29 2009 Mika Ilmaranta - 0.39-1 -- set close on exec flag for fds and sockets -- call closelog() within forked child before exec - -* Thu Jun 18 2009 Mika Ilmaranta - 0.38-1 -- require mailx for /bin/mail as default_script uses it - -* Thu Jun 18 2009 Mika Ilmaranta - 0.37-1 -- when dumping config log also group's warn_email and logic -- set last previous last group members next to the new last member - -* Thu Jun 18 2009 Mika Ilmaranta - 0.36-1 -- apply sane defaults to group parameters - -* Thu Jun 4 2009 Mika Ilmaranta - 0.35-1 -- only log sendto errors with debug >= 9 - -* Thu Jun 4 2009 Mika Ilmaranta - 0.34-1 -- better sendto error ignore fix -- changed syslog calls for Mandrake - -* Thu Jun 4 2009 Mika Ilmaranta - 0.33-1 -- ping_send: don't care about sendto errors - -* Wed Apr 29 2009 Mika Ilmaranta - 0.32-1 -- split long debug explanation line in lsm.conf - -* Wed Apr 29 2009 Mika Ilmaranta - 0.31-1 -- left only defaults in lsm.conf and moved examples to - lsm.conf.sample - -* Tue Apr 28 2009 Mika Ilmaranta - 0.30-1 -- timeval_diff calculation order change to prevent - long overflow. nobody has encoutered that but just to be - sure -- use default ttl=0 which uses system default ttl - -* Sat Apr 18 2009 Mika Ilmaranta - 0.29-1 -- Added decision making section to README written by Dean Takemori - he suggested to include it in lsm.conf but I thought it was - long enough already - -* Sat Apr 18 2009 Mika Ilmaranta - 0.28-1 -- Tom Eastep's fix for last_sent_time initialization -- added time stamp to default_script mail body - -* Fri Apr 10 2009 Mika Ilmaranta - 0.27-1 -- added checks for missing group members - -* Fri Apr 10 2009 Mika Ilmaranta - 0.26-1 -- added connection grouping - -* Thu Apr 9 2009 Mika Ilmaranta - 0.25-1 -- gettimeofday failure patch from Dean Takemori - -* Sun Apr 5 2009 Mika Ilmaranta - 0.24-1 -- add support for SIGHUP to reload config - -* Tue Mar 24 2009 Mika Ilmaranta - 0.23-1 -- changed ping packets to use own socket for each target. - looks like setsockopt SO_BINDTOINTERFACE is not reversible and - according to documentation I found using it multiple times - may lead to unpredicted results due to kernel caching. - -* Tue Mar 24 2009 Mika Ilmaranta - 0.22-1 -- changed indentation to tabs - -* Mon Mar 16 2009 Mika Ilmaranta - 0.21-1 -- added LSM: to default_script mail subject - -* Tue Mar 10 2009 Mika Ilmaranta - 0.20-1 -- handle ENODEV as if the ping packet was sent, but do barf to syslog - about it. this will eventually cause a down event. added - an error flag which is set if sendto returns with value < 0. -- dump connection statuses to syslog when up/down-event happens. -- moved status dump's "header" -line above the pkt status bits. -- added error flag dumping. - -* Fri Mar 6 2009 Mika Ilmaranta - 0.19-1 -- fix pid file write order - -* Thu Mar 5 2009 Mika Ilmaranta - 0.18-1 -- added pid file handling - -* Thu Mar 5 2009 Mika Ilmaranta - 0.17-1 -- rebuild because of mystical i386 build problems - -* Wed Mar 4 2009 Mika Ilmaranta - 0.16-1 -- pass only LANG, PATH and TERM environment variables to - scripts - -* Wed Mar 4 2009 Mika Ilmaranta - 0.15-1 -- fixed all rpmlint errors reported in binary pkg - which means that default_script is moved to /usr/share/lsm - -* Wed Mar 4 2009 Mika Ilmaranta - 0.14-1 -- added ipv6 support to TODO list -- fixed rpmlint errors in lsm.spec - -* Tue Feb 24 2009 Mika Ilmaranta - 0.13-1 -- typos: lisence -> license -- mention SIGUSR1 behaviour in README -- added a check for ENODEV for ping packets - -* Fri Feb 20 2009 Mika Ilmaranta - 0.12-1 -- don't define device= in defaults - -* Wed Feb 18 2009 Mika Ilmaranta - 0.11-1 -- if device is not specified return NA - -* Wed Feb 18 2009 Mika Ilmaranta - 0.10-1 -- added device to script parameters -- first try on binding ping packets to device - -* Thu Feb 12 2009 Mika Ilmaranta - 0.9-1 -- fixed rtt comments in default_script - -* Thu Feb 12 2009 Mika Ilmaranta - 0.8-1 -- init script reload fix - -* Sat Feb 7 2009 Mika Ilmaranta - 0.7-1 -- fixed typos -- init script reload was missing - -* Sun Feb 1 2009 Mika Ilmaranta - 0.6-1 -- fixed comments and readme to correspond current status - -* Sun Feb 1 2009 Mika Ilmaranta - 0.6-1 -- now each target has its own ttl setting - -* Sat Jan 31 2009 Mika Ilmaranta - 0.5-8 -- check for no targets specified in conf - -* Sat Jan 31 2009 Mika Ilmaranta - 0.5-7 -- all except DEBUG is now syslogged - -* Sat Jan 31 2009 Mika Ilmaranta - 0.5-4 -- added ttl setting handling for ping packets. currently all - ping monitored links share a common ttl value which is - taken from the first config entry's ttl value. -- when SIGUSR1 is received lsm dumps current packet info to - syslog ... - -* Sat Jan 31 2009 Mika Ilmaranta - 0.5-3 -- changed avg rtt calculation so that only replied packets' - rtt is counted - -* Sat Jan 31 2009 Mika Ilmaranta - 0.5-2 -- Added a ping reply packet min size check - -* Fri Jan 30 2009 Mika Ilmaranta - 0.5-1 -- started adding support for arp check which is actually - using arp packets rather than ping packets in case - your gw administrators have blocked ping - -* Thu Jan 29 2009 Mika Ilmaranta - 0.4-1 -- Initial build - -#EOF diff --git a/plugin_export.c b/plugin_export.c index b2a9f82..a6db219 100644 --- a/plugin_export.c +++ b/plugin_export.c @@ -67,9 +67,9 @@ static void plugin_export_munin(CONFIG *first) return; } - fprintf(fp, "graph_title LSM Average Ping Latency\n"); + fprintf(fp, "graph_title Foolsm Average Ping Latency\n"); fprintf(fp, "graph_vlabel ms\n"); - fprintf(fp, "graph_info This graph shows LSM status\n"); + fprintf(fp, "graph_info This graph shows Foolsm status\n"); fprintf(fp, "graph_category network\n"); fprintf(fp, "graph_args --base 1000 -l 0\n"); @@ -107,9 +107,9 @@ static void plugin_export_munin(CONFIG *first) return; } - fprintf(fp, "graph_title LSM packet counts\n"); + fprintf(fp, "graph_title Foolsm packet counts\n"); fprintf(fp, "graph_vlabel percent\n"); - fprintf(fp, "graph_info This graph shows LSM status\n"); + fprintf(fp, "graph_info This graph shows Foolsm status\n"); fprintf(fp, "graph_category network\n"); fprintf(fp, "graph_args --base 1000 -l 0\n"); @@ -177,9 +177,9 @@ static void plugin_export_munin(CONFIG *first) return; } - fprintf(fp, "graph_title LSM connection statuses\n"); + fprintf(fp, "graph_title Foolsm connection statuses\n"); fprintf(fp, "graph_vlabel Status\n"); - fprintf(fp, "graph_info This graph shows LSM connection statuses\n"); + fprintf(fp, "graph_info This graph shows Foolsm connection statuses\n"); fprintf(fp, "graph_category network\n"); fprintf(fp, "graph_info Status: 0 = DOWN, 1 = UP, 2 = UNKNOWN, 3 = LONG_DOWN\n"); fprintf(fp, "graph_args --base 1000 --lower-limit 0 --upper-limit 3\n"); diff --git a/plugin_export.h b/plugin_export.h index 79c714b..22a6c95 100644 --- a/plugin_export.h +++ b/plugin_export.h @@ -12,7 +12,7 @@ License: GPLv2 #define __PLUGIN_EXPORT_H__ #include "config.h" -#include "lsm.h" +#include "foolsm.h" void plugin_export_init(void); void plugin_export(CONFIG *first); diff --git a/rsyslog-foolsm.conf.sample b/rsyslog-foolsm.conf.sample new file mode 100644 index 0000000..b35b089 --- /dev/null +++ b/rsyslog-foolsm.conf.sample @@ -0,0 +1,3 @@ +# Foobar Link Status Monitor Log file +if $programname == 'foolsm' then /var/log/foolsm.log +if $programname == 'foolsm' then ~ diff --git a/rsyslog-lsm.conf.sample b/rsyslog-lsm.conf.sample deleted file mode 100644 index a0da81c..0000000 --- a/rsyslog-lsm.conf.sample +++ /dev/null @@ -1,3 +0,0 @@ -# Link Status Monitor Log file -if $programname == 'lsm' then /var/log/lsm.log -if $programname == 'lsm' then ~ diff --git a/save_statuses.c b/save_statuses.c index d1178a4..a3aec0c 100644 --- a/save_statuses.c +++ b/save_statuses.c @@ -11,7 +11,7 @@ License: GPLv2 #include #include "config.h" -#include "lsm.h" +#include "foolsm.h" #include "save_statuses.h" typedef struct status_data { diff --git a/shorewall6_script b/shorewall6_script index b6d59c7..fad9afb 100644 --- a/shorewall6_script +++ b/shorewall6_script @@ -49,4 +49,3 @@ else fi exit 0 -# diff --git a/shorewall_script b/shorewall_script index b9aa859..3144480 100644 --- a/shorewall_script +++ b/shorewall_script @@ -50,4 +50,3 @@ else fi exit 0 -# diff --git a/usage.c b/usage.c index 6433488..60ff900 100644 --- a/usage.c +++ b/usage.c @@ -14,8 +14,8 @@ #include "usage.h" void usage_and_exit(void) { -#if defined(LSM_VERSION) - printf("%s version %s\n", get_prog(), LSM_VERSION); +#if defined(FOOLSM_VERSION) + printf("%s version %s\n", get_prog(), FOOLSM_VERSION); #endif printf("usage: %s\n" " [-h|--help|-v|--version]\n" -- cgit v1.2.3