BBB File /usr/local/sbin/ipwatchd
From Wiki
Jump to navigationJump to search
WARNING: Not fully tested. This page is not complete.
The monitoring process consists of a small C daemon that uses netlink and rtnetlink interface to watch for address changes on any of the network interfaces.
When a change is detected, 'ipwatchd' runs the /usr/local/sbin/ifdisplay script. That script outputs the configuration of eth0 and wlan0 to 'lpr', which then spools it to a serially attached printer.
'ipwatchd' uses the Debian services framework for start/stop/restart control, PID file management, and any of the other stuff that an application shouldn't be responsible for. See /etc/init.d/ipwatchd for the source to the init.d file, and how to install it.
As root, compile with 'gcc -W -Wall ipwatchd.c -o /usr/local/sbin/ipwatchd'
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <syslog.h> #include <errno.h> #include <sys/stat.h> #include <fcntl.h> #include <net/if.h> #include <netinet/in.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #define DAEMON_NAME "simpledaemon" // // // static void signal_handler (int sig) { switch (sig) { case SIGHUP: syslog (LOG_WARNING, "Received SIGHUP signal."); break; case SIGINT: case SIGTERM: syslog (LOG_INFO, "Daemon exiting"); exit (EXIT_SUCCESS); break; default: syslog (LOG_WARNING, "Unhandled signal %s", strsignal (sig)); break; } } // // // static void daemonize (char *rundir) { int pid, sid, i; struct sigaction newSigAction; sigset_t newSigSet; if (getppid () == 1) return; // // Set signal mask - signals we want to block // sigemptyset (&newSigSet); sigaddset (&newSigSet, SIGCHLD); // ignore child - i.e. we don't need to wait for it sigaddset (&newSigSet, SIGTSTP); // ignore Tty stop signals sigaddset (&newSigSet, SIGTTOU); // ignore Tty background writes sigaddset (&newSigSet, SIGTTIN); // ignore Tty background reads sigprocmask (SIG_BLOCK, &newSigSet, NULL); // Block the above specified signals // // Set up a signal handler // newSigAction.sa_handler = signal_handler; sigemptyset (&newSigAction.sa_mask); newSigAction.sa_flags = 0; // // Signals to handle // sigaction (SIGHUP, &newSigAction, NULL); // catch hangup signal sigaction (SIGTERM, &newSigAction, NULL); // catch term signal sigaction (SIGINT, &newSigAction, NULL); // catch interrupt signal if ((pid = fork ()) < 0) exit (EXIT_FAILURE); if (pid > 0) exit (EXIT_SUCCESS); umask (027); if ((sid = setsid ()) < 0) exit (EXIT_FAILURE); // // Close all descriptors // for (i = getdtablesize (); i >= 0; --i) close (i); // // Set stdin, stdout, stderr to /dev/null // i = open ("/dev/null", O_RDWR); dup (i); dup (i); // // Change directory we run from // chdir (rundir); } static void monitorNetlink (void) { struct sockaddr_nl addr; int nls; unsigned int len; char buffer [4096]; struct nlmsghdr *nlh; if ((nls = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { syslog (LOG_ERR, "socket() failed: %d/%s", errno, strerror (errno)); exit (EXIT_FAILURE); } memset (&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; addr.nl_groups = RTMGRP_IPV4_IFADDR; if (bind (nls, (struct sockaddr *) &addr, sizeof (addr)) == -1) { syslog (LOG_ERR, "bind() failed: %d/%s", errno, strerror (errno)); exit (EXIT_FAILURE); } nlh = (struct nlmsghdr *) buffer; while ((len = recv (nls, nlh, 4096, 0)) > 0) for (; (NLMSG_OK (nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE); nlh = NLMSG_NEXT (nlh, len)) if (nlh->nlmsg_type == RTM_NEWADDR) system ("/root/bin/ifdisplay"); } int main (int argc __attribute__ ((unused)), char **argv __attribute__ ((unused))) { setlogmask (LOG_UPTO (LOG_INFO)); openlog (DAEMON_NAME, LOG_CONS | LOG_PERROR, LOG_USER); syslog (LOG_INFO, "ipwatch starting up"); daemonize ("/tmp/"); syslog (LOG_INFO, "ipwatch running"); while (1) monitorNetlink (); }