nagircbot-0.0.33/0000755000175000017500000000000011515266716013455 5ustar folkertfolkertnagircbot-0.0.33/ssl.c0000644000175000017500000000066411515266716014430 0ustar folkertfolkert#include "ssl.h" int ssl_handshake( server_t *server ){ SSL_METHOD *meth; SSL_CTX *ctx; BIO *sbio; SSL_library_init(); meth=SSLv23_method(); ctx=SSL_CTX_new(meth); server->ssl = SSL_new(ctx); sbio=BIO_new_socket(server->fd, BIO_NOCLOSE); SSL_set_bio(server->ssl, sbio, sbio); return SSL_connect( server->ssl ); } void ssl_close( server_t *server ){ SSL_shutdown( server->ssl ); SSL_free(server->ssl); } nagircbot-0.0.33/error.h0000644000175000017500000000014111515266716014753 0ustar folkertfolkert/* (C) 2006-2010 by folkert@vanheusden.com GPLv2 applies */ void error_exit(char *format, ...); nagircbot-0.0.33/license.OpenSSL0000644000175000017500000000136711515266716016313 0ustar folkertfolkertThe GPL applies to this program. In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. nagircbot-0.0.33/br.h0000644000175000017500000000152111515266716014230 0ustar folkertfolkert/* (C) 2006-2010 by folkert@vanheusden.com GPLv2 applies */ /* code taken from linux kernel */ #if __GNUC__ == 2 && __GNUC_MINOR__ < 96 #define __builtin_expect(x, expected_value) (x) #endif #ifndef __builtin_expect #define __builtin_expect(x, expected_value) (x) #endif #define likely(x) __builtin_expect((x),1) #define unlikely(x) __builtin_expect((x),0) class buffered_reader { private: int fd, block_size; char *buffer; long long int buffer_length, buffer_pointer; char *mmap_addr, *cur_offset; off64_t size_of_file; int number_of_bytes_in_buffer(void); int read_into_buffer(void); public: buffered_reader(int fd, int block_size=4096); ~buffered_reader(); int garbage_collect(char shrink_buffer=0); char * read_line(void); off64_t file_offset(void); }; nagircbot-0.0.33/Makefile0000644000175000017500000000126611515266716015122 0ustar folkertfolkert# (C) 2006-2011 by folkert@vanheusden.com GPLv2 applies VERSION=0.0.33 DEBUG= -g -D_DEBUG #-fprofile-arcs -ftest-coverage # -pg -g CXXFLAGS+=-Wall -O2 -DVERSION=\"${VERSION}\" $(DEBUG) CFLAGS+=${CXXFLAGS} LDFLAGS+=$(DEBUG) -lcrypto -lssl -lstdc++ OBJS= ssl.o error.o log.o utils.o br.o pl.o anna.o all: nagircbot nagircbot: $(OBJS) $(CC) -Wall -W $(OBJS) $(LDFLAGS) -o nagircbot install: nagircbot cp nagircbot /usr/local/bin clean: rm -f $(OBJS) nagircbot core *.da *.gcov *.bb* package: clean mkdir nagircbot-$(VERSION) cp *.c* *.h Makefile thanks.txt readme.txt license.* nagircbot-$(VERSION) tar czf nagircbot-$(VERSION).tgz nagircbot-$(VERSION) rm -rf nagircbot-$(VERSION) nagircbot-0.0.33/utils.h0000644000175000017500000000143311515266716014767 0ustar folkertfolkert/* (C) 2006-2010 by folkert@vanheusden.com GPLv2 applies */ extern "C" { #include "ssl.h" } void * mymalloc(int size, char *what); void * myrealloc(void *oldp, int newsize, char *what); char * mystrdup(char *in); char * mtstrndup(char *in, int len); void myfree(void *p, char *what); ssize_t WRITE(int fd, char *whereto, size_t len); ssize_t IRCWRITE( server_t server_conn, char *whereto, size_t len); int IRCREAD( server_t server_conn, char *buff, size_t len); int get_filesize(char *filename); time_t get_filechanged(char *filename); void resolve_host(char *host, struct sockaddr_in *addr); int connect_to(char *hoststr); int write_pidfile(char *fname); #define incopy(a) *((struct in_addr *)a) #define max(x, y) ((x) > (y) ? (x) : (y)) #define min(x, y) ((x) < (y) ? (x) : (y)) nagircbot-0.0.33/error.c0000644000175000017500000000065311515266716014756 0ustar folkertfolkert#include #include #include #include #include #include #include void error_exit(char *format, ...) { char buffer[4096]; va_list ap; va_start(ap, format); vsnprintf(buffer, sizeof(buffer), format, ap); va_end(ap); fprintf(stderr, "%s: errno=%d (if applicable)\n", buffer, errno); syslog(LOG_ERR, "'%s': %m", buffer); exit(EXIT_FAILURE); } nagircbot-0.0.33/log.c0000644000175000017500000000050211515266716014377 0ustar folkertfolkert#include #include #include #include #include void dolog(char *format, ...) { char buffer[4096]; va_list ap; va_start(ap, format); vsnprintf(buffer, sizeof(buffer), format, ap); va_end(ap); fprintf(stderr, "%s\n", buffer); syslog(LOG_ERR, "%s", buffer); } nagircbot-0.0.33/pl.h0000644000175000017500000000656211515266716014252 0ustar folkertfolkert/* (C) 2006-2010 by folkert@vanheusden.com GPLv2 applies */ #define TYPE_IGNORE 0 #define TYPE_HOST 1 #define TYPE_SERVICE 2 #define V1_0_MAX_ELEMENTS 32 #define VARTYPE_PCHAR 0 #define VARTYPE_INT 1 #define VARTYPE_TIMET 2 #define VARTYPE_DOUBLE 3 #define STATS_OFFSET(x) (int)(offsetof(struct stats, x)) #define ST_HARD 1 #define ST_SOFT 0 struct v2_0_config { char *str; int offset; int type; }; struct stats { int type; char *host_name; int current_state; char *service_description; char *plugin_output; time_t last_state_change; int active_checks_enabled; int passive_checks_enabled; int notifications_enabled; int problem_has_been_acknowledged; double scheduled_downtime_depth; int state_type; int last_hard_state; double percent_state_change; double check_execution_time; double check_latency; int modified_attributes; int event_handler; int has_been_checked; int should_be_scheduled; int current_attempt; int max_attempts; int last_hard_state_change; int last_time_ok; int last_time_warning; int last_time_unknown; int last_time_critical; time_t last_check; time_t next_check; int check_type; double current_notification_number; int last_notification; int next_notification; int no_more_notifications; int event_handler_enabled; int acknowledgement_type; int flap_detection_enabled; int failure_prediction_enabled; int process_performance_data; int obsess_over_service; int obsess_over_host; time_t last_update; int is_flapping; char * performance_data; char * check_command; int last_time_up; int last_time_down; int last_time_unreachable; /* newly added in 3.0 */ char *author; double check_interval; int check_options; char *check_period; char *comment_data; int comment_id; int current_event_id; int current_notification_id; int current_problem_id; time_t entry_time; int entry_type; int expires; time_t expire_time; char *host_notification_period; int last_event_id; int last_problem_id; char *long_plugin_output; int next_comment_id; char *notification_period; int persistent; double retry_interval; char *service_notification_period; int source; int downtime_id; time_t start_time, end_time; int triggered_by; int fixed; int duration; char *comment; }; void parse_1_0_statuslog(int fd, struct stats **pstats, int *n_stats); void parse_2_0_statuslog(int fd, struct stats **pstats, int *n_stats); void free_stats_array(struct stats *pstats, int n_stats); void sort_stats_array(struct stats *pstats, int n_stats); int host_is_down(struct stats *pstats, int n_stats, char *host_name); int should_i_show_entry(struct stats *pstats, int n_stats, int cur_index, char list_all_problems, char always_notify, char also_acknowledged, char hide_ok); int find_index_by_host_and_service(struct stats *pstats, int n_stats, char *host_name, char *service_description); int check_max_age_last_check(struct stats *pstats, int n_stats, int max_time_last_host_update, int max_time_oldest_host_update, int max_time_last_host_check, int max_time_oldest_host_check, int max_time_last_service_check, int max_time_oldest_service_check, int max_time_oldest_next_service_check, char **message); void calc_stats_stats(struct stats *pstats, int n_stats, char list_all_problems, char always_notify, char also_acknowledged, char hide_ok, int *n_critical, int *n_warning, int *n_ok, int *n_up, int *n_down, int *n_unreachable, int *n_pending); nagircbot-0.0.33/pl.cpp0000644000175000017500000007135311515266716014605 0ustar folkertfolkert/* (C) 2006-2010 by folkert@vanheusden.com GPLv2 applies */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #include "error.h" } #include "utils.h" #include "br.h" #include "pl.h" static struct v2_0_config v2_0_config_elements[] = { {"acknowledgement_type", STATS_OFFSET(acknowledgement_type), VARTYPE_INT}, {"active_checks_enabled", STATS_OFFSET(active_checks_enabled), VARTYPE_INT}, {"author", STATS_OFFSET(author), VARTYPE_PCHAR}, {"check_command", STATS_OFFSET(check_command), VARTYPE_PCHAR}, {"check_execution_time", STATS_OFFSET(check_execution_time), VARTYPE_DOUBLE}, {"check_interval", STATS_OFFSET(check_interval), VARTYPE_DOUBLE}, {"check_latency", STATS_OFFSET(check_latency), VARTYPE_DOUBLE}, {"check_options", STATS_OFFSET(check_options), VARTYPE_INT}, {"check_period", STATS_OFFSET(check_period), VARTYPE_PCHAR}, {"check_type", STATS_OFFSET(check_type), VARTYPE_INT}, {"comment", STATS_OFFSET(comment), VARTYPE_PCHAR}, {"comment_data", STATS_OFFSET(comment_data), VARTYPE_PCHAR}, {"comment_id", STATS_OFFSET(comment_id), VARTYPE_INT}, {"current_attempt", STATS_OFFSET(current_attempt), VARTYPE_INT}, {"current_event_id", STATS_OFFSET(current_event_id), VARTYPE_INT}, {"current_notification_id", STATS_OFFSET(current_notification_id), VARTYPE_INT}, {"current_notification_number", STATS_OFFSET(current_notification_number), VARTYPE_DOUBLE}, {"current_problem_id", STATS_OFFSET(current_problem_id), VARTYPE_INT}, {"current_state", STATS_OFFSET(current_state), VARTYPE_INT}, {"downtime_id", STATS_OFFSET(downtime_id), VARTYPE_INT}, {"duration", STATS_OFFSET(duration), VARTYPE_INT}, {"end_time", STATS_OFFSET(end_time), VARTYPE_TIMET}, {"entry_time", STATS_OFFSET(entry_time), VARTYPE_TIMET}, {"entry_type", STATS_OFFSET(entry_type), VARTYPE_INT}, {"event_handler", STATS_OFFSET(event_handler), VARTYPE_INT}, {"event_handler_enabled", STATS_OFFSET(event_handler_enabled), VARTYPE_INT}, {"expire_time", STATS_OFFSET(expire_time), VARTYPE_TIMET}, {"expires", STATS_OFFSET(expires), VARTYPE_INT}, {"failure_prediction_enabled", STATS_OFFSET(failure_prediction_enabled), VARTYPE_INT}, {"fixed", STATS_OFFSET(fixed), VARTYPE_INT}, {"flap_detection_enabled", STATS_OFFSET(flap_detection_enabled), VARTYPE_INT}, {"has_been_checked", STATS_OFFSET(has_been_checked), VARTYPE_INT}, {"host_name", STATS_OFFSET(host_name), VARTYPE_PCHAR}, {"host_notification_period", STATS_OFFSET(host_notification_period), VARTYPE_PCHAR}, {"is_flapping", STATS_OFFSET(is_flapping), VARTYPE_INT}, {"last_check", STATS_OFFSET(last_check), VARTYPE_TIMET}, {"last_event_id", STATS_OFFSET(last_event_id), VARTYPE_INT}, {"last_hard_state", STATS_OFFSET(last_hard_state), VARTYPE_INT}, {"last_hard_state_change", STATS_OFFSET(last_hard_state_change), VARTYPE_INT}, {"last_notification", STATS_OFFSET(last_notification), VARTYPE_INT}, {"last_problem_id", STATS_OFFSET(last_problem_id), VARTYPE_INT}, {"last_state_change", STATS_OFFSET(last_state_change), VARTYPE_TIMET}, {"last_time_critical", STATS_OFFSET(last_time_critical), VARTYPE_INT}, {"last_time_down", STATS_OFFSET(last_time_down), VARTYPE_INT}, {"last_time_ok", STATS_OFFSET(last_time_ok), VARTYPE_INT}, {"last_time_unknown", STATS_OFFSET(last_time_unknown), VARTYPE_INT}, {"last_time_unreachable", STATS_OFFSET(last_time_unreachable), VARTYPE_INT}, {"last_time_up", STATS_OFFSET(last_time_up), VARTYPE_INT}, {"last_time_warning", STATS_OFFSET(last_time_warning), VARTYPE_INT}, {"last_update", STATS_OFFSET(last_update), VARTYPE_TIMET}, {"long_plugin_output", STATS_OFFSET(long_plugin_output), VARTYPE_PCHAR}, {"max_attempts", STATS_OFFSET(max_attempts), VARTYPE_INT}, {"modified_attributes", STATS_OFFSET(modified_attributes), VARTYPE_INT}, {"next_check", STATS_OFFSET(next_check), VARTYPE_TIMET}, {"next_comment_id", STATS_OFFSET(next_comment_id), VARTYPE_INT}, {"next_notification", STATS_OFFSET(next_notification), VARTYPE_INT}, {"no_more_notifications", STATS_OFFSET(no_more_notifications), VARTYPE_INT}, {"notification_period", STATS_OFFSET(notification_period), VARTYPE_PCHAR}, {"notifications_enabled", STATS_OFFSET(notifications_enabled), VARTYPE_INT}, {"obsess_over_host", STATS_OFFSET(obsess_over_host), VARTYPE_INT}, {"obsess_over_service", STATS_OFFSET(obsess_over_service), VARTYPE_INT}, {"passive_checks_enabled", STATS_OFFSET(passive_checks_enabled), VARTYPE_INT}, {"percent_state_change", STATS_OFFSET(percent_state_change), VARTYPE_DOUBLE}, {"performance_data", STATS_OFFSET(performance_data), VARTYPE_PCHAR}, {"persistent", STATS_OFFSET(persistent), VARTYPE_INT}, {"plugin_output", STATS_OFFSET(plugin_output), VARTYPE_PCHAR}, {"problem_has_been_acknowledged", STATS_OFFSET(problem_has_been_acknowledged), VARTYPE_INT}, {"process_performance_data", STATS_OFFSET(process_performance_data), VARTYPE_INT}, {"retry_interval", STATS_OFFSET(retry_interval), VARTYPE_DOUBLE}, {"scheduled_downtime_depth", STATS_OFFSET(scheduled_downtime_depth), VARTYPE_DOUBLE}, {"service_description", STATS_OFFSET(service_description), VARTYPE_PCHAR}, {"should_be_scheduled", STATS_OFFSET(should_be_scheduled), VARTYPE_INT}, {"source", STATS_OFFSET(source), VARTYPE_INT}, {"start_time", STATS_OFFSET(start_time), VARTYPE_TIMET}, {"state_type", STATS_OFFSET(state_type), VARTYPE_INT}, {"triggered_by", STATS_OFFSET(triggered_by), VARTYPE_INT}, {"type", STATS_OFFSET(type), VARTYPE_INT} }; /* service { host_name=ap service_description=HTTP modified_attributes=0 check_command=check_tcp!80 event_handler= has_been_checked=1 should_be_scheduled=1 check_execution_time=0.009 check_latency=0.712 current_state=0 last_hard_state=0 current_attempt=1 max_attempts=3 state_type=1 last_state_change=1128634047 last_hard_state_change=1128633828 last_time_ok=1129101510 last_time_warning=0 last_time_unknown=1128633828 last_time_critical=1126954624 plugin_output=TCP OK - 0.001 second response time on port 80 performance_data=time=0.001121s;0.000000;0.000000;0.000000;10.000000 last_check=1129101510 next_check=1129101630 check_type=0 current_notification_number=0 last_notification=0 next_notification=0 no_more_notifications=0 notifications_enabled=1 active_checks_enabled=1 passive_checks_enabled=1 event_handler_enabled=1 problem_has_been_acknowledged=0 acknowledgement_type=0 flap_detection_enabled=1 failure_prediction_enabled=1 process_performance_data=1 obsess_over_service=1 last_update=1129101556 is_flapping=0 percent_state_change=0.00 scheduled_downtime_depth=0 } host { host_name=ap modified_attributes=0 check_command=check-host-alive event_handler= has_been_checked=1 should_be_scheduled=0 check_execution_time=0.012 check_latency=0.000 current_state=0 last_hard_state=0 check_type=0 plugin_output=PING OK - Packet loss = 0%, RTA = 1.54 ms performance_data= last_check=1128863442 next_check=0 current_attempt=1 max_attempts=10 state_type=1 last_state_change=1128634057 last_hard_state_change=1128634057 last_time_up=1128863442 last_time_down=1128633868 last_time_unreachable=0 last_notification=1128634057 next_notification=0 no_more_notifications=0 current_notification_number=0 notifications_enabled=1 problem_has_been_acknowledged=0 acknowledgement_type=0 active_checks_enabled=1 passive_checks_enabled=1 event_handler_enabled=1 flap_detection_enabled=1 failure_prediction_enabled=1 process_performance_data=1 obsess_over_host=1 last_update=1129101556 is_flapping=0 percent_state_change=0.00 scheduled_downtime_depth=0 } */ int v2_0_find_entry_type(char *field_name) { int left = 0; int right = (sizeof(v2_0_config_elements) / sizeof(struct v2_0_config)) - 1; while(left <= right) { int mid = (left + right) / 2; int compare = strcmp(field_name, v2_0_config_elements[mid].str); if (compare > 0) left = mid + 1; else if (compare < 0) right = mid - 1; else return mid; } return -1; } void parse_2_0_statuslog(int fd, struct stats **pstats, int *n_stats) { int n_alloc = 0; int type = TYPE_IGNORE; /* start up buffered reader */ buffered_reader bf(fd); *pstats = NULL; *n_stats = 0; for(;;) { char *line = bf.read_line(); if (!line) break; if (strchr(line, '{')) { /* init */ type = TYPE_IGNORE; if (*n_stats == n_alloc) { if (n_alloc) n_alloc *= 2; else n_alloc = 128; *pstats = (struct stats *)myrealloc(*pstats, n_alloc * sizeof(struct stats), "stats array"); if (!*pstats) error_exit("Error allocating memory"); memset(&(*pstats)[*n_stats], 0x00, sizeof(struct stats) * (n_alloc - *n_stats)); } else { memset(&(*pstats)[*n_stats], 0x00, sizeof(struct stats)); } if (strncmp(line, "host", 4) == 0) { type = TYPE_HOST; } else if (strncmp(line, "service", 7) == 0) { type = TYPE_SERVICE; } else { type = TYPE_IGNORE; } } else if (type != TYPE_IGNORE) { char *cmd = line, *is; while(*cmd == ' ' || *cmd == '\t') cmd++; is = strchr(cmd, '='); if (is == NULL) { if (strchr(cmd, '}') != NULL) /* end of definition, store in array */ { if (type == TYPE_HOST && (*pstats)[*n_stats].current_state == 1) /* HOSTS: 0=ok, 1=down, 2=unreachable */ (*pstats)[*n_stats].current_state = 2; (*pstats)[*n_stats].type = type; (*n_stats)++; } } else { int index; char *record = (char *)(&(*pstats)[*n_stats]); char *par = is + 1; *is = 0x00; if ((index = v2_0_find_entry_type(cmd)) != -1) { switch(v2_0_config_elements[index].type) { case VARTYPE_PCHAR: *((char **)(&record[v2_0_config_elements[index].offset])) = mystrdup(par); break; case VARTYPE_INT: *((int *)(&record[v2_0_config_elements[index].offset])) = atoi(par); break; case VARTYPE_TIMET: *((time_t *)(&record[v2_0_config_elements[index].offset])) = atol(par); break; case VARTYPE_DOUBLE: *((double *)(&record[v2_0_config_elements[index].offset])) = atof(par); break; } } else { printf("{%s} ???\n", cmd); } } } /* this one does not use myfree() as the buffered reader does not * use mymalloc() and friends */ free(line); } } int split_1_0_line(char *line, char **out) { int out_index = 0; memset(out, 0x00, sizeof(char *) * V1_0_MAX_ELEMENTS); for(;out_index < V1_0_MAX_ELEMENTS;) { out[out_index++] = line; line = strchr(line, ';'); if (!line) break; *line = 0x00; /* replace ';' with 0x00 */ line++; } return out_index; } void parse_1_0_statuslog(int fd, struct stats **pstats, int *n_stats) { /* start up buffered reader */ buffered_reader bf(fd); *pstats = NULL; *n_stats = 0; for(;;) { int type = TYPE_IGNORE; char *host_name = NULL; int current_state = -1; char *service_description = NULL; char *plugin_output = NULL; time_t last_state_change = 0; char active_checks_enabled = 0; char passive_checks_enabled = 0; char notifications_enabled = 0; char problem_has_been_acknowledged = 0; int scheduled_downtime_depth = 0; char state_type = 0; char last_hard_state = 0; int modified_attributes = 0; int event_handler = 0; int has_been_checked = 0; int should_be_scheduled = 0; int current_attempt = 0; int max_attempts = 0; int last_hard_state_change = 0; int last_time_ok = 0; int last_time_warning = 0; int last_time_unknown = 0; int last_time_critical = 0; time_t last_check = 0; time_t next_check = 0; int check_type = 0; int current_notification_number = 0; int last_notification = 0; int next_notification = 0; int no_more_notifications = 0; int event_handler_enabled = 0; int acknowledgement_type = 0; int flap_detection_enabled = 0; int failure_prediction_enabled = 0; int process_performance_data = 0; int obsess_over_service = 0; time_t last_update = 0; int is_flapping = 0; double percent_state_change = 0; double check_execution_time = 0; double check_latency = 0; char * performance_data = NULL; char * check_command = NULL; int last_time_up = 0; int last_time_down = 0; int last_time_unreachable = 0; char *dummy; char *elements[V1_0_MAX_ELEMENTS]; int n_elem; char *line = bf.read_line(); if (!line) break; if (line[0] == '#') goto skip_line; n_elem = split_1_0_line(line, elements); *pstats = (struct stats *)myrealloc(*pstats, ((*n_stats) + 1) * sizeof(struct stats), "stats array"); if (!*pstats) error_exit("Error allocating memory"); memset(&(*pstats)[*n_stats], 0x00, sizeof(struct stats)); /* [Time of last update] HOST; Host Name (string); Status (OK/DOWN/UNREACHABLE); Last Check Time (long time); Last State Change (long time); Acknowledged (0/1); Time Up (long time); Time Down (long time); Time Unreachable (long time); Last Notification Time (long time); Current Notification Number (#); Notifications Enabled (0/1); Event Handlers Enabled (0/1); Checks Enabled (0/1); Flap Detection Enabled (0/1); Host is Flapping (0/1); Percent State Change (###.##); Scheduled downtime depth (#); Failure Prediction Enabled (0/1); Process Performance Data(0/1); Plugin Output (string) */ /* [Time of last update] SERVICE; Host Name (string); Service Description (string); Status (OK/WARNING/CRITICAL/UNKNOWN); Retry number (#/#); State Type (SOFT/HARD); Last check time (long time); Next check time (long time); Check type (ACTIVE/PASSIVE); Checks enabled (0/1); Accept Passive Checks (0/1); Event Handlers Enabled (0/1); Last state change (long time); Problem acknowledged (0/1); Last Hard State (OK/WARNING/CRITICAL/UNKNOWN); Time OK (long time); Time Unknown (long time); Time Warning (long time); Time Critical (long time); Last Notification Time (long time); Current Notification Number (#); Notifications Enabled (0/1); Latency (#); Execution Time (#); Flap Detection Enabled (0/1); Service is Flapping (0/1); Percent State Change (###.##); Scheduled Downtime Depth (#); Failure Prediction Enabled (0/1); Process Performance Date (0/1); Obsess Over Service (0/1); Plugin Output (string) */ dummy = strchr(elements[0], ' '); if (!dummy) goto skip_line; dummy++; if (strcmp(dummy, "HOST") == 0) type = TYPE_HOST; else if (strcmp(dummy, "SERVICE") == 0) type = TYPE_SERVICE; else if (strcmp(dummy, "PROGRAM") == 0) goto skip_line; else goto skip_line; last_update = atol(elements[0] + 1); if (type == TYPE_HOST) { if (n_elem != 21) goto skip_line; host_name = mystrdup(elements[1]); if (strcmp(elements[2], "UP") == 0) current_state = 0; else current_state = 2; last_check = atol(elements[3]); last_state_change = atol(elements[4]); problem_has_been_acknowledged = atoi(elements[5]); last_time_up = atol(elements[6]); last_time_down = atol(elements[7]); last_time_unreachable = atol(elements[8]); last_notification = atol(elements[9]); current_notification_number = atoi(elements[10]); notifications_enabled = atoi(elements[11]); event_handler_enabled = atoi(elements[12]); active_checks_enabled = atoi(elements[13]); /* in 2.0 it has been split up in passive and active */ flap_detection_enabled = atoi(elements[14]); is_flapping = atoi(elements[15]); percent_state_change = atof(elements[16]); scheduled_downtime_depth = atoi(elements[17]); failure_prediction_enabled = atoi(elements[18]); /* process_performance_data = atoi(elements[19]); */ plugin_output = mystrdup(elements[20]); } else if (type == TYPE_SERVICE) { if (n_elem != 32) goto skip_line; host_name = mystrdup(elements[1]); service_description = mystrdup(elements[2]); if (strcmp(elements[3], "OK") == 0) current_state = 0; else if (strcmp(elements[3], "WARNING") == 0) current_state = 1; else if (strcmp(elements[3], "CRITICAL") == 0) current_state = 2; else if (strcmp(elements[3], "UNKNOWN") == 0 || strcmp(elements[3], "PENDING") == 0) current_state = 3; /* retry_number = atoi(elements[4]); */ if (strcmp(elements[5], "SOFT") == 0) state_type = 0; else state_type = 1; last_check = atol(elements[6]); next_check = atol(elements[7]); if (strcmp(elements[8], "ACTIVE") == 0) check_type = 1; else check_type = 0; active_checks_enabled = atoi(elements[9]); /* accept_passive_checks = atoi(elements[10]); */ event_handler_enabled = atoi(elements[11]); last_state_change = atol(elements[12]); problem_has_been_acknowledged = atoi(elements[13]); if (strcmp(elements[14], "OK") == 0) last_hard_state = 0; else if (strcmp(elements[14], "WARNING") == 0) last_hard_state = 1; else if (strcmp(elements[14], "CRITICAL") == 0) last_hard_state = 2; else if (strcmp(elements[14], "UNKNOWN") == 0) last_hard_state = 3; last_time_ok = atol(elements[15]); last_time_unknown = atol(elements[16]); last_time_warning = atol(elements[17]); last_time_critical = atol(elements[18]); last_notification = atol(elements[19]); current_notification_number = atoi(elements[20]); notifications_enabled = atoi(elements[21]); check_latency = atof(elements[22]); check_execution_time = atof(elements[23]); flap_detection_enabled = atoi(elements[24]); is_flapping = atoi(elements[25]); percent_state_change = atof(elements[26]); scheduled_downtime_depth = atoi(elements[27]); failure_prediction_enabled = atoi(elements[28]); /* process_performance_date = atoi(elements[29]); */ obsess_over_service = atoi(elements[30]); plugin_output = mystrdup(elements[31]); } else error_exit("internal error: type %d unexpected\n", type); (*pstats)[*n_stats].type = type; (*pstats)[*n_stats].host_name = host_name?host_name:mystrdup(""); if (type == TYPE_HOST && current_state == 1) /* HOSTS: 0=ok, 1=down, 2=unreachable */ current_state = 2; (*pstats)[*n_stats].current_state = current_state; (*pstats)[*n_stats].service_description = service_description?service_description:mystrdup(""); (*pstats)[*n_stats].plugin_output = plugin_output?plugin_output:mystrdup(""); (*pstats)[*n_stats].last_state_change = last_state_change; (*pstats)[*n_stats].active_checks_enabled = active_checks_enabled; (*pstats)[*n_stats].passive_checks_enabled = passive_checks_enabled; (*pstats)[*n_stats].notifications_enabled = notifications_enabled; (*pstats)[*n_stats].problem_has_been_acknowledged = problem_has_been_acknowledged; (*pstats)[*n_stats].scheduled_downtime_depth = scheduled_downtime_depth; (*pstats)[*n_stats].state_type = state_type; (*pstats)[*n_stats].last_hard_state = last_hard_state; (*pstats)[*n_stats].modified_attributes = modified_attributes; (*pstats)[*n_stats].event_handler = event_handler; (*pstats)[*n_stats].has_been_checked = has_been_checked; (*pstats)[*n_stats].should_be_scheduled = should_be_scheduled; (*pstats)[*n_stats].current_attempt = current_attempt; (*pstats)[*n_stats].max_attempts = max_attempts; (*pstats)[*n_stats].last_hard_state_change = last_hard_state_change; (*pstats)[*n_stats].last_time_ok = last_time_ok; (*pstats)[*n_stats].last_time_warning = last_time_warning; (*pstats)[*n_stats].last_time_unknown = last_time_unknown; (*pstats)[*n_stats].last_time_critical = last_time_critical; (*pstats)[*n_stats].last_check = last_check; (*pstats)[*n_stats].next_check = next_check; (*pstats)[*n_stats].check_type = check_type; (*pstats)[*n_stats].current_notification_number = current_notification_number; (*pstats)[*n_stats].last_notification = last_notification; (*pstats)[*n_stats].next_notification = next_notification; (*pstats)[*n_stats].no_more_notifications = no_more_notifications; (*pstats)[*n_stats].event_handler_enabled = event_handler_enabled; (*pstats)[*n_stats].acknowledgement_type = acknowledgement_type; (*pstats)[*n_stats].flap_detection_enabled = flap_detection_enabled; (*pstats)[*n_stats].failure_prediction_enabled = failure_prediction_enabled; (*pstats)[*n_stats].process_performance_data = process_performance_data; (*pstats)[*n_stats].obsess_over_service = obsess_over_service; (*pstats)[*n_stats].last_update = last_update; (*pstats)[*n_stats].is_flapping = is_flapping; (*pstats)[*n_stats].percent_state_change = percent_state_change; (*pstats)[*n_stats].check_execution_time = check_execution_time; (*pstats)[*n_stats].check_latency = check_latency; (*pstats)[*n_stats].performance_data = performance_data; (*pstats)[*n_stats].check_command = check_command; (*pstats)[*n_stats].last_time_up = last_time_up; (*pstats)[*n_stats].last_time_down = last_time_down; (*pstats)[*n_stats].last_time_unreachable = last_time_unreachable; (*n_stats)++; skip_line: free(line); } close(fd); } void free_stats_array(struct stats *pstats, int n_stats) { if (pstats) { for(int loop=0; loop current_state < p2 -> current_state) return 1; else if (p1 -> current_state == p2 -> current_state) { if (p1 -> last_state_change < p2 -> last_state_change) return 1; return p2 -> last_state_change - p1 -> last_state_change; } return -1; } void sort_stats_array(struct stats *pstats, int n_stats) { if (n_stats > 1) qsort(pstats, n_stats, sizeof(struct stats), sort_compare_func); } int host_is_down(struct stats *pstats, int n_stats, char *host_name) { for(int loop=0; loop 3) error_exit("internal error: state %d not known", pstats[cur_index].current_state); return 1; } int find_index_by_host_and_service(struct stats *pstats, int n_stats, char *host_name, char *service_description) { int loop; static int last = 0; if (service_description) { for(loop=0; loop max_diff) { char *time_str = ctime(&check_time); char *dummy = strchr(time_str, '\n'); *dummy = 0x00; snprintf(buffer, sizeof(buffer), "limit reached of \"%s\" for %s: %d seconds (last check: %s (%d), max diff: %d)", descr, what?what:"?", cur_diff, time_str, (int)check_time, max_diff); *message = strdup(buffer); return -1; } return 0; } int check_max_age_last_check(struct stats *pstats, int n_stats, int max_time_last_host_update, int max_time_oldest_host_update, int max_time_last_host_check, int max_time_oldest_host_check, int max_time_last_service_check, int max_time_oldest_service_check, int max_time_oldest_next_service_check, char **message) { time_t now = time(NULL); int index; time_t most_recent_host_update = 0; time_t most_recent_host_check = 0; time_t most_recent_last_service_check = 0; time_t oldest_next_service_check = now; for(index=0; index #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" #include "pl.h" extern "C" { #include "error.h" #include "ssl.h" #include "log.h" } #define S_DISCONNECTED 1 #define S_CONNECTED 2 #define S_JOINING_CHANNEL 3 #define S_ON_CHANNEL 4 #define S_DISCONNECTING 127 #define L_HOST 1 #define L_FILE 2 #define ST_HARD 1 #define ST_SOFT 0 int check_interval = 60; /* check for new events every 1 minute */ int default_sleep = 2; /* initial sleep time between connect failures */ int max_sleep_time = 300; double sleep_multiply_factor = 2.0; int minimum_time_for_successfull_login = 25; // one needs to be on-channel for at least 5 seconds to be considered a successfull login int join_timeout = 5; // it should take no longer then 5 seconds to join a channel, otherwhise: abort connection and retry int max_n_join_tries = 2; // try 2 times to get on a channel char *server = "localhost:6667"; /* default irc server */ char *channel = "#nagircbot"; /* default channel to connect to */ char *nick_prefix = ""; /* prefix text for all messages sent to channel */ char *keyword = NULL; /* keyword for the channel to connect to */ char *nick = "nagircbot"; char *user = "nagircbot"; char *password = NULL; int one_line = 1; char *username = "Nagios IRC Bot " VERSION ", (C) www.vanheusden.com"; /* complete username */ int verbose = 255; /* default is log everything */ char *statuslog = "/usr/local/nagios/var/status.log"; int statuslog_version = 2; int statuslog_location = L_FILE; char use_colors = 0; char topic_summary = 0; char hard_only = 1; int max_time_last_host_update = 300, max_time_oldest_host_update = 3600, max_time_last_host_check = 300, max_time_oldest_host_check = 3 * 86400, max_time_last_service_check = 20 * 60, max_time_oldest_service_check = 3 * 86400, max_time_oldest_next_service_check = 20 * 60; int irc_server_keep_alive = 60; /* send an irc-command at least every 300 seconds (currently 'TIME') */ int announce_global_status_interval = 0; time_t last_announce_global_status_interval = 0; char critical_only = 0; regex_t *filters = NULL; int n_filters = 0; int use_ssl = 0; server_t server_conn; char *state_str[4] = { " OK ", "WARN", "CRIT", " ?? " }; char *color_str[4]; struct stats *prev = NULL; int n_prev = 0; char topic[4096] = { 0 }; time_t last_irc_io = 0; char *pidfile = NULL; int send_irc(server_t server_conn, char *format, ...) { int rc; char buffer[4096]; va_list ap; va_start(ap, format); vsnprintf(buffer, sizeof(buffer) - 3, format, ap); va_end(ap); if (verbose > 1) dolog("OUT: `%s'", buffer); strcat(buffer, "\r\n"); /* yes this is safe: check the vsnprintf command */ rc = IRCWRITE(server_conn, buffer, strlen(buffer)); if (rc == -1) { dolog("error sending: -1"); return -1; } else if (rc == 0) { dolog("connection closed"); return -1; } time(&last_irc_io); return 0; } int irc_set_nick(server_t server_conn, char *nick) { if (send_irc(server_conn, "NICK %s", nick) == -1) return -1; return 0; } int irc_login(server_t server_conn, char *user, char *username, char *server, char *password) { if (password != NULL && send_irc(server_conn, "PASS %s", password) == -1) return -1; if (irc_set_nick(server_conn, nick) == -1) return -1; /* FIXME: localhost must be, ehr, local host */ if (send_irc(server_conn, "USER %s \"localhost\" \"%s\" :%s", user, server, username) == -1) return -1; return 0; } int irc_join_channel(server_t server_conn, char *channel, char *keyword) { if (keyword != NULL) return send_irc(server_conn, "JOIN %s %s", channel, keyword); return send_irc(server_conn, "JOIN %s", channel); } int irc_topic(server_t server_conn, char *channel, char *topic) { return send_irc(server_conn, "TOPIC %s :%s", channel, topic); } int check_ping(server_t server_conn, char *data) { if (strncmp(data, "PING ", 5) == 0) { char *colon = strchr(data, ':'); char *cr = strchr(data, '\r'); char *lf = strchr(data, '\n'); if (cr>lf && cr != NULL) cr[1] = 0x00; else if (lf != NULL) lf[1] = 0x00; if (colon) { if (send_irc(server_conn, "PONG %s", colon + 1) == -1) return -1; } else if (verbose > 1) { dolog("Malformed PING request (%s)", data); } } return 0; } int irc_privmsg(server_t server_conn, char *channel, char *msg) { return send_irc(server_conn, "PRIVMSG %s :%s", channel, msg); } int irc_time(server_t server_conn) { return send_irc(server_conn, "TIME"); } void load_statuslog(char *statuslog, char is_file, char is_20_format, int prev_n_elements_in_stats_array, struct stats **pstats, int *n_stats) { char reload = 0; for(;;) { int fd; /* open file or connection to nagios status socket */ if (is_file == 1) /* file */ fd = open64(statuslog, O_RDONLY); else fd = connect_to(statuslog); if (fd == -1) { dolog("Failed to open nagios status-log at %s\n", statuslog); sleep(1); continue; } /* file/socket open, load data */ if (is_20_format) parse_2_0_statuslog(fd, pstats, n_stats); else parse_1_0_statuslog(fd, pstats, n_stats); close(fd); if (*n_stats == prev_n_elements_in_stats_array) { break; } dolog("Number of elements in status-log is different (%d) from previous run (%d), retrying", *n_stats, prev_n_elements_in_stats_array); reload = 1; sleep(1); /* remember the current number of elements for this load */ prev_n_elements_in_stats_array = *n_stats; /* and free up - it'll be reloaded */ free_stats_array(*pstats, *n_stats); } if (reload) { dolog("Size of status.log is stable (%d elements), continuing", *n_stats); } } int emit_status(server_t server_conn, char *channel, struct stats *what) { int loop; char buffer[4096]; char *prefix = "", *suffix = ""; struct tm *ptm = localtime(&what -> last_state_change); if (use_colors) { prefix = color_str[what -> current_state]; suffix = "\03"; } if (n_filters || one_line) { snprintf(buffer, sizeof(buffer), "%s%s%04d/%02d/%02d %02d:%02d %s %s %s %s%s", prefix, nick_prefix, ptm -> tm_year + 1900, ptm -> tm_mon + 1, ptm -> tm_mday, ptm -> tm_hour, ptm -> tm_min, state_str[what -> current_state], what -> host_name?what -> host_name:"", what -> service_description?what -> service_description:"", what -> plugin_output?what -> plugin_output:"", suffix); } /* regexp matches? then do not emit */ for(loop=0; loop tm_year + 1900, ptm -> tm_mon + 1, ptm -> tm_mday, ptm -> tm_hour, ptm -> tm_min); if (irc_privmsg(server_conn, channel, buffer) == -1) return -1; if (irc_privmsg(server_conn, channel, state_str[what -> current_state]) == -1) return -1; if (irc_privmsg(server_conn, channel, (char *)(what -> host_name?what -> host_name:"")) == -1) return -1; if (irc_privmsg(server_conn, channel, (char *)(what -> service_description?what -> service_description:"")) == -1) return -1; snprintf(buffer, sizeof(buffer), "%s%s", (char *)(what -> plugin_output?what -> plugin_output:""), suffix); if (irc_privmsg(server_conn, channel, buffer) == -1) return -1; } return 0; } void calc_statistics(struct stats *stats, int n_stats, char list_all_problems, char always_notify, char also_acknowledged, char hide_ok, char *buffer, int buffer_size) { int n_critical=0, n_warning=0, n_ok=0, n_up=0, n_down=0, n_unreachable=0, n_pending=0; calc_stats_stats(stats, n_stats, list_all_problems, always_notify, also_acknowledged, hide_ok, &n_critical, &n_warning, &n_ok, &n_up, &n_down, &n_unreachable, &n_pending); snprintf(buffer, buffer_size, "Critical: %d, warning: %d, ok: %d, up: %d, down: %d, unreachable: %d, pending: %d", n_critical, n_warning, n_ok, n_up, n_down, n_unreachable, n_pending); } int check_nagios_status(server_t server_conn) { struct stats *cur = NULL; int n_cur = 0; int loop; int any_shown = 0; #ifdef _DEBUG time_t now = time(NULL); printf("Checking @ %s", ctime(&now)); #endif load_statuslog(statuslog, statuslog_location == L_FILE?1:0, statuslog_version == 2?1:0, n_prev, &cur, &n_cur); if (topic_summary) { char buffer[4096]; calc_statistics(cur, n_cur, 0, 0, 0, 1, buffer, sizeof(buffer)); if (strcmp(topic, buffer) != 0) { strcpy(topic, buffer); if (irc_topic(server_conn, channel, buffer) == -1) return -1; } } if (announce_global_status_interval > 0) { if ((now - last_announce_global_status_interval) >= announce_global_status_interval) { char buffer[4096]; last_announce_global_status_interval = now; calc_statistics(cur, n_cur, 0, 0, 0, 1, buffer, sizeof(buffer)); if (irc_privmsg(server_conn, channel, buffer) == -1) return -1; } } for(loop=0; loop 1) dolog("reload_statuslog started"); if (statuslog_location == L_FILE) /* file */ fd_sl = open64(statuslog, O_RDONLY); else fd_sl = connect_to(statuslog); if (fd_sl != -1) { if (statuslog_version == 2) parse_2_0_statuslog(fd_sl, &cur, &n_cur); else parse_1_0_statuslog(fd_sl, &cur, &n_cur); close(fd_sl); free_stats_array(prev, n_prev); prev = cur; n_prev = n_cur; return 0; } dolog("reload failed: %s", strerror(errno)); return -1; } char * check_nagios() { char *message = NULL; (void)check_max_age_last_check(prev, n_prev, max_time_last_host_update, max_time_oldest_host_update, max_time_last_host_check, max_time_oldest_host_check, max_time_last_service_check, max_time_oldest_service_check, max_time_oldest_next_service_check, &message); return message; } int do_nagircbot(server_t server_conn, char *channel) { time_t last_check = 0; for(;;) { fd_set rfds; struct timeval tv; time_t now = time(NULL); if ((now - last_check) >= check_interval) { if (check_nagios_status(server_conn) == -1) return -1; last_check = now; } if (now >= (last_irc_io + irc_server_keep_alive)) { if (irc_time(server_conn) == -1) return -1; } FD_ZERO(&rfds); FD_SET(server_conn.fd, &rfds); tv.tv_sec = max(check_interval - (now - last_check), 0); tv.tv_usec = 0; if (irc_server_keep_alive > 0) { tv.tv_sec = min(max(0, (last_irc_io + irc_server_keep_alive) - now), tv.tv_sec); } if (announce_global_status_interval > 0) { tv.tv_sec = min(max(0, (last_announce_global_status_interval + announce_global_status_interval) - now), tv.tv_sec); } if (select(server_conn.fd + 1, &rfds, NULL, NULL, &tv) == -1) { if (errno == EAGAIN || errno == EINTR) continue; error_exit("select() failed %s\n", strerror(errno)); } if (FD_ISSET(server_conn.fd, &rfds)) { char recv_buffer[4096]; int rc = IRCREAD(server_conn, recv_buffer, sizeof(recv_buffer) - 1); if (rc == 0) { dolog("connection closed by IRC server"); return -1; } else if (rc == -1) { if (errno != EAGAIN && errno != EINTR) { dolog("error transmitting data to IRC server: %s", strerror(errno)); return -1; } } else { char *next_response = recv_buffer; char *response = NULL; char *cmd = NULL; char *crlf = NULL; recv_buffer[rc] = 0x00; while ((response = next_response) && (crlf = strchr( response, '\r'))) { if (*(crlf + 1) != '\n') { dolog( "Malformed server response: `%s' at `%s'.", recv_buffer, response ); return -1; } *crlf = '\0'; if (( crlf + 2 ) - recv_buffer < rc) next_response = crlf + 2; else next_response = NULL; if (verbose > 1) dolog("IN: `%s'", response); if (check_ping(server_conn, response) == -1) return -1; cmd = strchr(response, ' '); if (cmd) { while(*cmd == ' ') cmd++; if (strncmp(cmd, "KICK ", 5) == 0) { char *dummy = strchr(cmd, ' '); if (dummy) { while(*dummy == ' ') dummy++; dummy = strchr(dummy, ' '); } if (dummy) { while(*dummy == ' ') dummy++; if (strncmp(dummy, nick, strlen(nick)) == 0) { dolog("nagircbot got kicked (%s)", response); return -1; } else if (verbose > 1) { dolog("user %s got kicked from channel", dummy); } } } else if (strncmp(cmd, "PRIVMSG ", 8) == 0) { /* :flok!~flok@rammstein.amc.nl PRIVMSG nagircbot :test */ char *to_me = &cmd[8]; while(*to_me == ' ') to_me++; /* message to this bot? */ if (strncmp(to_me, nick, strlen(nick)) == 0) { /* yes */ char *msg = strchr(cmd, ':'); char *from_who = response + 1; char *dummy = strchr(from_who, '!'); if (msg != NULL && dummy != NULL) { msg++; *dummy = 0x00; if (strcasecmp(msg, "help") == 0) { int rc = 0; dolog("help requested by %s", from_who); rc |= irc_privmsg(server_conn, from_who, "resend - resend the last known problems"); rc |= irc_privmsg(server_conn, from_who, "statistics - returns the number of criticals/warnings/etc."); rc |= irc_privmsg(server_conn, from_who, "reload - completely forced reload the nagios status"); rc |= irc_privmsg(server_conn, from_who, "check - check if nagios is still running"); if (rc == -1) return -1; } else if (strcmp(msg, "resend") == 0) { dolog("resend requested by %s", from_who); if (resend_nagios_status(server_conn, from_who) == -1) return -1; } else if (strcmp(msg, "check") == 0) { char *message; int rc; dolog("nagios check requested by %s", from_who); message = check_nagios(); if (message) { char buffer[4096]; snprintf(buffer, sizeof(buffer), "Nagios has stopped running! -> %s", message); rc = irc_privmsg(server_conn, from_who, buffer); free(message); } else rc = irc_privmsg(server_conn, from_who, "Nagios is still running"); if (rc == -1) return -1; } else if (strcmp(msg, "statistics") == 0) { char buffer[4096]; dolog("statistics requested by %s", from_who); calc_statistics(prev, n_prev, 0, 0, 0, 1, buffer, sizeof(buffer)); if (irc_privmsg(server_conn, from_who, buffer) == -1) return -1; } else if (strcmp(msg, "reload") == 0) { dolog("reload requested by %s", from_who); if (reload_statuslog() == -1) { if (irc_privmsg(server_conn, from_who, "cannot access status.log") == -1) return -1; } else { if (irc_privmsg(server_conn, from_who, "nagios status reloaded") == -1) return -1; } } else { char buffer[4096]; dolog("giberish sent by %s", from_who); snprintf(buffer, sizeof(buffer), "'%s' is not understood - send 'help' for help", msg); if (irc_privmsg(server_conn, from_who, buffer) == -1) return -1; if (send_help(server_conn, from_who) == -1) return -1; } } } } else if (strncmp(cmd, "QUIT ", 5) == 0) { char *quit_nick = &response[1]; char *exclamation_mark = strchr(quit_nick, '!'); if (exclamation_mark) *exclamation_mark = 0x00; if (strcmp(nick, quit_nick) == 0) { dolog("Got QUITed (%s)", cmd); return -1; } else if (verbose > 1) { dolog("user %s quit", quit_nick); } } } } } } } dolog("NagIRCBot dropped of IRC server"); return -1; } void sighandler(int pid) { if (pid == SIGTERM) { if (pidfile) unlink(pidfile); exit(1); } } void version(void) { printf("nagircbot, v" VERSION " (C) 2006-2011 by folkert@vanheusden.com\n"); } void usage(void) { version(); printf("\n"); printf("-f path to status.log ('status_file' parameter in nagios.cfg)\n"); printf("-F host:port for retrieving status.log\n"); printf("-x status.log is in nagios 1.0 format\n"); printf("-X status.log is in nagios 2.0/3.0 format\n"); printf("-s IRC server to connect to (host:port)\n"); printf("-c channel to connect to (#channel - do not forget to escape the '#' in your shell)\n"); printf("-k keyword for the channel to connect to (default: no keyword)\n"); printf("-C use colors\n"); printf("-n nick\n"); printf("-u username (for logging into the irc server)\n"); printf("-U name (as seen by other users)\n"); printf("-p password (for logging into the irc server)\n"); printf("-N prefix for all in-channel messages, e.g. for nick highlight\n"); printf("-m display all information on separate lines\n"); printf("-t show a summary in the topic-line\n"); printf("-i check interval (in seconds - default 60)\n"); printf("-I how often to announce the global status in the channel (in seconds, 0 for off)\n"); printf(" do not set it smaller then the -i value\n"); printf("-d do not fork into the background\n"); printf("-T x checks to see if nagios is still running. comma-seperated list\n"); printf(" (without spaces!) with the following elements:\n"); printf(" max_time_last_host_update, max_time_oldest_host_update,\n"); printf(" max_time_last_host_check, max_time_oldest_host_check,\n"); printf(" max_time_last_service_check, max_time_oldest_service_check,\n"); printf(" max_time_oldest_next_service_check\n"); printf(" send 'check' in a private message to invoke the check\n"); printf("-z user user to run as\n"); printf("-H show only state type 'HARD' (default)\n"); printf("-S show also state type 'SOFT'\n"); printf("-R only announce CRITICAL/UNKNOWN errors on the channel\n"); printf("-A x filter (omit) lines that match with the given regular expression\n"); printf("-P x write pid to file x\n"); printf("-e Use encryption (SSL) (default: no)\n"); } void add_filter(char *string) { filters = (regex_t *)realloc(filters, sizeof(regex_t) * (n_filters + 1)); if (!filters) error_exit("add_filter: out of memory"); if (regcomp(&filters[n_filters], string, REG_EXTENDED)) error_exit("add_filter: failed to compile regexp '%s'", string); n_filters++; } int main(int argc, char *argv[]) { int state = S_DISCONNECTED; int fd = -1; int sleep_time = default_sleep; int c; int do_fork = 1; time_t time_join_channel_started = (time_t)0; time_t time_tcp_connected = (time_t)0; int join_tries = 0; char *runas = NULL; color_str[0] = mystrdup("_3,1 "); color_str[1] = mystrdup("_8,1 "); color_str[2] = mystrdup("_4,1 "); color_str[3] = mystrdup("_11,1 "); color_str[0][0] = color_str[1][0] = color_str[2][0] = color_str[3][0] = 3; while((c = getopt(argc, argv, "N:A:eRP:xXF:f:i:hHSs:c:k:Ctn:u:U:p:T:mvdVz:I:")) != -1) { switch(c) { case 'A': add_filter(optarg); break; case 'R': critical_only = 1; break; case 'e': use_ssl = 1; break; case 'P': pidfile = optarg; break; case 'I': announce_global_status_interval = atoi(optarg); break; case 'z': runas = optarg; break; case 'T': { char *dummy = optarg; max_time_last_host_update = atoi(dummy); dummy = strchr(dummy, ',') + 1; max_time_oldest_host_update = atoi(dummy); dummy = strchr(dummy, ',') + 1; max_time_last_host_check = atoi(dummy); dummy = strchr(dummy, ',') + 1; max_time_oldest_host_check = atoi(dummy); dummy = strchr(dummy, ',') + 1; max_time_last_service_check = atoi(dummy); dummy = strchr(dummy, ',') + 1; max_time_oldest_service_check = atoi(dummy); dummy = strchr(dummy, ',') + 1; max_time_oldest_next_service_check = atoi(dummy); break; } case 'H': hard_only = 1; break; case 'S': hard_only = 0; break; case 'd': do_fork = 0; break; case 't': topic_summary = 1; break; case 'C': use_colors = 1; break; case 'm': one_line = 0; break; case 'N': nick_prefix = mystrdup(optarg); break; case 'p': password = mystrdup(optarg); break; case 'U': username = mystrdup(optarg); break; case 'n': nick = mystrdup(optarg); break; case 'u': user = mystrdup(optarg); break; case 's': server = mystrdup(optarg); break; case 'c': channel = mystrdup(optarg); break; case 'k': keyword = mystrdup(optarg); break; case 'x': statuslog_version = 1; break; case 'X': statuslog_version = 2; break; case 'f': statuslog = optarg; statuslog_location = L_FILE; break; case 'F': statuslog = optarg; statuslog_location = L_HOST; break; case 'i': check_interval = atoi(optarg); break; case 'v': verbose = 1; break; case 'V': version(); return 0; case 'h': usage(); return 0; default: usage(); return 1; } } if (do_fork) { if (daemon(0, 0) == -1) { error_exit("Failed to become daemon process!"); } } if (pidfile) write_pidfile(pidfile); if (runas) { struct passwd *p = getpwnam(runas); if (p) { if (setgid(p -> pw_gid) == -1) error_exit("setgid(%d) failed", p -> pw_gid); if (setuid(p -> pw_uid) == -1) error_exit("setuid(%d) failed", p -> pw_uid); } else { error_exit("User '%s' not found.", runas); } } signal(SIGPIPE, SIG_IGN); signal(SIGTERM, sighandler); server_conn.addr = server; for(;;) { if (state == S_DISCONNECTED) { dolog("Connecting to %s", server); fd = connect_to(server); if (fd == -1) { if (verbose > 1) dolog("Cannot connect to %s: %m, will sleep %d seconds", server, sleep_time); sleep(sleep_time); if (sleep_time < max_sleep_time) sleep_time = (int)((double)sleep_time * 1.5); else sleep_time = max_sleep_time; } else { server_conn.fd = fd; if( use_ssl ) { dolog("Doing SSL handshake"); if( !ssl_handshake( &server_conn ) ){ dolog("SSL handshake failed!"); return 1; } } state = S_CONNECTED; join_tries = 0; time_tcp_connected = time(NULL); } if (verbose == 1) dolog("Connected to IRC server %s", server); } if (state == S_CONNECTED) { dolog("Logging in..."); if (irc_login(server_conn, user, username, server, password) == -1) state = S_DISCONNECTING; if (irc_join_channel(server_conn, channel, keyword) == -1) state = S_DISCONNECTING; state = S_JOINING_CHANNEL; time_join_channel_started = time(NULL); } if (state == S_JOINING_CHANNEL) { fd_set rfds; struct timeval tv; dolog("Joining channel..."); FD_ZERO(&rfds); FD_SET(server_conn.fd, &rfds); tv.tv_sec = 1; tv.tv_usec = 0; if (select(server_conn.fd + 1, &rfds, NULL, NULL, &tv) == -1) { if (errno != EAGAIN && errno != EINTR) error_exit("select() failed"); } if (FD_ISSET(server_conn.fd, &rfds)) { char recv_buffer[4096]; int rc = IRCREAD(server_conn, recv_buffer, sizeof(recv_buffer) - 1); if (rc == 0) state = S_DISCONNECTING; else if (rc == -1) { if (errno != EAGAIN && errno != EINTR) { dolog("failed joining channel: %s", strerror(errno)); state = S_DISCONNECTING; } } else { char *cmd, *pnt = recv_buffer, *end_marker; recv_buffer[rc] = 0x00; if (check_ping(server_conn, recv_buffer) == -1) return -1; do { end_marker = strchr(pnt, '\n'); if (end_marker) *end_marker = 0x00; if (!end_marker) end_marker = strchr(pnt, '\r'); if (end_marker) *end_marker = 0x00; #ifdef _DEBUG // printf("[%s]", pnt); #endif cmd = strchr(pnt, ' '); if (cmd) { while(*cmd == ' ') cmd++; if (strncmp(cmd, "JOIN ", 5) == 0) { if (verbose > 1) dolog("on channel"); state = S_ON_CHANNEL; } else if (strncmp(cmd, "KICK ", 5) == 0) { char *dummy = strchr(cmd, ' '); if (dummy) { while(*dummy == ' ') dummy++; dummy = strchr(dummy, ' '); } if (dummy) { while(*dummy == ' ') dummy++; if (strncmp(dummy, nick, strlen(nick)) == 0) state = S_CONNECTED; } } } pnt = end_marker + 1; } while(end_marker); } } } if (state == S_JOINING_CHANNEL && (time(NULL) - time_join_channel_started) > join_timeout) { if (++join_tries == max_n_join_tries) { state = S_DISCONNECTING; dolog("joining the channel %s too to long (%ds, timeout set to %ds), aborting and retrying ", channel, time(NULL) - time_join_channel_started, join_timeout); } else { state = S_CONNECTED; dolog("failed joining channel %s, retrying (%d/%d)", channel, join_tries, max_n_join_tries); } } if (state == S_ON_CHANNEL) { dolog("On channel, starting nagtail..."); sleep_time = default_sleep; (void)do_nagircbot(server_conn, channel); state = S_DISCONNECTING; } if (state == S_DISCONNECTING) { int took = time(NULL) - time_tcp_connected; dolog("Disconnected"); close(fd); fd = -1; state = S_DISCONNECTED; dolog("Session took %d seconds", took); if (took < minimum_time_for_successfull_login) { dolog("Will sleep %d seconds before retrying", sleep_time); sleep(sleep_time); if (sleep_time < max_sleep_time) sleep_time = (int)((double)sleep_time * sleep_multiply_factor); else sleep_time = max_sleep_time; } } } return 0; } nagircbot-0.0.33/utils.cpp0000644000175000017500000002054211515266716015324 0ustar folkertfolkert/* (C) 2006-2010 by folkert@vanheusden.com GPLv2 applies */ #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #include "error.h" } #include "utils.h" #ifdef _DEBUG typedef struct { void *p; char *descr; int size; } memlist; memlist *pm = NULL; int n_pm = 0; void LOG(char *s, ...) { va_list ap; FILE *fh = fopen("log.log", "a+"); if (!fh) error_exit("can't access log.log"); va_start(ap, s); vfprintf(fh, s, ap); va_end(ap); fclose(fh); } void dump_mem(int sig) { int loop; signal(SIGHUP, dump_mem); if (sig != SIGHUP) error_exit("unexpected signal %d for dump_mem\n", sig); LOG("%d elements of memory used\n", n_pm); for(loop=0; loop then configurable * via configurationfile with number of retries and/or * sleep * ---------------------------------------------------- */ void *dummy = realloc(oldp, newsize); if (!dummy) error_exit("failed to reallocate to %d bytes for %s\n", newsize, what); #endif return dummy; } void * mymalloc(int size, char *what) { void *dummy = myrealloc(NULL, size, what); if (!dummy) error_exit("failed to allocate %d bytes for %s\n", size, what); return dummy; } char * mystrndup(char *in, int len) { #ifdef _DEBUG char *dummy = (char *)mymalloc(len + 1, in); if (!dummy) error_exit("failed to copy string '%s': out of memory?\n", in); memcpy(dummy, in, len + 1); return dummy; #else char *dummy = strndup(in, len); if (!dummy) error_exit("failed to copy string '%s': out of memory?\n", in); return dummy; #endif } char * mystrdup(char *in) { return mystrndup(in, strlen(in)); } int IRCREAD( server_t server_conn, char *buff, size_t len){ if( server_conn.ssl ){ return SSL_read( server_conn.ssl, buff, len ); } return read( server_conn.fd, buff, len ); } ssize_t IRCWRITE(server_t server_conn, char *whereto, size_t len) { ssize_t cnt=0; while(len>0) { ssize_t rc; if( server_conn.ssl ){ rc = SSL_write( server_conn.ssl, whereto, len); }else{ rc = write(server_conn.fd, whereto, len); } if (rc == -1) { if (errno != EINTR && errno != EINPROGRESS && errno != EAGAIN) { syslog(LOG_INFO, "Error sending to IRC server: %m"); return -1; } } else if (rc == 0) { return -1; } else { whereto += rc; len -= rc; cnt += rc; } } return cnt; } ssize_t WRITE(int fd, char *whereto, size_t len) { ssize_t cnt=0; while(len>0) { ssize_t rc; rc = write(fd, whereto, len); if (rc == -1) { if (errno != EINTR && errno != EINPROGRESS && errno != EAGAIN) { syslog(LOG_INFO, "Error sending to IRC server: %m"); return -1; } } else if (rc == 0) { return -1; } else { whereto += rc; len -= rc; cnt += rc; } } return cnt; } int get_filesize(char *filename) { struct stat buf; if (stat(filename, &buf) == -1) { if (errno != ENOENT) error_exit("stat failed for %s", filename); return -1; } return buf.st_size; } time_t get_filechanged(char *filename) { struct stat buf; if (stat(filename, &buf) == -1) { if (errno != ENOENT) error_exit("stat failed for %s", filename); return -1; } return buf.st_mtime; } void resolve_host(char *host, struct sockaddr_in *addr) { struct hostent *hostdnsentries; hostdnsentries = gethostbyname(host); if (hostdnsentries == NULL) { switch(h_errno) { case HOST_NOT_FOUND: error_exit("The specified host is unknown.\n"); break; case NO_ADDRESS: error_exit("The requested name is valid but does not have an IP address.\n"); break; case NO_RECOVERY: error_exit("A non-recoverable name server error occurred.\n"); break; case TRY_AGAIN: error_exit("A temporary error occurred on an authoritative name server. Try again later.\n"); break; default: error_exit("Could not resolve %s for an unknown reason (%d)\n", host, h_errno); } } /* create address structure */ addr -> sin_family = hostdnsentries -> h_addrtype; addr -> sin_addr = incopy(hostdnsentries -> h_addr_list[0]); } int connect_to(char *h) { char *hoststr = mystrdup(h); int fd; char *colon = strchr(hoststr, ':'); int portnr = 33333; struct sockaddr_in addr; int keep_alive = 1; if (colon) { *colon = 0x00; portnr = atoi(colon + 1); } /* resolve */ memset(&addr, 0x00, sizeof(addr)); resolve_host(hoststr, &addr); addr.sin_port = htons(portnr); myfree(hoststr, "connect_to"); /* connect */ fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) error_exit("problem creating socket"); if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&keep_alive, sizeof(keep_alive)) == -1) error_exit("problem setting KEEPALIVE"); /* connect to peer */ if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == 0) { /* connection made, return */ return fd; } close(fd); return -1; } int write_pidfile(char *fname) { FILE *fh = fopen(fname, "w"); if (!fh) error_exit("write_pidfile::fopen: failed creating file %s", fname); fprintf(fh, "%i", getpid()); fclose(fh); return 0; } nagircbot-0.0.33/license.txt0000644000175000017500000000017711515266716015645 0ustar folkertfolkertThe license of this program can be obtained from: http://www.vanheusden.com/license.txt It is actually the GNU Public License. nagircbot-0.0.33/readme.txt0000644000175000017500000000114511515266716015454 0ustar folkertfolkertType: ./nagircbot -h for a list of options. Send a private message to nagircbot for: - 'statistics' - returns the number criticals/warnings/etc - 'reload' - force reloads the nagios status. use this when you altered the nagios configuration - 'check' - check if nagios is still running - 'resend' - resends the problems - 'help' - returns the possible commands For everything more or less related to 'nagircbot', please feel free to contact me on: folkert@vanheusden.com Consider using PGP. My PGP key-id is: 0x1f28d8ae Please support my opensource development: http://www.vanheusden.com/wishlist.php nagircbot-0.0.33/br.cpp0000644000175000017500000001145511515266716014572 0ustar folkertfolkert/* (C) 2006-2010 by folkert@vanheusden.com GPLv2 applies */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "br.h" buffered_reader::buffered_reader(int cur_fd, int cur_block_size) { #ifdef USE_MMAP struct stat64 finfo; #endif fd = cur_fd; block_size = cur_block_size; buffer = NULL; buffer_length = buffer_pointer = 0; mmap_addr = NULL; /* try do mmap */ #ifdef USE_MMAP if (fstat64(cur_fd, &finfo) == 0) { if (!S_ISFIFO(finfo.st_mode)) { /* mmap */ size_of_file = finfo.st_size; cur_offset = mmap_addr = (char *)mmap64(NULL, size_of_file, PROT_READ, MAP_SHARED, cur_fd, 0); if (!mmap_addr) { fprintf(stderr, "mmap64 failed: %d/%s\n", errno, strerror(errno)); } /* advise the kernel how to treat the mmaped region */ /* FIXME: change to madvise64 as soon as it comes available */ (void)madvise(mmap_addr, size_of_file, MADV_SEQUENTIAL); // fprintf(stderr, "*using mmap*\n"); } } else { fprintf(stderr, "Error obtaining information on fd %d: %d/%s\n", cur_fd, errno, strerror(errno)); } #endif if (!mmap_addr) { #if (_XOPEN_VERSION >= 600) (void)posix_fadvise(cur_fd, 0, 0, POSIX_FADV_SEQUENTIAL); // or POSIX_FADV_NOREUSE? #endif } } buffered_reader::~buffered_reader() { free(buffer); if (mmap_addr) munmap(mmap_addr, size_of_file); } int buffered_reader::number_of_bytes_in_buffer(void) { return buffer_length - buffer_pointer; } int buffered_reader::garbage_collect(char shrink_buffer) { if (buffer_pointer) { int n_to_move = number_of_bytes_in_buffer(); if (n_to_move > 0) { memmove(&buffer[0], &buffer[buffer_pointer], n_to_move); buffer_length -= buffer_pointer; buffer_pointer = 0; if (shrink_buffer) { char *dummy = (char *)realloc(buffer, buffer_length + 1); if (!dummy) { fprintf(stderr, "buffered_reader::garbage_collect: realloc failed\n"); syslog(LOG_EMERG, "buffered_reader::garbage_collect: realloc failed"); exit(1); } buffer = dummy; } buffer[buffer_length] = 0x00; } } return 0; } int buffered_reader::read_into_buffer(void) { char *dummy; int n_read = 0; garbage_collect(); dummy = (char *)realloc(buffer, buffer_length + block_size + 1); if (!dummy) { fprintf(stderr, "buffered_reader::read_into_buffer: realloc failed\n"); syslog(LOG_EMERG, "buffered_reader::read_into_buffer: realloc failed"); exit(1); } buffer = dummy; for(;;) { n_read = read(fd, &buffer[buffer_length], block_size); if (n_read == -1) { if (errno == EINTR || errno == EAGAIN) continue; fprintf(stderr, "buffered_reader::read_into_buffer: read failed (%s)\n", strerror(errno)); syslog(LOG_EMERG, "buffered_reader::read_into_buffer: read failed: %m"); exit(1); } buffer_length += n_read; break; } buffer[buffer_length] = 0x00; return n_read; } char * buffered_reader::read_line(void) { char *out = NULL; #ifdef USE_MMAP if (mmap_addr) { long long int n_bytes; char *lf; char *virtual_0x00 = &mmap_addr[size_of_file]; /* EOF reached? */ if (!cur_offset) return NULL; /* determine length of current line */ lf = (char *)memchr(cur_offset, '\n', (virtual_0x00 - cur_offset)); if (lf) n_bytes = lf - cur_offset; else n_bytes = virtual_0x00 - cur_offset; /* allocate memory & copy string */ out = (char *)malloc(n_bytes + 1); if (!out) { fprintf(stderr, "buffered_reader::read_line: malloc(%lld) failed\n", n_bytes + 1); syslog(LOG_EMERG, "buffered_reader::read_line: malloc(%lld) failed", n_bytes + 1); exit(1); } memcpy(out, cur_offset, n_bytes); out[n_bytes] = 0x00; if (lf) cur_offset = lf + 1; else cur_offset = NULL; } else #endif { long long int lf_offset = -1; long long int n_bytes, search_start; if (number_of_bytes_in_buffer() <= 0) { garbage_collect(); if (read_into_buffer() == 0) { // EOF return NULL; } } search_start = buffer_pointer; for(;;) { char *dummy = strchr(&buffer[buffer_pointer], '\n'); if (dummy) lf_offset = (long long int)(dummy - buffer); if (lf_offset != -1) break; if (read_into_buffer() == 0) { lf_offset = buffer_length; break; } } n_bytes = lf_offset - buffer_pointer; out = strndup(&buffer[buffer_pointer], n_bytes); if (!out) { fprintf(stderr, "buffered_reader::read_line: malloc(%lld) failed\n", n_bytes + 1); syslog(LOG_EMERG, "buffered_reader::read_line: malloc(%lld) failed", n_bytes + 1); exit(1); } buffer_pointer = lf_offset + 1; } return out; } off64_t buffered_reader::file_offset(void) { if (mmap_addr) return cur_offset - mmap_addr; else return lseek64(fd, 0, SEEK_CUR); } nagircbot-0.0.33/log.h0000644000175000017500000000013411515266716014405 0ustar folkertfolkert/* (C) 2006-2010 by folkert@vanheusden.com GPLv2 applies */ void dolog(char *format, ...); nagircbot-0.0.33/ssl.h0000644000175000017500000000051611515266716014431 0ustar folkertfolkert/* (C) 2006-2010 by folkert@vanheusden.com GPLv2 applies */ #ifndef _SSL_H_ #define _SSL_H_ #include #include typedef struct server { char *addr; SSL *ssl; int fd; } server_t; extern int ssl_handshake( server_t *server ); extern void ssl_close( server_t *server ); #endif