Radiator Server Documentation — v10.34.0

Tools radiator-client

Command-line RADIUS and TACACS+ test utility

Table of Contents

radiator-client sends test traffic to RADIUS and TACACS+ servers. The default mode sends individual RADIUS requests. Use a subcommand for RADIUS performance testing or TACACS+ sessions.

Installation

The radiator-client binary is included in the Radiator Server package:

/opt/radiator/server/bin/radiator-client

Command-Line Options

Run radiator-client --help to see all available modes. Use these commands to see mode-specific options:

radiator-client performance --help
radiator-client tacacs --help

The examples below without a subcommand use the default RADIUS request mode. Pass network destinations as --server HOST or --server HOST:PORT. A bare IPv6 address does not need brackets. Enclose IPv6 in brackets when setting an explicit port, for example --server [::1]:11812.

When the port is omitted, UDP and TCP use port 1812 for authentication, 1813 for accounting, and 3799 for CoA and Disconnect requests. TLS uses the RadSec port 2083. If you omit --server entirely, the host defaults to 127.0.0.1.

Basic Usage

Send an Access-Request with username and password:

radiator-client \
    --server 127.0.0.1 \
    --secret mysecret \
    --user alice \
    --password alicepass

Send an Accounting-Request:

radiator-client \
    --server 127.0.0.1 \
    --secret mysecret \
    --user alice \
    --type acct

Password Authentication Methods

By default, radiator-client uses --auth-method pap and sends the password in the RADIUS User-Password attribute.

Use --auth-method mschap or --auth-method mschapv2 to generate the required MS-CHAP attributes automatically from --user and --password. These modes are supported only with --type auth.

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user 'DOMAIN\alice' \
    --password secret \
    --auth-method mschapv2

Authentication method values:

  • pap: Send the password using User-Password.
  • mschap: Send MS-CHAP-Challenge and MS-CHAP-Response.
  • mschapv2: Send MS-CHAP-Challenge and MS-CHAP2-Response.

Adding Attributes

Using Dictionary Names

Add attributes by name with automatic type conversion:

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --attr "Service-Type=Framed-User" \
    --attr "NAS-IP-Address=10.0.0.1" \
    --attr "Cisco-avpair=shell:priv-lvl=15"

Using Raw AVP Format

Add raw AVPs when dictionary names are unavailable:

# Syntax: <type>=<format>,<value>
# Formats: str, hex, u32, i32, u128, i128, ipv4, ipv6

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --avp "1=str,alice" \
    --avp "4=ipv4,10.0.0.1" \
    --avp "6=u32,2"

Using Vendor-Specific Attributes

Add VSAs with vendor ID and type:

# Syntax: <vendor_id>:<vendor_type>=<format>,<value>[;<vendor_type>=<format>,<value>]

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --vsa "9:1=str,shell:priv-lvl=15"

Reading Attributes from File

Create an attribute file:

# attributes.txt
attr User-Name=alice
attr NAS-IP-Address=10.0.0.1
avp 6=u32,2
vsa 9:1=str,shell:priv-lvl=15

Use the file:

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --attr-file attributes.txt

Read from stdin:

echo "attr User-Name=testuser" | radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --attr-file -

Request Types

Access-Request (auth)

radiator-client \
    --type auth \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret

Expected response: Access-Accept (code 2)

Accounting-Request (acct)

radiator-client \
    --type acct \
    --server 127.0.0.1:1813 \
    --secret mysecret \
    --user alice \
    --attr "Acct-Status-Type=Start" \
    --attr "Acct-Session-Id=session123"

Expected response: Accounting-Response (code 5)

Disconnect-Request

radiator-client \
    --type disconnect-request \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --attr "Acct-Session-Id=session123"

Expected response: Disconnect-ACK (code 40)

CoA-Request

radiator-client \
    --type coa-request \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --attr "Session-Timeout=3600"

Expected response: CoA-ACK (code 43)

Repeating Requests

Execute multiple requests for testing:

# Repeat 10 times, fail if any request fails
radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --repeat 10 \
    --repeat-mode all

# Repeat 10 times, succeed if at least one request succeeds
radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --repeat 10 \
    --repeat-mode any

Repeat modes:

  • all: Exit with error if any request fails (default)
  • any: Exit with error only if all requests fail
  • whatever: Always exit with zero regardless of results

Transport Protocols

By default, radiator-client uses UDP transport. You can specify TCP or TLS (RadSec) transport using the --transport flag.

UDP Transport (Default)

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret

TCP Transport

Use plain TCP transport for RADIUS-over-TCP:

radiator-client \
    --server 127.0.0.1:2083 \
    --secret mysecret \
    --user alice \
    --password secret \
    --transport tcp

TLS Transport (RadSec)

Use TLS transport for secure RADIUS communication (RFC 6614). When using TLS, the shared secret is typically radsec.

Basic TLS with system CA certificates:

radiator-client \
    --server radius.example.com:2083 \
    --secret radsec \
    --user alice \
    --password secret \
    --transport tls \
    --tls-server-name radius.example.com

TLS with custom CA certificate:

radiator-client \
    --server 127.0.0.1:2083 \
    --secret radsec \
    --user alice \
    --password secret \
    --transport tls \
    --tls-ca-certificate /path/to/ca.pem \
    --tls-server-name radius.example.com

TLS with mutual authentication (client certificate):

radiator-client \
    --server 127.0.0.1:2083 \
    --secret radsec \
    --user alice \
    --password secret \
    --transport tls \
    --tls-ca-certificate /path/to/ca.pem \
    --tls-certificate /path/to/client-cert.pem \
    --tls-key /path/to/client-key.pem \
    --tls-server-name radius.example.com

TLS Options

OptionDescription
--tls-certificatePath to client certificate file (PEM format)
--tls-keyPath to client private key file (PEM format)
--tls-ca-certificatePath to CA certificate file (PEM format)
--tls-server-nameServer name for TLS SNI and certificate verification
--radius-versionRADIUS packet profile: 1.0 or 1.1; RADIUS/1.1 requires TLS
--tls-no-alpnOmit ALPN for pre-ALPN RADIUS/1.0
--radius-tokenOverride the RADIUS/1.1 Token field
--radius11-reserved-1Override the RADIUS/1.1 Reserved-1 field
--radius11-reserved-2Override the RADIUS/1.1 Reserved-2 field
--radius11-raw-attributeAppend a raw attribute to a RADIUS/1.1 packet

If --tls-ca-certificate is not specified, system root certificates are used for server verification. RADIUS/1.1 requires mutual TLS. When you set --radius-version 1.1, also set --tls-certificate and --tls-key.

The Token, reserved-field, and raw-attribute overrides are testing options. They can deliberately generate packets that violate RADIUS/1.1 requirements so that receiver validation can be tested.

PROXY Protocol Support

PROXY protocol can be combined with TCP or TLS transport.

Send requests with PROXY protocol v2 header:

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --transport tcp \
    --proxy-protocol v2 \
    --proxy-client-addr 192.168.1.100:12345

Raw Packet Handling

Send Raw Hex Packet

Replay captured RADIUS packets:

# From Wireshark: right-click packet, Copy -> As Hex Stream
radiator-client \
    --server 127.0.0.1:1812 \
    --hex "0104002a..." \
    --expect-code Access-Accept

Save Packet to File

Write packet hex without sending:

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --hex-output-file packet.hex

Read Packet from File

radiator-client \
    --server 127.0.0.1:1812 \
    --hex-input-file packet.hex

Response Code Validation

Use --expect-code to validate the response packet type. It accepts either a numeric code or a case-insensitive packet type name:

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --expect-code Access-Accept

Valid packet type names (case-insensitive): access-request, access-accept, access-reject, accounting-request, accounting-response, access-challenge, status-server, disconnect-request, disconnect-ack, disconnect-nak, coa-request, coa-ack, coa-nak.

Reply Message Validation

Use --expect-message to assert that the response Reply-Message matches the given string exactly. --expect-messsage (with triple 's') is also accepted as an alias for backwards compatibility.

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --expect-code access-reject \
    --expect-message "Invalid password"

The command exits with a non-zero status if the response has no Reply-Message or if the value does not match exactly.

Response Attribute Validation

Use --expect-attr to match a decoded response attribute value with an exact string or a regular expression.

Supported operators:

  • == exact match
  • != exact non-match
  • =~ regex match
  • !=~ regex non-match

Use == and =~ for positive assertions:

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --expect-attr "State==0xdeadbeef" \
    --expect-attr "Reply-Message=~/Invalid/"

Use != and !=~ for negative assertions:

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --expect-attr "Filter-Id!=ding" \
    --expect-attr "Reply-Message!=~/^Internal error$/"

Positive assertions fail when the response attribute is missing or when no matching value satisfies the expectation. Negative assertions fail only when a matching response attribute value is present.

Subcommands

SubcommandDescription
format-packetParse and display a RADIUS packet from hex input
performanceGenerate concurrent RADIUS traffic and report statistics
tacacsRun configured TACACS+ sessions

Format Packet

The format-packet subcommand parses a hex-encoded RADIUS packet and prints its contents in a readable table format. This is useful for inspecting captured packets from Wireshark or other tools.

# From a hex string argument
radiator-client format-packet "0104002ae15a5a35..."

It also accepts Wireshark-style hex dump input with offset prefixes:

radiator-client format-packet "
0000   28 00 00 3e e1 58 5a 35 ca a5 7b b3 cd eb 08 4e
0010   46 0b 10 b2 2c 2a 36 30 32 36 45 46 35 43 44 43
"

See radiator-client format-packet --help for details.

RADIUS Performance Testing

Use radiator-client performance to generate concurrent RADIUS traffic. The command accepts the options previously provided by radperftest.

Create a request template named performance.config.toml:

username = "user_"
username_suffix = 1000
password = "password"

Send 10,000 requests over 20 concurrent sockets:

radiator-client performance \
    --config performance.config.toml \
    --requests 10000 \
    --concurrency 20 \
    --window 50 \
    --secret mysecret \
    --server 127.0.0.1:1812
Run a sustained performance test

Use --max-duration without --requests to run for a fixed time. Add --target-tps to generate a specific global rate. The target rate is shared across all worker sockets.

This example generates 1,000 transactions per second (TPS) for 10 minutes. It uses 20 sockets with a window of 256 outstanding requests per socket:

radiator-client performance \
    --config performance.config.toml \
    --max-duration 10m \
    --target-tps 1000 \
    --measurement-padding-time 5s \
    --concurrency 20 \
    --window 256 \
    --timeout 5s \
    --secret mysecret \
    --server 127.0.0.1:1812 \
    --transport udp

--measurement-padding-time excludes the initial warm-up period from the reported measurement. It also provides time after the measurement to collect outstanding responses.

Set the combined request window high enough for the target rate and expected response time. The combined capacity is approximately concurrency * window when --sockets is not set. For example, 20 sockets with a window of 256 allow 5,120 outstanding requests. This capacity can hold five seconds of requests at 1,000 TPS without rejecting scheduled requests because the window is full.

Start with a rate below the expected server capacity. Increase --target-tps between runs until latency, timeouts, invalid replies, or window-full send failures increase. Treat the requested target and the reported achieved TPS as separate values. A lower achieved rate can indicate client-side window limits, network limits, or server saturation.

Omit --target-tps to generate requests as quickly as the configured sockets and windows allow. Use this mode to find maximum throughput. Use a target rate for soak tests and for tests that must reproduce production traffic.

Choose the RADIUS protocol

--transport selects the connection transport. --radius-version selects the RADIUS packet profile. Use the same combination as the server listener under test.

Use caseOptions
Standard RADIUS over UDP--transport udp --radius-version 1.0
RADIUS over a plain TCP connection--transport tcp --radius-version 1.0
RADIUS/1.0 over TLS (RadSec)--transport tls --radius-version 1.0
RADIUS/1.1 over TLS--transport tls --radius-version 1.1

UDP and RADIUS/1.0 are the defaults. Choose TCP only when the server has a plain RADIUS/TCP listener. Choose TLS when testing RadSec. For TLS, set --tls-server-name to the name in the server certificate. Set --tls-ca-certificate when the certificate is not trusted by the system root store.

RADIUS/1.1 requires TLS 1.3 and mutual TLS. Provide the client certificate and private key together:

radiator-client performance \
    --config performance.config.toml \
    --max-duration 10m \
    --target-tps 1000 \
    --concurrency 20 \
    --window 256 \
    --server radius.example.com:2083 \
    --transport tls \
    --radius-version 1.1 \
    --tls-server-name radius.example.com \
    --tls-ca-certificate ca.pem \
    --tls-certificate client.pem \
    --tls-key client-key.pem

Keep --requests-per-connection unset for a sustained test of established TCP or TLS connections. Set it only when the test must include periodic connection setup and TLS handshakes.

TACACS+ Testing

Use radiator-client tacacs to run TACACS+ authentication, authorization, or accounting sessions from a TOML configuration file.

--server HOST overrides the configured server and uses the TACACS+ default port 49. Add :PORT to use a different port.

Generate a documented example configuration:

radiator-client tacacs --print-example-config > tacacs-client.toml

Edit the connection and session values, then run the client:

radiator-client tacacs --config tacacs-client.toml

The configuration defines one complete authentication, authorization, or accounting session. In load-test output, one request means one complete configured session, not one TACACS+ packet.

Run a fixed number of TACACS+ sessions

Use --requests to set the total number of sessions. Use --concurrency to set the number of load workers:

radiator-client tacacs \
    --config tacacs-client.toml \
    --requests 10000 \
    --concurrency 20

Each worker opens a connection and reuses it when the server negotiates TACACS+ Single Connection Mode. Without Single Connection Mode, the worker opens a new connection for each session.

Run a sustained TACACS+ performance test

Use --max-duration without --requests to run sessions as quickly as possible for a fixed time:

radiator-client tacacs \
    --config tacacs-client.toml \
    --max-duration 10m \
    --concurrency 20

You can set both --requests and --max-duration. The test stops when it reaches either limit.

The result includes the duration, average successful sessions per second, attempted sessions, successful sessions, and failed sessions. The command returns an error when any session fails.

TACACS+ load testing does not provide target-rate pacing. A duration-based test runs at the maximum rate allowed by the configured concurrency, server, and network. Use it for saturation and sustained maximum-throughput tests.

Test TACACS+ session multiplexing

--window sets the maximum number of in-flight sessions on each negotiated single connection. Values greater than one require Single Connection Mode. Enable it in the session configuration:

[connection]
single_connect = true

Then set the worker count and per-connection window:

radiator-client tacacs \
    --config tacacs-client.toml \
    --max-duration 10m \
    --concurrency 20 \
    --window 16

This configuration allows up to 20 worker connections and 16 in-flight sessions per negotiated connection. The client waits for the first reply to confirm Single Connection Mode before it sends concurrent sessions on that connection.

Keep --window 1 when the server does not support Single Connection Mode or when the configured exchange expects the server to close the connection.

Choose the TACACS+ transport

TACACS+ performance tests support TCP and TLS. The session configuration selects the transport. You can override it with --transport tcp or --transport tls.

For TLS, use --tls-server-name for certificate name validation. Set --tls-ca-certificate when the certificate is not trusted by the system root store. Set --tls-certificate and --tls-key together when the server requires a client certificate.

Exit Codes

CodeMeaning
0Success (expected response received)
1Error (timeout, unexpected response, or other failure)

Troubleshooting

Common Issues

Timeout errors

  • Verify server IP and port are correct
  • Check firewall rules allow UDP traffic
  • Increase timeout with --timeout 10s

Invalid response authenticator

  • Verify shared secret matches server configuration
  • Check for secret character encoding issues

Access-Reject received

  • Verify username and password are correct
  • Check server logs for authentication failure reason
  • Use --verbose for detailed packet inspection

Verbose Mode

Enable verbose output to see a structured, annotated hex dump of each RADIUS packet. The output uses #-prefixed comment lines for metadata, so it can be directly re-fed to --hex or --hex-input-file for packet replay.

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --verbose

The verbose output includes:

  • Header section: Code, Length, and the fields defined by the selected packet profile. RADIUS/1.0 shows Identifier and Authenticator. RADIUS/1.1 shows Reserved-1, Token, and Reserved-2 instead. The section also includes a hex dump of the 20-byte header.
  • Attribute sections: Type, Length, Format, Name, Value, and a per-attribute hex dump. For vendor-specific attributes (VSAs), Vendor-ID, Vendor-Name, and Vendor-Type are also shown

JSON Mode

Use --json to write request and response packets as JSON objects. Each packet contains code, type, radiusVersion, length, and attributes.

Header fields depend on the packet profile:

  • RADIUS/1.0 includes identifier and authenticator.
  • RADIUS/1.1 includes token, reserved1, and reserved2. It omits identifier and authenticator because those fields do not exist in the RADIUS/1.1 header.

Combine --json with --verbose to add rawType, rawValueHex, and rawValueBytes to each attribute. Resolved enumerated values also include rawValue.

Dry Run

Use --dry-run to build and display the RADIUS request packet without sending it to the server. This is useful for inspecting what would be sent. Works with both normal and raw (--hex / --hex-input-file) modes:

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --dry-run

In JSON mode (--json), --dry-run outputs the request as a JSON object.

Hex Dump

Use --hex-dump to print a full raw hex dump of the entire packet after the table output. Unlike --verbose, which shows an annotated per-attribute hex dump, --hex-dump displays a single contiguous hex dump of the whole packet:

radiator-client \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --user alice \
    --password secret \
    --hex-dump

The --hex-dump flag is also available on the format-packet subcommand:

radiator-client format-packet --hex-dump "0104002ae15a5a35..."

Using Custom Dictionary

Load a custom RADIUS dictionary:

radiator-client \
    --dictionary /path/to/custom.dictionary \
    --server 127.0.0.1:1812 \
    --secret mysecret \
    --attr "Custom-Attribute=value"

Print the built-in dictionary:

radiator-client --print-dictionary
Navigation
  • Application log message index

  • Architecture Overview

  • Backend Load Balancing

  • Basic Installation

  • Built-in Environment Variables

  • Byte Size Units

  • Certificate Revocation Lists

  • Comparison Operators

  • Configuration Editor

  • Configuration Import and Export

  • Containers

  • Cron and interval timers

  • Data Types

  • Duration Units

  • Environment Variables

  • Execution Context

  • Execution Pipelines

  • Filters

  • Getting a Radiator License

  • Health check /live and /ready

  • High Availability and Load Balancing

  • High availability identifiers

  • HTTP Basic Authentication

  • Introduction

  • Linux systemd support

  • Local AAA Backends

  • Logging

  • Management API privilege levels

  • Namespaces

  • Password Hashing

  • Password Rehashing During Login

  • Probabilistic Sampling

  • Prometheus and OpenMetrics scraping

  • PROXY Protocol Support

  • Radiator server health and boot up logic

  • Radiator sizing

  • Radiator software releases

  • Radiator software security and dependency compliance

  • RadiatorDB

  • RadiatorDB Backup

  • RadiatorDB CLI

  • RadiatorDB Installation

  • RadiatorDB PostgreSQL 10k TPS example

  • RadiatorDB REST API

  • RadiatorDB sizing

  • Rate Limiting

  • Rate Limiting Algorithms

  • Reverse Dynamic Authorization

  • Service Level Objective

  • TACACS+ Authentication, Authorization, and Accounting

  • Template Rendering CLI

  • Timestamps

  • Tools radiator-client

  • TOTP/HOTP Authentication

  • What is Radiator?

  • YubiKey Authentication

  • YubiKey Context Variables