Подтвердить что ты не робот

Golang различают IPv4 IPv6

Для программы, над которой я работаю, я должен проверить, является ли IP (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, который работает всегда?

4b9b3361

Ответ 1

jimt ответ правильный, но довольно сложный. Я просто проверил бы ip.To4() != nil. Поскольку в документации указано, что "если ip не является адресом IPv4, To4 возвращает nil", это условие должно возвращать true тогда и только тогда, когда адрес является адресом IPv4.

Ответ 2

Длина 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.

Ответ 3

Я бы использовал .To4(),.To16() из сетевого пакета, чтобы узнать, является ли он адресом IPv4 или IPv6. проверьте сообщение в блоге. проверьте последний раздел блога, например, который может вам помочь.

Ответ 4

govalidator проверяет наличие : в строке.

func IsIPv6(str string) bool {
  ip := net.ParseIP(str)
  return ip != nil && strings.Contains(str, ":")
}