123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- package utils
- import (
- "net"
- )
- // IsIPv4 works the same way as net.ParseIP,
- // but without check for IPv6 case and without returning net.IP slice, whereby IsIPv4 makes no allocations.
- func IsIPv4(s string) bool {
- for i := 0; i < net.IPv4len; i++ {
- if len(s) == 0 {
- return false
- }
- if i > 0 {
- if s[0] != '.' {
- return false
- }
- s = s[1:]
- }
- n, ci := 0, 0
- for ci = 0; ci < len(s) && '0' <= s[ci] && s[ci] <= '9'; ci++ {
- n = n*10 + int(s[ci]-'0')
- if n > 0xFF {
- return false
- }
- }
- if ci == 0 || (ci > 1 && s[0] == '0') {
- return false
- }
- s = s[ci:]
- }
- return len(s) == 0
- }
- // IsIPv6 works the same way as net.ParseIP,
- // but without check for IPv4 case and without returning net.IP slice, whereby IsIPv6 makes no allocations.
- func IsIPv6(s string) bool {
- ellipsis := -1 // position of ellipsis in ip
- // Might have leading ellipsis
- if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
- ellipsis = 0
- s = s[2:]
- // Might be only ellipsis
- if len(s) == 0 {
- return true
- }
- }
- // Loop, parsing hex numbers followed by colon.
- i := 0
- for i < net.IPv6len {
- // Hex number.
- n, ci := 0, 0
- for ci = 0; ci < len(s); ci++ {
- if '0' <= s[ci] && s[ci] <= '9' {
- n *= 16
- n += int(s[ci] - '0')
- } else if 'a' <= s[ci] && s[ci] <= 'f' {
- n *= 16
- n += int(s[ci]-'a') + 10
- } else if 'A' <= s[ci] && s[ci] <= 'F' {
- n *= 16
- n += int(s[ci]-'A') + 10
- } else {
- break
- }
- if n > 0xFFFF {
- return false
- }
- }
- if ci == 0 || n > 0xFFFF {
- return false
- }
- if ci < len(s) && s[ci] == '.' {
- if ellipsis < 0 && i != net.IPv6len-net.IPv4len {
- return false
- }
- if i+net.IPv4len > net.IPv6len {
- return false
- }
- if !IsIPv4(s) {
- return false
- }
- s = ""
- i += net.IPv4len
- break
- }
- // Save this 16-bit chunk.
- i += 2
- // Stop at end of string.
- s = s[ci:]
- if len(s) == 0 {
- break
- }
- // Otherwise must be followed by colon and more.
- if s[0] != ':' || len(s) == 1 {
- return false
- }
- s = s[1:]
- // Look for ellipsis.
- if s[0] == ':' {
- if ellipsis >= 0 { // already have one
- return false
- }
- ellipsis = i
- s = s[1:]
- if len(s) == 0 { // can be at end
- break
- }
- }
- }
- // Must have used entire string.
- if len(s) != 0 {
- return false
- }
- // If didn't parse enough, expand ellipsis.
- if i < net.IPv6len {
- if ellipsis < 0 {
- return false
- }
- } else if ellipsis >= 0 {
- // Ellipsis must represent at least one 0 group.
- return false
- }
- return true
- }
|