head 1.13; access; symbols; locks; strict; comment @ * @; 1.13 date 2005.02.09.13.47.22; author wessels; state Exp; branches; next 1.12; 1.12 date 2003.02.13.23.31.41; author wessels; state Exp; branches; next 1.11; 1.11 date 2003.02.13.22.46.03; author wessels; state Exp; branches; next 1.10; 1.10 date 2003.02.06.18.46.34; author wessels; state Exp; branches; next 1.9; 1.9 date 2002.05.21.17.41.52; author wessels; state Exp; branches; next 1.8; 1.8 date 2002.05.21.17.41.38; author wessels; state Exp; branches; next 1.7; 1.7 date 2002.02.25.05.06.49; author wessels; state Exp; branches; next 1.6; 1.6 date 2001.05.29.00.06.30; author wessels; state Exp; branches; next 1.5; 1.5 date 2001.05.29.00.03.51; author wessels; state Exp; branches; next 1.4; 1.4 date 2000.12.09.06.00.14; author wessels; state Exp; branches; next 1.3; 1.3 date 2000.11.16.05.52.28; author wessels; state Exp; branches; next 1.2; 1.2 date 2000.11.12.21.18.13; author wessels; state Exp; branches; next 1.1; 1.1 date 2000.11.12.21.15.51; author wessels; state Exp; branches; next ; desc @@ 1.13 log @HTTP response needs content-type @ text @/* $Id: hostmon.c,v 1.12 2003/02/13 23:31:41 wessels Exp wessels $ */ #define USE_RFC868 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MY_MAXFD 256 #define HTTP_SERVER_PORT 8001 #define ICMP_RTT_HIST_SZ 200 #define ICMP_MAX_PKT_SZ 4096 #define N_MSGS 20 #define STRFTIME_FMT "%a, %d %b %Y %H:%M:%S %Z" typedef struct { const char *name; struct sockaddr_in sa; struct { int status; time_t last_change; int up_period; int down_period; struct timeval last_sent; int pkts_sent; int pkts_recv; unsigned short last_sent_seq; unsigned short last_recv_seq; int rtt_hist[ICMP_RTT_HIST_SZ]; int moved; struct { int down_time; char *email; time_t sent; } notify; char *other_node_down; } icmp; struct { unsigned short port; int period; unsigned int val; time_t send_time; time_t recv_time; } rfc868; void *next; } Host; typedef struct { void (*read) (int, void *); void *read_data; } FD; enum { ICMP_UNKNOWN, ICMP_UP, ICMP_DOWN }; Host *hostMatchAddr(struct sockaddr_in *sa); void icmpRecv(int s, void *unused); void icmpSetStatus(Host * h); void icmpNotify(Host * h); static const char *const ws = " \t\r\n"; static Host *Hosts = NULL; static Host **HostsTail = &Hosts; static FD fds[MY_MAXFD]; static struct timeval now; static int icmp_sock = -1; static int ident; static char *msgs[N_MSGS]; static char myhostname[128]; int in_cksum(unsigned short *ptr, int size) { register long sum; unsigned short oddbyte; register unsigned short answer; sum = 0; while (size > 1) { sum += *ptr++; size -= 2; } if (size == 1) { oddbyte = 0; *((unsigned char *) &oddbyte) = *(unsigned char *) ptr; sum += oddbyte; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return (answer); } int tvsub(struct timeval *t1, struct timeval *t2) { return (t2->tv_sec - t1->tv_sec) * 1000000 + (t2->tv_usec - t1->tv_usec); } void reaper(int sig) { int status; pid_t pid; do { pid = waitpid(-1, &status, WNOHANG); } while (pid > 0); } const char * icmpStatusStr(int status) { if (ICMP_UP == status) return "Up"; if (ICMP_DOWN == status) return "Down"; return "Unknown"; } const char * icmpStatusColor(int status) { if (ICMP_UP == status) return "#00ff00"; if (ICMP_DOWN == status) return "#ff0000"; return "#ffff00"; } void icmpSocketCreate(void) { static struct protoent *proto; if ((proto = getprotobyname("icmp")) == 0) { syslog(LOG_ERR, "unknown protocol: icmp"); exit(1); } if ((icmp_sock = socket(PF_INET, SOCK_RAW, proto->p_proto)) < 0) { syslog(LOG_ERR, "socket(PF_INET, SOCK_RAW, icmp): %s", strerror(errno)); exit(1); } syslog(LOG_DEBUG, "ICMP socket is FD %d\n", icmp_sock); fds[icmp_sock].read = icmpRecv; fds[icmp_sock].read_data = NULL; } #define SIZE_ICMP_HDR 8 #define DEF_DATALEN 56 void icmpSend(Host * h) { static unsigned char send_pkt[ICMP_MAX_PKT_SZ]; struct icmp *icp; int icmp_pktsize = DEF_DATALEN + SIZE_ICMP_HDR; int x; memset(send_pkt, '\0', sizeof(send_pkt)); icp = (struct icmp *) send_pkt; icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_cksum = 0; icp->icmp_id = ident; icp->icmp_seq = (++h->icmp.last_sent_seq); memcpy(send_pkt + SIZE_ICMP_HDR, &now, sizeof(now)); h->icmp.last_sent = now; h->icmp.pkts_sent++; icp->icmp_cksum = in_cksum((unsigned short *) icp, icmp_pktsize); if (-1 == icmp_sock) icmpSocketCreate(); syslog(LOG_DEBUG, "send %4d ICMP bytes to %s", icmp_pktsize, inet_ntoa(h->sa.sin_addr)); x = sendto(icmp_sock, send_pkt, icmp_pktsize, 0, (struct sockaddr *) &h->sa, sizeof(h->sa)); if (x < 0) syslog(LOG_ERR, "sendto: %s: %s", inet_ntoa(h->sa.sin_addr), strerror(errno)); } void icmpRecv(int s, void *unused) { static unsigned char recv_pkt[ICMP_MAX_PKT_SZ]; static struct sockaddr_in from; int fromlen = sizeof(from); struct timeval tv; struct timeval tv1; struct icmp *icp; struct ip *ip; int iphdrlen; int n; int rtt; Host *h; assert(s == icmp_sock); n = recvfrom(s, recv_pkt, sizeof(recv_pkt), 0, (struct sockaddr *) &from, &fromlen); gettimeofday(&tv, 0); ip = (struct ip *) recv_pkt; #if defined(__osf__) && __STDC__==1 #if BYTE_ORDER == BIG_ENDIAN iphdrlen = (ip->ip_vhl >> 4) << 2; #endif #if BYTE_ORDER == LITTLE_ENDIAN iphdrlen = (ip->ip_vhl & 0xF) << 2; #endif #else iphdrlen = ip->ip_hl << 2; #endif syslog(LOG_DEBUG, "recv %4d ICMP bytes from %s", n, inet_ntoa(from.sin_addr)); if (n < iphdrlen + SIZE_ICMP_HDR) { syslog(LOG_ERR, "packet too short (%d bytes) from %s", n, inet_ntoa(from.sin_addr)); return; } n -= iphdrlen; icp = (struct icmp *) &recv_pkt[iphdrlen]; if (icp->icmp_type != ICMP_ECHOREPLY) return; if (icp->icmp_id != ident) return; if ((h = hostMatchAddr(&from)) == NULL) return; memcpy(&tv1, &icp->icmp_data[0], sizeof(tv1)); rtt = tvsub(&tv1, &tv); h->icmp.rtt_hist[0] = rtt; icmpSetStatus(h); h->icmp.last_recv_seq = icp->icmp_seq; memmove(&h->icmp.rtt_hist[1], &h->icmp.rtt_hist[0], (ICMP_RTT_HIST_SZ - 1) * sizeof(h->icmp.rtt_hist[0])); h->icmp.moved = 1; } double icmpPktLoss(Host * h) { int sent = 0; int recv = 0; int i; for (i = 1; i < ICMP_RTT_HIST_SZ; i++) { if (h->icmp.rtt_hist[i] < 0) break; sent++; if (h->icmp.rtt_hist[i] > 0) recv++; } if (0 == sent) return -1.0; return 1.0 - (double) recv / (double) sent; } int icmpRttAvg(Host * h) { int rttsum = 0; int recv = 0; int i; for (i = 1; i < ICMP_RTT_HIST_SZ; i++) { if (h->icmp.rtt_hist[i] < 0) break; if (0 == h->icmp.rtt_hist[i]) continue; recv++; rttsum += h->icmp.rtt_hist[i]; } if (0 == recv) return -100; return rttsum / recv; } void icmpSetStatus(Host * h) { char buf[256]; char tbuf[256]; int newstatus; int i = h->icmp.last_sent_seq - h->icmp.last_recv_seq; if (i > 20) newstatus = ICMP_DOWN; else if (0 == h->icmp.last_recv_seq) newstatus = ICMP_UNKNOWN; else if (i > 10) newstatus = ICMP_UNKNOWN; else newstatus = ICMP_UP; if (newstatus == h->icmp.status) return; if (msgs[N_MSGS - 1]) free(msgs[N_MSGS - 1]); memmove(&msgs[1], &msgs[0], (N_MSGS - 1) * sizeof(msgs[0])); strftime(tbuf, 256, STRFTIME_FMT, localtime(&now.tv_sec)); snprintf(buf, 256, "%s: %s changed from %s to %s\n", tbuf, h->name, icmpStatusStr(h->icmp.status), icmpStatusStr(newstatus)); msgs[0] = strdup(buf); h->icmp.status = newstatus; h->icmp.last_change = now.tv_sec; } void icmpNotify(Host * h) { char cmd[256]; FILE *fp; if (ICMP_DOWN != h->icmp.status) return; if (0 == h->icmp.notify.down_time) return; if (NULL == h->icmp.notify.email) return; if ((now.tv_sec - h->icmp.last_change) < h->icmp.notify.down_time) return; if (h->icmp.notify.sent > h->icmp.last_change) return; memset(cmd, '\0', 256); snprintf(cmd, 256, "/usr/sbin/sendmail %s", h->icmp.notify.email); fp = popen(cmd, "w"); if (NULL == fp) { syslog(LOG_ERR, "popen: %s", strerror(errno)); return; } fprintf(fp, "From: hostmon@@%s\n", myhostname); fprintf(fp, "To: %s\n", h->icmp.notify.email); fprintf(fp, "Subject: %s is DOWN from %s\n", h->name, myhostname); fclose(fp); h->icmp.notify.sent = now.tv_sec; } int parseHost(char *buf, void *data) { Host *h = data; char *t; if (NULL == (t = strtok(buf, ws))) return 1; if (0 == strcmp(t, "}")) { int i; for (i = 0; i < ICMP_RTT_HIST_SZ; i++) h->icmp.rtt_hist[i] = -1; *HostsTail = h; HostsTail = (Host **) & h->next; return 1; } else if (0 == strcmp(t, "ip-address")) { if (NULL == (t = strtok(NULL, ws))) return 1; h->sa.sin_addr.s_addr = inet_addr(t); } else if (0 == strcmp(t, "icmp-up-period")) { if (NULL == (t = strtok(NULL, ws))) return 1; h->icmp.up_period = atoi(t); } else if (0 == strcmp(t, "icmp-down-period")) { if (NULL == (t = strtok(NULL, ws))) return 1; h->icmp.down_period = atoi(t); } else if (0 == strcmp(t, "icmp-notify-down-time")) { if (NULL == (t = strtok(NULL, ws))) return 1; h->icmp.notify.down_time = atoi(t); } else if (0 == strcmp(t, "icmp-notify-email")) { if (NULL == (t = strtok(NULL, ws))) return 1; h->icmp.notify.email = strdup(t); } else if (0 == strcmp(t, "if-other-node-down")) { if (NULL == (t = strtok(NULL, ws))) return 1; h->icmp.other_node_down = strdup(t); } else if (0 == strcmp(t, "rfc868-port")) { if (NULL == (t = strtok(NULL, ws))) return 1; h->rfc868.port = atoi(t); } else if (0 == strcmp(t, "rfc868-period")) { if (NULL == (t = strtok(NULL, ws))) return 1; h->rfc868.period = atoi(t); } return 0; } int parseConfig(const char *cf) { FILE *fp = fopen(cf, "r"); static char buf[512]; char *t; int (*parseFunc) (char *, void *) = NULL; void *parseData = NULL; if (NULL == fp) { perror(cf); return 1; } while (fgets(buf, 512, fp)) { if (parseFunc) { int x = parseFunc(buf, parseData); if (1 == x) parseFunc = parseData = NULL; } if (NULL == (t = strtok(buf, ws))) continue;; if (0 == strcmp(t, "host")) { Host *h = calloc(1, sizeof(*h)); assert(h); if (NULL == (t = strtok(NULL, ws))) { fprintf(stderr, "expected host name\n"); break; } h->name = strdup(t); if (NULL == (t = strtok(NULL, ws))) { fprintf(stderr, "expected open bracket, got NULL\n"); break; } if (strcmp(t, "{")) { fprintf(stderr, "expected open bracket, got %s\n", t); break; } parseFunc = parseHost; parseData = h; } } return 0; } Host * hostMatchAddr(struct sockaddr_in * sa) { Host *h; for (h = Hosts; h; h = h->next) { if (h->sa.sin_addr.s_addr == sa->sin_addr.s_addr) return h; } return NULL; } Host * hostMatchName(const char *name) { Host *h; for (h = Hosts; h; h = h->next) { if (0 == strcasecmp(h->name, name)) return h; } return NULL; } int hostNeedsPing(Host * h) { time_t last = h->icmp.last_sent.tv_sec; time_t delta; if (h->icmp.last_sent_seq == h->icmp.last_recv_seq) delta = h->icmp.up_period; else delta = h->icmp.down_period; if (now.tv_sec > last + delta) return 1; return 0; } void hostPing(Host * h) { if (!h->icmp.moved) memmove(&h->icmp.rtt_hist[1], &h->icmp.rtt_hist[0], (ICMP_RTT_HIST_SZ - 1) * sizeof(h->icmp.rtt_hist[0])); h->icmp.moved = 0; h->icmp.rtt_hist[0] = 0; icmpSetStatus(h); icmpNotify(h); icmpSend(h); } /* RFC868 SECTION */ #if USE_RFC868 static int rfc868_sock = -1; static void rfc868Send(Host * h) { struct sockaddr_in S; static char buf[1]; if (rfc868_sock < 0) return; if (h->rfc868.period < 1) return; memcpy(&S, &h->sa, sizeof(S)); S.sin_port = htons(h->rfc868.port); S.sin_family = AF_INET; syslog(LOG_DEBUG, "send %4d TIME bytes to %s", 1, inet_ntoa(S.sin_addr)); sendto(rfc868_sock, buf, 1, 0, (struct sockaddr *) &S, sizeof(S)); h->rfc868.send_time = now.tv_sec; } static void rfc868Recv(int s, void *unused) { int x; static char buf[32]; static struct sockaddr_in from; int fromlen = sizeof(from); unsigned int val; Host *h; assert(s == rfc868_sock); x = recvfrom(rfc868_sock, buf, 32, 0, (struct sockaddr *) &from, &fromlen); syslog(LOG_DEBUG, "recv %4d TIME bytes from %s", x, inet_ntoa(from.sin_addr)); if (x < 4) return; h = hostMatchAddr(&from); if (NULL == h) return; memcpy(&val, buf, 4); h->rfc868.val = ntohl(val); h->rfc868.recv_time = now.tv_sec; } static void rfc868Init(void) { struct sockaddr_in S; int x; rfc868_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (rfc868_sock < 0) { syslog(LOG_ALERT, "RFC868 socket: %s", strerror(errno)); return; } syslog(LOG_DEBUG, "TIME socket is FD %d\n", rfc868_sock); memset(&S, '\0', sizeof(S)); S.sin_family = AF_INET; S.sin_addr.s_addr = INADDR_ANY; S.sin_port = 0; x = bind(rfc868_sock, (struct sockaddr *) &S, sizeof(S)); if (x < 0) { syslog(LOG_ALERT, "bind: %s", strerror(errno)); close(rfc868_sock); rfc868_sock = -1; return; } syslog(LOG_DEBUG, "TIME socket bound to %s\n", inet_ntoa(S.sin_addr)); fds[rfc868_sock].read = rfc868Recv; fds[rfc868_sock].read_data = NULL; } static int rfc868NeedsQuery(Host * h) { if (h->rfc868.period < 1) return 0; if ((now.tv_sec - h->rfc868.send_time) > h->rfc868.period) return 1; return 0; } static char * rfc868Asctime(Host * h) { time_t when; struct tm *lt; static char when_str[64]; if (0 == h->rfc868.recv_time) return " "; if (now.tv_sec - h->rfc868.recv_time > 300) return "unknown"; if (now.tv_sec - h->rfc868.recv_time > 3600) return " "; when = h->rfc868.val - (unsigned int) 2208988800 + (now.tv_sec - h->rfc868.recv_time); lt = localtime(&when); assert(NULL != lt); strftime(when_str, 64, "%v %T", lt); return when_str; } static char * rfc868Color(Host * h) { time_t when; if (0 == h->rfc868.recv_time) return "#ff0000;"; when = h->rfc868.val - (unsigned int) 2208988800 + (now.tv_sec - h->rfc868.recv_time); if (abs(now.tv_sec - when) > 30) return "#ff0000"; if (abs(now.tv_sec - when) > 3) return "#ffff00"; return "#000000"; } #endif /* ============== */ int otherNodeIsDown(Host *h) { Host *other; if (NULL == h->icmp.other_node_down) return 1; other = hostMatchName(h->icmp.other_node_down); if (NULL == other) return 1; if (ICMP_DOWN == other->icmp.status) return 1; return 0; } void checkHosts(void) { Host *h; for (h = Hosts; h; h = h->next) { if (!otherNodeIsDown(h)) continue; if (hostNeedsPing(h)) { hostPing(h); break; } #if USE_RFC868 if (rfc868NeedsQuery(h)) { rfc868Send(h); break; } #endif } } void checkSockets(void) { fd_set R; struct timeval to; int x; int maxx = 0; to.tv_sec = 1; to.tv_usec = 0; FD_ZERO(&R); for (x = 0; x < MY_MAXFD; x++) { if (NULL == fds[x].read) continue; FD_SET(x, &R); if (x > maxx) maxx = x; } x = select(maxx + 1, &R, NULL, NULL, &to); if (0 == x) return; if (x < 0) { if (EINTR != errno) perror("select"); return; } for (x = 0; x < MY_MAXFD; x++) { if (NULL == fds[x].read) continue; if (!FD_ISSET(x, &R)) continue; fds[x].read(x, fds[x].read_data); } } void run(void) { for (;;) { gettimeofday(&now, 0); checkHosts(); checkSockets(); } } void htmlOutput(int s) { char buf[1024]; int x; Host *h; read(s, buf, 1024); x = snprintf(buf, 1024, "HTTP/1.0 200 Ok\r\n" "Cache-control: no-cache\r\n" "Content-type: text/html\r\n" "\r\n"); write(s, buf, x); x = snprintf(buf, 1024, "\n" "\n" "\n" "\n"); write(s, buf, x); x = snprintf(buf, 1024, "

\n" "\n"); write(s, buf, x); x = snprintf(buf, 1024, "\n" "\n" "\n" "\n" "\n"); write(s, buf, x); x = snprintf(buf, 1024, "\n" "\n" "\n" "\n" "\n"); write(s, buf, x); for (h = Hosts; h; h = h->next) { if (!otherNodeIsDown(h)) continue; x = snprintf(buf, 1024, "\n" "\n" "\n" "\n" "\n" "\n" "\n", h->name, icmpStatusColor(h->icmp.status), icmpStatusStr(h->icmp.status), icmpRttAvg(h) / 1000, 100.0 * icmpPktLoss(h), #if USE_RFC868 rfc868Color(h), rfc868Asctime(h)); #else "", ""); #endif write(s, buf, x); } x = snprintf(buf, 1024, "
HostICMPTime
StatusRTT (msec)Loss (%%)
%s%s%d%4.1f%s
\n"); write(s, buf, x); x = snprintf(buf, 1024, "\n" "

\n");
    write(s, buf, x);
    for (x = 0; x < N_MSGS; x++)
	if (msgs[x])
	    write(s, msgs[x], strlen(msgs[x]));
    x = snprintf(buf, 1024,
	"
\n" "\n"); write(s, buf, x); } void httpServerAccept(int fd, void *unused) { int s; s = accept(fd, NULL, NULL); if (s < 0) { perror("accept"); return; } if (fork()) { /* parent */ struct sigaction sa; memset(&sa, '\0', sizeof(sa)); sa.sa_handler = reaper; sa.sa_flags = SA_NODEFER; sigemptyset(&sa.sa_mask); if (sigaction(SIGCHLD, &sa, NULL) < 0) perror("sigaction SIGCHLD"); close(s); return; } htmlOutput(s); close(s); _exit(0); } void httpServerCreate(void) { int s; int x; struct sockaddr_in S; s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { perror("socket"); return; } x = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)) < 0) perror("setsockopt SO_REUSEADDR"); memset(&S, '\0', sizeof(S)); S.sin_family = AF_INET; S.sin_addr.s_addr = INADDR_ANY; S.sin_port = htons(HTTP_SERVER_PORT); while (bind(s, (struct sockaddr *) &S, sizeof(S)) < 0) { static int count = 0; fprintf(stderr, "[%d] ", ++count); perror("bind"); if (count == 120) break; sleep(1 << count); } listen(s, 10); fds[s].read = httpServerAccept; fds[s].read_data = NULL; } void writePid(void) { FILE *fp = fopen("/var/run/hostmon.pid", "w"); if (NULL == fp) return; fprintf(fp, "%d\n", (int) getpid()); fclose(fp); } void daemonize(void) { pid_t pid; int i; if ((pid = fork()) < 0) syslog(LOG_ALERT, "fork failed: %s", strerror(errno)); else if (pid > 0) exit(0); if (setsid() < 0) syslog(LOG_ALERT, "setsid failed: %s", strerror(errno)); #ifdef TIOCNOTTY if ((i = open("/dev/tty", O_RDWR)) >= 0) { ioctl(i, TIOCNOTTY, NULL); close(i); } #endif i = open("/dev/null", O_RDWR); dup2(i, 0); dup2(i, 1); dup2(i, 2); for (i = 3; i < MY_MAXFD; i++) close(i); } int main(int argc, char *argv[]) { char *config = "/usr/local/etc/hostmon.conf"; if (argc > 1) config = strdup(argv[1]); if (parseConfig(config)) return 1; memset(msgs, '\0', sizeof(msgs)); openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); daemonize(); /* * need to reopen syslog because paranoid daemonize() closes all * FDs */ closelog(); openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); writePid(); ident = getpid() & 0xffff; gethostname(myhostname, 128); strtok(myhostname, "."); httpServerCreate(); #if USE_RFC868 rfc868Init(); #endif run(); return 0; } @ 1.12 log @got the logic wrong @ text @d1 1 a1 1 /* $Id: hostmon.c,v 1.11 2003/02/13 22:46:03 wessels Exp $ */ d712 1 @ 1.11 log @add 'if-other-node-down' construct @ text @d1 1 a1 1 /* $Id: hostmon.c,v 1.10 2003/02/06 18:46:34 wessels Exp $ */ d629 1 a629 1 return 0; d632 1 a632 1 return 0; d635 1 @ 1.10 log @make time column go unknown->blank if we stop getting time data from the host @ text @d1 1 a1 1 /* $Id: hostmon.c,v 1.9 2002/05/21 17:41:52 wessels Exp $ */ d55 1 d389 4 d459 11 d624 13 d642 2 d738 2 @ 1.9 log @ -> @ text @d1 1 a1 1 /* $Id: hostmon.c,v 1.8 2002/05/21 17:41:38 wessels Exp wessels $ */ d579 4 @ 1.8 log @syslog fix @ text @d1 1 a1 1 /* $Id: hostmon.c,v 1.7 2002/02/25 05:06:49 wessels Exp $ */ d679 1 a679 1 "\n" d681 1 a681 1 "\n" @ 1.7 log @hostmon wasn't working on hq. something was wrong with the ICMP socket. It wasn't showing up in netstat output, and sendto() was returngin EISCONN. I added a lot of debugging and some ifdefs for the RFC868 code to eliminate it as the cause. ICMP worked w/o the RFC868 code, and then worked with it back in. Not sure what the real cause is/was. @ text @d1 1 a1 1 /* $Id: hostmon.c,v 1.6 2001/05/29 00:06:30 wessels Exp $ */ d843 6 @ 1.6 log @simple time support @ text @d1 3 a3 1 /* $Id: hostmon.c,v 1.5 2001/05/29 00:03:51 wessels Exp $ */ d15 1 d153 7 a159 2 if ((icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { perror("socket"); d162 1 d175 1 d189 2 a190 1 sendto(icmp_sock, d196 2 d233 1 d482 1 d493 2 d498 1 d524 1 d545 1 d557 1 d565 2 d600 1 d613 1 d618 1 d716 1 d719 3 d848 1 d850 1 @ 1.5 log @sequence numbers are 16 bits, which confused up/down detection @ text @d1 1 a1 1 /* $Id: hostmon.c,v 1.4 2000/12/09 06:00:14 wessels Exp wessels $ */ d53 7 d89 1 a89 1 int d374 8 d467 113 d589 4 d666 1 d683 1 d689 3 a691 1 100.0 * icmpPktLoss(h)); d818 1 @ 1.4 log @added pager notification oof, gindent! @ text @d1 1 a1 1 /* $Id: hostmon.c,v 1.2 2000/11/12 21:18:13 wessels Exp $ */ d43 2 a44 2 int last_sent_seq; int last_recv_seq; d165 1 a165 1 icp->icmp_seq = h->icmp.last_sent_seq = h->icmp.pkts_sent++; d168 1 @ 1.3 log @changed the way we determine up/down/unknown status changed when to ping again added a text event history buffer @ text @d37 1 d47 5 d70 1 d80 1 d300 30 d358 8 d447 1 d678 2 @ 1.2 log @changed RTT reporting to be in integer msec, not float @ text @d1 1 a1 1 /* $Id$ */ d29 2 d33 15 a47 13 const char *name; struct sockaddr_in sa; struct { int status; int up_period; int down_period; struct timeval last_sent; int pkts_sent; int pkts_recv; int rtt_hist[ICMP_RTT_HIST_SZ]; int moved; } icmp; void *next; d51 2 a52 2 void (*read)(int, void *); void *read_data; d56 3 a58 3 ICMP_UNKNOWN, ICMP_UP, ICMP_DOWN d61 1 a61 1 Host * hostMatchAddr(struct sockaddr_in *sa); d63 1 d72 1 d74 2 a75 1 int in_cksum(unsigned short *ptr, int size) d82 2 a83 2 sum += *ptr++; size -= 2; d86 3 a88 3 oddbyte = 0; *((unsigned char *) &oddbyte) = *(unsigned char *) ptr; sum += oddbyte; d102 2 a103 2 void reaper(int sig) d108 1 a108 1 pid = waitpid(-1, &status, WNOHANG); d115 5 a119 5 if (ICMP_UP == status) return "Up"; if (ICMP_DOWN == status) return "Down"; return "Unknown"; d125 5 a129 5 if (ICMP_UP == status) return "#00ff00"; if (ICMP_DOWN == status) return "#ff0000"; return "#ffff00"; d136 3 a138 3 perror("socket"); exit(1); } d144 1 a144 1 #define DEF_DATALEN 56 d146 1 a146 1 icmpSend(Host *h) d148 21 a168 21 static unsigned char send_pkt[ICMP_MAX_PKT_SZ]; struct icmp *icp; int icmp_pktsize = DEF_DATALEN + SIZE_ICMP_HDR; memset(send_pkt, '\0', sizeof(send_pkt)); icp = (struct icmp *) send_pkt; icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_cksum = 0; icp->icmp_id = ident; icp->icmp_seq = h->icmp.pkts_sent++; memcpy(send_pkt + SIZE_ICMP_HDR, &now, sizeof(now)); h->icmp.last_sent = now; icp->icmp_cksum = in_cksum((unsigned short *) icp, icmp_pktsize); if (-1 == icmp_sock) icmpSocketCreate(); sendto(icmp_sock, send_pkt, icmp_pktsize, 0, (struct sockaddr *) &h->sa, sizeof(h->sa)); d174 20 a193 20 static unsigned char recv_pkt[ICMP_MAX_PKT_SZ]; static struct sockaddr_in from; int fromlen = sizeof(from); struct timeval tv; struct timeval tv1; struct icmp *icp; struct ip *ip; int iphdrlen; int n; int rtt; Host *h; assert(s == icmp_sock); n = recvfrom(s, recv_pkt, sizeof(recv_pkt), 0, (struct sockaddr *) &from, &fromlen); gettimeofday(&tv, 0); ip = (struct ip *) recv_pkt; d196 2 a197 2 iphdrlen = (ip->ip_vhl >> 4) << 2; #endif d199 26 a224 25 iphdrlen = (ip->ip_vhl & 0xF) << 2; #endif #else iphdrlen = ip->ip_hl << 2; #endif if (n < iphdrlen + SIZE_ICMP_HDR) { syslog(LOG_ERR, "packet too short (%d bytes) from %s", n, inet_ntoa(from.sin_addr)); return; } n -= iphdrlen; icp = (struct icmp *) &recv_pkt[iphdrlen]; if (icp->icmp_type != ICMP_ECHOREPLY) return; if (icp->icmp_id != ident) return; if ((h = hostMatchAddr(&from)) == NULL) return; memcpy(&tv1, &icp->icmp_data[0], sizeof(tv1)); rtt = tvsub(&tv1, &tv); h->icmp.rtt_hist[0] = rtt; h->icmp.status = ICMP_UP; memmove(&h->icmp.rtt_hist[1], &h->icmp.rtt_hist[0], (ICMP_RTT_HIST_SZ - 1) * sizeof(h->icmp.rtt_hist[0])); h->icmp.moved = 1; d228 1 a228 1 icmpPktLoss(Host *h) d230 13 a242 13 int sent = 0; int recv = 0; int i; for (i=1; iicmp.rtt_hist[i] < 0) break; sent++; if (h->icmp.rtt_hist[i] > 0) recv++; } if (0 == sent) return -1.0; return 1.0 - (double) recv / (double) sent; d246 1 a246 1 icmpRttAvg(Host *h) d248 14 a261 14 int rttsum = 0; int recv = 0; int i; for (i=1; iicmp.rtt_hist[i] < 0) break; if (0 == h->icmp.rtt_hist[i]) continue; recv++; rttsum += h->icmp.rtt_hist[i]; } if (0 == recv) return -100; return rttsum / recv; d264 29 d297 25 a321 25 Host *h = data; char *t; if (NULL == (t = strtok(buf, ws))) return 1; if (0 == strcmp(t, "}")) { int i; for(i=0; iicmp.rtt_hist[i] = -1; *HostsTail = h; HostsTail = (Host **) &h->next; return 1; } else if (0 == strcmp(t, "ip-address")) { if (NULL == (t = strtok(NULL, ws))) return 1; h->sa.sin_addr.s_addr = inet_addr(t); } else if (0 == strcmp(t, "icmp-up-period")) { if (NULL == (t = strtok(NULL, ws))) return 1; h->icmp.up_period = atoi(t); } else if (0 == strcmp(t, "icmp-down-period")) { if (NULL == (t = strtok(NULL, ws))) return 1; h->icmp.down_period = atoi(t); } return 0; d327 14 a340 8 FILE *fp = fopen(cf, "r"); static char buf[512]; char *t; int (*parseFunc)(char*, void *) = NULL; void *parseData = NULL; if (NULL == fp) { perror(cf); return 1; d342 20 a361 27 while (fgets(buf, 512, fp)) { if (parseFunc) { int x = parseFunc(buf, parseData); if (1 == x) parseFunc = parseData = NULL; } if (NULL == (t = strtok(buf, ws))) continue;; if (0 == strcmp(t, "host")) { Host *h = calloc(1, sizeof(*h)); assert(h); if (NULL == (t = strtok(NULL, ws))) { fprintf(stderr, "expected host name\n"); break; } h->name = strdup(t); if (NULL == (t = strtok(NULL, ws))) { fprintf(stderr, "expected open bracket, got NULL\n"); break; } if (strcmp(t, "{")) { fprintf(stderr, "expected open bracket, got %s\n", t); break; } parseFunc = parseHost; parseData = h; } d363 2 a364 1 return 0; d368 1 a368 1 hostMatchAddr(struct sockaddr_in *sa) d370 6 a375 6 Host *h; for(h=Hosts; h; h=h->next) { if (h->sa.sin_addr.s_addr == sa->sin_addr.s_addr) return h; } return NULL; d379 1 a379 1 hostNeedsPing(Host *h) d381 9 a389 8 if (ICMP_UP == h->icmp.status) { if (now.tv_sec > h->icmp.last_sent.tv_sec + h->icmp.up_period) return 1; return 0; } if (now.tv_sec > h->icmp.last_sent.tv_sec + h->icmp.down_period) return 1; return 0; d393 1 a393 1 hostPing(Host *h) d395 7 a401 14 int i; if (!h->icmp.moved) memmove(&h->icmp.rtt_hist[1], &h->icmp.rtt_hist[0], (ICMP_RTT_HIST_SZ - 1) * sizeof(h->icmp.rtt_hist[0])); h->icmp.moved = 0; h->icmp.rtt_hist[0] = 0; for (i=1; iicmp.rtt_hist[i] > 0) break; if (i > 20) h->icmp.status = ICMP_DOWN; else if (i > 10) h->icmp.status = ICMP_UNKNOWN; icmpSend(h); d407 5 a411 6 Host *h; for(h = Hosts; h; h=h->next) { if (hostNeedsPing(h)) { hostPing(h); break; } d413 1 d419 29 a447 29 fd_set R; struct timeval to; int x; int maxx = 0; to.tv_sec = 1; to.tv_usec = 0; FD_ZERO(&R); for (x = 0; x maxx) maxx = x; } x = select(maxx+1, &R, NULL, NULL, &to); if (0 == x) return; if (x < 0) { if (EINTR != errno) perror("select"); return; } for (x = 0; x\n" "\n" "\n" "\n"); write(s, buf, x); x = snprintf(buf, 1024, "

\n" "\n"); write(s, buf, x); x = snprintf(buf, 1024, "\n" "\n" "\n" "\n"); write(s, buf, x); x = snprintf(buf, 1024, "\n" "\n" "\n" "\n" "\n"); write(s, buf, x); for (h=Hosts; h; h=h->next) { x = snprintf(buf, 1024, "\n" "\n" "\n" "\n" "\n" "\n", h->name, icmpStatusColor(h->icmp.status), icmpStatusStr(h->icmp.status), icmpRttAvg(h) / 1000, 100.0 * icmpPktLoss(h)); write(s, buf, x); } x = snprintf(buf, 1024, "
HostICMP
StatusRTT (msec)Loss (%%)
%s%s%d%4.1f
\n" "\n"); d509 15 d529 15 a543 19 int s; s = accept(fd, NULL, NULL); if (s < 0) { perror("accept"); return; } if (fork()) { /* parent */ struct sigaction sa; memset(&sa, '\0', sizeof(sa)); sa.sa_handler = reaper; sa.sa_flags = SA_NODEFER; sigemptyset(&sa.sa_mask); if (sigaction(SIGCHLD, &sa, NULL) < 0) perror("sigaction SIGCHLD"); close(s); return; } htmlOutput(s); d545 5 a549 1 _exit(0); d555 26 a580 26 int s; int x; struct sockaddr_in S; s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { perror("socket"); return; } x = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)) < 0) perror("setsockopt SO_REUSEADDR"); memset(&S, '\0', sizeof(S)); S.sin_family = AF_INET; S.sin_addr.s_addr = INADDR_ANY; S.sin_port = htons(HTTP_SERVER_PORT); while (bind(s, (struct sockaddr *) &S, sizeof(S)) < 0) { static int count = 0; fprintf(stderr, "[%d] ", ++count); perror("bind"); if (count == 120) break; sleep(1< 0) exit(0); if (setsid() < 0) syslog(LOG_ALERT, "setsid failed: %s", strerror(errno)); d606 2 a607 2 ioctl(i, TIOCNOTTY, NULL); close(i); d615 1 a615 1 close(i); d621 13 a633 12 char *config = "/usr/local/etc/hostmon.conf"; if (argc > 1) config = strdup(argv[1]); if (parseConfig(config)) return 1; openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); daemonize(); writePid(); ident = getpid() & 0xffff; httpServerCreate(); run(); return 0; @ 1.1 log @Initial revision @ text @d1 2 d252 1 a252 1 return -1; d469 1 a469 1 "%5.3f\n" d475 1 a475 1 (double) icmpRttAvg(h) / 1000.0, @