对于我正在处理的程序,我必须检查IP(将我连接到Internet的IP)是公共还是私有。为此,我需要区分IP是IPv4还是IPv6。
我想根据IP的长度来检查它:
conn, err := net.Dial("udp", "8.9.10.11:2342")
if err != nil {
fmt.Println("Error", err)
}
localaddr := conn.LocalAddr()
addr, _ := net.ResolveUDPAddr("udp", localaddr.String())
ip := addr.IP
fmt.Println(ip)
fmt.Println(len(ip))
嗯,我的IP是192.168.2.100,所以IPv4,但len(ip)告诉我长度是16,这将是IPv6。 我的错是什么?是否存在区分IPv4和IPv6的其他方法?
答案 0 :(得分:31)
ip.To4() != nil
。由于文档说"如果ip不是IPv4地址,To4返回nil"当且仅当地址是IPv4地址时,此条件应返回true
。
答案 1 :(得分:10)
IP的长度几乎总是16,因为net.IP
的内部表示对于任何一种情况都是相同的。来自the documentation:
请注意,在本文档中,将IP地址称为IPv4地址或IPv6地址是地址的语义属性,而不仅仅是字节片的长度:16字节片仍然可以是IPv4地址
分离这两种类型取决于IP的初始化方式。查看net.IPv4()
的代码,可以看到它被初始化为16个字节,前12个字节的值设置为v4InV6Prefix
。
// IPv4 returns the IP address (in 16-byte form) of the
// IPv4 address a.b.c.d.
func IPv4(a, b, c, d byte) IP {
p := make(IP, IPv6len)
copy(p, v4InV6Prefix)
p[12] = a
p[13] = b
p[14] = c
p[15] = d
return p
}
v4InV6Prefix
定义为:
var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
如果您想要可靠的差异化,请查看net.IP.To4
的来源如何处理它:
// To4 converts the IPv4 address ip to a 4-byte representation.
// If ip is not an IPv4 address, To4 returns nil.
func (ip IP) To4() IP {
if len(ip) == IPv4len {
return ip
}
if len(ip) == IPv6len &&
isZeros(ip[0:10]) &&
ip[10] == 0xff &&
ip[11] == 0xff {
return ip[12:16]
}
return nil
}
isZeros
未导出,因此您必须在本地复制该代码。然后,您可以执行与上述相同的操作,以确定您是否具有IPv4或IPv6。
答案 2 :(得分:3)
accepted answer Evan(ip.To4() != nil
)解决了这个问题。然而,有一些评论和其他答案检查表示是否是IPv4或IPv6并且它们并不总是准确的:
注意 :分别列出了几个有效的IPv4和IPv6有效标记列表。每个条目代表第一个基本条目的变体。可以根据需要组合变体,但出于空间原因,除了消除歧义外,没有列出任何变体组合。
有效的IPv4表示法:
"192.168.0.1"
:基本"192.168.0.1:80"
:带端口信息有效的IPv6表示法:
"::FFFF:C0A8:1"
:基本"::FFFF:C0A8:0001"
:前导零"0000:0000:0000:0000:0000:FFFF:C0A8:1"
:扩展双冒号"::FFFF:C0A8:1%1"
:带有区域信息"::FFFF:192.168.0.1"
:IPv4 literal "[::FFFF:C0A8:1]:80"
:带端口信息"[::FFFF:C0A8:1%1]:80"
:带有区域和端口信息所有这些情况(IPv4和IPv6列表)都将被the net
package视为IPv4地址。
IPv6列表的IPv4文字变体将被govalidator视为IPv4。
检查它是IPv4还是IPv6地址的最简单方法如下:
import strings
func IsIPv4(address string) bool {
return strings.Count(address, ":") < 2
}
func IsIPv6(address string) bool {
return strings.Count(address, ":") >= 2
}
答案 3 :(得分:2)
我会从网络包中使用.To4(),. To16()来查找它是IPv4还是IPv6地址。 检查blog post。查看博客的最后一部分,例如可能对您有所帮助。
答案 4 :(得分:2)
govalidator检查字符串中是否存在+14
。
: