summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2006-08-31 19:48:42 +0000
committerLennart Poettering <lennart@poettering.net>2006-08-31 19:48:42 +0000
commit7bf6b7b95b7c3327000794a24e104242598a9f3f (patch)
treed2e6c8597febe4a21019a04906a098e2be9d5c34
parent9d709a294b81066a0942a7a642df1b3d4940ad26 (diff)
add support for interface configuration with user supplied event script
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@1301 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe
-rw-r--r--avahi-autoipd/Makefile.am4
-rwxr-xr-xavahi-autoipd/avahi-autoipd.action77
-rw-r--r--avahi-autoipd/main.c176
3 files changed, 233 insertions, 24 deletions
diff --git a/avahi-autoipd/Makefile.am b/avahi-autoipd/Makefile.am
index c553470..3a6bb2a 100644
--- a/avahi-autoipd/Makefile.am
+++ b/avahi-autoipd/Makefile.am
@@ -20,13 +20,15 @@
if ENABLE_AUTOIPD
if HAVE_LIBDAEMON
+pkgsysconfdir=$(sysconfdir)/avahi
+
AM_CFLAGS= \
-I$(top_srcdir)
# This cool debug trap works on i386/gcc only
AM_CFLAGS+='-DDEBUG_TRAP=__asm__("int $$3")' \
-DAVAHI_RUNTIME_DIR=\"$(avahi_runtime_dir)/\" \
- -DAVAHI_DNSCONF_SCRIPT=\"$(pkgsysconfdir)/avahi-autoipd.action\"
+ -DAVAHI_IPCONF_SCRIPT=\"$(pkgsysconfdir)/avahi-autoipd.action\"
sbin_PROGRAMS = avahi-autoipd
diff --git a/avahi-autoipd/avahi-autoipd.action b/avahi-autoipd/avahi-autoipd.action
new file mode 100755
index 0000000..45ce1b5
--- /dev/null
+++ b/avahi-autoipd/avahi-autoipd.action
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# $Id$
+#
+# This file is part of avahi.
+#
+# avahi is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# avahi is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+# License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with avahi; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA.
+
+set -e
+
+# Command line arguments:
+# $1 event that happened:
+# BIND: Successfully claimed address
+# CONFLICT: An IP address conflict happened
+# UNBIND: The IP address is no longer needed
+# STOP: The daemon is terminating
+# $2 interface name
+# $3 IP adddress
+
+if [ -x /bin/ip -o -x /sbin/ip ] ; then
+
+ # We have the Linux ip tool from the iproute package
+
+ case "$1" in
+ BIND)
+ ip addr add "$3"/16 label "$2:avahi" scope link dev "$2"
+ ;;
+
+ CONFLICT|UNBIND|STOP)
+ ip addr del "$3"/16 label "$2:avahi" scope link dev "$2"
+ ;;
+
+ *)
+ echo "Unknown event $1" >&2
+ exit 1
+ ;;
+ esac
+
+elif [ -x /bin/ifconfig -o -x /sbin/ifconfig ] ; then
+
+ # We have the old ifconfig tool
+
+ case "$1" in
+ BIND)
+ ifconfig "$2" inet "$3" netmask 255.255.0.0
+ ;;
+
+ CONFLICT|UNBIND|STOP)
+ ifconfig "$2" inet 0
+ ;;
+
+ *)
+ echo "Unknown event $1" >&2
+ exit 1
+ ;;
+ esac
+else
+
+ echo "No network configuration tool found." >&2
+ exit 1
+
+fi
+
+exit 0
diff --git a/avahi-autoipd/main.c b/avahi-autoipd/main.c
index 6d83d3a..82dba88 100644
--- a/avahi-autoipd/main.c
+++ b/avahi-autoipd/main.c
@@ -127,6 +127,19 @@ typedef enum CalloutEvent {
CALLOUT_MAX
} CalloutEvent;
+static const char * const callout_event_table[CALLOUT_MAX] = {
+ [CALLOUT_BIND] = "BIND",
+ [CALLOUT_CONFLICT] = "CONFLICT",
+ [CALLOUT_UNBIND] = "UNBIND",
+ [CALLOUT_STOP] = "STOP"
+};
+
+typedef struct CalloutEventInfo {
+ CalloutEvent event;
+ uint32_t address;
+ int ifindex;
+} CalloutEventInfo;
+
#define RANDOM_DEVICE "/dev/urandom"
#define DEBUG(x) do {\
@@ -243,7 +256,7 @@ static int packet_parse(const void *data, size_t packet_len, ArpPacketInfo *info
}
static void set_state(State st, int reset_counter, uint32_t address) {
- const char* const state_table[] = {
+ static const char* const state_table[] = {
[STATE_START] = "START",
[STATE_WAITING_PROBE] = "WAITING_PROBE",
[STATE_PROBING] = "PROBING",
@@ -315,23 +328,6 @@ fail:
return -1;
}
-static int do_callout(CalloutEvent event, int iface, uint32_t addr) {
- char buf[64], ifname[IFNAMSIZ];
- const char * const event_table[CALLOUT_MAX] = {
- [CALLOUT_BIND] = "BIND",
- [CALLOUT_CONFLICT] = "CONFLICT",
- [CALLOUT_UNBIND] = "UNBIND",
- [CALLOUT_STOP] = "STOP"
- };
-
- daemon_log(LOG_INFO, "Callout %s, address %s on interface %s",
- event_table[event],
- inet_ntop(AF_INET, &addr, buf, sizeof(buf)),
- if_indextoname(iface, ifname));
-
- return 0;
-}
-
static int open_socket(int iface, uint8_t *hw_address) {
int fd = -1;
struct sockaddr_ll sa;
@@ -458,6 +454,125 @@ static struct timeval *elapse_time(struct timeval *tv, unsigned msec, unsigned j
return tv;
}
+static FILE* fork_dispatcher(void) {
+ FILE *ret;
+ int fds[2];
+ pid_t pid;
+
+ if (pipe(fds) < 0) {
+ daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno));
+ goto fail;
+ }
+
+ if ((pid = fork()) < 0)
+ goto fail;
+ else if (pid == 0) {
+ FILE *f = NULL;
+ int r = 1;
+
+ /* Please note that the signal pipe is not closed at this
+ * point, signals will thus be dispatched in the main
+ * process. */
+
+ daemon_retval_done();
+
+ setsid();
+
+ avahi_set_proc_title(argv0, "%s(%s): callout dispatcher", argv0, interface_name);
+
+ close(fds[1]);
+
+ if (!(f = fdopen(fds[0], "r"))) {
+ daemon_log(LOG_ERR, "fdopen() failed: %s", strerror(errno));
+ goto dispatcher_fail;
+ }
+
+ for (;;) {
+ CalloutEventInfo info;
+ char name[IFNAMSIZ], buf[64];
+ int k;
+
+ if (fread(&info, sizeof(info), 1, f) != 1) {
+ if (feof(f))
+ break;
+
+ daemon_log(LOG_ERR, "fread() failed: %s", strerror(errno));
+ goto dispatcher_fail;
+ }
+
+ assert(info.event <= CALLOUT_MAX);
+
+ if (!if_indextoname(info.ifindex, name)) {
+ daemon_log(LOG_ERR, "if_indextoname() failed: %s", strerror(errno));
+ continue;
+ }
+
+ if (daemon_exec("/", &k,
+ AVAHI_IPCONF_SCRIPT, AVAHI_IPCONF_SCRIPT,
+ callout_event_table[info.event],
+ name,
+ inet_ntop(AF_INET, &info.address, buf, sizeof(buf)), NULL) < 0) {
+
+ daemon_log(LOG_ERR, "Failed to run script: %s", strerror(errno));
+ continue;
+ }
+
+ if (k != 0)
+ daemon_log(LOG_WARNING, "Script execution failed with return value %i", k);
+ }
+
+ r = 0;
+
+ dispatcher_fail:
+
+ if (f)
+ fclose(f);
+
+ _exit(r);
+ }
+
+ /* parent */
+
+ close(fds[0]);
+ fds[0] = -1;
+
+ if (!(ret = fdopen(fds[1], "w"))) {
+ daemon_log(LOG_ERR, "fdopen() failed: %s", strerror(errno));
+ goto fail;
+ }
+
+ return ret;
+
+fail:
+ if (fds[0] >= 0)
+ close(fds[0]);
+ if (fds[1] >= 0)
+ close(fds[1]);
+
+ return NULL;
+}
+
+static int do_callout(FILE *f, CalloutEvent event, int iface, uint32_t addr) {
+ CalloutEventInfo info;
+ char buf[64], ifname[IFNAMSIZ];
+
+ daemon_log(LOG_INFO, "Callout %s, address %s on interface %s",
+ callout_event_table[event],
+ inet_ntop(AF_INET, &addr, buf, sizeof(buf)),
+ if_indextoname(iface, ifname));
+
+ info.event = event;
+ info.ifindex = iface;
+ info.address = addr;
+
+ if (fwrite(&info, sizeof(info), 1, f) != 1 || fflush(f) != 0) {
+ daemon_log(LOG_ERR, "Failed to write callout event: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
static int loop(int iface, uint32_t addr) {
enum {
FD_ARP,
@@ -480,15 +595,22 @@ static int loop(int iface, uint32_t addr) {
Event event = EVENT_NULL;
int retval_sent = !daemonize;
State st;
+ FILE *dispatcher = NULL;
daemon_signal_init(SIGINT, SIGTERM, SIGCHLD, SIGHUP,0);
+ if (!(dispatcher = fork_dispatcher()))
+ goto fail;
+
if ((fd = open_socket(iface, hw_address)) < 0)
goto fail;
if ((iface_fd = iface_init(iface)) < 0)
goto fail;
+/* if (drop_privs() < 0) */
+/* goto fail; */
+
if (force_bind)
st = STATE_START;
else if (iface_get_initial_state(&st) < 0)
@@ -571,7 +693,9 @@ static int loop(int iface, uint32_t addr) {
next_wakeup_valid = 1;
if (n_iteration == 0) {
- do_callout(CALLOUT_BIND, iface, addr);
+ if (do_callout(dispatcher, CALLOUT_BIND, iface, addr) < 0)
+ goto fail;
+
n_conflict = 0;
if (!retval_sent) {
@@ -610,7 +734,8 @@ static int loop(int iface, uint32_t addr) {
if (conflict) {
if (state == STATE_RUNNING || state == STATE_ANNOUNCING)
- do_callout(CALLOUT_CONFLICT, iface, addr);
+ if (do_callout(dispatcher, CALLOUT_CONFLICT, iface, addr) < 0)
+ goto fail;
/* Pick a new address */
addr = pick_addr(addr);
@@ -637,7 +762,8 @@ static int loop(int iface, uint32_t addr) {
daemon_log(LOG_INFO, "A routable address has been configured.");
if (state == STATE_RUNNING || state == STATE_ANNOUNCING)
- do_callout(CALLOUT_UNBIND, iface, addr);
+ if (do_callout(dispatcher, CALLOUT_UNBIND, iface, addr) < 0)
+ goto fail;
if (!retval_sent) {
daemon_retval_send(0);
@@ -775,7 +901,7 @@ static int loop(int iface, uint32_t addr) {
fail:
if (state == STATE_RUNNING || state == STATE_ANNOUNCING)
- do_callout(CALLOUT_STOP, iface, addr);
+ do_callout(dispatcher, CALLOUT_STOP, iface, addr);
avahi_free(out_packet);
avahi_free(in_packet);
@@ -788,6 +914,9 @@ fail:
if (daemonize && !retval_sent)
daemon_retval_send(ret);
+
+ if (dispatcher)
+ fclose(dispatcher);
return ret;
}
@@ -925,6 +1054,8 @@ int main(int argc, char*argv[]) {
avahi_init_proc_title(argc, argv);
+ signal(SIGPIPE, SIG_IGN);
+
if ((argv0 = strrchr(argv[0], '/')))
argv0++;
else
@@ -1048,7 +1179,6 @@ finish:
/* TODO:
- chroot/drop privs/caps
-- user script
- store last used address
- man page