Radiator Server Documentation — v10.34.0
Table of Contents
  • radius
  • Server configuration
  • Basic server configuration
  • RadSec (RADIUS over TLS) server configuration
  • RADIUS/1.1 (RFC 9765)
  • Generic ALPN compatibility
  • Backend response authentication
  • Proxying mode
  • Calling the proxy backend
  • PEAP inner EAP proxying
  • Modifying requests and replies
  • Logging proxy attributes
  • Server parameters
  • Connect parameters
  • Backend parameters

radius

This backend sends RADIUS requests to external RADIUS servers. It supports two modes of operation:

  • Proxying mode: Forwards the incoming RADIUS request to another RADIUS server. The proxy request and reply are derived from the original request context.
  • Query mode: Sends independent RADIUS requests that you construct within the execution context. This allows issuing RADIUS requests from any protocol handler, not just RADIUS.

Server configuration

Both modes share the same server configuration. Define one or more target servers within the backend block.

Basic server configuration

backends {
    radius "RADIUS_BACKEND" {
        # Server selection strategy (optional)
        # round-robin = distribute requests across healthy servers
        # hash-balance = route the same key to the same preferred server
        # fallback = try next healthy server if first does not respond
        # no-fallback = do not try next server if first does not respond
        server-selection round-robin;

        server "radius1.example.org" {
            # Required unless this is a strict RADIUS/1.1 TLS backend
            secret "ExampleSecret";

            # Request timeout (supports duration units: ms, s, m, h)
            timeout 7s;

            # Number of times to retry a timed out request
            retries 0;

            # Enable periodical health detection
            # status true;

            # Connection pool settings (optional)
            connections {
                # Maximum number of connections to open
                # max 10;

                # Keep one connection warm for fast failover and restart recovery
                # With UDP, this binds a local UDP socket for sending packets.
                # It does not establish a remote connection.
                min 1;
            }

            connect {
                # Transport protocol: udp, tcp, or tls
                protocol udp;

                # Server IP address
                ip 203.0.113.111;

                # Alternatively, use hostname instead of ip
                #host "radius1.example.org";

                # Optional DNS and TCP connection deadlines
                #dns-timeout 5s;
                #connection-timeout 5s;

                # Destination port
                port 1812;

                # Optional: socket buffer size in bytes
                #buffer 1048576;
            }
        }

        # Additional servers for redundancy
        server "radius2.example.org" {
            secret "ExampleSecret";
            timeout 7s;
            retries 0;
            connections {
                min 1;
            }
            # status true;  # default
            connect {
                protocol udp;
                ip 203.0.113.112;
                port 1812;
            }
        }
    }
}

RadSec (RADIUS over TLS) server configuration

For TLS connections, add a tls block inside the connect block.

RADIUS/1.1 (RFC 9765)

The following example enables both registered RADIUS ALPN profiles and prefers RADIUS/1.1:

backends {
    radius "RADSEC_BACKEND" {
        server "radsec.example.org" {
            secret "radsec";
            timeout 60s;
            status true;
            connections {
                min 1;
            }

            connect {
                protocol tls;
                host "radsec.example.org";
                port 2083;

                tls {
                    # TLS negotiation deadline after the TCP connection succeeds
                    handshake-timeout 5s;

                    # Offer RADIUS/1.1 and RADIUS/1.0, preferring 1.1
                    radius_versions 1.0, 1.1;

                    # Client certificate for mutual TLS
                    certificate "RADSEC_CLIENT_CERT";
                    certificate_key "RADSEC_CLIENT_KEY";

                    # CA certificate to validate server
                    server_ca_certificate "RADSEC_SERVER_CA";

                    # Optional: custom certificate verification
                    @verification {
                        if any {
                            cert.subject_alt.dns != "radsec.example.org";
                        } then {
                            reject;
                        } else {
                            accept;
                        }
                    }
                }
            }
        }
    }
}

The radius_versions TLS setting controls the RADIUS packet profiles offered with ALPN. It accepts none, 1.0, 1.1, or 1.0, 1.1. When omitted, Radiator enables only the radius/1.0 profile for compatibility with existing configurations. Configure radius_versions 1.0, 1.1; to enable both profiles and prefer RADIUS/1.1. Use radius_versions none; for a RADIUS/1.0 peer that does not use ALPN.

RFC 9765 specifies 1.0, 1.1 as the default for implementations that support both profiles. Radiator intentionally uses RADIUS/1.0 as a backward compatibility exception. This prevents an upgrade from changing packet encoding and validation for an existing backend. Configure 1.1 or 1.0, 1.1 to opt the backend into RFC 9765 behavior.

Any policy that enables RADIUS/1.1 requires TLS 1.3 and mutual TLS. Configure both certificate and certificate_key for the backend client identity. Radiator rejects an enabled RADIUS/1.1 policy without both settings and restricts the connection to TLS 1.3. RADIUS/1.1 packets use the negotiated Token field, omit Message-Authenticator, and carry attributes such as User-Password and Tunnel-Password using their underlying dictionary data types instead of the RADIUS/1.0 shared-secret transforms. The configured secret may be omitted when protocol tls; is combined with exactly radius_versions 1.1;. It remains required whenever the backend can use RADIUS/1.0, including mixed version policies, omitted radius_versions, radius_versions none;, the backward-compatible generic alpn_protocol setting, UDP or TCP transports, and reverse backends. Radiator supports RFC 9765 over TLS only. RADIUS/1.1 over DTLS is not supported. Radiator rejects an outgoing RADIUS/1.1 request that contains CHAP-Password without CHAP-Challenge. When proxy forwarding fails, Radiator returns a proxy-specific Protocol-Error to an incoming RADIUS/1.1 client.

When both versions are enabled, Radiator does not resume backend TLS sessions. This prevents a resumed session from changing its negotiated RADIUS version. RADIUS/1.1-only backends can resume TLS sessions according to the configured TLS 1.3 ticket settings.

Generic ALPN compatibility

The generic alpn_protocol setting remains available for compatibility with custom ALPN configurations; non-standard names use the RADIUS/1.0 packet profile. A RADIUS peer that omits ALPN is also accepted as RADIUS/1.0 when this older generic setting is used. Configure radius_versions when the peer must negotiate a registered RADIUS ALPN profile. Do not configure both radius_versions and alpn_protocol in the same TLS block. Each alpn_protocol value must contain between 1 and 255 bytes, and duplicate values are not allowed.

Backend response authentication

Set require_message_authenticator true to require Message-Authenticator in supported RADIUS/1.0 responses from the backend. Accounting-Response and replies to Status-Server probes are exempt. The default is false for compatibility with existing upstream servers. This setting does not apply to RADIUS/1.1.

Proxying mode

In proxying mode, the backend forwards the incoming RADIUS request to the configured server. Use this mode when you want to relay requests to another RADIUS server.

Dictionary-unknown attributes are dropped by default. Set proxy_unknown_attributes true only when a peer requires private attributes that cannot be defined in the dictionary.

When an Accounting-Request contains Acct-Delay-Time, Radiator adds the time spent in the proxy to the received value before each attempt. Retries are rebuilt with fresh correlation and authenticator values so the updated delay is covered by packet authentication.

Calling the proxy backend

Call the backend directly by name in a handler pipeline:

aaa {
    policy "DEFAULT" {
        handler "PROXY" {
            @execute {
                backend "RADIUS_BACKEND";
            }
        }
    }
}

PEAP inner EAP proxying

Call a RADIUS backend directly from an eap-peap @authentication block to proxy the complete inner EAP conversation. Radiator terminates the PEAP TLS tunnel. The upstream RADIUS server handles the inner EAP method. This mode is specific to PEAP; EAP-TTLS uses its existing inner attribute and nested method conversion.

backends {
    radius "INNER_EAP_RADIUS" {
        challenge-timeout 30s;

        @pre-proxying {
            if all {
                root.eap.identity == "anonymous@example.com";
                eap.identity == "user@example.com";
            } then {
                modify {
                    radiusproxy.request.attr.User-Name = aaa.identity.name;
                    radiusproxy.request.attr.NAS-Identifier = "peap-proxy";
                }
            }
        }

        server "upstream.example.com" {
            secret "shared-secret";
            connect {
                protocol udp;
                ip 192.0.2.10;
                port 1812;
            }
        }
    }
}

aaa {
    policy "PEAP" {
        handler "TERMINATE-PEAP" {
            @execute {
                eap {
                    eap-peap {
                        tls {
                            certificate_key "EAP_SERVER_KEY";
                            certificate "EAP_SERVER_CERT";
                            require_client_certificate false;
                        }

                        @authentication {
                            backend "INNER_EAP_RADIUS";
                        }
                    }
                }
            }
        }
    }
}

The proxy request contains the complete inner packet in EAP-Message. Radiator maps the inner EAP identity to User-Name before @pre-proxying runs. You can translate radiusproxy.request.attr.User-Name for upstream routing or lookup without changing the identity inside EAP-Message.

Radiator sends an upstream Access-Challenge EAP request back through the PEAP tunnel. It automatically returns the challenge State attributes in later Access-Requests. Each Access-Challenge must contain exactly one complete EAP-Request. Radiator restores its upstream EAP Identifier when PEAP header compression omits that field from the peer response.

An Access-Accept may omit EAP-Success, and an Access-Reject may omit EAP-Failure. Radiator forwards an included terminal EAP packet only when its result and Identifier match the completed inner exchange. It ignores an invalid or contradictory terminal EAP packet and bases the access decision on the RADIUS response Code, as required by RFC 3579. An Access-Accept may provide MPPE keys without EAP-Message. It must include both MS-MPPE-Recv-Key and MS-MPPE-Send-Key when either key is present. Radiator imports the pair for PEAP key derivation and cryptobinding. Configure a protected RADIUS transport when the inner method or added attributes require transport confidentiality.

Inside @pre-proxying, use root.eap.identity for the outer identity, eap.identity for the tunneled identity, and aaa.identity for the writable inner working identity. See EAP identity layers.

Modifying requests and replies

Use @pre-proxying and @post-proxying blocks within the backend configuration to filter or modify attributes:

backends {
    radius "RADIUS_PROXY" {
        # Modify request before sending to upstream server
        @pre-proxying {
            # Remove attributes from the proxy request
            filter {
                Tunnel-Type;
                Tunnel-Medium-Type;
                Tunnel-Private-Group-ID;
            }

            # Add or modify attributes
            modify {
                radiusproxy.request.attr.Operator-Name = "4EXAMPLE_COM:FI";
            }

            # Copy specific attributes from the original request
            copy {
                User-Name;
                User-Password;
            }
        }

        # Modify reply before returning to client
        @post-proxying {
            filter {
                Tunnel-Type;
                Tunnel-Medium-Type;
                Tunnel-Private-Group-ID;
            }

            copy {
                Reply-Message;
            }
        }

        server "radius1.example.org" {
            # ... server configuration ...
        }
    }
}

The copy and filter actions handle protected dictionary attributes according to both packet profiles. They decode a RADIUS/1.0 protected value with the source shared secret and re-protect it for a RADIUS/1.0 destination. RADIUS/1.1 carries the underlying value and relies on TLS protection. This allows selected User-Password, Tunnel-Password, and other protected attributes to cross RADIUS/1.0 and RADIUS/1.1 boundaries. Comparison rules use the decoded logical value. A protection or conversion error fails the action instead of silently removing the attribute. See the copy and filter action references.

Logging proxy attributes

Use the bare radiusproxy.request.attrs and radiusproxy.reply.attrs accessors to log all proxy request or reply attributes as a JSON array of {name, value} objects. This is useful for logging all proxied attributes in @pre-proxying and @post-proxying hooks without enumerating each attribute individually.

backends {
    radius "UPSTREAM" {
        @pre-proxying {
            copy {
                User-Name;
                User-Password;
                Service-Type;
                cisco-avpair;
            }

            log "PROXY_LOG" {
                json {
                    "Request-Code" "%{radiusproxy.request.code}";
                    "Request-Attributes" radiusproxy.request.attrs;
                }
            }
        }

        @post-proxying {
            copy {
                Class;
                Cisco-AVPair;
            }

            log "PROXY_LOG" {
                json {
                    "Reply-Code" "%{radiusproxy.reply.code}";
                    "Reply-Attributes" radiusproxy.reply.attrs;
                }
            }
        }
    }
}

The logged JSON output contains all attributes as an array:

{
  "Request-Code": "Access-Request",
  "Request-Attributes": [
    { "name": "user-name", "value": "mikem" },
    { "name": "service-type", "value": "framed-user" }
  ]
}

Server parameters

ParameterTypeDefaultDescription
secretstringconditionalRADIUS shared secret. May be omitted only for a forward TLS backend configured with exactly radius_versions 1.1;.
timeoutduration3sRequest timeout
retriesinteger2Number of UDP retransmission attempts after a request timeout. TCP and TLS do not retransmit on an open connection.
connection-status { ... }block-Configure active Status-Server monitoring independently for each connection.
statusbooleanfalseCompatibility syntax for enabling Status-Server polling with default settings.
max-incoming-packet-sizeinteger4096Largest packet accepted from the backend.
max-outgoing-packet-sizeinteger4096Largest packet constructed and sent to the backend.
nas_identifierstring-NAS-Identifier string included in outgoing Status-Server packets
connections { ... }block-Connection pool settings. Use max, min, window, idle-timeout, and selection inside it.
priorityinteger0Server priority for fallback selection (lower = higher priority). When servers have equal priority, they are tried in alphabetical order by server name.

Connect parameters

ParameterTypeDefaultDescription
protocolenum(required)Transport protocol: udp, tcp, or tls
ipIP address-Server IP address (use either ip or host)
hoststring-Server hostname (use either ip or host)
portinteger(required)Destination port
local-ipIP address-Source IP address
local-portinteger-Fixed source port; requires connections { max 1; }
bufferinteger1048576Requested receive and send socket buffer size in bytes
keepaliveblock-TCP keepalive settings for TCP and TLS connections

Backend parameters

ParameterTypeDefaultDescription
server-selectionenumfallbackServer selection strategy: fallback, round-robin, hash-balance, least-connections, or no-fallback

See Backend Load Balancing for syntax, field selection, multi-round behavior, and failover details.

Navigation
  • @init

  • @verification

  • aaa

  • backends

    • file

    • http

    • ipmap

    • jsonfile

    • ldap

    • mysql

    • postgresql

    • radiatordb

    • radius

      • connect

      • connection-status

      • connections

      • max-incoming-packet-size

      • max-outgoing-packet-size

      • nas_identifier

      • priority

      • proxy_unknown_attributes

      • query

      • require_message_authenticator

      • retries

      • server

      • server-selection

      • status

      • timeout

    • radius-dns-sd

    • sqlite

    • system

  • caches

  • captures

  • certificates

  • clients

  • conditions

  • dictionary

  • handshake-timeout

  • hmac-otp

  • include

  • interval

  • ip-accept

  • license

  • logging

  • management

  • negotiation

  • proxy-protocol

  • scripts

  • servers

  • statistics

  • stats

  • timer

  • ui