Forum Discussion
Creating a proper RADIUS Accounting-Response packet in iRules
If you do a lot of work with RADIUS messages being sent to your BIGIP so that you can get some information from another network node in the system, you are going to need to respond back to that node in a correct and proper way, so that you don’t mess it up, or otherwise fill up its error log with ‘improper response’ messages.
I was working on just that kind of iRule, and got it working. Here’s the code:
1:
2: RADIUS Acct-Resp packet
3:
4: input variables:
5: $rId -> RADIUS Request ID field
6: $rAuth -> RADIUS Request Authorization field
7: $static::SHARED_SECRET -> RADIUS Shared secret of the 2 nodes.
8:
9: UDP::drop ; kill the incoming packet, don’t need it.
10: set RADcode 5 ; RADIUS Accounting-Response Type code.
11: set md5hash [ format "05%02x00%02x" $rId 20 ]
12: set md5hash $md5hash$rAuth$static::SHARED_SECRET
13: set hash [ binary format H* $md5hash ]
14: set respAuth [md5 $hash]
15: set payldhdr [ binary format ccS $RADcode $rId 20 ]
16: set payload $payldhdr$respAuth
17: UDP::respond $payload
So the RADIUS Accounting-Response packet has, at a
minimum, four fields: RADIUS Type code(1 byte), ID number(1 byte),
Packet Length(2 byte Integer), and the Authenticator(16 bytes). Getting the
response authenticator correct is really the only tricky part.
Line 5: The RADIUS Request ID field comes from the incoming packet. You can retrieve this value previously in the iRule using a line of code like this: set rId [RADIUS::id]. Of course, this value can also be pulled out at the same time some other important fields are decoded using the sample code for line 6 below.
Line 6: The RADIUS Request Authorization field in the incoming packet is an MD5 hash of most if the incoming packet. To get this value, you will need to do a binary scan of the UDP packet:
set payload [UDP::payload]
binary scan $payload ccSH32a* rType rId rLen rAuth rPkt
In this example, we also pull out the Type Code (rType) and the packet ID (rId), the length of the overall packet, the Authorization field that we are looking for, and the rest of the packet, which should be all the AVP fields.
Line 9: We don’t need (and usually don’t want) the RADIUS Request packet from going on from the BIGIP, so we just drop the packet to prevent this.
Line 10: 0x05 is the
RADIUS Type Code for an Account-Response packet.
Line 11: Here’s where
we start working on our response authenticator. We are going to setup a
hexstring (which is hex characters displayed as a string; IE> “05140016” is
four bytes 0x05, 0x14, 0x00, 0x16), pack all of our values into it, convert it
to real binary hex, do the MD5 hash on the result, and use the MD5 checksum
result in the response packet. This line sets Type Code, id, and Length (hard
coded to 20 bytes).
Line 12: Using the hexstring from the last line, it adds the
Original request Authenticator, and the shared secret (which should already be
in hexstring format) to it. We now have
our complete hexstring that needs to be run through the MD5 checksum function.
Line 13: This line
simply converts the hexstring to a binary hex value.
Line 14: We get our
valid Authenticator for the response.
Line 15: Now we
create the actual response packet. This line sets the first three fields: Type
Code, id, and Length.
Line 16: We add the
header and the response Authenticator and we have our RADIUS
Accounting-Response packet.
Line 17: Send the
response back.
The RADIUS Accounting-Response protocol is documented in RFC-2866, Section 4.2.
- koenning_107182Nimbostratusthis irule shows how to craft a rfc compliant Radius Accouting Accept message
- Alex_DNimbostratusVery useful!
- player_72606Nimbostratus
Hi all,
first of all, great job on this one, works flawlessly 🙂 i'm trying to understand couple of things here, and i would appreciate your help ,I could not understand what are the following steps are needed :
set md5me [binary format cH2SH32H$static::secretlen $code $ident $len $auth $static::secrethex] running the MD5 set ResponseAuthRaw [ md5 $md5me] doing some string to binary conversion, i am sure i can avoid this, need to optimize it binary scan $ResponseAuthRaw H* ResponseAuth crafting the response packet set packetdata [binary format cH2SH32 $code $ident $len $ResponseAuth]
- nitassEmployee
he is creating response authenticator.
Response Authenticator The value of the Authenticator field in Access-Accept, Access- Reject, and Access-Challenge packets is called the Response Authenticator, and contains a one-way MD5 hash calculated over a stream of octets consisting of: the RADIUS packet, beginning with the Code field, including the Identifier, the Length, the Request Authenticator field from the Access-Request packet, and the response Attributes, followed by the shared secret. That is, ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) where + denotes concatenation.
Remote Authentication Dial In User Service (RADIUS)
- player_72606Nimbostratus
why do we need the binary scan? it's already done at the begining
- nitassEmployee
why do we need the binary scan?
it converts binary (ResponseAuthRaw) to hex (ResponseAuth) which then is used to craft response (packetdata).
- AceDawg1Nimbostratus
Good day all,
Trying to extend the functionality of these iRules. We've got an F5 sitting in front of a ClearPass RADIUS farm for 802.1x. We'd like to send a RADIUS access-accept message if the backend RADIUS are offline (fail open). The Cisco switch we're testing with kicks the following error message in the debug:
Hashes are not matching it appears. I suspect the issue has to do with the radius attribute being sent to the client. Tried creating the response without it but the result is a malformed packet. Any pointers are greatly appreciated.
when RULE_INIT { set static::secret "testing" binary scan $static::secret H* static::secrethex } when CLIENT_DATA { binary scan [UDP::payload] cH2SH32 code ident len auth if { $code == 1 } { set code 2 set len 134 set rad_attr_svr 25 set rad_attr_len_svr 58 set rad_attr_string 6bf92bf8920b46e49ca55f519c9194f0bc0b0000000000005230303030303162342d30312d35623030303734340000000000000000000000 set md5me [binary format cH2SH32H8 $code $ident $len $auth $static::secrethex] set ResponseAuthRaw [ md5 $md5me] binary scan $ResponseAuthRaw H* ResponseAuth set packetdata [binary format cH2SH32cca* $code $ident $len $ResponseAuth $rad_attr_svr $rad_attr_len_svr $rad_attr_string] UDP::drop clientside { UDP::respond ${packetdata} } } else { log local0. "Dropping Message" UDP::drop } }
Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com