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, который работает всегда?
Ответы
Ответ 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, ":")
}