给定:
- 一个网络地址A:(
172.17.0.0/16
) - 来自主机B的IP地址:(
172.17.0.2/16
)
如何判断B是否在A中?
所有地址都是以下形式的字符串变量:[点十进制表示法中的IP地址]/[子网掩码]
。我应该通过操作字符串来尝试吗(初步想法)?还有其他不同的方法吗?
下面是Python的相同问题:
以及Go的另一种方法:
2022年3月更新
对于Go 1.18,请查看下面的答案,由blackgreen提供。
给定:
172.17.0.0/16
)172.17.0.2/16
)如何判断B是否在A中?
所有地址都是以下形式的字符串变量:[点十进制表示法中的IP地址]/[子网掩码]
。我应该通过操作字符串来尝试吗(初步想法)?还有其他不同的方法吗?
下面是Python的相同问题:
以及Go的另一种方法:
2022年3月更新
对于Go 1.18,请查看下面的答案,由blackgreen提供。
Go net包 包含以下函数:
这些函数应该能够满足您的需求。
2022年3月更新:
如需适用于Go 1.18的内容,请查看下面的答案,作者是blackgreen
根据Zoyd的反馈...
https://play.golang.org/p/wdv2sPetmt
package main
import (
"fmt"
"net"
)
func main() {
A := "172.17.0.0/16"
B := "172.17.0.2/16"
ipA,ipnetA,_ := net.ParseCIDR(A)
ipB,ipnetB,_ := net.ParseCIDR(B)
fmt.Println("Network address A: ", A)
fmt.Println("IP address B: ", B)
fmt.Println("ipA : ", ipA)
fmt.Println("ipnetA : ", ipnetA)
fmt.Println("ipB : ", ipB)
fmt.Println("ipnetB : ", ipnetB)
fmt.Printf("\nDoes A (%s) contain: B (%s)?\n", ipnetA, ipB)
if ipnetA.Contains(ipB) {
fmt.Println("yes")
} else {
fmt.Println("no")
}
}
你可以使用新的 net/netip
包。该包定义了类型 netip.Addr
,相对于旧版本有明显的改进:
与 net.IP 类型相比,该包的 Addr 类型占用更少的内存,是不可变的,并且支持比较运算符(==),可以作为 map 的键。
你可以使用方法 Prefix.Contains
检查 IP 是否位于网络中:
Contains 方法会判断网络 p 是否包含 IP。
IPv4 地址不会匹配 IPv6 前缀。v6 映射的 IPv6 地址不会匹配 IPv4 前缀。零值 IP 不会匹配任何前缀。如果 IP 具有 IPv6 区域标识,则 Contains 返回 false,因为前缀将删除区域标识。
下面是一个例子:
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
}
172.17.0.2/16
,您可以再次使用 ip, err := netip.ParsePrefix
,然后使用 ip.Addr()
获取地址并将其传递给Contains
。net / netip
包是基于该工作完成的。根据tgogos的回答:
package main
import (
"fmt"
"net"
)
func main() {
A := "172.17.0.0/16"
B := "172.17.0.2"
_, ipnetA, _ := net.ParseCIDR(A)
ipB := net.ParseIP(B)
fmt.Printf("\nDoes A (%s) contain: B (%s)?\n", ipnetA, ipB)
if ipnetA.Contains(ipB) {
fmt.Println("yes")
} else {
fmt.Println("no")
}
}
ipaddress-go Go库 支持IPv4和IPv6的多态方式,并支持子网,包括检查地址或子网是否包含在包含子网中的方法。它还允许使用不仅仅是CIDR子网。免责声明:我是该库的项目经理。
示例代码:
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))
}
输出:
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
基于上面的答案,这样人们就可以轻松地将代码复制并粘贴到他们的项目中。
package main
import (
"fmt"
"log"
"net"
)
func main() {
// True
firstCheck, err := cidrRangeContains("10.0.0.0/24", "10.0.0.1")
if err != nil {
log.Println(err)
}
fmt.Println(firstCheck)
// False
secondCheck, err := cidrRangeContains("10.0.0.0/24", "127.0.0.1")
if err != nil {
log.Println(err)
}
fmt.Println(secondCheck)
}
// Check if a certain ip in a cidr range.
func cidrRangeContains(cidrRange string, checkIP string) (bool, error) {
_, ipnet, err := net.ParseCIDR(cidrRange)
if err != nil {
return false, err
}
secondIP := net.ParseIP(checkIP)
return ipnet.Contains(secondIP), err
}