github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/ipaddr/ip.go (about) 1 // Copyright 2021 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 // Copyright 2009 The Go Authors. All rights reserved. 12 // Use of this source code is governed by a BSD-style 13 // license that can be found in the LICENSE file. 14 15 // See the go license at https://golang.org/LICENSE. 16 17 // IP address manipulations 18 // 19 // IPv4 addresses are 4 bytes; IPv6 addresses are 16 bytes. 20 // An IPv4 address can be converted to an IPv6 address by 21 // adding a canonical prefix (10 zeros, 2 0xFFs). 22 // This library accepts either size of byte slice but always 23 // returns 16-byte addresses. 24 25 // This code was copied out of Go 1.16 as Go 1.17 removed the ability to 26 // parse leading 0s in IP addresses. We copy the Go 1.16 to keep the ParseIP 27 // function's capability to parse leading 0s and hence be compatible with 28 // Postgres. 29 // Example: '10.1.1.017' should be parsed as '10.1.1.17'. 30 31 package ipaddr 32 33 // An IP is a single IP address, a slice of bytes. 34 // Functions in this package accept either 4-byte (IPv4) 35 // or 16-byte (IPv6) slices as input. 36 // 37 // Note that in this documentation, referring to an 38 // IP address as an IPv4 address or an IPv6 address 39 // is a semantic property of the address, not just the 40 // length of the byte slice: a 16-byte slice can still 41 // be an IPv4 address. 42 type IP []byte 43 44 // IP address lengths (bytes). 45 const ( 46 IPv4len = 4 47 IPv6len = 16 48 ) 49 50 // ParseIP parses s as an IP address, returning the result. 51 // The string s can be in IPv4 dotted decimal ("192.0.2.1"), IPv6 52 // ("2001:db8::68"), or IPv4-mapped IPv6 ("::ffff:192.0.2.1") form. 53 // If s is not a valid textual representation of an IP address, 54 // ParseIP returns nil. 55 func ParseIP(s string) IP { 56 for i := 0; i < len(s); i++ { 57 switch s[i] { 58 case '.': 59 return parseIPv4(s) 60 case ':': 61 return parseIPv6(s) 62 } 63 } 64 return nil 65 } 66 67 func parseIPv4(s string) IP { 68 var p [IPv4len]byte 69 for i := 0; i < IPv4len; i++ { 70 if len(s) == 0 { 71 // Missing octets. 72 return nil 73 } 74 if i > 0 { 75 if s[0] != '.' { 76 return nil 77 } 78 s = s[1:] 79 } 80 n, c, ok := dtoi(s) 81 if !ok || n > 0xFF { 82 return nil 83 } 84 s = s[c:] 85 p[i] = byte(n) 86 } 87 if len(s) != 0 { 88 return nil 89 } 90 return makeIPv4(p[0], p[1], p[2], p[3]) 91 } 92 93 var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff} 94 95 // makeIPv4 returns the IP address (in 16-byte form) of the 96 // IPv4 address a.b.c.d. 97 func makeIPv4(a, b, c, d byte) IP { 98 p := make(IP, IPv6len) 99 copy(p, v4InV6Prefix) 100 p[12] = a 101 p[13] = b 102 p[14] = c 103 p[15] = d 104 return p 105 } 106 107 // parseIPv6 parses s as a literal IPv6 address described in RFC 4291 108 // and RFC 5952. 109 func parseIPv6(s string) (ip IP) { 110 ip = make(IP, IPv6len) 111 ellipsis := -1 // position of ellipsis in ip 112 113 // Might have leading ellipsis 114 if len(s) >= 2 && s[0] == ':' && s[1] == ':' { 115 ellipsis = 0 116 s = s[2:] 117 // Might be only ellipsis 118 if len(s) == 0 { 119 return ip 120 } 121 } 122 123 // Loop, parsing hex numbers followed by colon. 124 i := 0 125 for i < IPv6len { 126 // Hex number. 127 n, c, ok := xtoi(s) 128 if !ok || n > 0xFFFF { 129 return nil 130 } 131 132 // If followed by dot, might be in trailing IPv4. 133 if c < len(s) && s[c] == '.' { 134 if ellipsis < 0 && i != IPv6len-IPv4len { 135 // Not the right place. 136 return nil 137 } 138 if i+IPv4len > IPv6len { 139 // Not enough room. 140 return nil 141 } 142 ip4 := parseIPv4(s) 143 if ip4 == nil { 144 return nil 145 } 146 ip[i] = ip4[12] 147 ip[i+1] = ip4[13] 148 ip[i+2] = ip4[14] 149 ip[i+3] = ip4[15] 150 s = "" 151 i += IPv4len 152 break 153 } 154 155 // Save this 16-bit chunk. 156 ip[i] = byte(n >> 8) 157 ip[i+1] = byte(n) 158 i += 2 159 160 // Stop at end of string. 161 s = s[c:] 162 if len(s) == 0 { 163 break 164 } 165 166 // Otherwise must be followed by colon and more. 167 if s[0] != ':' || len(s) == 1 { 168 return nil 169 } 170 s = s[1:] 171 172 // Look for ellipsis. 173 if s[0] == ':' { 174 if ellipsis >= 0 { // already have one 175 return nil 176 } 177 ellipsis = i 178 s = s[1:] 179 if len(s) == 0 { // can be at end 180 break 181 } 182 } 183 } 184 185 // Must have used entire string. 186 if len(s) != 0 { 187 return nil 188 } 189 190 // If didn't parse enough, expand ellipsis. 191 if i < IPv6len { 192 if ellipsis < 0 { 193 return nil 194 } 195 n := IPv6len - i 196 for j := i - 1; j >= ellipsis; j-- { 197 ip[j+n] = ip[j] 198 } 199 for j := ellipsis + n - 1; j >= ellipsis; j-- { 200 ip[j] = 0 201 } 202 } else if ellipsis >= 0 { 203 // Ellipsis must represent at least one 0 group. 204 return nil 205 } 206 return ip 207 } 208 209 // Bigger than we need, not too big to worry about overflow 210 const big = 0xFFFFFF 211 212 // Decimal to integer. 213 // Returns number, characters consumed, success. 214 func dtoi(s string) (n int, i int, ok bool) { 215 n = 0 216 for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { 217 n = n*10 + int(s[i]-'0') 218 if n >= big { 219 return big, i, false 220 } 221 } 222 if i == 0 { 223 return 0, 0, false 224 } 225 return n, i, true 226 } 227 228 // Hexadecimal to integer. 229 // Returns number, characters consumed, success. 230 func xtoi(s string) (n int, i int, ok bool) { 231 n = 0 232 for i = 0; i < len(s); i++ { 233 if '0' <= s[i] && s[i] <= '9' { 234 n *= 16 235 n += int(s[i] - '0') 236 } else if 'a' <= s[i] && s[i] <= 'f' { 237 n *= 16 238 n += int(s[i]-'a') + 10 239 } else if 'A' <= s[i] && s[i] <= 'F' { 240 n *= 16 241 n += int(s[i]-'A') + 10 242 } else { 243 break 244 } 245 if n >= big { 246 return 0, i, false 247 } 248 } 249 if i == 0 { 250 return 0, i, false 251 } 252 return n, i, true 253 }