]> git.meshlink.io Git - catta/commitdiff
add support for interface configuration with user supplied event script
authorLennart Poettering <lennart@poettering.net>
Thu, 31 Aug 2006 19:48:42 +0000 (19:48 +0000)
committerLennart Poettering <lennart@poettering.net>
Thu, 31 Aug 2006 19:48:42 +0000 (19:48 +0000)
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@1301 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

avahi-autoipd/Makefile.am
avahi-autoipd/avahi-autoipd.action [new file with mode: 0755]
avahi-autoipd/main.c

index c553470293de2c557212962e288389df7c3b048b..3a6bb2a624d5d542bda0db3107725ca47f113514 100644 (file)
 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 (executable)
index 0000000..45ce1b5
--- /dev/null
@@ -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
index 6d83d3a53aea8345d091367ec421b9d0db30118e..82dba887a1bfda38ac88f8a9d7387f244703ee78 100644 (file)
@@ -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