golang区分IPv4 IPv6

对于我正在开发的程序,我必须检查 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?


慕娘9325324
浏览 282回答 3
3回答

POPMUISE

jimt 的回答是正确的,但相当复杂。我会简单地检查ip.To4() != nil。由于文档说“如果 ip 不是 IPv4 地址,To4 返回 nil”这个条件应该返回true当且仅当地址是 IPv4 地址。

有只小跳蛙

IP 的长度几乎总是 16,因为 的内部表示net.IP对于任何一种情况都是相同的。从文档:请注意,在本文档中,将 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。

繁华开满天机

该接受的答案由埃文(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 字面量"[::FFFF:C0A8:1]:80": 带有端口信息"[::FFFF:C0A8:1%1]:80": 带区域和端口信息所有这些情况(同时支持IPv4和IPv6名单)将被考虑IPv4地址的net包。IPv6 列表的 IPv4 文字变体将被govalidator视为 IPv4&nbsp;。检查它是 IPv4 还是 IPv6 地址的最简单方法如下:import stringsfunc IsIPv4(address string) bool {&nbsp; &nbsp; return strings.Count(address, ":") < 2}func IsIPv6(address string) bool {&nbsp; &nbsp; return strings.Count(address, ":") >= 2}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go