netip.mx raw

   1  // Copyright 2020 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  // Package netip defines an IP address type that's a small value type.
   6  // Building on that [Addr] type, the package also defines [AddrPort] (an
   7  // IP address and a port) and [Prefix] (an IP address and a bit length
   8  // prefix).
   9  //
  10  // Compared to the [net.IP] type, [Addr] type takes less memory, is immutable,
  11  // and is comparable (supports == and being a map key).
  12  package netip
  13  
  14  import (
  15  	"cmp"
  16  	"errors"
  17  	"internal/bytealg"
  18  	"internal/byteorder"
  19  	"internal/itoa"
  20  	"math"
  21  	"strconv"
  22  	"unique"
  23  )
  24  
  25  // Sizes: (64-bit)
  26  //   net.IP:     24 byte slice header + {4, 16} = 28 to 40 bytes
  27  //   net.IPAddr: 40 byte slice header + {4, 16} = 44 to 56 bytes + zone length
  28  //   netip.Addr: 24 bytes (zone is per-name singleton, shared across all users)
  29  
  30  // Addr represents an IPv4 or IPv6 address (with or without a scoped
  31  // addressing zone), similar to [net.IP] or [net.IPAddr].
  32  //
  33  // Unlike [net.IP] or [net.IPAddr], Addr is a comparable value
  34  // type (it supports == and can be a map key) and is immutable.
  35  //
  36  // The zero Addr is not a valid IP address.
  37  // Addr{} is distinct from both 0.0.0.0 and ::.
  38  type Addr struct {
  39  	// addr is the hi and lo bits of an IPv6 address. If z==z4,
  40  	// hi and lo contain the IPv4-mapped IPv6 address.
  41  	//
  42  	// hi and lo are constructed by interpreting a 16-byte IPv6
  43  	// address as a big-endian 128-bit number. The most significant
  44  	// bits of that number go into hi, the rest into lo.
  45  	//
  46  	// For example, 0011:2233:4455:6677:8899:aabb:ccdd:eeff is stored as:
  47  	//  addr.hi = 0x0011223344556677
  48  	//  addr.lo = 0x8899aabbccddeeff
  49  	//
  50  	// We store IPs like this, rather than as [16]byte, because it
  51  	// turns most operations on IPs into arithmetic and bit-twiddling
  52  	// operations on 64-bit registers, which is much faster than
  53  	// bytewise processing.
  54  	addr uint128
  55  
  56  	// Details about the address, wrapped up together and canonicalized.
  57  	z unique.Handle[addrDetail]
  58  }
  59  
  60  // addrDetail represents the details of an Addr, like address family and IPv6 zone.
  61  type addrDetail struct {
  62  	isV6   bool   // IPv4 is false, IPv6 is true.
  63  	zoneV6 string // != "" only if IsV6 is true.
  64  }
  65  
  66  // z0, z4, and z6noz are sentinel Addr.z values.
  67  // See the Addr type's field docs.
  68  var (
  69  	z0    unique.Handle[addrDetail]
  70  	z4    = unique.Make(addrDetail{})
  71  	z6noz = unique.Make(addrDetail{isV6: true})
  72  )
  73  
  74  // IPv6LinkLocalAllNodes returns the IPv6 link-local all nodes multicast
  75  // address ff02::1.
  76  func IPv6LinkLocalAllNodes() Addr { return AddrFrom16([16]byte{0: 0xff, 1: 0x02, 15: 0x01}) }
  77  
  78  // IPv6LinkLocalAllRouters returns the IPv6 link-local all routers multicast
  79  // address ff02::2.
  80  func IPv6LinkLocalAllRouters() Addr { return AddrFrom16([16]byte{0: 0xff, 1: 0x02, 15: 0x02}) }
  81  
  82  // IPv6Loopback returns the IPv6 loopback address ::1.
  83  func IPv6Loopback() Addr { return AddrFrom16([16]byte{15: 0x01}) }
  84  
  85  // IPv6Unspecified returns the IPv6 unspecified address "::".
  86  func IPv6Unspecified() Addr { return Addr{z: z6noz} }
  87  
  88  // IPv4Unspecified returns the IPv4 unspecified address "0.0.0.0".
  89  func IPv4Unspecified() Addr { return AddrFrom4([4]byte{}) }
  90  
  91  // AddrFrom4 returns the address of the IPv4 address given by the bytes in addr.
  92  func AddrFrom4(addr [4]byte) Addr {
  93  	return Addr{
  94  		addr: uint128{0, 0xffff00000000 | uint64(addr[0])<<24 | uint64(addr[1])<<16 | uint64(addr[2])<<8 | uint64(addr[3])},
  95  		z:    z4,
  96  	}
  97  }
  98  
  99  // AddrFrom16 returns the IPv6 address given by the bytes in addr.
 100  // An IPv4-mapped IPv6 address is left as an IPv6 address.
 101  // (Use Unmap to convert them if needed.)
 102  func AddrFrom16(addr [16]byte) Addr {
 103  	return Addr{
 104  		addr: uint128{
 105  			byteorder.BEUint64(addr[:8]),
 106  			byteorder.BEUint64(addr[8:]),
 107  		},
 108  		z: z6noz,
 109  	}
 110  }
 111  
 112  // ParseAddr parses s as an IP address, returning the result. The string
 113  // s can be in dotted decimal ("192.0.2.1"), IPv6 ("2001:db8::68"),
 114  // or IPv6 with a scoped addressing zone ("fe80::1cc0:3e8c:119f:c2e1%ens18").
 115  func ParseAddr(s string) (Addr, error) {
 116  	for i := 0; i < len(s); i++ {
 117  		switch s[i] {
 118  		case '.':
 119  			return parseIPv4(s)
 120  		case ':':
 121  			return parseIPv6(s)
 122  		case '%':
 123  			// Assume that this was trying to be an IPv6 address with
 124  			// a zone specifier, but the address is missing.
 125  			return Addr{}, parseAddrError{in: s, msg: "missing IPv6 address"}
 126  		}
 127  	}
 128  	return Addr{}, parseAddrError{in: s, msg: "unable to parse IP"}
 129  }
 130  
 131  // MustParseAddr calls [ParseAddr](s) and panics on error.
 132  // It is intended for use in tests with hard-coded strings.
 133  func MustParseAddr(s string) Addr {
 134  	ip, err := ParseAddr(s)
 135  	if err != nil {
 136  		panic(err)
 137  	}
 138  	return ip
 139  }
 140  
 141  type parseAddrError struct {
 142  	in  string // the string given to ParseAddr
 143  	msg string // an explanation of the parse failure
 144  	at  string // optionally, the unparsed portion of in at which the error occurred.
 145  }
 146  
 147  func (err parseAddrError) Error() string {
 148  	q := strconv.Quote
 149  	if err.at != "" {
 150  		return "ParseAddr(" + q(err.in) + "): " + err.msg + " (at " + q(err.at) + ")"
 151  	}
 152  	return "ParseAddr(" + q(err.in) + "): " + err.msg
 153  }
 154  
 155  func parseIPv4Fields(in string, off, end int, fields []uint8) error {
 156  	var val, pos int
 157  	var digLen int // number of digits in current octet
 158  	s := in[off:end]
 159  	for i := 0; i < len(s); i++ {
 160  		if s[i] >= '0' && s[i] <= '9' {
 161  			if digLen == 1 && val == 0 {
 162  				return parseAddrError{in: in, msg: "IPv4 field has octet with leading zero"}
 163  			}
 164  			val = val*10 + int(s[i]) - '0'
 165  			digLen++
 166  			if val > 255 {
 167  				return parseAddrError{in: in, msg: "IPv4 field has value >255"}
 168  			}
 169  		} else if s[i] == '.' {
 170  			// .1.2.3
 171  			// 1.2.3.
 172  			// 1..2.3
 173  			if i == 0 || i == len(s)-1 || s[i-1] == '.' {
 174  				return parseAddrError{in: in, msg: "IPv4 field must have at least one digit", at: s[i:]}
 175  			}
 176  			// 1.2.3.4.5
 177  			if pos == 3 {
 178  				return parseAddrError{in: in, msg: "IPv4 address too long"}
 179  			}
 180  			fields[pos] = uint8(val)
 181  			pos++
 182  			val = 0
 183  			digLen = 0
 184  		} else {
 185  			return parseAddrError{in: in, msg: "unexpected character", at: s[i:]}
 186  		}
 187  	}
 188  	if pos < 3 {
 189  		return parseAddrError{in: in, msg: "IPv4 address too short"}
 190  	}
 191  	fields[3] = uint8(val)
 192  	return nil
 193  }
 194  
 195  // parseIPv4 parses s as an IPv4 address (in form "192.168.0.1").
 196  func parseIPv4(s string) (ip Addr, err error) {
 197  	var fields [4]uint8
 198  	err = parseIPv4Fields(s, 0, len(s), fields[:])
 199  	if err != nil {
 200  		return Addr{}, err
 201  	}
 202  	return AddrFrom4(fields), nil
 203  }
 204  
 205  // parseIPv6 parses s as an IPv6 address (in form "2001:db8::68").
 206  func parseIPv6(in string) (Addr, error) {
 207  	s := in
 208  
 209  	// Split off the zone right from the start. Yes it's a second scan
 210  	// of the string, but trying to handle it inline makes a bunch of
 211  	// other inner loop conditionals more expensive, and it ends up
 212  	// being slower.
 213  	zone := ""
 214  	i := bytealg.IndexByteString(s, '%')
 215  	if i != -1 {
 216  		s, zone = s[:i], s[i+1:]
 217  		if zone == "" {
 218  			// Not allowed to have an empty zone if explicitly specified.
 219  			return Addr{}, parseAddrError{in: in, msg: "zone must be a non-empty string"}
 220  		}
 221  	}
 222  
 223  	var ip [16]byte
 224  	ellipsis := -1 // position of ellipsis in ip
 225  
 226  	// Might have leading ellipsis
 227  	if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
 228  		ellipsis = 0
 229  		s = s[2:]
 230  		// Might be only ellipsis
 231  		if len(s) == 0 {
 232  			return IPv6Unspecified().WithZone(zone), nil
 233  		}
 234  	}
 235  
 236  	// Loop, parsing hex numbers followed by colon.
 237  	i = 0
 238  	for i < 16 {
 239  		// Hex number. Similar to parseIPv4, inlining the hex number
 240  		// parsing yields a significant performance increase.
 241  		off := 0
 242  		acc := uint32(0)
 243  		for ; off < len(s); off++ {
 244  			c := s[off]
 245  			if c >= '0' && c <= '9' {
 246  				acc = (acc << 4) + uint32(c-'0')
 247  			} else if c >= 'a' && c <= 'f' {
 248  				acc = (acc << 4) + uint32(c-'a'+10)
 249  			} else if c >= 'A' && c <= 'F' {
 250  				acc = (acc << 4) + uint32(c-'A'+10)
 251  			} else {
 252  				break
 253  			}
 254  			if off > 3 {
 255  				//more than 4 digits in group, fail.
 256  				return Addr{}, parseAddrError{in: in, msg: "each group must have 4 or less digits", at: s}
 257  			}
 258  			if acc > math.MaxUint16 {
 259  				// Overflow, fail.
 260  				return Addr{}, parseAddrError{in: in, msg: "IPv6 field has value >=2^16", at: s}
 261  			}
 262  		}
 263  		if off == 0 {
 264  			// No digits found, fail.
 265  			return Addr{}, parseAddrError{in: in, msg: "each colon-separated field must have at least one digit", at: s}
 266  		}
 267  
 268  		// If followed by dot, might be in trailing IPv4.
 269  		if off < len(s) && s[off] == '.' {
 270  			if ellipsis < 0 && i != 12 {
 271  				// Not the right place.
 272  				return Addr{}, parseAddrError{in: in, msg: "embedded IPv4 address must replace the final 2 fields of the address", at: s}
 273  			}
 274  			if i+4 > 16 {
 275  				// Not enough room.
 276  				return Addr{}, parseAddrError{in: in, msg: "too many hex fields to fit an embedded IPv4 at the end of the address", at: s}
 277  			}
 278  
 279  			end := len(in)
 280  			if len(zone) > 0 {
 281  				end -= len(zone) + 1
 282  			}
 283  			err := parseIPv4Fields(in, end-len(s), end, ip[i:i+4])
 284  			if err != nil {
 285  				return Addr{}, err
 286  			}
 287  			s = ""
 288  			i += 4
 289  			break
 290  		}
 291  
 292  		// Save this 16-bit chunk.
 293  		ip[i] = byte(acc >> 8)
 294  		ip[i+1] = byte(acc)
 295  		i += 2
 296  
 297  		// Stop at end of string.
 298  		s = s[off:]
 299  		if len(s) == 0 {
 300  			break
 301  		}
 302  
 303  		// Otherwise must be followed by colon and more.
 304  		if s[0] != ':' {
 305  			return Addr{}, parseAddrError{in: in, msg: "unexpected character, want colon", at: s}
 306  		} else if len(s) == 1 {
 307  			return Addr{}, parseAddrError{in: in, msg: "colon must be followed by more characters", at: s}
 308  		}
 309  		s = s[1:]
 310  
 311  		// Look for ellipsis.
 312  		if s[0] == ':' {
 313  			if ellipsis >= 0 { // already have one
 314  				return Addr{}, parseAddrError{in: in, msg: "multiple :: in address", at: s}
 315  			}
 316  			ellipsis = i
 317  			s = s[1:]
 318  			if len(s) == 0 { // can be at end
 319  				break
 320  			}
 321  		}
 322  	}
 323  
 324  	// Must have used entire string.
 325  	if len(s) != 0 {
 326  		return Addr{}, parseAddrError{in: in, msg: "trailing garbage after address", at: s}
 327  	}
 328  
 329  	// If didn't parse enough, expand ellipsis.
 330  	if i < 16 {
 331  		if ellipsis < 0 {
 332  			return Addr{}, parseAddrError{in: in, msg: "address string too short"}
 333  		}
 334  		n := 16 - i
 335  		for j := i - 1; j >= ellipsis; j-- {
 336  			ip[j+n] = ip[j]
 337  		}
 338  		clear(ip[ellipsis : ellipsis+n])
 339  	} else if ellipsis >= 0 {
 340  		// Ellipsis must represent at least one 0 group.
 341  		return Addr{}, parseAddrError{in: in, msg: "the :: must expand to at least one field of zeros"}
 342  	}
 343  	return AddrFrom16(ip).WithZone(zone), nil
 344  }
 345  
 346  // AddrFromSlice parses the 4- or 16-byte byte slice as an IPv4 or IPv6 address.
 347  // Note that a [net.IP] can be passed directly as the []byte argument.
 348  // If slice's length is not 4 or 16, AddrFromSlice returns [Addr]{}, false.
 349  func AddrFromSlice(slice []byte) (ip Addr, ok bool) {
 350  	switch len(slice) {
 351  	case 4:
 352  		return AddrFrom4([4]byte(slice)), true
 353  	case 16:
 354  		return AddrFrom16([16]byte(slice)), true
 355  	}
 356  	return Addr{}, false
 357  }
 358  
 359  // v4 returns the i'th byte of ip. If ip is not an IPv4, v4 returns
 360  // unspecified garbage.
 361  func (ip Addr) v4(i uint8) uint8 {
 362  	return uint8(ip.addr.lo >> ((3 - i) * 8))
 363  }
 364  
 365  // v6 returns the i'th byte of ip. If ip is an IPv4 address, this
 366  // accesses the IPv4-mapped IPv6 address form of the IP.
 367  func (ip Addr) v6(i uint8) uint8 {
 368  	return uint8(*(ip.addr.halves()[(i/8)%2]) >> ((7 - i%8) * 8))
 369  }
 370  
 371  // v6u16 returns the i'th 16-bit word of ip. If ip is an IPv4 address,
 372  // this accesses the IPv4-mapped IPv6 address form of the IP.
 373  func (ip Addr) v6u16(i uint8) uint16 {
 374  	return uint16(*(ip.addr.halves()[(i/4)%2]) >> ((3 - i%4) * 16))
 375  }
 376  
 377  // isZero reports whether ip is the zero value of the IP type.
 378  // The zero value is not a valid IP address of any type.
 379  //
 380  // Note that "0.0.0.0" and "::" are not the zero value. Use IsUnspecified to
 381  // check for these values instead.
 382  func (ip Addr) isZero() bool {
 383  	// Faster than comparing ip == Addr{}, but effectively equivalent,
 384  	// as there's no way to make an IP with a nil z from this package.
 385  	return ip.z == z0
 386  }
 387  
 388  // IsValid reports whether the [Addr] is an initialized address (not the zero Addr).
 389  //
 390  // Note that "0.0.0.0" and "::" are both valid values.
 391  func (ip Addr) IsValid() bool { return ip.z != z0 }
 392  
 393  // BitLen returns the number of bits in the IP address:
 394  // 128 for IPv6, 32 for IPv4, and 0 for the zero [Addr].
 395  //
 396  // Note that IPv4-mapped IPv6 addresses are considered IPv6 addresses
 397  // and therefore have bit length 128.
 398  func (ip Addr) BitLen() int {
 399  	switch ip.z {
 400  	case z0:
 401  		return 0
 402  	case z4:
 403  		return 32
 404  	}
 405  	return 128
 406  }
 407  
 408  // Zone returns ip's IPv6 scoped addressing zone, if any.
 409  func (ip Addr) Zone() string {
 410  	if ip.z == z0 {
 411  		return ""
 412  	}
 413  	return ip.z.Value().zoneV6
 414  }
 415  
 416  // Compare returns an integer comparing two IPs.
 417  // The result will be 0 if ip == ip2, -1 if ip < ip2, and +1 if ip > ip2.
 418  // The definition of "less than" is the same as the [Addr.Less] method.
 419  func (ip Addr) Compare(ip2 Addr) int {
 420  	f1, f2 := ip.BitLen(), ip2.BitLen()
 421  	if f1 < f2 {
 422  		return -1
 423  	}
 424  	if f1 > f2 {
 425  		return 1
 426  	}
 427  	hi1, hi2 := ip.addr.hi, ip2.addr.hi
 428  	if hi1 < hi2 {
 429  		return -1
 430  	}
 431  	if hi1 > hi2 {
 432  		return 1
 433  	}
 434  	lo1, lo2 := ip.addr.lo, ip2.addr.lo
 435  	if lo1 < lo2 {
 436  		return -1
 437  	}
 438  	if lo1 > lo2 {
 439  		return 1
 440  	}
 441  	if ip.Is6() {
 442  		za, zb := ip.Zone(), ip2.Zone()
 443  		if za < zb {
 444  			return -1
 445  		}
 446  		if za > zb {
 447  			return 1
 448  		}
 449  	}
 450  	return 0
 451  }
 452  
 453  // Less reports whether ip sorts before ip2.
 454  // IP addresses sort first by length, then their address.
 455  // IPv6 addresses with zones sort just after the same address without a zone.
 456  func (ip Addr) Less(ip2 Addr) bool { return ip.Compare(ip2) == -1 }
 457  
 458  // Is4 reports whether ip is an IPv4 address.
 459  //
 460  // It returns false for IPv4-mapped IPv6 addresses. See [Addr.Unmap].
 461  func (ip Addr) Is4() bool {
 462  	return ip.z == z4
 463  }
 464  
 465  // Is4In6 reports whether ip is an "IPv4-mapped IPv6 address"
 466  // as defined by RFC 4291.
 467  // That is, it reports whether ip is in ::ffff:0:0/96.
 468  func (ip Addr) Is4In6() bool {
 469  	return ip.Is6() && ip.addr.hi == 0 && ip.addr.lo>>32 == 0xffff
 470  }
 471  
 472  // Is6 reports whether ip is an IPv6 address, including IPv4-mapped
 473  // IPv6 addresses.
 474  func (ip Addr) Is6() bool {
 475  	return ip.z != z0 && ip.z != z4
 476  }
 477  
 478  // Unmap returns ip with any IPv4-mapped IPv6 address prefix removed.
 479  //
 480  // That is, if ip is an IPv6 address wrapping an IPv4 address, it
 481  // returns the wrapped IPv4 address. Otherwise it returns ip unmodified.
 482  func (ip Addr) Unmap() Addr {
 483  	if ip.Is4In6() {
 484  		ip.z = z4
 485  	}
 486  	return ip
 487  }
 488  
 489  // WithZone returns an IP that's the same as ip but with the provided
 490  // zone. If zone is empty, the zone is removed. If ip is an IPv4
 491  // address, WithZone is a no-op and returns ip unchanged.
 492  func (ip Addr) WithZone(zone string) Addr {
 493  	if !ip.Is6() {
 494  		return ip
 495  	}
 496  	if zone == "" {
 497  		ip.z = z6noz
 498  		return ip
 499  	}
 500  	ip.z = unique.Make(addrDetail{isV6: true, zoneV6: zone})
 501  	return ip
 502  }
 503  
 504  // withoutZone unconditionally strips the zone from ip.
 505  // It's similar to WithZone, but small enough to be inlinable.
 506  func (ip Addr) withoutZone() Addr {
 507  	if !ip.Is6() {
 508  		return ip
 509  	}
 510  	ip.z = z6noz
 511  	return ip
 512  }
 513  
 514  // hasZone reports whether ip has an IPv6 zone.
 515  func (ip Addr) hasZone() bool {
 516  	return ip.z != z0 && ip.z != z4 && ip.z != z6noz
 517  }
 518  
 519  // IsLinkLocalUnicast reports whether ip is a link-local unicast address.
 520  func (ip Addr) IsLinkLocalUnicast() bool {
 521  	if ip.Is4In6() {
 522  		ip = ip.Unmap()
 523  	}
 524  
 525  	// Dynamic Configuration of IPv4 Link-Local Addresses
 526  	// https://datatracker.ietf.org/doc/html/rfc3927#section-2.1
 527  	if ip.Is4() {
 528  		return ip.v4(0) == 169 && ip.v4(1) == 254
 529  	}
 530  	// IP Version 6 Addressing Architecture (2.4 Address Type Identification)
 531  	// https://datatracker.ietf.org/doc/html/rfc4291#section-2.4
 532  	if ip.Is6() {
 533  		return ip.v6u16(0)&0xffc0 == 0xfe80
 534  	}
 535  	return false // zero value
 536  }
 537  
 538  // IsLoopback reports whether ip is a loopback address.
 539  func (ip Addr) IsLoopback() bool {
 540  	if ip.Is4In6() {
 541  		ip = ip.Unmap()
 542  	}
 543  
 544  	// Requirements for Internet Hosts -- Communication Layers (3.2.1.3 Addressing)
 545  	// https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.1.3
 546  	if ip.Is4() {
 547  		return ip.v4(0) == 127
 548  	}
 549  	// IP Version 6 Addressing Architecture (2.4 Address Type Identification)
 550  	// https://datatracker.ietf.org/doc/html/rfc4291#section-2.4
 551  	if ip.Is6() {
 552  		return ip.addr.hi == 0 && ip.addr.lo == 1
 553  	}
 554  	return false // zero value
 555  }
 556  
 557  // IsMulticast reports whether ip is a multicast address.
 558  func (ip Addr) IsMulticast() bool {
 559  	if ip.Is4In6() {
 560  		ip = ip.Unmap()
 561  	}
 562  
 563  	// Host Extensions for IP Multicasting (4. HOST GROUP ADDRESSES)
 564  	// https://datatracker.ietf.org/doc/html/rfc1112#section-4
 565  	if ip.Is4() {
 566  		return ip.v4(0)&0xf0 == 0xe0
 567  	}
 568  	// IP Version 6 Addressing Architecture (2.4 Address Type Identification)
 569  	// https://datatracker.ietf.org/doc/html/rfc4291#section-2.4
 570  	if ip.Is6() {
 571  		return ip.addr.hi>>(64-8) == 0xff // ip.v6(0) == 0xff
 572  	}
 573  	return false // zero value
 574  }
 575  
 576  // IsInterfaceLocalMulticast reports whether ip is an IPv6 interface-local
 577  // multicast address.
 578  func (ip Addr) IsInterfaceLocalMulticast() bool {
 579  	// IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses)
 580  	// https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1
 581  	if ip.Is6() && !ip.Is4In6() {
 582  		return ip.v6u16(0)&0xff0f == 0xff01
 583  	}
 584  	return false // zero value
 585  }
 586  
 587  // IsLinkLocalMulticast reports whether ip is a link-local multicast address.
 588  func (ip Addr) IsLinkLocalMulticast() bool {
 589  	if ip.Is4In6() {
 590  		ip = ip.Unmap()
 591  	}
 592  
 593  	// IPv4 Multicast Guidelines (4. Local Network Control Block (224.0.0/24))
 594  	// https://datatracker.ietf.org/doc/html/rfc5771#section-4
 595  	if ip.Is4() {
 596  		return ip.v4(0) == 224 && ip.v4(1) == 0 && ip.v4(2) == 0
 597  	}
 598  	// IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses)
 599  	// https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1
 600  	if ip.Is6() {
 601  		return ip.v6u16(0)&0xff0f == 0xff02
 602  	}
 603  	return false // zero value
 604  }
 605  
 606  // IsGlobalUnicast reports whether ip is a global unicast address.
 607  //
 608  // It returns true for IPv6 addresses which fall outside of the current
 609  // IANA-allocated 2000::/3 global unicast space, with the exception of the
 610  // link-local address space. It also returns true even if ip is in the IPv4
 611  // private address space or IPv6 unique local address space.
 612  // It returns false for the zero [Addr].
 613  //
 614  // For reference, see RFC 1122, RFC 4291, and RFC 4632.
 615  func (ip Addr) IsGlobalUnicast() bool {
 616  	if ip.z == z0 {
 617  		// Invalid or zero-value.
 618  		return false
 619  	}
 620  
 621  	if ip.Is4In6() {
 622  		ip = ip.Unmap()
 623  	}
 624  
 625  	// Match package net's IsGlobalUnicast logic. Notably private IPv4 addresses
 626  	// and ULA IPv6 addresses are still considered "global unicast".
 627  	if ip.Is4() && (ip == IPv4Unspecified() || ip == AddrFrom4([4]byte{255, 255, 255, 255})) {
 628  		return false
 629  	}
 630  
 631  	return ip != IPv6Unspecified() &&
 632  		!ip.IsLoopback() &&
 633  		!ip.IsMulticast() &&
 634  		!ip.IsLinkLocalUnicast()
 635  }
 636  
 637  // IsPrivate reports whether ip is a private address, according to RFC 1918
 638  // (IPv4 addresses) and RFC 4193 (IPv6 addresses). That is, it reports whether
 639  // ip is in 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, or fc00::/7. This is the
 640  // same as [net.IP.IsPrivate].
 641  func (ip Addr) IsPrivate() bool {
 642  	if ip.Is4In6() {
 643  		ip = ip.Unmap()
 644  	}
 645  
 646  	// Match the stdlib's IsPrivate logic.
 647  	if ip.Is4() {
 648  		// RFC 1918 allocates 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 as
 649  		// private IPv4 address subnets.
 650  		return ip.v4(0) == 10 ||
 651  			(ip.v4(0) == 172 && ip.v4(1)&0xf0 == 16) ||
 652  			(ip.v4(0) == 192 && ip.v4(1) == 168)
 653  	}
 654  
 655  	if ip.Is6() {
 656  		// RFC 4193 allocates fc00::/7 as the unique local unicast IPv6 address
 657  		// subnet.
 658  		return ip.v6(0)&0xfe == 0xfc
 659  	}
 660  
 661  	return false // zero value
 662  }
 663  
 664  // IsUnspecified reports whether ip is an unspecified address, either the IPv4
 665  // address "0.0.0.0" or the IPv6 address "::".
 666  //
 667  // Note that the zero [Addr] is not an unspecified address.
 668  func (ip Addr) IsUnspecified() bool {
 669  	return ip == IPv4Unspecified() || ip == IPv6Unspecified()
 670  }
 671  
 672  // Prefix keeps only the top b bits of IP, producing a Prefix
 673  // of the specified length.
 674  // If ip is a zero [Addr], Prefix always returns a zero Prefix and a nil error.
 675  // Otherwise, if bits is less than zero or greater than ip.BitLen(),
 676  // Prefix returns an error.
 677  func (ip Addr) Prefix(b int) (Prefix, error) {
 678  	if b < 0 {
 679  		return Prefix{}, errors.New("negative Prefix bits")
 680  	}
 681  	effectiveBits := b
 682  	switch ip.z {
 683  	case z0:
 684  		return Prefix{}, nil
 685  	case z4:
 686  		if b > 32 {
 687  			return Prefix{}, errors.New("prefix length " + itoa.Itoa(b) + " too large for IPv4")
 688  		}
 689  		effectiveBits += 96
 690  	default:
 691  		if b > 128 {
 692  			return Prefix{}, errors.New("prefix length " + itoa.Itoa(b) + " too large for IPv6")
 693  		}
 694  	}
 695  	ip.addr = ip.addr.and(mask6(effectiveBits))
 696  	return PrefixFrom(ip, b), nil
 697  }
 698  
 699  // As16 returns the IP address in its 16-byte representation.
 700  // IPv4 addresses are returned as IPv4-mapped IPv6 addresses.
 701  // IPv6 addresses with zones are returned without their zone (use the
 702  // [Addr.Zone] method to get it).
 703  // The ip zero value returns all zeroes.
 704  func (ip Addr) As16() (a16 [16]byte) {
 705  	byteorder.BEPutUint64(a16[:8], ip.addr.hi)
 706  	byteorder.BEPutUint64(a16[8:], ip.addr.lo)
 707  	return a16
 708  }
 709  
 710  // As4 returns an IPv4 or IPv4-in-IPv6 address in its 4-byte representation.
 711  // If ip is the zero [Addr] or an IPv6 address, As4 panics.
 712  // Note that 0.0.0.0 is not the zero Addr.
 713  func (ip Addr) As4() (a4 [4]byte) {
 714  	if ip.z == z4 || ip.Is4In6() {
 715  		byteorder.BEPutUint32(a4[:], uint32(ip.addr.lo))
 716  		return a4
 717  	}
 718  	if ip.z == z0 {
 719  		panic("As4 called on IP zero value")
 720  	}
 721  	panic("As4 called on IPv6 address")
 722  }
 723  
 724  // AsSlice returns an IPv4 or IPv6 address in its respective 4-byte or 16-byte representation.
 725  func (ip Addr) AsSlice() []byte {
 726  	switch ip.z {
 727  	case z0:
 728  		return nil
 729  	case z4:
 730  		var ret [4]byte
 731  		byteorder.BEPutUint32(ret[:], uint32(ip.addr.lo))
 732  		return ret[:]
 733  	default:
 734  		var ret [16]byte
 735  		byteorder.BEPutUint64(ret[:8], ip.addr.hi)
 736  		byteorder.BEPutUint64(ret[8:], ip.addr.lo)
 737  		return ret[:]
 738  	}
 739  }
 740  
 741  // Next returns the address following ip.
 742  // If there is none, it returns the zero [Addr].
 743  func (ip Addr) Next() Addr {
 744  	ip.addr = ip.addr.addOne()
 745  	if ip.Is4() {
 746  		if uint32(ip.addr.lo) == 0 {
 747  			// Overflowed.
 748  			return Addr{}
 749  		}
 750  	} else {
 751  		if ip.addr.isZero() {
 752  			// Overflowed
 753  			return Addr{}
 754  		}
 755  	}
 756  	return ip
 757  }
 758  
 759  // Prev returns the IP before ip.
 760  // If there is none, it returns the IP zero value.
 761  func (ip Addr) Prev() Addr {
 762  	if ip.Is4() {
 763  		if uint32(ip.addr.lo) == 0 {
 764  			return Addr{}
 765  		}
 766  	} else if ip.addr.isZero() {
 767  		return Addr{}
 768  	}
 769  	ip.addr = ip.addr.subOne()
 770  	return ip
 771  }
 772  
 773  // String returns the string form of the IP address ip.
 774  // It returns one of 5 forms:
 775  //
 776  //   - "invalid IP", if ip is the zero [Addr]
 777  //   - IPv4 dotted decimal ("192.0.2.1")
 778  //   - IPv6 ("2001:db8::1")
 779  //   - "::ffff:1.2.3.4" (if [Addr.Is4In6])
 780  //   - IPv6 with zone ("fe80:db8::1%eth0")
 781  //
 782  // Note that unlike package net's IP.String method,
 783  // IPv4-mapped IPv6 addresses format with a "::ffff:"
 784  // prefix before the dotted quad.
 785  func (ip Addr) String() string {
 786  	switch ip.z {
 787  	case z0:
 788  		return "invalid IP"
 789  	case z4:
 790  		return ip.string4()
 791  	default:
 792  		if ip.Is4In6() {
 793  			return ip.string4In6()
 794  		}
 795  		return ip.string6()
 796  	}
 797  }
 798  
 799  // AppendTo appends a text encoding of ip,
 800  // as generated by [Addr.MarshalText],
 801  // to b and returns the extended buffer.
 802  func (ip Addr) AppendTo(b []byte) []byte {
 803  	switch ip.z {
 804  	case z0:
 805  		return b
 806  	case z4:
 807  		return ip.appendTo4(b)
 808  	default:
 809  		if ip.Is4In6() {
 810  			return ip.appendTo4In6(b)
 811  		}
 812  		return ip.appendTo6(b)
 813  	}
 814  }
 815  
 816  // digits is a string of the hex digits from 0 to f. It's used in
 817  // appendDecimal and appendHex to format IP addresses.
 818  const digits = "0123456789abcdef"
 819  
 820  // appendDecimal appends the decimal string representation of x to b.
 821  func appendDecimal(b []byte, x uint8) []byte {
 822  	// Using this function rather than strconv.AppendUint makes IPv4
 823  	// string building 2x faster.
 824  
 825  	if x >= 100 {
 826  		b = append(b, digits[x/100])
 827  	}
 828  	if x >= 10 {
 829  		b = append(b, digits[x/10%10])
 830  	}
 831  	return append(b, digits[x%10])
 832  }
 833  
 834  // appendHex appends the hex string representation of x to b.
 835  func appendHex(b []byte, x uint16) []byte {
 836  	// Using this function rather than strconv.AppendUint makes IPv6
 837  	// string building 2x faster.
 838  
 839  	if x >= 0x1000 {
 840  		b = append(b, digits[x>>12])
 841  	}
 842  	if x >= 0x100 {
 843  		b = append(b, digits[x>>8&0xf])
 844  	}
 845  	if x >= 0x10 {
 846  		b = append(b, digits[x>>4&0xf])
 847  	}
 848  	return append(b, digits[x&0xf])
 849  }
 850  
 851  // appendHexPad appends the fully padded hex string representation of x to b.
 852  func appendHexPad(b []byte, x uint16) []byte {
 853  	return append(b, digits[x>>12], digits[x>>8&0xf], digits[x>>4&0xf], digits[x&0xf])
 854  }
 855  
 856  func (ip Addr) string4() string {
 857  	const max = len("255.255.255.255")
 858  	ret := []byte{:0:max}
 859  	ret = ip.appendTo4(ret)
 860  	return string(ret)
 861  }
 862  
 863  func (ip Addr) appendTo4(ret []byte) []byte {
 864  	ret = appendDecimal(ret, ip.v4(0))
 865  	ret = append(ret, '.')
 866  	ret = appendDecimal(ret, ip.v4(1))
 867  	ret = append(ret, '.')
 868  	ret = appendDecimal(ret, ip.v4(2))
 869  	ret = append(ret, '.')
 870  	ret = appendDecimal(ret, ip.v4(3))
 871  	return ret
 872  }
 873  
 874  func (ip Addr) string4In6() string {
 875  	const max = len("::ffff:255.255.255.255%enp5s0")
 876  	ret := []byte{:0:max}
 877  	ret = ip.appendTo4In6(ret)
 878  	return string(ret)
 879  }
 880  
 881  func (ip Addr) appendTo4In6(ret []byte) []byte {
 882  	ret = append(ret, "::ffff:"...)
 883  	ret = ip.Unmap().appendTo4(ret)
 884  	if ip.z != z6noz {
 885  		ret = append(ret, '%')
 886  		ret = append(ret, ip.Zone()...)
 887  	}
 888  	return ret
 889  }
 890  
 891  // string6 formats ip in IPv6 textual representation. It follows the
 892  // guidelines in section 4 of RFC 5952
 893  // (https://tools.ietf.org/html/rfc5952#section-4): no unnecessary
 894  // zeros, use :: to elide the longest run of zeros, and don't use ::
 895  // to compact a single zero field.
 896  func (ip Addr) string6() string {
 897  	// Use a zone with a "plausibly long" name, so that most zone-ful
 898  	// IP addresses won't require additional allocation.
 899  	//
 900  	// The compiler does a cool optimization here, where ret ends up
 901  	// stack-allocated and so the only allocation this function does
 902  	// is to construct the returned string. As such, it's okay to be a
 903  	// bit greedy here, size-wise.
 904  	const max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0")
 905  	ret := []byte{:0:max}
 906  	ret = ip.appendTo6(ret)
 907  	return string(ret)
 908  }
 909  
 910  func (ip Addr) appendTo6(ret []byte) []byte {
 911  	zeroStart, zeroEnd := uint8(255), uint8(255)
 912  	for i := uint8(0); i < 8; i++ {
 913  		j := i
 914  		for j < 8 && ip.v6u16(j) == 0 {
 915  			j++
 916  		}
 917  		if l := j - i; l >= 2 && l > zeroEnd-zeroStart {
 918  			zeroStart, zeroEnd = i, j
 919  		}
 920  	}
 921  
 922  	for i := uint8(0); i < 8; i++ {
 923  		if i == zeroStart {
 924  			ret = append(ret, ':', ':')
 925  			i = zeroEnd
 926  			if i >= 8 {
 927  				break
 928  			}
 929  		} else if i > 0 {
 930  			ret = append(ret, ':')
 931  		}
 932  
 933  		ret = appendHex(ret, ip.v6u16(i))
 934  	}
 935  
 936  	if ip.z != z6noz {
 937  		ret = append(ret, '%')
 938  		ret = append(ret, ip.Zone()...)
 939  	}
 940  	return ret
 941  }
 942  
 943  // StringExpanded is like [Addr.String] but IPv6 addresses are expanded with leading
 944  // zeroes and no "::" compression. For example, "2001:db8::1" becomes
 945  // "2001:0db8:0000:0000:0000:0000:0000:0001".
 946  func (ip Addr) StringExpanded() string {
 947  	switch ip.z {
 948  	case z0, z4:
 949  		return ip.String()
 950  	}
 951  
 952  	const size = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
 953  	ret := []byte{:0:size}
 954  	for i := uint8(0); i < 8; i++ {
 955  		if i > 0 {
 956  			ret = append(ret, ':')
 957  		}
 958  
 959  		ret = appendHexPad(ret, ip.v6u16(i))
 960  	}
 961  
 962  	if ip.z != z6noz {
 963  		// The addition of a zone will cause a second allocation, but when there
 964  		// is no zone the ret slice will be stack allocated.
 965  		ret = append(ret, '%')
 966  		ret = append(ret, ip.Zone()...)
 967  	}
 968  	return string(ret)
 969  }
 970  
 971  // AppendText implements the [encoding.TextAppender] interface,
 972  // It is the same as [Addr.AppendTo].
 973  func (ip Addr) AppendText(b []byte) ([]byte, error) {
 974  	return ip.AppendTo(b), nil
 975  }
 976  
 977  // MarshalText implements the [encoding.TextMarshaler] interface,
 978  // The encoding is the same as returned by [Addr.String], with one exception:
 979  // If ip is the zero [Addr], the encoding is the empty string.
 980  func (ip Addr) MarshalText() ([]byte, error) {
 981  	buf := []byte{}
 982  	switch ip.z {
 983  	case z0:
 984  	case z4:
 985  		const maxCap = len("255.255.255.255")
 986  		buf = []byte{:0:maxCap}
 987  	default:
 988  		if ip.Is4In6() {
 989  			const maxCap = len("::ffff:255.255.255.255%enp5s0")
 990  			buf = []byte{:0:maxCap}
 991  			break
 992  		}
 993  		const maxCap = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0")
 994  		buf = []byte{:0:maxCap}
 995  	}
 996  	return ip.AppendText(buf)
 997  }
 998  
 999  // UnmarshalText implements the encoding.TextUnmarshaler interface.
1000  // The IP address is expected in a form accepted by [ParseAddr].
1001  //
1002  // If text is empty, UnmarshalText sets *ip to the zero [Addr] and
1003  // returns no error.
1004  func (ip *Addr) UnmarshalText(text []byte) error {
1005  	if len(text) == 0 {
1006  		*ip = Addr{}
1007  		return nil
1008  	}
1009  	var err error
1010  	*ip, err = ParseAddr(string(text))
1011  	return err
1012  }
1013  
1014  // AppendBinary implements the [encoding.BinaryAppender] interface.
1015  func (ip Addr) AppendBinary(b []byte) ([]byte, error) {
1016  	switch ip.z {
1017  	case z0:
1018  	case z4:
1019  		b = byteorder.BEAppendUint32(b, uint32(ip.addr.lo))
1020  	default:
1021  		b = byteorder.BEAppendUint64(b, ip.addr.hi)
1022  		b = byteorder.BEAppendUint64(b, ip.addr.lo)
1023  		b = append(b, ip.Zone()...)
1024  	}
1025  	return b, nil
1026  }
1027  
1028  func (ip Addr) marshalBinarySize() int {
1029  	switch ip.z {
1030  	case z0:
1031  		return 0
1032  	case z4:
1033  		return 4
1034  	default:
1035  		return 16 + len(ip.Zone())
1036  	}
1037  }
1038  
1039  // MarshalBinary implements the [encoding.BinaryMarshaler] interface.
1040  // It returns a zero-length slice for the zero [Addr],
1041  // the 4-byte form for an IPv4 address,
1042  // and the 16-byte form with zone appended for an IPv6 address.
1043  func (ip Addr) MarshalBinary() ([]byte, error) {
1044  	return ip.AppendBinary([]byte{:0:ip.marshalBinarySize()})
1045  }
1046  
1047  // UnmarshalBinary implements the [encoding.BinaryUnmarshaler] interface.
1048  // It expects data in the form generated by MarshalBinary.
1049  func (ip *Addr) UnmarshalBinary(b []byte) error {
1050  	n := len(b)
1051  	switch {
1052  	case n == 0:
1053  		*ip = Addr{}
1054  		return nil
1055  	case n == 4:
1056  		*ip = AddrFrom4([4]byte(b))
1057  		return nil
1058  	case n == 16:
1059  		*ip = AddrFrom16([16]byte(b))
1060  		return nil
1061  	case n > 16:
1062  		*ip = AddrFrom16([16]byte(b[:16])).WithZone(string(b[16:]))
1063  		return nil
1064  	}
1065  	return errors.New("unexpected slice size")
1066  }
1067  
1068  // AddrPort is an IP and a port number.
1069  type AddrPort struct {
1070  	ip   Addr
1071  	port uint16
1072  }
1073  
1074  // AddrPortFrom returns an [AddrPort] with the provided IP and port.
1075  // It does not allocate.
1076  func AddrPortFrom(ip Addr, port uint16) AddrPort { return AddrPort{ip: ip, port: port} }
1077  
1078  // Addr returns p's IP address.
1079  func (p AddrPort) Addr() Addr { return p.ip }
1080  
1081  // Port returns p's port.
1082  func (p AddrPort) Port() uint16 { return p.port }
1083  
1084  // splitAddrPort splits s into an IP address string and a port
1085  // string. It splits strings shaped like "foo:bar" or "[foo]:bar",
1086  // without further validating the substrings. v6 indicates whether the
1087  // ip string should parse as an IPv6 address or an IPv4 address, in
1088  // order for s to be a valid ip:port string.
1089  func splitAddrPort(s string) (ip, port string, v6 bool, err error) {
1090  	i := bytealg.LastIndexByteString(s, ':')
1091  	if i == -1 {
1092  		return "", "", false, errors.New("not an ip:port")
1093  	}
1094  
1095  	ip, port = s[:i], s[i+1:]
1096  	if len(ip) == 0 {
1097  		return "", "", false, errors.New("no IP")
1098  	}
1099  	if len(port) == 0 {
1100  		return "", "", false, errors.New("no port")
1101  	}
1102  	if ip[0] == '[' {
1103  		if len(ip) < 2 || ip[len(ip)-1] != ']' {
1104  			return "", "", false, errors.New("missing ]")
1105  		}
1106  		ip = ip[1 : len(ip)-1]
1107  		v6 = true
1108  	}
1109  
1110  	return ip, port, v6, nil
1111  }
1112  
1113  // ParseAddrPort parses s as an [AddrPort].
1114  //
1115  // It doesn't do any name resolution: both the address and the port
1116  // must be numeric.
1117  func ParseAddrPort(s string) (AddrPort, error) {
1118  	var ipp AddrPort
1119  	ip, port, v6, err := splitAddrPort(s)
1120  	if err != nil {
1121  		return ipp, err
1122  	}
1123  	port16, err := strconv.ParseUint(port, 10, 16)
1124  	if err != nil {
1125  		return ipp, errors.New("invalid port " + strconv.Quote(port) + " parsing " + strconv.Quote(s))
1126  	}
1127  	ipp.port = uint16(port16)
1128  	ipp.ip, err = ParseAddr(ip)
1129  	if err != nil {
1130  		return AddrPort{}, err
1131  	}
1132  	if v6 && ipp.ip.Is4() {
1133  		return AddrPort{}, errors.New("invalid ip:port " + strconv.Quote(s) + ", square brackets can only be used with IPv6 addresses")
1134  	} else if !v6 && ipp.ip.Is6() {
1135  		return AddrPort{}, errors.New("invalid ip:port " + strconv.Quote(s) + ", IPv6 addresses must be surrounded by square brackets")
1136  	}
1137  	return ipp, nil
1138  }
1139  
1140  // MustParseAddrPort calls [ParseAddrPort](s) and panics on error.
1141  // It is intended for use in tests with hard-coded strings.
1142  func MustParseAddrPort(s string) AddrPort {
1143  	ip, err := ParseAddrPort(s)
1144  	if err != nil {
1145  		panic(err)
1146  	}
1147  	return ip
1148  }
1149  
1150  // IsValid reports whether p.Addr() is valid.
1151  // All ports are valid, including zero.
1152  func (p AddrPort) IsValid() bool { return p.ip.IsValid() }
1153  
1154  // Compare returns an integer comparing two AddrPorts.
1155  // The result will be 0 if p == p2, -1 if p < p2, and +1 if p > p2.
1156  // AddrPorts sort first by IP address, then port.
1157  func (p AddrPort) Compare(p2 AddrPort) int {
1158  	if c := p.Addr().Compare(p2.Addr()); c != 0 {
1159  		return c
1160  	}
1161  	return cmp.Compare(p.Port(), p2.Port())
1162  }
1163  
1164  func (p AddrPort) String() string {
1165  	var b []byte
1166  	switch p.ip.z {
1167  	case z0:
1168  		return "invalid AddrPort"
1169  	case z4:
1170  		const max = len("255.255.255.255:65535")
1171  		b = []byte{:0:max}
1172  		b = p.ip.appendTo4(b)
1173  	default:
1174  		if p.ip.Is4In6() {
1175  			const max = len("[::ffff:255.255.255.255%enp5s0]:65535")
1176  			b = []byte{:0:max}
1177  			b = append(b, '[')
1178  			b = p.ip.appendTo4In6(b)
1179  		} else {
1180  			const max = len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535")
1181  			b = []byte{:0:max}
1182  			b = append(b, '[')
1183  			b = p.ip.appendTo6(b)
1184  		}
1185  		b = append(b, ']')
1186  	}
1187  	b = append(b, ':')
1188  	b = strconv.AppendUint(b, uint64(p.port), 10)
1189  	return string(b)
1190  }
1191  
1192  // AppendTo appends a text encoding of p,
1193  // as generated by [AddrPort.MarshalText],
1194  // to b and returns the extended buffer.
1195  func (p AddrPort) AppendTo(b []byte) []byte {
1196  	switch p.ip.z {
1197  	case z0:
1198  		return b
1199  	case z4:
1200  		b = p.ip.appendTo4(b)
1201  	default:
1202  		b = append(b, '[')
1203  		if p.ip.Is4In6() {
1204  			b = p.ip.appendTo4In6(b)
1205  		} else {
1206  			b = p.ip.appendTo6(b)
1207  		}
1208  		b = append(b, ']')
1209  	}
1210  	b = append(b, ':')
1211  	b = strconv.AppendUint(b, uint64(p.port), 10)
1212  	return b
1213  }
1214  
1215  // AppendText implements the [encoding.TextAppender] interface. The
1216  // encoding is the same as returned by [AddrPort.AppendTo].
1217  func (p AddrPort) AppendText(b []byte) ([]byte, error) {
1218  	return p.AppendTo(b), nil
1219  }
1220  
1221  // MarshalText implements the [encoding.TextMarshaler] interface. The
1222  // encoding is the same as returned by [AddrPort.String], with one exception: if
1223  // p.Addr() is the zero [Addr], the encoding is the empty string.
1224  func (p AddrPort) MarshalText() ([]byte, error) {
1225  	buf := []byte{}
1226  	switch p.ip.z {
1227  	case z0:
1228  	case z4:
1229  		const maxCap = len("255.255.255.255:65535")
1230  		buf = []byte{:0:maxCap}
1231  	default:
1232  		const maxCap = len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535")
1233  		buf = []byte{:0:maxCap}
1234  	}
1235  	return p.AppendText(buf)
1236  }
1237  
1238  // UnmarshalText implements the encoding.TextUnmarshaler
1239  // interface. The [AddrPort] is expected in a form
1240  // generated by [AddrPort.MarshalText] or accepted by [ParseAddrPort].
1241  func (p *AddrPort) UnmarshalText(text []byte) error {
1242  	if len(text) == 0 {
1243  		*p = AddrPort{}
1244  		return nil
1245  	}
1246  	var err error
1247  	*p, err = ParseAddrPort(string(text))
1248  	return err
1249  }
1250  
1251  // AppendBinary implements the [encoding.BinaryAppendler] interface.
1252  // It returns [Addr.AppendBinary] with an additional two bytes appended
1253  // containing the port in little-endian.
1254  func (p AddrPort) AppendBinary(b []byte) ([]byte, error) {
1255  	b, err := p.Addr().AppendBinary(b)
1256  	if err != nil {
1257  		return nil, err
1258  	}
1259  	return byteorder.LEAppendUint16(b, p.Port()), nil
1260  }
1261  
1262  // MarshalBinary implements the [encoding.BinaryMarshaler] interface.
1263  // It returns [Addr.MarshalBinary] with an additional two bytes appended
1264  // containing the port in little-endian.
1265  func (p AddrPort) MarshalBinary() ([]byte, error) {
1266  	return p.AppendBinary([]byte{:0:p.Addr().marshalBinarySize()+2})
1267  }
1268  
1269  // UnmarshalBinary implements the [encoding.BinaryUnmarshaler] interface.
1270  // It expects data in the form generated by [AddrPort.MarshalBinary].
1271  func (p *AddrPort) UnmarshalBinary(b []byte) error {
1272  	if len(b) < 2 {
1273  		return errors.New("unexpected slice size")
1274  	}
1275  	var addr Addr
1276  	err := addr.UnmarshalBinary(b[:len(b)-2])
1277  	if err != nil {
1278  		return err
1279  	}
1280  	*p = AddrPortFrom(addr, byteorder.LEUint16(b[len(b)-2:]))
1281  	return nil
1282  }
1283  
1284  // Prefix is an IP address prefix (CIDR) representing an IP network.
1285  //
1286  // The first [Prefix.Bits]() of [Addr]() are specified. The remaining bits match any address.
1287  // The range of Bits() is [0,32] for IPv4 or [0,128] for IPv6.
1288  type Prefix struct {
1289  	ip Addr
1290  
1291  	// bitsPlusOne stores the prefix bit length plus one.
1292  	// A Prefix is valid if and only if bitsPlusOne is non-zero.
1293  	bitsPlusOne uint8
1294  }
1295  
1296  // PrefixFrom returns a [Prefix] with the provided IP address and bit
1297  // prefix length.
1298  //
1299  // It does not allocate. Unlike [Addr.Prefix], [PrefixFrom] does not mask
1300  // off the host bits of ip.
1301  //
1302  // If bits is less than zero or greater than ip.BitLen, [Prefix.Bits]
1303  // will return an invalid value -1.
1304  func PrefixFrom(ip Addr, bits int) Prefix {
1305  	var bitsPlusOne uint8
1306  	if !ip.isZero() && bits >= 0 && bits <= ip.BitLen() {
1307  		bitsPlusOne = uint8(bits) + 1
1308  	}
1309  	return Prefix{
1310  		ip:          ip.withoutZone(),
1311  		bitsPlusOne: bitsPlusOne,
1312  	}
1313  }
1314  
1315  // Addr returns p's IP address.
1316  func (p Prefix) Addr() Addr { return p.ip }
1317  
1318  // Bits returns p's prefix length.
1319  //
1320  // It reports -1 if invalid.
1321  func (p Prefix) Bits() int { return int(p.bitsPlusOne) - 1 }
1322  
1323  // IsValid reports whether p.Bits() has a valid range for p.Addr().
1324  // If p.Addr() is the zero [Addr], IsValid returns false.
1325  // Note that if p is the zero [Prefix], then p.IsValid() == false.
1326  func (p Prefix) IsValid() bool { return p.bitsPlusOne > 0 }
1327  
1328  func (p Prefix) isZero() bool { return p == Prefix{} }
1329  
1330  // IsSingleIP reports whether p contains exactly one IP.
1331  func (p Prefix) IsSingleIP() bool { return p.IsValid() && p.Bits() == p.ip.BitLen() }
1332  
1333  // compare returns an integer comparing two prefixes.
1334  // The result will be 0 if p == p2, -1 if p < p2, and +1 if p > p2.
1335  // Prefixes sort first by validity (invalid before valid), then
1336  // address family (IPv4 before IPv6), then prefix length, then
1337  // address.
1338  //
1339  // Unexported for Go 1.22 because we may want to compare by p.Addr first.
1340  // See post-acceptance discussion on go.dev/issue/61642.
1341  func (p Prefix) compare(p2 Prefix) int {
1342  	if c := cmp.Compare(p.Addr().BitLen(), p2.Addr().BitLen()); c != 0 {
1343  		return c
1344  	}
1345  	if c := cmp.Compare(p.Bits(), p2.Bits()); c != 0 {
1346  		return c
1347  	}
1348  	return p.Addr().Compare(p2.Addr())
1349  }
1350  
1351  type parsePrefixError struct {
1352  	in  string // the string given to ParsePrefix
1353  	msg string // an explanation of the parse failure
1354  }
1355  
1356  func (err parsePrefixError) Error() string {
1357  	return "netip.ParsePrefix(" + strconv.Quote(err.in) + "): " + err.msg
1358  }
1359  
1360  // ParsePrefix parses s as an IP address prefix.
1361  // The string can be in the form "192.168.1.0/24" or "2001:db8::/32",
1362  // the CIDR notation defined in RFC 4632 and RFC 4291.
1363  // IPv6 zones are not permitted in prefixes, and an error will be returned if a
1364  // zone is present.
1365  //
1366  // Note that masked address bits are not zeroed. Use Masked for that.
1367  func ParsePrefix(s string) (Prefix, error) {
1368  	i := bytealg.LastIndexByteString(s, '/')
1369  	if i < 0 {
1370  		return Prefix{}, parsePrefixError{in: s, msg: "no '/'"}
1371  	}
1372  	ip, err := ParseAddr(s[:i])
1373  	if err != nil {
1374  		return Prefix{}, parsePrefixError{in: s, msg: err.Error()}
1375  	}
1376  	// IPv6 zones are not allowed: https://go.dev/issue/51899
1377  	if ip.Is6() && ip.z != z6noz {
1378  		return Prefix{}, parsePrefixError{in: s, msg: "IPv6 zones cannot be present in a prefix"}
1379  	}
1380  
1381  	bitsStr := s[i+1:]
1382  
1383  	// strconv.Atoi accepts a leading sign and leading zeroes, but we don't want that.
1384  	if len(bitsStr) > 1 && (bitsStr[0] < '1' || bitsStr[0] > '9') {
1385  		return Prefix{}, parsePrefixError{in: s, msg: "bad bits after slash: " + strconv.Quote(bitsStr)}
1386  	}
1387  
1388  	bits, err := strconv.Atoi(bitsStr)
1389  	if err != nil {
1390  		return Prefix{}, parsePrefixError{in: s, msg: "bad bits after slash: " + strconv.Quote(bitsStr)}
1391  	}
1392  	maxBits := 32
1393  	if ip.Is6() {
1394  		maxBits = 128
1395  	}
1396  	if bits < 0 || bits > maxBits {
1397  		return Prefix{}, parsePrefixError{in: s, msg: "prefix length out of range"}
1398  	}
1399  	return PrefixFrom(ip, bits), nil
1400  }
1401  
1402  // MustParsePrefix calls [ParsePrefix](s) and panics on error.
1403  // It is intended for use in tests with hard-coded strings.
1404  func MustParsePrefix(s string) Prefix {
1405  	ip, err := ParsePrefix(s)
1406  	if err != nil {
1407  		panic(err)
1408  	}
1409  	return ip
1410  }
1411  
1412  // Masked returns p in its canonical form, with all but the high
1413  // p.Bits() bits of p.Addr() masked off.
1414  //
1415  // If p is zero or otherwise invalid, Masked returns the zero [Prefix].
1416  func (p Prefix) Masked() Prefix {
1417  	m, _ := p.ip.Prefix(p.Bits())
1418  	return m
1419  }
1420  
1421  // Contains reports whether the network p includes ip.
1422  //
1423  // An IPv4 address will not match an IPv6 prefix.
1424  // An IPv4-mapped IPv6 address will not match an IPv4 prefix.
1425  // A zero-value IP will not match any prefix.
1426  // If ip has an IPv6 zone, Contains returns false,
1427  // because Prefixes strip zones.
1428  func (p Prefix) Contains(ip Addr) bool {
1429  	if !p.IsValid() || ip.hasZone() {
1430  		return false
1431  	}
1432  	if f1, f2 := p.ip.BitLen(), ip.BitLen(); f1 == 0 || f2 == 0 || f1 != f2 {
1433  		return false
1434  	}
1435  	if ip.Is4() {
1436  		// xor the IP addresses together; mismatched bits are now ones.
1437  		// Shift away the number of bits we don't care about.
1438  		// Shifts in Go are more efficient if the compiler can prove
1439  		// that the shift amount is smaller than the width of the shifted type (64 here).
1440  		// We know that p.bits is in the range 0..32 because p is Valid;
1441  		// the compiler doesn't know that, so mask with 63 to help it.
1442  		// Now truncate to 32 bits, because this is IPv4.
1443  		// If all the bits we care about are equal, the result will be zero.
1444  		return uint32((ip.addr.lo^p.ip.addr.lo)>>((32-p.Bits())&63)) == 0
1445  	} else {
1446  		// xor the IP addresses together.
1447  		// Mask away the bits we don't care about.
1448  		// If all the bits we care about are equal, the result will be zero.
1449  		return ip.addr.xor(p.ip.addr).and(mask6(p.Bits())).isZero()
1450  	}
1451  }
1452  
1453  // Overlaps reports whether p and o contain any IP addresses in common.
1454  //
1455  // If p and o are of different address families or either have a zero
1456  // IP, it reports false. Like the Contains method, a prefix with an
1457  // IPv4-mapped IPv6 address is still treated as an IPv6 mask.
1458  func (p Prefix) Overlaps(o Prefix) bool {
1459  	if !p.IsValid() || !o.IsValid() {
1460  		return false
1461  	}
1462  	if p == o {
1463  		return true
1464  	}
1465  	if p.ip.Is4() != o.ip.Is4() {
1466  		return false
1467  	}
1468  	var minBits int
1469  	if pb, ob := p.Bits(), o.Bits(); pb < ob {
1470  		minBits = pb
1471  	} else {
1472  		minBits = ob
1473  	}
1474  	if minBits == 0 {
1475  		return true
1476  	}
1477  	// One of these Prefix calls might look redundant, but we don't require
1478  	// that p and o values are normalized (via Prefix.Masked) first,
1479  	// so the Prefix call on the one that's already minBits serves to zero
1480  	// out any remaining bits in IP.
1481  	var err error
1482  	if p, err = p.ip.Prefix(minBits); err != nil {
1483  		return false
1484  	}
1485  	if o, err = o.ip.Prefix(minBits); err != nil {
1486  		return false
1487  	}
1488  	return p.ip == o.ip
1489  }
1490  
1491  // AppendTo appends a text encoding of p,
1492  // as generated by [Prefix.MarshalText],
1493  // to b and returns the extended buffer.
1494  func (p Prefix) AppendTo(b []byte) []byte {
1495  	if p.isZero() {
1496  		return b
1497  	}
1498  	if !p.IsValid() {
1499  		return append(b, "invalid Prefix"...)
1500  	}
1501  
1502  	// p.ip is non-nil, because p is valid.
1503  	if p.ip.z == z4 {
1504  		b = p.ip.appendTo4(b)
1505  	} else {
1506  		if p.ip.Is4In6() {
1507  			b = append(b, "::ffff:"...)
1508  			b = p.ip.Unmap().appendTo4(b)
1509  		} else {
1510  			b = p.ip.appendTo6(b)
1511  		}
1512  	}
1513  
1514  	b = append(b, '/')
1515  	b = appendDecimal(b, uint8(p.Bits()))
1516  	return b
1517  }
1518  
1519  // AppendText implements the [encoding.TextAppender] interface.
1520  // It is the same as [Prefix.AppendTo].
1521  func (p Prefix) AppendText(b []byte) ([]byte, error) {
1522  	return p.AppendTo(b), nil
1523  }
1524  
1525  // MarshalText implements the [encoding.TextMarshaler] interface,
1526  // The encoding is the same as returned by [Prefix.String], with one exception:
1527  // If p is the zero value, the encoding is the empty string.
1528  func (p Prefix) MarshalText() ([]byte, error) {
1529  	buf := []byte{}
1530  	switch p.ip.z {
1531  	case z0:
1532  	case z4:
1533  		const maxCap = len("255.255.255.255/32")
1534  		buf = []byte{:0:maxCap}
1535  	default:
1536  		const maxCap = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0/128")
1537  		buf = []byte{:0:maxCap}
1538  	}
1539  	return p.AppendText(buf)
1540  }
1541  
1542  // UnmarshalText implements the encoding.TextUnmarshaler interface.
1543  // The IP address is expected in a form accepted by [ParsePrefix]
1544  // or generated by [Prefix.MarshalText].
1545  func (p *Prefix) UnmarshalText(text []byte) error {
1546  	if len(text) == 0 {
1547  		*p = Prefix{}
1548  		return nil
1549  	}
1550  	var err error
1551  	*p, err = ParsePrefix(string(text))
1552  	return err
1553  }
1554  
1555  // AppendBinary implements the [encoding.AppendMarshaler] interface.
1556  // It returns [Addr.AppendBinary] with an additional byte appended
1557  // containing the prefix bits.
1558  func (p Prefix) AppendBinary(b []byte) ([]byte, error) {
1559  	b, err := p.Addr().withoutZone().AppendBinary(b)
1560  	if err != nil {
1561  		return nil, err
1562  	}
1563  	return append(b, uint8(p.Bits())), nil
1564  }
1565  
1566  // MarshalBinary implements the [encoding.BinaryMarshaler] interface.
1567  // It returns [Addr.MarshalBinary] with an additional byte appended
1568  // containing the prefix bits.
1569  func (p Prefix) MarshalBinary() ([]byte, error) {
1570  	// without the zone the max length is 16, plus an additional byte is 17
1571  	return p.AppendBinary([]byte{:0:p.Addr().withoutZone().marshalBinarySize()+1})
1572  }
1573  
1574  // UnmarshalBinary implements the [encoding.BinaryUnmarshaler] interface.
1575  // It expects data in the form generated by [Prefix.MarshalBinary].
1576  func (p *Prefix) UnmarshalBinary(b []byte) error {
1577  	if len(b) < 1 {
1578  		return errors.New("unexpected slice size")
1579  	}
1580  	var addr Addr
1581  	err := addr.UnmarshalBinary(b[:len(b)-1])
1582  	if err != nil {
1583  		return err
1584  	}
1585  	*p = PrefixFrom(addr, int(b[len(b)-1]))
1586  	return nil
1587  }
1588  
1589  // String returns the CIDR notation of p: "<ip>/<bits>".
1590  func (p Prefix) String() string {
1591  	if !p.IsValid() {
1592  		return "invalid Prefix"
1593  	}
1594  	return p.ip.String() + "/" + itoa.Itoa(p.Bits())
1595  }
1596