为了账号安全,请及时绑定邮箱和手机立即绑定

golang区分IPv4 IPv6

golang区分IPv4 IPv6

Go
慕娘9325324 2021-07-30 14:02:43
对于我正在开发的程序,我必须检查 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.IPfmt.Println(ip)fmt.Println(len(ip))好吧,我的 IP 是 192.168.2.100,所以是 IPv4,但是 len(ip) 告诉我长度是 16,这就是 IPv6。我的错误是什么?是否存在任何其他方法来区分始终有效的 IPv4 和 IPv6?
查看完整描述

3 回答

?
POPMUISE

TA贡献1765条经验 获得超5个赞

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


查看完整回答
反对 回复 2021-08-02
?
有只小跳蛙

TA贡献1824条经验 获得超8个赞

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。


查看完整回答
反对 回复 2021-08-02
?
繁华开满天机

TA贡献1816条经验 获得超4个赞

接受的答案埃文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 。

检查它是 IPv4 还是 IPv6 地址的最简单方法如下:

import strings


func IsIPv4(address string) bool {

    return strings.Count(address, ":") < 2

}


func IsIPv6(address string) bool {

    return strings.Count(address, ":") >= 2

}


查看完整回答
反对 回复 2021-08-02
  • 3 回答
  • 0 关注
  • 281 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信