reverse

The reverse block is an alternative to connect within a RADIUS backend server configuration. Instead of establishing an outbound connection to a remote RADIUS server, reverse selects an existing inbound connection from a client that has connected to a local RADIUS server running in the same Radiator process.

This enables Reverse Dynamic Authorization (Reverse CoA) scenarios where Radiator needs to send RADIUS requests such as Disconnect-Request or CoA-Request back to NAS devices over their existing connections. The NAS devices connect to a local RADIUS server (typically over RadSec/TLS), and the reverse block picks one of those connections to deliver the request.

For more information, see the Reverse Dynamic Authorization article.

Syntax

The reverse block must contain exactly one @select block which determines which connected client receives the request. The @select block is an execution pipeline.

reverse {
    @select {
        if all {
            connection.status.nas_identifier == "NAS123";
        } then {
            accept;
        } else {
            reject;
        }
    }
}

The @select pipeline is evaluated for each connected client where the connection is represented in the connection.* variable namespace. If the pipeline returns accept, that connection is selected to receive the request. If it returns reject or ignore, the connection is not selected and the next connection is evaluated. If no connections are accepted, the request fails with error code errors.NO_REVERSE_CONNECTIONS. This error can be captured on the caller side. See the example below. Any other errors raised during the evaluation of the @select pipeline are also propagated to the caller.

The @select block can also reference any other variables available in the execution context, such as request attributes or user information, to make selection decisions based on the request being processed. See the Execution Context documentation for the full list of available variables.

@select {
    if all {
        # Select the connection where the NAS-Identifier matches the one in the RADIUS request attributes
        connection.status.nas_identifier == radius.request.attr.NAS-Identifier;
    } then {
        accept;
    } else {
        reject;
    }
}

Selection mode

An optional selection mode can be specified after @select:

reverse {
    # Returns the first matching connection (default)
    @select first {
        # ...
    }
}
reverse {
    # Distributes requests across all matching connections
    @select round-robin {
        # ...
    }
}

Modes

ModeDescription
firstReturns the first connected client for which the @select pipeline returns accept. This is the default when no mode is specified.
round-robinCollects all connected clients for which the @select pipeline returns accept, then picks one using a round-robin counter.

Connection variables

Inside the @select pipeline, each candidate connection is exposed through the connection.* variable namespace. Use these variables to match the desired connection.

VariableTypeDescription
connection.idintegerUnique connection identifier within the process
connection.client_namestringName of the connected client
connection.peer_addrstringRemote address of the connected client (ip:port)
connection.peer_ipipRemote IP address of the connected client
connection.server_namestringName of the local server the client connected to
connection.server_addrstringLocal address the server is listening on (ip:port)
connection.server_ipipLocal IP address the server is listening on
connection.transport_protocolstringTransport protocol: tcp or tls
connection.connectedtimestampTime when the connection was established
connection.disconnectedtimestampTime when the connection was closed (empty if connected)
connection.status.receivedtimestampTime of the last server status message
connection.status.nas_identifierstringNAS-Identifier value from the connected client. Available only when the client sends Status-Server packets containing a NAS-Identifier attribute.

When the connection uses TLS with client certificates, the following certificate variables are also available:

VariableTypeDescription
connection.cert.subject.cnstringCommon Name from the client certificate
connection.cert.subject_alt.emailstringSubject Alternative Name email addresses
connection.cert.subject_alt.email[N]stringSpecific email address by index
connection.cert.subject_alt.dnsstringSubject Alternative Name DNS names
connection.cert.subject_alt.dns[N]stringSpecific DNS name by index
connection.cert.subject_alt.uristringSubject Alternative Name URIs
connection.cert.subject_alt.uri[N]stringSpecific URI by index

Constraints

  • The reverse block and the connect block are mutually exclusive. A server definition must use one or the other.
  • The @select pipeline block inside reverse is required.
  • Only active (not disconnected) connections are considered as candidates.
  • If no connected client matches the @select pipeline, the backend request fails with an error.

Example: basic reverse CoA

Accept the first available reverse connection:

backends {
    radius "REVERSE_DYNAUTH" {
        server "REVERSE" {
            secret "mysecret";
            reverse {
                @select {
                    accept;
                }
            }
        }

        query "DISCONNECT_USER" {
            bindings {
                radius.request.code = radius.DISCONNECT_REQUEST;
                radius.request.attr.User-Name = "mikem";
            }
        }
    }
}

Example: Error handling

The backend error can be captured using the try action on the caller side:

try backend {
    name "REVERSE_DYNAUTH";
    request "DISCONNECT_USER";
}

if all {
    aaa.caught_error.code == errors.NO_REVERSE_CONNECTIONS;
} then {
    reject "operation failed: no available connections for reverse request";
} else if all {
    aaa.caught_error != none;
} then {
    reject "operation failed: %{aaa.caught_error}";
}

Example: Debugging connection variables

Use the debug action to inspect the available connection variables and their values for each connected client:

@select {
    debug """
    === Evaluating connection %{connection.id} ===
    Server name: %{connection.server_name}
    NAS-Identifier: %{connection.status.nas_identifier}
    Peer IP: %{connection.peer_ip}
    Certificate CN: %{connection.cert.subject.cn}
    Certificate SAN email: %{connection.cert.subject_alt.email[0]}
    """;
    # Reject all connections to see the debug output for all candidates
    reject;
}
  • connect - Outbound connection to a remote RADIUS server (alternative to reverse)
  • query - Independent RADIUS requests used with reverse to construct CoA or Disconnect messages