[PATCH] odhcpd: add option to use absolute timestamps
Nick Hainke
vincent at systemli.org
Sat Jan 30 11:32:40 EST 2021
Until now it is not possible to give absolute timestamps in odhcpd.
This means that on every new RA or request, the timestamp is renewed.
Further, the valid and preferred lifetimes are not synced between all
devices.
There are several usecases when it is needed to have absolute timestamp
that needed to be synced across all devices, e.g. your ISP delegates
you a prefix for some certain time, or you want to change to another
prefix.
The purpose of having this as a absolute timestamp is to make it easier
to track. An example configuration is
option absolute_lifetime '1'
option valid_lifetime '05 Jan 2021 23:00:00'
option preferred_lifetime '05 Jan 2021 23:00:00'
If the valid_lifetime is in the past, the preferred lifetime and valid
lifetime are set to 1 minute.
Signed-off-by: Nick Hainke <vincent at systemli.org>
---
README | 8 ++++--
src/config.c | 69 ++++++++++++++++++++++++++++++++++---------------
src/dhcpv6-ia.c | 10 +++++++
src/odhcpd.h | 1 +
4 files changed, 65 insertions(+), 23 deletions(-)
diff --git a/README b/README
index f9cbb11..0af5c75 100644
--- a/README
+++ b/README
@@ -107,11 +107,13 @@ dns_service bool 1 Announce the address of interface as DNS service
if the list of dns is empty
domain list <local search domain> Search domains to announce
-leasetime string 12h DHCPv4 address leasetime
+leasetime string 12h DHCPv4 address leasetime. If absolute_lifetime is
+ set the value can be given as a date, e.g. "10 Jan 2020 00:00:00".
start integer 100 DHCPv4 pool start
limit integer 150 DHCPv4 pool size
preferred_lifetime string 12h Value for the preferred lifetime
- for a prefix
+ for a prefix. If absolute_lifetime is set the value can
+ be given as a date, e.g. "10 Jan 2020 00:00:00".
ra_default integer 0 Override default route
0: default, 1: ignore no public address, 2: ignore all
ra_flags list other-config List of RA flags to be
@@ -145,6 +147,8 @@ ndproxy_slave bool 0 NDProxy external slave
prefix_filter string ::/0 Only advertise on-link prefixes within
[IPv6 prefix] the provided IPv6 prefix; others are
filtered out.
+absolute_lifetime bool 0 Interpret configured lifetime as
+ absolute timestamps. The format has to be "10 Jan 2020 00:00:00".
Sections of type host (static leases)
diff --git a/src/config.c b/src/config.c
index 78b5855..42f73a1 100644
--- a/src/config.c
+++ b/src/config.c
@@ -8,6 +8,7 @@
#include <string.h>
#include <sys/stat.h>
#include <syslog.h>
+#include <time.h>
#include <uci.h>
#include <uci_blob.h>
@@ -83,6 +84,7 @@ enum {
IFACE_ATTR_NDPROXY_SLAVE,
IFACE_ATTR_PREFIX_FILTER,
IFACE_ATTR_PREFERRED_LIFETIME,
+ IFACE_ATTR_ABSOLUTE_LIFETIME,
IFACE_ATTR_MAX
};
@@ -132,6 +134,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
[IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_PREFIX_FILTER] = { .name = "prefix_filter", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_PREFERRED_LIFETIME] = { .name = "preferred_lifetime", .type = BLOBMSG_TYPE_STRING },
+ [IFACE_ATTR_ABSOLUTE_LIFETIME] = { .name = "absolute_lifetime", .type = BLOBMSG_TYPE_BOOL },
};
static const struct uci_blob_param_info iface_attr_info[IFACE_ATTR_MAX] = {
@@ -212,6 +215,7 @@ static void set_interface_defaults(struct interface *iface)
iface->ra_mininterval = iface->ra_maxinterval/3;
iface->ra_lifetime = -1;
iface->ra_dns = true;
+ iface->absolute_lifetime = false;
}
static void clean_interface(struct interface *iface)
@@ -321,29 +325,48 @@ static void set_config(struct uci_section *s)
}
}
-static double parse_leasetime(struct blob_attr *c) {
+static double parse_leasetime(struct blob_attr *c, bool absolute) {
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')
- time *= 60;
- else if (endptr[0] == 'h')
- time *= 3600;
- else if (endptr[0] == 'd')
- time *= 24 * 3600;
- else if (endptr[0] == 'w')
- time *= 7 * 24 * 3600;
- else
+ double ret_time = strcmp(val, "infinite") ? strtod(val, &endptr) : UINT32_MAX;
+
+ if (absolute)
+ {
+ // "10 Jan 2020 00:00:00"
+ // Parse absolut time
+ struct tm tm = {0};
+ char *s = strptime(val, "%d %b %Y %H:%M:%S", &tm);
+ if (s == NULL) {
+ syslog(LOG_ERR, "Failed to Parse Date: %s", val);
goto err;
+ }
+
+ time_t now = odhcpd_time();
+ time_t wall_time = time(NULL);
+ time_t t = mktime(&tm);
+
+ double diff = difftime(t,wall_time);
+ ret_time += now + diff;
+ } else {
+ if (ret_time && endptr && endptr[0]) {
+ if (endptr[0] == 's')
+ ret_time *= 1;
+ else if (endptr[0] == 'm')
+ ret_time *= 60;
+ else if (endptr[0] == 'h')
+ ret_time *= 3600;
+ else if (endptr[0] == 'd')
+ ret_time *= 24 * 3600;
+ else if (endptr[0] == 'w')
+ ret_time *= 7 * 24 * 3600;
+ else
+ goto err;
+ }
}
- if (time < 60)
- time = 60;
+ if (ret_time < 60)
+ ret_time = 60;
- return time;
+ return ret_time;
err:
return -1;
@@ -409,7 +432,7 @@ int set_lease_from_blobmsg(struct blob_attr *ba)
}
if ((c = tb[LEASE_ATTR_LEASETIME])) {
- double time = parse_leasetime(c);
+ double time = parse_leasetime(c, false); // do not support absolute timestamps for now
if (time < 0)
goto err;
@@ -520,8 +543,12 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
if ((c = tb[IFACE_ATTR_DYNAMICDHCP]))
iface->no_dynamic_dhcp = !blobmsg_get_bool(c);
+
+ if ((c = tb[IFACE_ATTR_ABSOLUTE_LIFETIME]))
+ iface->absolute_lifetime = blobmsg_get_bool(c);
+
if ((c = tb[IFACE_ATTR_LEASETIME])) {
- double time = parse_leasetime(c);
+ double time = parse_leasetime(c, iface->absolute_lifetime);
if (time < 0)
goto err;
@@ -529,7 +556,7 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
}
if ((c = tb[IFACE_ATTR_PREFERRED_LIFETIME])) {
- double time = parse_leasetime(c);
+ double time = parse_leasetime(c, iface->absolute_lifetime);
if (time < 0)
goto err;
diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c
index a59fc20..78be8b8 100644
--- a/src/dhcpv6-ia.c
+++ b/src/dhcpv6-ia.c
@@ -865,6 +865,16 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status,
if (prefix_valid > leasetime)
prefix_valid = leasetime;
+ if (iface->absolute_lifetime) {
+ if ((long int) iface->dhcp_leasetime > now) {
+ prefix_valid = iface->dhcp_leasetime - now;
+ prefix_pref = iface->preferred_lifetime - now;
+ } else { // if we have a timestamp in the past set pref and valid to 60s
+ prefix_valid = 60;
+ prefix_pref = 60;
+ }
+ }
+
if (a->flags & OAF_DHCPV6_PD) {
struct dhcpv6_ia_prefix o_ia_p = {
.type = htons(DHCPV6_OPT_IA_PREFIX),
diff --git a/src/odhcpd.h b/src/odhcpd.h
index 45b6784..98673a8 100644
--- a/src/odhcpd.h
+++ b/src/odhcpd.h
@@ -288,6 +288,7 @@ struct interface {
uint32_t ra_hoplimit;
int ra_mtu;
uint32_t preferred_lifetime;
+ bool absolute_lifetime;
// DHCP
uint32_t dhcp_leasetime;
--
2.30.0
More information about the openwrt-devel
mailing list