Don't return a DHCPv6 reply in response to a confirm without address(es)
authorHans Dedecker <dedeckeh@gmail.com>
Wed, 16 Apr 2014 09:53:32 +0000 (11:53 +0200)
committerHans Dedecker <dedeckeh@gmail.com>
Wed, 23 Apr 2014 07:20:29 +0000 (09:20 +0200)
RFC3315 Section 18.2.2 states no reply must returned by the server in case no address(es) are present :
If the server is unable to perform this test (for example, the server does not have information about prefixes on the link to which the client is connected),
or there were no addresses in any of the IAs sent by the client, the server MUST NOT send a reply to the client.

src/dhcpv6-ia.c
src/dhcpv6.c

index 844dfd30b7d507d119c500b622e223a9b54e7057..5e34b5cf7430888dd77e51da288fa7f71d0dd38c 100644 (file)
@@ -972,6 +972,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
        dhcpv6_for_each_option(start, end, otype, olen, odata) {
                bool is_pd = (otype == DHCPV6_OPT_IA_PD);
                bool is_na = (otype == DHCPV6_OPT_IA_NA);
+               bool ia_addr_present = false;
                if (!is_pd && !is_na)
                        continue;
 
@@ -1024,6 +1025,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
                                if (stype != DHCPV6_OPT_IA_ADDR || slen < sizeof(struct dhcpv6_ia_addr) - 4)
                                        continue;
 
+                               ia_addr_present = true;
 #ifdef DHCPV6_OPT_PREFIX_CLASS
                                uint8_t *xdata;
                                uint16_t xtype, xlen;
@@ -1178,8 +1180,8 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
                                a->valid_until = now + 3600; // Block address for 1h
                                update_state = true;
                        }
-               } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM) {
-                       // Always send NOTONLINK for CONFIRM so that clients restart connection
+               } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM && ia_addr_present) {
+                       // Send NOTONLINK for CONFIRM with addr present so that clients restart connection
                        status = DHCPV6_STATUS_NOTONLINK;
                        ia_response_len = append_reply(buf, buflen, status, ia, a, iface, true);
                }
index 62f30e23f749694808e47b84702ad48d504ce18c..55b9ea9208f8aee993bdde236a8c34b440cd3583 100644 (file)
@@ -320,7 +320,7 @@ static void handle_client_request(void *addr, void *data, size_t len,
        if (opts[-4] != DHCPV6_MSG_INFORMATION_REQUEST) {
                ssize_t ialen = dhcpv6_handle_ia(pdbuf, sizeof(pdbuf), iface, addr, &opts[-4], opts_end);
                iov[6].iov_len = ialen;
-               if (ialen < 0 || (ialen == 0 && opts[-4] == DHCPV6_MSG_REBIND))
+               if (ialen < 0 || (ialen == 0 && (opts[-4] == DHCPV6_MSG_REBIND || opts[-4] == DHCPV6_MSG_CONFIRM)))
                        return;
        }