From 6bb6f717422e07363de1a53b7ca9827fa9008ee4 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Wed, 5 Jun 2013 23:57:03 +0000 Subject: [PATCH] Add support for Rapid Commit, RFC3315 and RFC4039. --- dhcp-common.c | 8 ++++++++ dhcp-common.h | 2 ++ dhcp.c | 14 +++++++++++++- dhcp.h | 1 + dhcp6.c | 36 +++++++++++++++++++++++++++++++----- dhcp6.h | 2 +- dhcpcd.8.in | 8 ++++---- dhcpcd.conf | 5 +++++ 8 files changed, 65 insertions(+), 11 deletions(-) diff --git a/dhcp-common.c b/dhcp-common.c index 7b217f94..3f28d24a 100644 --- a/dhcp-common.c +++ b/dhcp-common.c @@ -329,6 +329,14 @@ print_option(char *s, ssize_t len, int type, int dl, const uint8_t *data, return print_string(s, len, dl, data); } + if (type & FLAG) { + if (s) { + *s++ = '1'; + *s = '\0'; + } + return 2; + } + /* DHCPv6 status code */ if (type & SCODE && dl >= (int)sizeof(u16)) { if (s) { diff --git a/dhcp-common.h b/dhcp-common.h index 22f98bc1..3a30b252 100644 --- a/dhcp-common.h +++ b/dhcp-common.h @@ -56,6 +56,8 @@ #define ADDRIPV6 (1 << 14) #define BINHEX (1 << 15) #define SCODE (1 << 16) +#define FLAG (1 << 17) +#define NOREQ (1 << 18) struct dhcp_opt { uint16_t option; diff --git a/dhcp.c b/dhcp.c index 8180a40e..6c25da9a 100644 --- a/dhcp.c +++ b/dhcp.c @@ -183,6 +183,7 @@ const struct dhcp_opt dhcp_opts[] = { { 75, IPV4A, "streettalk_server" }, { 76, IPV4A, "streettalk_directory_assistance_server" }, { 77, STRING, "user_class" }, + { 80, FLAG | NOREQ, "rapid_commit" }, { 81, STRING | RFC3397, "fqdn_name" }, { 85, IPV4A, "nds_servers" }, { 86, STRING, "nds_tree_name" }, @@ -929,6 +930,15 @@ make_message(struct dhcp_message **message, p += len; } + if (type == DHCP_DISCOVER && + !(options & DHCPCD_TEST) && + has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT)) + { + /* RFC 4039 Section 3 */ + *p++ = DHO_RAPIDCOMMIT; + *p++ = 0; + } + if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST) PUTADDR(DHO_IPADDRESS, ifo->req_addr); @@ -1037,6 +1047,8 @@ make_message(struct dhcp_message **message, if (!(opt->type & REQUEST || has_option_mask(ifo->requestmask, opt->option))) continue; + if (opt->type & NOREQ) + continue; if (type == DHCP_INFORM && (opt->option == DHO_RENEWALTIME || opt->option == DHO_REBINDTIME)) @@ -2141,7 +2153,7 @@ dhcp_handle(struct interface *iface, struct dhcp_message **dhcpp, get_option_uint8(&tmp, dhcp, i) != 0) { /* If we are bootp, then ignore the need for serverid. - * To ignore bootp, require dhcp_message_type instead. */ + * To ignore bootp, require dhcp_message_type. */ if (type == 0 && i == DHO_SERVERID) continue; log_dhcp(LOG_WARNING, "reject DHCP", iface, dhcp, from); diff --git a/dhcp.h b/dhcp.h index c5124df1..ccf07a9d 100644 --- a/dhcp.h +++ b/dhcp.h @@ -103,6 +103,7 @@ enum DHO { DHO_VENDORCLASSID = 60, DHO_CLIENTID = 61, DHO_USERCLASS = 77, /* RFC 3004 */ + DHO_RAPIDCOMMIT = 80, /* RFC 4039 */ DHO_FQDN = 81, DHO_DNSSEARCH = 119, /* RFC 3397 */ DHO_CSR = 121, /* RFC 3442 */ diff --git a/dhcp6.c b/dhcp6.c index 9d4d8285..d44e227f 100644 --- a/dhcp6.c +++ b/dhcp6.c @@ -109,8 +109,8 @@ const struct dhcp_opt dhcp6_opts[] = { { D6_OPTION_SERVERID, BINHEX, "server_id" }, { D6_OPTION_IA_ADDR, IPV6A, "ia_addr" }, { D6_OPTION_PREFERENCE, UINT8, "preference" }, - { D6_OPTION_RAPID_COMMIT, 0, "rapid_commit" }, { D6_OPTION_UNICAST, ADDRIPV6, "unicast" }, + { D6_OPTION_RAPID_COMMIT, FLAG | NOREQ, "rapid_commit" }, { D6_OPTION_STATUS_CODE, SCODE, "status_code" }, { D6_OPTION_SIP_SERVERS_NAME, RFC3397, "sip_servers_names" }, { D6_OPTION_SIP_SERVERS_ADDRESS,IPV6A, "sip_servers_addresses" }, @@ -141,6 +141,7 @@ const struct dhcp_compat dhcp_compats[] = { { DHO_DNSDOMAIN, D6_OPTION_FQDN }, { DHO_NISSERVER, D6_OPTION_NIS_SERVERS }, { DHO_NTPSERVER, D6_OPTION_SNTP_SERVERS }, + { DHO_RAPIDCOMMIT, D6_OPTION_RAPID_COMMIT }, { DHO_FQDN, D6_OPTION_FQDN }, { DHO_DNSSEARCH, D6_OPTION_DOMAIN_LIST }, { 0, 0 } @@ -393,8 +394,9 @@ dhcp6_makemessage(struct interface *ifp) si = NULL; if (state->state != DH6S_RELEASE) { for (opt = dhcp6_opts; opt->option; opt++) { - if (opt->type & REQUEST || - has_option_mask(ifo->requestmask6, opt->option)) + if (!(opt->type & NOREQ) && + (opt->type & REQUEST || + has_option_mask(ifo->requestmask6, opt->option))) { n_options++; len += sizeof(*u16); @@ -463,6 +465,11 @@ dhcp6_makemessage(struct interface *ifp) IA = 0; } + if (state->state == DH6S_DISCOVER && + !(options & DHCPCD_TEST) && + has_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT)) + len += sizeof(*o); + if (m == NULL) { m = state->new; ml = state->new_len; @@ -539,6 +546,15 @@ dhcp6_makemessage(struct interface *ifp) dhcp6_makevendor(o); #endif + if (state->state == DH6S_DISCOVER && + !(options & DHCPCD_TEST) && + has_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT)) + { + o = D6_NEXT_OPTION(o); + o->code = htons(D6_OPTION_RAPID_COMMIT); + o->len = 0; + } + for (l = 0; IA && l < ifo->iaid_len; l++) { o = D6_NEXT_OPTION(o); o->code = htons(ifo->ia_type); @@ -624,9 +640,10 @@ dhcp6_makemessage(struct interface *ifp) o->len = 0; u16 = (uint16_t *)(void *)D6_OPTION_DATA(o); for (opt = dhcp6_opts; opt->option; opt++) { - if (opt->type & REQUEST || + if (!(opt->type & NOREQ) && + (opt->type & REQUEST || has_option_mask(ifo->requestmask6, - opt->option)) + opt->option))) { *u16++ = htons(opt->option); o->len += sizeof(*u16); @@ -1962,6 +1979,13 @@ dhcp6_handledata(__unused void *arg) return; } break; + case DH6S_DISCOVER: + if (has_option_mask(ifo->requestmask6, + D6_OPTION_RAPID_COMMIT) && + dhcp6_getoption(D6_OPTION_RAPID_COMMIT, r, len)) + state->state = DH6S_REQUEST; + else + op = NULL; case DH6S_REQUEST: /* FALLTHROUGH */ case DH6S_RENEW: /* FALLTHROUGH */ case DH6S_REBIND: @@ -2004,6 +2028,8 @@ dhcp6_handledata(__unused void *arg) switch(r->type) { case DHCP6_ADVERTISE: + if (state->state == DH6S_REQUEST) /* rapid commit */ + break; ap = TAILQ_FIRST(&state->addrs); syslog(LOG_INFO, "%s: ADV %s from %s", ifp->name, ap->saddr, sfrom); diff --git a/dhcp6.h b/dhcp6.h index de6e6499..f1b8c7dc 100644 --- a/dhcp6.h +++ b/dhcp6.h @@ -61,9 +61,9 @@ #define D6_OPTION_IA_ADDR 5 #define D6_OPTION_PREFERENCE 7 #define D6_OPTION_ELAPSED 8 -#define D6_OPTION_RAPID_COMMIT 9 #define D6_OPTION_UNICAST 12 #define D6_OPTION_STATUS_CODE 13 +#define D6_OPTION_RAPID_COMMIT 14 #define D6_OPTION_VENDOR 16 #define D6_OPTION_SIP_SERVERS_NAME 21 #define D6_OPTION_SIP_SERVERS_ADDRESS 22 diff --git a/dhcpcd.8.in b/dhcpcd.8.in index 1dc79399..5e6ebf78 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 June 5, 2013 +.Dd June 6, 2013 .Dt DHCPCD 8 .Os .Sh NAME @@ -603,9 +603,9 @@ running on the .Xr dhcpcd-run-hooks 8 , .Xr resolvconf 8 .Sh STANDARDS -RFC 951, RFC 1534, RFC 2131, RFC 2132, RFC 2855, RFC 3004, RFC 3315,RFC 3361, -RFC 3633, RFC 3396, RFC 3397, RFC 3442, RFC 3927, RFC 4075, RFC 4361, RFC 4390, -RFC 4702, RFC 4704, RFC 4861, RFC 4833, RFC 5227, RFC 5969, RFC 6106. +RFC 951, RFC 1534, RFC 2131, RFC 2132, RFC 2855, RFC 3004, RFC 3315, RFC 3361, +RFC 3633, RFC 3396, RFC 3397, RFC 3442, RFC 3927, RFC 4039, RFC 4075, RFC 4361, +RFC 4390, RFC 4702, RFC 4704, RFC 4861, RFC 4833, RFC 5227, RFC 5969, RFC 6106. .Sh AUTHORS .An Roy Marples Aq roy@marples.name .Sh BUGS diff --git a/dhcpcd.conf b/dhcpcd.conf index 1f5b4adb..78628de1 100644 --- a/dhcpcd.conf +++ b/dhcpcd.conf @@ -16,6 +16,11 @@ fqdn # Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361. duid +# Rapid commit support. +# Safe to enable by default because it requires the equivalent option set +# on the server to actually work. +option rapid_commit + # A list of options to request from the DHCP server. option domain_name_servers, domain_name, domain_search, host_name option classless_static_routes -- 2.47.3