英文:
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 地址]/[子网掩码]
。我应该尝试通过操作字符串来实现(初步想法)。还有其他方法吗?
以下是关于 Python 的同样问题的链接:
以及使用 Go 的另一种方法:
2022 年 3 月更新
对于 Go 1.18,请查看 下面的答案(由 blackgreen 提供)。
英文:
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:
and another approach with Go:
UPDATE March 2022
👉 for Go 1.18, check the answer below by blackgreen
答案1
得分: 21
Go net包 包含以下函数:
- ParseCIDR:接受表示IP/掩码的字符串,并返回一个IP和一个IPNet
- IPNet.Contains:检查一个IP是否在网络中
这应该满足你的需求。
英文:
The Go net package includes the following functions:
- ParseCIDR: takes a string representing an IP/mask and returns an
IP and an IPNet - IPNet.Contains: checks whether an IP is in a
network
This should cover your needs.
答案2
得分: 11
更新于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("网络地址 A: ", A)
fmt.Println("IP地址 B: ", B)
fmt.Println("ipA : ", ipA)
fmt.Println("ipnetA : ", ipnetA)
fmt.Println("ipB : ", ipB)
fmt.Println("ipnetB : ", ipnetB)
fmt.Printf("\nA (%s) 是否包含 B (%s)?\n", ipnetA, ipB)
if ipnetA.Contains(ipB) {
fmt.Println("是")
} else {
fmt.Println("否")
}
}
英文:
UPDATE March 2022
👉 for Go 1.18, check the answer below by blackgreen
Based on Zoyd's feedback...
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")
}
}
答案3
得分: 10
Go 1.18
您可以使用新的net/netip
包。该包定义了netip.Addr
类型,相比旧类型有显著改进:
与
net.IP
类型相比,该包的Addr
类型占用更少的内存,是不可变的,并且支持比较(支持==和作为map键)。
您可以使用Prefix.Contains
方法来检查一个IP是否在网络中:
Contains
方法报告网络p是否包含IP。IPv4地址不会匹配IPv6前缀。v6-mapped 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
}
如果您要检查的IP还有子网掩码,例如您的示例中的172.17.0.2/16
,您可以再次使用ip, err := netip.ParsePrefix
,然后使用ip.Addr()
获取地址,并将其传递给Contains
方法。
在playground中的代码:https://go.dev/play/p/ikWRpPa1egI
对于那些对实现细节感兴趣的人,您可以查看Brad Fitzpatrick(Go团队的前成员)的博文。net/netip
包基于该工作。
英文:
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.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.
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
<hr>
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.
答案4
得分: 9
根据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("\nA(%s)是否包含B(%s)?\n", ipnetA, ipB)
if ipnetA.Contains(ipB) {
fmt.Println("是的")
} else {
fmt.Println("不是")
}
}
英文:
Based on tgogos's answer:
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")
}
}
答案5
得分: 1
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
英文:
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
答案6
得分: 0
根据上面的答案,人们可以轻松地将代码复制粘贴到他们的项目中。
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)
}
// 检查某个IP是否在CIDR范围内。
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
}
英文:
Based on the answer above so people can easily copy and paste the code into their projects.
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论