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 ();
}