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

NOTE: 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 xref:howto:index.adoc[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

xref:unlang/keywords.adoc[Keywords], which are the basic statements of the
language, e.g., xref:unlang/load-balance.adoc[load-balance],
xref:unlang/if.adoc[if], xref:unlang/else.adoc[else], etc.

.Example
[source,unlang]
----
load-balance {
	sql1
	sql2
	sql3
}
----

== Interpreter

The xref:unlang/interpreter.adoc[Interpreter] processes an input
"request" packet, by running policies which contain
xref:unlang/keywords.adoc[Keywords].  The result of the interpretation
is usually an output "reply" packet.

While the interpreter allows some fairly complex policies to be made,
it is not a general purpose programming language.  The purpose of the
language is to receive packets, process their contents, and send
replies.  A secondary goal is to do that as quickly as possible.

== Conditional Expressions

xref:unlang/condition/index.adoc[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.

.Example
[source,unlang]
----
if ((&User-Name == "bob") && (&Calling-Station-Id == "00:01:03:04:05")) {
	...
}
----

== Editing Attributes and lists.

xref:unlang/edit.adoc[Attribute editing] statements are used to edit
attributes and lists of attributes.  The old-style
xref:unlang/update.adoc[update] sections are deprecated, and no longer
supported.

xref:unlang/local.adoc[Local variables] can be defined, so that the
local `dictionary` file no longer needs to be modified.

Most request packets will result in reply packets that contain
additional information for the requester.  Attribute editing allows
policies to add attributes to requests, replies, or to other places.

.Example
[source,unlang]
----
&reply.Session-Timeout := 3600
&reply.Framed-IP-Address := 192.0.2.4
----

== Dynamic Expansions

xref:xlat/index.adoc[Dynamic expansion] Using `%{...}` to perform dynamic
expansions. (also known as xref:xlat/index.adoc[xlat])

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

.Example
[source,unlang]
----
&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
xref:type/index.adoc[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 an
error.

.Example
[source,unlang]
----
&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 a syntax similar to the configuration files.  The
policies can contain comments, whitespace, sections, etc.

Where `unlang` differs from the basic configuration file format is in
its 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 xref:unlang/if.adoc[if] are evaluated
for every packet that is received.  Attribute
xref:unlang/edit.adoc[editing] statements such as can be used to edit
attribute contents or lists of attributes.

.Example
[source,unlang]
----
# First, the keyword 'if'

# followed by condition which checks that the User-Name
# attribute has value "bob"

if (&User-Name == "bob") {
    # followed by instructions to add the Reply-Message
    # attribute to the "reply" list, with contents
    # "Hello, bob"

    &reply.Reply-Message := "Hello, bob"
}
----

// Copyright (C) 2021 Network RADIUS SAS.  Licenced under CC-by-NC 4.0.
// This documentation was developed by Network RADIUS SAS.
