Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go - check if IP address is in a network

Given:

  • a network address A: (172.17.0.0/16)
  • and an IP address from a host B: (172.17.0.2/16)

how can we say if B is in A?

All addresses are string variables in the following form: [IP address in dot-decimal notation]/[subnet mask]. Should I try to do it by manipulating strings (initial thoughts). Is there a different path?

Here is the same question for Python:

  • How can I check if an ip is in a network in python

and another approach with Go:

  • Go/GoLang check IP address in range

UPDATE March 2022
👉 for Go 1.18, check the answer below by blackgreen

like image 671
tgogos Avatar asked Apr 07 '17 09:04

tgogos


People also ask

How do you check if an IP address belongs to a network?

To see all of the devices connected to your network, type arp -a in a Command Prompt window. This will show you the allocated IP addresses and the MAC addresses of all connected devices.

How do I know if my IP is accessible?

Ping is a network utility that is used to test if a host is reachable over a network or over the Internet by using the Internet Control Message Protocol “ICMP”. When you initiate an ICMP request will be sent from a source to a destination host.

How do you check if a public IP is active?

Ping the IP address. Review the output of the ping request. If there is a ping reply, confirm the output is replying from the IP address you are pinging. If there is no reply, enter the command “arp -a” on Windows or “show arp” on many network devices and check to see if you see the IP address and mac address.

How do I find duplicate IP addresses on my network?

Here is how you can check it: On an unaffected host on the same network, open up a command prompt. On a Windows machine, type "arp -a [suspected duplicate IP]" and hit enter. On a Mac or Linux machine, type "arp [suspected duplicate IP]" and hit enter.


2 Answers

Go 1.18

You can use the new package net/netip. The package defines the type netip.Addr which is a significant improvement over the old one:

Compared to the net.IP type, this package's Addr type takes less memory, is immutable, and is comparable (supports == and being a map key).

You can check if an IP is within a network with the method Prefix.Compare:

Contains reports whether the network p includes ip.

An IPv4 address will not match an IPv6 prefix. A v6-mapped IPv6 address will not match an IPv4 prefix. A zero-value IP will not match any prefix. If ip has an IPv6 zone, Contains returns false, because Prefixes strip zones.

An example:

package main

import (
    "fmt"
    "net/netip"
)

func main() {
    network, err := netip.ParsePrefix("172.17.0.0/16")
    if err != nil {
        panic(err)
    }

    ip, err := netip.ParseAddr("172.17.0.2")
    if err != nil {
        panic(err)
    }

    b := network.Contains(ip)
    fmt.Println(b) // true
}

If the IP you want to check also has the subnet mask, like 172.17.0.2/16 as in your example, you can use ip, err := netip.ParsePrefix again, and then obtain the address with ip.Addr() and pass that to Contains.

Code in the playground: https://go.dev/play/p/ikWRpPa1egI


For those who are interested in the implementation details, you can see this blog post by Brad Fitzpatrick (former member of the Go team). The net/netip package is based on that work.

like image 65
blackgreen Avatar answered Oct 01 '22 23:10

blackgreen


The ipaddress-go Go library supports both IPv4 and IPv6 in a polymorphic manner and supports subnets, including methods that check for containment of an address or subnet in a containing subnet. It also allows for more than just CIDR subnets. Disclaimer: I am the project manager of that library.

Example code:

contains("172.17.0.0/16", "172.17.0.2/16")
contains("10.10.20.0/30", "10.10.20.3")
contains("10.10.20.0/30", "10.10.20.5")
contains("10.10.20.0/30", "10.10.20.0/31")
contains("1::/64", "1::1")
contains("1::/64", "2::1")
contains("1::/64", "1::/32")
contains("1::/64", "1::/112")
contains("1::3-4:5-6", "1::4:5")
contains("1-2::/64", "2::")
contains("bla", "foo")

func contains(network, address string) {
    one, two := ipaddr.NewIPAddressString(network),
        ipaddr.NewIPAddressString(address)
    fmt.Printf("%v contains %v %v\n", one, two, one.Contains(two))
}

Output:

172.17.0.0/16 contains 172.17.0.2/16 true
10.10.20.0/30 contains 10.10.20.3 true
10.10.20.0/30 contains 10.10.20.5 false
10.10.20.0/30 contains 10.10.20.0/31 true
1::/64 contains 1::1 true
1::/64 contains 2::1 false
1::/64 contains 1::/32 false
1::/64 contains 1::/112 true
1::3-4:5-6 contains 1::4:5 true
1-2::/64 contains 2:: true
bla contains foo false
like image 34
Sean F Avatar answered Oct 01 '22 23:10

Sean F