aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--pingu.c180
-rw-r--r--pingu.conf22
-rw-r--r--xlib.c19
-rw-r--r--xlib.h1
5 files changed, 178 insertions, 47 deletions
diff --git a/Makefile b/Makefile
index db8718c..de1c586 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-TARGETS = mtu
+TARGETS = mtu pingu
CFLAGS ?= -g
prefix = /usr
@@ -10,6 +10,7 @@ INSTALL = install
INSTALLDIR = $(INSTALL) -d
pingu_OBJS = \
+ icmp.o \
log.o \
pingu.o \
xlib.o
diff --git a/pingu.c b/pingu.c
index bfe5fcb..cebd349 100644
--- a/pingu.c
+++ b/pingu.c
@@ -1,20 +1,32 @@
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include "icmp.h"
#include "pingu.h"
#include "xlib.h"
-int pingu_verbose = 0;
+#define DEFAULT_CONFIG "/etc/pingu.conf"
+#define DEFAULT_PIDFILE "/var/run/pingu.pid"
+
+int pingu_verbose = 0, pid_file_fd = 0;
+char *pid_file = DEFAULT_PIDFILE;
+int interval = 30;
struct provider {
- char *router;
+ struct sockaddr_in address;
char *name;
char *interface;
char *up_action;
@@ -95,13 +107,14 @@ int read_config(const char *file, struct provider_list *head)
parse_line(line, &key, &value);
if (key == NULL)
continue;
-// printf("DEBUG: lineno=%i, key='%s', val='%s'\n",
-// lineno, key, value);
- if (strcmp(key, "router") == 0) {
+ if (p == NULL && strcmp(key, "interval") == 0) {
+ interval = atoi(value);
+ } else if (strcmp(key, "router") == 0) {
p = xmalloc(sizeof(struct provider));
memset(p, 0, sizeof(struct provider));
- p->router = xstrdup(value);
+ if (init_sockaddr(&p->address, value) < 0)
+ return 1;
p->status = 1; /* online by default */
SLIST_INSERT_HEAD(head, p, provider_list);
} else if (p && strcmp(key, "interface") == 0) {
@@ -121,19 +134,50 @@ int read_config(const char *file, struct provider_list *head)
return 0;
}
-static int ping(const char *host)
+int do_ping(struct sockaddr_in *to, int seq, int retries)
{
- char cmd[280];
- snprintf(cmd, sizeof(cmd), "ping -c 1 -q %s >/dev/null 2>&1", host);
- return system(cmd);
+ __u8 buf[1500];
+ struct iphdr *ip = (struct iphdr *) buf;
+ struct icmphdr *icp;
+ struct sockaddr_in from;
+ int retry;
+ int len = sizeof(struct iphdr) + sizeof(struct icmphdr);
+ int fd = icmp_open();
+
+ for (retry = 0; retry < retries; retry++) {
+ icmp_send_ping(fd, (struct sockaddr *) to, sizeof(*to),
+ seq, len);
+
+ if ((len = icmp_read_reply(fd, (struct sockaddr *) &from,
+ sizeof(from), buf, sizeof(buf))) <= 0)
+ continue;
+
+ icp = (struct icmphdr *) &buf[ip->ihl * 4];
+ if (icp->type == ICMP_ECHOREPLY && icp->un.echo.id == getpid()) {
+ icmp_close(fd);
+ return 0;
+ }
+ }
+ icmp_close(fd);
+ return -1;
}
-void usage(int retcode)
+int usage(const char *program)
{
- fprintf(stderr, "usage:\n");
- exit(retcode);
+ fprintf(stderr, "usage: %s [-dh] [-c CONFIG] [-p PIDFILE]\n"
+ "options:\n"
+ " -c Read configuration from FILE (default is "
+ DEFAULT_CONFIG ")\n"
+ " -d Debug mode. Stay in foreground\n"
+ " -h Show this help\n"
+ " -p Use PIDFILE as pidfile (default is "
+ DEFAULT_PIDFILE ")\n"
+ "\n",
+ program);
+ return 1;
}
+#if 0
void dump_provider(struct provider *p)
{
printf("router: %s\n"
@@ -143,47 +187,111 @@ void dump_provider(struct provider *p)
"down-action: %s\n"
"p->status: %i\n"
"\n",
- p->router, p->name, p->interface,
+ inet_ntoa(p->address.sin_addr), p->name, p->interface,
p->up_action, p->down_action, p->status);
}
+#endif
+
+
void ping_loop(struct provider_list *head, int interval)
{
struct provider *p;
+ int seq = 0;
while (1) {
+ seq++;
SLIST_FOREACH(p, head, provider_list) {
- int status = (ping(p->router) != 0);
+ int status = (do_ping(&p->address, seq, 3) == 0);
if (status != p->status) {
p->status = status;
- printf("status changed for %s to %i\n",
- p->router, status);
+ if (status)
+ system(p->up_action);
+ else
+ system(p->down_action);
}
}
sleep(interval);
+ seq &= 0xffff;
+ }
+}
+
+static void remove_pid_file(void)
+{
+ if (pid_file_fd != 0) {
+ close(pid_file_fd);
+ pid_file_fd = 0;
+ remove(pid_file);
+ }
+}
+
+static int daemonize(void)
+{
+ char tmp[16];
+ pid_t pid;
+
+ pid = fork();
+ if (pid < 0)
+ return -1;
+ if (pid > 0)
+ exit(0);
+
+ if (setsid() < 0)
+ return -1;
+
+ pid = fork();
+ if (pid < 0)
+ return -1;
+ if (pid > 0)
+ exit(0);
+
+ if (chdir("/") < 0)
+ return -1;
+
+ pid_file_fd = open(pid_file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
+ if (pid_file_fd < 0) {
+ log_error("Unable to open %s: %s.", pid_file, strerror(errno));
+ return -1;
+ }
+
+ if (flock(pid_file_fd, LOCK_EX | LOCK_NB) < 0) {
+ log_error("Unable to lock pid file (already running?).");
+ close(pid_file_fd);
+ pid_file_fd = 0;
+ return -1;
}
+
+ ftruncate(pid_file_fd, 0);
+ write(pid_file_fd, tmp, sprintf(tmp, "%d\n", getpid()));
+ atexit(remove_pid_file);
+
+ freopen("/dev/null", "r", stdin);
+ freopen("/dev/null", "w", stdout);
+ freopen("/dev/null", "w", stderr);
+
+ umask(0);
+
+ return 0;
}
int main(int argc, char *argv[])
{
- int c;
- char *config = "/etc/pingu.conf";
- char **hosts;
- int *offline;
- int hosts_count;
- int interval = 30;
- const char *script = NULL;
+ int c, debug_mode = 0;
struct provider_list providers;
+ char *config_file = DEFAULT_CONFIG;
- while ((c = getopt(argc, argv, "c:i:s:")) != -1) {
+ while ((c = getopt(argc, argv, "c:dhp:")) != -1) {
switch (c) {
case 'c':
- config = optarg;
+ config_file = optarg;
break;
- case 's':
- script = optarg;
+ case 'd':
+ debug_mode++;
break;
- case 'i':
- interval = atoi(optarg);
+ case 'h':
+ return usage(basename(argv[0]));
+ return;
+ case 'p':
+ pid_file = optarg;
break;
}
}
@@ -192,17 +300,15 @@ int main(int argc, char *argv[])
argv += optind;
SLIST_INIT(&providers);
- if (read_config(config, &providers) == -1)
+ if (read_config(config_file, &providers) == -1)
return 1;
-// if (argc == 0)
-// usage(EXIT_FAILURE);
-
- offline = xmalloc(sizeof(int) * argc);
- memset(offline, 0, sizeof(int) * argc);
+ if (!debug_mode) {
+ if (daemonize() == -1)
+ return 1;
+ }
ping_loop(&providers, interval);
- free(hosts);
return 0;
}
diff --git a/pingu.conf b/pingu.conf
index 44956a5..215b25c 100644
--- a/pingu.conf
+++ b/pingu.conf
@@ -1,14 +1,18 @@
# comments are prefixed with #
-interface eth0
-provider ISP-1
-pinghost 10.2.0.3
-up-action /etc/pingu/isp1 up
-down-action /etc/pingu/isp1 down
+# global option
+interval 3
+router 10.65.67.11
interface eth1
-provider ISP-2
-pinghost 192.168.0.1
-up-action echo "isp 2 went up" >> /var/log/isp2.log
-down-action echo "iso 2 went down" >> /var/log/isp2.log
+provider ISP-1
+up-action echo "isp 1 went up" >> /tmp/pingu.log
+down-action echo "iso 1 went down" >> /tmp/pingu.log
+
+#router 10.2.0.3
+#interface eth0
+#provider ISP-1
+#up-action /etc/pingu/isp1 up
+#down-action /etc/pingu/isp1 down
+
diff --git a/xlib.c b/xlib.c
index d8392c1..e48ec39 100644
--- a/xlib.c
+++ b/xlib.c
@@ -1,4 +1,9 @@
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -29,3 +34,17 @@ char *xstrdup(const char *str)
return s;
}
+int init_sockaddr(struct sockaddr_in *addr, const char *host)
+{
+ memset((char *) addr, 0, sizeof(struct sockaddr_in));
+ addr->sin_family = AF_INET;
+ if (inet_aton(host, &addr->sin_addr) == 0) {
+ struct hostent *hp;
+ hp = gethostbyname(host);
+ if (!hp)
+ return -1;
+ memcpy(&addr->sin_addr, hp->h_addr, 4);
+ }
+ return 0;
+}
+
diff --git a/xlib.h b/xlib.h
index e6f9e16..a66a6bd 100644
--- a/xlib.h
+++ b/xlib.h
@@ -5,4 +5,5 @@ void *xmalloc(size_t size);
void *xrealloc(void *ptr, size_t size);
char *xstrdup(const char *str);
+int init_sockaddr(struct sockaddr_in *addr, const char *host);
#endif