Lua script context API - RADIUS sub-context

radius

RADIUS packet data.

Fields

FieldTypeDescription
requestpacketRADIUS request packet
replypacketRADIUS reply packet
dynauthpacketDynamic authorization packet
clientclient?RADIUS client info
serverserver?RADIUS server info

Packet Methods

MethodParametersReturnsDescription
attr(name, tag?)attribute name, optional tagvalue?Get first attribute value
attr_last(name, tag?)attribute name, optional tagvalue?Get last attribute value
attr_all(name, tag?)attribute name, optional tagvaluesGet all attribute values as an array
attrs()-tableGet all attributes as a table
append_attr(name, tag?, value)name, tag, value-Append attribute (reply only)
append_attrs(name, tag?, values)name, tag, values-Append multiple values (reply only)
set_attr(name, tag?, value)name, tag, value-Set attribute if not exists (reply only)
set_attrs(name, tag?, values)name, tag, values-Set multiple values (reply only)

Attribute Names

All attribute names are stored in lowercase by the RADIUS dictionary parser regardless of how they appear in the dictionary file or the RADIUS packet. Always use lowercase names when calling attr(), attr_last(), attr_all(), and the write methods.

-- Correct: lowercase
local ip    = radius.request:attr("framed-ip-address")
local nas   = radius.request:attr("nas-identifier")
local mac   = radius.request:attr("calling-station-id")
local user  = radius.request:attr("user-name")

-- Wrong: mixed-case returns nil
-- local ip = radius.request:attr("Framed-IP-Address")  -- nil

Note: radconf condition expressions (radius.request.attr.Framed-IP-Address) and template expansions (%{radius.request.attr.Framed-IP-Address}) use a separate code path and are not affected by this lowercasing requirement.

attrs() Return Value

attrs() returns a Lua table where each key is a lowercase attribute name (string) and each value is an array (table with integer keys starting at 1) containing all occurrences of that attribute.

Attribute values are mapped to Lua types as follows:

RADIUS typeLua type
Integer / Unsignednumber
Text / Stringstring
IP address / networkstring (dotted-decimal or CIDR)
Bytes / binarystring (raw bytes)
Booleanboolean
Missing / unknownnil

Single-occurrence attributes still appear as a one-element array so you can always iterate uniformly:

local all = radius.request:attrs()
-- all["user-name"]          -> { "alice" }
-- all["framed-ip-address"]  -> { "10.0.0.5" }
-- all["class"]              -> { "group1", "group2" }  (multi-value)

-- Inspect every attribute and its values
for name, values in pairs(all) do
    for _, v in ipairs(values) do
        context:log("AUTHLOG", name .. " = " .. tostring(v))
    end
end

Client Object

FieldTypeDescription
namestringClient name
ipstring?Client IP address

Server Object

FieldTypeDescription
namestringServer name
ipstringServer IP address
portnumberServer port
tlsbooleanIs TLS enabled?

Example

local context, previous = ...

local radius = context.radius

-- Read request attributes (use lowercase names)
local username = radius.request:attr("user-name")
local nas_ip   = radius.request:attr("nas-ip-address")
local framed   = radius.request:attr("framed-ip-address")

-- Get all values of a multi-value attribute
local all_filters = radius.request:attr_all("filter-id")
if all_filters then
    for _, f in ipairs(all_filters) do
        context:log("AUTHLOG", "Filter: " .. tostring(f))
    end
end

-- Dump every attribute in the request for debugging
local all = radius.request:attrs()
for name, values in pairs(all) do
    for _, v in ipairs(values) do
        context:log("AUTHLOG", name .. " = " .. tostring(v))
    end
end

-- Add reply attributes
radius.reply:append_attr("reply-message", nil, "Welcome!")
radius.reply:set_attr("session-timeout", nil, 3600)

-- Check client
if radius.client then
    local client_name = radius.client.name
    local client_ip   = radius.client.ip
end

return previous