]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
fix DHCPv6 date encode / decode
authorAlan T. DeKok <aland@freeradius.org>
Thu, 21 Nov 2019 19:26:09 +0000 (14:26 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 21 Nov 2019 20:49:08 +0000 (15:49 -0500)
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.

src/protocols/dhcpv6/decode.c
src/protocols/dhcpv6/dhcpv6.h
src/protocols/dhcpv6/encode.c
src/tests/unit/protocols/dhcpv6/dates.txt

index c6b5230d786cabe95d7bd7b52468ba96d8b47dd0..9adbd72531ed6a691a8ff3d5ccd219ed7772894b 100644 (file)
@@ -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);
index a07fba08d8077b26aaf443faa0c6545bc8c49d9c..f9195ac315c2a3fa073db47e3beafa8a000c9b2c 100644 (file)
@@ -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;
index 4e45120ca0fd5bfc6c0e5dce0f57d05061cb3d1f..b21c5aabcb761e4874e192243d2246189d4cf8f4 100644 (file)
@@ -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);
        }
index 2693984fc184c7a380014f9a67d0ab6854448d18..4a6ebf756aa6e2e175b0c4dd80b7fb2ef437b972 100644 (file)
@@ -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