summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2016-11-17 16:11:56 +0100
committerJohn Crispin <john@phrozen.org>2016-11-21 11:35:30 +0100
commit6c3bc0141dacc88992583d6f2cdc8a360df7422d (patch)
tree4cf9e6f28c5e398106aa3f6d88155b71cef5e0cf
parent801cfeea100ca7b211c9841f0fcb757b17f47860 (diff)
config: Support infinite as DHCP pool leasetime value
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>
-rw-r--r--src/config.c7
-rw-r--r--src/dhcpv4.c30
-rw-r--r--src/dhcpv6-ia.c20
-rw-r--r--src/odhcpd.h2
4 files changed, 33 insertions, 26 deletions
diff --git a/src/config.c b/src/config.c
index ef51112..44b049d 100644
--- a/src/config.c
+++ b/src/config.c
@@ -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')
diff --git a/src/dhcpv4.c b/src/dhcpv4.c
index f277a67..8469038 100644
--- a/src/dhcpv4.c
+++ b/src/dhcpv4.c
@@ -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
}
diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c
index 4c321ac..597bc74 100644
--- a/src/dhcpv6-ia.c
+++ b/src/dhcpv6-ia.c
@@ -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;
diff --git a/src/odhcpd.h b/src/odhcpd.h
index 3e8fc3e..e322ebd 100644
--- a/src/odhcpd.h
+++ b/src/odhcpd.h
@@ -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))