Merge pull request #21 from mehlis/fix-nak-by-doing-valid-reply
[project/odhcpd.git] / src / dhcpv6-ia.c
index c655d93..90dcaf5 100644 (file)
@@ -258,6 +258,8 @@ void dhcpv6_write_statefile(void)
                                        for (size_t i = 0; i < addrlen; ++i) {
                                                if (addrs[i].prefix > 96)
                                                        continue;
+                                               if (c->valid_until <= now)
+                                                       continue;
 
                                                addr = addrs[i].addr;
                                                if (c->length == 128)
@@ -267,7 +269,7 @@ void dhcpv6_write_statefile(void)
 
                                                inet_ntop(AF_INET6, &addr, ipbuf, sizeof(ipbuf) - 1);
 
-                                               if (c->length == 128 && c->hostname && i == 0) {
+                                               if (c->length == 128 && c->hostname) {
                                                        fputs(ipbuf, fp);
 
                                                        char b[256];
@@ -620,7 +622,7 @@ static void update(struct interface *iface)
        if (change) {
                struct dhcpv6_assignment *c;
                list_for_each_entry(c, &iface->ia_assignments, head)
-                       if (c != border)
+                       if (c != border && !iface->managed)
                                apply_lease(iface, c, false);
        }
 
@@ -718,8 +720,14 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
                datalen += sizeof(stat);
        } else {
                if (a) {
-                       uint32_t pref = 3600;
-                       uint32_t valid = 3600;
+                       uint32_t leasetime = iface->dhcpv4_leasetime;
+                       if (leasetime == 0)
+                               leasetime = 3600;
+                       else if (leasetime < 60)
+                               leasetime = 60;
+
+                       uint32_t pref = leasetime;
+                       uint32_t valid = leasetime;
 
                        struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->ia_addr;
                        size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len;
@@ -933,6 +941,8 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
        char hostname[256];
        size_t hostname_len = 0;
        bool class_oro = false;
+       bool notonlink = false;
+
        dhcpv6_for_each_option(start, end, otype, olen, odata) {
                if (otype == DHCPV6_OPT_CLIENTID) {
                        clid_data = odata;
@@ -966,7 +976,6 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
                goto out;
 
        update(iface);
-       bool update_state = false;
 
        struct dhcpv6_assignment *first = NULL;
        dhcpv6_for_each_option(start, end, otype, olen, odata) {
@@ -1155,7 +1164,6 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
                                }
                                a->accept_reconf = accept_reconf;
                                apply_lease(iface, a, true);
-                               update_state = true;
                        } else if (!assigned && a && a->managed_size == 0) { // Cleanup failed assignment
                                free_dhcpv6_assignment(a);
                        }
@@ -1174,16 +1182,15 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
                        } else if (hdr->msg_type == DHCPV6_MSG_RELEASE) {
                                a->valid_until = 0;
                                apply_lease(iface, a, false);
-                               update_state = true;
                        } else if (hdr->msg_type == DHCPV6_MSG_DECLINE && a->length == 128) {
                                a->clid_len = 0;
                                a->valid_until = now + 3600; // Block address for 1h
-                               update_state = true;
                        }
                } 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);
+                       notonlink = true;
                }
 
                buf += ia_response_len;
@@ -1191,19 +1198,18 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
                response_len += ia_response_len;
        }
 
-       if ((hdr->msg_type == DHCPV6_MSG_RELEASE  || hdr->msg_type == DHCPV6_MSG_DECLINE) &&
+       if ((hdr->msg_type == DHCPV6_MSG_RELEASE || hdr->msg_type == DHCPV6_MSG_DECLINE || notonlink) &&
                        response_len + 6 < buflen) {
                buf[0] = 0;
                buf[1] = DHCPV6_OPT_STATUS;
                buf[2] = 0;
                buf[3] = 2;
                buf[4] = 0;
-               buf[5] = DHCPV6_STATUS_OK;
+               buf[5] = (notonlink) ? DHCPV6_STATUS_NOTONLINK : DHCPV6_STATUS_OK;
                response_len += 6;
        }
 
-       if (update_state)
-               dhcpv6_write_statefile();
+       dhcpv6_write_statefile();
 
 out:
        return response_len;