Unlang Policy Language
The server supports a simple processing language called "Unlang",
which is short for "un-language". The original intention of using an
"un-language" was to avoid creating yet another programming language.
Instead, the unlang
syntax allows for simple if / then / else
checks, and attribute editing. It does not support recursion,
subroutines, or more complex flow controls.
Where more complicated functionality is required, we recommend using
the lua
, perl
or python
modules. Those modules allow the insertion of
full-featured scripts at any point in the packet processing.
The documentation is this directory is reference
documentation. That is, it describes the syntax of unlang keywords,
using minimal examples. The reference documentation does not,
however, describe when to use the keywords, or how to create
policies. Please see the howto directory for
more in-depth "how to" guides.
|
The documentation is organized so that each item is on its own page.
The page beings with a description of the item, followed by some text
explaining what the item does. The page concludes with one or more
examples of using the item in unlang
policies.
The unlang
processing can be split into some high-level concepts.
Keywords
Keywords, which are the basic statements of the language, e.g., load-balance, if, else, etc.
load-balance {
sql1
sql2
sql3
}
Conditional Expressions
Conditional expressions, which are used to check if conditions evaluate to true or false. Conditional expressions can be used to control the flow of processing.
if ((&User-Name == "bob") && (&Calling-Station-Id == "00:01:03:04:05")) {
...
}
Update Statements
update statements are used to edit attributes and lists of attributes.
Most request packets will result in reply packets that contain
additional information for the requestor. The update
section allows
policies to add attributes to requests, replies, or to other places.
update reply {
&Session-Timeout := 3600
&Framed-IP-Address := 192.0.2.4
}
String Expansions
String expansion Using %{…}
to perform dynamic
string expansions. (also known as xlat)
String expansions are usually performed in order to get additional information which is not immediately available to the policy. This information can be taken from almost any source, including other attributes, databases, and scripts.
update reply {
&Framed-IP-Address := "%{sql:SELECT static_ip from table WHERE user = '%{User-Name}'}"
}
Data Types
Each attribute used by the server has an associated
data type. The unlang
interpreter enforces
restrictions on assignments, so that only valid data types can be
assigned to an attribute. Invalid assignments result in a run-time
error.
update reply {
&Framed-IP-Address := 192.0.2.4
&Session-Timeout := 5
&Reply-Message := "hello"
}
Design Goals of Unlang
The goal of unlang
is to allow simple policies to be written with
minimal effort. Conditional checks can be performed by the policies,
which can then update the request or response attributes based on the
results of those checks. unlang
can only be used in a processing
section, it cannot be used anywhere else, including in configuration
sections for a client or a module. The reason for this limitation is
that the language is intended to perform specific actions on requests
and responses. The client and module sections contain definitions for
a client or module; they do not define how a request is processed.
unlang
uses the same the basic syntax as the configuration files.
The syntax of the configuration file for lines, comments, sections,
sub-section, etc., all apply to unlang
.
Where unlang
differs from the basic configuration file format is in
complexity and operation. The normal configuration files are
declarative and they are static. That is, they declare variables
and values for those variables. Those values do not change when the
server is running.
In contrast, unlang
performs run-time processing of requests.
Conditional statements such as if are evaluated for every
packet that is received. Attribute editing statements such as
update can be used to edit attribute contents or lists
of attributes.
# First, the keyword 'if'
# followed by condition which checks that the User-Name
# attribute has value "bob"
if (&User-Name == "bob") {
# keyword "update"
# followed by instructions to add the Reply-Message
# attribute to the "reply" list, with contents
# "Hello, bob"
update reply {
Reply-Message := "Hello, bob"
}
}