acct_unique with more than one Class attribute
Hi, I'm trying to use acct_unique from the default accounting policy with FR 3.0.13: acct_unique { update request { &Tmp-String-9 := "${policy.class_value_prefix}" } if (("%{hex:&Class}" =~ /^%{hex:&Tmp-String-9}/) && \ ("%{string:&Class}" =~ /^${policy.class_value_prefix}([0-9a-f]{32})/i)) { update request { &Acct-Unique-Session-Id := "%{md5:%{1},%{Acct-Session-ID}}" } } else { update request { &Acct-Unique-Session-Id := "%{md5:%{User-Name},%{Acct-Session-ID},%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}},%{NAS-Identifier},%{NAS-Port-ID}, %{NAS-Port}}" } } } Currently I already use the Class attribute to deliver some QoS, and so this policy doesn't work. Any hint to modify it to manage multi value Class atttibute? Thanks, Andrea -- ---------------------------------------------------------------- Hit any user to continue. ---------------------------------------------------------------- Ing. Andrea Gabellini Email: andrea.gabellini@telecomitalia.sm Skype: andreagabellini Tel: (+378) 0549 886111 Fax: (+378) 0549 886188 Telecom Italia San Marino S.p.A. Via XXVIII Luglio, 212 - Piano -2 47893 Borgo Maggiore Republic of San Marino http://www.telecomitalia.sm
Hi, as a workaround I tried to use &Class[n] instead of &Class. The Class attribute is added in the reply as the last thing in post-auth. So if the NAS doesn't touch the list, probably this works. Is there a better solution? Thanks, Andrea Il 23/03/2017 18:33, Andrea Gabellini ha scritto:
Hi,
I'm trying to use acct_unique from the default accounting policy with FR 3.0.13:
acct_unique { update request { &Tmp-String-9 := "${policy.class_value_prefix}" }
if (("%{hex:&Class}" =~ /^%{hex:&Tmp-String-9}/) && \ ("%{string:&Class}" =~ /^${policy.class_value_prefix}([0-9a-f]{32})/i)) { update request { &Acct-Unique-Session-Id := "%{md5:%{1},%{Acct-Session-ID}}" } }
else { update request { &Acct-Unique-Session-Id := "%{md5:%{User-Name},%{Acct-Session-ID},%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}},%{NAS-Identifier},%{NAS-Port-ID}, %{NAS-Port}}" } } }
Currently I already use the Class attribute to deliver some QoS, and so this policy doesn't work. Any hint to modify it to manage multi value Class atttibute?
Thanks, Andrea
-- ---------------------------------------------------------------- Doing nothing gets pretty tiresome because you can't stop and rest. ---------------------------------------------------------------- Ing. Andrea Gabellini Email: andrea.gabellini@telecomitalia.sm Skype: andreagabellini Tel: (+378) 0549 886111 Fax: (+378) 0549 886188 Telecom Italia San Marino S.p.A. Via XXVIII Luglio, 212 - Piano -2 47893 Borgo Maggiore Republic of San Marino http://www.telecomitalia.sm
On 24/03/2017 09:48, Andrea Gabellini wrote:
as a workaround I tried to use &Class[n] instead of &Class. The Class attribute is added in the reply as the last thing in post-auth. So if the NAS doesn't touch the list, probably this works.
Is there a better solution?
http://networkradius.com/doc/3.0.10/unlang/foreach.html It says "The foreach statement loops over a list of attributes", but I think it means "The foreach statement loops over all the instances of a specified attribute". Example: https://lists.freeradius.org/pipermail/freeradius-users/2014-February/070473... Or, if you can rewrite the whole test as a single regexp, then you try: if (&Class[*] =~ /regexp(captures)/) { ... }
Il 24/03/2017 10:59, Brian Candler ha scritto:
On 24/03/2017 09:48, Andrea Gabellini wrote:
as a workaround I tried to use &Class[n] instead of &Class. The Class attribute is added in the reply as the last thing in post-auth. So if the NAS doesn't touch the list, probably this works.
Is there a better solution?
http://networkradius.com/doc/3.0.10/unlang/foreach.html
It says "The foreach statement loops over a list of attributes", but I think it means "The foreach statement loops over all the instances of a specified attribute". Example:
https://lists.freeradius.org/pipermail/freeradius-users/2014-February/070473...
Or, if you can rewrite the whole test as a single regexp, then you try:
if (&Class[*] =~ /regexp(captures)/) { ... }
Hi, I tried both &Class[*] and the foreach statement. The next problem is the string conversion. What happens: - &Class[*]: It returns all instances of the attribute separated with a comma. Only the first one is converted to a string. - foreach statement: "%{string:%{Foreach-Variable-0}}" results in an empty string This is my test configuration snippet: acct_unique { ... update request { &Tmp-String-8 := "%{&Class[0]}" &Tmp-String-7 := "%{&Class[1]}" &Tmp-String-6 := "%{&Class[*]}" &Tmp-String-8 := "%{string:&Class[0]}" &Tmp-String-7 := "%{string:&Class[1]}" &Tmp-String-6 := "%{string:&Class[*]}" } foreach &Class { update request { &Tmp-String-6 := "%{Foreach-Variable-0}" &Tmp-String-5 := "%{string:%{Foreach-Variable-0}}" } } ... } and this the debug output: (3) Mon Mar 27 11:33:31 2017: Debug: policy acct_unique { (3) Mon Mar 27 11:33:31 2017: Debug: update request { (3) Mon Mar 27 11:33:31 2017: Debug: } # update request = noop (3) Mon Mar 27 11:33:31 2017: Debug: update request { (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND %{&Class[0]} (3) Mon Mar 27 11:33:31 2017: Debug: --> 0x54657374436c617373 (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND %{&Class[1]} (3) Mon Mar 27 11:33:31 2017: Debug: --> 0x617574685f69643a6532613166366265393632356165613337316436363865326236303433363363 (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND %{&Class[*]} (3) Mon Mar 27 11:33:31 2017: Debug: --> 0x54657374436c617373,0x617574685f69643a6532613166366265393632356165613337316436363865326236303433363363 (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND %{string:&Class[0]} (3) Mon Mar 27 11:33:31 2017: Debug: --> TestClass (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND %{string:&Class[1]} (3) Mon Mar 27 11:33:31 2017: Debug: --> auth_id:e2a1f6be9625aea371d668e2b604363c (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND %{string:&Class[*]} (3) Mon Mar 27 11:33:31 2017: Debug: --> TestClass (3) Mon Mar 27 11:33:31 2017: Debug: } # update request = noop (3) Mon Mar 27 11:33:31 2017: Debug: foreach &Class (3) Mon Mar 27 11:33:31 2017: Debug: update request { (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND Foreach-Variable-0 (3) Mon Mar 27 11:33:31 2017: Debug: --> 0x54657374436c617373 (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND %{Foreach-Variable-0} (3) Mon Mar 27 11:33:31 2017: Debug: --> 0x54657374436c617373 (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND Foreach-Variable-0 (3) Mon Mar 27 11:33:31 2017: Debug: --> 0x54657374436c617373 (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND %{string:%{Foreach-Variable-0}} (3) Mon Mar 27 11:33:31 2017: Debug: --> (3) Mon Mar 27 11:33:31 2017: Debug: } # update request = noop (3) Mon Mar 27 11:33:31 2017: Debug: update request { (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND Foreach-Variable-0 (3) Mon Mar 27 11:33:31 2017: Debug: --> 0x617574685f69643a6532613166366265393632356165613337316436363865326236303433363363 (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND %{Foreach-Variable-0} (3) Mon Mar 27 11:33:31 2017: Debug: --> 0x617574685f69643a6532613166366265393632356165613337316436363865326236303433363363 (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND Foreach-Variable-0 (3) Mon Mar 27 11:33:31 2017: Debug: --> 0x617574685f69643a6532613166366265393632356165613337316436363865326236303433363363 (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND %{string:%{Foreach-Variable-0}} (3) Mon Mar 27 11:33:31 2017: Debug: --> (3) Mon Mar 27 11:33:31 2017: Debug: } # update request = noop (3) Mon Mar 27 11:33:31 2017: Debug: } # foreach &Class = noop
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
-- ---------------------------------------------------------------- The name is Baud......, James Baud. ---------------------------------------------------------------- Ing. Andrea Gabellini Email: andrea.gabellini@telecomitalia.sm Skype: andreagabellini Tel: (+378) 0549 886111 Fax: (+378) 0549 886188 Telecom Italia San Marino S.p.A. Via XXVIII Luglio, 212 - Piano -2 47893 Borgo Maggiore Republic of San Marino http://www.telecomitalia.sm
On 27/03/2017 10:37, Andrea Gabellini wrote:
I tried both &Class[*] and the foreach statement. The next problem is the string conversion. What happens:
- &Class[*]: It returns all instances of the attribute separated with a comma. Only the first one is converted to a string.
Only if you write %{Class[*]} or %{&Class[*]}, i.e. you ask Freeradius to convert it into a string. Don't do that. Try this: if (&Class[*] =~ /pattern(.*)pattern/) { ... use %{1} to get the capture group } I think this should work if you are on FreeRADIUS 3.x. That is, only the first match should be used. (But I've not tested it myself)
- foreach statement: "%{string:%{Foreach-Variable-0}}" results in an empty string ... (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND Foreach-Variable-0 (3) Mon Mar 27 11:33:31 2017: Debug: --> 0x54657374436c617373 That doesn't look empty to me. 54=T, 65=e, 63=s 74=t etc.
The underlying issue is that 'Class' is not a string attribute, so it's hard to treat it as such. I have in the past modified the dictionary so that Class *is* a string. But in general, it could contain binary data, and FreeRADIUS isn't great at handling that if the dictionary says the attribute is a String. Regards, Brian.
On 27/03/2017 11:10, Brian Candler wrote:
The underlying issue is that 'Class' is not a string attribute, so it's hard to treat it as such.
Ah now I see, that's probably why &Class =~ /.../ may not work. You could try (<string>&Class[*] =~ /.../). Or you could try copying &Class to &Tmp-String-0 first. I believe there is a syntax for copying all the values of one attribute to another attribute, but I can't remember what that is right now. Also there is the filtering version of update you can try: update request { &Class =~ /.../ } which only keeps instances matching the regexp. Again, not sure how the binary Class attribute will interact with that. Sorry, I'm not being very specific here, you'll have to test the various options. Regards, Brian.
Il 27/03/2017 12:43, Brian Candler ha scritto:
On 27/03/2017 11:10, Brian Candler wrote:
The underlying issue is that 'Class' is not a string attribute, so it's hard to treat it as such.
Ah now I see, that's probably why &Class =~ /.../ may not work.
You could try (<string>&Class[*] =~ /.../).
This doesn't work: Mon Mar 27 12:52:18 2017 : Error: /usr/local/freeradius/etc/raddb/policy.d/accounting[55]: Parse error in condition Mon Mar 27 12:52:18 2017 : Error: /usr/local/freeradius/etc/raddb/policy.d/accounting[55]: (<string>&Class[*] =~ /(.*)/) { Mon Mar 27 12:52:18 2017 : Error: /usr/local/freeradius/etc/raddb/policy.d/accounting[55]: ^ Cannot use cast with regex comparison
Or you could try copying &Class to &Tmp-String-0 first. I believe there is a syntax for copying all the values of one attribute to another attribute, but I can't remember what that is right now.
Any clue on this :-) Defining the Class attribute as string works. Thanks. I would like to trying again without this workaround....
Also there is the filtering version of update you can try:
update request {
&Class =~ /.../
}
which only keeps instances matching the regexp. Again, not sure how the binary Class attribute will interact with that.
Sorry, I'm not being very specific here, you'll have to test the various options.
Regards,
Brian.
-- ---------------------------------------------------------------- Never trust anything that bleeds for five days and doesn't die. ---------------------------------------------------------------- Ing. Andrea Gabellini Email: andrea.gabellini@telecomitalia.sm Skype: andreagabellini Tel: (+378) 0549 886111 Fax: (+378) 0549 886188 Telecom Italia San Marino S.p.A. Via XXVIII Luglio, 212 - Piano -2 47893 Borgo Maggiore Republic of San Marino http://www.telecomitalia.sm
Il 27/03/2017 12:10, Brian Candler ha scritto:
On 27/03/2017 10:37, Andrea Gabellini wrote:
I tried both &Class[*] and the foreach statement. The next problem is the string conversion. What happens:
- &Class[*]: It returns all instances of the attribute separated with a comma. Only the first one is converted to a string.
Only if you write %{Class[*]} or %{&Class[*]}, i.e. you ask Freeradius to convert it into a string.
Don't do that. Try this:
if (&Class[*] =~ /pattern(.*)pattern/) { ... use %{1} to get the capture group }
if (&Class[*] =~ /(.*)/) { update request { &Tmp-String-5 := "Match: %{1}" } } results in: Mon Mar 27 12:40:37 2017 : Debug: (2) EXPAND %{&Class[*]} Mon Mar 27 12:40:37 2017 : Debug: (2) --> 0x54657374436c617373,0x617574685f69643a3066313863343665653637633462323563616131633361303830656233356538 Mon Mar 27 12:40:37 2017 : Debug: (2) &Tmp-String-6 := 0x54657374436c617373,0x617574685f69643a3066313863343665653637633462323563616131633361303830656233356538 ... Mon Mar 27 12:40:37 2017 : Debug: (2) if (&Class[*] =~ /(.*)/) { Mon Mar 27 12:40:37 2017 : Debug: (2) if (&Class[*] =~ /(.*)/) -> TRUE Mon Mar 27 12:40:37 2017 : Debug: (2) if (&Class[*] =~ /(.*)/) { Mon Mar 27 12:40:37 2017 : Debug: (2) update request { Mon Mar 27 12:40:37 2017 : Debug: (2) EXPAND Match: %{1} Mon Mar 27 12:40:37 2017 : Debug: (2) --> Match: 0x54657374436c617373 Mon Mar 27 12:40:37 2017 : Debug: (2) &Tmp-String-5 := Match: 0x54657374436c617373 Mon Mar 27 12:40:37 2017 : Debug: (2) } # update request = noop Mon Mar 27 12:40:37 2017 : Debug: (2) } # if (&Class[*] =~ /(.*)/) = noop Same problem. %{&Class[*]} when used contains only the first instance.
I think this should work if you are on FreeRADIUS 3.x. That is, only the first match should be used. (But I've not tested it myself)
- foreach statement: "%{string:%{Foreach-Variable-0}}" results in an empty string ... (3) Mon Mar 27 11:33:31 2017: Debug: EXPAND Foreach-Variable-0 (3) Mon Mar 27 11:33:31 2017: Debug: --> 0x54657374436c617373 That doesn't look empty to me. 54=T, 65=e, 63=s 74=t etc.
Please look few lines later. The problem is the string conversion of %{Foreach-Variable-0}
The underlying issue is that 'Class' is not a string attribute, so it's hard to treat it as such. I have in the past modified the dictionary so that Class *is* a string. But in general, it could contain binary data, and FreeRADIUS isn't great at handling that if the dictionary says the attribute is a String.
Regards,
Brian.
-- ---------------------------------------------------------------- I'm not a complete idiot, some parts are missing. ---------------------------------------------------------------- Ing. Andrea Gabellini Email: andrea.gabellini@telecomitalia.sm Skype: andreagabellini Tel: (+378) 0549 886111 Fax: (+378) 0549 886188 Telecom Italia San Marino S.p.A. Via XXVIII Luglio, 212 - Piano -2 47893 Borgo Maggiore Republic of San Marino http://www.telecomitalia.sm
On 27/03/2017 11:45, Andrea Gabellini wrote:
Mon Mar 27 12:40:37 2017 : Debug: (2) if (&Class[*] =~ /(.*)/) { Mon Mar 27 12:40:37 2017 : Debug: (2) update request { Mon Mar 27 12:40:37 2017 : Debug: (2) EXPAND Match: %{1} Mon Mar 27 12:40:37 2017 : Debug: (2) --> Match: 0x54657374436c617373 Mon Mar 27 12:40:37 2017 : Debug: (2) &Tmp-String-5 := Match: 0x54657374436c617373
Ah, so that seems to have worked; the problem is doing a regexp match on an "octets" attribute, which is converting it to hex first, and that's not what you want. You could as a temporary workaround try putting an override in your local dictionary (raddb/dictionary): ATTRIBUTE Class 25 string That should work because I ended up doing exactly that a long time ago with FreeRADIUS 2.1. Otherwise in 3.0 it might be possible to try casting, e.g. <string>&Class, but I'm not sure if that will also give you the hex encoding.
participants (2)
-
Andrea Gabellini -
Brian Candler