Matching a prefix in huntgroups file
What is the way to match a range of IPs in the preprocess huntgroups file? This is with freeradius 3.0.12. Unfortunately, the sample huntgroups file doesn't show any example of matching a range. Here's what I've tried: network NAS-IP-Address =~ ^10\.254\. network NAS-IP-Address =~ "^10\.254\." network NAS-IP-Address =~ "10\.254\..*" network NAS-IP-Address =~ /^10\.254\./ Those all don't match: (0) if (&Huntgroup-Name == "network") { (0) ERROR: Failed retrieving values required to evaluate condition network NAS-IP-Address == 10.254.0.0/16 gives a parse error: /etc/raddb/mods-config/preprocess/huntgroups[5]: Parse error (check) for entry network: Invalid IPv4 mask length "/16". Only "/32" permitted for non-prefix types network 10.254.0.0/16 == NAS-IP-Address gives a different parse error: /etc/raddb/mods-config/preprocess/huntgroups[5]: Parse error (check) for entry network: Invalid vendor name in attribute name "10.254.0.0/16" I know *something* is happening with the regexps, because I can get a compilation error if I make it invalid: network NAS-IP-Address =~ ^10\.254\ /etc/raddb/mods-config/preprocess/huntgroups[5]: Parse error (check) for entry network: Error at offset 9 compiling regex for NAS-IP-Address: Pattern compilation failed: \ at end of pattern But it won't match the supplied NAS-IP-Address. I have no problem with a simple == condition matching a single IP address though. Any clues? Thanks, Brian.
On 04/11/2016 16:31, Brian Candler wrote:
But it won't match the supplied NAS-IP-Address. I have no problem with a simple == condition matching a single IP address though.
Supplementary question: I see in http://freeradius.org/press/ for freeradius 3.0.11: * "unlang" comparisons of IP addresses to IP prefixes are now detected, and types automatically cast. But does that mean you can test for an IP address being within a prefix? If so, which operator would you use? I tried: if (&NAS-IP-Address == 10.254.0.0/16) { ... but got no match. A string expansion works though: if ("%{NAS-IP-Address}" =~ /^10\.254\./) { ... Thanks, Brian.
On Nov 4, 2016, at 12:57 PM, Brian Candler <b.candler@pobox.com> wrote:
On 04/11/2016 16:31, Brian Candler wrote:
But it won't match the supplied NAS-IP-Address. I have no problem with a simple == condition matching a single IP address though.
Supplementary question: I see in http://freeradius.org/press/ for freeradius 3.0.11:
* "unlang" comparisons of IP addresses to IP prefixes are now detected, and types automatically cast.
But does that mean you can test for an IP address being within a prefix? If so, which operator would you use? I tried:
if (&NAS-IP-Address == 10.254.0.0/16) { ...
That should work. There are tests for it. Or, just cast NAS-IP-Address to <ipv4prefix>
but got no match. A string expansion works though:
if ("%{NAS-IP-Address}" =~ /^10\.254\./) { ...
Which is also hugely slower, and less flexible. Alan DeKok.
On 04/11/2016 16:59, Alan DeKok wrote:
But does that mean you can test for an IP address being within a prefix? If so, which operator would you use? I tried:
if (&NAS-IP-Address == 10.254.0.0/16) { ...
That should work. There are tests for it. Doesn't seem to. Here's a testing entry in policy.d/foo
foo { if (10.254.1.1 == 10.254.0.0/16) { update { Tmp-String-0 := "AAA" } } update { request:NAS-IP-Address := 10.254.1.1 } if (&NAS-IP-Address == 10.254.0.0/16) { update { Tmp-String-1 := "BBB" } } } and here's the debug output: (0) policy foo { (0) if (10.254.1.1 == 10.254.0.0/16) { (0) if (10.254.1.1 == 10.254.0.0/16) -> FALSE (0) update { (0) request:NAS-IP-Address := 10.254.1.1 (0) } # update = noop (0) if (&NAS-IP-Address == 10.254.0.0/16) { (0) if (&NAS-IP-Address == 10.254.0.0/16) -> FALSE (0) } # policy foo = noop
Or, just cast NAS-IP-Address to <ipv4prefix>
That doesn't seem to work either: (0) policy foo { (0) if (<ipv4prefix>10.254.1.1 == 10.254.0.0/16) { (0) if (<ipv4prefix>10.254.1.1 == 10.254.0.0/16) -> FALSE (0) update { (0) request:NAS-IP-Address := 10.254.1.1 (0) } # update = noop (0) if (<ipv4prefix>&NAS-IP-Address == 10.254.0.0/16) { (0) if (<ipv4prefix>&NAS-IP-Address == 10.254.0.0/16) -> FALSE (0) } # policy foo = noop The above tests done on ubuntu 16.04, with freeradius 3.0.12 from the PPA. Regards, Brian.
Here's something odd then when trying out the "<" operator to check for address within prefix. (0) policy foo { (0) if (10.254.1.1 < 10.254.0.0/16) { (0) if (10.254.1.1 < 10.254.0.0/16) -> FALSE (0) update { (0) request:NAS-IP-Address := 10.254.1.1 (0) } # update = noop (0) if (&NAS-IP-Address < 10.254.0.0/16) { (0) if (&NAS-IP-Address < 10.254.0.0/16) -> TRUE (0) if (&NAS-IP-Address < 10.254.0.0/16) { (0) update { (0) Tmp-String-1 := "BBB" (0) } # update = noop (0) } # if (&NAS-IP-Address < 10.254.0.0/16) = noop (0) } # policy foo = noop It seems the operator behaves differently for a literal versus an attribute? Making the literal explicitly an IPv4 prefix rather than IPv4 address doesn't change this. (0) policy foo { (0) if (10.254.1.1/32 < 10.254.0.0/16) { (0) if (10.254.1.1/32 < 10.254.0.0/16) -> FALSE
On Nov 6, 2016, at 11:53 AM, Brian Candler <b.candler@pobox.com> wrote:
Here's something odd then when trying out the "<" operator to check for address within prefix.
(0) policy foo { (0) if (10.254.1.1 < 10.254.0.0/16) { (0) if (10.254.1.1 < 10.254.0.0/16) -> FALSE
The parser assumes that most things are strings, unless told otherwise.
It seems the operator behaves differently for a literal versus an attribute?
Yes. An attribute has a type. A literal string is just a string. There is no way to determine what "type" a string is. It's just a string.
Making the literal explicitly an IPv4 prefix rather than IPv4 address doesn't change this.
(0) policy foo { (0) if (10.254.1.1/32 < 10.254.0.0/16) { (0) if (10.254.1.1/32 < 10.254.0.0/16) -> FALSE
Try: if (<ipv4prefix>10.254.1.1/32 < 10.254.0.0/16) { Alan DeKok.
On 06/11/2016 17:11, Alan DeKok wrote:
On Nov 6, 2016, at 11:53 AM, Brian Candler <b.candler@pobox.com> wrote:
Here's something odd then when trying out the "<" operator to check for address within prefix.
(0) policy foo { (0) if (10.254.1.1 < 10.254.0.0/16) { (0) if (10.254.1.1 < 10.254.0.0/16) -> FALSE The parser assumes that most things are strings, unless told otherwise. OK. So that's equivalent to "10.254.1.1" < "10.254.0.0/16" then, which indeed is false.
Try:
if (<ipv4prefix>10.254.1.1/32 < 10.254.0.0/16) { That works, thanks.
So let me try to understand. Is the RHS still initially parsed as a string, but because of the typed value on the LHS, the compare operator automatically casts its RHS from string to ipv4prefix? Another question: I believe there is a separate data type for a single ip(v4) address. The following causes a parse error: /etc/freeradius/policy.d/foo[2]: Parse error in condition /etc/freeradius/policy.d/foo[2]: (<ipv4addr>10.254.1.1 < 10.254.0.0/16) { /etc/freeradius/policy.d/foo[2]: ^ Invalid data type in cast But I get a different error if I try <ipaddr>: /etc/freeradius/policy.d/foo[2]: Parse error in condition /etc/freeradius/policy.d/foo[2]: (<ipaddr>10.254.1.1 < 10.254.0.0/16) { /etc/freeradius/policy.d/foo[2]: ^ Failed to parse field In this case then, I am guessing it's trying to convert the RHS to an ipaddr, which is can't because of the slash. Also, the unlang manpage says that you can't explicitly cast the RHS. If I understand this right, it means that in general, if you have a single IP address on the LHS, you should cast it to <ipv4prefix> to ensure the < operator casts its RHS to an ipv4prefix as well. However, it seems it's not necessary in this specific case; if (&NAS-IP-Address < 10.254.0.0/16) { i.e. in this case it's happy to accept that the RHS could be a (string representation of) a prefix, rather than a single IP address. Thanks, Brian.
Hi,
foo { if (10.254.1.1 == 10.254.0.0/16) { update { Tmp-String-0 := "AAA" } } update { request:NAS-IP-Address := 10.254.1.1 } if (&NAS-IP-Address == 10.254.0.0/16) { update { Tmp-String-1 := "BBB" } } }
given that you are mapping particular IP addresses as clients with particular needs, surely this will be easier just to add a local custom tag to the client definition instead and thus you can leave your foo policy alone.... eg add my_group to the client definition and then foo { update { Tmp-String-0 := &client:my_group } } ...as example....then your tmp-string-0 is exactly what that custom tag in the clients.conf is. (this sort of thing often done if you have eg default return vlan or QoS class for particular NAS or groups of NAS) alan
On 06/11/2016 18:33, A.L.M.Buxey@lboro.ac.uk wrote:
Hi,
foo { if (10.254.1.1 == 10.254.0.0/16) { update { Tmp-String-0 := "AAA" } } update { request:NAS-IP-Address := 10.254.1.1 } if (&NAS-IP-Address == 10.254.0.0/16) { update { Tmp-String-1 := "BBB" } } } given that you are mapping particular IP addresses as clients with particular needs, surely this will be easier just to add a local custom tag to the client definition instead and thus you can leave your foo policy alone.... eg add my_group to the client definition and then
foo { update { Tmp-String-0 := &client:my_group } }
...as example....then your tmp-string-0 is exactly what that custom tag in the clients.conf is. The update { Tmp-String-0 ... } is just a method I use to force some output into the radiusd -X, to show a particular branch was taken and/or show the contents of a particular attribute. Maybe there is a cleaner way in freeradius to emit a debug message?
As for setting attributes in clients.conf: thanks for the suggestion, but I don't think this is going to work if the messages go through a proxy, as clients.conf will only match the proxy's IP address. I really do want to match on the NAS-IP-Address attribute. I could do a files or database lookup on NAS-IP-Address, but with a /16 that would be a lot of entries to populate. So right now, with less that a dozen tests to do, a sequential lookup in unlang or huntgroups is fine. Regards, Brian.
On Nov 4, 2016, at 5:56 PM, Brian Candler <b.candler@pobox.com> wrote:
On 04/11/2016 16:59, Alan DeKok wrote:
But does that mean you can test for an IP address being within a prefix? If so, which operator would you use? I tried:
if (&NAS-IP-Address == 10.254.0.0/16) { ...
That should work. There are tests for it. Doesn't seem to. Here's a testing entry in policy.d/foo
OK... going back and reading the code helped. That should really be documented somewhere... NAS-IP-Address is an IP address, not a network. So equality comparisons won't work. You have to do: if (&NAS-IP-Address < 10.254.0.0/16) { Which checks that the IP is "within" the network. ASCII doesn't have a "set contains" character, so "<" is the best we can do.
Or, just cast NAS-IP-Address to <ipv4prefix>
That doesn't seem to work either:
(0) policy foo { (0) if (<ipv4prefix>10.254.1.1 == 10.254.0.0/16) { (0) if (<ipv4prefix>10.254.1.1 == 10.254.0.0/16) -> FALSE
Because the LHS is a /32, and the RHS is a /16. Alan DeKok.
On 07/11/16 16:03, Alan DeKok wrote:
if (&NAS-IP-Address < 10.254.0.0/16) {
Which checks that the IP is "within" the network. ASCII doesn't have a "set contains" character, so "<" is the best we can do.
FWIW, Postgres uses "<<" for "is contained within" or "<<=" for "contained within or equals" and conversely for >> and >>=. Newer versions have && for "contains or contained by".
On Nov 7, 2016, at 11:38 AM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
On 07/11/16 16:03, Alan DeKok wrote:
if (&NAS-IP-Address < 10.254.0.0/16) {
Which checks that the IP is "within" the network. ASCII doesn't have a "set contains" character, so "<" is the best we can do.
FWIW, Postgres uses "<<" for "is contained within" or "<<=" for "contained within or equals" and conversely for >> and >>=. Newer versions have && for "contains or contained by".
"<<" is also used for bit shifting. There is no perfect answer here. :( I'd love to use a sideways "U", which is the mathematical symbol for "set contains". But that's not easy in the ASCII character set. Alan DeKok.
On Nov 7, 2016, at 12:08 PM, Alan DeKok <aland@deployingradius.com> wrote:
On Nov 7, 2016, at 11:38 AM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
On 07/11/16 16:03, Alan DeKok wrote:
if (&NAS-IP-Address < 10.254.0.0/16) {
Which checks that the IP is "within" the network. ASCII doesn't have a "set contains" character, so "<" is the best we can do.
FWIW, Postgres uses "<<" for "is contained within" or "<<=" for "contained within or equals" and conversely for >> and >>=. Newer versions have && for "contains or contained by".
"<<" is also used for bit shifting. There is no perfect answer here. :(
I'd love to use a sideways "U", which is the mathematical symbol for "set contains". But that's not easy in the ASCII character set.
Yeah we tried a bunch of different variations, I don't think postgresql's operators are any less ambiguous than >= > < <=. I'd support allowing the proper UTF8 chars too, and actually displaying those when conditions are printed in debug output. -Arran
On 09-11-16 16:19, Arran Cudbard-Bell wrote:
On Nov 7, 2016, at 12:08 PM, Alan DeKok <aland@deployingradius.com> wrote:
On Nov 7, 2016, at 11:38 AM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
On 07/11/16 16:03, Alan DeKok wrote:
if (&NAS-IP-Address < 10.254.0.0/16) {
Which checks that the IP is "within" the network. ASCII doesn't have a "set contains" character, so "<" is the best we can do.
FWIW, Postgres uses "<<" for "is contained within" or "<<=" for "contained within or equals" and conversely for >> and >>=. Newer versions have && for "contains or contained by".
"<<" is also used for bit shifting. There is no perfect answer here. :(
I'd love to use a sideways "U", which is the mathematical symbol for "set contains". But that's not easy in the ASCII character set.
Yeah we tried a bunch of different variations, I don't think postgresql's operators are any less ambiguous than >= > < <=.
I'd support allowing the proper UTF8 chars too, and actually displaying those when conditions are printed in debug output.
-Arran
I'm not really sure how the config parser works, but are we really limited to some special chars for tokens? You can make it a bit more verbose (and way less ambiguous) with syntax like this: if (&NAS-IP-Address cidr_contained_in 10.254.0.0/16) { ... } if (10.254.0.0/16 cidr_contains &NAS-IP-Address) { ... } -- Herwin Weststrate
On Nov 9, 2016, at 10:24 AM, Herwin Weststrate <herwin@quarantainenet.nl> wrote:
I'm not really sure how the config parser works,
Badly. :( It's a recursive descent parser, with minimal local awareness.
but are we really limited to some special chars for tokens? You can make it a bit more verbose (and way less ambiguous) with syntax like this:
if (&NAS-IP-Address cidr_contained_in 10.254.0.0/16) { ... }
if (10.254.0.0/16 cidr_contains &NAS-IP-Address) { ... }
That would work, *if* you can tell that what data types are being used. For the first example, it works. Unless the attribute is defined at run-time (e.g. LDAP-Group), in which case it gets more complex. For the second example, you have to guess that the LHS is a CIDR? Parsing random strings *correctly* is hard. Alan DeKok.
On 09/11/2016 16:30, Alan DeKok wrote:
For the second example, you have to guess that the LHS is a CIDR? Parsing random strings *correctly* is hard.
No absolutely not. Magic typing is the work of the devil. You force the author to cast an untyped LHS and bomb out if the cast fails - at compile time for constants, runtime for dynamics: if ('10.254.0.0/16'::ipaddress contains &NAS-IP-Address) if (&Tmp-String-0::ipaddress ...) OT: remind me why & is now a thing in front of unlang attribute names, as opposed to defining barewords as attributes?
On Nov 9, 2016, at 2:32 PM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
On 09/11/2016 16:30, Alan DeKok wrote:
For the second example, you have to guess that the LHS is a CIDR? Parsing random strings *correctly* is hard.
No absolutely not. Magic typing is the work of the devil. You force the author to cast an untyped LHS and bomb out if the cast fails - at compile time for constants, runtime for dynamics:
if ('10.254.0.0/16'::ipaddress contains &NAS-IP-Address)
if (&Tmp-String-0::ipaddress ...)
OT: remind me why & is now a thing in front of unlang attribute names, as opposed to defining barewords as attributes?
Because barewords were also used for enumeration values and the ambiguity was annoying. -Arran
On Nov 9, 2016, at 2:32 PM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
No absolutely not. Magic typing is the work of the devil. You force the author to cast an untyped LHS and bomb out if the cast fails - at compile time for constants, runtime for dynamics:
Yes.
if ('10.254.0.0/16'::ipaddress contains &NAS-IP-Address)
if (&Tmp-String-0::ipaddress ...)
Yeah. That's not nice.
OT: remind me why & is now a thing in front of unlang attribute names, as opposed to defining barewords as attributes?
Because attribute names can be mostly anything. And magic typing strings as attribute names is hard. :) Part of the issue is legacy compatibility. The parser always allowed bare strings, and then figured out (mostly) which ones were attributes, and which ones were not. And it got that magic typing wrong. So... &Foo is *always* an attribute reference. /foo/ is *always* a regex. "foo" is *always* an expanded string. 'foo' is *always* a constant string. And bare words are... of the devil. If the LHS is (say) integer, the RHS bare word is a number, and parsed as such. If the LHS is an IP address (cast or attribute), the RHS bare word is an IP address, or maybe a CIDR. If both sides are bare words, who knows what the heck they ware. So they're treated as strings. We *could* allow bare words on the LHS and things on the right: if (10.1.2.3 == &NAS-IP-Address) The interpreter in v4 is a lot more flexible than v3, and can handle this. The parser can mostly handle it, too. We just have to add some tests to be sure it works, and continues to work. But this: if (10.1.2.3 10.1/16) is the work of the devil. No one knows what either side of the expression really is... so all guesses are wrong. Alan DeKok.
On 09/11/2016 19:44, Alan DeKok wrote:
So... &Foo is *always* an attribute reference. /foo/ is *always* a regex. "foo" is *always* an expanded string. 'foo' is *always* a constant string. And bare words are... of the devil. It seems to me that bare numbers, and bare ipv4/ipv6 addresses and prefixes, could be recognised as such by the lexical analyser pretty easily. If you want the string "345" or "1.2.3.4" instead, then you put quotes around it.
I think that covers most of the radius data types. I suppose you could parse MAC addresses too, but that would be rarely used.
If both sides are bare words, who knows what the heck they ware. So they're treated as strings.
Perhaps it would be better to bomb out in that case. It's hard to think of any case where both sides as string literals is actually *useful*, and if for some reason you really wanted that, you could just use quotes. So the only bareword string-like thing that's really needed is a dictionary enumerated value; and as those are restricted to being on the RHS where the LHS is a dictionary attribute, then that's not really a problem. &Service-Type == Login-User # fine Login-User == &Service-Type # no good reason I can see for this Service-Type == 1 # pretty pointless If you wanted, there could be something like Service-Type::Login-User as an explicit way to select an enumeration value. That is: any bare-word which doesn't look like a number or IP address is an enumeration, and the attribute qualifier is optional if the LHS is an attribute. Bikeshed: I did think that "$" or "@" would look more natural as a way to access the value of an attribute :-) Regards, Brian.
On Nov 10, 2016, at 12:31 PM, Brian Candler <b.candler@pobox.com> wrote:
On 09/11/2016 19:44, Alan DeKok wrote:
So... &Foo is *always* an attribute reference. /foo/ is *always* a regex. "foo" is *always* an expanded string. 'foo' is *always* a constant string. And bare words are... of the devil. It seems to me that bare numbers, and bare ipv4/ipv6 addresses and prefixes, could be recognised as such by the lexical analyser pretty easily. If you want the string "345" or "1.2.3.4" instead, then you put quotes around it.
Numerical IPv4 addresses have large overlap with hostnames. As I've said repeatedly, it's just not possible to do this right, all of the time. *NOT* doing it badly is better than doing it badly.
If you wanted, there could be something like Service-Type::Login-User as an explicit way to select an enumeration value. That is: any bare-word which doesn't look like a number or IP address is an enumeration, and the attribute qualifier is optional if the LHS is an attribute.
Please look at the code and see how "simple" this is. It's not.
Bikeshed: I did think that "$" or "@" would look more natural as a way to access the value of an attribute :-)
$ was already used. @ is used by other languages for different things. & is a compromise. Alan DeKok.
On 10/11/2016 21:50, Alan DeKok wrote:
On Nov 10, 2016, at 12:31 PM, Brian Candler <b.candler@pobox.com> wrote:
On 09/11/2016 19:44, Alan DeKok wrote:
So... &Foo is *always* an attribute reference. /foo/ is *always* a regex. "foo" is *always* an expanded string. 'foo' is *always* a constant string. And bare words are... of the devil. It seems to me that bare numbers, and bare ipv4/ipv6 addresses and prefixes, could be recognised as such by the lexical analyser pretty easily. If you want the string "345" or "1.2.3.4" instead, then you put quotes around it. Numerical IPv4 addresses have large overlap with hostnames. Is there a RADIUS data type for "hostname" which is not a string? I could not find it in "man dictionary"
The type field can be one of the standard types: string UTF-8 printable text (the RFCs call this "text") octets opaque binary data (the RFCs call this "string") ipaddr IPv4 address date Seconds since January 1, 1970 (32-bits) integer 32-bit unsigned integer ipv6addr IPv6 Address ipv6prefix IPV6 prefix, with mask ifid Interface Id (hex:hex:hex:hex) integer64 64-bit unsigned integer The type field can be one of the following non-standard types: ether Ethernet MAC address abinary Ascend binary filter format byte 8-bit unsigned integer short 16-bit unsigned integer signed 31-bit signed integer (packed into 32-bit field) tlv Type-Length-Value (allows nested attributes) ipv4prefix IPv4 Prefix as given in RFC 6572. Put another way: how is a hostname distinct from a string? Is there any location in unlang where you would want to use a bare hostname, where you couldn't enclose it in double-quotes to make it a string? Regards, Brian.
On Nov 11, 2016, at 6:05 AM, Brian Candler <b.candler@pobox.com> wrote:
Numerical IPv4 addresses have large overlap with hostnames. Is there a RADIUS data type for "hostname" which is not a string? I could not find it in "man dictionary"
Are you really going to claim that you *don't* want the server to accept host names on input, and turn them into IP addresses?
The type field can be one of the standard types:
Quoting the text I wrote back at me isn't helpful. I know it already.
Put another way: how is a hostname distinct from a string? Is there any location in unlang where you would want to use a bare hostname, where you couldn't enclose it in double-quotes to make it a string?
Sure, if you want to treat host names as *strings*, and not have them converted to addresses. i.e. hostnames *are* addresses after they're parsed. Please go write a parser which accepts anything as input, and determines which data type it is. Once you've done that, you can claim it's easy, and tell me how to do it. Or, read the code, to see how FreeRADIUS makes it's decisions. And then describe how to make the code better, with patches, and showing how it doesn't classify the input wrong. The option you should *not* take is to make suggestions without understanding the problem space. I've said repeatedly it's not a trivial problem. You keep coming up with simple solutions, and asking why they won't work. I've been trying to explain why it won't work. It's not trivial. It's time for you to understand why it won't work... by going and trying to do it yourself. Alan DeKok.
On 11/11/2016 11:50, Alan DeKok wrote:
On Nov 11, 2016, at 6:05 AM, Brian Candler <b.candler@pobox.com> wrote:
Numerical IPv4 addresses have large overlap with hostnames. Is there a RADIUS data type for "hostname" which is not a string? I could not find it in "man dictionary" Are you really going to claim that you *don't* want the server to accept host names on input, and turn them into IP addresses? On "input" in what context? Are you thinking of something like this?
Framed-IP-Address := foo.example.com
Put another way: how is a hostname distinct from a string? Is there any location in unlang where you would want to use a bare hostname, where you couldn't enclose it in double-quotes to make it a string? Sure, if you want to treat host names as *strings*, and not have them converted to addresses.
i.e. hostnames *are* addresses after they're parsed.
To be pedantic, hostnames become addresses after they're resolved. It doesn't necessarily follow that they're resolved at the time they're parsed. The server *can* choose to resolve them at parse time, with some consequences (e.g. having to restart server if data in DNS changes). But it could delay resolution until the time of use.
On Nov 11, 2016, at 8:26 AM, Brian Candler <b.candler@pobox.com> wrote:
On "input" in what context? Are you thinking of something like this?
Framed-IP-Address := foo.example.com
That's exactly what I'm saying. Also, your examples of comparing IP addresses / net masks. Host names can go there, too.
Put another way: how is a hostname distinct from a string? Is there any location in unlang where you would want to use a bare hostname, where you couldn't enclose it in double-quotes to make it a string? Sure, if you want to treat host names as *strings*, and not have them converted to addresses.
i.e. hostnames *are* addresses after they're parsed.
To be pedantic, hostnames become addresses after they're resolved. It doesn't necessarily follow that they're resolved at the time they're parsed.
That is a distinctly unhelpful response. You ignored the point of my argument, and instead talked about something different. How do you know that a particular string is a host name, *before* it's parsed? Me: It's hard. You: it's easy! Me: OK, how? You: it's EASY!!!!!! <sigh> Just stop. Please. If the LHS is an attribute of type "ipaddr", yes, you can parse the RHS as an IP address or host name. If the LHS is cast to an IP address, it's possible, too. But what about this: if (host.name.example.com == host.b.example.org) Do you do a string comparison? Do you resolve them as IP addresses, and compare the addresses? What about: if (localhost == foo.example.com) The LHS could be an IP address, or it could be just a string. Until the admin *tells* the parser what it is, the parser CANNOT GUESS. Because the guesses are likely to be wrong. And no, I don't want answers to those questions. I want you to *think* about the problem before coming up with trivial, but unhelpful suggestions.
The server *can* choose to resolve them at parse time, with some consequences (e.g. having to restart server if data in DNS changes). But it could delay resolution until the time of use.
You don't understand *why* it's hard, and instead are arguing about irrelevant details. Go learn more to understand *why* it's hard. I'm done arguing with someone who thinks it's trivial, but won't do the research to see why it isn't trivial. Alan DeKok.
On 11/11/2016 13:42, Alan DeKok wrote:
How do you know that a particular string is a host name,*before* it's parsed?
You don't. That is: I don't think the *parser* needs to decide whether a string is a hostname or not! A concrete example: Framed-IP-Address := foo.example.com # let's say this is DISALLOWED. Framed-IP-Address := "foo.example.com" # allowed. RHS has type 'string'. The question is then not one of parsing, but of assignment semantics. If the LHS has type "ipaddr", and the RHS has type "string", then the string is converted into an ipaddr via hostname resolution. This is unconditional: you don't have to inspect the string to decide whether it looks like a hostname or not. I personally don't mind the implicit cast from string to ipaddr (*), but you could instead require it to be explicit: Framed-IP-Address := <ipaddr>"foo.example.com" If the RHS is a constant string literal then this could still be resolved at parse/compile time. But the potential is also there to do late resolution: e.g. Framed-IP-Address := <ipaddr>"%{User-Name}.example.com" Regards, Brian. (*) It's not really any different to the current FR behaviour, which allows these implicitly: Framed-IP-Address := foo.example.com # treated as hostname, resolved to IP Reply-Message := foo.example.com # treated as string Framed-IP-Address += 1.2.3.4 # IP Reply-Message += 1.2.3.4 # string
On Nov 11, 2016, at 9:37 AM, Brian Candler <b.candler@pobox.com> wrote:
The question is then not one of parsing, but of assignment semantics.
No.
If the LHS has type "ipaddr", and the RHS has type "string", then the string is converted into an ipaddr via hostname resolution.
No.
This is unconditional: you don't have to inspect the string to decide whether it looks like a hostname or not.
No.
I personally don't mind the implicit cast from string to ipaddr (*), but you could instead require it to be explicit:
Framed-IP-Address := <ipaddr>"foo.example.com"
No.
If the RHS is a constant string literal then this could still be resolved at parse/compile time. But the potential is also there to do late resolution: e.g.
Framed-IP-Address := <ipaddr>"%{User-Name}.example.com"
No. Alan DeKok.
On Nov 4, 2016, at 12:31 PM, Brian Candler <b.candler@pobox.com> wrote:
What is the way to match a range of IPs in the preprocess huntgroups file?
Compare address start and finish. NAS-IP-Address > foo, NAS-IP-Address < bar
This is with freeradius 3.0.12. Unfortunately, the sample huntgroups file doesn't show any example of matching a range.
Here's what I've tried:
network NAS-IP-Address =~ ^10\.254\.
Regular expressions aren't supported in the hunt groups or "users" file. Alan DeKok.
As Alan says, cast to ipv4prefix. In the worst case use your regex with unlang but whatever you do, don't use huntgroup , it's extremely slow by many factors! alan
On 04/11/2016 18:28, Alan Buxey wrote:
whatever you do, don't use huntgroup , it's extremely slow by many factors!
I currently only have 4 or 5 huntgroups, and I can't see how it would be much slower doing a linear search through huntgroups than doing the same 4 or 5 tests sequentially in unlang. In an ideal world I'd do a direct mapping from NAS-IP-Address to nas type, but given the large blocks (e.g. /16) I don't really want to populate a table with 65,536 entries.
I've offered you advice. Ignore both myself and Alan DeKok if you think huntgroups can't be slower than unlang. Huntgroups should have been removed a long time back. :/ alan
On 05/11/2016 20:23, Alan Buxey wrote:
I've offered you advice. Ignore both myself and Alan DeKok if you think huntgroups can't be slower than unlang.
Would you care to explain then? Because when I look in the code, it looks like huntgroups just iterates over paircmp and hunt_paircmp, stopping at the first match. But in any case, I don't really care about a sub-microsecond optimisation, when the majority of the latency and processing is in the LDAP lookup and subsequent processing. If huntgroups makes the logic clearer and easier to maintain, that is the more important benefit to me. Regards, Brian.
participants (7)
-
A.L.M.Buxey@lboro.ac.uk -
Alan Buxey -
Alan DeKok -
Arran Cudbard-Bell -
Brian Candler -
Herwin Weststrate -
Phil Mayers