Golang : Proper way to test CIDR membership of an IP 4 or 6 address example
Problem:
You have generated a range of IP addresses from a given Classless Inter-Domain Routing address(CIDR) address and you want to check if an IP version 4 or 6 address is within the range(membership). How to do that?
Solution:
The common solution is the use net.Contains()
function to test if the IP address is part of the range of IP addresses. Trouble is... most people will happily convert the IP address from string
to []byte
type to feed the net.Contains()
function.
Guess what. net.Contains()
function will happily accept the input and report false.
Doing this will introduce hard to trace bug once the source code is compiled and shipped to production. The proper way is to convert the string input with the net.ParseIP()
function before feeding the net.Contains()
function.
IP 4 and IP 6 code examples :
package main
import (
"fmt"
"net"
"os"
)
func main() {
// generate a range of IP version 4 addresses from a Classless Inter-Domain Routing address
ipAddress, ipNet, err := net.ParseCIDR("123.45.67.64/27")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// generate a range of IPv4 addresses from the CIDR address
var ipAddresses []string
for ipAddress := ipAddress.Mask(ipNet.Mask); ipNet.Contains(ipAddress); inc(ipAddress) {
//fmt.Println(ipAddress)
ipAddresses = append(ipAddresses, ipAddress.String())
}
// list out the ipAddresses within range
for key, ipAddress := range ipAddresses {
fmt.Printf("[%v] %s\n", key, ipAddress)
}
//test for IP version 4 address for membership
// WRONG WAY!!
fmt.Println("Contains 123.45.67.69 : ", ipNet.Contains([]byte("123.45.67.69")))
// CORRECT / PROPER WAY!
fmt.Println("Contains 123.45.67.69 : ", ipNet.Contains(net.ParseIP("123.45.67.69")))
}
func inc(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
Output :
[0] 123.45.67.64
...
[31] 123.45.67.95
Contains 123.45.67.69 : false
Contains 123.45.67.69 : true
same as above, just further test on IP version 6 addresses for extra confirmation purpose.
package main
import (
"fmt"
"net"
"os"
)
func main() {
// generate a range of IP version 6 addresses from a Classless Inter-Domain Routing address
ip6Address, ipNet, err := net.ParseCIDR("12:3456:78:90ab:cd:ef01:23:30/125")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// generate a range of IPv6 addresses from the CIDR address
var ip6Addresses []string
for ip6Address := ip6Address.Mask(ipNet.Mask); ipNet.Contains(ip6Address); inc(ip6Address) {
ip6Addresses = append(ip6Addresses, ip6Address.String())
}
// list out the range of ip6Addresses
for key, ip6Address := range ip6Addresses {
fmt.Printf("[%v] %s\n", key, ip6Address)
}
//test for IP version 6 address for membership
// WRONG WAY!!
fmt.Println("Contains 12:3456:78:90ab:cd:ef01:23:33 : ", ipNet.Contains([]byte("12:3456:78:90ab:cd:ef01:23:33")))
// CORRECT / PROPER WAY!
fmt.Println("Contains 12:3456:78:90ab:cd:ef01:23:33 : ", ipNet.Contains(net.ParseIP("12:3456:78:90ab:cd:ef01:23:33")))
}
func inc(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
Happy coding!
References:
https://golang.org/pkg/net/#ParseIP
See also : Golang : Check if IP address is version 4 or 6
By Adam Ng
IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.
Advertisement
Tutorials
+17.1k Golang : Get future or past hours, minutes or seconds
+11.8k Golang : convert(cast) string to integer value
+21.5k Golang : Use TLS version 1.2 and enforce server security configuration over client
+14.3k Golang : Convert(cast) int to float example
+12.3k Golang : Transform comma separated string to slice example
+31.1k Golang : Example for ECDSA(Elliptic Curve Digital Signature Algorithm) package functions
+8.2k Golang : How to check variable or object type during runtime?
+6.7k Golang : Calculate BMI and risk category
+14.9k Golang : How to get Unix file descriptor for console and file
+14.3k Golang : Get URI segments by number and assign as variable example
+7.5k Golang : Lock executable to a specific machine with unique hash of the machine
+5.6k Facebook : How to force facebook to scrape latest URL link data?