github.com/gofiber/fiber/v2@v2.47.0/utils/ips.go (about) 1 package utils 2 3 import ( 4 "net" 5 ) 6 7 // IsIPv4 works the same way as net.ParseIP, 8 // but without check for IPv6 case and without returning net.IP slice, whereby IsIPv4 makes no allocations. 9 func IsIPv4(s string) bool { 10 for i := 0; i < net.IPv4len; i++ { 11 if len(s) == 0 { 12 return false 13 } 14 15 if i > 0 { 16 if s[0] != '.' { 17 return false 18 } 19 s = s[1:] 20 } 21 22 n, ci := 0, 0 23 24 for ci = 0; ci < len(s) && '0' <= s[ci] && s[ci] <= '9'; ci++ { 25 n = n*10 + int(s[ci]-'0') 26 if n >= 0xFF { 27 return false 28 } 29 } 30 31 if ci == 0 || (ci > 1 && s[0] == '0') { 32 return false 33 } 34 35 s = s[ci:] 36 } 37 38 return len(s) == 0 39 } 40 41 // IsIPv6 works the same way as net.ParseIP, 42 // but without check for IPv4 case and without returning net.IP slice, whereby IsIPv6 makes no allocations. 43 func IsIPv6(s string) bool { 44 ellipsis := -1 // position of ellipsis in ip 45 46 // Might have leading ellipsis 47 if len(s) >= 2 && s[0] == ':' && s[1] == ':' { 48 ellipsis = 0 49 s = s[2:] 50 // Might be only ellipsis 51 if len(s) == 0 { 52 return true 53 } 54 } 55 56 // Loop, parsing hex numbers followed by colon. 57 i := 0 58 for i < net.IPv6len { 59 // Hex number. 60 n, ci := 0, 0 61 62 for ci = 0; ci < len(s); ci++ { 63 if '0' <= s[ci] && s[ci] <= '9' { 64 n *= 16 65 n += int(s[ci] - '0') 66 } else if 'a' <= s[ci] && s[ci] <= 'f' { 67 n *= 16 68 n += int(s[ci]-'a') + 10 69 } else if 'A' <= s[ci] && s[ci] <= 'F' { 70 n *= 16 71 n += int(s[ci]-'A') + 10 72 } else { 73 break 74 } 75 if n > 0xFFFF { 76 return false 77 } 78 } 79 if ci == 0 || n > 0xFFFF { 80 return false 81 } 82 83 if ci < len(s) && s[ci] == '.' { 84 if ellipsis < 0 && i != net.IPv6len-net.IPv4len { 85 return false 86 } 87 if i+net.IPv4len > net.IPv6len { 88 return false 89 } 90 91 if !IsIPv4(s) { 92 return false 93 } 94 95 s = "" 96 i += net.IPv4len 97 break 98 } 99 100 // Save this 16-bit chunk. 101 i += 2 102 103 // Stop at end of string. 104 s = s[ci:] 105 if len(s) == 0 { 106 break 107 } 108 109 // Otherwise must be followed by colon and more. 110 if s[0] != ':' || len(s) == 1 { 111 return false 112 } 113 s = s[1:] 114 115 // Look for ellipsis. 116 if s[0] == ':' { 117 if ellipsis >= 0 { // already have one 118 return false 119 } 120 ellipsis = i 121 s = s[1:] 122 if len(s) == 0 { // can be at end 123 break 124 } 125 } 126 } 127 128 // Must have used entire string. 129 if len(s) != 0 { 130 return false 131 } 132 133 // If didn't parse enough, expand ellipsis. 134 if i < net.IPv6len { 135 if ellipsis < 0 { 136 return false 137 } 138 } else if ellipsis >= 0 { 139 // Ellipsis must represent at least one 0 group. 140 return false 141 } 142 return true 143 }