= Built-In Expansions In addition to storing attribute references, the server has a number of built-in expansions. These expansions act largely as functions which operate on inputs, and produce an output. == Attribute Manipulation === %{length: ... } The `length` expansion returns the size of the input as an integer. When the input is a string, then the output is identical to the `strlen` expansion. When the input is an attribute reference, the output is the size of the attributes data as encoded "on the wire". .Return: _size_ .Determining the length of fixed and variable length attributes ==== [source,unlang] ---- update control { &Tmp-String-0 := "Caipirinha" &Framed-IP-Address := 192.0.2.1 } update reply { &Reply-Message := "The length of %{control:Tmp-String-0} is %{length:&control:Tmp-String-0}" &Reply-Message += "The length of %{control:Framed-IP-Address} is %{length:&control:Framed-IP-Address}" } ---- .Output .... The length of Caipirinha is 10 The length of 192.168.0.2 is 4 .... ==== `length` is built in to the server core. === %{integer:<&ref>} Print the value of the attribute an integer. In normal operation, `integer` attributes are printed using the name given by a `VALUE` statement in a dictionary. Similarly, date attributes are printed as dates, i.e., "January 1 2010. The `integer` expansion applies only to attributes which can be converted to an integer. For all other inputs, it returns `0`. A common usage is to find the difference between two dates. For example, if a request contains `Service-Type = Login-User`, the expansion of `%{integer:&Service-Type}` will yield `1`, which is the value associated with the `Login-User` name. Using `%{integer:&Event-Timestamp}` will return the event timestamp as an unsigned 32-bit number. .Return: _string_ .Determining the integer value of an enumerated attribute ==== [source,unlang] ---- update { &control:Service-Type := Login-User } update reply { &Reply-Message := "The value of Service-Type is %{integer:&control:Service-Type}" } ---- .Output ``` The value of Service-Type is 1 ``` ==== `integer` is built in to the server core. === %{rand:} Generate random number from `0` to `-1`. .Return: _uint64_ .Generating a random number between 0 and 511 ==== [source,unlang] ---- update reply { &Reply-Message := "The random number is %{rand:512}" } ---- .Output ``` The random number is 347 ``` ==== `rand` is provided by the `rlm_expr` module. === %{tag:} CAUTION: This expansion is deprecated and will likely be removed. Returns a list of tags for any attributes found using ````. .Return: _int8_ .Determining the tag value of the second instance of the `radius.Tunnel-Server-Endpoint` attribute ==== [source,unlang] ---- update request { &Tunnel-Server-Endpoint := '192.0.1.1' &Tunnel-Server-Endpoint:1 := '192.0.5.2' &Tunnel-Server-Endpoint:1 += '192.0.3.8' &Tunnel-Server-Endpoint:2 := '192.0.2.1' &Tunnel-Server-Endpoint:2 += '192.0.3.4' } update reply { &Reply-Message := "The tag value of the second instance of Tunnel-Server-Enpoint is %{request:Tunnel-Server-Endpoint[1]}" } ---- .Output ``` The tag value of the second instance of Tunnel-Server-Enpoint is 192.0.5.2 ``` ==== `tag` is built in to the server core. === %{string:} Convert input to a string (if possible). For _octets_ type attributes, this means interpreting the data as a UTF8 string, and inserting octal escape sequences where appropriate. For other types, this means printing the value in its _presentation_ format, i.e. dotted quads for IPv4 addresses, link:https://en.wikipedia.org/wiki/ISO_8601[ISO 8601] time for date types, enumeration values for attributes such as `radius.Service-Type` etc. .Return: _string_ .String interpolation using the raw octets value of Tmp-Octets-0, and the stringified version ==== [source,unlang] ---- update control { &Tmp-Octets-0 := 0x7465737431 } update reply { &Reply-Message := "The string value of %{control:Tmp-Octets-0} is %{string:%{control:Tmp-Octets-0}}" } ---- ==== .Output ``` The string value of 0x7465737431 is test1 ``` `string` is built in to the server core. == Server Manipulation === %{config:} Refers to a variable in the configuration file. See the documentation on configuration file references. .Return: _string_ .Example [source,unlang] ---- "Server installed in %{config:prefix}" "Module rlm_exec.shell_escape = %{config:modules.exec.shell_escape}" ---- .Output ``` Server installed in /opt/freeradius Module rlm_exec.shell_escape = yes ``` `config` is built in to the server core. === %{client:} Refers to a variable that was defined in the client section for the current client. See the sections `client { ... }` in `clients.conf`. .Return: _string_ .Example [source,unlang] ---- "The client ipaddr is %{client:ipaddr}" ---- .Output ``` The client ipaddr is 192.168.5.9 ``` `client` is built in to the server core. === %{debug:} Dynamically change the debug level to something high, recording the old level. .Return: _string_ .Example [source,unlang] ---- authorize { if (&request:User-Name == "bob") { "%{debug:4}" } else { "%{debug:0}" } ... } ---- .Output (_extra informations only for that condition_) ``` ... (0) authorize { (0) if (&request:User-Name == "bob") { (0) EXPAND %{debug:4} (0) --> 2 (0) } # if (&request:User-Name == "bob") (...) (0) filter_username { (0) if (&State) { (0) ... (0) } ... ``` `debug` is built in to the server core. === %{debug_attr:} Print to debug output all instances of current attribute, or all attributes in a list. expands to a zero-length string. .Return: _string_ .Example [source,unlang] ---- authorize { if (&request:User-Name == "bob") { "%{debug_attr:request[*]}" } ... } ---- .Output ``` ... (0) authorize { (0) if (&request:User-Name == "bob") { (0) Attributes matching "request[*]" (0) &request:User-Name = bob (0) &request:User-Password = hello (0) &request:NAS-IP-Address = 127.0.1.1 (0) &request:NAS-Port = 1 (0) &request:Message-Authenticator = 0x9210ee447a9f4c522f5300eb8fc15e14 (0) EXPAND %{debug_attr:request[*]} (0) } # if (&request:User-Name == "bob") (...) ... ``` `debug_attr` is built in to the server core. == String manipulation === %{lpad:<&ref> } Left-pad a string. .Return: _string_ .Example [source,unlang] ---- update control { &Tmp-String-0 := "123" } update reply { &Reply-Message := "Maximum should be %{lpad:&control:Tmp-String-0 11 0}" } ---- .Output ``` Maximum should be 00000000123 ``` `lpad` is provided by the `rlm_expr` module. === %{rpad:<&ref> } Right-pad a string. .Return: _string_ .Example [source,unlang] ---- update control { &Tmp-String-0 := "123" } update reply { &Reply-Message := "Maximum should be %{rpad:&control:Tmp-String-0 11 0}" } ---- .Output ``` Maximum should be 12300000000 ``` `rpad` is provided by the `rlm_expr` module. === %{pairs:<&list:[*]>} Serialize attributes as comma-delimited string. .Return: _string_ .Example [source,unlang] ---- update { &control:Tmp-String-0 := "This is a string" &control:Tmp-String-0 += "This is another one" } update reply { &Reply-Message := "Serialize output: %{pairs:&control[*]}" } ---- .Output ``` Serialize output: Tmp-String-0 = \"This is a string\"Tmp-String-0 = \"This is another one\" ``` `pairs` is provided by the `rlm_expr` module. === %{randstr: ...} Get random string built from character classes. .Return: _string_ .Example [source,unlang] ---- update reply { &Reply-Message := "The random string output is %{randstr:aaaaaaaa}" } ---- .Output ``` The random string output is 4Uq0gPyG ``` `randstr` is provided by the `rlm_expr` module. === %{strlen: ... } Length of given string. .Return: _integer_ .Example [source,unlang] ---- update control { &Tmp-String-0 := "Caipirinha" } update reply { &Reply-Message := "The length of %{control:Tmp-String-0} is %{strlen:&control:Tmp-String-0}" } ---- .Output ``` The length of Caipirinha is 21 ``` `strlen` is built in to the server core. === %{tolower: ... } Dynamically expands the string and returns the lowercase version of it. This definition is only available in version 2.1.10 and later. .Return: _string_ .Example [source,unlang] ---- update control { &Tmp-String-0 := "CAIPIRINHA" } update reply { &Reply-Message := "tolower of %{control:Tmp-String-0} is %{tolower:%{control:Tmp-String-0}}" } ---- .Output ``` tolower of CAIPIRINHA is caipirinha ``` `tolower` is provided by the `rlm_expr` module. === %{toupper: ... } Dynamically expands the string and returns the uppercase version of it. This definition is only available in version 2.1.10 and later. .Return: _string_ .Example [source,unlang] ---- update control { &Tmp-String-0 := "caipirinha" } update reply { &Reply-Message := "toupper of %{control:Tmp-String-0} is %{toupper:%{control:Tmp-String-0}}" } ---- .Output ``` toupper of caipirinha is CAIPIRINHA ``` `toupper` is provided by the `rlm_expr` module. == String Conversion === %{base64: ... } Encode a string using Base64. .Return: _string_ .Example [source,unlang] ---- update control { &Tmp-String-0 := "Caipirinha" } update reply { &Reply-Message := "The base64 of %{control:Tmp-String-0} is %{base64:%{control:Tmp-String-0}}" } ---- .Output ``` The base64 of foo is Q2FpcGlyaW5oYQ== ``` `base64` is provided by the `rlm_expr` module. === %{base64tohex: ... } Decode a base64 string (e.g. previously encoded using `base64`) to hex. .Return: _string_ .Example [source,unlang] ---- update control { &Tmp-String-0 := "Q2FpcGlyaW5oYQ==" } update reply { &Reply-Message := "The base64tohex of %{control:Tmp-String-0} is %{base64tohex:%{control:Tmp-String-0}}" } ---- .Output ``` The base64decode of Q2FpcGlyaW5oYQ== is 436169706972696e6861 ``` `base64tohex` is provided by the `rlm_expr` module. === %{hex: ... } Convert to hex. .Return: _string_ .Example [source,unlang] ---- update control { &Tmp-String-0 := "12345" } update reply { &Reply-Message := "The value of %{control:Tmp-String-0} in hex is %{hex:%{control:Tmp-String-0}}" } ---- .Output ``` The value of 12345 in hex is 3132333435 ``` `hex` is built in to the server core. === %{urlquote: ... } Quote URL special characters. .Return: _string_. .Example [source,unlang] ---- update { &control:Tmp-String-0 := "http://example.org/" } update reply { &Reply-Message += "The urlquote of %{control:Tmp-String-0} is %{urlquote:%{control:Tmp-String-0}}" } ---- .Output ``` The urlquote of http://example.org/ is http%3A%2F%2Fexample.org%2F ``` `urlquote` is provided by the `rlm_expr` module. === %{urlunquote: ... } Unquote URL special characters. .Return: _string_. .Example [source,unlang] ---- update { &control:Tmp-String-0 := "http%%3A%%2F%%2Fexample.org%%2F" # Attention for the double %. } update reply { &Reply-Message += "The urlunquote of %{control:Tmp-String-0} is %{urlunquote:%{control:Tmp-String-0}}" } ---- .Output ``` The urlunquote of http%3A%2F%2Fexample.org%2F is http://example.org/ ``` `urlunquote` is provided by the `rlm_expr` module. == Hashing and Encryption === %{hmacmd5: } Generate `HMAC-MD5` of string. .Return: _octal_ .Example [source,unlang] ---- update { &control:Tmp-String-0 := "mykey" &control:Tmp-String-1 := "Caipirinha" } update { &control:Tmp-Octets-0 := "%{hmacmd5:%{control:Tmp-String-0} %{control:Tmp-String-1}}" } update reply { &Reply-Message := "The HMAC-MD5 of %{control:Tmp-String-1} in octets is %{control:Tmp-Octets-0}" &Reply-Message += "The HMAC-MD5 of %{control:Tmp-String-1} in hex is %{hex:control:Tmp-Octets-0}" } ---- .Output ``` The HMAC-MD5 of Caipirinha in octets is \317}\264@K\216\371\035\304\367\202,c\376\341\203 The HMAC-MD5 of Caipirinha in hex is 636f6e74726f6c3a546d702d4f63746574732d30 ``` `hmacmd5` is provided by the `rlm_expr` module. === %{hmacsha1: } Generate `HMAC-SHA1` of string. .Return: _octal_ .Example [source,unlang] ---- update { &control:Tmp-String-0 := "mykey" &control:Tmp-String-1 := "Caipirinha" } update { &control:Tmp-Octets-0 := "%{hmacsha1:%{control:Tmp-String-0} %{control:Tmp-String-1}}" } update reply { &Reply-Message := "The HMAC-SHA1 of %{control:Tmp-String-1} in octets is %{control:Tmp-Octets-0}" &Reply-Message += "The HMAC-SHA1 of %{control:Tmp-String-1} in hex is %{hex:control:Tmp-Octets-0}" } ---- .Output ``` The HMAC-SHA1 of Caipirinha in octets is \311\007\212\234j\355\207\035\225\256\372ʙ>R\"\341\351O) The HMAC-SHA1 of Caipirinha in hex is 636f6e74726f6c3a546d702d4f63746574732d30 ``` `hmacsha1` is provided by the `rlm_expr` module. === %{md5: ... } Dynamically expands the string and performs an MD5 hash on it. The result is binary data. .Return: _binary data_ .Example [source,unlang] ---- update control { &Tmp-String-0 := "Caipirinha" } update reply { &Reply-Message := "md5 of %{control:Tmp-String-0} is octal=%{md5:%{control:Tmp-String-0}}" &Reply-Message := "md5 of %{control:Tmp-String-0} is hex=%{hex:%{md5:%{control:Tmp-String-0}}}" } ---- .Output ``` md5 of Caipirinha is octal=\024\204\013md||\230\243\3472\3703\330n\251 md5 of Caipirinha is hex=14840b6d647c7c98a3e732f833d86ea9 ``` `md5` is provided by the `rlm_expr` module. == Miscellaneous Expansions === +%{0}+..+%{32}+ `%{0}` expands to the portion of the subject that matched the last regular expression evaluated. `%{1}`..`%{32}` expand to the contents of any capture groups in the pattern. Every time a regular expression is evaluated, whether it matches or not, the numbered capture group values will be cleared. === +%{regex:}+ Return named subcapture value from the last regular expression evaluated. Results of named capture groups are available using the `%{regex:}` expansion. They will also be accessible using the numbered expansions described xref:builtin.adoc#_0_32[above]. Every time a regular expression is evaluated, whether it matches or not, the named capture group values will be cleared. [NOTE] ==== This expansion is only available if the server is built with libpcre or libpcre2. Use the output of `radiusd -Xxv` to determine which regular expression library in use. .... ... Debug : regex-pcre : no Debug : regex-pcre2 : yes Debug : regex-posix : no Debug : regex-posix-extended : no Debug : regex-binsafe : yes ... Debug : pcre2 : 10.33 (2019-04-16) - retrieved at build time .... ==== `regex` is built in to the server core. === +%{nexttime: