OUR SITES NetworkRADIUS FreeRADIUS

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".

Example 1. Determining the length of fixed and variable length attributes
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.

Example 2. Determining the integer value of an enumerated attribute
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:<number>}

Generate random number from 0 to <number>-1.

Example 3. Generating a random number between 0 and 511
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:<attribute ref>}

This expansion is deprecated and will likely be removed.

Returns a list of tags for any attributes found using <attribute ref>.

Example 4. Determining the tag value of the second instance of the radius.Tunnel-Server-Endpoint attribute
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:<data>}

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, ISO 8601 time for date types, enumeration values for attributes such as radius.Service-Type etc.

Example 5. String interpolation using the raw octets value of Tmp-Octets-0, and the stringified version
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:<key>}

Refers to a variable in the configuration file. See the documentation on configuration file references.

Example
"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:<key>}

Refers to a variable that was defined in the client section for the current client. See the sections client { …​ } in clients.conf.

Example
"The client ipaddr is %{client:ipaddr}"
Output
The client ipaddr is 192.168.5.9

client is built in to the server core.

%{debug:<level>}

Dynamically change the debug level to something high, recording the old level.

Example
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:<list:[index]>}

Print to debug output all instances of current attribute, or all attributes in a list. expands to a zero-length string.

Example
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> <val> <char>}

Left-pad a string.

Example
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> <val> <char>}

Right-pad a string.

Example
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.

Example
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.

Example
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.

Example
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.

Example
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.

Example
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.

Example
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.

Example
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.

Example
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.

Example
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.

Example
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:<shared_key> <string>}

Generate HMAC-MD5 of string.

Example
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:<shared_key> <string>}

Generate HMAC-SHA1 of string.

Example
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.

Example
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:<named capture group>}

Return named subcapture value from the last regular expression evaluated.

Results of named capture groups are available using the %{regex:<named capture group>} expansion. They will also be accessible using the numbered expansions described above.

Every time a regular expression is evaluated, whether it matches or not, the named capture group values will be cleared.

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:<time>}

Calculate number of seconds until next n hour(s), day(s), week(s), year(s).

Example:

With the current time at 16:18, %{nexttime:1h} will expand to 2520.

update reply {
    &Reply-Message := "You should wait for %{nexttime:1h}s"
}
Output
You should wait for 2520s

nexttime is provided by the rlm_expr module.

%{Packet-Type}

The packet type (Access-Request, etc.)

%{Packet-Src-IP-Address} and %{Packet-Src-IPv6-Address}

The source IPv4 or IPv6 address of the packet. See also the expansions %{client:ipaddr} and %{client:ipv6addr}. The two expansions should be identical, unless %{client:ipaddr} contains a DNS hostname.

%{Packet-Dst-IP-Address} and %{Packet-Dst-IPv6-Address}

The destination IPv4 or IPv6 address of the packet. See also the expansions %{listen:ipaddr} and %{listen:ipv6addr}. If the socket is listening on a "wildcard" address, then these two expansions will be different, as follows: the %{listen:ipaddr} will be the wildcard address and %{Packet-DST-IP-Address} will be the unicast address to which the packet was sent.

%{Packet-Src-Port} and %{Packet-Dst-Port}

The source/destination ports associated with the packet.

Example
update control {
    &Tmp-String-0 := "user@example.com"
}

if (&control:Tmp-String-0 =~ /^(?<login>(.*))@(?<domain>(.*))$/) {
    update reply {
        &Reply-Message := "The %{control:Tmp-String-0} { login=%{regex:login}, domain=%{regex:domain} }"
    }
}
Output
The user@example.com { login=user, domain=example.com }