Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect if two Golang net.IPNet objects intersect?

How to detect if there is intersection between two Golang net.IPNet objects?

That is, how to check both if the first network is subnet of the second one OR if the second network is subnet of the first one.

Does Go provide any utility function ready for this specific task?

See test code below.

package main

import (
    "fmt"
    "net"
)

func main() {
    _, net1, _ := net.ParseCIDR("1.1.1.1/24")
    _, net2, _ := net.ParseCIDR("1.1.0.2/16")
    _, net3, _ := net.ParseCIDR("1.1.1.3/25")
    _, net4, _ := net.ParseCIDR("1.2.0.4/16")

    test(net1, net2, true)
    test(net2, net1, true)
    test(net1, net3, true)
    test(net3, net1, true)
    test(net1, net4, false)
    test(net4, net1, false)
}

func test(n1, n2 *net.IPNet, expect bool) {
    result := intersect(n1, n2)
    var label string
    if result == expect {
        label = "good"
    } else {
        label = "FAIL"
    }
    fmt.Printf("test intersect(%v,%v)=%v expected=%v => %s\n", n1, n2, result, expect, label)
}

func intersect(n1, n2 *net.IPNet) bool {
    return false // FIXME WRITEME
}

Run it on Go Playground

like image 410
Everton Avatar asked Jan 11 '16 19:01

Everton


2 Answers

If (as your test cases seem to imply) you don't care about which side contains which, but just that there's overlap, this should be sufficient.

func intersect(n1, n2 *net.IPNet) bool {
    return n2.Contains(n1.IP) || n1.Contains(n2.IP)
}
like image 172
dahc Avatar answered Oct 23 '22 11:10

dahc


You can use the fact that IP addresses (net.IP) and netmasks (net.IPMask) are simply byte slices ([]byte) that contain the binary IP addresses. You can use the usual bitwise-operators on the network addresses and their masks to determine if one network is a subnet of another:

func intersect(n1, n2 *net.IPNet) bool {
    for i := range n1.IP {
        if n1.IP[i] & n1.Mask[i] != n2.IP[i] & n2.Mask[i] & n1.Mask[i] {
            return false
        }
    }
    return true
}

This function is missing some basic sanity checks (for example, it would break when passed one IPv4 and one IPv6 address), but the example should be sufficient to get the gist of it.

It succeeds in all test cases from your question, except the first one. But after all, 1.1.0.2/16 is not really a subnet of 1.1.1.1/24 (it's the other way around).

https://play.golang.org/p/Kur5n2hfLg

like image 22
helmbert Avatar answered Oct 23 '22 10:10

helmbert