From: Alan T. DeKok Date: Mon, 21 Oct 2019 16:42:13 +0000 (-0400) Subject: allow for uncompressed labels, and add unit tests X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9f98783faebe68cb45280e06f9e2607c2afa734d;p=thirdparty%2Ffreeradius-server.git allow for uncompressed labels, and add unit tests --- diff --git a/src/bin/unit_test_attribute.c b/src/bin/unit_test_attribute.c index 1b5358ebf86..f677cc2898c 100644 --- a/src/bin/unit_test_attribute.c +++ b/src/bin/unit_test_attribute.c @@ -1275,7 +1275,7 @@ static size_t command_encode_dns_label(command_result_t *result, UNUSED command_ RETURN_OK_WITH_ERROR(); } - ret = fr_value_box_to_dns_label(&need, dns_label, sizeof(dns_label), where, box); + ret = fr_value_box_to_dns_label(&need, dns_label, sizeof(dns_label), where, true, box); talloc_free(box); if (ret < 0) RETURN_OK_WITH_ERROR(); diff --git a/src/lib/util/value.c b/src/lib/util/value.c index a9b05b5a64c..748ec6b7ad2 100644 --- a/src/lib/util/value.c +++ b/src/lib/util/value.c @@ -1424,15 +1424,15 @@ static bool dns_label_compress(uint8_t const *start, uint8_t const *end, uint8_t * @param[out] buf Buffer where labels are stored * @param[in] buf_len The length of the output buffer * @param[out] where Where to write this label + * @param[in] compression Whether or not to do DNS label compression. * @param[in] value to encode. * @return - * - 0 no bytes were written, see need value to determine if it was because - * the fr_value_box_t was #FR_TYPE_OCTETS/#FR_TYPE_STRING and was - * NULL (which is unfortunately valid) + * - 0 no bytes were written, see need value to determine * - >0 the number of bytes written to "where", NOT "buf + where + outlen" * - <0 on error. */ -ssize_t fr_value_box_to_dns_label(size_t *need, uint8_t *buf, size_t buf_len, uint8_t *where, fr_value_box_t const *value) +ssize_t fr_value_box_to_dns_label(size_t *need, uint8_t *buf, size_t buf_len, uint8_t *where, bool compression, + fr_value_box_t const *value) { uint8_t *label; uint8_t *end = buf + buf_len; @@ -1440,17 +1440,26 @@ ssize_t fr_value_box_to_dns_label(size_t *need, uint8_t *buf, size_t buf_len, ui uint8_t *data; int namelen = 0; - if (!buf || !buf_len || !where || !value) return -1; + if (!buf || !buf_len || !where || !value) { + fr_strerror_printf("Invalid input"); + return -1; + } /* * Don't allow stupidities */ - if (!((where >= buf) && (where < (buf + buf_len)))) return -1; + if (!((where >= buf) && (where < (buf + buf_len)))) { + fr_strerror_printf("Label is outside of buffer"); + return -1; + } /* * We can only encode strings. */ - if (value->type != FR_TYPE_STRING) return -1; + if (value->type != FR_TYPE_STRING) { + fr_strerror_printf("Asked to encode non-string type"); + return -1; + } if (value->vb_length > 255) { fr_strerror_printf("Label is too long"); @@ -1546,7 +1555,7 @@ ssize_t fr_value_box_to_dns_label(size_t *need, uint8_t *buf, size_t buf_len, ui } /* - * Allow [-0-9a-zA-Z] + * Only encode [-0-9a-zA-Z]. Anything else is forbidden. */ if (!((*q == '-') || ((*q >= '0') && (*q <= '9')) || ((*q >= 'A') && (*q <= 'Z')) || ((*q >= 'a') && (*q <= 'z')))) { @@ -1565,7 +1574,7 @@ ssize_t fr_value_box_to_dns_label(size_t *need, uint8_t *buf, size_t buf_len, ui * Only one label, don't compress it. Or, the label is * already compressed. */ - if ((buf == where) || ((data - where) <= 2)) goto done; + if (!compression || (buf == where) || ((data - where) <= 2)) goto done; /* * Do label compression on the resulting string, starting diff --git a/src/lib/util/value.h b/src/lib/util/value.h index fc5d76a6a24..0304ebef6d9 100644 --- a/src/lib/util/value.h +++ b/src/lib/util/value.h @@ -510,7 +510,7 @@ ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted); -ssize_t fr_value_box_to_dns_label(size_t *need, uint8_t *buf, size_t buflen, uint8_t *where, fr_value_box_t const *value); +ssize_t fr_value_box_to_dns_label(size_t *need, uint8_t *buf, size_t buflen, uint8_t *where, bool compression, fr_value_box_t const *value); ssize_t fr_dns_label_length(uint8_t const *buf, size_t buf_len, uint8_t const **p_label); diff --git a/src/protocols/dhcpv6/encode.c b/src/protocols/dhcpv6/encode.c index f34d2b034c2..bebd2f1496d 100644 --- a/src/protocols/dhcpv6/encode.c +++ b/src/protocols/dhcpv6/encode.c @@ -264,10 +264,13 @@ static ssize_t encode_value(uint8_t *out, size_t outlen, */ case FR_TYPE_STRING: /* - * DNS labels get a special encoder. + * DNS labels get a special encoder. Since we're + * only encoding one value, it's always + * uncompressed. */ - if (da->flags.subtype == FLAG_ENCODE_DNS_LABEL) { - slen = fr_value_box_to_dns_label(NULL, p, outlen, p, &vp->data); + if ((da->flags.subtype == FLAG_ENCODE_DNS_LABEL) || + (da->flags.subtype == FLAG_ENCODE_UNCOMPRESSED_DNS_LABEL)) { + slen = fr_value_box_to_dns_label(NULL, p, outlen, p, false, &vp->data); /* * @todo - check for free space, etc. @@ -492,14 +495,16 @@ static inline ssize_t encode_array(uint8_t *out, size_t outlen, * DNS labels have internalized length, so we don't need * length headers. */ - if ((da->type == FR_TYPE_STRING) && (da->flags.subtype == FLAG_ENCODE_DNS_LABEL)) { + if ((da->type == FR_TYPE_STRING) && da->flags.subtype){ + bool compression = (da->flags.subtype == FLAG_ENCODE_DNS_LABEL); + while (p < end) { vp = fr_cursor_current(cursor); /* * @todo - encode length and stuff */ - slen = fr_value_box_to_dns_label(NULL, out, outlen, p, &vp->data); + slen = fr_value_box_to_dns_label(NULL, out, outlen, p, compression, &vp->data); if (slen <= 0) return PAIR_ENCODE_ERROR; p += slen; diff --git a/src/tests/unit/data_types.txt b/src/tests/unit/data_types.txt index bac66df0d70..5fafc55353d 100644 --- a/src/tests/unit/data_types.txt +++ b/src/tests/unit/data_types.txt @@ -93,7 +93,7 @@ match Aug 21 2019 07:43:03 UTC #data foo # -# DNS labels WITHOUT compression +# DNS labels # encode-dns-label foo.com match 03 66 6f 6f 03 63 6f 6d 00 diff --git a/src/tests/unit/dhcpv6.txt b/src/tests/unit/dhcpv6.txt index e4d2af7037b..7532f0f6b03 100644 --- a/src/tests/unit/dhcpv6.txt +++ b/src/tests/unit/dhcpv6.txt @@ -182,5 +182,20 @@ match 00 15 00 15 03 66 6f 6f 02 63 61 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 encode-pair SIP-Server-Domain-Name-List = "www.example.com", SIP-Server-Domain-Name-List = "ftp.example.com" match 00 15 00 17 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 03 66 74 70 c0 04 +encode-pair SIP-Server-Domain-Name-List = "www.example.com", SIP-Server-Domain-Name-List = "ftp.example.com", SIP-Server-Domain-Name-List = "ns.example.com" +match 00 15 00 1c 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 03 66 74 70 c0 04 02 6e 73 c0 04 + +# +# This attribute is NOT compressed! +# +encode-pair BCMCS-Server-Domain-Name-List = "www.example.com" +match 00 21 00 11 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 + +encode-pair BCMCS-Server-Domain-Name-List = "www.example.com", BCMCS-Server-Domain-Name-List = "ftp.example.com" +match 00 21 00 22 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 03 66 74 70 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 + +encode-pair BCMCS-Server-Domain-Name-List = "www.example.com", BCMCS-Server-Domain-Name-List = "ftp.example.com", BCMCS-Server-Domain-Name-List = "ns.example.com" +match 00 21 00 32 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 03 66 74 70 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 02 6e 73 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 + count -match 82 +match 90