]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
We can now detected primary addresses added or changed in BSD.
authorRoy Marples <roy@marples.name>
Thu, 19 Mar 2009 17:52:12 +0000 (17:52 +0000)
committerRoy Marples <roy@marples.name>
Thu, 19 Mar 2009 17:52:12 +0000 (17:52 +0000)
As such, we can wait for a 3RDPARTY to configure the interface, such as PPP.
We can then take the destination addess and automatically give it a default
route or any other DHCP option such as DNS servers.
This addresses #159.

13 files changed:
configure.c
configure.h
dhcp.c
dhcpcd-run-hooks.8.in
dhcpcd.8.in
dhcpcd.c
dhcpcd.conf.5.in
dhcpcd.h
if-bsd.c
if-options.c
if-options.h
net.c
net.h

index d41b03ed01552e20780783cf604ca26019bf53cf..bb1bba50d87190d28b7be6b5eb7b886675b24620 100644 (file)
@@ -497,9 +497,12 @@ add_subnet_route(struct rt *rt, const struct interface *iface)
        struct rt *r;
 
        if (iface->net.s_addr == INADDR_BROADCAST ||
-           iface->net.s_addr == INADDR_ANY)
+           iface->net.s_addr == INADDR_ANY ||
+           (iface->state->options->options &
+            (DHCPCD_INFORM | DHCPCD_STATIC) &&
+            iface->state->options->req_addr.s_addr == INADDR_ANY))
                return rt;
-       
+
        r = xmalloc(sizeof(*r));
        r->dest.s_addr = iface->addr.s_addr & iface->net.s_addr;
        r->net.s_addr = iface->net.s_addr;
@@ -534,8 +537,8 @@ get_routes(const struct interface *iface) {
        return get_option_routes(iface->state->new);
 }
 
-static void
-build_routes()
+void
+build_routes(void)
 {
        struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL;
        const struct interface *ifp;
@@ -591,7 +594,12 @@ static int
 delete_address(struct interface *iface)
 {
        int retval;
+       struct if_options *ifo;
 
+       ifo = iface->state->options;
+       if (ifo->options & DHCPCD_INFORM ||
+           (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
+               return 0;
        syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
            iface->name,
            inet_ntoa(iface->addr),
@@ -616,10 +624,9 @@ configure(struct interface *iface)
        sort_interfaces();
 
        if (dhcp == NULL) {
-               if (iface->addr.s_addr != 0) {
-                       build_routes();
+               build_routes();
+               if (iface->addr.s_addr != 0)
                        delete_address(iface);
-               }
                run_script(iface);
                return 0;
        }
index d103b6e5ae9cf4fab5bc19af27c635381a530929..58b78026d57db244efce4d4161376553271ed284 100644 (file)
@@ -32,6 +32,7 @@
 
 int send_interface(int, const struct interface *);
 int run_script(const struct interface *);
+void build_routes(void);
 int configure(struct interface *);
 int route_deleted(const struct rt *);
 #endif
diff --git a/dhcp.c b/dhcp.c
index 2689b734cd6d55c2bada5629c81a645f92349a08..15b21c98ee3194fe3915d994fd46e4e3d7f2ee84 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -195,8 +195,13 @@ int make_option_mask(uint8_t *mask, const char *opts, int add)
                                        if (opt->option == n)
                                                match = 1;
                        }
-                       if (match) {    
-                               if (add == 1)
+                       if (match) {
+                               if (add == 2 && !(opt->type & IPV4)) {
+                                       free(o);
+                                       errno = EINVAL;
+                                       return -1;
+                               }
+                               if (add == 1 || add == 2)
                                        add_option_mask(mask,
                                            opt->option);
                                else
index 6e025ac1154ef5002294d1a0daf52be4fb6008ed..89525697b46d97fea37eafec275229f74abed4ed 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd January 15, 2009
+.Dd March 19, 2009
 .Dt DHCPCD.SH 8 SMM
 .Os
 .Sh NAME
@@ -91,6 +91,8 @@ dhcpcd failed to contact any DHCP servers but did obtain an IPV4LL address.
 .It Dv STATIC
 dhcpcd has been configured with a static configuration which has not been
 obtained from a DHCP server.
+.It Dv 3RDPARTY
+dhcpcd is monitoring the interface for a 3rd party to give it an IP address.
 .It Dv TIMEOUT
 dhcpcd failed to contact any DHCP servers but was able to use an old lease.
 .It Dv EXPIRE
index eae48484b6c689e939afdde2fd6d7bb0f143209e..a1edeebb16e57e7ea27baec5b989db59cf3e8151 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd March 10, 2009
+.Dd March 19, 2009
 .Dt DHCPCD 8 SMM
 .Os
 .Sh NAME
@@ -461,6 +461,19 @@ When discovering interfaces, the interface name must not match
 which is a space or comma separated list of patterns passed to
 .Xr fnmatch 3 .
 .El
+.Sh 3RDPARTY LINK MANAGEMENT
+Some interfaces require configuration by 3rd parties, such as PPP or VPN.
+When an interface configuration in
+.Nm
+is marked as STATIC or INFORM without an address then
+.Nm
+will monitor the interface until an address is added or removed from it and
+act accordingly.
+For point to point interfaces (like PPP), a default route to it's
+destination is automatically added to the configuration.
+If the point to point interface if configured for INFORM, then
+.Nm
+unicasts INFORM to the destination.
 .Sh NOTES
 .Nm
 requires a Berkley Packet Filter, or BPF device on BSD based systems and a
index 752ca5554be632bf8eae86b1617bdfe0d5e48236..2448f5e24a6ba2a755fba8825ae6a3b5872e51ba 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -33,6 +33,7 @@ const char copyright[] = "Copyright (c) 2006-2009 Roy Marples";
 #include <sys/uio.h>
 
 #include <arpa/inet.h>
+#include <net/route.h>
 
 #include <ctype.h>
 #include <errno.h>
@@ -663,7 +664,11 @@ configure_interface(struct interface *iface, int argc, char **argv)
        free_options(ifs->options);
        ifo = ifs->options = read_config(cffile, iface->name, iface->ssid);
        add_options(ifo, argc, argv);
-
+       if (iface->flags & IFF_NOARP)
+               ifo->options &= ~(DHCPCD_ARP | DHCPCD_IPV4LL);
+       if (ifo->options & DHCPCD_LINK && carrier_status(iface->name) == -1)
+               ifo->options &= ~DHCPCD_LINK;
+       
        if (ifo->metric != -1)
                iface->metric = ifo->metric;
 
@@ -821,17 +826,44 @@ dhcp_message_new(struct in_addr *addr, struct in_addr *mask)
                *p++ = DHO_SUBNETMASK;
                *p++ = sizeof(mask->s_addr);
                memcpy(p, &mask->s_addr, sizeof(mask->s_addr));
+               p+= sizeof(mask->s_addr);
        }
        *p++ = DHO_END;
        return dhcp;
 }
 
+static int
+handle_3rdparty(struct interface *iface)
+{
+       struct if_options *ifo;
+       struct in_addr addr, net, dst;
+       
+       ifo = iface->state->options;
+       if (ifo->req_addr.s_addr != INADDR_ANY)
+               return 0;
+
+       if (get_address(iface->name, &addr, &net, &dst) == 1)
+               handle_ifa(RTM_NEWADDR, iface->name, &addr, &net, &dst);
+       else {
+               syslog(LOG_INFO,
+                       "%s: waiting for 3rd party to configure IP address",
+                       iface->name);
+               iface->state->reason = "3RDPARTY";
+               run_script(iface);
+       }
+       return 1;
+}
+
 static void
 start_static(struct interface *iface)
 {
-       struct if_options *ifo = iface->state->options;
+       struct if_options *ifo;
 
-       iface->state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
+       if (handle_3rdparty(iface))
+               return;
+       ifo = iface->state->options;
+       iface->state->offer =
+           dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
        delete_timeout(NULL, iface);
        bind_interface(iface);
 }
@@ -839,11 +871,12 @@ start_static(struct interface *iface)
 static void
 start_inform(struct interface *iface)
 {
-       struct if_options *ifo = iface->state->options;
+       if (handle_3rdparty(iface))
+               return;
 
-       ifo->options |= DHCPCD_STATIC;
+       iface->state->options->options |= DHCPCD_STATIC;
        start_static(iface);
-       ifo->options &= ~DHCPCD_STATIC;
+       iface->state->options->options &= ~DHCPCD_STATIC;
 
        iface->state->state = DHS_INFORM;
        iface->state->xid = arc4random();
@@ -909,6 +942,7 @@ start_interface(void *arg)
        struct timeval now;
        uint32_t l;
 
+       handle_carrier(iface->name);
        if (iface->carrier == LINK_DOWN) {
                syslog(LOG_INFO, "%s: waiting for carrier", iface->name);
                return;
@@ -930,9 +964,14 @@ start_interface(void *arg)
                start_inform(iface);
                return;
        }
+       if (iface->hwlen == 0 && ifo->clientid[0] == '\0') {
+               syslog(LOG_WARNING, "%s: needs a clientid to configure",
+                       iface->name);
+               return;
+       }
        if (ifo->req_addr.s_addr) {
-               iface->state->offer = dhcp_message_new(&ifo->req_addr,
-                   &ifo->req_mask);
+               iface->state->offer =
+                   dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
                if (ifo->options & DHCPCD_REQUEST)
                        ifo->req_addr.s_addr = 0;
                else {
@@ -1019,13 +1058,23 @@ init_state(struct interface *iface, int argc, char **argv)
                iface->carrier = LINK_UNKNOWN;
 }
 
-static void
-handle_new_interface(const char *ifname)
+void
+handle_interface(int action, const char *ifname)
 {
        struct interface *ifs, *ifp, *ifn, *ifl = NULL;
        const char * const argv[] = { "dhcpcd", ifname };
        int i;
 
+       if (action == -1) {
+               ifp = find_interface(ifname);
+               if (ifp != NULL)
+                       stop_interface(ifp);
+               return;
+       } else if (action == 0) {
+               handle_carrier(ifname);
+               return;
+       }
+
        /* If running off an interface list, check it's in it. */
        if (ifc) {
                for (i = 0; i < ifc; i++)
@@ -1055,24 +1104,91 @@ handle_new_interface(const char *ifname)
        }
 }
 
-static void
-handle_remove_interface(const char *ifname)
+static int
+dhcp_message_add_addr(struct dhcp_message *dhcp, char c, struct in_addr *addr)
 {
-       struct interface *iface;
+       uint8_t *p;
+       size_t len;
 
-       iface = find_interface(ifname);
-       if (iface != NULL)
-               stop_interface(iface);
+       p = dhcp->options;
+       while (*p != DHO_END) {
+               p++;
+               p += *p + 1;
+       }
+
+       len = p - (uint8_t *)dhcp;
+       if (len + 6 > sizeof(*dhcp)) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       *p++ = c;
+       *p++ = sizeof(addr->s_addr);
+       memcpy(p, &addr->s_addr, sizeof(addr->s_addr));
+       p += sizeof(addr->s_addr);
+       *p = DHO_END;
+       return 0;
+}
+
+void
+handle_ifa(int type, const char *ifname,
+    struct in_addr *addr, struct in_addr *net, struct in_addr *dst)
+{
+       struct interface *ifp;
+       struct if_options *ifo;
+       int i;
+
+       if (addr->s_addr == INADDR_ANY)
+               return;
+       for (ifp = ifaces; ifp; ifp = ifp->next)
+               if (strcmp(ifp->name, ifname) == 0)
+                       break;
+       if (ifp == NULL)
+               return;
+       ifo = ifp->state->options;
+       if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)) == 0 ||
+           ifo->req_addr.s_addr != INADDR_ANY)
+               return;
+       
+       switch (type) {
+       case RTM_DELADDR:
+               if (ifp->state->new &&
+                   ifp->state->new->yiaddr == addr->s_addr)
+                       drop_config(ifp, "EXPIRE");
+               break;
+       case RTM_NEWADDR:
+               if (ifo->options & DHCPCD_INFORM) {
+                       ifp->state->state = DHS_INFORM;
+                       ifp->state->xid = arc4random();
+                       ifp->addr = *addr;
+                       ifp->net = *net;
+                       ifp->state->lease.server = *dst;
+                       open_sockets(ifp);
+                       send_inform(ifp);
+               } else {
+                       free(ifp->state->old);
+                       ifp->state->old = ifp->state->new;
+                       ifp->state->new = dhcp_message_new(addr, net);
+                       if (dst) {
+                               for (i = 1; i < 255; i++)
+                                       if (has_option_mask(ifo->dstmask, i))
+                                               dhcp_message_add_addr(
+                                                       ifp->state->new,
+                                                       i, dst);
+                       }
+                       ifp->state->reason = "STATIC";
+                       build_routes();
+                       run_script(ifp);
+               }
+               break;
+       }
 }
 
 /* ARGSUSED */
 static void
 handle_link(_unused void *arg)
 {
-       if (manage_link(linkfd,
-               handle_carrier,
-               handle_new_interface,
-               handle_remove_interface) == -1)
+       if (manage_link(linkfd))
                syslog(LOG_ERR, "manage_link: %m");
 }
 
index e21e568e76aa5381c32afb5d172a56495a637e15..988d74e96a61b521083ff6b08220fa571df822c3 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd March 10, 2009
+.Dd March 19, 2009
 .Dt DHCPCD.CONF 5 SMM
 .Os
 .Sh NAME
@@ -143,9 +143,15 @@ It can be a variable to be used in
 .Xr dhcpcd-run-hooks 8
 or the numerical value.
 You can specify more options seperated by commas, spaces or more option lines.
-.Ic quiet
+.It Ic destination Ar option
+If
+.Nm
+detects an address added to a point to point interface (PPP, TUN, etc) then
+it will set the listed DHCP options to the destination address of the
+interface.
+.It Ic quiet
 Supress any dhcpcd output to the console, except for errors.
-.Ic reboot Ar seconds
+.It Ic reboot Ar seconds
 Allow
 .Ar reboot
 seconds before moving to the discover phase if we have an old lease to use.
@@ -192,6 +198,13 @@ Here is an example which configures a static address, routes and dns.
 .D1 static ip_address=192.168.0.10/24
 .D1 static routers=192.168.0.1
 .D1 static domain_name_servers=192.168.0.1
+.Pp
+Here is an example for PPP which gives the destination a default route.
+It uses the special destination keyword to insert the destination address
+into the value.
+.D1 interface ppp0
+.D1 static ip_address=
+.D1 destination routers
 .It Ic timeout Ar seconds
 The default timeout for waiting for a DHCP response is 30 seconds which may
 be too long or too short and can be changed here.
index d8a5fabd9076ef16e247caa9ae6847ce49969580..927f019f6e23c5f812ff3c9589b900aedbe8bb9f 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -82,6 +82,7 @@ struct interface {
        char name[IF_NAMESIZE];
        struct if_state *state;
 
+       int flags;
        sa_family_t family;
        unsigned char hwaddr[HWADDR_LEN];
        size_t hwlen;
@@ -118,6 +119,9 @@ extern struct interface *ifaces;
 
 struct interface *find_interface(const char *);
 int handle_args(struct fd_list *, int, char **);
+void handle_interface(int, const char *);
+void handle_ifa(int, const char *,
+    struct in_addr *, struct in_addr *, struct in_addr *);
 void handle_exit_timeout(void *);
 void start_interface(void *);
 void start_discover(void *);
index 8d5529cac55b9cb5aa4ce3052a40c77b89badbda..0db8b30430cf5d6bf23a30ea8a5b4f6c4718ee89 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
 #include "if-options.h"
 #include "net.h"
 
-#define ROUNDUP(a)                                                     \
+#define ROUNDUP(a)                                                           \
        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
 
-/* Darwin doesn't define this for some very odd reason */
-#ifndef SA_SIZE
-# define SA_SIZE(sa)                                                   \
-       (  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?          \
-           sizeof(long)                :                               \
-           1 + ( (((struct sockaddr *)(sa))->sa_len - 1) |             \
-               (sizeof(long) - 1) ) )
-#endif
+/* FIXME: Why do we need to check for sa_family 255 */
+#define COPYOUT(sin, sa)                                                     \
+       sin.s_addr = ((sa) != NULL && ((sa)->sa_family == AF_INET ||          \
+               (sa)->sa_family == 255))                                      \
+           ?                                                                 \
+           (((struct sockaddr_in *)sa)->sin_addr).s_addr : 0
 
 static int a_fd = -1;
 static int r_fd = -1;
@@ -139,11 +138,11 @@ if_address(const struct interface *iface, const struct in_addr *address,
        memset(&ifa, 0, sizeof(ifa));
        strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name));
 
-#define ADDADDR(_var, _addr) {                                         \
-               _s.sa = &_var;                                          \
-               _s.sin->sin_family = AF_INET;                           \
-               _s.sin->sin_len = sizeof(*_s.sin);                      \
-               memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr)); \
+#define ADDADDR(_var, _addr) {                                               \
+               _s.sa = &_var;                                                \
+               _s.sin->sin_family = AF_INET;                                 \
+               _s.sin->sin_len = sizeof(*_s.sin);                            \
+               memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr));   \
        }
 
        ADDADDR(ifa.ifra_addr, address);
@@ -184,17 +183,17 @@ if_route(const struct interface *iface, const struct in_addr *dest,
        size_t l;
        int retval = 0;
 
-#define ADDSU(_su) {                                                   \
-               l = SA_SIZE(&(_su.sa));                                 \
-               memcpy(bp, &(_su), l);                                  \
-               bp += l;                                                \
-       } 
-#define ADDADDR(_addr) {                                               \
-               memset (&su, 0, sizeof(su));                            \
-               su.sin.sin_family = AF_INET;                            \
-               su.sin.sin_len = sizeof(su.sin);                        \
-               memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
-               ADDSU(su);                                              \
+#define ADDSU(_su) {                                                         \
+               l = ROUNDUP(_su.sa.sa_len);                                   \
+               memcpy(bp, &(_su), l);                                        \
+               bp += l;                                                      \
+       }
+#define ADDADDR(_a) {                                                        \
+               memset (&su, 0, sizeof(su));                                  \
+               su.sin.sin_family = AF_INET;                                  \
+               su.sin.sin_len = sizeof(su.sin);                              \
+               memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr));       \
+               ADDSU(su);                                                    \
        }
 
        memset(&rtm, 0, sizeof(rtm));
@@ -272,22 +271,38 @@ open_link_socket(void)
        return fd;
 }
 
+static void
+get_addrs(int type, char *cp, struct sockaddr **sa)
+{
+       int i;
+
+       for (i = 0; i < RTAX_MAX; i++) {
+               if (type & (1 << i)) {
+                       sa[i] = (struct sockaddr *)cp;
+#ifdef DEBUG
+                       printf ("got %d %d %s\n", i, sa[i]->sa_family,
+                           inet_ntoa(((struct sockaddr_in *)sa[i])->
+                               sin_addr));
+#endif
+                       ADVANCE(cp, sa[i]);
+               } else
+                       sa[i] = NULL;
+       }
+}
+
 #define BUFFER_LEN     2048
 int
-manage_link(int fd,
-    void (*if_carrier)(const char *),
-    void (*if_add)(const char *),
-    void (*if_remove)(const char *))
+manage_link(int fd)
 {
-       char buffer[2048], *p, *e;
+       char buffer[2048], *p, *e, *cp;
        char ifname[IF_NAMESIZE];
        ssize_t bytes;
        struct rt_msghdr *rtm;
-       struct if_announcemsghdr *ifa;
+       struct if_announcemsghdr *ifan;
        struct if_msghdr *ifm;
+       struct ifa_msghdr *ifam;
        struct rt rt;
-       struct sockaddr *sa;
-       struct sockaddr_in *sin;
+       struct sockaddr *sa, *rti_info[RTAX_MAX];
 
        for (;;) {
                bytes = read(fd, buffer, BUFFER_LEN);
@@ -303,13 +318,13 @@ manage_link(int fd,
                        rtm = (struct rt_msghdr *)(void *)p;
                        switch(rtm->rtm_type) {
                        case RTM_IFANNOUNCE:
-                               ifa = (struct if_announcemsghdr *)(void *)p;
-                               switch(ifa->ifan_what) {
+                               ifan = (struct if_announcemsghdr *)(void *)p;
+                               switch(ifan->ifan_what) {
                                case IFAN_ARRIVAL:
-                                       if_add(ifa->ifan_name);
+                                       handle_interface(1, ifan->ifan_name);
                                        break;
                                case IFAN_DEPARTURE:
-                                       if_remove(ifa->ifan_name);
+                                       handle_interface(-1, ifan->ifan_name);
                                        break;
                                }
                                break;
@@ -317,7 +332,7 @@ manage_link(int fd,
                                ifm = (struct if_msghdr *)(void *)p;
                                memset(ifname, 0, sizeof(ifname));
                                if (if_indextoname(ifm->ifm_index, ifname))
-                                       if_carrier(ifname);
+                                       handle_interface(0, ifname);
                                break;
                        case RTM_DELETE:
                                if (!(rtm->rtm_addrs & RTA_DST) ||
@@ -326,26 +341,30 @@ manage_link(int fd,
                                        break;
                                if (rtm->rtm_pid == getpid())
                                        break;
-                               sa = (struct sockaddr *)(rtm + 1);
+                               cp = (char *)(void *)(rtm + 1);
+                               sa = (struct sockaddr *)(void *)cp;
                                if (sa->sa_family != AF_INET)
                                        break;
-                               rt.next = NULL;
+                               get_addrs(rtm->rtm_addrs, cp, rti_info);
                                rt.iface = NULL;
-                               sin = (struct sockaddr_in *)(void *)sa;
-                               memcpy(&rt.dest.s_addr, &sin->sin_addr.s_addr,
-                                   sizeof(rt.dest.s_addr));
-                               sa = (struct sockaddr *)
-                                   (ROUNDUP(sa->sa_len) + (char *)sa);
-                               sin = (struct sockaddr_in *)(void *)sa;
-                               memcpy(&rt.gate.s_addr, &sin->sin_addr.s_addr,
-                                   sizeof(rt.gate.s_addr));
-                               sa = (struct sockaddr *)
-                                   (ROUNDUP(sa->sa_len) + (char *)sa);
-                               sin = (struct sockaddr_in *)(void *)sa;
-                               memcpy(&rt.net.s_addr, &sin->sin_addr.s_addr,
-                                   sizeof(rt.net.s_addr));
+                               rt.next = NULL;
+                               COPYOUT(rt.dest, rti_info[RTAX_DST]);
+                               COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
+                               COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
                                route_deleted(&rt);
                                break;
+                       case RTM_DELADDR:
+                       case RTM_NEWADDR:
+                               ifam = (struct ifa_msghdr *)(void *)p;
+                               cp = (char *)(void *)(ifam + 1);
+                               get_addrs(ifam->ifam_addrs, cp, rti_info);
+                               COPYOUT(rt.dest, rti_info[RTAX_IFA]);
+                               COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
+                               COPYOUT(rt.gate, rti_info[RTAX_BRD]);
+                               if (if_indextoname(ifam->ifam_index, ifname))
+                                       handle_ifa(rtm->rtm_type, ifname,
+                                           &rt.dest, &rt.net, &rt.gate);
+                               break;
                        }
                }
        }
@@ -391,15 +410,12 @@ discover_link(struct interface **ifs, int argc, char * const *argv,
                ifp->hwlen = sdl->sdl_alen;
                memcpy(ifp->hwaddr, LLADDR(sdl), sdl->sdl_alen);
                break;
-       default:
-               /* Don't needlessly spam console on startup */
-               if (!(options & DHCPCD_MASTER &&
-                       !(options & DHCPCD_DAEMONISED) &&
-                       options & DHCPCD_QUIET))
-                       syslog(LOG_ERR, "%s: unsupported interface type",
-                           ifr->ifr_name);
-               free(ifp);
-               ifp = NULL;
+       case IFT_LOOP:
+               /* We don't allow loopback unless requested */
+               if (argc == 0 && ifac == 0) {
+                       free(ifp);
+                       ifp = NULL;
+               }
                break;
        }
        if (ifl)
@@ -413,6 +429,7 @@ discover_interfaces(int argc, char * const *argv)
 {
        struct interface *ifs = NULL;
 
-       do_interface(NULL, discover_link, &ifs, argc, argv, NULL, NULL, 2);
+       do_interface(NULL, discover_link, &ifs, argc, argv,
+                       NULL, NULL, NULL, 2);
        return ifs;
 }
index c49031dff1784a26d5e4028374b3319dcd5ae5cc..e7c38d24c051d6692f2aac2ff4bde0016c9155c5 100644 (file)
@@ -78,6 +78,7 @@ const struct option cf_options[] = {
        {"clientid",        optional_argument, NULL, 'I'},
        {"nolink",          no_argument,       NULL, 'K'},
        {"noipv4ll",        no_argument,       NULL, 'L'},
+       {"destination",     required_argument, NULL, 'N'},
        {"nooption",        optional_argument, NULL, 'O'},
        {"require",         required_argument, NULL, 'Q'},
        {"static",          required_argument, NULL, 'S'},
@@ -543,6 +544,16 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
        case 'L':
                ifo->options &= ~DHCPCD_IPV4LL;
                break;
+       case 'N':
+               if (make_option_mask(ifo->dstmask, arg, 2) != 0) {
+                       if (errno == EINVAL)
+                               syslog(LOG_ERR, "option `%s' does not take"
+                                   " an IPv4 address", arg);
+                       else
+                               syslog(LOG_ERR, "unknown otpion `%s'", arg);
+                       return -1;
+               }
+               break;
        case 'O':
                if (make_option_mask(ifo->requestmask, arg, -1) != 0 ||
                    make_option_mask(ifo->requiremask, arg, -1) != 0 ||
@@ -608,8 +619,8 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
                                rt->next = xmalloc(sizeof(*rt));
                                rt = rt->next;
                        }
-                       rt->dest.s_addr = 0;
-                       rt->net.s_addr = 0;
+                       rt->dest.s_addr = INADDR_ANY;
+                       rt->net.s_addr = INADDR_ANY;
                        rt->next = NULL;
                        if (parse_addr(&rt->gate, NULL, p) == -1)
                                return -1;
index 98c2f9516019dbb35de41bff2efeade045f4683f..39c390f343e1106bd3503a3a2f9e8050192ba3a3 100644 (file)
@@ -77,6 +77,7 @@ struct if_options {
        uint8_t requestmask[256 / 8];
        uint8_t requiremask[256 / 8];
        uint8_t nomask[256 / 8];
+       uint8_t dstmask[256 / 8];
        uint32_t leasetime;
        time_t timeout;
        time_t reboot;
diff --git a/net.c b/net.c
index b9cb280c2d1861ab7df0bc09bbdd1f3759dc626a..bfe1fd35fc4190ad780ec41e95c5ea0d9c87f65d 100644 (file)
--- a/net.c
+++ b/net.c
@@ -174,7 +174,7 @@ hwaddr_aton(unsigned char *buffer, const char *addr)
 struct interface *
 init_interface(const char *ifname)
 {
-       int s, arpable;
+       int s;
        struct ifreq ifr;
        struct interface *iface = NULL;
 
@@ -187,12 +187,10 @@ init_interface(const char *ifname)
        strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
        if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1)
                goto eexit;
-       if (ifr.ifr_flags & IFF_LOOPBACK || ifr.ifr_flags & IFF_POINTOPOINT)
-               goto eexit;
-       arpable = !(ifr.ifr_flags & IFF_NOARP);
 
        iface = xzalloc(sizeof(*iface));
        strlcpy(iface->name, ifname, sizeof(iface->name));
+       iface->flags = ifr.ifr_flags;
        /* We reserve the 100 range for virtual interfaces, if and when
         * we can work them out. */
        iface->metric = 200 + if_nametoindex(iface->name);
@@ -243,7 +241,6 @@ init_interface(const char *ifname)
                goto eexit;
        snprintf(iface->leasefile, sizeof(iface->leasefile),
            LEASEFILE, ifname);
-       iface->arpable = arpable;
        /* 0 is a valid fd, so init to -1 */
        iface->raw_fd = -1;
        iface->udp_fd = -1;
@@ -277,7 +274,7 @@ int
 do_interface(const char *ifname,
     void (*do_link)(struct interface **, int, char * const *, struct ifreq *),
     struct interface **ifs, int argc, char * const *argv,
-    struct in_addr *addr, struct in_addr *net, int act)
+    struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
 {
        int s;
        struct ifconf ifc;
@@ -348,6 +345,16 @@ do_interface(const char *ifname,
                                continue;
                        netmask = sin->sin_addr.s_addr;
                        if (act == 1) {
+                               if (dst) {
+                                       sin = (struct sockaddr_in *)
+                                               (void *)&ifr->ifr_dstaddr;
+                                       if (ioctl(s, SIOCGIFDSTADDR, ifr)
+                                           == -1)
+                                               dst->s_addr = INADDR_ANY;
+                                       else
+                                               dst->s_addr =
+                                                   sin->sin_addr.s_addr;
+                               }
                                addr->s_addr = address;
                                net->s_addr = netmask;
                                retval = 1;
@@ -436,12 +443,10 @@ carrier_status(const char *ifname)
        if (retval == 1) {
                memset(&ifmr, 0, sizeof(ifmr));
                strlcpy(ifmr.ifm_name, ifr.ifr_name, sizeof(ifmr.ifm_name));
+               retval = -1;
                if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1 &&
                    ifmr.ifm_status & IFM_AVALID)
-               {
-                       if (!(ifmr.ifm_status & IFM_ACTIVE))
-                               retval = 0;
-               }
+                       retval = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0;
        }
 #endif
        close(s);
diff --git a/net.h b/net.h
index cbac54b568744fe9ba288db8f607f3ccb20c69b9..f0ff3ad0926afa745459f9cb5f6844d6e1669e55 100644 (file)
--- a/net.h
+++ b/net.h
@@ -106,7 +106,7 @@ int up_interface(const char *);
 int do_interface(const char *,
     void (*)(struct interface **, int, char * const *, struct ifreq *),
     struct interface **, int, char * const *,
-    struct in_addr *, struct in_addr *, int);
+    struct in_addr *, struct in_addr *, struct in_addr *, int);
 int if_address(const struct interface *,
     const struct in_addr *, const struct in_addr *,
     const struct in_addr *, int);
@@ -115,9 +115,9 @@ int if_address(const struct interface *,
 #define del_address(iface, addr, net)                                  \
        if_address(iface, addr, net, NULL, -1)
 #define has_address(iface, addr, net)                                  \
-       do_interface(iface, NULL, NULL, 0, NULL, addr, net, 0)
-#define get_address(iface, addr, net)                                  \
-       do_interface(iface, NULL, NULL, 0, NULL, addr, net, 1)
+       do_interface(iface, NULL, NULL, 0, NULL, addr, net, NULL, 0)
+#define get_address(iface, addr, net, dst)                             \
+       do_interface(iface, NULL, NULL, 0, NULL, addr, net, dst, 1)
 
 int if_route(const struct interface *, const struct in_addr *,
     const struct in_addr *, const struct in_addr *, int, int);
@@ -147,9 +147,6 @@ ssize_t get_raw_packet(struct interface *, int, void *, ssize_t);
 
 int init_socket(void);
 int open_link_socket(void);
-int manage_link(int,
-    void (*)(const char *),
-    void (*)(const char *),
-    void (*)(const char *));
+int manage_link(int);
 int carrier_status(const char *);
 #endif