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  }