github.com/kaydxh/golang@v0.0.131/go/net/parse.go (about) 1 /* 2 *Copyright (c) 2022, kaydxh 3 * 4 *Permission is hereby granted, free of charge, to any person obtaining a copy 5 *of this software and associated documentation files (the "Software"), to deal 6 *in the Software without restriction, including without limitation the rights 7 *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 *copies of the Software, and to permit persons to whom the Software is 9 *furnished to do so, subject to the following conditions: 10 * 11 *The above copyright notice and this permission notice shall be included in all 12 *copies or substantial portions of the Software. 13 * 14 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 *SOFTWARE. 21 */ 22 package net 23 24 import "net" 25 26 // ParseIP parses s as an IP address, returning the result. 27 // The string s can be in IPv4 dotted decimal ("192.0.2.1"), IPv6 28 // ("2001:db8::68"), or IPv4-mapped IPv6 ("::ffff:192.0.2.1") form. 29 // If s is not a valid textual representation of an IP address, 30 // ParseIP returns nil. 31 func ParseIP(s string) net.IP { 32 for i := 0; i < len(s); i++ { 33 switch s[i] { 34 case '.': 35 return parseIPv4(s) 36 case ':': 37 return parseIPv6(s) 38 } 39 } 40 return nil 41 } 42 43 // Parse IPv4 address (d.d.d.d). 44 func parseIPv4(s string) net.IP { 45 var p [net.IPv4len]byte 46 for i := 0; i < net.IPv4len; i++ { 47 if len(s) == 0 { 48 // Missing octets. 49 return nil 50 } 51 if i > 0 { 52 if s[0] != '.' { 53 return nil 54 } 55 s = s[1:] 56 } 57 n, c, ok := dtoi(s) 58 if !ok || n > 0xFF { 59 return nil 60 } 61 // 62 // NOTE: This correct check was added for go-1.17, but is a 63 // backwards-incompatible change for kubernetes users, who might have 64 // stored data which uses these leading zeroes already. 65 // 66 // See https://issue.k8s.io/100895 67 // 68 //if c > 1 && s[0] == '0' { 69 // // Reject non-zero components with leading zeroes. 70 // return nil 71 //} 72 s = s[c:] 73 p[i] = byte(n) 74 } 75 if len(s) != 0 { 76 return nil 77 } 78 return net.IPv4(p[0], p[1], p[2], p[3]) 79 } 80 81 // parseIPv6 parses s as a literal IPv6 address described in RFC 4291 82 // and RFC 5952. 83 func parseIPv6(s string) (ip net.IP) { 84 ip = make(net.IP, net.IPv6len) 85 ellipsis := -1 // position of ellipsis in ip 86 87 // Might have leading ellipsis 88 if len(s) >= 2 && s[0] == ':' && s[1] == ':' { 89 ellipsis = 0 90 s = s[2:] 91 // Might be only ellipsis 92 if len(s) == 0 { 93 return ip 94 } 95 } 96 97 // Loop, parsing hex numbers followed by colon. 98 i := 0 99 for i < net.IPv6len { 100 // Hex number. 101 n, c, ok := xtoi(s) 102 if !ok || n > 0xFFFF { 103 return nil 104 } 105 106 // If followed by dot, might be in trailing IPv4. 107 if c < len(s) && s[c] == '.' { 108 if ellipsis < 0 && i != net.IPv6len-net.IPv4len { 109 // Not the right place. 110 return nil 111 } 112 if i+net.IPv4len > net.IPv6len { 113 // Not enough room. 114 return nil 115 } 116 ip4 := parseIPv4(s) 117 if ip4 == nil { 118 return nil 119 } 120 ip[i] = ip4[12] 121 ip[i+1] = ip4[13] 122 ip[i+2] = ip4[14] 123 ip[i+3] = ip4[15] 124 s = "" 125 i += net.IPv4len 126 break 127 } 128 129 // Save this 16-bit chunk. 130 ip[i] = byte(n >> 8) 131 ip[i+1] = byte(n) 132 i += 2 133 134 // Stop at end of string. 135 s = s[c:] 136 if len(s) == 0 { 137 break 138 } 139 140 // Otherwise must be followed by colon and more. 141 if s[0] != ':' || len(s) == 1 { 142 return nil 143 } 144 s = s[1:] 145 146 // Look for ellipsis. 147 if s[0] == ':' { 148 if ellipsis >= 0 { // already have one 149 return nil 150 } 151 ellipsis = i 152 s = s[1:] 153 if len(s) == 0 { // can be at end 154 break 155 } 156 } 157 } 158 159 // Must have used entire string. 160 if len(s) != 0 { 161 return nil 162 } 163 164 // If didn't parse enough, expand ellipsis. 165 if i < net.IPv6len { 166 if ellipsis < 0 { 167 return nil 168 } 169 n := net.IPv6len - i 170 for j := i - 1; j >= ellipsis; j-- { 171 ip[j+n] = ip[j] 172 } 173 for j := ellipsis + n - 1; j >= ellipsis; j-- { 174 ip[j] = 0 175 } 176 } else if ellipsis >= 0 { 177 // Ellipsis must represent at least one 0 group. 178 return nil 179 } 180 return ip 181 } 182 183 // Bigger than we need, not too big to worry about overflow 184 const big = 0xFFFFFF 185 186 // Decimal to integer. 187 // Returns number, characters consumed, success. 188 func dtoi(s string) (n int, i int, ok bool) { 189 n = 0 190 for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { 191 n = n*10 + int(s[i]-'0') 192 if n >= big { 193 return big, i, false 194 } 195 } 196 if i == 0 { 197 return 0, 0, false 198 } 199 return n, i, true 200 } 201 202 // Hexadecimal to integer. 203 // Returns number, characters consumed, success. 204 func xtoi(s string) (n int, i int, ok bool) { 205 n = 0 206 for i = 0; i < len(s); i++ { 207 if '0' <= s[i] && s[i] <= '9' { 208 n *= 16 209 n += int(s[i] - '0') 210 } else if 'a' <= s[i] && s[i] <= 'f' { 211 n *= 16 212 n += int(s[i]-'a') + 10 213 } else if 'A' <= s[i] && s[i] <= 'F' { 214 n *= 16 215 n += int(s[i]-'A') + 10 216 } else { 217 break 218 } 219 if n >= big { 220 return 0, i, false 221 } 222 } 223 if i == 0 { 224 return 0, i, false 225 } 226 return n, i, true 227 }