How to decode the five different data types in a RADIUS packet
How to decode the five different data types in a
RADIUS packet
When a handset device on a cellular carrier turns on, usually
a RADIUS packet is generated and sent out to a number of different network
nodes to let them know that the handset device is on and about to access
services of the wireless network. In
some of those networks, F5 BIGIP devices also receive this RADIUS packet so
that they too can get ready to handle network traffic from the handset device. Some times the BIGIP will query some sort of
AAA or Policy servers to see if the handset device is allowed to connect to
nodes beyond the BIGIP, and needs some of the information contained in the
RADIUS packet in order to do the query. Here’s how to pull that information out
within iRules.
RADIUS packets have five official data types: Integer, Text, String, IPAddress, and
Time. These are defined in the RADIUS
standards (RFC-2865, RFC-2866, among
others). “String” can be something of a misnomer, as it can contain binary
data. “Text” is used for textual, printable, strings (I.E. UTF-8 encoded
characters). Of these five types, only
Text can be used without modification or checks. Here’s how to decode the other four:
Integer
-- One would think that you could
use Integer types without modification, but there is one subtle gotcha. RADIUS integers are “unsigned”, meaning they
are always positive. iRules integers are signed – the left-most bit is used as
a flag to denote positive and negative numbers.
If the left-most bit is set, then the number is negative. So in some cases, the numbers coming from
RADIUS may show up as negative, rather than positive, numbers. You just need to make sure this left-most bit
is unset:
set
acctAuthen [RADIUS::avp 45 "integer"]
set
acctAuthen [expr { $acctAuthen && 0xff }]
if
{ $static::DEBUG eq 1 && $acctAuthen != "" } { puts
"Acct-Authentic: $acctAuthen" }
String
-- Since iRules can handle non-UTF-8 bytes in
its string type, there is no issue using what you get from the RADIUS packet
without modification. The problem comes if you want to print out or otherwise
log the contents of the String when its holding binary data. This can be done using a simple binary scan command:
set
acctSessId [RADIUS::avp 44 "string"]
binary
scan $acctSessId H* acctSessId
if
{ $static::DEBUG eq 1 && $acctSessId != "" } { puts
"Acct-Session-Id: $acctSessId" }
In /var/log/tmm:
… local/bigipfw
notice Acct-Session-Id: ff082000
IPAddress
-- Or “address” as its referenced in the spec. This is almost always an IPv4 address. When you retrieve this avp, you get a
four-byte string, with the four octets of an IPv4 address. It’s pretty simple
to decode:
set
a1 [RADIUS::avp 8 "ipaddr"]
; network byte order
binary
scan $a1 cccc a b c d
set
a [expr { $a & 0xff }]
; make unsigned values
set
b [expr { $b & 0xff }]
set
c [expr { $c & 0xff }]
set
d [expr { $c & 0xff }]
set
frmdIPAddr "$a.$b.$c.$d"
if
{ $static::DEBUG eq 1 & $frmdIPAddr != "" } { puts
"Framed-IP-Address: $frmdIPAddr" }
Time
-- These values are stored as a
four-byte “epoch” value (this is, the number of seconds since July 1, 1970…
which I believe was the next closest start of the month at the time the
programmer who wrote the procedure, wrote it).
Give that iRules is derived from the TCL programming language, we are
lucky in that TCL has built in functions to manipulate this value and print out
a date/time format that we can use:
set
eventTimestamp [RADIUS::avp 55 "integer"]
set
timest [clock format $eventTimestamp -format {%a %b %d %Y %H:%M:%S}]
if
{ $static::DEBUG eq 1 && $timest != "" } { puts "Event-Timestamp:
$timest" }
More
information about the RADIUS:: iRules commands can be found .