]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add DNS label decoding to structs, and update the tests
authorAlan T. DeKok <aland@freeradius.org>
Mon, 18 Nov 2019 23:44:12 +0000 (18:44 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 18 Nov 2019 23:55:11 +0000 (18:55 -0500)
src/lib/util/struct.c
src/lib/util/struct.h
src/protocols/dhcpv6/decode.c
src/protocols/radius/decode.c
src/tests/unit/protocols/dhcpv6/rfc4704.txt

index 988fb34331edcdc6094104684fd3a92199bd7b24..07a603a2b2e13c2bf46d907d450f92187c6854ff 100644 (file)
@@ -62,7 +62,8 @@ VALUE_PAIR *fr_unknown_from_network(TALLOC_CTX *ctx, fr_dict_attr_t const *paren
  */
 ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor,
                               fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len,
-                              fr_dict_attr_t const **child_p)
+                              fr_dict_attr_t const **child_p,
+                              fr_decode_value_t decode_value, void *decoder_ctx)
 {
        unsigned int            child_num;
        uint8_t const           *p = data, *end = data + data_len;
@@ -185,6 +186,23 @@ ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor,
 
                if (!child_length) child_length = (end - p);
 
+               /*
+                *      Magic values get the callback called.
+                *
+                *      Note that if this is an *array* of DNS labels,
+                *      the callback should deal with this.
+                */
+               if (decode_value && !child->flags.extra && child->flags.subtype) {
+                       ssize_t slen;
+
+                       slen = decode_value(ctx, &child_cursor, NULL, child, p, child_length, decoder_ctx);
+                       if (slen < 0) return slen - (p - data);
+
+                       p += slen;      /* not always the same as child->flags.length */
+                       child_num++;    /* go to the next child */
+                       continue;
+               }
+
                /*
                 *      We only allow a limited number of data types
                 *      inside of a struct.
@@ -281,7 +299,8 @@ ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor,
                }
 
                if (child->type == FR_TYPE_STRUCT) {
-                       slen = fr_struct_from_network(ctx, &child_cursor, child, p, end - p, child_p);
+                       slen = fr_struct_from_network(ctx, &child_cursor, child, p, end - p, child_p,
+                               decode_value, decoder_ctx);
                        if (slen < 0) goto unknown_child;
                        p += slen;
 
index 1c4b016b75c70c2d4482498c9ba56f79fc65b252..99e57e15ad279de318d52ce247f2b7da5a708b88 100644 (file)
@@ -31,9 +31,14 @@ RCSIDH(struct_h, "$Id$")
 extern "C" {
 #endif
 
+typedef ssize_t (*fr_decode_value_t)(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
+                                    fr_dict_attr_t const *parent,
+                                    uint8_t const *data, size_t const data_len, void *decoder_ctx);
+
 ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor,
                               fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len,
-                              fr_dict_attr_t const **child) CC_HINT(nonnull(2,3,4));
+                              fr_dict_attr_t const **child,
+                              fr_decode_value_t decode_value, void *decoder_ctx) CC_HINT(nonnull(2,3,4));
 
 typedef ssize_t (*fr_encode_value_t)(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth,
                                     fr_cursor_t *cursor, void *encoder_ctx);
index 79cfcfdd14eb507676b5e76098011285f39d0846..d5bb07ab35b4f6a4ef6166be042c3b9a95d413f5 100644 (file)
@@ -39,8 +39,8 @@
 #include "attrs.h"
 
 static ssize_t decode_option(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
-                             fr_dict_attr_t const *parent,
-                             uint8_t const *data, size_t const data_len, void *decoder_ctx);
+                            fr_dict_attr_t const *parent,
+                            uint8_t const *data, size_t const data_len, void *decoder_ctx);
 
 static ssize_t decode_raw(TALLOC_CTX *ctx, fr_cursor_t *cursor, UNUSED fr_dict_t const *dict,
                          fr_dict_attr_t const *parent,
@@ -83,6 +83,35 @@ static ssize_t decode_raw(TALLOC_CTX *ctx, fr_cursor_t *cursor, UNUSED fr_dict_t
        return data_len;
 }
 
+static ssize_t decode_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
+                           fr_dict_attr_t const *parent,
+                           uint8_t const *data, size_t const data_len, void *decoder_ctx);
+static ssize_t decode_array(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
+                           fr_dict_attr_t const *parent,
+                           uint8_t const *data, size_t const data_len, void *decoder_ctx);
+static ssize_t decode_dns_labels(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
+                                fr_dict_attr_t const *parent,
+                                uint8_t const *data, size_t const data_len, void *decoder_ctx);
+
+/** Handle arrays of DNS lavels for fr_struct_from_network()
+ *
+ */
+static ssize_t decode_value_trampoline(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
+                                      fr_dict_attr_t const *parent,
+                                      uint8_t const *data, size_t const data_len, void *decoder_ctx)
+{
+       if (parent->flags.array) return decode_array(ctx, cursor, dict, parent, data, data_len, decoder_ctx);
+
+       /*
+        *      @todo - we might need to limit this to only one DNS label.
+        */
+       if (!parent->flags.extra && (parent->type == FR_TYPE_STRING) && parent->flags.subtype) {
+               return decode_dns_labels(ctx, cursor, dict, parent, data, data_len, decoder_ctx);
+       }
+
+       return decode_value(ctx, cursor, dict, parent, data, data_len, decoder_ctx);
+}
+
 
 static ssize_t decode_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
                            fr_dict_attr_t const *parent,
@@ -168,7 +197,8 @@ static ssize_t decode_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t cons
                break;
 
        case FR_TYPE_STRUCT:
-               rcode = fr_struct_from_network(ctx, cursor, parent, data, data_len, &tlv);
+               rcode = fr_struct_from_network(ctx, cursor, parent, data, data_len, &tlv,
+                                              decode_value_trampoline, decoder_ctx);
                if (rcode < 0) return rcode;
 
                if (tlv) {
@@ -312,7 +342,7 @@ static ssize_t decode_dns_labels(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t
                 *      bug in the code.
                 */
                rcode = fr_dns_label_to_value_box(vp, &vp->data, data, data_len, data + total, true);
-               if (rcode < 0) {
+               if (rcode <= 0) {
                        fr_pair_list_free(&vp);
                        goto raw;
                }
index eb9aeffc2e4bb9665281c454b310d3b178ded1b1..d4c426efd4a2038c53401e3d8e26dbccc4dd4614 100644 (file)
@@ -974,6 +974,21 @@ create_attrs:
        return total;
 }
 
+/** Wrapper called by fr_struct_from_network()
+ *
+ *  Because extended attributes can continue across the current value.
+ *  So that function needs to know both the value length, *and* the
+ *  packet length.  But when we're decoding values inside of a struct,
+ *  we're not using extended attributes.
+ */
+static ssize_t decode_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_t const *dict,
+                           fr_dict_attr_t const *parent,
+                           uint8_t const *data, size_t data_len, void *decoder_ctx)
+{
+       return fr_radius_decode_pair_value(ctx, cursor, dict, parent, data, data_len, data_len, decoder_ctx);
+}
+
+
 /** Create any kind of VP from the attribute contents
  *
  * "length" is AT LEAST the length of this attribute, as we
@@ -1351,7 +1366,8 @@ ssize_t fr_radius_decode_pair_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dic
                 *      attribute, OR it's already been grouped
                 *      into a contiguous memory buffer.
                 */
-               rcode = fr_struct_from_network(ctx, cursor, parent, p, attr_len, &child);
+               rcode = fr_struct_from_network(ctx, cursor, parent, p, attr_len, &child,
+                                              decode_value, decoder_ctx);
                if (rcode < 0) goto raw;
 
                /*
index 464e2621d3b26ad3aa1753e13a41ac8f370fbf5b..72ab6496a4a65fe5d1c6e91f73dfe451fa7a3039 100644 (file)
@@ -45,7 +45,7 @@ match 00 27 00 0b 01 09 74 61 70 69 6f 63 61 30 31
 # fields like 'string encode=dns_label'. e.g: Client-FQDN-Domain-Name
 #
 decode-pair -
-no match Client-FQDN-Flags = Server-Update, Client-FQDN-Domain-Name = "tapioca01"
+match Client-FQDN-Flags = Server-Update, Client-FQDN-Domain-Name = "tapioca01"
 
 count
 match 6