我有一个Go程序,它接收来自客户端的URL并使用net/http包获取它们。在进行进一步处理之前,我想检查URL是否映射到私有(不可路由/RFC1918网络)地址空间。
最直接的方法是执行显式DNS请求并检查已知的私有范围的地址。之后,为URL执行HTTP GET请求。
有更好的方法来完成这个任务吗?最好与http.Client集成,以便作为GET请求的一部分执行。
我有一个Go程序,它接收来自客户端的URL并使用net/http包获取它们。在进行进一步处理之前,我想检查URL是否映射到私有(不可路由/RFC1918网络)地址空间。
最直接的方法是执行显式DNS请求并检查已知的私有范围的地址。之后,为URL执行HTTP GET请求。
有更好的方法来完成这个任务吗?最好与http.Client集成,以便作为GET请求的一部分执行。
你可能还想包含对环回地址(IPv4或IPv6)和/或IPv6链路本地地址或唯一本地地址的检查。这是一个例子,其中包含RFC1918地址列表以及针对它们的简单检查,使用isPrivateIP(ip net.IP)
函数:
var privateIPBlocks []*net.IPNet
func init() {
for _, cidr := range []string{
"127.0.0.0/8", // IPv4 loopback
"10.0.0.0/8", // RFC1918
"172.16.0.0/12", // RFC1918
"192.168.0.0/16", // RFC1918
"169.254.0.0/16", // RFC3927 link-local
"::1/128", // IPv6 loopback
"fe80::/10", // IPv6 link-local
"fc00::/7", // IPv6 unique local addr
} {
_, block, err := net.ParseCIDR(cidr)
if err != nil {
panic(fmt.Errorf("parse error on %q: %v", cidr, err))
}
privateIPBlocks = append(privateIPBlocks, block)
}
}
func isPrivateIP(ip net.IP) bool {
if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
return true
}
for _, block := range privateIPBlocks {
if block.Contains(ip) {
return true
}
}
return false
}
fc00::/7
- dtoux"169.254.0.0/16" // RFC3927 - https://en.wikipedia.org/wiki/Link-local_address
或者额外加上:ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast()
- Dougnukem这解决了golang问题29146,由Aaran McGuire提出:
net
: 添加IP.IsPrivate()
添加
IsPrivate()
辅助函数以根据RFC 1918和RFC 4193检查IP是否为私有
net包似乎有很多帮助程序来报告IP是什么。例如:
IsLoopback()
IsMulticast()
IsInterfaceLocalMulticast()
package main
import (
"fmt"
"net"
)
func main() {
fmt.Println(privateIPCheck("1.1.1.1")) // False since this is not a private IP
fmt.Println(privateIPCheck("10.8.0.1")) // True: Since this is a private ip.
}
// Check if a ip is private.
func privateIPCheck(ip string) bool {
ipAddress := net.ParseIP(ip)
return ipAddress.IsPrivate()
}
这需要使用 Go 1.17 版本。
看起来没有比我描述的更好的方法了。结合@MichaelHausenblas的代码和@JimB的建议,我的代码最终变成了这样。
func privateIP(ip string) (bool, error) {
var err error
private := false
IP := net.ParseIP(ip)
if IP == nil {
err = errors.New("Invalid IP")
} else {
_, private24BitBlock, _ := net.ParseCIDR("10.0.0.0/8")
_, private20BitBlock, _ := net.ParseCIDR("172.16.0.0/12")
_, private16BitBlock, _ := net.ParseCIDR("192.168.0.0/16")
private = private24BitBlock.Contains(IP) || private20BitBlock.Contains(IP) || private16BitBlock.Contains(IP)
}
return private, err
}
net.IPNet
拥有Contains
方法。 - JimB