Search code examples
javaip-addresscidr

Sean Foley IPAddress library and containment inside CIDR


Similar to this question although not quite the same, I'm having trouble understanding why the Sean Foley IPAddress library doesn't think that an IP address is contained inside a CIDR.

From what I've read, I thought that the CIDR/mask of "20.108.106.0/22" encompasses addresses in the range from 20.108.104.0 to 20.108.107.255. This range calculator I used here suggests it does.

Given that, I believe that the address 20.108.106.72 should be contained inside the CIDR range 20.108.106.0/22. This CIDR range checker seems to agree that it should as well.

Trying out using the IPAddress library with some sample code doesn't seem to match this though. This code is Kotlin but should work the same as the Java:

@Test
fun testCidr() {
    val cidr = IPAddressString("20.108.106.0/22").getAddress()
    val ip = IPAddressString("20.108.106.72").getAddress()
    println("$ip is inside $cidr = ${cidr.contains(ip)}")
}
Output:
20.108.106.72 is inside 20.108.106.0/22 = false

I've read the attached question, but I don't think my CIDR range is a non-zero host (eg. 20.108.106.72) because the last section is zero. and the other range checking tools I've used seem to suggest it should work. I'm sure this isn't a bug, but must be some misunderstanding on my part. I'm trying to write code that will cope with any input of IP addresses in several forms eg. IPv6, single IP addresses, CIDR ranges which is why I was wanting to use a library like this one without needing to parse or understand the address first. I see that it works when I specify my range like "20.108.106.0/23" but again I don't understand why that would be. Thanks


Solution

  • I believe the answer is actually the same as in the linked question. To quote the relevant part:

    In summary, 10.90.6.14/30 is the same as 10.90.6.14 because the host is not zero. 10.90.6.12/30 is the subnet of 4 addresses because the host is zero. If you want to convert to the subnet, then use toPrefixBlock.

    Which basically says a host is zero if the address is the first address in the subnet given by your CIDR mask.

    Which means for your example: 20.108.104.0/22 would be the needed CIDR range.

    Reading the linked question again, it seems like you can use the toPrefixBlock() method in your example code to get the wanted result without actually changing the supplied CIDR range.

    @Test
    fun testCidr() {
        val cidr = IPAddressString("20.108.106.0/22").getAddress().toPrefixBlock()
        val ip = IPAddressString("20.108.106.72").getAddress()
        println("$ip is inside $cidr = ${cidr.contains(ip)}")
    }
    

    Incidentally your 20.108.106.0/23 range works since 20.108.106.0 is the first address in that subnet.