RADIUS Disconnect support
Hi Guys I have been playing with (read: using in production) RADIUS disconnect support and I have a few ideas about how we can/should integrate it into FreeRADIUS server which I thought I would share with you all for your comments. Firstly let me explain how I am using it. I have the following defined: exec radsqlkill { wait = yes program = "/usr/local/bin/radsqlkill.pl %{Calling-Station-Id}" shell_escape = yes output = none packet_type = Access-Request } authorize { radsqlkill } Now, radsqlkill.pl is designed to kill any active sessions with a Disconnect packet based on info from the radacct table. It can be provided with a username, or in my case Calling-Station-Id. Basically this lets me do simultaneous use limiting but instead of rejecting the second login it disconnects the first and allows the second. I think that this functionality and more needs to be rolled into radiusd. Basically we need to be able to do the following things: 1) Receive a disconnect packet on port 1700 and check a shared secret (New listen type in radiusd.conf) 2) Query the radacct table to find disconnect attributes based on a supplied attributes (username, callingstationid etc) 3) Send disconnect packet(s) to NAS with a shared secret and return status Now the shared secret in 1) is different from the shared secret in 3). They are both NEW config options and need to be saved somewhere. I think to keep things simple 1) should be an additional option in each realm in proxy.conf (as Disconnect senders will _mostly_ correspond with home servers) and 3) should be an additional option in each client in clients.conf (as Disconnect receivers will _mostly_ correspond with client NAS) It is technically possible that we would want to allow disconnect packets from non home servers, and send them to NAS which are not clients (think where you have chained RADIUS proxies) but I think it will make things unnecessary complicated. What do others think? I think the 3 steps I have listed above will allow everyone to be able to do what they want with Disconnect packets. Basically in the situation where radius is acting as a proxy and you want to allow a home server to disconnect a user on a NAS client you will need all 3 steps (in order). To do what I am doing above with my perl script you will only need steps 2) and 3). People who want to generate disconnect attributes from arbitrary input (a script or custom module) will simply use 3). In all cases the module should look up the appropriate shared secret from the NAS table or clients.conf. Does anyone have anything to add to this? I plan to start implimenting this as I have time as my perl script causes a 500ms Authentication delay (mostly due to perl startup) which I would like to get rid of :-) Cheers -- Peter Nixon http://www.peternixon.net/ PGP Key: http://www.peternixon.net/public.asc
Peter Nixon wrote:
Firstly let me explain how I am using it. I have the following defined:
exec radsqlkill { wait = yes program = "/usr/local/bin/radsqlkill.pl %{Calling-Station-Id}" shell_escape = yes output = none packet_type = Access-Request }
That could be replaced with rlm_perl, I think. That would remove most of the startup overhead of forking a separate program & starting perl.
I think that this functionality and more needs to be rolled into radiusd. Basically we need to be able to do the following things:
1) Receive a disconnect packet on port 1700 and check a shared secret (New listen type in radiusd.conf)
That's not hard.
2) Query the radacct table to find disconnect attributes based on a supplied attributes (username, callingstationid etc)
That's more complicated. I'll say why later.
3) Send disconnect packet(s) to NAS with a shared secret and return status
That's not hard.
Now the shared secret in 1) is different from the shared secret in 3). They are both NEW config options and need to be saved somewhere. I think to keep things simple 1) should be an additional option in each realm in proxy.conf (as Disconnect senders will _mostly_ correspond with home servers) and 3) should be an additional option in each client in clients.conf (as Disconnect receivers will _mostly_ correspond with client NAS)
Yes.
It is technically possible that we would want to allow disconnect packets from non home servers, and send them to NAS which are not clients (think where you have chained RADIUS proxies) but I think it will make things unnecessary complicated. What do others think?
As an admin, it's easier for me to send disconnect packets to a RADIUS server than try to figure out which NAS the user is on. But that's just my $0.02.
I think the 3 steps I have listed above will allow everyone to be able to do what they want with Disconnect packets. Basically in the situation where radius is acting as a proxy and you want to allow a home server to disconnect a user on a NAS client you will need all 3 steps (in order). To do what I am doing above with my perl script you will only need steps 2) and 3). People who want to generate disconnect attributes from arbitrary input (a script or custom module) will simply use 3).
Allowing home servers to disconnect people is horrid. Have you read the text in the RFCs's for how to handle trust? i.e. Is this home server really supposed to be sending a disconnect for that user? Or how to handle the whole reverse proxy chain? It's disgusting, and almost impossible to do right. If FreeRADIUS is the server the NAS talks to, disconnect is awkward, but not impossible. If it's a proxying server, disconnect is horrid. I have some ideas to make it easier, but they require all RADIUS servers to implement the same updated algorithm. If that's OK, we can move ahead. Alan DeKok. -- http://deployingradius.com - The web site of the book http://deployingradius.com/blog/ - The blog
On Tue 23 Jan 2007 09:11, Alan DeKok wrote:
Peter Nixon wrote:
Firstly let me explain how I am using it. I have the following defined:
exec radsqlkill { wait = yes program = "/usr/local/bin/radsqlkill.pl %{Calling-Station-Id}" shell_escape = yes output = none packet_type = Access-Request }
That could be replaced with rlm_perl, I think. That would remove most of the startup overhead of forking a separate program & starting perl.
Yes. That is something I plan to investigate. I initially wrote the perl script to be called from a website (to allow manual disconnect of users) so I haven't yet gone to the trouble to rewrite it for rlm_perl.
I think that this functionality and more needs to be rolled into radiusd. Basically we need to be able to do the following things:
1) Receive a disconnect packet on port 1700 and check a shared secret (New listen type in radiusd.conf)
That's not hard.
2) Query the radacct table to find disconnect attributes based on a supplied attributes (username, callingstationid etc)
That's more complicated. I'll say why later.
Complicated. Yes. Impossible. No....
3) Send disconnect packet(s) to NAS with a shared secret and return status
That's not hard.
Now the shared secret in 1) is different from the shared secret in 3). They are both NEW config options and need to be saved somewhere. I think to keep things simple 1) should be an additional option in each realm in proxy.conf (as Disconnect senders will _mostly_ correspond with home servers) and 3) should be an additional option in each client in clients.conf (as Disconnect receivers will _mostly_ correspond with client NAS)
Yes.
It is technically possible that we would want to allow disconnect packets from non home servers, and send them to NAS which are not clients (think where you have chained RADIUS proxies) but I think it will make things unnecessary complicated. What do others think?
As an admin, it's easier for me to send disconnect packets to a RADIUS server than try to figure out which NAS the user is on. But that's just my $0.02.
Yes. Thats true of course, and I was also thinking the same thing. It would technically be possible to send directly to the NAS-IP-Address as listed in radacct if there was a disconnect key listed for that IP. However only dealing with "clients" certainly makes things easier. In either case, radiusd should act like a NAS when it receives a disconnect packet in that it should figure out (via an SQL query) if that "session" is online, and if so where to send a disconnect to. Notice that I said "a" disconnect. The disconnect packet we send out SHOULD be a whole new packet, which may include attributes received in the disconnect packet from the home server or may include other attributes from the same session in our database. For example on my proxies I overwrite NAS-IP-Address with my own IP address so as not to a) leak information about upstream NAS b) confuse the billing interfaces and IP pool management of my customer's home servers. I will therefore have to put the real NAS-IP-Address in an disconnect packets I send (which is stored in radacct) rather than forwarding the NAS-IP-Address I receive in disconnect packets from home servers.
I think the 3 steps I have listed above will allow everyone to be able to do what they want with Disconnect packets. Basically in the situation where radius is acting as a proxy and you want to allow a home server to disconnect a user on a NAS client you will need all 3 steps (in order). To do what I am doing above with my perl script you will only need steps 2) and 3). People who want to generate disconnect attributes from arbitrary input (a script or custom module) will simply use 3).
Allowing home servers to disconnect people is horrid. Have you read the text in the RFCs's for how to handle trust?
I have not, but I will.
i.e. Is this home server really supposed to be sending a disconnect for that user? Or how to handle the whole reverse proxy chain? It's disgusting, and almost impossible to do right.
Well, IF we have a disconnect secret listed for the home server AND IF the home server knows the "X-Ascend-Session-Svr-Key" it means that we sent them an accounting packet for the session and didn't strip "X-Ascend-Session-Svr-Key" which means that we trust them to disconnect the user. I think this will work fine for as many proxies in a chain as necessary. The whole thing relies on each proxy in the chain having a local acct database listing all online users. I understand that its not ideal, but its not a huge imposition for most deployments, and it has the distinct advantage of allow rewriting of requests and knowing exactly where to send a request. (At least in the way I am deployed it does :-)
If FreeRADIUS is the server the NAS talks to, disconnect is awkward, but not impossible. If it's a proxying server, disconnect is horrid.
I am prepared to ignore any non-freeradius servers at this point unless there are some existing implementations which work better than that way I describe above.
I have some ideas to make it easier, but they require all RADIUS servers to implement the same updated algorithm. If that's OK, we can move ahead.
It's fine with me. A working solution (even for a subset of the problem) is better than no solution. Cheers -- Peter Nixon http://www.peternixon.net/ PGP Key: http://www.peternixon.net/public.asc
participants (2)
-
Alan DeKok -
Peter Nixon