Go - 检查 IP 地址是否在网络中
Go - check if IP address is in a network
鉴于:
- 一个网络地址A:(
172.17.0.0/16
)
- 以及来自主机 B 的 IP 地址:(
172.17.0.2/16
)
如何判断B是否在A中?
所有地址都是以下形式的字符串变量:[IP address in dot-decimal notation]/[subnet mask]
。我是否应该尝试通过操纵字符串来做到这一点(初步想法)。有不同的路径吗?
这是 Python 的相同问题:
- How can I check if an ip is in a network in python
以及 Go 的另一种方法:
- Go/GoLang check IP address in range
2022 年 3 月更新
对于 Go 1.18,检查 by blackgreen
Go net package包括以下功能:
- ParseCIDR: 取一个代表 IP/mask 和 returns 的字符串
IP 和 IPNet
- IPNet.Contains:检查IP是否在
网络
这应该能满足您的需求。
2022 年 3 月更新
对于 Go 1.18,检查 by 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")
}
}
基于 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")
}
}
基于上面的答案,人们可以轻松地将代码复制并粘贴到他们的项目中。
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
}
The ipaddress-go Go library 以多态方式同时支持 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
Go 1.18
您可以使用新包 net/netip
。该包定义了类型netip.Addr
,这是对旧类型的重大改进:
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).
您可以使用方法 Prefix.Contains
:
检查 IP 是否在网络内
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.
一个例子:
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
}
如果你要查的IP也有子网掩码,比如你的例子172.17.0.2/16
,你可以再用ip, err := netip.ParsePrefix
,然后用ip.Addr()
获取地址并将其传递给 Contains
.
操场上的代码:https://go.dev/play/p/ikWRpPa1egI
对于实现细节感兴趣的人,可以查看 Brad Fitzpatrick(前 Go 团队成员)的 this blog post。 net/netip
包基于该工作。
鉴于:
- 一个网络地址A:(
172.17.0.0/16
) - 以及来自主机 B 的 IP 地址:(
172.17.0.2/16
)
如何判断B是否在A中?
所有地址都是以下形式的字符串变量:[IP address in dot-decimal notation]/[subnet mask]
。我是否应该尝试通过操纵字符串来做到这一点(初步想法)。有不同的路径吗?
这是 Python 的相同问题:
- How can I check if an ip is in a network in python
以及 Go 的另一种方法:
- Go/GoLang check IP address in range
2022 年 3 月更新
对于 Go 1.18,检查
Go net package包括以下功能:
- ParseCIDR: 取一个代表 IP/mask 和 returns 的字符串 IP 和 IPNet
- IPNet.Contains:检查IP是否在 网络
这应该能满足您的需求。
2022 年 3 月更新
对于 Go 1.18,检查
根据 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")
}
}
基于 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")
}
}
基于上面的答案,人们可以轻松地将代码复制并粘贴到他们的项目中。
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
}
The ipaddress-go Go library 以多态方式同时支持 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
Go 1.18
您可以使用新包 net/netip
。该包定义了类型netip.Addr
,这是对旧类型的重大改进:
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).
您可以使用方法 Prefix.Contains
:
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.
一个例子:
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
}
如果你要查的IP也有子网掩码,比如你的例子172.17.0.2/16
,你可以再用ip, err := netip.ParsePrefix
,然后用ip.Addr()
获取地址并将其传递给 Contains
.
操场上的代码:https://go.dev/play/p/ikWRpPa1egI
对于实现细节感兴趣的人,可以查看 Brad Fitzpatrick(前 Go 团队成员)的 this blog post。 net/netip
包基于该工作。