There have been some long-needed changes to the "unlang" interpreter / compiler. For people who've looked at the code, it hadn't really changed since 2000 or so. Largely because it's core to the server, and confusing as heck. Now that we have a large number of test cases, I've been going through and fixing the code. It passes all of the tests, and more have been added. The new compiler is in modcall.c. The interpreter has been moved to interpreter.c. The split means it's easier to understand each piece in isolation. One benefit is that the mess of "if / then / else" statements has been changed to be table driven. Each keyword "foo" now as a dedicated compilation function compile_foo(), and a dedicate interpreter function modcall_foo(). This makes adding new keywords almost trivial. So the question is... what else would you like to see in "unlang"? I don't want to make it a general-purpose language, but some additional features may be useful. e.g. it would be possible for modules to dynamically register new unlang keywords / syntax: if (foo) { module-thing argument { ... ??? ... } } Ideas? Comments? Alan DeKok.
On Dec 11, 2015, at 8:57 AM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
On 11/12/15 13:55, Alan DeKok wrote:
Ideas? Comments?
The module/argument thing is a nice idea, particularly if it is possible to soft-define them in policy.d
Examples? Use-cases? Passing arguments to *existing* module functions is not possible. But it's possible to define new keywords which map to new module functions. Alan DeKok.
On 11 Dec 2015, at 09:08, Alan DeKok <aland@deployingradius.com> wrote:
On Dec 11, 2015, at 8:57 AM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
On 11/12/15 13:55, Alan DeKok wrote:
Ideas? Comments?
The module/argument thing is a nice idea, particularly if it is possible to soft-define them in policy.d
Examples? Use-cases?
Passing arguments to *existing* module functions is not possible. But it's possible to define new keywords which map to new module functions.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
policy ipaddr resolve_fqdn (string hostname) { return <ipaddr>"%{a:&hostname}" } update request { &Tmp-ipaddr-0 := resolve_fqdn("google.com") } TMPL_TYPE_FUNCTION :) Same TMPL type could be used for module functions and policy defined functions. -Arran Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS development team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
On Dec 11, 2015, at 9:17 AM, Arran Cudbard-Bell <a.cudbardb@freeradius.org> wrote:
policy ipaddr resolve_fqdn (string hostname) { return <ipaddr>"%{a:&hostname}" }
Can I gouge out my eyes now? I'm wary of adding things like that to the server. It might be useful, but it has a high potential for abuse and/or confusion.
update request { &Tmp-ipaddr-0 := resolve_fqdn("google.com")
As opposed to: &Tmp-ipaddr-0 := "google.com" Which works today? :( Alan DeKok.
On 11 Dec 2015, at 09:21, Alan DeKok <aland@deployingradius.com> wrote:
On Dec 11, 2015, at 9:17 AM, Arran Cudbard-Bell <a.cudbardb@freeradius.org> wrote:
policy ipaddr resolve_fqdn (string hostname) { return <ipaddr>"%{a:&hostname}" }
Can I gouge out my eyes now?
Go ahead :)
I'm wary of adding things like that to the server. It might be useful, but it has a high potential for abuse and/or confusion.
People abuse policies now, using Tmp attributes as arguments and to hold return values has a far greater potential for confusion. By refusing to add proper functions, we're increasing real world abuse and confusion. Are you going to argue perl subroutines are more readable than C functions? I doubt anyone except Larry Wall's most devout followers would agree with you.
update request { &Tmp-ipaddr-0 := resolve_fqdn("google.com")
As opposed to:
&Tmp-ipaddr-0 := "google.com"
Which works today?
It has the potential to be dynamic, which doesn't work today, or at least I hope not. The unbound module would be a great test for converting to async as it has very little state, and the API in its normal form is asynchronous. -Arran Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS development team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
On 11/12/15 14:33, Arran Cudbard-Bell wrote:
People abuse policies now, using Tmp attributes as arguments and to hold return values has a far greater potential for confusion.
Yep. I use Tmp-* attributes a lot in policies. I don't consider it abuse really; it's what we've got.
By refusing to add proper functions, we're increasing real world abuse and confusion.
I understand the reasoning behind unlang being limited. Implementing yet-another fullblown language is not a great way to spend resources. I would probably make more use of the embedded languages for complex policies, but none of the options suit me; perl is, well, perl. Python although I love it, is a very poor choice for use in threaded environments. Unlang is "good enough" but is sometimes messy. A few tweaks to avoid some of the more onerous set/unset of Tmp/control: variables would probably obviate any desire to move outside the server core for me.
On Dec 11, 2015, at 9:47 AM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
On 11/12/15 14:33, Arran Cudbard-Bell wrote:
People abuse policies now, using Tmp attributes as arguments and to hold return values has a far greater potential for confusion.
Yep. I use Tmp-* attributes a lot in policies. I don't consider it abuse really; it's what we've got.
Yeah... simpler would be better. But I'm wary of extending things *too* much.
By refusing to add proper functions, we're increasing real world abuse and confusion.
I understand the reasoning behind unlang being limited. Implementing yet-another fullblown language is not a great way to spend resources.
I would probably make more use of the embedded languages for complex policies, but none of the options suit me; perl is, well, perl. Python although I love it, is a very poor choice for use in threaded environments.
Unlang is "good enough" but is sometimes messy. A few tweaks to avoid some of the more onerous set/unset of Tmp/control: variables would probably obviate any desire to move outside the server core for me
I agree. I'll see if I can come up with something sane. And easy to implement. Alan DeKok.
On 11/12/15 14:08, Alan DeKok wrote:
On Dec 11, 2015, at 8:57 AM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
On 11/12/15 13:55, Alan DeKok wrote:
Ideas? Comments?
The module/argument thing is a nice idea, particularly if it is possible to soft-define them in policy.d
Examples? Use-cases?
It's a bit vague, but a lot of the datastore modules - SQL, redis, etc. - have way more functionality than a simple lookup/map construct can easily express. Being able to "call" methods with parameters may provide a cleaner, more expressive syntax, which lowers cognitive load and contributes to ease of maintenance. As an example, the built-in cache module involves a (IMO) fairly ugly set of constructs relying on control attributes to distinguish between check, lookup, set and delete. if (cache.exists %{Key}) { othercache.delete %{Other-Key} } ...as opposed to: update { control:Cache-Status-Only = yes } cache if (ok) { update { control:Cache-Status-Only = no control:Cache-TTL = 0 } othercache } update { control:Cache-Status-Only !* ANY control:Cache-TTL !* ANY }
On Fri, Dec 11, 2015 at 02:41:49PM +0000, Phil Mayers wrote:
As an example, the built-in cache module involves a (IMO) fairly ugly set of constructs relying on control attributes to distinguish between check, lookup, set and delete.
if (cache.exists %{Key}) { othercache.delete %{Other-Key} }
...as opposed to:
Exactly. Parameters are used at the moment for modules and policies, just in a really ugly way by having to set or read temporary attributes. It's much the same way as you use parameters for C functions, but behind the scenes those values get put into CPU registers. The parameters are much easier to comprehend (assuming the syntax is sane). Cheers, Matthew -- Matthew Newton, Ph.D. <mcn4@le.ac.uk> Systems Specialist, Infrastructure Services, I.T. Services, University of Leicester, Leicester LE1 7RH, United Kingdom For IT help contact helpdesk extn. 2253, <ithelp@le.ac.uk>
On Dec 11, 2015, at 9:54 AM, Matthew Newton <mcn4@leicester.ac.uk> wrote:
Parameters are used at the moment for modules and policies, just in a really ugly way by having to set or read temporary attributes.
Yes. That's been a long-time issue.
It's much the same way as you use parameters for C functions, but behind the scenes those values get put into CPU registers. The parameters are much easier to comprehend (assuming the syntax is sane).
Do you have suggestions for syntax? Alan DeKok.
On Fri, Dec 11, 2015 at 10:31:57AM -0500, Alan DeKok wrote:
On Dec 11, 2015, at 9:54 AM, Matthew Newton <mcn4@leicester.ac.uk> wrote:
It's much the same way as you use parameters for C functions, but behind the scenes those values get put into CPU registers. The parameters are much easier to comprehend (assuming the syntax is sane).
Do you have suggestions for syntax?
Haven't really thought about it much before. Maybe for starters passing things in just simply something like this, to save the extraneous update{} beforehand? policy: to_lower(Tmp-String-0) { update reply { Tmp-String-1 := "%{tolower:%{Tmp-String-0}}" } } i.e. list of control attributes that are set when the policy/module is called. server: # request:Calling-Station-Id contains AABBCCDDEEFF to_lower(&Calling-Station-Id) # control:Tmp-String-0 now contains AABBCCDDEEFF # reply:Tmp-String-1 now contains aabbccddeeff A development could then be to have a param list as well as request/control/reply, so "parameters" don't mess up any of the existing attribute lists. But that could get messy when one policy calls another policy unless it was somehow nested, which I think would be more undesireable. An alternative would be to have everything within a policy work on a separate param list created just for that policy, which is discarded at the end of the policy, essentially local variables. The above policy could then become the following (very forced example): policy: to_lower(Tmp-String-0) { update param { Tmp-String-1 := "%{tolower:%{param:Tmp-String-0}}" } update reply { Tmp-String-1 := ¶m:Tmp-String-1 } } i.e. list of control attributes that are set when the policy/module is called. server: # request:Calling-Station-Id contains AABBCCDDEEFF to_lower(&Calling-Station-Id) # reply:Tmp-String-1 now contains aabbccddeeff So control:Tmp-String-0 isn't messed up in the calling context. I imagine the first of these isn't too hard to do and would save quite a lot of messy updates-before-policies - but adding a separate parameter list for each policy call might be more tricky. And maybe it should be called "local" rather than "param" as well. Matthew -- Matthew Newton, Ph.D. <mcn4@le.ac.uk> Systems Specialist, Infrastructure Services, I.T. Services, University of Leicester, Leicester LE1 7RH, United Kingdom For IT help contact helpdesk extn. 2253, <ithelp@le.ac.uk>
On 11/12/2015 3:55 μμ, Alan DeKok wrote:
So the question is... what else would you like to see in "unlang"?
Ideas? Comments?
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
I would like to see a new operator === which will return true if there is a single match in a list context. That way one can run a check such as: if (NAS-IP-Address === &control:NAS-IP-Address) { update reply { Reply-Message = "NAS IP Address not allowed" } reject } instead of: update control { Tmp-String-5 := 'REJECT' } foreach &control:NAS-IP-Address { if (NAS-IP-Address == "%{Foreach-Variable-0}"){ update control { Tmp-String-5 := 'ALLOW' } } } if (control:Tmp-String-5 == 'REJECT'){ update reply { Reply-Mssage = "NAS IP Address not allowed" } reject }
On 12 Dec 2015, at 06:55, Kostas Kalevras <kkalev@noc.ntua.gr> wrote:
On 11/12/2015 3:55 μμ, Alan DeKok wrote:
So the question is... what else would you like to see in "unlang"?
Ideas? Comments?
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
I would like to see a new operator === which will return true if there is a single match in a list context. That way one can run a check such as:
if (NAS-IP-Address === &control:NAS-IP-Address) { update reply { Reply-Message = "NAS IP Address not allowed" } reject }
if (NAS-IP-Address == &control:NAS-IP-Address[*]) { } already exists in the v3.1.x branch. Works with the regex operator too, and both sides can be multivalued. -Arran Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS development team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
participants (5)
-
Alan DeKok -
Arran Cudbard-Bell -
Kostas Kalevras -
Matthew Newton -
Phil Mayers