]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
start of encoding Relay-Message
authorAlan T. DeKok <aland@freeradius.org>
Sun, 4 Oct 2020 14:54:38 +0000 (10:54 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Sun, 4 Oct 2020 14:54:38 +0000 (10:54 -0400)
The tests for encoding relay packets don't yet work, for a few
reasons.

* fr_value_box_from_str() is passed dst_enumv, and it then
  checks if the value is a valid _attribute_ name?  Which
  doesn't work for IPv6 addresses, as they contain ":"
* the fr_pair_list_afrom_substr() function doesn't treat
  "Attr-" as special, so it tries to look it up in the various
  dictionaries, and fails.
* the fr_dhcpv6_encode() function is failing for nested packets,
  and doesn't return a useful error message

src/modules/proto_dhcpv6/proto_dhcpv6.c
src/protocols/dhcpv6/base.c
src/protocols/dhcpv6/dhcpv6.h
src/protocols/dhcpv6/encode.c

index 6b6324121a204ad2186b0ccdc825ca983470117c..3cadb95a7459e3b526cd55014c0c79127bfb50f5 100644 (file)
@@ -390,8 +390,8 @@ static ssize_t mod_encode(void const *instance, REQUEST *request, uint8_t *buffe
                if (data_len > 0) return data_len;
        }
 
-       data_len = fr_dhcpv6_encode(buffer, buffer_len, (uint8_t const *) original, request->reply->code,
-                                   request->reply->vps);
+       data_len = fr_dhcpv6_encode(buffer, buffer_len, request->packet->data, request->packet->data_len,
+                                   request->reply->code, request->reply->vps);
        if (data_len < 0) {
                RPEDEBUG("Failed encoding DHCPv6 reply");
                return -1;
index e46c640722e41d454c6ada794ae4b0d484d7940c..9012ea0a7508fb470896bccb9cd3ca72f553520c 100644 (file)
@@ -739,7 +739,7 @@ void *fr_dhcpv6_next_encodable(void **prev, void *to_eval, void *uctx)
 /** Encode a DHCPv6 packet
  *
  */
-ssize_t        fr_dhcpv6_encode(uint8_t *packet, size_t packet_len, uint8_t const *original,
+ssize_t        fr_dhcpv6_encode(uint8_t *packet, size_t packet_len, uint8_t const *original, size_t length,
                         int msg_type, VALUE_PAIR *vps)
 {
        VALUE_PAIR *vp;
@@ -816,6 +816,9 @@ ssize_t     fr_dhcpv6_encode(uint8_t *packet, size_t packet_len, uint8_t const *orig
 
 encode_options:
        packet_ctx.root = root;
+       packet_ctx.original = original;
+       packet_ctx.original_length = length;
+
        end = packet + packet_len;
 
        fr_cursor_talloc_iter_init(&cursor, &vps, fr_dhcpv6_next_encodable, dict_dhcpv6, VALUE_PAIR);
index aeb2b15d99e1ba66bc3a30aed1e19a9fbaf0a29b..93de2f6d7f9174322299203754aec5797dcdaa71 100644 (file)
@@ -112,6 +112,8 @@ typedef struct CC_HINT(__packed__) {
 
 typedef struct {
        fr_dict_attr_t const    *root;                          //!< Root attribute of the dictionary.
+       uint8_t const           *original;                      //!< original packet
+       size_t                  original_length;                //!< length of the original packet
 } fr_dhcpv6_encode_ctx_t;
 
 typedef struct {
@@ -134,7 +136,7 @@ bool                fr_dhcpv6_ok(uint8_t const *packet, size_t packet_len,
 bool           fr_dhcpv6_verify(uint8_t const *packet, size_t packet_len, fr_dhcpv6_decode_ctx_t const *packet_ctx,
                                 bool from_server);
 
-ssize_t                fr_dhcpv6_encode(uint8_t *packet, size_t packet_len, uint8_t const *original,
+ssize_t                fr_dhcpv6_encode(uint8_t *packet, size_t packet_len, uint8_t const *original, size_t length,
                                 int msg_type, VALUE_PAIR *vps);
 
 ssize_t                fr_dhcpv6_decode(TALLOC_CTX *ctx, uint8_t const *packet, size_t packet_len,
index 9134f82bb291db4645fab40c7ef94f86f71eeae2..303b6453e12091293e94fe43664c9458266d1007 100644 (file)
@@ -727,7 +727,7 @@ static ssize_t encode_vsio_hdr(fr_dbuff_t *dbuff,
        }
 
        /*
-        *      Copy in the 32bit PEN (Private Enterprise Number)
+(&work_dbuff, &da_stack, depth, cursor, encoder_ctx);   *      Copy in the 32bit PEN (Private Enterprise Number)
         */
        fr_dbuff_advance(&work_dbuff, OPT_HDR_LEN);
        fr_dbuff_in(&work_dbuff, dv->attr);
@@ -774,6 +774,77 @@ static ssize_t encode_vsio_hdr(fr_dbuff_t *dbuff,
        return fr_dbuff_set(dbuff, &work_dbuff);
 }
 
+/** Encode a Relay-Message
+ *
+ *     Header + stuff
+ */
+static ssize_t encode_relay_message(fr_dbuff_t *dbuff,
+                                   fr_da_stack_t *da_stack, unsigned int depth,
+                                   fr_cursor_t *cursor, void *encoder_ctx)
+{
+       fr_dbuff_t              work_dbuff = FR_DBUFF_NO_ADVANCE(dbuff);
+       fr_dbuff_t              hdr_dbuff = FR_DBUFF_NO_ADVANCE(dbuff);
+       fr_dict_attr_t const    *da = da_stack->da[depth];
+       ssize_t                 len;
+       uint8_t const           *original = NULL;
+       size_t                  original_length = 0;
+       VALUE_PAIR              *vp;
+       fr_dhcpv6_encode_ctx_t  *packet_ctx = encoder_ctx;
+
+       FR_PROTO_STACK_PRINT(da_stack, depth);
+
+       vp = fr_cursor_current(cursor);
+       if (!vp->vp_group) {
+               vp = fr_cursor_next(cursor);
+               fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
+               return PAIR_ENCODE_SKIPPED;
+       }
+
+       /*
+        *      Make space for the header...
+        */
+       FR_DBUFF_ADVANCE_RETURN(&work_dbuff, OPT_HDR_LEN);
+
+       /*
+        *      Pass the original packet to the packet encode routine.
+        */
+       if (packet_ctx->original) {
+               uint8_t const *options;
+
+               if (packet_ctx->original[0] == FR_DHCPV6_RELAY_FORWARD) {
+                       options = packet_ctx->original + 2 + 32;
+               } else {
+                       options = packet_ctx->original + 4;
+               }
+
+               original = fr_dhcpv6_option_find(options, packet_ctx->original + packet_ctx->original_length,
+                                                attr_relay_message->attr);
+               if (original) {
+                       original_length = (original[2] << 8) | original[3];
+                       original += 4;
+               }
+       }
+
+       vp = fr_cursor_current(cursor);
+
+       len = fr_dhcpv6_encode(work_dbuff.p, fr_dbuff_remaining(&work_dbuff), original, original_length, FR_DHCPV6_RELAY_REPLY, vp->vp_group);
+       if (len <= 0) return -1;
+
+       /*
+        *      Write out the option number and length (before the value we just wrote)
+        */
+       encode_option_hdr(&hdr_dbuff, (uint16_t)da->attr, (uint16_t) (fr_dbuff_used(&work_dbuff) - OPT_HDR_LEN));
+
+#ifndef NDEBUG
+       FR_PROTO_HEX_DUMP(dbuff->p, fr_dbuff_used(&work_dbuff), "Done RFC header");
+#endif
+
+       vp = fr_cursor_next(cursor);
+       fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
+
+       return fr_dbuff_set(dbuff, &work_dbuff);
+}
+
 /** Encode a DHCPv6 option and any sub-options.
  *
  * @param[out] out             Where to write encoded DHCP attributes.
@@ -830,6 +901,13 @@ static ssize_t encode_option(fr_dbuff_t *dbuff, fr_cursor_t *cursor, void * enco
                len = encode_vsio_hdr(&work_dbuff, &da_stack, depth, cursor, encoder_ctx);
                break;
 
+       case FR_TYPE_GROUP:
+               if (da_stack.da[depth] == attr_relay_message) {
+                       len = encode_relay_message(&work_dbuff, &da_stack, depth, cursor, encoder_ctx);
+                       break;
+               }
+               FALL_THROUGH;
+
        default:
                len = encode_rfc_hdr(&work_dbuff, &da_stack, depth, cursor, encoder_ctx);
                break;
@@ -870,7 +948,7 @@ static ssize_t fr_dhcpv6_encode_proto(UNUSED TALLOC_CTX *ctx, VALUE_PAIR *vps, u
 {
 //     fr_dhcpv6_decode_ctx_t  *test_ctx = talloc_get_type_abort(proto_ctx, fr_dhcpv6_decode_ctx_t);
 
-       return fr_dhcpv6_encode(data, data_len, NULL, 0, vps);
+       return fr_dhcpv6_encode(data, data_len, NULL, 0, 0, vps);
 }
 
 /*