Capture RADIUS Attributes from a pppd Link

The radattr plugin gets pppd to dump every RADIUS-returned attribute into a per-interface file, ready for your ip-up or ip-down scripts to read. Handy when a hook needs a server-supplied value and you would rather not stand up a second RADIUS client to get at it.

Fifteen minutes if RADIUS authentication is already working here. The examples assume Debian or Ubuntu packaging, the installed ppp package version 2.4.9-1+1.1ubuntu4, and an interface named something like ppp0. The plugin itself never creates a connection or configures RADIUS; it only watches one that already exists.

1. Check the existing RADIUS setup

Confirm the package is installed and the plugins are actually present before touching anything else. This is a read-only check:

dpkg-query -W -f='${Package} ${Version}\n' ppp
dpkg -L ppp | grep -E '/(radius|radattr)\.so$'

Expected output gives you the package version plus paths for radius.so and radattr.so. The plugin directory is package-specific, so do not hard-code a path copied from another host.

Checkpoint: the existing RADIUS plugin has to work before you bolt on attribute capture. If authentication is not already succeeding, fix that separately with pppd-radius(8) and the radiusclient configuration first. radattr does not replace /etc/radiusclient/radiusclient.conf, it just rides alongside it.

2. Add the plugins in the required order

Add both plugin lines to the pppd invocation or the peer file it uses. Order matters here: load radius.so first, then radattr.so, because the second depends on symbols the first provides.

plugin radius.so
plugin radattr.so

If the connection is started with a peer definition, place these lines with its other pppd options. If it is started by a service or another manager, change the source that actually builds the pppd command rather than testing an unrelated shell command. A typical command-line shape is:

sudo pppd call <peer-name> plugin radius.so plugin radattr.so

The command above starts or restarts a link and may alter routes, authentication state and service availability. Do not run it on a production link until you have a maintenance window and a recovery path. Preserve the current peer file before editing it:

sudo cp --preserve=mode,ownership /etc/ppp/peers/<peer-name> /etc/ppp/peers/<peer-name>.before-radattr

Checkpoint: inspect the effective configuration before bringing up the link. You should see both plugin options, with radius.so before radattr.so.

3. Establish one test connection

Bring the link up through whatever mechanism normally manages it, and keep the pppd log open in another window. A missing plugin or the wrong load order shows up there, not in a later file check.

Once authentication completes, find the interface name:

ip -o link show | awk -F': ' '$2 ~ /^ppp[0-9]+$/ {print $2}'

For an interface named ppp0, the expected capture file is /var/run/radattr.ppp0. The manpage calls the name pppN: it is the actual PPP interface name, not a literal filename suffix to copy unchanged.

Do not create or edit this file by hand. It is runtime state owned by the plugin and may be replaced when the link is re-established.

4. Verify the captured attributes

Read the file with elevated privileges only if its permissions actually require it:

sudo test -r /var/run/radattr.ppp0 && sudo sed -n '1,120p' /var/run/radattr.ppp0

Successful output consists of one returned attribute per line, in the form Attribute-Name Attribute-Value. The exact lines depend on the RADIUS server response. An empty or absent file does not prove that the plugin loaded: check the interface name, authentication log and plugin order first.

Use these checks without displaying values if the attributes may contain sensitive network or identity data:

sudo test -s /var/run/radattr.ppp0
sudo wc -l /var/run/radattr.ppp0

The first command is successful only when the file exists and is non-empty. The second reports how many attribute lines were captured. Keep the file out of general-purpose logs and do not paste its contents into tickets until you have removed secrets and personal data.

5. Use the file from PPP hooks

The format exists for /etc/ppp/ip-up and /etc/ppp/ip-down to consume. Have those hooks work out the right file for the interface rather than assuming ppp0 forever. A minimal read-only fragment taking the interface name as its first argument looks like this:

#!/bin/sh
iface=$1
attrs=/var/run/radattr."$iface"

if [ -r "$attrs" ]; then
    while IFS= read -r attribute; do
        logger --tag ppp-radattr -- "$iface $attribute"
    done < "$attrs"
fi

Treat this only as a shape for your hook. Logging every attribute may disclose account, addressing or policy information, so reduce it to the specific attribute your workflow needs. Quote the interface-derived path and validate any value before using it in a command, route change or filename. A hook that fails should not tear down a working link unless that is an explicit operational requirement.

Run hooks with the privileges supplied by pppd. Do not make the runtime file world-readable just to avoid using the existing privilege boundary.

6. Diagnose the common traps

Most problems trace back to one of five habits:

Done means