From: Roy Marples Date: Tue, 31 Mar 2009 08:35:38 +0000 (+0000) Subject: Add the ability to arping an address and select a profile based on the X-Git-Tag: v5.0.0~25 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f767217f6e4c3be4a23fcd330f5252b8ff5c238;p=thirdparty%2Fdhcpcd.git Add the ability to arping an address and select a profile based on the hardware address replied with or the ip address. --- diff --git a/arp.c b/arp.c index 93bd3ea4..4a22eeae 100644 --- a/arp.c +++ b/arp.c @@ -104,6 +104,9 @@ handle_arp_packet(void *arg) uint8_t *hw_s, *hw_t; ssize_t bytes; struct if_state *state = iface->state; + struct if_options *opts = state->options; + const char *hwaddr; + struct in_addr ina; state->fail.s_addr = 0; for(;;) { @@ -139,6 +142,28 @@ handle_arp_packet(void *arg) memcpy(&reply_s, hw_s + ar.ar_hln, ar.ar_pln); memcpy(&reply_t, hw_t + ar.ar_hln, ar.ar_pln); + /* Check for arping */ + if (state->arping_index && + state->arping_index <= opts->arping_len && + (reply_s == opts->arping[state->arping_index - 1] || + (reply_s == 0 && + reply_t == opts->arping[state->arping_index - 1]))) + { + ina.s_addr = reply_s; + hwaddr = hwaddr_ntoa((unsigned char *)hw_s, + (size_t)ar.ar_hln); + syslog(LOG_INFO, + "%s: found %s on hardware address %s", + iface->name, inet_ntoa(ina), hwaddr); + if (select_profile(iface, hwaddr) == -1 && + errno == ENOENT) + select_profile(iface, inet_ntoa(ina)); + close_sockets(iface); + delete_timeout(NULL, iface); + start_interface(iface); + return; + } + /* Check for conflict */ if (state->offer && (reply_s == state->offer->yiaddr || @@ -216,8 +241,13 @@ send_arp_probe(void *arg) struct if_state *state = iface->state; struct in_addr addr; struct timeval tv; + int arping = 0; - if (state->offer) { + if (state->probes == 0 && + state->arping_index < state->options->arping_len) { + addr.s_addr = state->options->arping[state->arping_index++]; + arping = 1; + } else if (state->offer) { if (state->offer->yiaddr) addr.s_addr = state->offer->yiaddr; else @@ -230,9 +260,12 @@ send_arp_probe(void *arg) add_event(iface->arp_fd, handle_arp_packet, iface); } if (state->probes == 0) { - syslog(LOG_INFO, "%s: checking %s is available" - " on attached networks", - iface->name, inet_ntoa(addr)); + if (arping) + syslog(LOG_INFO, "%s: searching for %s", + iface->name, inet_ntoa(addr)); + else + syslog(LOG_INFO, "%s: checking for %s", + iface->name, inet_ntoa(addr)); } if (++state->probes < PROBE_NUM) { tv.tv_sec = PROBE_MIN; @@ -242,7 +275,14 @@ send_arp_probe(void *arg) } else { tv.tv_sec = ANNOUNCE_WAIT; tv.tv_usec = 0; - add_timeout_tv(&tv, bind_interface, iface); + if (arping) { + state->probes = 0; + if (state->arping_index < state->options->arping_len) + add_timeout_tv(&tv, send_arp_probe, iface); + else + add_timeout_tv(&tv, start_interface, iface); + } else + add_timeout_tv(&tv, bind_interface, iface); } syslog(LOG_DEBUG, "%s: sending ARP probe (%d of %d), next in %0.2f seconds", @@ -250,3 +290,11 @@ send_arp_probe(void *arg) if (send_arp(iface, ARPOP_REQUEST, 0, addr.s_addr) == -1) syslog(LOG_ERR, "send_arp: %m"); } + +void +start_arping(struct interface *iface) +{ + iface->state->probes = 0; + iface->state->arping_index = 0; + send_arp_probe(iface); +} diff --git a/arp.h b/arp.h index c9bc9e49..924d22f9 100644 --- a/arp.h +++ b/arp.h @@ -41,6 +41,9 @@ #define RATE_LIMIT_INTERVAL 60 #define DEFEND_INTERVAL 10 +#include "dhcpcd.h" + void send_arp_announce(void *); void send_arp_probe(void *); +void start_arping(struct interface *); #endif diff --git a/configure.c b/configure.c index dbb9118d..5d8b6b41 100644 --- a/configure.c +++ b/configure.c @@ -202,6 +202,11 @@ make_env(const struct interface *iface, char ***argv) e--; } *--p = '\0'; + if (*iface->state->profile) { + e = strlen("profile=") + strlen(iface->state->profile) + 2; + env[elen] = xmalloc(e); + snprintf(env[elen++], e, "profile=%s", iface->state->profile); + } if (iface->wireless) { e = strlen("new_ssid=") + strlen(iface->ssid) + 2; if (iface->state->new != NULL || diff --git a/dhcpcd.c b/dhcpcd.c index f3b96a9d..f32e0459 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -677,16 +677,13 @@ send_release(struct interface *iface) } static void -configure_interface(struct interface *iface, int argc, char **argv) +configure_interface1(struct interface *iface) { struct if_state *ifs = iface->state; - struct if_options *ifo; + struct if_options *ifo = ifs->options; uint8_t *duid; size_t len = 0, ifl; - free_options(ifs->options); - ifo = ifs->options = read_config(cffile, iface->name, iface->ssid); - add_options(ifo, argc, argv); if (iface->flags & IFF_POINTOPOINT && !(ifo->options & DHCPCD_INFORM)) ifo->options |= DHCPCD_STATIC; if (iface->flags & IFF_NOARP || @@ -739,11 +736,42 @@ configure_interface(struct interface *iface, int argc, char **argv) } } +int +select_profile(struct interface *iface, const char *profile) +{ + struct if_options *ifo; + + ifo = read_config(cffile, iface->name, iface->ssid, profile); + if (ifo == NULL) { + syslog(LOG_DEBUG, "%s: no profile %s", iface->name, profile); + return -1; + } + if (profile != NULL) { + strlcpy(iface->state->profile, profile, + sizeof(iface->state->profile)); + syslog(LOG_INFO, "%s: selected profile %s", + iface->name, profile); + } else + *iface->state->profile = '\0'; + free_options(iface->state->options); + iface->state->options = ifo; + configure_interface1(iface); + return 0; +} + +static void +configure_interface(struct interface *iface, int argc, char **argv) +{ + select_profile(iface, NULL); + add_options(iface->state->options, argc, argv); + configure_interface1(iface); +} + + static void handle_carrier(const char *ifname) { struct interface *iface; - char ssid[IF_SSIDSIZE]; for (iface = ifaces; iface; iface = iface->next) if (strcmp(iface->name, ifname) == 0) @@ -767,15 +795,9 @@ handle_carrier(const char *ifname) if (iface->carrier != LINK_UP) { iface->carrier = LINK_UP; syslog(LOG_INFO, "%s: carrier acquired", iface->name); - if (iface->wireless) { - /* We need to reconfigre for if ssid changed */ - memset(ssid, 0, sizeof(ssid)); - getifssid(iface->name, ssid); - if (strcmp(iface->ssid, ssid) != 0) { - strlcpy(iface->ssid, ssid, sizeof(iface->ssid)); - configure_interface(iface, margc, margv); - } - } + if (iface->wireless) + getifssid(iface->name, iface->ssid); + configure_interface(iface, margc, margv); iface->state->interval = 0; iface->state->reason = "CARRIER"; run_script(iface); @@ -982,6 +1004,10 @@ start_interface(void *arg) start_discover(iface); return; } + if (iface->state->arping_index < ifo->arping_len) { + start_arping(iface); + return; + } if (ifo->options & DHCPCD_STATIC) { start_static(iface); return; @@ -1179,7 +1205,7 @@ handle_ifa(int type, const char *ifname, ifp->state->state = DHS_INFORM; ifp->state->xid = arc4random(); ifp->state->lease.server.s_addr = - dst ? dst->s_addr : INADDR_ANY; + dst ? dst->s_addr : INADDR_ANY; ifp->addr = *addr; ifp->net = *net; open_sockets(ifp); @@ -1488,7 +1514,7 @@ main(int argc, char **argv) margv = argv; margc = argc; - ifo = read_config(cffile, NULL, NULL); + ifo = read_config(cffile, NULL, NULL, NULL); opt = add_options(ifo, argc, argv); if (opt != 1) { if (opt == 0) diff --git a/dhcpcd.conf.5.in b/dhcpcd.conf.5.in index 988d74e9..51793773 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 19, 2009 +.Dd March 31, 2009 .Dt DHCPCD.CONF 5 SMM .Os .Sh NAME @@ -57,13 +57,25 @@ When discovering interfaces, the interface name must not match .Ar pattern which is a space or comma separated list of patterns passed to .Xr fnmatch 3 . +.It Ic arping Ar address Op address +.Nm dhcpcd +will arping each address in order. +If an address is found, we will select the replying hardware address as the +profile, otherwise the ip address. +Example: +.Pp +.D1 interface bge0 +.D1 arping 192.168.0.1 +.Pp +.D1 profile 192.168.0.1 +.D1 static ip_address=192.168.0.10/24 .It Ic background Background immediately. This is useful for startup scripts which don't disable link messages for carrier status. -.It Ic blacklist Ar address Ns Op Ar /cidr +.It Ic blacklist Ar address Ns Op /cidr Ignores all packets from -.Ar address Ns Op Ar /cidr . +.Ar address Ns Op /cidr . .It Ic clientid Ar string Send the .Ar clientid . @@ -149,6 +161,9 @@ If 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 profile Ar name +Subsequent options are only parsed for this profile +.Ar name . .It Ic quiet Supress any dhcpcd output to the console, except for errors. .It Ic reboot Ar seconds diff --git a/dhcpcd.h b/dhcpcd.h index a65e8633..e353a33f 100644 --- a/dhcpcd.h +++ b/dhcpcd.h @@ -39,6 +39,7 @@ #define HWADDR_LEN 20 #define IF_SSIDSIZE 33 +#define PROFILE_LEN 32 enum DHS { DHS_INIT, @@ -60,6 +61,7 @@ enum DHS { struct if_state { enum DHS state; + char profile[PROFILE_LEN]; struct if_options *options; struct dhcp_message *sent; struct dhcp_message *offer; @@ -76,6 +78,7 @@ struct if_state { int conflicts; time_t defend; struct in_addr fail; + size_t arping_index; }; struct interface { @@ -134,5 +137,6 @@ void start_expire(void *); void send_decline(struct interface *); void close_sockets(struct interface *); void drop_config(struct interface *, const char *); +int select_profile(struct interface *, const char *); #endif diff --git a/if-options.c b/if-options.c index 4ef78b79..c10240cc 100644 --- a/if-options.c +++ b/if-options.c @@ -46,6 +46,7 @@ #include "net.h" const struct option cf_options[] = { + {"arping", required_argument, NULL, 'a'}, {"background", no_argument, NULL, 'b'}, {"script", required_argument, NULL, 'c'}, {"debug", no_argument, NULL, 'd'}, @@ -311,6 +312,13 @@ parse_option(struct if_options *ifo, int opt, const char *arg) struct rt *rt; switch(opt) { + case 'a': + if (parse_addr(&addr, NULL, arg) != 0) + return -1; + ifo->arping = xrealloc(ifo->arping, + sizeof(in_addr_t) * (ifo->arping_len + 1)); + ifo->arping[ifo->arping_len++] = addr.s_addr; + break; case 'e': /* FALLTHROUGH */ case 'n': /* FALLTHROUGH */ case 'x': /* FALLTHROUGH */ @@ -693,12 +701,13 @@ parse_config_line(struct if_options *ifo, const char *opt, char *line) } struct if_options * -read_config(const char *file, const char *ifname, const char *ssid) +read_config(const char *file, + const char *ifname, const char *ssid, const char *profile) { struct if_options *ifo; FILE *f; char *line, *option, *p; - int skip = 0; + int skip = 0, have_profile = 0; /* Seed our default options */ ifo = xzalloc(sizeof(*ifo)); @@ -749,16 +758,30 @@ read_config(const char *file, const char *ifname, const char *ssid) skip = 1; continue; } + /* Start of a profile block, skip if not ours */ + if (strcmp(option, "profile") == 0) { + if (profile && line && strcmp(line, profile) == 0) { + skip = 0; + have_profile = 1; + } else + skip = 1; + continue; + } if (skip) continue; - if (parse_config_line(ifo, option, line) != 1) { + if (parse_config_line(ifo, option, line) != 1) break; - } } fclose(f); + if (profile && !have_profile) { + free_options(ifo); + errno = ENOENT; + ifo = NULL; + } + /* Terminate the encapsulated options */ - if (ifo->vendor[0]) { + if (ifo && ifo->vendor[0]) { ifo->vendor[0]++; ifo->vendor[ifo->vendor[0]] = DHO_END; } diff --git a/if-options.h b/if-options.h index 64c8bdea..7fad0e5d 100644 --- a/if-options.h +++ b/if-options.h @@ -37,7 +37,7 @@ /* Don't set any optional arguments here so we retain POSIX * compatibility with getopt */ -#define IF_OPTS "bc:def:h:i:kl:m:no:pqr:s:t:u:v:xy:z:ABC:DEF:GI:KLN:O:Q:TVX:Z:" +#define IF_OPTS "a:bc:def:h:i:kl:m:no:pqr:s:t:u:v:xy:z:ABC:DEF:GI:KLN:O:Q:TVX:Z:" #define DEFAULT_TIMEOUT 30 #define DEFAULT_REBOOT 10 @@ -100,9 +100,12 @@ struct if_options { size_t blacklist_len; in_addr_t *blacklist; + size_t arping_len; + in_addr_t *arping; }; -struct if_options *read_config(const char *, const char *, const char *); +struct if_options *read_config(const char *, + const char *, const char *, const char *); int add_options(struct if_options *, int, char **); void free_options(struct if_options *);