diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2016-10-06 16:29:18 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2016-10-06 16:29:18 +0000 |
commit | 432e4be4b386265a8c7d11952628bcf51e5c46b8 (patch) | |
tree | 45594b80c734d225dc12f89f96a261c03717cb16 | |
parent | d690d085048eb7d9e73e77cd86a4869ec7c25810 (diff) |
Add support for RFC 6842, which says the client MUST drop packets when
the server provides a client-identifier value and it doesn't match
the value the client sent.
So stop suppressing client-identifer info in the leases file and when
reading the leases file stop discarding leases that don't have current
client-identifier info. Don't use them, but keep them around in case
the client-identifier info changes back next time.
Also construct the default client-identifier (if needed) before reading
the leases file.
-rw-r--r-- | sbin/dhclient/clparse.c | 42 | ||||
-rw-r--r-- | sbin/dhclient/dhclient.c | 61 | ||||
-rw-r--r-- | sbin/dhclient/dispatch.c | 5 | ||||
-rw-r--r-- | sbin/dhclient/options.c | 19 |
4 files changed, 73 insertions, 54 deletions
diff --git a/sbin/dhclient/clparse.c b/sbin/dhclient/clparse.c index c7a6f087dd4..f427eafcb4c 100644 --- a/sbin/dhclient/clparse.c +++ b/sbin/dhclient/clparse.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clparse.c,v 1.102 2016/09/30 13:20:57 krw Exp $ */ +/* $OpenBSD: clparse.c,v 1.103 2016/10/06 16:29:17 krw Exp $ */ /* Parser for dhclient config and lease files. */ @@ -466,7 +466,6 @@ parse_client_lease_statement(FILE *cfile, int is_static, struct interface_info * { struct client_state *client = ifi->client; struct client_lease *lease, *lp, *pl; - struct option_data *opt1, *opt2; int token; token = next_token(NULL, cfile); @@ -495,31 +494,28 @@ parse_client_lease_statement(FILE *cfile, int is_static, struct interface_info * token = next_token(NULL, cfile); /* - * If the new lease is for an obsolete client-identifier, toss it. - */ - opt1 = &lease->options[DHO_DHCP_CLIENT_IDENTIFIER]; - opt2 = &config->send_options[DHO_DHCP_CLIENT_IDENTIFIER]; - if (opt1->len && opt2->len && (opt1->len != opt2->len || - memcmp(opt1->data, opt2->data, opt1->len))) { - note("Obsolete client identifier (%s) in recorded lease", - pretty_print_option(DHO_DHCP_CLIENT_IDENTIFIER, opt1, 0)); - free_client_lease(lease); - return; - } - - /* - * The new lease will supersede a lease of the same type and for - * the same address or the same SSID. + * The new lease will supersede a lease which is of the same type + * AND the same ssid AND the same Client Identifier AND the same + * IP address. */ TAILQ_FOREACH_SAFE(lp, &client->leases, next, pl) { if (lp->is_static != is_static) continue; - if ((strcmp(lp->ssid, ifi->ssid) == 0) || - (lp->address.s_addr == lease->address.s_addr)) { - TAILQ_REMOVE(&client->leases, lp, next); - lp->is_static = 0; /* Else it won't be freed. */ - free_client_lease(lp); - } + if (strcmp(lp->ssid, ifi->ssid) != 0) + continue; + if ((lease->options[DHO_DHCP_CLIENT_IDENTIFIER].len != 0) && + ((lp->options[DHO_DHCP_CLIENT_IDENTIFIER].len != + lease->options[DHO_DHCP_CLIENT_IDENTIFIER].len) || + memcmp(lp->options[DHO_DHCP_CLIENT_IDENTIFIER].data, + lease->options[DHO_DHCP_CLIENT_IDENTIFIER].data, + lp->options[DHO_DHCP_CLIENT_IDENTIFIER].len))) + continue; + if (lp->address.s_addr != lease->address.s_addr) + continue; + + TAILQ_REMOVE(&client->leases, lp, next); + lp->is_static = 0; /* Else it won't be freed. */ + free_client_lease(lp); } /* diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c index 692643c8754..40edc43c02e 100644 --- a/sbin/dhclient/dhclient.c +++ b/sbin/dhclient/dhclient.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dhclient.c,v 1.391 2016/09/29 15:29:06 krw Exp $ */ +/* $OpenBSD: dhclient.c,v 1.392 2016/10/06 16:29:17 krw Exp $ */ /* * Copyright 2004 Henning Brauer <henning@openbsd.org> @@ -430,6 +430,7 @@ int main(int argc, char *argv[]) { struct interface_info *ifi; + struct option_data *opt; struct ifreq ifr; struct ieee80211_nwid nwid; struct stat sb; @@ -506,6 +507,7 @@ main(int argc, char *argv[]) ifi->index = if_nametoindex(ifi->name); if (ifi->index == 0) error("%s: no such interface", ifi->name); + get_hw_address(ifi); tzset(); @@ -555,6 +557,29 @@ main(int argc, char *argv[]) read_client_conf(ifi); + /* + * Set default client identifier, if needed, *before* reading + * the leases file! Changes to the lladdr will trigger a restart + * and go through here again. + * + * Check both len && data so + * + * send dhcp-client-identifier ""; + * + * can be used to suppress sending the default client + * identifier. + */ + opt = &config->send_options[DHO_DHCP_CLIENT_IDENTIFIER]; + if (opt->len == 0 && opt->data == NULL) { + opt->data = calloc(1, ETHER_ADDR_LEN + 1); + if (opt->data == NULL) + error("no memory for default client identifier"); + opt->data[0] = HTYPE_ETHER; + memcpy(&opt->data[1], ifi->hw_address.ether_addr_octet, + ETHER_ADDR_LEN); + opt->len = ETHER_ADDR_LEN + 1; + } + if ((pw = getpwnam("_dhcp")) == NULL) error("no such user: _dhcp"); @@ -732,32 +757,13 @@ state_reboot(void *xifi) struct client_state *client = ifi->client; char ifname[IF_NAMESIZE]; struct client_lease *lp; - struct option_data *opt; time_t cur_time; + int i; cancel_timeout(); deleting.s_addr = INADDR_ANY; adding.s_addr = INADDR_ANY; - get_hw_address(ifi); - opt = &config->send_options[DHO_DHCP_CLIENT_IDENTIFIER]; - /* - * Check both len && data so - * send dhcp-client-identifier ""; - * can be used to suppress sending the default client - * identifier. - */ - if (opt->len == 0 && opt->data == NULL) { - /* Build default client identifier. */ - opt->data = calloc(1, ETHER_ADDR_LEN + 1); - if (opt->data != NULL) { - opt->data[0] = HTYPE_ETHER; - memcpy(&opt->data[1], ifi->hw_address.ether_addr_octet, - ETHER_ADDR_LEN); - opt->len = ETHER_ADDR_LEN + 1; - } - } - time(&cur_time); if (client->active) { if (client->active->expiry <= cur_time) @@ -768,9 +774,15 @@ state_reboot(void *xifi) } /* Run through the list of leases and see if one can be used. */ + i = DHO_DHCP_CLIENT_IDENTIFIER; TAILQ_FOREACH(lp, &client->leases, next) { if (strcmp(lp->ssid, ifi->ssid) != 0) continue; + if ((lp->options[i].len != 0) && ((lp->options[i].len != + config->send_options[i].len) || + memcmp(lp->options[i].data, config->send_options[i].data, + lp->options[i].len))) + continue; if (addressinuse(ifi, lp->address, ifname) && strncmp(ifname, ifi->name, IF_NAMESIZE) != 0) continue; @@ -2004,12 +2016,7 @@ lease_as_string(struct interface_info *ifi, char *type, } for (i = 0; i < 256; i++) { - if (i == DHO_DHCP_CLIENT_IDENTIFIER) { - /* Ignore any CLIENT_IDENTIFIER from server. */ - opt = &config->send_options[i]; - } else - opt = &lease->options[i]; - + opt = &lease->options[i]; if (opt->len == 0) continue; diff --git a/sbin/dhclient/dispatch.c b/sbin/dhclient/dispatch.c index b05b576e4ab..555d3436a3f 100644 --- a/sbin/dhclient/dispatch.c +++ b/sbin/dhclient/dispatch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dispatch.c,v 1.110 2016/09/29 00:40:08 krw Exp $ */ +/* $OpenBSD: dispatch.c,v 1.111 2016/10/06 16:29:17 krw Exp $ */ /* * Copyright 2004 Henning Brauer <henning@openbsd.org> @@ -86,8 +86,7 @@ get_hw_address(struct interface_info *ifi) found = 0; for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { if ((ifa->ifa_flags & IFF_LOOPBACK) || - (ifa->ifa_flags & IFF_POINTOPOINT) || - (!(ifa->ifa_flags & IFF_UP))) + (ifa->ifa_flags & IFF_POINTOPOINT)) continue; if (strcmp(ifi->name, ifa->ifa_name) != 0) diff --git a/sbin/dhclient/options.c b/sbin/dhclient/options.c index 2a85ea50126..93aa1f2b3b0 100644 --- a/sbin/dhclient/options.c +++ b/sbin/dhclient/options.c @@ -1,4 +1,4 @@ -/* $OpenBSD: options.c,v 1.78 2016/09/02 15:44:26 mpi Exp $ */ +/* $OpenBSD: options.c,v 1.79 2016/10/06 16:29:17 krw Exp $ */ /* DHCP options parsing and reassembly. */ @@ -711,6 +711,22 @@ do_packet(struct interface_info *ifi, unsigned int from_port, (unsigned char *)packet->sname, sizeof(packet->sname)); } + + /* + * RFC 6842 says if the server sends a client identifier + * that doesn't match then the packet must be dropped. + */ + i = DHO_DHCP_CLIENT_IDENTIFIER; + if ((options[i].len != 0) && + ((options[i].len != config->send_options[i].len) || + memcmp(options[i].data, config->send_options[i].data, + options[i].len) != 0)) { +#ifdef DEBUG + debug("Discarding packet with client-identifier '%s'", + pretty_print_option(i, &options[i], 0)); +#endif + goto done; + } } type = "<unknown>"; @@ -757,6 +773,7 @@ do_packet(struct interface_info *ifi, unsigned int from_port, free(info); +done: for (i = 0; i < 256; i++) free(options[i].data); } |