[Answers Posted] Relevance Challenge - IP Address is in which Subnet - February 2020

https://developer.bigfix.com/relevance/search/?query=Cidr

We have several options there.

registration cidr address of client is probably the most useful I think.

Perhaps this is obvious and I’m just missing it? I want to valuate whether a client’s IP address (or addresses) is within a set of known CIDR ranges. There are inspectors for the client’s address, but the CIDR range matching math is missing. I’m not quite sure how to go about it. Enumerate the range as a list of strings and then match the address against that?

1 Like

Ah, I think I see. I could take this problem in two different ways. Depending on how you look at it, the ‘cidr’ properties will either give your own IP address in CIDR format, or your subnet in CIDR format. ‘cidr strings’ returns it in subnet format:

q: addresses of adapters of network
A: 192.168.1.151
T: 12.696 ms

q: cidr addresses whose (it != "127.0.0.0/8") of adapters of network
A: 192.168.1.151/24
T: 8.530 ms

q: cidr strings whose (it != "127.0.0.0/8") of adapters of network
A: 192.168.1.0/24
T: 4.444 ms

If you have a defined list of every CIDR subnet, that’s great, you should be able to compare it directly to ‘cidr strings’. So if I had a list of subnets that included 192.168.1.0/24 that’s a pretty easy comparison.

But if we haven’t split out every subnet, but we want to compare to a superblock like 192.168.0.0/16, I think we go back into the use-case for this challenge and “how do I apply the relevance above”.

We can make a couple of small modifications to a large piece of relevance to get “only the subnets that match one of my IP addresses” like so

(
	    item 0 of it  /* Subnet CIDR Address */
	           /* IP address bitset string elements matching this subnet */
	           /* IP Address AND Subnet Mask = Subnet Address bitset */

           /* Previously I was counting "number of" these, now we only want the ones that match */
	  ,  (
	         item 1 of it  /* subnet address bitset string */
	       , item 2 of it  /* subnet mask bitset string */
	       , elements of item 3 of it  /* ip address bitset strings */
	       ) whose (bit set (item 2 of it) * item 1 of it = item 0 of it)
) of

	(
	  /* Derive bitsets for subnets */
	  item 0 of it  /* subnet CIDR address */
	  ,  bit set (concatenation of ((last 8 of padded string of (it as integer as bit set)) as string) of substrings separated by "." of preceding text of first "/" of item 0 of it) 
	  ,  bit set ((concatenation of  "1" of integers in (1,(it)) & concatenation of "0" of integers in (31, it)) of (following text of first "/" of item 0 of it as integer))
	  , item 1 of it /* preserve IP address set of bitset strings */
	) of
	
	(
	   /* unwind subnet CIDR strings */
	   elements of item 0 of it
	   , item 1 of it
	) of
	
	(
	  item 0 of it   /* preserve subnet CIDR strings */
	         /* Convert set of IP addresses into a set of IP Address Bitsets */
	  ,  set of (it as string) of 
	       (concatenation of ((last 8 of padded string of (it as integer as bit set)) as string) of substrings separated by "." of it)  of elements of item 1 of it
	)
	of 
	
	(
	  set of (   /* Subnet CIDR Addresses */
	          "192.168.1.0/24"
	        ; "192.168.2.0/25"
	        ; "192.168.0.0/16"
	        ; "192.168.2.128/25"
	        ; "192.168.3.0/25"
	        ; "192.168.3.128/26"
	        ; "192.168.3.192/26"
	        ; "0.1.0.0/27"
	      )
	     /* Previously I was giving a static list of IP addresses, now let's retrieve addresses from the client */
	 , set of (  /* IP Addresses */
	       addresses of adapters of network as string
	      )
)

For me this gives result

192.168.0.0/16, ( 11000000101010000000000000000000, 11111111111111110000000000000000, 11000000101010000000000110010111 )
192.168.1.0/24, ( 11000000101010000000000100000000, 11111111111111111111111100000000, 11000000101010000000000110010111 )

(My IP address matches against both 192.168.0.0/16, and against 192.168.1.0/24, but not the other subnets).

We can turn that into a true/false by just putting ‘exists’ in front of it…

exists
(
	    item 0 of it  /* Subnet CIDR Address */
	           /* IP address bitset string elements matching this subnet */
	           /* IP Address AND Subnet Mask = Subnet Address bitset */
	  ,  (
	         item 1 of it  /* subnet address bitset string */
	       , item 2 of it  /* subnet mask bitset string */
	       , elements of item 3 of it  /* ip address bitset strings */
	       ) whose (bit set (item 2 of it) * item 1 of it = item 0 of it)
) of

	(
	  /* Derive bitsets for subnets */
	  item 0 of it  /* subnet CIDR address */
	  ,  bit set (concatenation of ((last 8 of padded string of (it as integer as bit set)) as string) of substrings separated by "." of preceding text of first "/" of item 0 of it) 
	  ,  bit set ((concatenation of  "1" of integers in (1,(it)) & concatenation of "0" of integers in (31, it)) of (following text of first "/" of item 0 of it as integer))
	  , item 1 of it /* preserve IP address set of bitset strings */
	) of
	
	(
	   /* unwind subnet CIDR strings */
	   elements of item 0 of it
	   , item 1 of it
	) of
	
	(
	  item 0 of it   /* preserve subnet CIDR strings */
	         /* Convert set of IP addresses into a set of IP Address Bitsets */
	  ,  set of (it as string) of 
	       (concatenation of ((last 8 of padded string of (it as integer as bit set)) as string) of substrings separated by "." of it)  of elements of item 1 of it
	)
	of 
	
	(
	  set of (   /* Subnet CIDR Addresses */
	          "192.168.1.0/24"
	        ; "192.168.2.0/25"
	        ; "192.168.0.0/16"
	        ; "192.168.2.128/25"
	        ; "192.168.3.0/25"
	        ; "192.168.3.128/26"
	        ; "192.168.3.192/26"
	        ; "0.1.0.0/27"
	      )
	
	 , set of (  /* IP Addresses */
	       addresses of adapters of network as string
	      )
)

:True

It gets the job done, but it’s definitely difficult to read and a good argument for adding operators like cidr subnet contains ip address and ip address is contained by cidr subnet

4 Likes

Oh yeah - I just recalled why I didn’t need this as a use-case to begin with. Since this is evaluating at the client, I would probably use the “Location Property Wizard” to tag the clients based on their subnet, and then use those tags to change whatever else I needed to change (relay affiliations or such). The Location Property Wizard handles most or all of this for you.

Thanks!

And, maybe I’ll finally look at the Location Property Wizard. :smiley: