From: Alan T. DeKok Date: Thu, 21 Nov 2019 19:26:09 +0000 (-0500) Subject: fix DHCPv6 date encode / decode X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=889b344b7bf99b7c2ff5bb06d13d79641c10fd2c;p=thirdparty%2Ffreeradius-server.git fix DHCPv6 date encode / decode decode didn't add the date offset from Jan 1 1970 --> Jan 1, 2000. encode added 30*365*86400, which doesn't account for the fact that years are ~365.25 days long. --- diff --git a/src/protocols/dhcpv6/decode.c b/src/protocols/dhcpv6/decode.c index c6b5230d786..9adbd72531e 100644 --- a/src/protocols/dhcpv6/decode.c +++ b/src/protocols/dhcpv6/decode.c @@ -174,7 +174,6 @@ static ssize_t decode_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t cons case FR_TYPE_UINT32: case FR_TYPE_UINT64: case FR_TYPE_SIZE: - case FR_TYPE_DATE: case FR_TYPE_IFID: case FR_TYPE_ETHERNET: case FR_TYPE_IPV4_ADDR: @@ -196,6 +195,24 @@ static ssize_t decode_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t cons } break; + /* + * A standard 32bit integer, but unlike normal UNIX timestamps + * starts from the 1st of January 2000. + * + * In the encoder we subtract 30 years to any values, so + * here we need to add that to the time here. + */ + case FR_TYPE_DATE: + vp = fr_pair_afrom_da(ctx, parent); + if (!vp) return -1; + + if (fr_value_box_from_network(vp, &vp->data, vp->da->type, vp->da, data, data_len, true) < 0) { + fr_pair_list_free(&vp); + goto raw; + } + vp->vp_date += ((fr_time_t) DHCPV6_DATE_OFFSET) * NSEC; + break; + case FR_TYPE_STRUCT: rcode = fr_struct_from_network(ctx, cursor, parent, data, data_len, &tlv, decode_value_trampoline, decoder_ctx); diff --git a/src/protocols/dhcpv6/dhcpv6.h b/src/protocols/dhcpv6/dhcpv6.h index a07fba08d80..f9195ac315c 100644 --- a/src/protocols/dhcpv6/dhcpv6.h +++ b/src/protocols/dhcpv6/dhcpv6.h @@ -45,6 +45,13 @@ enum { FLAG_ENCODE_PARTIAL_DNS_LABEL, //!< encode as a partial DNS label }; +/* + * DHCPv6 defines dates to start from Jan 1, 2000. Which is + * exactly this number of seconds off of the standard Unix time + * stamps. + */ +#define DHCPV6_DATE_OFFSET (946684800) + typedef struct { fr_dict_attr_t const *root; //!< Root attribute of the dictionary. } fr_dhcpv6_encode_ctx_t; diff --git a/src/protocols/dhcpv6/encode.c b/src/protocols/dhcpv6/encode.c index 4e45120ca0f..b21c5aabcb7 100644 --- a/src/protocols/dhcpv6/encode.c +++ b/src/protocols/dhcpv6/encode.c @@ -401,25 +401,24 @@ static ssize_t encode_value(uint8_t *out, size_t outlen, * A standard 32bit integer, but unlike normal UNIX timestamps * starts from the 1st of January 2000. * - * In the decoder we add 946,080,000 seconds (30 years) to any - * values, so here we need to subtract 946,080,000 seconds, or - * if the value is less than 946,080,000 seconds, just encode - * a 0x0000000000 value. + * In the decoder we add 30 years to any values, so here + * we need to subtract that time, or if the value is less + * than that time, just encode a 0x0000000000 + * value. */ case FR_TYPE_DATE: { uint32_t adj_date; - fr_time_t date = fr_time_to_sec(vp->vp_date); + uint64_t date = fr_time_to_sec(vp->vp_date); CHECK_FREESPACE(outlen, fr_dhcpv6_option_len(vp)); - - if (date < 946080000) { /* 30 years */ + if (date < DHCPV6_DATE_OFFSET) { /* 30 years */ memset(p, 0, sizeof(uint32_t)); p += sizeof(uint32_t); break; } - adj_date = htonl(date - 946080000); + adj_date = htonl(date - DHCPV6_DATE_OFFSET); memcpy(p, &adj_date, sizeof(adj_date)); p += sizeof(adj_date); } diff --git a/src/tests/unit/protocols/dhcpv6/dates.txt b/src/tests/unit/protocols/dhcpv6/dates.txt index 2693984fc18..4a6ebf756aa 100644 --- a/src/tests/unit/protocols/dhcpv6/dates.txt +++ b/src/tests/unit/protocols/dhcpv6/dates.txt @@ -9,33 +9,39 @@ proto dhcpv6 proto-dictionary dhcpv6 # -# Date. Like a 32bit unix timestamp but starts from 1st Jan 2000 instead of 1st Jan 1970 +# Date. Like a 32bit unix timestamp but starts from 1st Jan 2000 instead of 1st Jan 2000 # encode-pair Failover-Expiration-Time = 0 match 00 78 00 04 00 00 00 00 decode-pair - -match Failover-Expiration-Time = "Jan 1 1970 00:00:00 UTC" +match Failover-Expiration-Time = "Jan 1 2000 00:00:00 UTC" + +# +# Anything before Jan 1, 2000 gets mashed to "0". +# +encode-pair Failover-Expiration-Time = "Jan 1 1999 00:00:00 UTC" +match 00 78 00 04 00 00 00 00 # Still less than 946080000 (30 years), so still 0 (we can't represent dates earlier than 1st Jan 2000) encode-pair Failover-Expiration-Time = 500 match 00 78 00 04 00 00 00 00 decode-pair - -match Failover-Expiration-Time = "Jan 1 1970 00:00:00 UTC" +match Failover-Expiration-Time = "Jan 1 2000 00:00:00 UTC" -encode-pair Failover-Expiration-Time = 946080000 +encode-pair Failover-Expiration-Time = 946684800 match 00 78 00 04 00 00 00 00 decode-pair - -match Failover-Expiration-Time = "Jan 1 1970 00:00:00 UTC" +match Failover-Expiration-Time = "Jan 1 2000 00:00:00 UTC" # 1st second of 1st Jan 2000 -encode-pair Failover-Expiration-Time = 946080001 +encode-pair Failover-Expiration-Time = 946684801 match 00 78 00 04 00 00 00 01 decode-pair - -match Failover-Expiration-Time = "Jan 1 1970 00:00:01 UTC" +match Failover-Expiration-Time = "Jan 1 2000 00:00:01 UTC" count -match 18 +match 20