Hello, To update users rate-limits dynamically i have defined following custom attributes in dictionary file ATTRIBUTE Subscriber-NAS-Vendor 3050 string ATTRIBUTE Subscriber-Total-Bytes 3051 integer64 ATTRIBUTE Subscriber-Quota 3052 integer64 ATTRIBUTE Fair-Usage-Rate 3053 integer and written following unlang codes in accounting section: # Rate Policy for unlimited, fair usage and limeted accounts update control { Subscriber-NAS-Vendor = "%{sql: SELECT nas_vendor FROM radcheck WHERE username='%{User-Name}' AND attribute = 'Cleartext-Password' limit 1}" Subscriber-Quota = "%{sql:SELECT IFNULL(quota, 0) FROM radcheck WHERE username='%{User-Name}' AND attribute = 'Cleartext-Password' limit 1}" } if (&control:Subscriber-Quota > 0) { update control { Subscriber-Total-Bytes = "%{sql:SELECT IFNULL(SUM(IFNULL(acctinputoctets, 0) + IFNULL(acctoutputoctets, 0)), 0) FROM radacct WHERE username='%{User-Name}'AND acctstarttime\ >= DATE_SUB(LAST_DAY(NOW()), INTERVAL DAY(LAST_DAY(NOW()))-1 DAY)}" Fair-Usage-Rate = "%{sql:SELECT IFNULL(fairusage_rate, 0) FROM radcheck WHERE username='%{User-Name}' AND attribute = 'Cleartext-Password' limit 1}" } } # over qouta fair usage acoount if (&control:Subscriber-Quota > 0 && &control:Fair-Usage-Rate > 0 && &control:Subscriber-Total-Bytes > &control:Subscriber-Quota) { switch "%{&control:Subscriber-NAS-Vendor}" { case "Mikrotik" { update reply { &Mikrotik-Rate-Limit = "%{sql:SELECT GetRate('%{User-Name}', 'fairusage')}" } } case "Cisco" { update reply { &Cisco-Avpair = "%{sql:SELECT GetRate('%{User-Name}', 'fairusage')}" &Cisco-Avpair += "%{sql:SELECT GetRate('%{User-Name}', 'upload')}" } } } } # over quota limited account elsif (&control:Subscriber-Quota > 0 && &control:Fair-Usage-Rate == 0 && &control:Subscriber-Total-Bytes > &control:Subscriber-Quota) { update disconnect { &User-Name := "%{User-Name}" } } # unlimited and other accounts under quota else { switch "%{&control:Subscriber-NAS-Vendor}" { case "Mikrotik" { update reply { # upload and download strings are equal for Mikrotik (Uk/Dk) &Mikrotik-Rate-Limit = "%{sql:SELECT GetRate('%{User-Name}', 'download')}" } } case "Cisco" { update reply { &Cisco-Avpair = "%{sql:SELECT GetRate('%{User-Name}', 'download')}" &Cisco-Avpair += "%{sql:SELECT GetRate('%{User-Name}', 'upload')}" } } } } if i test it with a user for Mikrotik nas for which GetRate sql function returns 2048k/16324k rate string the relevant part in freeradius debug output is: Executing select query: SELECT TOP 1 nas_vendor FROM radcheck WHERE username='aaa@dinler' AND attribute = 'Cleartext-Password' rlm_sql (sql): Released connection (5) (1) EXPAND %{sql: SELECT TOP 1 nas_vendor FROM radcheck WHERE username='%{User-Name}' AND attribute = 'Cleartext-Password'} (1) --> Mikrotik (1) Subscriber-NAS-Vendor = Mikrotik (1) EXPAND %{User-Name} (1) --> aaa@dinler (1) SQL-User-Name set to 'aaa@dinler' rlm_sql (sql): Reserved connection (1) (1) Executing select query: SELECT TOP 1 ISNULL(quota, 0) FROM radcheck WHERE username='aaa@dinler' AND attribute = 'Cleartext-Password' rlm_sql (sql): Released connection (1) (1) EXPAND %{sql:SELECT TOP 1 ISNULL(quota, 0) FROM radcheck WHERE username='%{User-Name}' AND attribute = 'Cleartext-Password'} (1) --> 0 (1) Subscriber-Quota = 0 (1) } # update control = noop (1) if (&control:Subscriber-Quota > 0) { (1) if (&control:Subscriber-Quota > 0) -> FALSE (1) if (&control:Subscriber-Quota > 0 && &control:Fair-Usage-Rate > 0 && &control:Subscriber-Total-Bytes > &control:Subscriber-Quota) { (1) if (&control:Subscriber-Quota > 0 && &control:Fair-Usage-Rate > 0 && &control:Subscriber-Total-Bytes > &control:Subscriber-Quota) -> FALSE (1) elsif (&control:Subscriber-Quota > 0 && &control:Fair-Usage-Rate == 0 && &control:Subscriber-Total-Bytes > &control:Subscriber-Quota) { (1) elsif (&control:Subscriber-Quota > 0 && &control:Fair-Usage-Rate == 0 && &control:Subscriber-Total-Bytes > &control:Subscriber-Quota) -> FALSE (1) else { (1) switch %{&control:Subscriber-NAS-Vendor} { (1) case Mikrotik { (1) update reply { (1) EXPAND %{User-Name} (1) --> aaa@dinler (1) SQL-User-Name set to 'aaa@dinler' rlm_sql (sql): Reserved connection (2) (1) Executing select query: SELECT dbo.GetRate('aaa@dinler', 'download') rlm_sql (sql): Released connection (2) (1) EXPAND %{sql:SELECT dbo.GetRate('%{User-Name}', 'download')} (1) --> 2048k/16324k (1) &Mikrotik-Rate-Limit = 2048k/16324k (1) } # update reply = noop (1) } # case Mikrotik = noop (1) } # switch %{&control:Subscriber-NAS-Vendor} = noop (1) } # else = noop (1) [exec] = noop (1) attr_filter.accounting_response: EXPAND %{User-Name} (1) attr_filter.accounting_response: --> aaa@dinler (1) attr_filter.accounting_response: Matched entry DEFAULT at line 12 (1) [attr_filter.accounting_response] = updated (1) } # accounting = updated (1) Sent Accounting-Response Id 1 from 127.0.0.1:1813 to 127.0.0.1:61732 length 0 (1) Mikrotik-Rate-Limit = "2048k/16324k" (1) Finished request all look fine, but the reply message Mikrotik-Rate-Limit = "2048k/16324k" is not conformed. But if i set Mikrotik-Rate-Limit = "2048k/16324k" in radreply table atleast upload rate is obeyed. Do i update reply in wrong place, or doing some other things wrong? Thanks.
On Jul 10, 2019, at 12:53 AM, Ali Arslan via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote:
To update users rate-limits dynamically i have defined following custom attributes in dictionary file ,,, and written following unlang codes in accounting section: .. if i test it with a user for Mikrotik nas for which GetRate sql function returns 2048k/16324k rate string the relevant part in freeradius debug output is:
That's a pretty good design, and a good summary.
(1) Sent Accounting-Response Id 1 from 127.0.0.1:1813 to 127.0.0.1:61732 length 0 (1) Mikrotik-Rate-Limit = "2048k/16324k" (1) Finished request
all look fine, but the reply message Mikrotik-Rate-Limit = "2048k/16324k" is not conformed.
Yes. The NAS will ignore the contents of the Accounting-Response packet.
But if i set Mikrotik-Rate-Limit = "2048k/16324k" in radreply table atleast upload rate is obeyed.
Do i update reply in wrong place, or doing some other things wrong?
You need to send an empty Accounting-Response packet. And *also* a CoA-Request packet to the NAS. See sites-available/originate-coa for details. The CoA-Request packet will need to contain attributes that identify the user session. Typically this is User-Name, NAS-Identifier, NAS-Port, etc. The exact list is found either in the NAS documentation, or by trial & error via testing. Typically you can just copy the relevant attributes from the Accounting-Request packet into the CoA-Request packet. Alan DeKok.
Hi Alan, thanks for your reply.
You need to send an empty Accounting-Response packet. And *also* a CoA-Request packet to the NAS. See sites-available/originate-coa for details.
The CoA-Request packet will need to contain attributes that identify the user session. Typically this is User-Name, NAS-Identifier, NAS-Port, etc. The exact list is found either in the NAS documentation, or by trial & error via testing.
> Typically you can just copy the relevant attributes from the Accounting-Request packet into the CoA-Request packet. I have changed Reply updates to CoA updates as you suggested, like switch "%{&control:Subscriber-NAS-Vendor}" { case "Mikrotik" { update coa { &User-Name = "%{User-Name}" # upload and download strings are equal for Mikrotik (Uk/Dk) &Mikrotik-Rate-Limit := "%{sql:SELECT GetRate('%{User-Name}', 'download')}" } } case "Cisco" { update coa { &User-Name = "%{User-Name}" &Cisco-Avpair := "%{sql:SELECT GetRate('%{User-Name}', 'download')}" &Cisco-Avpair += "%{sql:SELECT GetRate('%{User-Name}', 'upload')}" } } } debug output finishes as follows: (338) [attr_filter.accounting_response] = updated (338) } # accounting = updated (338) Sent CoA-Request Id 248 from 0.0.0.0:51176 to {nas.IP}:3799 length 65 (338) User-Name = "testUser" (338) NAS-IP-Address = {nas.IP} (338) Mikrotik-Rate-Limit := "802k/12288k" (338) Sent Accounting-Response Id 69 from {RadiusServer.IP}:1813 to {nas.IP}.15:36823 length 0 (338) Finished request so not getting a CoA-ACK result because of some problem(s) in my coa configuration, but the same command work by radclient $"echo \"User-Name={radcheck.username}\nMikrotik-Rate-Limit:={radcheck.upload_rate}k/{radcheck.download_rate}k/\" | radclient {nas.IP}:{nas.RadiusIncomingPort} CoA {nas.Secret}" with result: Sent CoA-Request Id 46 from 0.0.0.0:43039 to {nas.IP}:3799 length 62 Received CoA-ACK Id 46 from {nas.IP}:3799 to 0.0.0.0:0 length 34 In home_server example-coa in originate-coa file it says "Change this IP address to the IP address of the NAS." and i changed IP to the IP address of a NAS (if i can make it work i will add more NASes) and chaged its original name example-coa to NAS name mikrotik1 and renamed example-coa in home_server_pool coa to the new name mikrotik1. There is somoething wrong or missing in my coa configuration. Any help much appreciated. Thanks - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
Hi, In originate-coa documentation it says # This secret SHOULD NOT be the same as the shared # secret in a "client" section. for home_server example-coa secret which confused me, so i had left it as is. Now i set it equal to the NAS secret and it start to work. Thanks.
On Jul 11, 2019, at 12:04 AM, Ali Arslan via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote:
Hi,
In originate-coa documentation it says
# This secret SHOULD NOT be the same as the shared # secret in a "client" section.
for home_server example-coa secret which confused me, so i had left it as is.
Now i set it equal to the NAS secret and it start to work.
The recommendation is that the RADIUS Accounting secret is not the same as the CoA secret. They're on different ports, and can be different things. But it's good to hear that it works. Alan DeKok.
participants (2)
-
Alan DeKok -
Ali Arslan