[PATCH] odhcpd: add option to use absolute timestamps
Hans Dedecker
dedeckeh at gmail.com
Sat Feb 6 15:26:58 EST 2021
On Sat, Jan 30, 2021 at 5:33 PM Nick Hainke <vincent at systemli.org> wrote:
>
> 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.
I have my reservations about the patch as it requires knowledge of
absolute time on devices.
This is a problem as not all devices have a RTC; or the time needs to
be synchronized with a wan NTP server.
This is also the reason why netifd does not to support absolute
lifetimes for configured prefixes
Hans
>
> 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
>
>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel at lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list