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  }