Regular Expressions
(<subject> =~ /<pattern>/)
(<subject> =~ /<pattern>/[imsux])
(<subject> !~ /<pattern>/)
(<subject> !~ /<pattern>/[imsux])
Matching
The regular expression operators perform regular expression matching
on the data. The <subject>
field can be an attribute reference or data,
as with the other comparison operators. The /<pattern>/
field must be a valid regular expression.
The =~
operator evaluates to true
when data
matches the
/<pattern>/
. Otherwise, it evaluates to false
.
The !~
operator evaluates to true
when data
does not match the
/<pattern>/
. Otherwise, it evaluates to true
.
The regular expression comparison is performed on the string representation
of the left side of the comparison. That is, if the left side is an
integer, the regular expression will behave as if the
value 0
was the literal string "0"
. Similarly, if the left side is an
&Attribute-Name, then the regular expression will behave
as if the attribute was printed to a string, and the match was performed on the
resulting string.
User-Name
attribute contains a realm of example.comif (&User-Name =~ /@example\.com$/) {
...
}
Dialects
The syntax of the regular expression is defined by the regular expression library available on the local system.
FreeRADIUS currently supports:
-
libpcre and libpcre2 both of which provide Perl Compatible Regular expressions.
-
Regex support provided by the local libc implementation, usually Posix regular expressions.
Use the output of ... 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 |
Depending on the regular expression library or libc implementation the server
was built against, the pattern matching function available may not be binary
safe (see If a binary safe regex match function is not available, and a match is
attempted against a subject that contains one or more |
Flags
The regular expression /<pattern>/
may be followed by one or more flag
characters. Again, which flags are available depends on the regular expression
library the server was built with. Multiple flags may be specified per
/pattern/
.
Flag Character | Available with | Effect |
---|---|---|
|
All |
Enable case-insensitive matching. |
|
All |
'^' and '$' match newlines within the subject. |
|
libpcre[2] |
'.' matches anything, including newlines. |
|
libpcre[2] |
Treats subjects as UTF8. Invalid UTF8 sequences will result in the match failing. |
|
libpcre[2] |
Allows comments in expressions by ignoring whitespace, and text between '#' and the next newline character. |
Subcapture groups
When the =~
or !~
operators are used, then parentheses in the regular
expression will sub capture groups, which contain part of the subject string.
The special expansion %{0}
expands to the portion of the subject that
matched. The expansions
%{1}
..%{32}
expand to the contents of any subcapture groups.
When using libpcre[2], named capture groups may also be accessed using the
built-in expansion
%regex(<named capture group>)
.
Please see the xlat documentation for more information on regular expression matching.
if (&User-Name =~ /^(.*)@example\.com$/) {
&reply += {
Reply-Message = "Hello %{1}"
}
}
Dynamic expressions and escaping
If the pattern contains a dynamic expansion, elements of the expansion could potentially affect pattern evaluation in unanticipated ways.
To prevent this, the server will, by default, escape any special characters in the values produced by the dynamic expansion, so that they are treated as literal characters in the regular expression.
To allow non-literals in dynamic elements of regular expressions, wrap any literal
values or expansions in %regex.safe(…)
.
local pattern
switch (realm) {
case example.com {
pattern = %regex.safe('.*\.example\.com')
}
case test.com {
# '.' does not need to be escaped
pattern = 'test.com'
}
}
if (&Stripped-User-Name =~ /^%{pattern}$/) {
...
}
Pre-Compiled vs Runtime Compiled
When the server starts any regular expressions comparisons it finds will be pre-compiled, and if support is available, JIT’d (converted to machine code) to ensure fast execution.
If a pattern contains a dynamic expansion, the pattern cannot be compiled on startup, and will be compiled at runtime each time the expression is evaluated. The server will also turn off JITing for runtime compiled expressions, as the overhead is greater than the time that would be saved during evaluation.
if (&User-Name =~ /^@%{Tmp-String-0}$/) {
...
}
To ensure optimal performance you should limit the number of patterns containing dynamic expansions, and if using PCRE, combine multiple expressions operating on the same subject into a single expression using the PCRE alternation '|' operator.
if (&User-Name =~ /^@(%{Tmp-String-0}|%{Tmp-String-1})$/) {
...
}