How to get current datetime in freeradius?
Hello, Is there a way to get the current date and time in /etc/freeradius/3.0/sites-enabled/default? I checked man unlang but couldn't find anything. What I'm trying to achieve is if Now() > Expires-At then disconnect the user. preacct { update request { Expires-At = "%{sql:SELECT expires_at FROM main_db.`user` WHERE main_db.`user`.username ='%{User-Name}'}" } if ("%{Now()}"} > Expires-At) { update disconnect { &User-Name = "%{User-Name}" } } Many Thanks, Houman
Hi Houman,
Is there a way to get the current date and time in /etc/freeradius/3.0/sites-enabled/default? I checked man unlang but couldn't find anything. have a look here:
https://wiki.freeradius.org/config/run_time_variables#one-character-variable... Kind regards, Christian Strauf -- Dipl.-Math. Christian Strauf Clausthal Univ. of Technology E-Mail: strauf@rz.tu-clausthal.de Rechenzentrum Web: www.rz.tu-clausthal.de Erzstraße 18 Tel.: +49-5323-72-2086 Fax: -992086 D-38678 Clausthal-Zellerfeld
On 1/10/2019, at 1:35 PM, Christian Strauf <strauf@rz.tu-clausthal.de> wrote:
Hi Houman,
Is there a way to get the current date and time in /etc/freeradius/3.0/sites-enabled/default? I checked man unlang but couldn't find anything. have a look here:
https://wiki.freeradius.org/config/run_time_variables#one-character-variable... <https://wiki.freeradius.org/config/run_time_variables#one-character-variables>
You may also want to consider using the Event-Timestamp or some other attribute, rather than the time on the system doing the processing of the packet - so that if there are delays or similar the packet is processed correctly as though there was not any delays. In this case it probably doesn’t matter, other cases it might, so a good habit to get in to at least considering it. -- Nathan Ward
Hello Nathan, Fair point. I have tried your way like this, but I get an error with Event-Timestamp. This is not predefined like %{User-Name} I take it. So how do I get that? /etc/freeradius/3.0/sites-enabled/default[565]: (Expires-At < %{Event-Timestamp}) { /etc/freeradius/3.0/sites-enabled/default[565]: ^ Failed to parse value for attribute preacct { update request { Expires-At = "%{sql:SELECT expires_at FROM main_db.`user` WHERE main_db.`user`.username ='%{User-Name}'}" } if (Expires-At < %{Event-Timestamp}) { update disconnect { &User-Name = "%{User-Name}" } } Many Thanks, Houman On Tue, 1 Oct 2019 at 13:52, Nathan Ward <lists+freeradius@daork.net> wrote:
On 1/10/2019, at 1:35 PM, Christian Strauf <strauf@rz.tu-clausthal.de> wrote:
Hi Houman,
Is there a way to get the current date and time in /etc/freeradius/3.0/sites-enabled/default? I checked man unlang but couldn't find anything. have a look here:
https://wiki.freeradius.org/config/run_time_variables#one-character-variable... < https://wiki.freeradius.org/config/run_time_variables#one-character-variable...
You may also want to consider using the Event-Timestamp or some other attribute, rather than the time on the system doing the processing of the packet - so that if there are delays or similar the packet is processed correctly as though there was not any delays.
In this case it probably doesn’t matter, other cases it might, so a good habit to get in to at least considering it.
-- Nathan Ward
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
On Oct 1, 2019, at 5:56 PM, Houman <houmie@gmail.com> wrote
Fair point. I have tried your way like this, but I get an error with Event-Timestamp. This is not predefined like %{User-Name} I take it. So how do I get that?
That attribute is sent by the NAS in a packet. If it isn't sent in a packet, see the Wiki for variable expansions. You can use the local time via %l Alan DeKok.
Thanks Alan, Ok fair point. I have now gone back to the document that Christian sent me earlier: https://wiki.freeradius.org/config/run_time_variables#one-character-variable... /etc/freeradius/3.0/sites-enabled/default[565]: (Expires-At < %{l}) { /etc/freeradius/3.0/sites-enabled/default[565]: ^ Failed to parse value for attribute /etc/freeradius/3.0/sites-enabled/default[565]: (Expires-At < %l) { /etc/freeradius/3.0/sites-enabled/default[565]: ^ Failed to parse value for attribute I'm still unable to get the local timestamp. Do I have to enable anything else? Thanks, Houman On Wed, 2 Oct 2019 at 01:11, Alan DeKok <aland@deployingradius.com> wrote:
On Oct 1, 2019, at 5:56 PM, Houman <houmie@gmail.com> wrote
Fair point. I have tried your way like this, but I get an error with Event-Timestamp. This is not predefined like %{User-Name} I take it. So how do I get that?
That attribute is sent by the NAS in a packet. If it isn't sent in a packet, see the Wiki for variable expansions. You can use the local time via %l
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
Hi Houman
I'm still unable to get the local timestamp. Do I have to enable anything else? If you need the local time multiple times (or did I misunderstand you?), try something like this:
update control { &Tmp-Integer-0 := "%l" } Use this in your configuration (note that I made some modifications to "Expires-At": preacct { update control { &Tmp-Integer-0 := "%l" } update request { &Expires-At := "%{sql:SELECT expires_at FROM main_db.`user` WHERE main_db.`user`.username ='%{User-Name}'}" } if (&control:Tmp-Integer-0 > &request:Expires-At) { update disconnect { &User-Name = "%{User-Name}" } } ... } If you don't need the time multiple times, you should be able to use "%l" instead of &control:Tmp-Integer-0. Also note that you need to use some other Tmp-Integer-0 if you already use that pre-defined control variable. Kind regards, Christian Strauf
Hello Christian, You are right that I need to compare every time the current time against the membership expiration date. Hence I should get it multiple times. The issue is now that I need to convert the MySQL date Expires-At to integer so that the two are comparable. Because right now Expires-At is set as Date: echo 'ATTRIBUTE Expires-At 3001 date' >> /etc/freeradius/3.0/dictionary And it throws this error: /etc/freeradius/3.0/sites-enabled/default[568]: (&control:Tmp-Integer-0 > &request:Expires-At) { /etc/freeradius/3.0/sites-enabled/default[568]: ^ Attribute comparisons must be of the same data type So I changed it to integer: echo 'ATTRIBUTE Expires-At 3001 integer' >> /etc/freeradius/3.0/dictionary And got it running, but naturally it doesn't convert the date to integer. (23) # Executing section preacct from file /etc/freeradius/3.0/sites-enabled/default (23) preacct { (23) [preprocess] = ok (23) update control { (23) EXPAND %l (23) --> 1569999851 (23) &Tmp-Integer-0 := 1569999851 (23) } # update control = noop (23) update request { (23) EXPAND %{User-Name} (23) --> houman (23) SQL-User-Name set to 'houman' rlm_sql (sql): Reserved connection (20) (23) Executing select query: SELECT expires_at FROM main_db.`user` WHERE main_db.`user`.username ='houman' rlm_sql (sql): Released connection (20) Need 6 more connections to reach 10 spares rlm_sql (sql): Opening additional connection (24), 1 of 28 pending slots used rlm_sql_mysql: Starting connect to MySQL server rlm_sql_mysql: Connected to database 'radius_db' on 3.10.46.171 via TCP/IP, server version 8.0.17, protocol version 10 (23) EXPAND %{sql:SELECT expires_at FROM main_db.`user` WHERE main_db.`user`.username ='%{User-Name}'} (23) --> 2019-12-27 13:22:05 (23) } # update request = fail (23) } # preacct = fail (23) Not sending reply to client. Is %l a unix time stamp? Is there a good way to covert the date to integer within Radius? So that I don't have to change the database schema and add a timestamp in there? Alternatively there could be a way to calculate it in place. Many Thanks, Houman On Wed, 2 Oct 2019 at 07:38, Christian Strauf <strauf@rz.tu-clausthal.de> wrote:
Hi Houman
I'm still unable to get the local timestamp. Do I have to enable anything else? If you need the local time multiple times (or did I misunderstand you?), try something like this:
update control { &Tmp-Integer-0 := "%l" }
Use this in your configuration (note that I made some modifications to "Expires-At":
preacct { update control { &Tmp-Integer-0 := "%l" } update request { &Expires-At := "%{sql:SELECT expires_at FROM main_db.`user` WHERE main_db.`user`.username ='%{User-Name}'}" } if (&control:Tmp-Integer-0 > &request:Expires-At) { update disconnect { &User-Name = "%{User-Name}" } } ... }
If you don't need the time multiple times, you should be able to use "%l" instead of &control:Tmp-Integer-0. Also note that you need to use some other Tmp-Integer-0 if you already use that pre-defined control variable.
Kind regards, Christian Strauf- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
Hi Houman, "%l" gives you POSIX time (seconds since the Unix epoch). You should be able to modify your query like this to make it work (make sure to test it, it's just off the top of my head): %{sql:SELECT UNIX_TIMESTAMP(expires_at) FROM main_db.`user` WHERE main_db.`user`.username ='%{User-Name}'} UNIX_TIMESTAMP should convert the date to POSIX time in seconds (unsigned integer). Kind regards, Christian Strauf
Hi Christian, It works. Totally awesome thank you for all your help. Regards Houman On Wed, 2 Oct 2019 at 10:39, Christian Strauf <strauf@rz.tu-clausthal.de> wrote:
Hi Houman,
"%l" gives you POSIX time (seconds since the Unix epoch). You should be able to modify your query like this to make it work (make sure to test it, it's just off the top of my head):
%{sql:SELECT UNIX_TIMESTAMP(expires_at) FROM main_db.`user` WHERE main_db.`user`.username ='%{User-Name}'}
UNIX_TIMESTAMP should convert the date to POSIX time in seconds (unsigned integer).
Kind regards, Christian Strauf
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
Hi Christian, There are only two issues, I wanted to discuss here with the group: 1) Is there a way to send a custom message to the NAS when a disconnect based on the custom condition happens? This way the user is not wondering why he keeps getting disconnected but gets to know the real reason behind it. 2) Even though I have added the condition to "authorize", "accounting" and "preacct" sections, the initial disconnect attempt remains unresponsive. (11) SQL-User-Name set to 'houman' rlm_sql (sql): Reserved connection (9) (11) Executing select query: SELECT UNIX_TIMESTAMP(expires_at) FROM main_db.`user` WHERE main_db.`user`.username ='houman' rlm_sql (sql): Released connection (9) (11) EXPAND %{sql:SELECT UNIX_TIMESTAMP(expires_at) FROM main_db.`user` WHERE main_db.`user`.username ='%{User-Name}'} (11) --> 1545916925 (11) &Expires-Timestamp := 1545916925 (11) } # update request = noop (11) if (&control:Current-Timestamp > &request:Expires-Timestamp) { (11) if (&control:Current-Timestamp > &request:Expires-Timestamp) -> TRUE (11) if (&control:Current-Timestamp > &request:Expires-Timestamp) { (11) update disconnect { (11) EXPAND %{User-Name} (11) --> houman (11) &User-Name = houman (11) } # update disconnect = noop (11) } # if (&control:Current-Timestamp > &request:Expires-Timestamp) = noop (11) } # accounting = updated (11) Sent Disconnect-Request Id 221 from 0.0.0.0:48470 to 127.0.0.1:3799 length 28 (11) User-Name = "houman" (11) Sent Accounting-Response Id 156 from 127.0.0.1:1813 to 127.0.0.1:51530 length 0 (11) Finished request (11) Cleaning up request packet ID 156 with timestamp +50 Waking up in 1.8 seconds. (11) Clearing existing &reply: attributes (11) Received Disconnect-NAK Id 221 from 127.0.0.1:3799 to 127.0.0.1:48470 length 20 (11) # Executing section post-proxy from file /etc/freeradius/3.0/sites-enabled/default (11) post-proxy { (11) eap: No pre-existing handler found (11) [eap] = noop (11) } # post-proxy = noop (11) Cleaning up request packet ID 156 with timestamp +50 Waking up in 3.4 seconds. Only after the 300 seconds pass (which is defined in Acct-Interim-Interval) the second disconnect attempt successfully disconnects the user. post-auth { update reply { Acct-Interim-Interval = 300 } *300 seconds later:* EXPAND %{sql:SELECT UNIX_TIMESTAMP(expires_at) FROM main_db.`user` WHERE main_db.`user`.username ='%{User-Name}'} (13) --> 1545916925 (13) &Expires-Timestamp := 1545916925 (13) } # update request = noop (13) if (&control:Current-Timestamp > &request:Expires-Timestamp) { (13) if (&control:Current-Timestamp > &request:Expires-Timestamp) -> TRUE (13) if (&control:Current-Timestamp > &request:Expires-Timestamp) { (13) update disconnect { (13) EXPAND %{User-Name} (13) --> houman (13) &User-Name = houman (13) } # update disconnect = noop (13) } # if (&control:Current-Timestamp > &request:Expires-Timestamp) = noop (13) } # accounting = updated (13) Sent Disconnect-Request Id 103 from 0.0.0.0:48470 to 127.0.0.1:3799 length 28 (13) User-Name = "houman" (13) Sent Accounting-Response Id 158 from 127.0.0.1:1813 to 127.0.0.1:51530 length 0 (13) Finished request (13) Cleaning up request packet ID 158 with timestamp +60 Waking up in 1.8 seconds. (13) Clearing existing &reply: attributes (13) Received Disconnect-NAK Id 103 from 127.0.0.1:3799 to 127.0.0.1:48470 length 20 (13) # Executing section post-proxy from file /etc/freeradius/3.0/sites-enabled/default (13) post-proxy { (13) eap: No pre-existing handler found (13) [eap] = noop (13) } # post-proxy = noop (13) Cleaning up request packet ID 158 with timestamp +60 Ready to process requests I could obviously reduce this to 10 seconds from 300 seconds, but it's not ideal since it's heavier on the database. Not sure if you have an idea how to improve this. Many Thanks, Houman On Wed, 2 Oct 2019 at 13:09, Christian Strauf <strauf@rz.tu-clausthal.de> wrote:
Hi Houman,
"%l" gives you POSIX time (seconds since the Unix epoch). You should be able to modify your query like this to make it work (make sure to test it, it's just off the top of my head):
%{sql:SELECT UNIX_TIMESTAMP(expires_at) FROM main_db.`user` WHERE main_db.`user`.username ='%{User-Name}'}
UNIX_TIMESTAMP should convert the date to POSIX time in seconds (unsigned integer).
Kind regards, Christian Strauf
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
On Oct 14, 2019, at 4:03 PM, Houman <houmie@gmail.com> wrote:
There are only two issues, I wanted to discuss here with the group:
1) Is there a way to send a custom message to the NAS when a disconnect based on the custom condition happens? This way the user is not wondering why he keeps getting disconnected but gets to know the real reason behind it.
No. There is no ability in RADIUS to send custom messages in a Disconnect-Request packet. Even if there was, the underlying protocols (PPP, EAP, etc.) usually don't provide for messages on disconnect.
2) Even though I have added the condition to "authorize", "accounting" and "preacct" sections, the initial disconnect attempt remains unresponsive.
Read the debug log to see why.
(11) Sent Disconnect-Request Id 221 from 0.0.0.0:48470 to 127.0.0.1:3799 length 28 (11) User-Name = "houman" ... (11) Received Disconnect-NAK Id 221 from 127.0.0.1:3799 to 127.0.0.1:48470 length 20
The NAS sent a NAK. Which meant that the NAS refused to disconnect the user. Very likely because the attributes in the Disconnect-Request packet were not enough to identify the users session. What attributes *should* be in the Disconnect-Request? The short answer is to read the NAS documentation. Generally the best guess is the same session attributes which are in the Accounting-Request packets.
Only after the 300 seconds pass (which is defined in Acct-Interim-Interval) the second disconnect attempt successfully disconnects the user.
No.
(13) Sent Disconnect-Request Id 103 from 0.0.0.0:48470 to 127.0.0.1:3799 length 28 (13) User-Name = "houman" ... (13) Received Disconnect-NAK Id 103 from 127.0.0.1:3799 to 127.0.0.1:48470 length 20
The NAS sends a NAK again. The user might be disconnected at that time, but it has nothing to do with the Disconnect-Request packet that was sent. Alan DeKok.
Hi Alan, Thank you very much for all your help on this. I got in touch with the NAS makers (StrongSwan) and did some analysis together. Essentially the NAS only needs the User-Name for the disconnect request, which I'm already providing. The reason why it sends a NAK is that no IKE_SA was found with a matching remote identity. This is what happens on the NAS side in the log file:
received RADIUS DAE Disconnect-Request for houman from 127.0.0.1 no IKE_SA matches houman, sending Disconnect-NAK
So the question is why the disconnect fails upon login, but a bit later on it works again: "You can't use this method for IKE_SAs that are concurrently being established. Such IKE_SAs are locked and, thus, skipped by the Disconnect handler. This particular IKE_SA is waiting for the EAP-Accounting response and until that's received and the IKE_AUTH response has been sent, the IKE_SA can't be closed via this code path. It also affects SAs later if they are locked for some reason (e.g. handling rekeyings or DPDs, but not interim Accounting updates as the SA is unlocked before sending those). So perhaps the RADIUS server could retry sending the Disconnect message if it still has state around for the user but received a NAK (or delay sending the Disconnect for a bit)." It's a bit of a dilemma. I have a reason to disconnect the user based on a condition. But the user can still reconnect and I won't be able to disconnect him straight away. I have to wait until the next Acct-Interim-Interval kicks in before I can actually disconnect him again. Since the authentication happens through Freeradius, is there a way to reject the user immediately during authentication other than sending disconnect requests? Many Thanks, Houman On Tue, 15 Oct 2019 at 04:24, Alan DeKok <aland@deployingradius.com> wrote:
On Oct 14, 2019, at 4:03 PM, Houman <houmie@gmail.com> wrote:
There are only two issues, I wanted to discuss here with the group:
1) Is there a way to send a custom message to the NAS when a disconnect based on the custom condition happens? This way the user is not wondering why he keeps getting disconnected but gets to know the real reason behind it.
No. There is no ability in RADIUS to send custom messages in a Disconnect-Request packet. Even if there was, the underlying protocols (PPP, EAP, etc.) usually don't provide for messages on disconnect.
2) Even though I have added the condition to "authorize", "accounting" and "preacct" sections, the initial disconnect attempt remains unresponsive.
Read the debug log to see why.
(11) Sent Disconnect-Request Id 221 from 0.0.0.0:48470 to 127.0.0.1:3799 length 28 (11) User-Name = "houman" ... (11) Received Disconnect-NAK Id 221 from 127.0.0.1:3799 to 127.0.0.1:48470 length 20
The NAS sent a NAK. Which meant that the NAS refused to disconnect the user. Very likely because the attributes in the Disconnect-Request packet were not enough to identify the users session.
What attributes *should* be in the Disconnect-Request? The short answer is to read the NAS documentation. Generally the best guess is the same session attributes which are in the Accounting-Request packets.
Only after the 300 seconds pass (which is defined in Acct-Interim-Interval) the second disconnect attempt successfully disconnects the user.
No.
(13) Sent Disconnect-Request Id 103 from 0.0.0.0:48470 to 127.0.0.1:3799 length 28 (13) User-Name = "houman" ... (13) Received Disconnect-NAK Id 103 from 127.0.0.1:3799 to 127.0.0.1:48470 length 20
The NAS sends a NAK again.
The user might be disconnected at that time, but it has nothing to do with the Disconnect-Request packet that was sent.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
On Oct 15, 2019, at 10:08 AM, Houman <houmie@gmail.com> wrote:
Thank you very much for all your help on this. I got in touch with the NAS makers (StrongSwan) and did some analysis together. Essentially the NAS only needs the User-Name for the disconnect request, which I'm already providing. The reason why it sends a NAK is that no IKE_SA was found with a matching remote identity. This is what happens on the NAS side in the log file:
Ok.
It's a bit of a dilemma. I have a reason to disconnect the user based on a condition. But the user can still reconnect and I won't be able to disconnect him straight away.
You should be able to save the condition in a DB, and then *reject* the next connection attempt by the user.
I have to wait until the next Acct-Interim-Interval kicks in before I can actually disconnect him again. Since the authentication happens through Freeradius, is there a way to reject the user immediately during authentication other than sending disconnect requests?
Return Access-Reject. Alan DeKok.
Hi Alan, May you elaborate a bit more on Access-Reject? Do I still set it in /etc/freeradius/3.0/sites-enabled/default like this? authorize { update control { &Current-Timestamp := "%l" } update request { &Expires-Timestamp := "%{sql:SELECT UNIX_TIMESTAMP(expires_at) FROM main_db.`user` WHERE main_db.`user`.username ='%{User-Name}'}" } if (&control:Current-Timestamp > &request:Expires-Timestamp) { * always reject {* * rcode = reject* * }* } Many Thanks, Houman On Tue, 15 Oct 2019 at 18:03, Alan DeKok <aland@deployingradius.com> wrote:
On Oct 15, 2019, at 10:08 AM, Houman <houmie@gmail.com> wrote:
Thank you very much for all your help on this. I got in touch with the NAS makers (StrongSwan) and did some analysis together. Essentially the NAS only needs the User-Name for the disconnect request, which I'm already providing. The reason why it sends a NAK is that no IKE_SA was found with a matching remote identity. This is what happens on the NAS side in the log file:
Ok.
It's a bit of a dilemma. I have a reason to disconnect the user based on a condition. But the user can still reconnect and I won't be able to disconnect him straight away.
You should be able to save the condition in a DB, and then *reject* the next connection attempt by the user.
I have to wait until the next Acct-Interim-Interval kicks in before I can actually disconnect him again. Since the authentication happens through Freeradius, is there a way to reject the user immediately during authentication other than sending disconnect requests?
Return Access-Reject.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
On Oct 15, 2019, at 11:11 AM, Houman <houmie@gmail.com> wrote:
Hi Alan,
May you elaborate a bit more on Access-Reject?
Do I still set it in /etc/freeradius/3.0/sites-enabled/default like this?
You just use the word "reject". You don't copy module configurations into the "authorize" section. Alan DeKok.
It works!! Amazing! Thank you Alan. On Tue, 15 Oct 2019 at 19:15, Alan DeKok <aland@deployingradius.com> wrote:
On Oct 15, 2019, at 11:11 AM, Houman <houmie@gmail.com> wrote:
Hi Alan,
May you elaborate a bit more on Access-Reject?
Do I still set it in /etc/freeradius/3.0/sites-enabled/default like this?
You just use the word "reject". You don't copy module configurations into the "authorize" section.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
participants (4)
-
Alan DeKok -
Christian Strauf -
Houman -
Nathan Ward