Hello, problem solved. I post this message for the sake of completeness and in case, if anyone will ever need to solve a similar problem. Of course, any comments on how my solution can be improved are welcomed. 1) At the SQL side I created a view (active_users) with three columns (nasipaddress, nasport and vlan) that always shows the active sessions. Basically it selects all entries from the accounting table (radacct) where the stop time is NULL and then the result is joined with the user attribute table (radreply) in order to append the vlan to each record. Of course, the join is done by the user name. 2) In the RADIUS config the following expression is added to the post-auth section of the default server. # Prevent multiple untagged VLANs on the same port at the same time. # Otherwise there would be short-curcuit fault between the affected VLANs if ( "%{sql:SELECT COUNT(*) FROM active_users WHERE nasipaddress = '%{NAS-IP-Address}' AND nasport = %{NAS-Port} AND vlan <> '%{reply:Tunnel-Private-Group-ID}' }" != 0 ) { reject } The SQL statement counts all (active) sessions on the same NAS on the same NAS port with a different VLAN assignment than the VLAN the current user is going to be assigned to. If the number does not equal zero, there is at least one session on the same port with a different VLAN. In that case the user is rejected. 3) Prevent stalled-session Accouning-Stop messages can be lost. In that case a session will falsely remain active and thus likely block out any other user. I use an interim update intervall with five minutes. If three updates were missed, i.e. the last update time is less then the current system time minus 15 minutes, the session is considered to be stalled and the stop time is set to the last update time. This way a stalled session is closed 15 minutes after the last update. Yours, Matthias Am Sonntag 16 Dezember 2012, 17:07:53 schrieb Alan DeKok:
Matthias Nagel wrote:
Now, I would like to write some kind of RADIUS policy to prevent this behaviour.
(a) store information in a database (b) use "unlang" to query the database
This policy is supposed to do the following during the post-authentication phase:
1) If there is no active session on the NAS port, just return Access-Accept
You may need to create a new table which stores active sessions. INSERT data into it on authentication / accounting start. DELETE data on accounting stop.
2) If there is at least one active session on the NAS port and the 'Tunnel-Private-Group-ID' of that session equals the 'Tunnel-Private-Group-ID' of the new request, return Access-Accept.
Store the Tunnel-Private-Group-ID of a session on INSERT. Query it on the next session authentication.
3) If there is at least one active session on the NAS port and the 'Tunnel-Private-Group-ID' of that session DOES NOT equal the 'Tunnel-Private-Group-ID' of the new request, return Access-Reject.
Query the DB. If it doesn't match, reject.
Is this possible to do? I have the accounting information in a SQL database, hence I know, if there are active sessions on some port. But I do not know, which would be the correct RADIUS configuration section and I do not know if "unlang" or some other configuration directive can perform such a check.
"unlang" is just a way to write policies. It does NOT store data. SQL databases store data.
The two together can solve this problem.
Alan DeKok. - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
Matthias Nagel Willy-Andreas-Allee 1, Zimmer 506 76131 Karlsruhe Telefon: +49-721-8695-1506 Mobil: +49-151-15998774 e-Mail: matthias.h.nagel@gmail.com ICQ: 499797758 Skype: nagmat84