From: Roy Marples Date: Thu, 19 Mar 2009 17:52:12 +0000 (+0000) Subject: We can now detected primary addresses added or changed in BSD. X-Git-Tag: v5.0.0~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1abffd5ba55b4e4a2a149001a33349ef39139457;p=thirdparty%2Fdhcpcd.git We can now detected primary addresses added or changed in BSD. 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. --- diff --git a/configure.c b/configure.c index d41b03ed..bb1bba50 100644 --- a/configure.c +++ b/configure.c @@ -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; } diff --git a/configure.h b/configure.h index d103b6e5..58b78026 100644 --- a/configure.h +++ b/configure.h @@ -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 2689b734..15b21c98 100644 --- 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 diff --git a/dhcpcd-run-hooks.8.in b/dhcpcd-run-hooks.8.in index 6e025ac1..89525697 100644 --- a/dhcpcd-run-hooks.8.in +++ b/dhcpcd-run-hooks.8.in @@ -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 diff --git a/dhcpcd.8.in b/dhcpcd.8.in index eae48484..a1edeebb 100644 --- a/dhcpcd.8.in +++ b/dhcpcd.8.in @@ -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 diff --git a/dhcpcd.c b/dhcpcd.c index 752ca555..2448f5e2 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -33,6 +33,7 @@ const char copyright[] = "Copyright (c) 2006-2009 Roy Marples"; #include #include +#include #include #include @@ -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"); } diff --git a/dhcpcd.conf.5.in b/dhcpcd.conf.5.in index e21e568e..988d74e9 100644 --- a/dhcpcd.conf.5.in +++ b/dhcpcd.conf.5.in @@ -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. diff --git a/dhcpcd.h b/dhcpcd.h index d8a5fabd..927f019f 100644 --- 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 *); diff --git a/if-bsd.c b/if-bsd.c index 8d5529ca..0db8b304 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -60,17 +60,16 @@ #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; } diff --git a/if-options.c b/if-options.c index c49031df..e7c38d24 100644 --- a/if-options.c +++ b/if-options.c @@ -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; diff --git a/if-options.h b/if-options.h index 98c2f951..39c390f3 100644 --- a/if-options.h +++ b/if-options.h @@ -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 b9cb280c..bfe1fd35 100644 --- 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 cbac54b5..f0ff3ad0 100644 --- 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