From: Nick Porter Date: Wed, 24 Mar 2021 13:57:57 +0000 (+0000) Subject: v4: Define parameters for %(dhcpv4_decode: ) and %(dhcpv4_encode: ) xlats (#4023) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ff3ffe3ec6f7705b16ea870a530a889471a5c64f;p=thirdparty%2Ffreeradius-server.git v4: Define parameters for %(dhcpv4_decode: ) and %(dhcpv4_encode: ) xlats (#4023) * 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() --- diff --git a/doc/antora/modules/raddb/pages/mods-available/dhcpv4.adoc b/doc/antora/modules/raddb/pages/mods-available/dhcpv4.adoc index 3c154e3601f..c0c055cf195 100644 --- a/doc/antora/modules/raddb/pages/mods-available/dhcpv4.adoc +++ b/doc/antora/modules/raddb/pages/mods-available/dhcpv4.adoc @@ -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 { diff --git a/raddb/mods-available/dhcpv4 b/raddb/mods-available/dhcpv4 index 43fb9c71bc6..32f0aa855be 100644 --- a/raddb/mods-available/dhcpv4 +++ b/raddb/mods-available/dhcpv4 @@ -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 { diff --git a/src/lib/unlang/xlat.h b/src/lib/unlang/xlat.h index 98d9abc6d28..b6cdf4c6055 100644 --- a/src/lib/unlang/xlat.h +++ b/src/lib/unlang/xlat.h @@ -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)); diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index 0cbd6d45f8a..356b7f1302c 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -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. */ diff --git a/src/modules/rlm_dhcpv4/rlm_dhcpv4.c b/src/modules/rlm_dhcpv4/rlm_dhcpv4.c index 8ca98fe041b..2880ba3ca46 100644 --- a/src/modules/rlm_dhcpv4/rlm_dhcpv4.c +++ b/src/modules/rlm_dhcpv4/rlm_dhcpv4.c @@ -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; } diff --git a/src/tests/keywords/radius.conf b/src/tests/keywords/radius.conf index 88c4f12a9ce..45cccbf96b9 100644 --- a/src/tests/keywords/radius.conf +++ b/src/tests/keywords/radius.conf @@ -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 index 00000000000..b18496a41df --- /dev/null +++ b/src/tests/keywords/xlat-dhcpv4 @@ -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