of built-in expansions. These expansions act largely as functions
which operate on inputs, and produce an output.
+
+
== Attribute Manipulation
=== %{length: ... }
}
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}"
+ &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}"
}
----
....
====
+`length` is built in to the server core.
+
+
+
=== %{integer:<&ref>}
Print the value of the attribute an integer.
[source,unlang]
----
update {
- &control.Service-Type := Login-User
+ &control:Service-Type := Login-User
}
update reply {
- &Reply-Message := "The value of Service-Type is %{integer:&control.Service-Type}"
+ &Reply-Message := "The value of Service-Type is %{integer:&control:Service-Type}"
}
----
```
====
+`integer` is built in to the server core.
+
+
+
=== %{rand:<number>}
Generate random number from `0` to `<number>-1`.
```
====
+`rand` is provided by the `rlm_expr` module.
+
+
+
=== %{tag:<attribute ref>}
CAUTION: This expansion is deprecated and will likely be removed.
}
update reply {
- &Reply-Message := "The tag value of the second instance of Tunnel-Server-Enpoint is %{request.Tunnel-Server-Endpoint[1]}"
+ &Reply-Message := "The tag value of the second instance of Tunnel-Server-Enpoint is %{request:Tunnel-Server-Endpoint[1]}"
}
----
```
====
+`tag` is built in to the server core.
+
+
+
=== %{string:<data>}
-Convert input to a string if (possible). For _octets_ type attributes, this
+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.
&Tmp-Octets-0 := 0x7465737431
}
update reply {
- &Reply-Message := "The string value of %{control.Tmp-Octets-0} is %{string:%{control.Tmp-Octets-0}}"
+ &Reply-Message := "The string value of %{control:Tmp-Octets-0} is %{string:%{control:Tmp-Octets-0}}"
}
----
====
The string value of 0x7465737431 is test1
```
+`string` is built in to the server core.
+
+
+
== Server Manipulation
=== %{config:<key>}
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
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.
[source,unlang]
----
authorize {
- if (&request.User-Name == "bob") {
+ if (&request:User-Name == "bob") {
"%{debug:4}"
} else {
"%{debug:0}"
```
...
(0) authorize {
-(0) if (&request.User-Name == "bob") {
+(0) if (&request:User-Name == "bob") {
(0) EXPAND %{debug:4}
(0) --> 2
-(0) } # if (&request.User-Name == "bob") (...)
+(0) } # if (&request:User-Name == "bob") (...)
(0) filter_username {
(0) if (&State) {
(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.
[source,unlang]
----
authorize {
- if (&request.User-Name == "bob") {
+ if (&request:User-Name == "bob") {
"%{debug_attr:request[*]}"
}
...
```
...
(0) authorize {
-(0) if (&request.User-Name == "bob") {
+(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) &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") (...)
+(0) } # if (&request:User-Name == "bob") (...)
...
```
-== String manipulation
-
-=== %{concat:<delim> <&ref:[idx]>}
+`debug_attr` is built in to the server core.
-Used to join two or more attributes, separated by a delimiter.
-.Return: _string_
-
-.Example
-[source,unlang]
-----
-update {
- &control.Tmp-String-0 := "aaa"
- &control.Tmp-String-0 += "bb"
- &control.Tmp-String-0 += "c"
-}
-
-update reply {
- &Reply-Message += "%{concat:, %{control.Tmp-String-0[*]}}"
- &Reply-Message += "%{concat:,%{control.Tmp-String-0[*]}}"
-}
-----
-
-.Output
-
-```
-aaa, bb, c
-aaa,bb,c
-```
+== String manipulation
=== %{lpad:<&ref> <val> <char>}
&Tmp-String-0 := "123"
}
update reply {
- &Reply-Message := "Maximum should be %{lpad:&control.Tmp-String-0 11 0}"
+ &Reply-Message := "Maximum should be %{lpad:&control:Tmp-String-0 11 0}"
}
----
Maximum should be 00000000123
```
+`lpad` is provided by the `rlm_expr` module.
+
+
+
=== %{rpad:<&ref> <val> <char>}
Right-pad a string.
&Tmp-String-0 := "123"
}
update reply {
- &Reply-Message := "Maximum should be %{rpad:&control.Tmp-String-0 11 0}"
+ &Reply-Message := "Maximum should be %{rpad:&control:Tmp-String-0 11 0}"
}
----
Maximum should be 12300000000
```
+`rpad` is provided by the `rlm_expr` module.
+
+
+
=== %{pairs:<&list:[*]>}
Serialize attributes as comma-delimited string.
[source,unlang]
----
update {
- &control.Tmp-String-0 := "This is a string"
- &control.Tmp-String-0 += "This is another one"
+ &control:Tmp-String-0 := "This is a string"
+ &control:Tmp-String-0 += "This is another one"
}
update reply {
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.
The random string output is 4Uq0gPyG
```
+`randstr` is provided by the `rlm_expr` module.
+
+
+
=== %{strlen: ... }
Length of given string.
&Tmp-String-0 := "Caipirinha"
}
update reply {
- &Reply-Message := "The length of %{control.Tmp-String-0} is %{strlen:&control.Tmp-String-0}"
+ &Reply-Message := "The length of %{control:Tmp-String-0} is %{strlen:&control:Tmp-String-0}"
}
----
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
&Tmp-String-0 := "CAIPIRINHA"
}
update reply {
- &Reply-Message := "tolower of %{control.Tmp-String-0} is %{tolower:%{control.Tmp-String-0}}"
+ &Reply-Message := "tolower of %{control:Tmp-String-0} is %{tolower:%{control:Tmp-String-0}}"
}
----
tolower of CAIPIRINHA is caipirinha
```
+`tolower` is provided by the `rlm_expr` module.
+
+
+
=== %{toupper: ... }
Dynamically expands the string and returns the uppercase version of
&Tmp-String-0 := "caipirinha"
}
update reply {
- &Reply-Message := "toupper of %{control.Tmp-String-0} is %{toupper:%{control.Tmp-String-0}}"
+ &Reply-Message := "toupper of %{control:Tmp-String-0} is %{toupper:%{control:Tmp-String-0}}"
}
----
toupper of caipirinha is CAIPIRINHA
```
+`toupper` is provided by the `rlm_expr` module.
+
+
+
== String Conversion
=== %{base64: ... }
&Tmp-String-0 := "Caipirinha"
}
update reply {
- &Reply-Message := "The base64 of %{control.Tmp-String-0} is %{base64:%{control.Tmp-String-0}}"
+ &Reply-Message := "The base64 of %{control:Tmp-String-0} is %{base64:%{control:Tmp-String-0}}"
}
----
The base64 of foo is Q2FpcGlyaW5oYQ==
```
-=== %{base64decode: ... }
+`base64` is provided by the `rlm_expr` module.
+
+
+
+=== %{base64tohex: ... }
-Decode a string previously encoded using Base64.
+Decode a base64 string (e.g. previously encoded using `base64`) to
+hex.
.Return: _string_
&Tmp-String-0 := "Q2FpcGlyaW5oYQ=="
}
update reply {
- &Reply-Message := "The base64decode of %{control.Tmp-String-0} is %{base64decode:%{control.Tmp-String-0}}"
+ &Reply-Message := "The base64tohex of %{control:Tmp-String-0} is %{base64tohex:%{control:Tmp-String-0}}"
}
----
.Output
```
-The base64decode of Q2FpcGlyaW5oYQ== is Caipirinha
+The base64decode of Q2FpcGlyaW5oYQ== is 436169706972696e6861
```
-=== %{bin: ... }
+`base64tohex` is provided by the `rlm_expr` module.
-Convert string to binary.
-.Return: _octal_
-
-.Example
-
-[source,unlang]
-----
-update control {
- &Tmp-String-0 := "10"
-}
-update reply {
- &Reply-Message := "The %{control.Tmp-String-0} in binary is %{bin:%{control.Tmp-String-0}}"
-}
-----
-
-.Output
-
-```
-The 10 in binary is \020
-```
=== %{hex: ... }
&Tmp-String-0 := "12345"
}
update reply {
- &Reply-Message := "The value of %{control.Tmp-String-0} in hex is %{hex:%{control.Tmp-String-0}}"
+ &Reply-Message := "The value of %{control:Tmp-String-0} in hex is %{hex:%{control:Tmp-String-0}}"
}
----
The value of 12345 in hex is 3132333435
```
+`hex` is built in to the server core.
+
+
+
=== %{urlquote: ... }
Quote URL special characters.
[source,unlang]
----
update {
- &control.Tmp-String-0 := "http://example.org/"
+ &control:Tmp-String-0 := "http://example.org/"
}
update reply {
- &Reply-Message += "The urlquote of %{control.Tmp-String-0} is %{urlquote:%{control.Tmp-String-0}}"
+ &Reply-Message += "The urlquote of %{control:Tmp-String-0} is %{urlquote:%{control:Tmp-String-0}}"
}
----
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.
[source,unlang]
----
update {
- &control.Tmp-String-0 := "http%%3A%%2F%%2Fexample.org%%2F" # Attention for the double %.
+ &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}}"
+ &Reply-Message += "The urlunquote of %{control:Tmp-String-0} is %{urlunquote:%{control:Tmp-String-0}}"
}
----
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>}
[source,unlang]
----
update {
- &control.Tmp-String-0 := "mykey"
- &control.Tmp-String-1 := "Caipirinha"
+ &control:Tmp-String-0 := "mykey"
+ &control:Tmp-String-1 := "Caipirinha"
}
update {
- &control.Tmp-Octets-0 := "%{hmacmd5:%{control.Tmp-String-0} %{control.Tmp-String-1}}"
+ &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}"
+ &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}"
}
----
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.
[source,unlang]
----
update {
- &control.Tmp-String-0 := "mykey"
- &control.Tmp-String-1 := "Caipirinha"
+ &control:Tmp-String-0 := "mykey"
+ &control:Tmp-String-1 := "Caipirinha"
}
update {
- &control.Tmp-Octets-0 := "%{hmacsha1:%{control.Tmp-String-0} %{control.Tmp-String-1}}"
+ &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}"
+ &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}"
}
----
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
&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}}}"
+ &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}}}"
}
----
md5 of Caipirinha is hex=14840b6d647c7c98a3e732f833d86ea9
```
-=== Other Hashing Functions
-
-The following hashes are supported for all versions of OpenSSL.
-
-* `%{md2: ... }`
-* `%{md4: ... }`
-* `%{md5: ... }`
-* `%{sha1: ... }`
-* `%{sha224: ... }`
-* `%{sha256: ... }`
-* `%{sha384: ... }`
-* `%{sha512: ... }`
-
-The following hashes are supported for when OpenSSL 1.1.1 or greater
-is installed. This version adds support for the `sha3` and `blake`
-families of digest functions.
-
-* `%{blake2s_256: ... }`
-* `%{blake2b_512: ... }`
-* `%{sha2_224: ... }`
-* `%{sha2_256: ... }`
-* `%{sha2_384: ... }`
-* `%{sha2_512: ... }`
-* `%{sha3_224: ... }`
-* `%{sha3_256: ... }`
-* `%{sha3_384: ... }`
-* `%{sha3_512: ... }`
-
-.Return: _octal_
-
-.Example
-
-[source,unlang]
-----
-update {
- &control.Tmp-String-0 := "Caipirinha"
-}
-update reply {
- &Reply-Message := "The md5 of %{control.Tmp-String-0} in octal is %{md5:%{control.Tmp-String-0}}"
- &Reply-Message += "The md5 of %{control.Tmp-String-0} in hex is %{hex:%{md5:%{control.Tmp-String-0}}}"
-}
-----
+`md5` is provided by the `rlm_expr` module.
-.Output
-```
-The md5 of Caipirinha in octal is \024\204\013md||\230\243\3472\3703\330n\251
-The md5 of Caipirinha in hex is 14840b6d647c7c98a3e732f833d86ea9
-```
== Miscellaneous Expansions
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.
....
====
+`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`).
You should wait for 2520s
```
-=== +%{pack:%{Attribute-Name}%{Attribute-Name}...}+
-
-Pack multiple multiple attributes and/or literals into a binary string.
-For best results, each attribute passed to `pack` should be fixed size.
-That is, not data type `octets` or `string` as the length of those values
-will not be encoded.
-
-See also the `unpack` module, which is the inverse to `pack`.
-
-.Return: _octets_
+`nexttime` is provided by the `rlm_expr` module.
-.Example:
-
-[source,unlang]
-----
-update reply {
- &Class := "%{pack:%{reply.Framed-IP-Address}%{NAS-IP-Address}}"
-}
-----
-
-.Output
-```
-You should wait for 2520s
-```
=== +%{Packet-Type}+
The packet type (`Access-Request`, etc.)
-=== +%{Packet-SRC-IP-Address} and %{Packet-SRC-IPv6-Address}+
+
+
+=== +%{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}+
+
+
+=== +%{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
address and `%{Packet-DST-IP-Address}` will be the unicast address to
which the packet was sent.
-=== +%{Packet-SRC-Port} and %{Packet-DST-Port}+
+
+
+=== +%{Packet-Src-Port} and %{Packet-Dst-Port}+
The source/destination ports associated with the packet.
&Tmp-String-0 := "user@example.com"
}
-if (&control.Tmp-String-0 =~ /^(?<login>(.*))@(?<domain>(.*))$/) {
+if (&control:Tmp-String-0 =~ /^(?<login>(.*))@(?<domain>(.*))$/) {
update reply {
- &Reply-Message := "The %{control.Tmp-String-0} { login=%{regex:login}, domain=%{regex:domain} }"
+ &Reply-Message := "The %{control:Tmp-String-0} { login=%{regex:login}, domain=%{regex:domain} }"
}
}
----