Hi Alan, Many thanks, the following now works as expected: (1) Calling-Station-Id = "oxidized.syrex.co.za" (1) update request { (1) Tmp-IP-Address-0 := &Calling-Station-Id -> 41.0.0.5 (1) } # update request = noop (1) if ((&Client-Shortname == "isp_core") && !(&User-Name == "revisioncfg" && &Tmp-IP-Address-0 && <ipv4prefix>&Tmp-IP-Address-0 < 41.0.0.0/29)) { (1) EXPAND &Client-Shortname (1) --> isp_core (1) if ((&Client-Shortname == "isp_core") && !(&User-Name == "revisioncfg" && &Tmp-IP-Address-0 && <ipv4prefix>&Tmp-IP-Address-0 < 41.0.0.0/29)) -> FALSE (32) Calling-Station-Id = "197.91.242.47" (32) update request { (32) Tmp-IP-Address-0 := &Calling-Station-Id -> 197.91.242.47 (32) } # update request = noop (32) if ((&Client-Shortname == "isp_core") && !(&User-Name == " revisioncfg" && &Tmp-IP-Address-0 && <ipv4prefix>&Tmp-IP-Address-0 < 41.0.0.0/29)) { (32) EXPAND &Client-Shortname (32) --> isp_core (32) if ((&Client-Shortname == "isp_core") && !(&User-Name == " revisioncfg" && &Tmp-IP-Address-0 && <ipv4prefix>&Tmp-IP-Address-0 < 41.0.0.0/29)) -> TRUE What it however does allow is for someone to set a DNS PTR record for their source IP as a hostname that would resolve to an IP in the 41.0.0.0/29 subnet. I presume I should limit validation to numeric values only by first validating Calling-Station-Id =~ /^\d{1,3}(\.\d{1,3}){3}$/ ? Regards David Herselman -----Original Message----- From: Freeradius-Users <freeradius-users-bounces+dhe=syrex.co@lists.freeradius.org> On Behalf Of Alan DeKok Sent: Saturday, 12 June 2021 3:06 PM To: FreeRadius users mailing list <freeradius-users@lists.freeradius.org> Subject: Re: Help testing if a variable contains an IPv4 On Jun 12, 2021, at 8:55 AM, David Herselman via Freeradius-Users <freeradius-users@lists.freeradius.org> wrote:
I'm trying to allow non MFA logins from configuration revisioning systems where the target device doesn't support SSH key based authentication. I started constructing an unlang check using '<ipv4prefix>' and hit some quirks.
Most of our devices include the calling station's source IP in their request, whilst a few send the reverse DNS lookup strings. How do I test if a variable matches the structure of an IPv4 IP?
It depends. In RADIUS, attributes have a data type. Some are type "string", and others are type "ipaddr". The first one can contain an ASCII string which represents the *printed* form on an IP address. But it's not an IP address. In contrast, the "ipaddr" data type is a 32-bit IPv4 address.
My problem appears to be that '<ipv4prefix>&String < 41.0.0.0/29' returns true, for example:
Because an ASCII string isn't a 32-bit IPv4 address.
(0) Calling-Station-Id = "oxidized.syrex.co.za" (0) if (&Client-Shortname == "core_routers") && !(&User-Name == "revisioncfg" && &Calling-Station-Id && <ipv4prefix>&Calling-Station-Id < 41.0.0.0/29) {
That won't work. What you're asking is for it to do a DNS lookup (generally a bad idea, too), and then compare the resulting IP address to the prefix. What's actually happening is that it's casting the first 32-bits of the string to an IP address, and then checking that. The solution is to copy the Calling-Station-ID to an attribute of type "ipaddr" first. e.g. Tmp-IP-Address-0. Then, compare that address to the prefix: update request { Tmp-IP-Address-0 := &Calling-Station-Id } if (<ipv4prefix>&Tmp-IP-Address-0 < 41.0.0.0/29) { ... } Alan DeKok. - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html