]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
v4: Define parameters for %(dhcpv4_decode: ) and %(dhcpv4_encode: ) xlats (#4023)
authorNick Porter <nick@portercomputing.co.uk>
Wed, 24 Mar 2021 13:57:57 +0000 (13:57 +0000)
committerGitHub <noreply@github.com>
Wed, 24 Mar 2021 13:57:57 +0000 (13:57 +0000)
* Simplify loops

* Define arguments for dhcpv4 xlats

* Update documentation for %(dhcpv4_decode: )

* Update documentation for %(dhcpv4_encode: ) xlat

* Add dhcpv4 module for dhcp tests

* Test %(dhcpv4_decode: ) and %(dhcpv4_encode: )

* Remove un-used xlat_fmt_to_cursor()

doc/antora/modules/raddb/pages/mods-available/dhcpv4.adoc
raddb/mods-available/dhcpv4
src/lib/unlang/xlat.h
src/lib/unlang/xlat_builtin.c
src/modules/rlm_dhcpv4/rlm_dhcpv4.c
src/tests/keywords/radius.conf
src/tests/keywords/xlat-dhcpv4 [new file with mode: 0644]

index 3c154e3601f48bf2db250404aaaf206369669e7c..c0c055cf195fc2246a3882582a0141fdc86e6e4f 100644 (file)
@@ -34,7 +34,7 @@ This module takes no configuration.
 
 The rlm_dhcpv4 provides the below xlat's functions to handle the DHCPV4 packets.
 
-### %{dhcpv4_decode:...}
+### %(dhcpv4_decode:...)
 
 Decode DHCP option declared in dictionary.rfc2131.
 
@@ -47,7 +47,7 @@ Decode DHCP option declared in dictionary.rfc2131.
 update request {
   &Tmp-Octets-0 := 0x520d0103abcdef0206010203040506
 }
-if ("%{dhcpv4_decode:%{Tmp-Octets-0}}" != 2) {
+if ("%(dhcpv4_decode:%{Tmp-Octets-0})" != 2) {
   update reply {
     &Reply-Message := "Problems decoding the DHPCv4 fields."
   }
@@ -64,7 +64,7 @@ update reply {
 "The value of Relay-Agent-Information.Circuit-ID=0xabcdef, Relay-Agent-Information.Remote-ID=0x010203040506"
 ```
 
-### %{dhcpv4_encode:...}
+### %(dhcpv4_encode:...)
 
 Encode DHCP option declared in dictionary.rfc2131.
 
@@ -79,7 +79,7 @@ update request {
   &Relay-Agent-Information.Remote-ID := 0x010203040506
 }
 update request {
-  &Tmp-Octets-0 := "%{dhcpv4_encode:&request[*]}"
+  &Tmp-Octets-0 := "%(dhcpv4_encode:&request[*])"
 }
 if (&Tmp-Octets-0 != 0x520d0103abcdef0206010203040506) {
   update reply {
index 43fb9c71bc64f88b6c19a88b66c426b929ead079..32f0aa855be93ddf89b744d2c856dfffd14f051d 100644 (file)
@@ -39,7 +39,7 @@ dhcpv4 {
 #
 #  The rlm_dhcpv4 provides the below xlat's functions to handle the DHCPV4 packets.
 #
-#  ### %{dhcpv4_decode:...}
+#  ### %(dhcpv4_decode:...)
 #
 #  Decode DHCP option declared in dictionary.rfc2131.
 #
@@ -52,7 +52,7 @@ dhcpv4 {
 #  update request {
 #    &Tmp-Octets-0 := 0x520d0103abcdef0206010203040506
 #  }
-#  if ("%{dhcpv4_decode:%{Tmp-Octets-0}}" != 2) {
+#  if ("%(dhcpv4_decode:%{Tmp-Octets-0})" != 2) {
 #    update reply {
 #      &Reply-Message := "Problems decoding the DHPCv4 fields."
 #    }
@@ -69,7 +69,7 @@ dhcpv4 {
 #  "The value of Relay-Agent-Information.Circuit-ID=0xabcdef, Relay-Agent-Information.Remote-ID=0x010203040506"
 #  ```
 #
-#  ### %{dhcpv4_encode:...}
+#  ### %(dhcpv4_encode:...)
 #
 #  Encode DHCP option declared in dictionary.rfc2131.
 #
@@ -84,7 +84,7 @@ dhcpv4 {
 #    &Relay-Agent-Information.Remote-ID := 0x010203040506
 #  }
 #  update request {
-#    &Tmp-Octets-0 := "%{dhcpv4_encode:&request[*]}"
+#    &Tmp-Octets-0 := "%(dhcpv4_encode:&request[*])"
 #  }
 #  if (&Tmp-Octets-0 != 0x520d0103abcdef0206010203040506) {
 #    update reply {
index 98d9abc6d28258a88a8e06ced664c3c34957d822..b6cdf4c60556471ccbd9269b39c29df72533233b 100644 (file)
@@ -303,9 +303,6 @@ typedef size_t (*xlat_escape_legacy_t)(request_t *request, char *out, size_t out
 
 int            xlat_fmt_get_vp(fr_pair_t **out, request_t *request, char const *name);
 
-int            xlat_fmt_to_cursor(TALLOC_CTX *ctx, fr_dcursor_t **out,
-                                  bool *tainted, request_t *requst, char const *fmt);
-
 ssize_t                xlat_eval(char *out, size_t outlen, request_t *request, char const *fmt, xlat_escape_legacy_t escape,
                          void const *escape_ctx)
                          CC_HINT(nonnull (1 ,3 ,4));
index 0cbd6d45f8a5cd7fac3c1fa88c9e3e5f074c9fcc..356b7f1302ce0ca2e8c379289274d3f9c1019012 100644 (file)
@@ -60,7 +60,7 @@ static char const hextab[] = "0123456789abcdef";
 
 /** Return a VP from the specified request.
  *
- * @note DEPRECATED, TO NOT USE.  @see xlat_fmt_to_cursor instead.
+ * @note DEPRECATED, TO NOT USE.
  *
  * @param out where to write the pointer to the resolved VP. Will be NULL if the attribute couldn't
  *     be resolved.
@@ -90,73 +90,6 @@ int xlat_fmt_get_vp(fr_pair_t **out, request_t *request, char const *name)
 }
 
 
-/** Convenience function to convert a string attribute reference to a cursor
- *
- * This is intended to be used by xlat functions which need to iterate over
- * an attribute reference provided as a format string or as a boxed value.
- *
- * We can't add attribute reference support to the xlat parser
- * as the inputs and outputs of xlat functions are all boxed values and
- * couldn't represent a fr_pair_t.
- *
- * @param[in] ctx      To allocate new cursor in.
- * @param[out] out     Where to write heap allocated cursor.  Must be freed
- *                     once it's done with.  The heap based cursor is to
- *                     simplify memory management, as all tmpls are heap
- *                     allocated, and we need to bind the lifetime of the
- *                     tmpl and tmpl cursor together.
- * @param[in] tainted  May be NULL.  Set to true if one or more of the pairs
- *                     in the cursor's scope have the tainted flag high.
- * @param[in] request  The current request.
- * @param[in] fmt      string.  Leading whitespace will be ignored.
- * @return
- *     - 0 on success.
- *     - -1 on failure.
- */
-int xlat_fmt_to_cursor(TALLOC_CTX *ctx, fr_dcursor_t **out,
-                      bool *tainted, request_t *request, char const *fmt)
-{
-       tmpl_t                  *vpt;
-       fr_pair_t               *vp;
-       fr_dcursor_t            *cursor;
-       tmpl_cursor_ctx_t       cc;
-
-       fr_skip_whitespace(fmt);        /* Not binary safe, but attr refs should only contain printable chars */
-
-       if (tmpl_afrom_attr_str(NULL, NULL, &vpt, fmt,
-                               &(tmpl_rules_t){
-                                       .dict_def = request->dict,
-                                       .prefix = TMPL_ATTR_REF_PREFIX_AUTO
-                               }) <= 0) {
-               RPEDEBUG("Failed parsing attribute reference");
-               return -1;
-       }
-
-       MEM(cursor = talloc(ctx, fr_dcursor_t));
-       talloc_steal(cursor, vpt);
-       vp = tmpl_cursor_init(NULL, NULL, &cc, cursor, request, vpt);
-       tmpl_cursor_clear(&cc);
-       *out = cursor;
-
-       if (!tainted) return 0;
-
-       *tainted = false;       /* Needed for the rest of the code */
-
-       if (!vp) return 0;
-
-       do {
-               if (vp->vp_tainted) {
-                       *tainted = true;
-                       break;
-               }
-       } while ((vp = fr_dcursor_next(cursor)));
-
-       fr_dcursor_head(cursor);        /* Reset */
-
-       return 0;
-}
-
-
 /*
  *     Compare two xlat_t structs, based ONLY on the module name.
  */
index 8ca98fe041b5fae7b84ffa8d3e04419cf75fd2dc..2880ba3ca4642dc3c8a88aaf79771b084137a81a 100644 (file)
@@ -50,13 +50,18 @@ typedef struct {
        int nothing;
 } rlm_dhcpv4_t;
 
+static xlat_arg_parser_t const dhcpv4_decode_xlat_args[] = {
+       { .single = true, .variadic = true, .type = FR_TYPE_VOID },
+       XLAT_ARG_PARSER_TERMINATOR
+};
+
 /** Decode DHCP option data
  *
  * Creates DHCP attributes based on the given binary option data
  *
  * Example:
 @verbatim
-%{dhcpv4_decode:%{Tmp-Octets-0}}
+%(dhcpv4_decode:%{Tmp-Octets-0})
 @endverbatim
  *
  * @ingroup xlat_functions
@@ -65,17 +70,14 @@ static xlat_action_t dhcpv4_decode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
                                        request_t *request, UNUSED void const *xlat_inst, UNUSED void *xlat_thread_inst,
                                        fr_value_box_list_t *in)
 {
-       fr_dcursor_t    in_cursor;
-       fr_value_box_t  *vb, *vb_decoded;
-       fr_pair_t       *vp;
+       fr_value_box_t  *vb = NULL, *vb_decoded;
+       fr_pair_t       *vp = NULL;
        fr_pair_list_t  head;
        int             decoded = 0;
 
        fr_pair_list_init(&head);
 
-       for (vb = fr_dcursor_talloc_init(&in_cursor, in, fr_value_box_t);
-            vb;
-            vb = fr_dcursor_next(&in_cursor)) {
+       while ((vb = fr_dlist_next(in, vb))) {
                uint8_t const   *p, *end;
                ssize_t         len;
                fr_pair_list_t  vps;
@@ -111,9 +113,7 @@ static xlat_action_t dhcpv4_decode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
                fr_tmp_pair_list_move(&head, &vps);
        }
 
-       for (vp = fr_pair_list_head(&head);
-            vp;
-            vp = fr_pair_list_next(&head, vp)) {
+       while ((vp = fr_pair_list_next(&head, vp))) {
                RDEBUG2("dhcp_option: &%pP", vp);
                decoded++;
        }
@@ -131,13 +131,18 @@ static xlat_action_t dhcpv4_decode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
        return XLAT_ACTION_DONE;
 }
 
+static xlat_arg_parser_t const dhcpv4_encode_xlat_args[] = {
+       { .required = true, .single = true, .type = FR_TYPE_STRING },
+       XLAT_ARG_PARSER_TERMINATOR
+};
+
 /** Encode DHCP option data
  *
  * Returns octet string created from the provided DHCP attributes
  *
  * Example:
 @verbatim
-%{dhcpv4_encode:&request[*]}
+%(dhcpv4_encode:&request[*])
 @endverbatim
  *
  * @ingroup xlat_functions
@@ -146,7 +151,10 @@ static xlat_action_t dhcpv4_encode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
                                        request_t *request, UNUSED void const *xlat_inst, UNUSED void *xlat_thread_inst,
                                        fr_value_box_list_t *in)
 {
+       tmpl_t          *vpt;
+       fr_pair_t       *vp;
        fr_dcursor_t    *cursor;
+       tmpl_cursor_ctx_t       cc;
        bool            tainted = false;
        fr_value_box_t  *encoded;
 
@@ -155,28 +163,36 @@ static xlat_action_t dhcpv4_encode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
        ssize_t         len = 0;
        fr_value_box_t  *in_head = fr_dlist_head(in);
 
-       if (!in_head) return XLAT_ACTION_DONE;
-
-       if (fr_value_box_list_concat(ctx, in_head, in, FR_TYPE_STRING, true) < 0) {
-               RPEDEBUG("Failed concatenating input string for attribute reference");
+       if (tmpl_afrom_attr_str(NULL, NULL, &vpt, in_head->vb_strvalue,
+                               &(tmpl_rules_t){
+                                       .dict_def = request->dict,
+                                       .prefix = TMPL_ATTR_REF_PREFIX_AUTO
+                               }) <= 0) {
+               RPEDEBUG("Failed parsing attribute reference");
                return XLAT_ACTION_FAIL;
        }
 
-       if (xlat_fmt_to_cursor(NULL, &cursor, &tainted, request, in_head->vb_strvalue) < 0) return XLAT_ACTION_FAIL;
+       MEM(cursor = talloc(ctx, fr_dcursor_t));
+       talloc_steal(cursor, vpt);
+       vp = tmpl_cursor_init(NULL, NULL, &cc, cursor, request, vpt);
 
-       if (!fr_dcursor_head(cursor)) return XLAT_ACTION_DONE;  /* Nothing to encode */
+       if (!vp) return XLAT_ACTION_DONE; /* Nothing to encode */
 
        while (fr_dcursor_filter_current(cursor, fr_dhcpv4_is_encodable, NULL)) {
+               vp = fr_dcursor_current(cursor);
+               if (vp->vp_tainted) tainted = true;
                len = fr_dhcpv4_encode_option(&FR_DBUFF_TMP(p, end), cursor,
                                              &(fr_dhcpv4_ctx_t){ .root = fr_dict_root(dict_dhcpv4) });
                if (len < 0) {
                        RPEDEBUG("DHCP option encoding failed");
                        talloc_free(cursor);
+                       tmpl_cursor_clear(&cc);
                        return XLAT_ACTION_FAIL;
                }
                p += len;
        }
        talloc_free(cursor);
+       tmpl_cursor_clear(&cc);
 
        /*
         *      Pass the options string back
@@ -190,13 +206,17 @@ static xlat_action_t dhcpv4_encode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
 
 static int dhcp_load(void)
 {
+       xlat_t  *xlat;
+
        if (fr_dhcpv4_global_init() < 0) {
                PERROR("Failed initialising protocol library");
                return -1;
        }
 
-       xlat_register(NULL, "dhcpv4_decode", dhcpv4_decode_xlat, false);
-       xlat_register(NULL, "dhcpv4_encode", dhcpv4_encode_xlat, false);
+       xlat = xlat_register(NULL, "dhcpv4_decode", dhcpv4_decode_xlat, false);
+       xlat_func_args(xlat, dhcpv4_decode_xlat_args);
+       xlat = xlat_register(NULL, "dhcpv4_encode", dhcpv4_encode_xlat, false);
+       xlat_func_args(xlat, dhcpv4_encode_xlat_args);
 
        return 0;
 }
index 88c4f12a9ced8d028ea5fe8ff9bdd3e1c7e1beb1..45cccbf96b9585399869e96c2307c08beba33b7a 100644 (file)
@@ -30,6 +30,10 @@ modules {
 
        }
 
+       dhcpv4 {
+
+       }
+
 }
 
 policy {
diff --git a/src/tests/keywords/xlat-dhcpv4 b/src/tests/keywords/xlat-dhcpv4
new file mode 100644 (file)
index 0000000..b18496a
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# PRE: update
+#
+
+update control {
+        &Tmp-Octets-0 := 0x520d0103abcdef0206010203040506
+}
+
+if ("%(dhcpv4_decode:%{control.Tmp-Octets-0})" != 2) {
+        test_fail
+}
+
+debug_request
+
+if ( &Relay-Agent-Information.Circuit-Id != 0xabcdef ) {
+        test_fail
+}
+
+if ( &Relay-Agent-Information.Remote-Id != 0x010203040506 ) {
+        test_fail
+}
+
+update control {
+        &Tmp-Octets-1 := "%(dhcpv4_encode:&request[*])"
+}
+
+if ( &control.Tmp-Octets-1 != 0x520d0103abcdef0206010203040506 ) {
+        test_fail
+}
+
+debug_control
+success