From 36833ea26684b70b0d6093ecec648fe192a582ec Mon Sep 17 00:00:00 2001 From: Hans Dedecker Date: Wed, 13 Feb 2019 12:07:49 +0100 Subject: [PATCH] dhcpv6: rapid commit support Add support for rapid commit according to RFC8415 18.3.1 Signed-off-by: Hans Dedecker --- src/dhcpv6-ia.c | 12 ++++++++---- src/dhcpv6.c | 48 ++++++++++++++++++++++++++++++------------------ src/dhcpv6.h | 1 + 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 2820946..7c3ccad 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -1170,7 +1170,7 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac uint8_t *clid_data = NULL, clid_len = 0, mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; char hostname[256]; size_t hostname_len = 0; - bool notonlink = false; + bool notonlink = false, rapid_commit = false; char duidbuf[261]; dhcpv6_for_each_option(start, end, otype, olen, odata) { @@ -1194,6 +1194,8 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac hostname_len = strcspn(hostname, "."); } else if (otype == DHCPV6_OPT_RECONF_ACCEPT) accept_reconf = true; + else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT) + rapid_commit = true; } if (!clid_data || !clid_len || clid_len > 130) @@ -1348,16 +1350,18 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac hdr->msg_type == DHCPV6_MSG_REBIND ? false : true); /* Was only a solicitation: mark binding for removal */ - if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT) { + if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT && !rapid_commit) { a->flags &= ~OAF_BOUND; a->flags |= OAF_TENTATIVE; if (!(a->flags & OAF_STATIC)) /* Keep tentative assignment around for 60 seconds */ a->valid_until = now + 60; + } else if (assigned && - (hdr->msg_type == DHCPV6_MSG_REQUEST || - hdr->msg_type == DHCPV6_MSG_REBIND)) { + ((hdr->msg_type == DHCPV6_MSG_SOLICIT && rapid_commit) || + hdr->msg_type == DHCPV6_MSG_REQUEST || + hdr->msg_type == DHCPV6_MSG_REBIND)) { if (hostname_len > 0) { a->hostname = realloc(a->hostname, hostname_len + 1); if (a->hostname) { diff --git a/src/dhcpv6.c b/src/dhcpv6.c index a40c353..f2080c8 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -163,6 +163,7 @@ enum { IOV_DEST, IOV_MAXRT, #define IOV_STAT IOV_MAXRT + IOV_RAPID_COMMIT, IOV_DNS, IOV_DNS_ADDR, IOV_SEARCH, @@ -237,6 +238,8 @@ static void handle_client_request(void *addr, void *data, size_t len, struct interface *iface, void *dest_addr) { struct dhcpv6_client_header *hdr = data; + uint8_t *opts = (uint8_t *)&hdr[1], *opts_end = (uint8_t *)data + len; + bool o_rapid_commit = false; if (len < sizeof(*hdr)) return; @@ -273,6 +276,11 @@ static void handle_client_request(void *addr, void *data, size_t len, } maxrt = {htons(DHCPV6_OPT_SOL_MAX_RT), htons(sizeof(maxrt) - 4), htonl(60)}; + struct __attribute__((packed)) { + uint16_t type; + uint16_t len; + } rapid_commit = {htons(DHCPV6_OPT_RAPID_COMMIT), 0}; + struct __attribute__((packed)) { uint16_t type; uint16_t len; @@ -336,6 +344,7 @@ static void handle_client_request(void *addr, void *data, size_t len, [IOV_NESTED] = {NULL, 0}, [IOV_DEST] = {&dest, (uint8_t*)&dest.clientid_type - (uint8_t*)&dest}, [IOV_MAXRT] = {&maxrt, sizeof(maxrt)}, + [IOV_RAPID_COMMIT] = {&rapid_commit, 0}, [IOV_DNS] = {&dns, (dns_cnt) ? sizeof(dns) : 0}, [IOV_DNS_ADDR] = {dns_addr_ptr, dns_cnt * sizeof(*dns_addr_ptr)}, [IOV_SEARCH] = {&search, (search_len) ? sizeof(search) : 0}, @@ -346,30 +355,19 @@ static void handle_client_request(void *addr, void *data, size_t len, [IOV_RELAY_MSG] = {NULL, 0} }; - uint8_t *opts = (uint8_t*)&hdr[1], *opts_end = (uint8_t*)data + len; if (hdr->msg_type == DHCPV6_MSG_RELAY_FORW) handle_nested_message(data, len, &hdr, &opts, &opts_end, iov); - memcpy(dest.tr_id, hdr->transaction_id, sizeof(dest.tr_id)); - if (hdr->msg_type == DHCPV6_MSG_ADVERTISE || hdr->msg_type == DHCPV6_MSG_REPLY || hdr->msg_type == DHCPV6_MSG_RELAY_REPL) return; if (!IN6_IS_ADDR_MULTICAST((struct in6_addr *)dest_addr) && iov[IOV_NESTED].iov_len == 0 && - (hdr->msg_type == DHCPV6_MSG_SOLICIT || hdr->msg_type == DHCPV6_MSG_CONFIRM || - hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST)) + (hdr->msg_type == DHCPV6_MSG_SOLICIT || hdr->msg_type == DHCPV6_MSG_CONFIRM || + hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST)) return; - if (hdr->msg_type == DHCPV6_MSG_SOLICIT) { - dest.msg_type = DHCPV6_MSG_ADVERTISE; - } else if (hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST) { - iov[IOV_REFRESH].iov_base = &refresh; - iov[IOV_REFRESH].iov_len = sizeof(refresh); - - /* Return inf max rt option in reply to information request */ - maxrt.type = htons(DHCPV6_OPT_INF_MAX_RT); - } + memcpy(dest.tr_id, hdr->transaction_id, sizeof(dest.tr_id)); /* Go through options and find what we need */ uint16_t otype, olen; @@ -406,6 +404,9 @@ static void handle_client_request(void *addr, void *data, size_t len, free(addrs); } #endif + } else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT) { + iov[IOV_RAPID_COMMIT].iov_len = sizeof(rapid_commit); + o_rapid_commit = true; } } @@ -422,6 +423,16 @@ static void handle_client_request(void *addr, void *data, size_t len, return; } + if (hdr->msg_type == DHCPV6_MSG_SOLICIT && !o_rapid_commit) { + dest.msg_type = DHCPV6_MSG_ADVERTISE; + } else if (hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST) { + iov[IOV_REFRESH].iov_base = &refresh; + iov[IOV_REFRESH].iov_len = sizeof(refresh); + + /* Return inf max rt option in reply to information request */ + maxrt.type = htons(DHCPV6_OPT_INF_MAX_RT); + } + if (hdr->msg_type != DHCPV6_MSG_INFORMATION_REQUEST) { ssize_t ialen = dhcpv6_ia_handle_IAs(pdbuf, sizeof(pdbuf), iface, addr, (const void *)hdr, opts_end); @@ -433,10 +444,11 @@ static void handle_client_request(void *addr, void *data, size_t len, if (iov[IOV_NESTED].iov_len > 0) /* Update length */ update_nested_message(data, len, iov[IOV_DEST].iov_len + iov[IOV_MAXRT].iov_len + - iov[IOV_DNS].iov_len + iov[IOV_DNS_ADDR].iov_len + - iov[IOV_SEARCH].iov_len + iov[IOV_SEARCH_DOMAIN].iov_len + - iov[IOV_PDBUF].iov_len + iov[IOV_CERID].iov_len + - iov[IOV_DHCPV6_RAW].iov_len - (4 + opts_end - opts)); + iov[IOV_RAPID_COMMIT].iov_len + iov[IOV_DNS].iov_len + + iov[IOV_DNS_ADDR].iov_len + iov[IOV_SEARCH].iov_len + + iov[IOV_SEARCH_DOMAIN].iov_len + iov[IOV_PDBUF].iov_len + + iov[IOV_CERID].iov_len + iov[IOV_DHCPV6_RAW].iov_len - + (4 + opts_end - opts)); odhcpd_send(iface->dhcpv6_event.uloop.fd, addr, iov, ARRAY_SIZE(iov), iface); } diff --git a/src/dhcpv6.h b/src/dhcpv6.h index 7abc8af..aaf919c 100644 --- a/src/dhcpv6.h +++ b/src/dhcpv6.h @@ -44,6 +44,7 @@ #define DHCPV6_OPT_STATUS 13 #define DHCPV6_OPT_RELAY_MSG 9 #define DHCPV6_OPT_AUTH 11 +#define DHCPV6_OPT_RAPID_COMMIT 14 #define DHCPV6_OPT_USER_CLASS 15 #define DHCPV6_OPT_INTERFACE_ID 18 #define DHCPV6_OPT_RECONF_MSG 19 -- 2.25.1