aboutsummaryrefslogtreecommitdiff
path: root/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'config.c')
-rw-r--r--config.c762
1 files changed, 762 insertions, 0 deletions
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..5f653f2
--- /dev/null
+++ b/config.c
@@ -0,0 +1,762 @@
+/*
+
+(C) 2009-2015 Mika Ilmaranta <ilmis@nullnet.fi>
+
+License: GPLv2
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <dirent.h>
+#include <fnmatch.h>
+
+#include "config.h"
+#include "defs.h"
+
+static CONFIG defaults;
+static int errors = 0;
+
+GLOBAL cfg;
+
+static void read_one_config(char *fn, CONFIG **first, CONFIG **last, GROUPS **firstg, GROUPS **lastg);
+static int find_all_configs(char* fn, int mustexist, CONFIG **first, CONFIG **last, GROUPS **firstg, GROUPS **lastg);
+static void reassign(char **dst, char *src);
+static void release(char **dst);
+static int eqcmp(char *str, char *pat);
+static int check_addrs(CONFIG *cur);
+
+static void reassign(char **dst, char *src)
+{
+ if(*dst) free(*dst);
+ *dst = strdup(src);
+}
+
+static void release(char **dst)
+{
+ if(*dst) free(*dst);
+ *dst = NULL;
+}
+
+static int eqcmp(char *str, char *pat)
+{
+ int i;
+
+ i = strlen(pat);
+ if(!strncmp(str, pat, i) && str[i] == '=') return 0;
+ return 1;
+}
+
+int reload_config(char *fn, CONFIG **first, CONFIG **last, GROUPS **firstg, GROUPS **lastg) {
+ free_config(first, last, firstg, lastg);
+ init_config();
+ return(read_config(fn, first, last, firstg, lastg));
+}
+
+void free_config(CONFIG **first, CONFIG **last, GROUPS **firstg, GROUPS **lastg) {
+ CONFIG *cur, *prev;
+ GROUPS *curg, *prevg;
+ GROUP_MEMBERS *curgm, *prevgm;
+
+ cur = (*first);
+ while(cur) {
+ if(cur->name && cur->name != defaults.name) release(&cur->name);
+ if(cur->sourceip && cur->sourceip != defaults.sourceip) release(&cur->sourceip);
+ if(cur->srcinfo) freeaddrinfo(cur->srcinfo);
+ if(cur->checkip && cur->checkip != defaults.checkip) release(&cur->checkip);
+ if(cur->dstinfo) freeaddrinfo(cur->dstinfo);
+ if(cur->eventscript && cur->eventscript != defaults.eventscript) release(&cur->eventscript);
+ if(cur->notifyscript && cur->notifyscript != defaults.notifyscript) release(&cur->notifyscript);
+ if(cur->warn_email && cur->warn_email != defaults.warn_email) release(&cur->warn_email);
+ if(cur->device && cur->device != defaults.device) release(&cur->device);
+ if(cur->queue && cur->queue != defaults.queue) release(&cur->queue);
+ if(cur->long_down_email && cur->long_down_email != defaults.long_down_email) release(&cur->long_down_email);
+ if(cur->long_down_notifyscript && cur->long_down_notifyscript != defaults.long_down_notifyscript) release(&cur->long_down_notifyscript);
+ if(cur->long_down_eventscript && cur->long_down_eventscript != defaults.long_down_eventscript) release(&cur->long_down_eventscript);
+
+ prev = cur;
+ cur = cur->next;
+ free(prev);
+ }
+
+ *first = NULL;
+ *last = NULL;
+
+ curg = (*firstg);
+ while(curg) {
+ curgm = curg->fgm;
+ while(curgm) {
+ free(curgm->name);
+
+ prevgm = curgm;
+ curgm = curgm->next;
+ free(prevgm);
+ }
+ curg->fgm = NULL;
+ curg->lgm = NULL;
+
+ if(curg->name && curg->name != defaults.name) release(&curg->name);
+ if(curg->eventscript && curg->eventscript != defaults.eventscript) release(&curg->eventscript);
+ if(curg->notifyscript && curg->notifyscript != defaults.notifyscript) release(&curg->notifyscript);
+ if(curg->warn_email && curg->warn_email != defaults.warn_email) release(&curg->warn_email);
+ if(curg->queue && curg->queue != defaults.queue) release(&curg->queue);
+
+ prevg = curg;
+ curg = curg->next;
+ free(prevg);
+ }
+
+ *firstg = NULL;
+ *lastg = NULL;
+
+ if(defaults.name) release(&defaults.name);
+ if(defaults.checkip) release(&defaults.checkip);
+ if(defaults.eventscript) release(&defaults.eventscript);
+ if(defaults.notifyscript) release(&defaults.notifyscript);
+ if(defaults.warn_email) release(&defaults.warn_email);
+ if(defaults.sourceip) release(&defaults.sourceip);
+ if(defaults.device) release(&defaults.device);
+ if(defaults.queue) release(&defaults.queue);
+
+ if(defaults.long_down_email) release(&defaults.long_down_email);
+ if(defaults.long_down_notifyscript) release(&defaults.long_down_notifyscript);
+ if(defaults.long_down_eventscript) release(&defaults.long_down_eventscript);
+}
+
+void init_config(void)
+{
+ /* zero cfg and defaults */
+ memset(&cfg, 0, sizeof(cfg));
+ memset(&defaults, 0, sizeof(defaults));
+
+ /* initialize to sane value */
+ cfg.debug = 8;
+
+ defaults.name = strdup("defaults");
+ defaults.checkip = strdup("127.0.0.1");
+ defaults.eventscript = NULL;
+ defaults.notifyscript = strdup("/usr/libexec/lsm/default_script");
+ defaults.max_packet_loss = 15;
+ defaults.max_successive_pkts_lost = 7;
+ defaults.min_packet_loss = 5;
+ defaults.min_successive_pkts_rcvd = 10;
+ defaults.interval_ms = 1000;
+ defaults.timeout_ms = 1000;
+ defaults.warn_email = strdup("root");
+ defaults.check_arp = 0;
+ defaults.sourceip = NULL;
+ defaults.ttl = 0;
+
+ /* assume default unknown state for connections unless user has stated otherwise later in config */
+ defaults.status = UNKNOWN;
+
+ /* no exec queue by default */
+ defaults.queue = NULL;
+
+ defaults.long_down_email = NULL;
+
+ /* by default don't execute notify script on unkown to up event */
+ defaults.unknown_up_notify = 0;
+
+ /* by default no accelerated startup */
+ defaults.startup_acceleration = 0;
+
+ /* by default no startup burst */
+ defaults.startup_burst_pkts = 0;
+ defaults.startup_burst_interval = MIN_PERHOST_INTERVAL;
+}
+
+static int find_all_configs(char* fn, int mustexist, CONFIG **first, CONFIG **last, GROUPS **firstg, GROUPS **lastg)
+{
+ struct dirent **namelist;
+ char dir[BUFSIZ], pattern[128], *p, s[BUFSIZ];
+ int n, i, found;
+
+ /* Split fn to dir/pattern */
+ strcpy(dir, fn);
+ if((p = strrchr(dir, '/')) == NULL) {
+ strcpy(dir, ".");
+ strcpy(pattern, fn);
+ } else {
+ *p = 0;
+ strcpy(pattern, p + 1);
+ }
+
+ /* Find list of all files */
+ n = scandir(dir, &namelist, 0, alphasort);
+ if (n < 0) {
+ if (mustexist == 0)
+ return(0);
+ syslog(LOG_ERR, "%s: can't read directory \"%s\"", __FUNCTION__, dir);
+ return(-1);
+ }
+
+ /* See if name matches pattern */
+ found = 0;
+ for (i = 0; i < n; i++) {
+ if (fnmatch(pattern, namelist[i]->d_name, 0) == 0 &&
+ fnmatch("*~", namelist[i]->d_name, 0) != 0) {
+ snprintf(s, BUFSIZ, "%s/%s", dir, namelist[i]->d_name);
+ read_one_config(s, first, last, firstg, lastg);
+ found++;
+ }
+ free(namelist[i]);
+ }
+ free(namelist);
+
+ /* Fail if no matches found */
+ if (found == 0) {
+ if (mustexist == 0)
+ return(0);
+ syslog(LOG_ERR, "%s: no config files found for \"%s\"", __FUNCTION__, fn);
+ return(-1);
+ }
+
+ return(0);
+}
+
+int read_config(char *fn, CONFIG **first, CONFIG **last, GROUPS **firstg, GROUPS **lastg)
+{
+ CONFIG *cur = NULL;
+ GROUPS *curg = NULL;
+ GROUP_MEMBERS *curgm = NULL;
+
+ errors = 0;
+
+ read_one_config(fn, first, last, firstg, lastg);
+
+ for(curg = *firstg; curg; curg = curg->next) {
+ for(curgm = curg->fgm; curgm; curgm = curgm->next) {
+ int found = 0;
+
+ for(cur = *first; cur; cur = cur->next) {
+ if(!strcmp(cur->name, curgm->name)) {
+ curgm->cfg_ptr = cur;
+ found = 1;
+ break;
+ }
+ }
+ if(!found) {
+ syslog(LOG_ERR, "%s: %s: connection group member \"%s\" not found", __FILE__, __FUNCTION__, curgm->name);
+ errors++;
+ }
+ }
+ }
+
+ /* some parameter sanity checking */
+ for(cur = *first; cur; cur = cur->next) {
+ if(strlen(cur->checkip) == 0) {
+ syslog(LOG_ERR, "WARNING: connection \"%s\" has no checkip parameter set", cur->name);
+ errors++;
+ } else {
+ if(check_addrs(cur) < 0) {
+ errors++;
+ }
+ }
+
+ if(cur->max_packet_loss <= cur->min_packet_loss) {
+ syslog(LOG_ERR, "WARNING: connection \"%s\" max_packet_loss (%d) <= min_packet_loss (%d). that would cause flip-flop effect", cur->name, cur->max_packet_loss, cur->min_packet_loss);
+ errors++;
+ }
+
+ }
+ if(errors) return(-1);
+
+ return(0);
+}
+
+static void read_one_config(char *fn, CONFIG **first, CONFIG **last, GROUPS **firstg, GROUPS **lastg)
+{
+ CONFIG *cur = NULL;
+ GROUPS *curg = NULL;
+ GROUP_MEMBERS *curgm = NULL;
+ FILE *fp;
+ char buf[BUFSIZ];
+ int mode = 0;
+ int line = 1;
+
+ if((fp = fopen(fn, "r")) == 0) {
+ syslog(LOG_ERR, "%s: can't open config file \"%s\"", __FUNCTION__, fn);
+ return;
+ }
+
+ while(fgets(buf, BUFSIZ, fp)) {
+ char *p = NULL;
+
+ if(*buf && buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = '\0'; /* strip lf */
+ if((p = strchr(buf, '#')) != NULL) *p = '\0'; /* strip comment */
+ while((p = strchr(buf, '\t')) != NULL) *p = ' '; /* tabs -> spaces */
+ while(*buf == ' ') memmove(buf, buf + 1, strlen(buf)); /* strip leading space */
+ while((p = strstr(buf, " ")) != NULL) memmove(p, p + 1, strlen(p)); /* strip multi white space */
+ while((p = strstr(buf, " =")) != NULL) memmove(p, p + 1, strlen(p)); /* strip spaces before = */
+ while((p = strstr(buf, "= ")) != NULL) memmove(p + 1, p + 2, strlen(p + 1)); /* strip spaces after = */
+ while(*buf && buf[strlen(buf) - 1] == ' ') buf[strlen(buf) - 1] = '\0'; /* strip tailing space */
+
+ if(!*buf) continue;
+
+ if(mode) {
+ if (!strcmp(buf, "}")) {
+ mode=0;
+ continue;
+ }
+
+ switch(mode) {
+ case 1: /* defaults */
+ if(!eqcmp(buf, "name"))
+ reassign(&defaults.name, strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "checkip"))
+ reassign(&defaults.checkip, strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "eventscript"))
+ reassign(&defaults.eventscript, strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "notifyscript"))
+ reassign(&defaults.notifyscript, strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "unknown_up_notify"))
+ defaults.unknown_up_notify = atoi(strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "max_packet_loss"))
+ defaults.max_packet_loss = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "max_successive_pkts_lost"))
+ defaults.max_successive_pkts_lost = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "min_packet_loss"))
+ defaults.min_packet_loss = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "min_successive_pkts_rcvd"))
+ defaults.min_successive_pkts_rcvd = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "interval_ms"))
+ defaults.interval_ms = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "timeout_ms"))
+ defaults.timeout_ms = atoi(strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "warn_email"))
+ reassign(&defaults.warn_email, strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "check_arp"))
+ defaults.check_arp = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "sourceip"))
+ reassign(&defaults.sourceip, strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "device"))
+ reassign(&defaults.device, strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "ttl"))
+ defaults.ttl = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "status"))
+ defaults.status = atoi(strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "queue"))
+ reassign(&defaults.queue, strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "long_down_time"))
+ defaults.long_down_time = atoi(strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "long_down_email"))
+ reassign(&defaults.long_down_email, strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "long_down_notifyscript"))
+ reassign(&defaults.long_down_notifyscript, strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "long_down_eventscript"))
+ reassign(&defaults.long_down_eventscript, strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "startup_acceleration"))
+ defaults.startup_acceleration = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "startup_burst_pkts"))
+ defaults.startup_burst_pkts = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "startup_burst_interval"))
+ defaults.startup_burst_interval = atoi(strchr(buf, '=') + 1);
+ else {
+ syslog(LOG_ERR, "%s: %s: unrecognised "
+ "default config option on "
+ "line %d \"%s\"", __FILE__,
+ __FUNCTION__, line, buf);
+ errors++;
+ }
+ break;
+ case 2: /* connection */
+ if(!cur) {
+ syslog(LOG_ERR, "read_config: cur == NULL");
+ break;
+ }
+
+ if(!eqcmp(buf, "name")) cur->name = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "checkip")) cur->checkip = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "eventscript")) cur->eventscript = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "notifyscript")) cur->notifyscript = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "unknown_up_notify")) cur->unknown_up_notify = atoi(strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "max_packet_loss")) cur->max_packet_loss = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "max_successive_pkts_lost")) cur->max_successive_pkts_lost = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "min_packet_loss")) cur->min_packet_loss = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "min_successive_pkts_rcvd")) cur->min_successive_pkts_rcvd = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "interval_ms")) cur->interval_ms = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "timeout_ms")) cur->timeout_ms = atoi(strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "warn_email")) cur->warn_email = strdup(strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "check_arp")) cur->check_arp = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "sourceip")) cur->sourceip = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "device")) cur->device = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "ttl")) cur->ttl = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "status")) cur->status = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "queue")) cur->queue = strdup(strchr(buf, '=') + 1);
+
+ else if(!eqcmp(buf, "long_down_time")) cur->long_down_time = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "long_down_email")) cur->long_down_email = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "long_down_notifyscript")) cur->long_down_notifyscript = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "long_down_eventscript")) cur->long_down_eventscript = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "startup_acceleration")) cur->startup_acceleration = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "startup_burst_pkts")) cur->startup_burst_pkts = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "startup_burst_interval")) cur->startup_burst_interval = atoi(strchr(buf, '=') + 1);
+ else {
+ syslog(LOG_ERR, "%s: %s: unrecognised connection config option on line %d \"%s\"", __FILE__, __FUNCTION__, line, buf);
+ errors++;
+ }
+ break;
+ case 3: /* group */
+ if(!eqcmp(buf, "name")) curg->name = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "eventscript")) curg->eventscript = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "notifyscript")) curg->notifyscript = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "unknown_up_notify")) curg->unknown_up_notify = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "warn_email")) curg->warn_email = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "logic")) curg->logic = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "status")) curg->status = atoi(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "queue")) curg->queue = strdup(strchr(buf, '=') + 1);
+ else if(!eqcmp(buf, "member-connection")) {
+ if((curgm = (GROUP_MEMBERS *)malloc(sizeof(GROUP_MEMBERS))) == NULL) {
+ syslog(LOG_ERR, "%s: %s: can't malloc for group member", __FILE__, __FUNCTION__);
+ fclose(fp);
+ return;
+ }
+ curgm->name = strdup(strchr(buf, '=') + 1);
+ curgm->cfg_ptr = NULL;
+
+ if(curg->lgm) { /* insert as last */
+ curgm->next = NULL;
+ curgm->prev = curg->lgm;
+ curg->lgm->next = curgm;
+ curg->lgm = curgm;
+ } else { /* empty member list */
+ curgm->next = NULL;
+ curgm->prev = NULL;
+ curg->fgm = curgm;
+ curg->lgm = curgm;
+ }
+ }
+ else {
+ syslog(LOG_ERR, "%s: %s: unrecognised group config option on line %d \"%s\"", __FILE__, __FUNCTION__, line, buf);
+ errors++;
+ }
+ break;
+ default:
+ syslog(LOG_ERR, "%s: %s: switch(mode) hit default: should never happen. mode was %d", __FILE__, __FUNCTION__, mode);
+ errors++;
+ break;
+ }
+ }
+ else {
+ /* global config */
+ if(!eqcmp(buf, "debug"))
+ cfg.debug = atoi(strchr(buf, '=') + 1);
+
+ /* per connection configs */
+ else if(!strcmp(buf, "defaults {"))
+ mode=1;
+ else if(!strcmp(buf, "connection {")) {
+ mode=2;
+ if((cur = malloc(sizeof(CONFIG))) == NULL) {
+ syslog(LOG_ERR, "%s: %s: can't malloc for config", __FILE__, __FUNCTION__);
+ return;
+ }
+
+ if(*last) { /* not first */
+ (*last)->next = cur;
+ cur->prev = *last;
+ cur->next = NULL;
+ *last = cur;
+ }
+ else {
+ *first = cur;
+ *last = cur;
+ cur->prev = NULL;
+ cur->next = NULL;
+ }
+ /* fill in defaults */
+ if(defaults.name) {
+ cur->name = defaults.name;
+ cur->sourceip = defaults.sourceip;
+ cur->srcinfo = NULL;
+ cur->checkip = defaults.checkip;
+ cur->dstinfo = NULL;
+ cur->eventscript = defaults.eventscript;
+ cur->notifyscript = defaults.notifyscript;
+ cur->unknown_up_notify = defaults.unknown_up_notify;
+ cur->max_packet_loss = defaults.max_packet_loss;
+ cur->max_successive_pkts_lost = defaults.max_successive_pkts_lost;
+ cur->min_packet_loss = defaults.min_packet_loss;
+ cur->min_successive_pkts_rcvd = defaults.min_successive_pkts_rcvd;
+ cur->interval_ms = defaults.interval_ms;
+ cur->timeout_ms = defaults.timeout_ms;
+ cur->warn_email = defaults.warn_email;
+ cur->check_arp = defaults.check_arp;
+ cur->device = defaults.device;
+ cur->ttl = defaults.ttl;
+ cur->status = defaults.status;
+ cur->queue = defaults.queue;
+ cur->long_down_time = defaults.long_down_time;
+ cur->long_down_email = defaults.long_down_email;
+ cur->long_down_notifyscript = defaults.long_down_notifyscript;
+ cur->long_down_eventscript = defaults.long_down_eventscript;
+ cur->startup_acceleration = defaults.startup_acceleration;
+ cur->startup_burst_pkts = defaults.startup_burst_pkts;
+ cur->startup_burst_interval = defaults.startup_burst_interval;
+ }
+ else
+ syslog(LOG_ERR, "%s: %s: defaults not set", __FILE__, __FUNCTION__);
+ }
+ else if(!strcmp(buf, "group {")) {
+ mode = 3;
+
+ if((curg = (GROUPS *)malloc(sizeof(GROUPS))) == NULL) {
+ syslog(LOG_ERR, "read_config: can't malloc for group");
+ return;
+ }
+
+ /* apply sane defaults for group */
+ curg->name = defaults.name;
+ curg->eventscript = defaults.eventscript;
+ curg->notifyscript = defaults.notifyscript;
+ curg->unknown_up_notify = defaults.unknown_up_notify;
+ curg->warn_email = defaults.warn_email;
+ curg->logic = 0; /* default group logic or */
+ curg->status = defaults.status;
+ curg->queue = defaults.queue;
+
+ curg->fgm = NULL;
+ curg->lgm = NULL;
+
+ if(*lastg) { /* not first group */
+ (*lastg)->next = curg;
+ curg->prev = *lastg;
+ curg->next = NULL;
+ *lastg = curg;
+ } else {
+ *firstg = curg;
+ *lastg = curg;
+ curg->prev = NULL;
+ curg->next = NULL;
+ }
+ }
+ else if(!strncmp(buf, "include ", 8)) {
+ if(find_all_configs(strchr(buf, ' ') + 1, 1, first, last, firstg, lastg) != 0) {
+ syslog(LOG_ERR, "%s: %s: failed to process included config file on line %d \"%s\"", __FILE__, __FUNCTION__, line, strchr(buf, ' ') + 1);
+ errors++;
+ }
+ continue;
+ }
+ else if(!strncmp(buf, "-include ", 9)) {
+ if(find_all_configs(strchr(buf, ' ') + 1, 0, first, last, firstg, lastg) != 0) {
+ syslog(LOG_ERR, "%s: %s: failed to process included config file on line %d \"%s\"", __FILE__, __FUNCTION__, line, strchr(buf, ' ') + 1);
+ errors++;
+ }
+ continue;
+ }
+ else {
+ syslog(LOG_ERR, "%s: %s: unrecognised global config option in file \"%s\" on line %d \"%s\"", __FILE__, __FUNCTION__, fn, line, buf);
+ errors++;
+ }
+ }
+ line++;
+ }
+
+ if(mode != 0) {
+ syslog(LOG_ERR, "%s: %s: missing closing bracket at the end of config file \"%s\"", __FILE__, __FUNCTION__, fn);
+ errors++;
+ }
+
+ fclose(fp);
+}
+
+void dump_config(CONFIG **first, CONFIG **last, GROUPS **firstg, GROUPS **lastg)
+{
+ CONFIG *cur;
+ GROUPS *curg;
+ GROUP_MEMBERS *curgm;
+
+ syslog(LOG_INFO, "cfg.debug = \"%d\"", cfg.debug);
+
+ for(cur = *first; cur; cur = cur->next) {
+ syslog(LOG_INFO, "cur->name = \"%s\"", cur->name);
+ syslog(LOG_INFO, "cur->sourceip = \"%s\"", cur->sourceip);
+#if defined(DEBUG)
+ if(cur->srcinfo) {
+ char sbuf[INET6_ADDRSTRLEN];
+
+ syslog(LOG_INFO, "cur->srcinfo = \"%s\"", inet_ntop(cur->srcinfo->ai_family, &cur->srcinfo->ai_addr, sbuf, INET6_ADDRSTRLEN));
+ }
+#endif
+ syslog(LOG_INFO, "cur->checkip = \"%s\"", cur->checkip);
+#if defined(DEBUG)
+ if(cur->dstinfo) {
+ char sbuf[INET6_ADDRSTRLEN];
+
+ syslog(LOG_INFO, "cur->dstinfo = \"%s\"", inet_ntop(cur->dstinfo->ai_family, &cur->dstinfo->ai_addr, sbuf, INET6_ADDRSTRLEN));
+ }
+#endif
+ syslog(LOG_INFO, "cur->eventscript = \"%s\"", cur->eventscript);
+ syslog(LOG_INFO, "cur->notifyscript = \"%s\"", cur->notifyscript);
+ syslog(LOG_INFO, "cur->unknown_up_notify = \"%d\"", cur->unknown_up_notify);
+
+ syslog(LOG_INFO, "cur->max_packet_loss = \"%d\"", cur->max_packet_loss);
+ syslog(LOG_INFO, "cur->max_successive_pkts_lost = \"%d\"", cur->max_successive_pkts_lost);
+ syslog(LOG_INFO, "cur->min_packet_loss = \"%d\"", cur->min_packet_loss);
+ syslog(LOG_INFO, "cur->min_successive_pkts_rcvd = \"%d\"", cur->min_successive_pkts_rcvd);
+ syslog(LOG_INFO, "cur->interval_ms = \"%d\"", cur->interval_ms);
+ syslog(LOG_INFO, "cur->timeout_ms = \"%d\"", cur->timeout_ms);
+
+ syslog(LOG_INFO, "cur->warn_email = \"%s\"", cur->warn_email);
+
+ syslog(LOG_INFO, "cur->check_arp = \"%d\"", cur->check_arp);
+ syslog(LOG_INFO, "cur->device = \"%s\"", cur->device);
+ syslog(LOG_INFO, "cur->ttl = \"%d\"", cur->ttl);
+ syslog(LOG_INFO, "cur->status = \"%d\"", cur->status);
+ syslog(LOG_INFO, "cur->startup_acceleration = \"%d\"", cur->startup_acceleration);
+ syslog(LOG_INFO, "cur->startup_burst_pkts = \"%d\"", cur->startup_burst_pkts);
+ syslog(LOG_INFO, "cur->startup_burst_interval = \"%d\"", cur->startup_burst_interval);
+ }
+
+ for(curg = *firstg; curg; curg = curg->next) {
+ syslog(LOG_INFO, "curg->name = \"%s\"", curg->name);
+ syslog(LOG_INFO, "curg->eventscript = \"%s\"", curg->eventscript);
+ syslog(LOG_INFO, "curg->notifyscript = \"%s\"", curg->notifyscript);
+ syslog(LOG_INFO, "curg->unknown_up_notify = \"%d\"", curg->unknown_up_notify);
+ syslog(LOG_INFO, "curg->warn_email = \"%s\"", curg->warn_email);
+ syslog(LOG_INFO, "curg->logic = \"%s\"", curg->logic == 0 ? "OR" : "AND");
+
+ for(curgm = curg->fgm; curgm; curgm = curgm->next) {
+ syslog(LOG_INFO, "curgm->name = \"%s\"", curgm->name);
+ }
+ }
+}
+
+static int check_addrs(CONFIG *cur)
+{
+ struct in6_addr serveraddr;
+ struct addrinfo hints;
+#if defined(DEBUG)
+ struct addrinfo *rp;
+#endif
+ int rc;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICSERV;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ if((rc = inet_pton(AF_INET, cur->checkip, &serveraddr)) == 1) { /* valid v4 addr */
+ hints.ai_family = AF_INET;
+ hints.ai_flags |= AI_NUMERICHOST;
+ }
+ else if((rc = inet_pton(AF_INET6, cur->checkip, &serveraddr)) == 1) { /* valid v6 addr */
+ hints.ai_family = AF_INET6;
+ hints.ai_flags |= AI_NUMERICHOST;
+ }
+
+ if((rc = getaddrinfo(cur->checkip, "1025", &hints, &(cur->dstinfo))) != 0) {
+ syslog(LOG_ERR, "WARNING: connection \"%s\" checkip is invalid %s, %s", cur->name, cur->checkip, gai_strerror(rc));
+ return(-1);
+ }
+
+#if defined(DEBUG)
+ for(rp = cur->dstinfo; rp; rp = rp->ai_next) {
+ unsigned char *s;
+ char buf[BUFSIZ];
+ char sbuf[INET6_ADDRSTRLEN];
+ int i;
+
+ memset(buf, 0, BUFSIZ);
+ s = (unsigned char *)rp;
+
+ strcat(buf, "hex dump:");
+ for(i = 0; i < sizeof(struct addrinfo); i++)
+ sprintf(buf + strlen(buf), " %2x", s[i]);
+ syslog(LOG_INFO, "%s: %s: dst %s", __FILE__, __FUNCTION__, buf);
+
+ memset(buf, 0, BUFSIZ);
+ s = (unsigned char *)rp;
+
+ strcat(buf, "dec dump:");
+ for(i = 0; i < sizeof(struct addrinfo); i++)
+ sprintf(buf + strlen(buf), " %3d", s[i]);
+ syslog(LOG_INFO, "%s: %s: dst %s", __FILE__, __FUNCTION__, buf);
+
+ syslog(LOG_INFO, "%s: %s: dst %s = %s", __FILE__, __FUNCTION__, cur->checkip, inet_ntop(rp->ai_family, &rp->ai_addr, sbuf, INET6_ADDRSTRLEN));
+ }
+#endif
+
+ if(cur->dstinfo->ai_family == AF_INET6 && cur->check_arp) {
+ syslog(LOG_ERR, "WARNING: connection \"%s\" ipv6 and arping are not compatible", cur->name);
+ return(-1);
+ }
+
+ if(!cur->sourceip || !*cur->sourceip) return(0); /* sourceip is not mandatory */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICSERV;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ if((rc = inet_pton(AF_INET, cur->sourceip, &serveraddr)) == 1) { /* valid v4 addr */
+ hints.ai_family = AF_INET;
+ hints.ai_flags |= AI_NUMERICHOST;
+ }
+ else if((rc = inet_pton(AF_INET6, cur->sourceip, &serveraddr)) == 1) { /* valid v6 addr */
+ hints.ai_family = AF_INET6;
+ hints.ai_flags |= AI_NUMERICHOST;
+ }
+
+ if((rc = getaddrinfo(cur->sourceip, "1025", &hints, &(cur->srcinfo))) != 0) {
+ syslog(LOG_ERR, "WARNING: connection \"%s\" sourceip is invalid %s, %s", cur->name, cur->sourceip, gai_strerror(rc));
+ return(-1);
+ }
+
+#if defined(DEBUG)
+ for(rp = cur->srcinfo; rp; rp = rp->ai_next) {
+ unsigned char *s;
+ char buf[BUFSIZ];
+ char sbuf[INET6_ADDRSTRLEN];
+ int i;
+
+ memset(buf, 0, BUFSIZ);
+ s = (unsigned char *)rp;
+
+ strcat(buf, "hex dump:");
+ for(i = 0; i < sizeof(struct addrinfo); i++)
+ sprintf(buf + strlen(buf), " %2x", s[i]);
+ syslog(LOG_INFO, "%s: %s: src %s", __FILE__, __FUNCTION__, buf);
+
+ memset(buf, 0, BUFSIZ);
+ s = (unsigned char *)rp;
+
+ strcat(buf, "dec dump:");
+ for(i = 0; i < sizeof(struct addrinfo); i++)
+ sprintf(buf + strlen(buf), " %3d", s[i]);
+ syslog(LOG_INFO, "%s: %s: src %s", __FILE__, __FUNCTION__, buf);
+
+ syslog(LOG_INFO, "%s: %s: src %s = %s", __FILE__, __FUNCTION__, cur->checkip, inet_ntop(rp->ai_family, &rp->ai_addr, sbuf, INET6_ADDRSTRLEN));
+ }
+#endif
+
+ if(cur->srcinfo->ai_family != cur->dstinfo->ai_family) {
+ syslog(LOG_ERR, "WARNING: connection \"%s\" sourceip and checkip have unmatching protocol families", cur->name);
+ return(-1);
+ }
+
+ return(0);
+}
+
+/* EOF */