config: Support infinite as DHCP pool leasetime value
authorHans Dedecker <dedeckeh@gmail.com>
Thu, 17 Nov 2016 15:11:56 +0000 (16:11 +0100)
committerJohn Crispin <john@phrozen.org>
Mon, 21 Nov 2016 10:35:30 +0000 (11:35 +0100)
Add support for infinite leasetime value; this can be done by
specifying "infinite" as leasetime value which is similar to
dnsmasq infinite leasetime support.
Specifying "infinite" as leasetime is valid for both the host
and dhcp uci sections.
A DHCPv4/DHCPv6 assignment is now considered infinite if valid_unil
holds the value 0.

Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
src/config.c
src/dhcpv4.c
src/dhcpv6-ia.c
src/odhcpd.h

index ef511129f64c3a9e290d6084830c5ec70332edd5..44b049d409e313de90842b6b87bf8accab8a5864 100644 (file)
@@ -218,9 +218,10 @@ static void set_config(struct uci_section *s)
 }
 
 static double parse_leasetime(struct blob_attr *c) {
-       char *val = blobmsg_get_string(c), *endptr;
-       double time = strtod(val, &endptr);
-       if (time && endptr[0]) {
+       char *val = blobmsg_get_string(c), *endptr = NULL;
+       double time = strcmp(val, "infinite") ? strtod(val, &endptr) : UINT32_MAX;
+
+       if (time && endptr && endptr[0]) {
                if (endptr[0] == 's')
                        time *= 1;
                else if (endptr[0] == 'm')
index f277a67a23f8a49e4da48bc6b88fb170155fc2d7..84690384db0fef14975d91f91b71fff12f72c908 100644 (file)
@@ -181,7 +181,8 @@ int setup_dhcpv4_interface(struct interface *iface, bool enable)
                        a->addr = ntohl(lease->ipaddr.s_addr);
                        memcpy(a->hwaddr, lease->mac.ether_addr_octet, sizeof(a->hwaddr));
                        memcpy(a->hostname, lease->hostname, hostlen);
-                       a->valid_until = LONG_MAX;
+                       /* Infinite valid */
+                       a->valid_until = 0;
 
                        // Assign to all interfaces
                        struct dhcpv4_assignment *c;
@@ -246,8 +247,7 @@ static void dhcpv4_put(struct dhcpv4_message *msg, uint8_t **cookie,
        *cookie = c + len;
 }
 
-
-// Simple DHCPv6-server for information requests
+// Handler for DHCPv4 messages
 static void handle_dhcpv4(void *addr, void *data, size_t len,
                struct interface *iface, _unused void *dest_addr)
 {
@@ -396,11 +396,13 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
                val = htonl(leasetime);
                dhcpv4_put(&reply, &cookie, DHCPV4_OPT_LEASETIME, 4, &val);
 
-               val = htonl(500 * leasetime / 1000);
-               dhcpv4_put(&reply, &cookie, DHCPV4_OPT_RENEW, 4, &val);
+               if (leasetime != UINT32_MAX) {
+                       val = htonl(500 * leasetime / 1000);
+                       dhcpv4_put(&reply, &cookie, DHCPV4_OPT_RENEW, 4, &val);
 
-               val = htonl(875 * leasetime / 1000);
-               dhcpv4_put(&reply, &cookie, DHCPV4_OPT_REBIND, 4, &val);
+                       val = htonl(875 * leasetime / 1000);
+                       dhcpv4_put(&reply, &cookie, DHCPV4_OPT_REBIND, 4, &val);
+               }
 
                dhcpv4_put(&reply, &cookie, DHCPV4_OPT_NETMASK, 4, &ifnetmask.sin_addr);
 
@@ -598,7 +600,7 @@ static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
                        a = c;
                        if (c->addr == raddr)
                                break;
-               } else if (c->valid_until < now) {
+               } else if (!INFINITE_VALID(c->valid_until) && c->valid_until < now) {
                        list_del(&c->head);
                        free(c);
                }
@@ -640,10 +642,10 @@ static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
                        leasetime = iface->dhcpv4_leasetime;
                }
 
-               // Was only a solicitation: mark binding for removal
+               // Was only a discover; mark binding for removal
                if (assigned && a->valid_until < now) {
-                       a->valid_until = (msg == DHCPV4_MSG_DISCOVER) ? 0 :
-                                       (now + leasetime);
+                       a->valid_until = ((msg == DHCPV4_MSG_DISCOVER) ? now : ((leasetime == UINT32_MAX) ?
+                                               0 : (time_t)(now + leasetime)));
                } else if (!assigned && a) { // Cleanup failed assignment
                        free(a);
                        a = NULL;
@@ -652,9 +654,9 @@ static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
                if (assigned && a)
                        lease = a;
        } else if (msg == DHCPV4_MSG_RELEASE) {
-               if (a && a->valid_until != LONG_MAX)
-                       a->valid_until = 0;
-       } else if (msg == DHCPV4_MSG_DECLINE && a && a->valid_until != LONG_MAX) {
+               if (a && !INFINITE_VALID(a->valid_until))
+                       a->valid_until = now - 1;
+       } else if (msg == DHCPV4_MSG_DECLINE && a && !INFINITE_VALID(a->valid_until)) {
                memset(a->hwaddr, 0, sizeof(a->hwaddr));
                a->valid_until = now + 3600; // Block address for 1h
        }
index 4c321ac0da44a7a78561426f0d1404a92a72dbdd..597bc74981e6f2d2293ff4b1918c933dac5a4870 100644 (file)
@@ -262,7 +262,7 @@ void dhcpv6_write_statefile(void)
                                                        m = i;
 
                                        for (size_t i = 0; i < addrlen; ++i) {
-                                               if (addrs[i].prefix > 96 || c->valid_until <= now ||
+                                               if (addrs[i].prefix > 96 || (!INFINITE_VALID(c->valid_until) && c->valid_until <= now) ||
                                                                (iface->managed < RELAYD_MANAGED_NO_AFLAG && i != m &&
                                                                                addrs[i].prefix == 64))
                                                        continue;
@@ -592,7 +592,8 @@ void dhcpv6_ia_postupdate(struct interface *iface, time_t now)
        struct list_head reassign = LIST_HEAD_INIT(reassign);
        struct dhcpv6_assignment *c, *d;
        list_for_each_entry_safe(c, d, &iface->ia_assignments, head) {
-               if (c->clid_len == 0 || c->valid_until < now || c->managed_size)
+               if (c->clid_len == 0 || (!INFINITE_VALID(c->valid_until) && c->valid_until < now) ||
+                               c->managed_size)
                        continue;
 
                if (c->length < 128 && c->assigned >= border->assigned && c != border)
@@ -637,7 +638,7 @@ static void reconf_timer(struct uloop_timeout *event)
 
                struct dhcpv6_assignment *a, *n;
                list_for_each_entry_safe(a, n, &iface->ia_assignments, head) {
-                       if (a->valid_until < now) {
+                       if (!INFINITE_VALID(a->valid_until) && a->valid_until < now) {
                                if ((a->length < 128 && a->clid_len > 0) ||
                                                (a->length == 128 && a->clid_len == 0)) {
                                        list_del(&a->head);
@@ -768,9 +769,10 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
                                }
                        }
 
-                       a->valid_until = valid + now;
-                       out.t1 = htonl(pref * 5 / 10);
-                       out.t2 = htonl(pref * 8 / 10);
+                       /* UINT32_MAX is considered as infinite leasetime */
+                       a->valid_until = (valid == UINT32_MAX) ? 0 : valid + now;
+                       out.t1 = htonl((pref == UINT32_MAX) ? pref : pref * 5 / 10);
+                       out.t2 = htonl((pref == UINT32_MAX) ? pref : pref * 8 / 10);
 
                        if (!out.t1)
                                out.t1 = htonl(1);
@@ -1031,7 +1033,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
                        if (((c->clid_len == clid_len && !memcmp(c->clid_data, clid_data, clid_len)) ||
                                        (c->clid_len >= clid_len && !c->clid_data[0] && !c->clid_data[1]
                                                && !memcmp(c->mac, mac, sizeof(mac)))) &&
-                                       (c->iaid == ia->iaid || c->valid_until < now) &&
+                                       (c->iaid == ia->iaid || (!INFINITE_VALID(c->valid_until) && c->valid_until < now)) &&
                                        ((is_pd && c->length <= 64) || (is_na && c->length == 128))) {
                                a = c;
 
@@ -1114,7 +1116,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
 
                        // Was only a solicitation: mark binding for removal
                        if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT) {
-                               a->valid_until = 0;
+                               a->valid_until = now;
                        } else if (assigned && hdr->msg_type == DHCPV6_MSG_REQUEST) {
                                if (hostname_len > 0) {
                                        a->hostname = realloc(a->hostname, hostname_len + 1);
@@ -1141,7 +1143,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
                                if (a)
                                        apply_lease(iface, a, true);
                        } else if (hdr->msg_type == DHCPV6_MSG_RELEASE) {
-                               a->valid_until = 0;
+                               a->valid_until = now - 1;
                                apply_lease(iface, a, false);
                        } else if (hdr->msg_type == DHCPV6_MSG_DECLINE && a->length == 128) {
                                a->clid_len = 0;
index 3e8fc3ea6032c1ddab5047aaf88c4d60626f4ddc..e322ebd5b48b82da40a7fd609a798e687c484b0c 100644 (file)
@@ -44,6 +44,8 @@
 #define RELAYD_BUFFER_SIZE 8192
 #define RELAYD_MAX_PREFIXES 8
 
+#define INFINITE_VALID(x) ((x) == 0)
+
 #define _unused __attribute__((unused))
 #define _packed __attribute__((packed))