erl -p -i -e 's/^&//' $(git grep -lE '^&|[^&]&[a-zA-Z]' doc/antora/modules | egrep -v 'raddb|developers|interpreter.adoc|assets')
Instead of doing:
```
-&Reply-Message += "foo"
+Reply-Message += "foo"
```
you should edit the `reply` list, using the `+=` operator:
```
-&reply += {
+reply += {
&Reply-Message = "foo"
}
```
In v4, you can remove the `update`, and rewrite the SQL call to:
```
-&reply.Framed-IP-Address := %sql("SELECT ...")
+reply.Framed-IP-Address := %sql("SELECT ...")
```
Using double quotes everywhere means that every bit of data gets
natively. For example:
```
-&Reply-Message := "1 + 2 = %{1 + 2}"
+Reply-Message := "1 + 2 = %{1 + 2}"
```
will return the string `1 + 2 = 3`. The contents of the expansion can
still available, so
```
-&control.LDAP-Group[*] == "foo"
+control.LDAP-Group[*] == "foo"
```
can also be used to test membership after having called the `ldap` module,
if `cacheable_name` or `cacheable_dn` are enabled.
[source,unlang]
----
-&reply.Reply-Message := &User-Name
+reply.Reply-Message := &User-Name
...
# U == user
# e == expired
-&control.SMB-Account-Ctrl-Text := '[Ue]'
+control.SMB-Account-Ctrl-Text := '[Ue]'
```
This will cause the client to receive `error 648 - password expired`.
.Example Copying Attributes
[source,unlang]
----
-&control.Reply-Message := { "one", "two" }
+control.Reply-Message := { "one", "two" }
-&reply.Reply-Message := &control.Reply-Message[*]
+reply.Reply-Message := &control.Reply-Message[*]
----
The following example will take an input string `"192.168.0.1"`, split
.Example Creating multiple Attributes
----
-&Tmp-Integer-0 := %explode("192.168.0.1", '.')
+Tmp-Integer-0 := %explode("192.168.0.1", '.')
----
If you need to cast an entire list to a value, then the value being
.Example Creating multiple Attributes
----
-&reply.Reply-Message := (string) (%explode("192.168.0.1", '.'))
+reply.Reply-Message := (string) (%explode("192.168.0.1", '.'))
----
=== Other Data Types
.Syntax
[source,unlang]
----
-&Attribute-Name
+Attribute-Name
----
The `Attribute-Name` operator returns a reference to the named
.Examples
[source,unlang]
----
-&User-Name
-&NAS-IP-Address
+User-Name
+NAS-IP-Address
----
== Lists
[source,unlang]
----
-&request.User-Name
-&reply.NAS-IP-Address
+request.User-Name
+reply.NAS-IP-Address
----
== Array References
.Syntax
[source,unlang]
----
-&Attribute-Name[<index>]
+Attribute-Name[<index>]
----
When an attribute appears multiple times in a list, this syntax allows
.Integer Array index
[source,unlang]
----
-&EAP-Message[1]
-&reply.NAS-IP-Address[2]
+EAP-Message[1]
+reply.NAS-IP-Address[2]
----
The `<index>` can also be a special value `n`, which means "the last attribute in the list.
.Last attribute in a list
[source,unlang]
----
-&EAP-Message[n]
+EAP-Message[n]
----
The `<index>` can also be a reference to a numerical attribute.
----
uint32 foo
-&foo = 2
+foo = 2
-&EAP-Message[&foo]
+EAP-Message[&foo]
----
The `<index>` can also be an expression which is calculated at run time. The expression _must_ not cause the server to call an external database, script, etc. The main purpose of these expressions is to calculated an index without first placing it into another attribute.
.Expression as an Array index
[source,unlang]
----
-&index = 0
+index = 0
-&EAP-Message[%{&index + 1}]
+EAP-Message[%{&index + 1}]
----
=== Array References in lists
.Examples
[source,unlang]
----
-&request.[0]
+request.[0]
----
i.e. "the first child of the `request` list.
.Syntax
[source,unlang]
----
-&Attribute-Name.Attribute-Name
+Attribute-Name.Attribute-Name
----
In some cases, attributes are nested or grouped. The child reference
[source,unlang]
----
-&TLV-One.Child-one
-&TLV-One.Child-one.Child-Three
-&reply.TLV[3].Child-Two
+TLV-One.Child-one
+TLV-One.Child-one.Child-Three
+reply.TLV[3].Child-Two
----
== Putting it All Together
.Examples
[source,unlang]
----
-&TLV-One.Child-one[3].Child-Three
-&reply.TLV[3].Child-Two
+TLV-One.Child-one[3].Child-Three
+reply.TLV[3].Child-Two
----
== Compatibility with Older Versions of FreeRADIUS
.Syntax
[source,unlang]
----
-&attribute := <expression>
-&attribute = <expression>
-&attribute += <expression>
-&attribute -= <expression>
+attribute := <expression>
+attribute = <expression>
+attribute += <expression>
+attribute -= <expression>
...
-&list1 := &list2
-&list1 += { &attribute = value, ... }
-&list1 += " attribute = value, ... "
+list1 := &list2
+list1 += { &attribute = value, ... }
+list1 += " attribute = value, ... "
...
----
.Syntax
[source,unlang]
----
-&<list> <op> <rhs>
+<list> <op> <rhs>
----
List editing can be done for the usual xref:reference:unlang/list.adoc[lists] such as `request`,
====
[source,unlang]
----
-&reply := {}
+reply := {}
----
====
====
[source,unlang]
----
-&reply += {
+reply += {
&Filter-Id = "foo"
}
----
====
[source,unlang]
----
-&reply += &request.User-Name
+reply += &request.User-Name
----
====
====
[source,unlang]
----
-&reply := {
+reply := {
&Filter-Id = "foo"
}
----
====
[source,unlang]
----
-&reply -= &Filter-Id
+reply -= &Filter-Id
----
====
====
[source,unlang]
----
-&reply -= &Filter-Id[*]
+reply -= &Filter-Id[*]
----
====
====
[source,unlang]
----
-&reply -= {
+reply -= {
&Filter-Id == "bar"
}
----
====
[source,unlang]
----
-&reply := &request
+reply := &request
----
====
====
[source,unlang]
----
-&reply += &request
+reply += &request
----
====
====
[source,unlang]
----
-&reply += "Filter-Id = 'foo'"
+reply += "Filter-Id = 'foo'"
----
====
====
[source,unlang]
----
-&reply += "sql("SELECT pairs FROM pair_table WHERE username = '%{User-Name}'")
+reply += "sql("SELECT pairs FROM pair_table WHERE username = '%{User-Name}'")
----
====
.Syntax
[source,unlang]
----
-&<attribute> <op> <rhs>
+<attribute> <op> <rhs>
----
Attribute editing can be done for any
.Expression in an assignment
[source,unlang]
----
-&NAS-Port = 1 + 2
+NAS-Port = 1 + 2
----
== Operators in an Expression
[source,unlang]
----
-&NAS-Port = 5 + (&User-Name == "bob")
+NAS-Port = 5 + (&User-Name == "bob")
----
This expression will return `6` if the users name is `bob`, and `5` otherwise.
[source,unlang]
----
-&Filter-Id = "Adding %{NAS-Port} + 4 = %{&NAS-Port + 4}"
+Filter-Id = "Adding %{NAS-Port} + 4 = %{&NAS-Port + 4}"
----
The old ``%{expr:...}` syntax will return an error in v4. That functiuonality is no longer supported.
[source,unlang]
----
-&Reply-Message := "foo" + "bar"
+Reply-Message := "foo" + "bar"
----
Will result in `Reply-Message == "foobar"`.
[source,unlang]
----
-&Reply-Message -= "bar"
+Reply-Message -= "bar"
----
Will result in `Reply-Message == "foo"` !.
[source,unlang]
----
-&NAS-Port-Id = (uint32) "%sql("SELECT...") + 4
+NAS-Port-Id = (uint32) "%sql("SELECT...") + 4
----
== Errors
[source,unlang]
----
-&NAS-Port-Id = (5 - "foo") || 6
+NAS-Port-Id = (5 - "foo") || 6
----
Will return `6`, as the left side expression of the `||` operator evaluates to `null`.
.Example of modifying values
[source,unlang]
----
-&Tmp-Integer-0 := { 1, 3, 5, 11 }
+Tmp-Integer-0 := { 1, 3, 5, 11 }
foreach self (&Tmp-Integer-0) {
&self += 19
[source,unlang]
----
-&Tmp-Integer-0 := { 20, 22, 24, 30 }
+Tmp-Integer-0 := { 20, 22, 24, 30 }
----
.Pseudocode for variable modification
[source,unlang]
----
string total
-&Tmp-Integer-0 := { 1, 3, 5, 11 }
+Tmp-Integer-0 := { 1, 3, 5, 11 }
foreach string ref, uint32 self (Tmp-Integer-0) {
total += ref
.Example
[source,unlang]
----
-&reply.Session-Timeout := 3600
-&reply.Framed-IP-Address := 192.0.2.4
+reply.Session-Timeout := 3600
+reply.Framed-IP-Address := 192.0.2.4
----
== Dynamic Expansions
.Example
[source,unlang]
----
-&reply.Framed-IP-Address := %sql("SELECT static_ip from table WHERE user = '%{User-Name}'")
+reply.Framed-IP-Address := %sql("SELECT static_ip from table WHERE user = '%{User-Name}'")
----
== Data Types
.Example
[source,unlang]
----
-&reply += {
+reply += {
&Framed-IP-Address = 192.0.2.4
&Session-Timeout = 5
&Reply-Message = "hello"
.Example of Load-Balance SQL module
[source,unlang]
----
-&Reply-Message := %sql_all("SELECT message FROM table WHERE name='%{User-Name}'")
+Reply-Message := %sql_all("SELECT message FROM table WHERE name='%{User-Name}'")
}
----
.Example of Redundant-Load-Balance SQL module
[source,unlang]
----
-&Reply-Message := %sql_all("SELECT message FROM table WHERE name='%{User-Name}'")
+Reply-Message := %sql_all("SELECT message FROM table WHERE name='%{User-Name}'")
}
----
.Example of Redundant SQL module
[source,unlang]
----
-&Reply-Message := %sql_all("SELECT message FROM table WHERE name='%{User-Name}'")
+Reply-Message := %sql_all("SELECT message FROM table WHERE name='%{User-Name}'")
----
The one caveat here is that the arguments passed to the underlying
[source,unlang]
----
-&request += {
+request += {
&User-Name = "foo"
&Filter-Id = "bar"
&NAS-IP-Address = 127.0.0.1
[source,unlang]
----
-&request.User-Name := "foo"
-&request.Filter-Id := "bar"
+request.User-Name := "foo"
+request.Filter-Id := "bar"
----
Note that the following conversion is _not_ correct, as it will
[source,unlang]
----
-&request := {
+request := {
&User-Name = "foo"
&Filter-Id = "bar"
}
[source,unlang]
----
-&request.User-Name = "foo"
-&request.Filter-Id = "bar"
+request.User-Name = "foo"
+request.Filter-Id = "bar"
----
=== Removing Attributes from a list: !*
[source,unlang]
----
-&request -= &User-Name
+request -= &User-Name
----
== More Complex Conversions
.Old Style - no longer supported
[source,unlang]
----
-&Reply-Message := "Hello %{%{User-Name}:-none}"
+Reply-Message := "Hello %{%{User-Name}:-none}"
----
.New Alternation
[source,unlang]
----
-&Reply-Message := "Hello %{&User-Name || 'none'}"
+Reply-Message := "Hello %{&User-Name || 'none'}"
----
This approach also means that nested alternation is no longer necessary:
.Old Style - no longer supported
[source,unlang]
----
-&Reply-Message := "Hello %{%{NAS-Identifer}:-%{%{User-Name}:-none}}"
+Reply-Message := "Hello %{%{NAS-Identifer}:-%{%{User-Name}:-none}}"
----
.New Alternation
[source,unlang]
----
-&Reply-Message := "Hello %{&NAS-Identifier || &User-Name || 'none'}"
+Reply-Message := "Hello %{&NAS-Identifier || &User-Name || 'none'}"
----
[NOTE]
====
[source,unlang]
----
-&Tmp-String-0 := "Caipirinha"
-&Framed-IP-Address := 192.0.2.1
+Tmp-String-0 := "Caipirinha"
+Framed-IP-Address := 192.0.2.1
-&reply += {
+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)"
}
====
[source,unlang]
----
-&reply.Reply-Message := "The random number is %rand(512}"
+reply.Reply-Message := "The random number is %rand(512}"
----
.Output
&request.Tmp-String-0 := "not bob!"
}
-&reply.Reply-Message := "%eval(&request.Tmp-String-0}"
+reply.Reply-Message := "%eval(&request.Tmp-String-0}"
----
.Output when `User-Name == bob`
[source,unlang]
----
-&reply.Reply-Message := "You should wait for %nexttime(1h)s"
+reply.Reply-Message := "You should wait for %nexttime(1h)s"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "Caipirinha is a light and refreshing drink!"
-&reply.Reply-Message := "%sub(%{control.Tmp-String-0}, / /, ',')"
+control.Tmp-String-0 := "Caipirinha is a light and refreshing drink!"
+reply.Reply-Message := "%sub(%{control.Tmp-String-0}, / /, ',')"
----
.Output
[source,unlang]
----
-&Acct-Start-Time := %time(now)
+Acct-Start-Time := %time(now)
----
The current time can also be compared to a known date:
[source,unlang]
----
-&control += {
+control += {
&Tmp-String-0 = "aaa"
&Tmp-String-0 = "bb"
&Tmp-String-0 = "c"
}
-&reply += {
+reply += {
&Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ', ')"
&Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ',')"
}
----
string foo
-&foo += { "a", "c", "c", "d" } # abcd
+foo += { "a", "c", "c", "d" } # abcd
-&foo += &control.Tmp-String-0[*]
+foo += &control.Tmp-String-0[*]
----
// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
[source,unlang]
----
-&control.Tmp-String-0 := "Caipirinha"
-&reply.Reply-Message := "The base64 of %{control.Tmp-String-0} is %base64.encode(%{control.Tmp-String-0})"
+control.Tmp-String-0 := "Caipirinha"
+reply.Reply-Message := "The base64 of %{control.Tmp-String-0} is %base64.encode(%{control.Tmp-String-0})"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "Q2FpcGlyaW5oYQ=="
-&reply.Reply-Message := "The base64.decode of %{control.Tmp-String-0} is %base64.decode(%{control.Tmp-String-0})"
+control.Tmp-String-0 := "Q2FpcGlyaW5oYQ=="
+reply.Reply-Message := "The base64.decode of %{control.Tmp-String-0} is %base64.decode(%{control.Tmp-String-0})"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "10"
-&reply.Reply-Message := "The %{control.Tmp-String-0} in binary is %bin(%{control.Tmp-String-0})"
+control.Tmp-String-0 := "10"
+reply.Reply-Message := "The %{control.Tmp-String-0} in binary is %bin(%{control.Tmp-String-0})"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "12345"
-&reply.Reply-Message := "The value of %{control.Tmp-String-0} in hex is %hex(%{control.Tmp-String-0})"
+control.Tmp-String-0 := "12345"
+reply.Reply-Message := "The value of %{control.Tmp-String-0} in hex is %hex(%{control.Tmp-String-0})"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "http://example.org/"
-&reply += {
+control.Tmp-String-0 := "http://example.org/"
+reply += {
&Reply-Message = "The urlquote of %{control.Tmp-String-0} is %urlquote(%{control.Tmp-String-0})"
}
----
[source,unlang]
----
-&control.Tmp-String-0 := "http%%3A%%2F%%2Fexample.org%%2F" # Attention for the double %.
-&reply += {
+control.Tmp-String-0 := "http%%3A%%2F%%2Fexample.org%%2F" # Attention for the double %.
+reply += {
&Reply-Message = "The urlunquote of %{control.Tmp-String-0} is %urlunquote(%{control.Tmp-String-0})"
}
----
[source,unlang]
----
-&reply.Reply-Message := "The 1 + 2 = %{1 + 2}"
+reply.Reply-Message := "The 1 + 2 = %{1 + 2}"
----
== %integer(...)
[source,unlang]
----
-&reply.Reply-Message := "Value of Service-Type is %{(integer) &Service-Type}"
+reply.Reply-Message := "Value of Service-Type is %{(integer) &Service-Type}"
----
=== +%pack(%{Attribute-Name}%{Attribute-Name}...)+
[source,unlang]
----
-&reply.Class := "%pack(%{reply.Framed-IP-Address}%{NAS-IP-Address}}"
+reply.Class := "%pack(%{reply.Framed-IP-Address}%{NAS-IP-Address}}"
----
It is easier to just use casting and string append:
[source,unlang]
----
-&reply.Class := (octets) &Framed-IP-Address + (octets) &NAS-IP-Address.
+reply.Class := (octets) &Framed-IP-Address + (octets) &NAS-IP-Address.
----
== %string(...)
[source,unlang]
----
-&reply.Reply-Message := "The printable version of Class is %{(string) &Class}"
+reply.Reply-Message := "The printable version of Class is %{(string) &Class}"
----
== %strlen( ... )
[source,unlang]
----
-&control += {
+control += {
&Tmp-String-0 = "aaa"
&Tmp-String-0 = "bb"
&Tmp-String-0 = "c"
}
-&reply += {
+reply += {
&Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ', ')"
&Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ',')"
}
----
string foo
-&foo += { "a", "c", "c", "d" } # abcd
+foo += { "a", "c", "c", "d" } # abcd
-&foo += &control.Tmp-String-0[*]
+foo += &control.Tmp-String-0[*]
----
== %explode(<&ref>, <delim>)
[source,unlang]
----
-&control.Tmp-String-0 := "bob.toba@domain.com"
+control.Tmp-String-0 := "bob.toba@domain.com"
-&control.Tmp-String-1 := "%explode(&control.Tmp-String-0, '@')"
+control.Tmp-String-1 := "%explode(&control.Tmp-String-0, '@')"
-&reply.Reply-Message := "Welcome %{control.Tmp-String-1[0]}"
+reply.Reply-Message := "Welcome %{control.Tmp-String-1[0]}"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "123"
+control.Tmp-String-0 := "123"
-&reply.Reply-Message := "Maximum should be %lpad(%{control.Tmp-String-0}, 11, '0')"
+reply.Reply-Message := "Maximum should be %lpad(%{control.Tmp-String-0}, 11, '0')"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "123"
+control.Tmp-String-0 := "123"
-&reply.Reply-Message := "Maximum should be %rpad(%{control.Tmp-String-0}, 11, '0')"
+reply.Reply-Message := "Maximum should be %rpad(%{control.Tmp-String-0}, 11, '0')"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := { "This is a string", "This is another one" }
-&reply.Reply-Message := "Serialize output: %pairs(&control.[*])"
+control.Tmp-String-0 := { "This is a string", "This is another one" }
+reply.Reply-Message := "Serialize output: %pairs(&control.[*])"
----
.Output
[source,unlang]
----
-&reply.Reply-Message := "The random string output is %randstr(aaaaaaaa}"
+reply.Reply-Message := "The random string output is %randstr(aaaaaaaa}"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "CAIPIRINHA"
-&reply.Reply-Message := "tolower of %{control.Tmp-String-0} is %tolower(%{control.Tmp-String-0})"
+control.Tmp-String-0 := "CAIPIRINHA"
+reply.Reply-Message := "tolower of %{control.Tmp-String-0} is %tolower(%{control.Tmp-String-0})"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "caipirinha"
-&reply.Reply-Message := "toupper of %{control.Tmp-String-0} is " + %toupper(%{control.Tmp-String-0})
+control.Tmp-String-0 := "caipirinha"
+reply.Reply-Message := "toupper of %{control.Tmp-String-0} is " + %toupper(%{control.Tmp-String-0})
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "bob.toba@domain.com"
+control.Tmp-String-0 := "bob.toba@domain.com"
-&control.Tmp-String-1 := "%explode(&control.Tmp-String-0, '@')"
+control.Tmp-String-1 := "%explode(&control.Tmp-String-0, '@')"
-&reply.Reply-Message := "Welcome %{control.Tmp-String-1[0]}"
+reply.Reply-Message := "Welcome %{control.Tmp-String-1[0]}"
----
.Output
====
[source,unlang]
----
-&filename = "${logdir}/" + %file.escape(%{User-Name})
+filename = "${logdir}/" + %file.escape(%{User-Name})
%exec("/bin/rm", %{filename})
----
----
string line
-&line := %file.head("/var/log/radius.log")
+line := %file.head("/var/log/radius.log")
----
====
----
string line
-&line := %file.tail("/var/log/radius.log")
+line := %file.tail("/var/log/radius.log")
-&line := %file.tail("/var/log/radius.log", 2)
+line := %file.tail("/var/log/radius.log", 2)
----
====
.Examples
[source,unlang]
----
-&reply.Reply-Message := %sql(SELECT name FROM mytable WHERE username = %{User-Name})
+reply.Reply-Message := %sql(SELECT name FROM mytable WHERE username = %{User-Name})
----
// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
[source,unlang]
----
-&control.Tmp-String-0 := "mykey"
-&control.Tmp-String-1 := "Caipirinha"
-&reply.control.Tmp-Octets-0 := "%hmacmd5(%{control.Tmp-String-0} %{control.Tmp-String-1})"
+control.Tmp-String-0 := "mykey"
+control.Tmp-String-1 := "Caipirinha"
+reply.control.Tmp-Octets-0 := "%hmacmd5(%{control.Tmp-String-0} %{control.Tmp-String-1})"
-&reply += {
+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)"
}
[source,unlang]
----
-&control.Tmp-String-0 := "mykey"
-&control.Tmp-String-1 := "Caipirinha"
-&control.Tmp-Octets-0 := "%hmacsha1(%{control.Tmp-String-0}, %{control.Tmp-String-1})"
+control.Tmp-String-0 := "mykey"
+control.Tmp-String-1 := "Caipirinha"
+control.Tmp-Octets-0 := "%hmacsha1(%{control.Tmp-String-0}, %{control.Tmp-String-1})"
-&reply += {
+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}"
}
[source,unlang]
----
-&control.Tmp-String-0 := "Caipirinha"
-&reply += {
+control.Tmp-String-0 := "Caipirinha"
+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}))"
}
[source,unlang]
----
-&control.Tmp-String-0 := "Caipirinha"
-&reply += {
+control.Tmp-String-0 := "Caipirinha"
+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}}}"
}
[source,unlang]
----
-&Reply-Message := "%{User-Name} with a literal %%"
+Reply-Message := "%{User-Name} with a literal %%"
----
// Copyright (C) 2021 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
[source,unlang]
----
-&control.Tmp-String-0 := "123"
+control.Tmp-String-0 := "123"
-&reply.Reply-Message := "Maximum should be %lpad(%{control.Tmp-String-0}, 11, '0')"
+reply.Reply-Message := "Maximum should be %lpad(%{control.Tmp-String-0}, 11, '0')"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := { "This is a string", "This is another one" }
-&reply.Reply-Message := "Serialize output: %pairs(&control.[*])"
+control.Tmp-String-0 := { "This is a string", "This is another one" }
+reply.Reply-Message := "Serialize output: %pairs(&control.[*])"
----
.Output
.Output
```
-&Relay-Agent-Information.Circuit-Id = 0xabcdef, &Relay-Agent-Information.Remote-Id = 0x010203040506
-&User-Name = "ABCD"
+Relay-Agent-Information.Circuit-Id = 0xabcdef, &Relay-Agent-Information.Remote-Id = 0x010203040506
+User-Name = "ABCD"
```
== %PROTO.encode(_list_)
----
%dhcpv4.encode("&Relay-Agent-Information.Circuit-Id = 0xabcdef, &Relay-Agent-Information.Remote-Id = 0x010203040506")
%radius.encode("&User-Name = 'ABCD'")
-&Tmp-Octets-1 := %dhcpv4.encode(&request.Relay-Agent-Information.[*])
+Tmp-Octets-1 := %dhcpv4.encode(&request.Relay-Agent-Information.[*])
----
.Output
[source,unlang]
----
-&reply.Reply-Message := "The random string output is %randstr(8a)"
+reply.Reply-Message := "The random string output is %randstr(8a)"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "123"
+control.Tmp-String-0 := "123"
-&reply.Reply-Message := "Maximum should be %rpad(%{control.Tmp-String-0}, 11, '0')"
+reply.Reply-Message := "Maximum should be %rpad(%{control.Tmp-String-0}, 11, '0')"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "CAIPIRINHA"
-&reply.Reply-Message := "tolower of %{control.Tmp-String-0} is %tolower(%{control.Tmp-String-0})"
+control.Tmp-String-0 := "CAIPIRINHA"
+reply.Reply-Message := "tolower of %{control.Tmp-String-0} is %tolower(%{control.Tmp-String-0})"
----
.Output
[source,unlang]
----
-&control.Tmp-String-0 := "caipirinha"
-&reply.Reply-Message := "toupper of %{control.Tmp-String-0} is " + %toupper(%{control.Tmp-String-0})
+control.Tmp-String-0 := "caipirinha"
+reply.Reply-Message := "toupper of %{control.Tmp-String-0} is " + %toupper(%{control.Tmp-String-0})
----
.Output