|  | // Copyright 2020 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // Package netip defines an IP address type that's a small value type. | 
|  | // Building on that Addr type, the package also defines AddrPort (an | 
|  | // IP address and a port), and Prefix (an IP address and a bit length | 
|  | // prefix). | 
|  | // | 
|  | // Compared to the net.IP type, this package's Addr type takes less | 
|  | // memory, is immutable, and is comparable (supports == and being a | 
|  | // map key). | 
|  | package netip | 
|  |  | 
|  | import ( | 
|  | "errors" | 
|  | "math" | 
|  | "strconv" | 
|  |  | 
|  | "internal/bytealg" | 
|  | "internal/intern" | 
|  | "internal/itoa" | 
|  | ) | 
|  |  | 
|  | // Sizes: (64-bit) | 
|  | //   net.IP:     24 byte slice header + {4, 16} = 28 to 40 bytes | 
|  | //   net.IPAddr: 40 byte slice header + {4, 16} = 44 to 56 bytes + zone length | 
|  | //   netip.Addr: 24 bytes (zone is per-name singleton, shared across all users) | 
|  |  | 
|  | // Addr represents an IPv4 or IPv6 address (with or without a scoped | 
|  | // addressing zone), similar to net.IP or net.IPAddr. | 
|  | // | 
|  | // Unlike net.IP or net.IPAddr, Addr is a comparable value | 
|  | // type (it supports == and can be a map key) and is immutable. | 
|  | // | 
|  | // The zero Addr is not a valid IP address. | 
|  | // Addr{} is distinct from both 0.0.0.0 and ::. | 
|  | type Addr struct { | 
|  | // addr is the hi and lo bits of an IPv6 address. If z==z4, | 
|  | // hi and lo contain the IPv4-mapped IPv6 address. | 
|  | // | 
|  | // hi and lo are constructed by interpreting a 16-byte IPv6 | 
|  | // address as a big-endian 128-bit number. The most significant | 
|  | // bits of that number go into hi, the rest into lo. | 
|  | // | 
|  | // For example, 0011:2233:4455:6677:8899:aabb:ccdd:eeff is stored as: | 
|  | //  addr.hi = 0x0011223344556677 | 
|  | //  addr.lo = 0x8899aabbccddeeff | 
|  | // | 
|  | // We store IPs like this, rather than as [16]byte, because it | 
|  | // turns most operations on IPs into arithmetic and bit-twiddling | 
|  | // operations on 64-bit registers, which is much faster than | 
|  | // bytewise processing. | 
|  | addr uint128 | 
|  |  | 
|  | // z is a combination of the address family and the IPv6 zone. | 
|  | // | 
|  | // nil means invalid IP address (for a zero Addr). | 
|  | // z4 means an IPv4 address. | 
|  | // z6noz means an IPv6 address without a zone. | 
|  | // | 
|  | // Otherwise it's the interned zone name string. | 
|  | z *intern.Value | 
|  | } | 
|  |  | 
|  | // z0, z4, and z6noz are sentinel IP.z values. | 
|  | // See the IP type's field docs. | 
|  | var ( | 
|  | z0    = (*intern.Value)(nil) | 
|  | z4    = new(intern.Value) | 
|  | z6noz = new(intern.Value) | 
|  | ) | 
|  |  | 
|  | // IPv6LinkLocalAllNodes returns the IPv6 link-local all nodes multicast | 
|  | // address ff02::1. | 
|  | func IPv6LinkLocalAllNodes() Addr { return AddrFrom16([16]byte{0: 0xff, 1: 0x02, 15: 0x01}) } | 
|  |  | 
|  | // IPv6Unspecified returns the IPv6 unspecified address "::". | 
|  | func IPv6Unspecified() Addr { return Addr{z: z6noz} } | 
|  |  | 
|  | // IPv4Unspecified returns the IPv4 unspecified address "0.0.0.0". | 
|  | func IPv4Unspecified() Addr { return AddrFrom4([4]byte{}) } | 
|  |  | 
|  | // AddrFrom4 returns the address of the IPv4 address given by the bytes in addr. | 
|  | func AddrFrom4(addr [4]byte) Addr { | 
|  | return Addr{ | 
|  | addr: uint128{0, 0xffff00000000 | uint64(addr[0])<<24 | uint64(addr[1])<<16 | uint64(addr[2])<<8 | uint64(addr[3])}, | 
|  | z:    z4, | 
|  | } | 
|  | } | 
|  |  | 
|  | // AddrFrom16 returns the IPv6 address given by the bytes in addr. | 
|  | // An IPv6-mapped IPv4 address is left as an IPv6 address. | 
|  | // (Use Unmap to convert them if needed.) | 
|  | func AddrFrom16(addr [16]byte) Addr { | 
|  | return Addr{ | 
|  | addr: uint128{ | 
|  | beUint64(addr[:8]), | 
|  | beUint64(addr[8:]), | 
|  | }, | 
|  | z: z6noz, | 
|  | } | 
|  | } | 
|  |  | 
|  | // ipv6Slice is like IPv6Raw, but operates on a 16-byte slice. Assumes | 
|  | // slice is 16 bytes, caller must enforce this. | 
|  | func ipv6Slice(addr []byte) Addr { | 
|  | return Addr{ | 
|  | addr: uint128{ | 
|  | beUint64(addr[:8]), | 
|  | beUint64(addr[8:]), | 
|  | }, | 
|  | z: z6noz, | 
|  | } | 
|  | } | 
|  |  | 
|  | // ParseAddr parses s as an IP address, returning the result. The string | 
|  | // s can be in dotted decimal ("192.0.2.1"), IPv6 ("2001:db8::68"), | 
|  | // or IPv6 with a scoped addressing zone ("fe80::1cc0:3e8c:119f:c2e1%ens18"). | 
|  | func ParseAddr(s string) (Addr, error) { | 
|  | for i := 0; i < len(s); i++ { | 
|  | switch s[i] { | 
|  | case '.': | 
|  | return parseIPv4(s) | 
|  | case ':': | 
|  | return parseIPv6(s) | 
|  | case '%': | 
|  | // Assume that this was trying to be an IPv6 address with | 
|  | // a zone specifier, but the address is missing. | 
|  | return Addr{}, parseAddrError{in: s, msg: "missing IPv6 address"} | 
|  | } | 
|  | } | 
|  | return Addr{}, parseAddrError{in: s, msg: "unable to parse IP"} | 
|  | } | 
|  |  | 
|  | // MustParseAddr calls ParseAddr(s) and panics on error. | 
|  | // It is intended for use in tests with hard-coded strings. | 
|  | func MustParseAddr(s string) Addr { | 
|  | ip, err := ParseAddr(s) | 
|  | if err != nil { | 
|  | panic(err) | 
|  | } | 
|  | return ip | 
|  | } | 
|  |  | 
|  | type parseAddrError struct { | 
|  | in  string // the string given to ParseAddr | 
|  | msg string // an explanation of the parse failure | 
|  | at  string // optionally, the unparsed portion of in at which the error occurred. | 
|  | } | 
|  |  | 
|  | func (err parseAddrError) Error() string { | 
|  | q := strconv.Quote | 
|  | if err.at != "" { | 
|  | return "ParseAddr(" + q(err.in) + "): " + err.msg + " (at " + q(err.at) + ")" | 
|  | } | 
|  | return "ParseAddr(" + q(err.in) + "): " + err.msg | 
|  | } | 
|  |  | 
|  | // parseIPv4 parses s as an IPv4 address (in form "192.168.0.1"). | 
|  | func parseIPv4(s string) (ip Addr, err error) { | 
|  | var fields [4]uint8 | 
|  | var val, pos int | 
|  | var digLen int // number of digits in current octet | 
|  | for i := 0; i < len(s); i++ { | 
|  | if s[i] >= '0' && s[i] <= '9' { | 
|  | if digLen == 1 && val == 0 { | 
|  | return Addr{}, parseAddrError{in: s, msg: "IPv4 field has octet with leading zero"} | 
|  | } | 
|  | val = val*10 + int(s[i]) - '0' | 
|  | digLen++ | 
|  | if val > 255 { | 
|  | return Addr{}, parseAddrError{in: s, msg: "IPv4 field has value >255"} | 
|  | } | 
|  | } else if s[i] == '.' { | 
|  | // .1.2.3 | 
|  | // 1.2.3. | 
|  | // 1..2.3 | 
|  | if i == 0 || i == len(s)-1 || s[i-1] == '.' { | 
|  | return Addr{}, parseAddrError{in: s, msg: "IPv4 field must have at least one digit", at: s[i:]} | 
|  | } | 
|  | // 1.2.3.4.5 | 
|  | if pos == 3 { | 
|  | return Addr{}, parseAddrError{in: s, msg: "IPv4 address too long"} | 
|  | } | 
|  | fields[pos] = uint8(val) | 
|  | pos++ | 
|  | val = 0 | 
|  | digLen = 0 | 
|  | } else { | 
|  | return Addr{}, parseAddrError{in: s, msg: "unexpected character", at: s[i:]} | 
|  | } | 
|  | } | 
|  | if pos < 3 { | 
|  | return Addr{}, parseAddrError{in: s, msg: "IPv4 address too short"} | 
|  | } | 
|  | fields[3] = uint8(val) | 
|  | return AddrFrom4(fields), nil | 
|  | } | 
|  |  | 
|  | // parseIPv6 parses s as an IPv6 address (in form "2001:db8::68"). | 
|  | func parseIPv6(in string) (Addr, error) { | 
|  | s := in | 
|  |  | 
|  | // Split off the zone right from the start. Yes it's a second scan | 
|  | // of the string, but trying to handle it inline makes a bunch of | 
|  | // other inner loop conditionals more expensive, and it ends up | 
|  | // being slower. | 
|  | zone := "" | 
|  | i := bytealg.IndexByteString(s, '%') | 
|  | if i != -1 { | 
|  | s, zone = s[:i], s[i+1:] | 
|  | if zone == "" { | 
|  | // Not allowed to have an empty zone if explicitly specified. | 
|  | return Addr{}, parseAddrError{in: in, msg: "zone must be a non-empty string"} | 
|  | } | 
|  | } | 
|  |  | 
|  | var ip [16]byte | 
|  | ellipsis := -1 // position of ellipsis in ip | 
|  |  | 
|  | // Might have leading ellipsis | 
|  | if len(s) >= 2 && s[0] == ':' && s[1] == ':' { | 
|  | ellipsis = 0 | 
|  | s = s[2:] | 
|  | // Might be only ellipsis | 
|  | if len(s) == 0 { | 
|  | return IPv6Unspecified().WithZone(zone), nil | 
|  | } | 
|  | } | 
|  |  | 
|  | // Loop, parsing hex numbers followed by colon. | 
|  | i = 0 | 
|  | for i < 16 { | 
|  | // Hex number. Similar to parseIPv4, inlining the hex number | 
|  | // parsing yields a significant performance increase. | 
|  | off := 0 | 
|  | acc := uint32(0) | 
|  | for ; off < len(s); off++ { | 
|  | c := s[off] | 
|  | if c >= '0' && c <= '9' { | 
|  | acc = (acc << 4) + uint32(c-'0') | 
|  | } else if c >= 'a' && c <= 'f' { | 
|  | acc = (acc << 4) + uint32(c-'a'+10) | 
|  | } else if c >= 'A' && c <= 'F' { | 
|  | acc = (acc << 4) + uint32(c-'A'+10) | 
|  | } else { | 
|  | break | 
|  | } | 
|  | if acc > math.MaxUint16 { | 
|  | // Overflow, fail. | 
|  | return Addr{}, parseAddrError{in: in, msg: "IPv6 field has value >=2^16", at: s} | 
|  | } | 
|  | } | 
|  | if off == 0 { | 
|  | // No digits found, fail. | 
|  | return Addr{}, parseAddrError{in: in, msg: "each colon-separated field must have at least one digit", at: s} | 
|  | } | 
|  |  | 
|  | // If followed by dot, might be in trailing IPv4. | 
|  | if off < len(s) && s[off] == '.' { | 
|  | if ellipsis < 0 && i != 12 { | 
|  | // Not the right place. | 
|  | return Addr{}, parseAddrError{in: in, msg: "embedded IPv4 address must replace the final 2 fields of the address", at: s} | 
|  | } | 
|  | if i+4 > 16 { | 
|  | // Not enough room. | 
|  | return Addr{}, parseAddrError{in: in, msg: "too many hex fields to fit an embedded IPv4 at the end of the address", at: s} | 
|  | } | 
|  | // TODO: could make this a bit faster by having a helper | 
|  | // that parses to a [4]byte, and have both parseIPv4 and | 
|  | // parseIPv6 use it. | 
|  | ip4, err := parseIPv4(s) | 
|  | if err != nil { | 
|  | return Addr{}, parseAddrError{in: in, msg: err.Error(), at: s} | 
|  | } | 
|  | ip[i] = ip4.v4(0) | 
|  | ip[i+1] = ip4.v4(1) | 
|  | ip[i+2] = ip4.v4(2) | 
|  | ip[i+3] = ip4.v4(3) | 
|  | s = "" | 
|  | i += 4 | 
|  | break | 
|  | } | 
|  |  | 
|  | // Save this 16-bit chunk. | 
|  | ip[i] = byte(acc >> 8) | 
|  | ip[i+1] = byte(acc) | 
|  | i += 2 | 
|  |  | 
|  | // Stop at end of string. | 
|  | s = s[off:] | 
|  | if len(s) == 0 { | 
|  | break | 
|  | } | 
|  |  | 
|  | // Otherwise must be followed by colon and more. | 
|  | if s[0] != ':' { | 
|  | return Addr{}, parseAddrError{in: in, msg: "unexpected character, want colon", at: s} | 
|  | } else if len(s) == 1 { | 
|  | return Addr{}, parseAddrError{in: in, msg: "colon must be followed by more characters", at: s} | 
|  | } | 
|  | s = s[1:] | 
|  |  | 
|  | // Look for ellipsis. | 
|  | if s[0] == ':' { | 
|  | if ellipsis >= 0 { // already have one | 
|  | return Addr{}, parseAddrError{in: in, msg: "multiple :: in address", at: s} | 
|  | } | 
|  | ellipsis = i | 
|  | s = s[1:] | 
|  | if len(s) == 0 { // can be at end | 
|  | break | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Must have used entire string. | 
|  | if len(s) != 0 { | 
|  | return Addr{}, parseAddrError{in: in, msg: "trailing garbage after address", at: s} | 
|  | } | 
|  |  | 
|  | // If didn't parse enough, expand ellipsis. | 
|  | if i < 16 { | 
|  | if ellipsis < 0 { | 
|  | return Addr{}, parseAddrError{in: in, msg: "address string too short"} | 
|  | } | 
|  | n := 16 - i | 
|  | for j := i - 1; j >= ellipsis; j-- { | 
|  | ip[j+n] = ip[j] | 
|  | } | 
|  | for j := ellipsis + n - 1; j >= ellipsis; j-- { | 
|  | ip[j] = 0 | 
|  | } | 
|  | } else if ellipsis >= 0 { | 
|  | // Ellipsis must represent at least one 0 group. | 
|  | return Addr{}, parseAddrError{in: in, msg: "the :: must expand to at least one field of zeros"} | 
|  | } | 
|  | return AddrFrom16(ip).WithZone(zone), nil | 
|  | } | 
|  |  | 
|  | // AddrFromSlice parses the 4- or 16-byte byte slice as an IPv4 or IPv6 address. | 
|  | // Note that a net.IP can be passed directly as the []byte argument. | 
|  | // If slice's length is not 4 or 16, AddrFromSlice returns Addr{}, false. | 
|  | func AddrFromSlice(slice []byte) (ip Addr, ok bool) { | 
|  | switch len(slice) { | 
|  | case 4: | 
|  | return AddrFrom4(*(*[4]byte)(slice)), true | 
|  | case 16: | 
|  | return ipv6Slice(slice), true | 
|  | } | 
|  | return Addr{}, false | 
|  | } | 
|  |  | 
|  | // v4 returns the i'th byte of ip. If ip is not an IPv4, v4 returns | 
|  | // unspecified garbage. | 
|  | func (ip Addr) v4(i uint8) uint8 { | 
|  | return uint8(ip.addr.lo >> ((3 - i) * 8)) | 
|  | } | 
|  |  | 
|  | // v6 returns the i'th byte of ip. If ip is an IPv4 address, this | 
|  | // accesses the IPv4-mapped IPv6 address form of the IP. | 
|  | func (ip Addr) v6(i uint8) uint8 { | 
|  | return uint8(*(ip.addr.halves()[(i/8)%2]) >> ((7 - i%8) * 8)) | 
|  | } | 
|  |  | 
|  | // v6u16 returns the i'th 16-bit word of ip. If ip is an IPv4 address, | 
|  | // this accesses the IPv4-mapped IPv6 address form of the IP. | 
|  | func (ip Addr) v6u16(i uint8) uint16 { | 
|  | return uint16(*(ip.addr.halves()[(i/4)%2]) >> ((3 - i%4) * 16)) | 
|  | } | 
|  |  | 
|  | // isZero reports whether ip is the zero value of the IP type. | 
|  | // The zero value is not a valid IP address of any type. | 
|  | // | 
|  | // Note that "0.0.0.0" and "::" are not the zero value. Use IsUnspecified to | 
|  | // check for these values instead. | 
|  | func (ip Addr) isZero() bool { | 
|  | // Faster than comparing ip == Addr{}, but effectively equivalent, | 
|  | // as there's no way to make an IP with a nil z from this package. | 
|  | return ip.z == z0 | 
|  | } | 
|  |  | 
|  | // IsValid reports whether the Addr is an initialized address (not the zero Addr). | 
|  | // | 
|  | // Note that "0.0.0.0" and "::" are both valid values. | 
|  | func (ip Addr) IsValid() bool { return ip.z != z0 } | 
|  |  | 
|  | // BitLen returns the number of bits in the IP address: | 
|  | // 128 for IPv6, 32 for IPv4, and 0 for the zero Addr. | 
|  | // | 
|  | // Note that IPv4-mapped IPv6 addresses are considered IPv6 addresses | 
|  | // and therefore have bit length 128. | 
|  | func (ip Addr) BitLen() int { | 
|  | switch ip.z { | 
|  | case z0: | 
|  | return 0 | 
|  | case z4: | 
|  | return 32 | 
|  | } | 
|  | return 128 | 
|  | } | 
|  |  | 
|  | // Zone returns ip's IPv6 scoped addressing zone, if any. | 
|  | func (ip Addr) Zone() string { | 
|  | if ip.z == nil { | 
|  | return "" | 
|  | } | 
|  | zone, _ := ip.z.Get().(string) | 
|  | return zone | 
|  | } | 
|  |  | 
|  | // Compare returns an integer comparing two IPs. | 
|  | // The result will be 0 if ip == ip2, -1 if ip < ip2, and +1 if ip > ip2. | 
|  | // The definition of "less than" is the same as the Less method. | 
|  | func (ip Addr) Compare(ip2 Addr) int { | 
|  | f1, f2 := ip.BitLen(), ip2.BitLen() | 
|  | if f1 < f2 { | 
|  | return -1 | 
|  | } | 
|  | if f1 > f2 { | 
|  | return 1 | 
|  | } | 
|  | hi1, hi2 := ip.addr.hi, ip2.addr.hi | 
|  | if hi1 < hi2 { | 
|  | return -1 | 
|  | } | 
|  | if hi1 > hi2 { | 
|  | return 1 | 
|  | } | 
|  | lo1, lo2 := ip.addr.lo, ip2.addr.lo | 
|  | if lo1 < lo2 { | 
|  | return -1 | 
|  | } | 
|  | if lo1 > lo2 { | 
|  | return 1 | 
|  | } | 
|  | if ip.Is6() { | 
|  | za, zb := ip.Zone(), ip2.Zone() | 
|  | if za < zb { | 
|  | return -1 | 
|  | } | 
|  | if za > zb { | 
|  | return 1 | 
|  | } | 
|  | } | 
|  | return 0 | 
|  | } | 
|  |  | 
|  | // Less reports whether ip sorts before ip2. | 
|  | // IP addresses sort first by length, then their address. | 
|  | // IPv6 addresses with zones sort just after the same address without a zone. | 
|  | func (ip Addr) Less(ip2 Addr) bool { return ip.Compare(ip2) == -1 } | 
|  |  | 
|  | func (ip Addr) lessOrEq(ip2 Addr) bool { return ip.Compare(ip2) <= 0 } | 
|  |  | 
|  | // Is4 reports whether ip is an IPv4 address. | 
|  | // | 
|  | // It returns false for IP4-mapped IPv6 addresses. See IP.Unmap. | 
|  | func (ip Addr) Is4() bool { | 
|  | return ip.z == z4 | 
|  | } | 
|  |  | 
|  | // Is4In6 reports whether ip is an IPv4-mapped IPv6 address. | 
|  | func (ip Addr) Is4In6() bool { | 
|  | return ip.Is6() && ip.addr.hi == 0 && ip.addr.lo>>32 == 0xffff | 
|  | } | 
|  |  | 
|  | // Is6 reports whether ip is an IPv6 address, including IPv4-mapped | 
|  | // IPv6 addresses. | 
|  | func (ip Addr) Is6() bool { | 
|  | return ip.z != z0 && ip.z != z4 | 
|  | } | 
|  |  | 
|  | // Unmap returns ip with any IPv4-mapped IPv6 address prefix removed. | 
|  | // | 
|  | // That is, if ip is an IPv6 address wrapping an IPv4 adddress, it | 
|  | // returns the wrapped IPv4 address. Otherwise it returns ip unmodified. | 
|  | func (ip Addr) Unmap() Addr { | 
|  | if ip.Is4In6() { | 
|  | ip.z = z4 | 
|  | } | 
|  | return ip | 
|  | } | 
|  |  | 
|  | // WithZone returns an IP that's the same as ip but with the provided | 
|  | // zone. If zone is empty, the zone is removed. If ip is an IPv4 | 
|  | // address, WithZone is a no-op and returns ip unchanged. | 
|  | func (ip Addr) WithZone(zone string) Addr { | 
|  | if !ip.Is6() { | 
|  | return ip | 
|  | } | 
|  | if zone == "" { | 
|  | ip.z = z6noz | 
|  | return ip | 
|  | } | 
|  | ip.z = intern.GetByString(zone) | 
|  | return ip | 
|  | } | 
|  |  | 
|  | // withoutZone unconditionally strips the zone from IP. | 
|  | // It's similar to WithZone, but small enough to be inlinable. | 
|  | func (ip Addr) withoutZone() Addr { | 
|  | if !ip.Is6() { | 
|  | return ip | 
|  | } | 
|  | ip.z = z6noz | 
|  | return ip | 
|  | } | 
|  |  | 
|  | // hasZone reports whether IP has an IPv6 zone. | 
|  | func (ip Addr) hasZone() bool { | 
|  | return ip.z != z0 && ip.z != z4 && ip.z != z6noz | 
|  | } | 
|  |  | 
|  | // IsLinkLocalUnicast reports whether ip is a link-local unicast address. | 
|  | func (ip Addr) IsLinkLocalUnicast() bool { | 
|  | // Dynamic Configuration of IPv4 Link-Local Addresses | 
|  | // https://datatracker.ietf.org/doc/html/rfc3927#section-2.1 | 
|  | if ip.Is4() { | 
|  | return ip.v4(0) == 169 && ip.v4(1) == 254 | 
|  | } | 
|  | // IP Version 6 Addressing Architecture (2.4 Address Type Identification) | 
|  | // https://datatracker.ietf.org/doc/html/rfc4291#section-2.4 | 
|  | if ip.Is6() { | 
|  | return ip.v6u16(0)&0xffc0 == 0xfe80 | 
|  | } | 
|  | return false // zero value | 
|  | } | 
|  |  | 
|  | // IsLoopback reports whether ip is a loopback address. | 
|  | func (ip Addr) IsLoopback() bool { | 
|  | // Requirements for Internet Hosts -- Communication Layers (3.2.1.3 Addressing) | 
|  | // https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.1.3 | 
|  | if ip.Is4() { | 
|  | return ip.v4(0) == 127 | 
|  | } | 
|  | // IP Version 6 Addressing Architecture (2.4 Address Type Identification) | 
|  | // https://datatracker.ietf.org/doc/html/rfc4291#section-2.4 | 
|  | if ip.Is6() { | 
|  | return ip.addr.hi == 0 && ip.addr.lo == 1 | 
|  | } | 
|  | return false // zero value | 
|  | } | 
|  |  | 
|  | // IsMulticast reports whether ip is a multicast address. | 
|  | func (ip Addr) IsMulticast() bool { | 
|  | // Host Extensions for IP Multicasting (4. HOST GROUP ADDRESSES) | 
|  | // https://datatracker.ietf.org/doc/html/rfc1112#section-4 | 
|  | if ip.Is4() { | 
|  | return ip.v4(0)&0xf0 == 0xe0 | 
|  | } | 
|  | // IP Version 6 Addressing Architecture (2.4 Address Type Identification) | 
|  | // https://datatracker.ietf.org/doc/html/rfc4291#section-2.4 | 
|  | if ip.Is6() { | 
|  | return ip.addr.hi>>(64-8) == 0xff // ip.v6(0) == 0xff | 
|  | } | 
|  | return false // zero value | 
|  | } | 
|  |  | 
|  | // IsInterfaceLocalMulticast reports whether ip is an IPv6 interface-local | 
|  | // multicast address. | 
|  | func (ip Addr) IsInterfaceLocalMulticast() bool { | 
|  | // IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses) | 
|  | // https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1 | 
|  | if ip.Is6() { | 
|  | return ip.v6u16(0)&0xff0f == 0xff01 | 
|  | } | 
|  | return false // zero value | 
|  | } | 
|  |  | 
|  | // IsLinkLocalMulticast reports whether ip is a link-local multicast address. | 
|  | func (ip Addr) IsLinkLocalMulticast() bool { | 
|  | // IPv4 Multicast Guidelines (4. Local Network Control Block (224.0.0/24)) | 
|  | // https://datatracker.ietf.org/doc/html/rfc5771#section-4 | 
|  | if ip.Is4() { | 
|  | return ip.v4(0) == 224 && ip.v4(1) == 0 && ip.v4(2) == 0 | 
|  | } | 
|  | // IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses) | 
|  | // https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1 | 
|  | if ip.Is6() { | 
|  | return ip.v6u16(0)&0xff0f == 0xff02 | 
|  | } | 
|  | return false // zero value | 
|  | } | 
|  |  | 
|  | // IsGlobalUnicast reports whether ip is a global unicast address. | 
|  | // | 
|  | // It returns true for IPv6 addresses which fall outside of the current | 
|  | // IANA-allocated 2000::/3 global unicast space, with the exception of the | 
|  | // link-local address space. It also returns true even if ip is in the IPv4 | 
|  | // private address space or IPv6 unique local address space. | 
|  | // It returns false for the zero Addr. | 
|  | // | 
|  | // For reference, see RFC 1122, RFC 4291, and RFC 4632. | 
|  | func (ip Addr) IsGlobalUnicast() bool { | 
|  | if ip.z == z0 { | 
|  | // Invalid or zero-value. | 
|  | return false | 
|  | } | 
|  |  | 
|  | // Match package net's IsGlobalUnicast logic. Notably private IPv4 addresses | 
|  | // and ULA IPv6 addresses are still considered "global unicast". | 
|  | if ip.Is4() && (ip == IPv4Unspecified() || ip == AddrFrom4([4]byte{255, 255, 255, 255})) { | 
|  | return false | 
|  | } | 
|  |  | 
|  | return ip != IPv6Unspecified() && | 
|  | !ip.IsLoopback() && | 
|  | !ip.IsMulticast() && | 
|  | !ip.IsLinkLocalUnicast() | 
|  | } | 
|  |  | 
|  | // IsPrivate reports whether ip is a private address, according to RFC 1918 | 
|  | // (IPv4 addresses) and RFC 4193 (IPv6 addresses). That is, it reports whether | 
|  | // ip is in 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, or fc00::/7. This is the | 
|  | // same as net.IP.IsPrivate. | 
|  | func (ip Addr) IsPrivate() bool { | 
|  | // Match the stdlib's IsPrivate logic. | 
|  | if ip.Is4() { | 
|  | // RFC 1918 allocates 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 as | 
|  | // private IPv4 address subnets. | 
|  | return ip.v4(0) == 10 || | 
|  | (ip.v4(0) == 172 && ip.v4(1)&0xf0 == 16) || | 
|  | (ip.v4(0) == 192 && ip.v4(1) == 168) | 
|  | } | 
|  |  | 
|  | if ip.Is6() { | 
|  | // RFC 4193 allocates fc00::/7 as the unique local unicast IPv6 address | 
|  | // subnet. | 
|  | return ip.v6(0)&0xfe == 0xfc | 
|  | } | 
|  |  | 
|  | return false // zero value | 
|  | } | 
|  |  | 
|  | // IsUnspecified reports whether ip is an unspecified address, either the IPv4 | 
|  | // address "0.0.0.0" or the IPv6 address "::". | 
|  | // | 
|  | // Note that the zero Addr is not an unspecified address. | 
|  | func (ip Addr) IsUnspecified() bool { | 
|  | return ip == IPv4Unspecified() || ip == IPv6Unspecified() | 
|  | } | 
|  |  | 
|  | // Prefix keeps only the top b bits of IP, producing a Prefix | 
|  | // of the specified length. | 
|  | // If ip is a zero Addr, Prefix always returns a zero Prefix and a nil error. | 
|  | // Otherwise, if bits is less than zero or greater than ip.BitLen(), | 
|  | // Prefix returns an error. | 
|  | func (ip Addr) Prefix(b int) (Prefix, error) { | 
|  | if b < 0 { | 
|  | return Prefix{}, errors.New("negative Prefix bits") | 
|  | } | 
|  | effectiveBits := b | 
|  | switch ip.z { | 
|  | case z0: | 
|  | return Prefix{}, nil | 
|  | case z4: | 
|  | if b > 32 { | 
|  | return Prefix{}, errors.New("prefix length " + itoa.Itoa(b) + " too large for IPv4") | 
|  | } | 
|  | effectiveBits += 96 | 
|  | default: | 
|  | if b > 128 { | 
|  | return Prefix{}, errors.New("prefix length " + itoa.Itoa(b) + " too large for IPv6") | 
|  | } | 
|  | } | 
|  | ip.addr = ip.addr.and(mask6(effectiveBits)) | 
|  | return PrefixFrom(ip, b), nil | 
|  | } | 
|  |  | 
|  | const ( | 
|  | netIPv4len = 4 | 
|  | netIPv6len = 16 | 
|  | ) | 
|  |  | 
|  | // As16 returns the IP address in its 16-byte representation. | 
|  | // IPv4 addresses are returned in their v6-mapped form. | 
|  | // IPv6 addresses with zones are returned without their zone (use the | 
|  | // Zone method to get it). | 
|  | // The ip zero value returns all zeroes. | 
|  | func (ip Addr) As16() (a16 [16]byte) { | 
|  | bePutUint64(a16[:8], ip.addr.hi) | 
|  | bePutUint64(a16[8:], ip.addr.lo) | 
|  | return a16 | 
|  | } | 
|  |  | 
|  | // As4 returns an IPv4 or IPv4-in-IPv6 address in its 4-byte representation. | 
|  | // If ip is the zero Addr or an IPv6 address, As4 panics. | 
|  | // Note that 0.0.0.0 is not the zero Addr. | 
|  | func (ip Addr) As4() (a4 [4]byte) { | 
|  | if ip.z == z4 || ip.Is4In6() { | 
|  | bePutUint32(a4[:], uint32(ip.addr.lo)) | 
|  | return a4 | 
|  | } | 
|  | if ip.z == z0 { | 
|  | panic("As4 called on IP zero value") | 
|  | } | 
|  | panic("As4 called on IPv6 address") | 
|  | } | 
|  |  | 
|  | // AsSlice returns an IPv4 or IPv6 address in its respective 4-byte or 16-byte representation. | 
|  | func (ip Addr) AsSlice() []byte { | 
|  | switch ip.z { | 
|  | case z0: | 
|  | return nil | 
|  | case z4: | 
|  | var ret [4]byte | 
|  | bePutUint32(ret[:], uint32(ip.addr.lo)) | 
|  | return ret[:] | 
|  | default: | 
|  | var ret [16]byte | 
|  | bePutUint64(ret[:8], ip.addr.hi) | 
|  | bePutUint64(ret[8:], ip.addr.lo) | 
|  | return ret[:] | 
|  | } | 
|  | } | 
|  |  | 
|  | // Next returns the address following ip. | 
|  | // If there is none, it returns the zero Addr. | 
|  | func (ip Addr) Next() Addr { | 
|  | ip.addr = ip.addr.addOne() | 
|  | if ip.Is4() { | 
|  | if uint32(ip.addr.lo) == 0 { | 
|  | // Overflowed. | 
|  | return Addr{} | 
|  | } | 
|  | } else { | 
|  | if ip.addr.isZero() { | 
|  | // Overflowed | 
|  | return Addr{} | 
|  | } | 
|  | } | 
|  | return ip | 
|  | } | 
|  |  | 
|  | // Prev returns the IP before ip. | 
|  | // If there is none, it returns the IP zero value. | 
|  | func (ip Addr) Prev() Addr { | 
|  | if ip.Is4() { | 
|  | if uint32(ip.addr.lo) == 0 { | 
|  | return Addr{} | 
|  | } | 
|  | } else if ip.addr.isZero() { | 
|  | return Addr{} | 
|  | } | 
|  | ip.addr = ip.addr.subOne() | 
|  | return ip | 
|  | } | 
|  |  | 
|  | // String returns the string form of the IP address ip. | 
|  | // It returns one of 5 forms: | 
|  | // | 
|  | //   - "invalid IP", if ip is the zero Addr | 
|  | //   - IPv4 dotted decimal ("192.0.2.1") | 
|  | //   - IPv6 ("2001:db8::1") | 
|  | //   - "::ffff:1.2.3.4" (if Is4In6) | 
|  | //   - IPv6 with zone ("fe80:db8::1%eth0") | 
|  | // | 
|  | // Note that unlike package net's IP.String method, | 
|  | // IP4-mapped IPv6 addresses format with a "::ffff:" | 
|  | // prefix before the dotted quad. | 
|  | func (ip Addr) String() string { | 
|  | switch ip.z { | 
|  | case z0: | 
|  | return "invalid IP" | 
|  | case z4: | 
|  | return ip.string4() | 
|  | default: | 
|  | if ip.Is4In6() { | 
|  | // TODO(bradfitz): this could alloc less. | 
|  | if z := ip.Zone(); z != "" { | 
|  | return "::ffff:" + ip.Unmap().String() + "%" + z | 
|  | } else { | 
|  | return "::ffff:" + ip.Unmap().String() | 
|  | } | 
|  | } | 
|  | return ip.string6() | 
|  | } | 
|  | } | 
|  |  | 
|  | // AppendTo appends a text encoding of ip, | 
|  | // as generated by MarshalText, | 
|  | // to b and returns the extended buffer. | 
|  | func (ip Addr) AppendTo(b []byte) []byte { | 
|  | switch ip.z { | 
|  | case z0: | 
|  | return b | 
|  | case z4: | 
|  | return ip.appendTo4(b) | 
|  | default: | 
|  | if ip.Is4In6() { | 
|  | b = append(b, "::ffff:"...) | 
|  | b = ip.Unmap().appendTo4(b) | 
|  | if z := ip.Zone(); z != "" { | 
|  | b = append(b, '%') | 
|  | b = append(b, z...) | 
|  | } | 
|  | return b | 
|  | } | 
|  | return ip.appendTo6(b) | 
|  | } | 
|  | } | 
|  |  | 
|  | // digits is a string of the hex digits from 0 to f. It's used in | 
|  | // appendDecimal and appendHex to format IP addresses. | 
|  | const digits = "0123456789abcdef" | 
|  |  | 
|  | // appendDecimal appends the decimal string representation of x to b. | 
|  | func appendDecimal(b []byte, x uint8) []byte { | 
|  | // Using this function rather than strconv.AppendUint makes IPv4 | 
|  | // string building 2x faster. | 
|  |  | 
|  | if x >= 100 { | 
|  | b = append(b, digits[x/100]) | 
|  | } | 
|  | if x >= 10 { | 
|  | b = append(b, digits[x/10%10]) | 
|  | } | 
|  | return append(b, digits[x%10]) | 
|  | } | 
|  |  | 
|  | // appendHex appends the hex string representation of x to b. | 
|  | func appendHex(b []byte, x uint16) []byte { | 
|  | // Using this function rather than strconv.AppendUint makes IPv6 | 
|  | // string building 2x faster. | 
|  |  | 
|  | if x >= 0x1000 { | 
|  | b = append(b, digits[x>>12]) | 
|  | } | 
|  | if x >= 0x100 { | 
|  | b = append(b, digits[x>>8&0xf]) | 
|  | } | 
|  | if x >= 0x10 { | 
|  | b = append(b, digits[x>>4&0xf]) | 
|  | } | 
|  | return append(b, digits[x&0xf]) | 
|  | } | 
|  |  | 
|  | // appendHexPad appends the fully padded hex string representation of x to b. | 
|  | func appendHexPad(b []byte, x uint16) []byte { | 
|  | return append(b, digits[x>>12], digits[x>>8&0xf], digits[x>>4&0xf], digits[x&0xf]) | 
|  | } | 
|  |  | 
|  | func (ip Addr) string4() string { | 
|  | const max = len("255.255.255.255") | 
|  | ret := make([]byte, 0, max) | 
|  | ret = ip.appendTo4(ret) | 
|  | return string(ret) | 
|  | } | 
|  |  | 
|  | func (ip Addr) appendTo4(ret []byte) []byte { | 
|  | ret = appendDecimal(ret, ip.v4(0)) | 
|  | ret = append(ret, '.') | 
|  | ret = appendDecimal(ret, ip.v4(1)) | 
|  | ret = append(ret, '.') | 
|  | ret = appendDecimal(ret, ip.v4(2)) | 
|  | ret = append(ret, '.') | 
|  | ret = appendDecimal(ret, ip.v4(3)) | 
|  | return ret | 
|  | } | 
|  |  | 
|  | // string6 formats ip in IPv6 textual representation. It follows the | 
|  | // guidelines in section 4 of RFC 5952 | 
|  | // (https://tools.ietf.org/html/rfc5952#section-4): no unnecessary | 
|  | // zeros, use :: to elide the longest run of zeros, and don't use :: | 
|  | // to compact a single zero field. | 
|  | func (ip Addr) string6() string { | 
|  | // Use a zone with a "plausibly long" name, so that most zone-ful | 
|  | // IP addresses won't require additional allocation. | 
|  | // | 
|  | // The compiler does a cool optimization here, where ret ends up | 
|  | // stack-allocated and so the only allocation this function does | 
|  | // is to construct the returned string. As such, it's okay to be a | 
|  | // bit greedy here, size-wise. | 
|  | const max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0") | 
|  | ret := make([]byte, 0, max) | 
|  | ret = ip.appendTo6(ret) | 
|  | return string(ret) | 
|  | } | 
|  |  | 
|  | func (ip Addr) appendTo6(ret []byte) []byte { | 
|  | zeroStart, zeroEnd := uint8(255), uint8(255) | 
|  | for i := uint8(0); i < 8; i++ { | 
|  | j := i | 
|  | for j < 8 && ip.v6u16(j) == 0 { | 
|  | j++ | 
|  | } | 
|  | if l := j - i; l >= 2 && l > zeroEnd-zeroStart { | 
|  | zeroStart, zeroEnd = i, j | 
|  | } | 
|  | } | 
|  |  | 
|  | for i := uint8(0); i < 8; i++ { | 
|  | if i == zeroStart { | 
|  | ret = append(ret, ':', ':') | 
|  | i = zeroEnd | 
|  | if i >= 8 { | 
|  | break | 
|  | } | 
|  | } else if i > 0 { | 
|  | ret = append(ret, ':') | 
|  | } | 
|  |  | 
|  | ret = appendHex(ret, ip.v6u16(i)) | 
|  | } | 
|  |  | 
|  | if ip.z != z6noz { | 
|  | ret = append(ret, '%') | 
|  | ret = append(ret, ip.Zone()...) | 
|  | } | 
|  | return ret | 
|  | } | 
|  |  | 
|  | // StringExpanded is like String but IPv6 addresses are expanded with leading | 
|  | // zeroes and no "::" compression. For example, "2001:db8::1" becomes | 
|  | // "2001:0db8:0000:0000:0000:0000:0000:0001". | 
|  | func (ip Addr) StringExpanded() string { | 
|  | switch ip.z { | 
|  | case z0, z4: | 
|  | return ip.String() | 
|  | } | 
|  |  | 
|  | const size = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") | 
|  | ret := make([]byte, 0, size) | 
|  | for i := uint8(0); i < 8; i++ { | 
|  | if i > 0 { | 
|  | ret = append(ret, ':') | 
|  | } | 
|  |  | 
|  | ret = appendHexPad(ret, ip.v6u16(i)) | 
|  | } | 
|  |  | 
|  | if ip.z != z6noz { | 
|  | // The addition of a zone will cause a second allocation, but when there | 
|  | // is no zone the ret slice will be stack allocated. | 
|  | ret = append(ret, '%') | 
|  | ret = append(ret, ip.Zone()...) | 
|  | } | 
|  | return string(ret) | 
|  | } | 
|  |  | 
|  | // MarshalText implements the encoding.TextMarshaler interface, | 
|  | // The encoding is the same as returned by String, with one exception: | 
|  | // If ip is the zero Addr, the encoding is the empty string. | 
|  | func (ip Addr) MarshalText() ([]byte, error) { | 
|  | switch ip.z { | 
|  | case z0: | 
|  | return []byte(""), nil | 
|  | case z4: | 
|  | max := len("255.255.255.255") | 
|  | b := make([]byte, 0, max) | 
|  | return ip.appendTo4(b), nil | 
|  | default: | 
|  | max := len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0") | 
|  | b := make([]byte, 0, max) | 
|  | if ip.Is4In6() { | 
|  | b = append(b, "::ffff:"...) | 
|  | b = ip.Unmap().appendTo4(b) | 
|  | if z := ip.Zone(); z != "" { | 
|  | b = append(b, '%') | 
|  | b = append(b, z...) | 
|  | } | 
|  | return b, nil | 
|  | } | 
|  | return ip.appendTo6(b), nil | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | // UnmarshalText implements the encoding.TextUnmarshaler interface. | 
|  | // The IP address is expected in a form accepted by ParseAddr. | 
|  | // | 
|  | // If text is empty, UnmarshalText sets *ip to the zero Addr and | 
|  | // returns no error. | 
|  | func (ip *Addr) UnmarshalText(text []byte) error { | 
|  | if len(text) == 0 { | 
|  | *ip = Addr{} | 
|  | return nil | 
|  | } | 
|  | var err error | 
|  | *ip, err = ParseAddr(string(text)) | 
|  | return err | 
|  | } | 
|  |  | 
|  | func (ip Addr) marshalBinaryWithTrailingBytes(trailingBytes int) []byte { | 
|  | var b []byte | 
|  | switch ip.z { | 
|  | case z0: | 
|  | b = make([]byte, trailingBytes) | 
|  | case z4: | 
|  | b = make([]byte, 4+trailingBytes) | 
|  | bePutUint32(b, uint32(ip.addr.lo)) | 
|  | default: | 
|  | z := ip.Zone() | 
|  | b = make([]byte, 16+len(z)+trailingBytes) | 
|  | bePutUint64(b[:8], ip.addr.hi) | 
|  | bePutUint64(b[8:], ip.addr.lo) | 
|  | copy(b[16:], z) | 
|  | } | 
|  | return b | 
|  | } | 
|  |  | 
|  | // MarshalBinary implements the encoding.BinaryMarshaler interface. | 
|  | // It returns a zero-length slice for the zero Addr, | 
|  | // the 4-byte form for an IPv4 address, | 
|  | // and the 16-byte form with zone appended for an IPv6 address. | 
|  | func (ip Addr) MarshalBinary() ([]byte, error) { | 
|  | return ip.marshalBinaryWithTrailingBytes(0), nil | 
|  | } | 
|  |  | 
|  | // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. | 
|  | // It expects data in the form generated by MarshalBinary. | 
|  | func (ip *Addr) UnmarshalBinary(b []byte) error { | 
|  | n := len(b) | 
|  | switch { | 
|  | case n == 0: | 
|  | *ip = Addr{} | 
|  | return nil | 
|  | case n == 4: | 
|  | *ip = AddrFrom4(*(*[4]byte)(b)) | 
|  | return nil | 
|  | case n == 16: | 
|  | *ip = ipv6Slice(b) | 
|  | return nil | 
|  | case n > 16: | 
|  | *ip = ipv6Slice(b[:16]).WithZone(string(b[16:])) | 
|  | return nil | 
|  | } | 
|  | return errors.New("unexpected slice size") | 
|  | } | 
|  |  | 
|  | // AddrPort is an IP and a port number. | 
|  | type AddrPort struct { | 
|  | ip   Addr | 
|  | port uint16 | 
|  | } | 
|  |  | 
|  | // AddrPortFrom returns an AddrPort with the provided IP and port. | 
|  | // It does not allocate. | 
|  | func AddrPortFrom(ip Addr, port uint16) AddrPort { return AddrPort{ip: ip, port: port} } | 
|  |  | 
|  | // Addr returns p's IP address. | 
|  | func (p AddrPort) Addr() Addr { return p.ip } | 
|  |  | 
|  | // Port returns p's port. | 
|  | func (p AddrPort) Port() uint16 { return p.port } | 
|  |  | 
|  | // splitAddrPort splits s into an IP address string and a port | 
|  | // string. It splits strings shaped like "foo:bar" or "[foo]:bar", | 
|  | // without further validating the substrings. v6 indicates whether the | 
|  | // ip string should parse as an IPv6 address or an IPv4 address, in | 
|  | // order for s to be a valid ip:port string. | 
|  | func splitAddrPort(s string) (ip, port string, v6 bool, err error) { | 
|  | i := stringsLastIndexByte(s, ':') | 
|  | if i == -1 { | 
|  | return "", "", false, errors.New("not an ip:port") | 
|  | } | 
|  |  | 
|  | ip, port = s[:i], s[i+1:] | 
|  | if len(ip) == 0 { | 
|  | return "", "", false, errors.New("no IP") | 
|  | } | 
|  | if len(port) == 0 { | 
|  | return "", "", false, errors.New("no port") | 
|  | } | 
|  | if ip[0] == '[' { | 
|  | if len(ip) < 2 || ip[len(ip)-1] != ']' { | 
|  | return "", "", false, errors.New("missing ]") | 
|  | } | 
|  | ip = ip[1 : len(ip)-1] | 
|  | v6 = true | 
|  | } | 
|  |  | 
|  | return ip, port, v6, nil | 
|  | } | 
|  |  | 
|  | // ParseAddrPort parses s as an AddrPort. | 
|  | // | 
|  | // It doesn't do any name resolution: both the address and the port | 
|  | // must be numeric. | 
|  | func ParseAddrPort(s string) (AddrPort, error) { | 
|  | var ipp AddrPort | 
|  | ip, port, v6, err := splitAddrPort(s) | 
|  | if err != nil { | 
|  | return ipp, err | 
|  | } | 
|  | port16, err := strconv.ParseUint(port, 10, 16) | 
|  | if err != nil { | 
|  | return ipp, errors.New("invalid port " + strconv.Quote(port) + " parsing " + strconv.Quote(s)) | 
|  | } | 
|  | ipp.port = uint16(port16) | 
|  | ipp.ip, err = ParseAddr(ip) | 
|  | if err != nil { | 
|  | return AddrPort{}, err | 
|  | } | 
|  | if v6 && ipp.ip.Is4() { | 
|  | return AddrPort{}, errors.New("invalid ip:port " + strconv.Quote(s) + ", square brackets can only be used with IPv6 addresses") | 
|  | } else if !v6 && ipp.ip.Is6() { | 
|  | return AddrPort{}, errors.New("invalid ip:port " + strconv.Quote(s) + ", IPv6 addresses must be surrounded by square brackets") | 
|  | } | 
|  | return ipp, nil | 
|  | } | 
|  |  | 
|  | // MustParseAddrPort calls ParseAddrPort(s) and panics on error. | 
|  | // It is intended for use in tests with hard-coded strings. | 
|  | func MustParseAddrPort(s string) AddrPort { | 
|  | ip, err := ParseAddrPort(s) | 
|  | if err != nil { | 
|  | panic(err) | 
|  | } | 
|  | return ip | 
|  | } | 
|  |  | 
|  | // isZero reports whether p is the zero AddrPort. | 
|  | func (p AddrPort) isZero() bool { return p == AddrPort{} } | 
|  |  | 
|  | // IsValid reports whether p.IP() is valid. | 
|  | // All ports are valid, including zero. | 
|  | func (p AddrPort) IsValid() bool { return p.ip.IsValid() } | 
|  |  | 
|  | func (p AddrPort) String() string { | 
|  | switch p.ip.z { | 
|  | case z0: | 
|  | return "invalid AddrPort" | 
|  | case z4: | 
|  | a := p.ip.As4() | 
|  | buf := make([]byte, 0, 21) | 
|  | for i := range a { | 
|  | buf = strconv.AppendUint(buf, uint64(a[i]), 10) | 
|  | buf = append(buf, "...:"[i]) | 
|  | } | 
|  | buf = strconv.AppendUint(buf, uint64(p.port), 10) | 
|  | return string(buf) | 
|  | default: | 
|  | // TODO: this could be more efficient allocation-wise: | 
|  | return joinHostPort(p.ip.String(), itoa.Itoa(int(p.port))) | 
|  | } | 
|  | } | 
|  |  | 
|  | func joinHostPort(host, port string) string { | 
|  | // We assume that host is a literal IPv6 address if host has | 
|  | // colons. | 
|  | if bytealg.IndexByteString(host, ':') >= 0 { | 
|  | return "[" + host + "]:" + port | 
|  | } | 
|  | return host + ":" + port | 
|  | } | 
|  |  | 
|  | // AppendTo appends a text encoding of p, | 
|  | // as generated by MarshalText, | 
|  | // to b and returns the extended buffer. | 
|  | func (p AddrPort) AppendTo(b []byte) []byte { | 
|  | switch p.ip.z { | 
|  | case z0: | 
|  | return b | 
|  | case z4: | 
|  | b = p.ip.appendTo4(b) | 
|  | default: | 
|  | if p.ip.Is4In6() { | 
|  | b = append(b, "[::ffff:"...) | 
|  | b = p.ip.Unmap().appendTo4(b) | 
|  | if z := p.ip.Zone(); z != "" { | 
|  | b = append(b, '%') | 
|  | b = append(b, z...) | 
|  | } | 
|  | } else { | 
|  | b = append(b, '[') | 
|  | b = p.ip.appendTo6(b) | 
|  | } | 
|  | b = append(b, ']') | 
|  | } | 
|  | b = append(b, ':') | 
|  | b = strconv.AppendInt(b, int64(p.port), 10) | 
|  | return b | 
|  | } | 
|  |  | 
|  | // MarshalText implements the encoding.TextMarshaler interface. The | 
|  | // encoding is the same as returned by String, with one exception: if | 
|  | // p.Addr() is the zero Addr, the encoding is the empty string. | 
|  | func (p AddrPort) MarshalText() ([]byte, error) { | 
|  | var max int | 
|  | switch p.ip.z { | 
|  | case z0: | 
|  | case z4: | 
|  | max = len("255.255.255.255:65535") | 
|  | default: | 
|  | max = len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535") | 
|  | } | 
|  | b := make([]byte, 0, max) | 
|  | b = p.AppendTo(b) | 
|  | return b, nil | 
|  | } | 
|  |  | 
|  | // UnmarshalText implements the encoding.TextUnmarshaler | 
|  | // interface. The AddrPort is expected in a form | 
|  | // generated by MarshalText or accepted by ParseAddrPort. | 
|  | func (p *AddrPort) UnmarshalText(text []byte) error { | 
|  | if len(text) == 0 { | 
|  | *p = AddrPort{} | 
|  | return nil | 
|  | } | 
|  | var err error | 
|  | *p, err = ParseAddrPort(string(text)) | 
|  | return err | 
|  | } | 
|  |  | 
|  | // MarshalBinary implements the encoding.BinaryMarshaler interface. | 
|  | // It returns Addr.MarshalBinary with an additional two bytes appended | 
|  | // containing the port in little-endian. | 
|  | func (p AddrPort) MarshalBinary() ([]byte, error) { | 
|  | b := p.Addr().marshalBinaryWithTrailingBytes(2) | 
|  | lePutUint16(b[len(b)-2:], p.Port()) | 
|  | return b, nil | 
|  | } | 
|  |  | 
|  | // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. | 
|  | // It expects data in the form generated by MarshalBinary. | 
|  | func (p *AddrPort) UnmarshalBinary(b []byte) error { | 
|  | if len(b) < 2 { | 
|  | return errors.New("unexpected slice size") | 
|  | } | 
|  | var addr Addr | 
|  | err := addr.UnmarshalBinary(b[:len(b)-2]) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | *p = AddrPortFrom(addr, leUint16(b[len(b)-2:])) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // Prefix is an IP address prefix (CIDR) representing an IP network. | 
|  | // | 
|  | // The first Bits() of Addr() are specified. The remaining bits match any address. | 
|  | // The range of Bits() is [0,32] for IPv4 or [0,128] for IPv6. | 
|  | type Prefix struct { | 
|  | ip Addr | 
|  |  | 
|  | // bits is logically a uint8 (storing [0,128]) but also | 
|  | // encodes an "invalid" bit, currently represented by the | 
|  | // invalidPrefixBits sentinel value. It could be packed into | 
|  | // the uint8 more with more complicated expressions in the | 
|  | // accessors, but the extra byte (in padding anyway) doesn't | 
|  | // hurt and simplifies code below. | 
|  | bits int16 | 
|  | } | 
|  |  | 
|  | // invalidPrefixBits is the Prefix.bits value used when PrefixFrom is | 
|  | // outside the range of a uint8. It's returned as the int -1 in the | 
|  | // public API. | 
|  | const invalidPrefixBits = -1 | 
|  |  | 
|  | // PrefixFrom returns a Prefix with the provided IP address and bit | 
|  | // prefix length. | 
|  | // | 
|  | // It does not allocate. Unlike Addr.Prefix, PrefixFrom does not mask | 
|  | // off the host bits of ip. | 
|  | // | 
|  | // If bits is less than zero or greater than ip.BitLen, Prefix.Bits | 
|  | // will return an invalid value -1. | 
|  | func PrefixFrom(ip Addr, bits int) Prefix { | 
|  | if bits < 0 || bits > ip.BitLen() { | 
|  | bits = invalidPrefixBits | 
|  | } | 
|  | b16 := int16(bits) | 
|  | return Prefix{ | 
|  | ip:   ip.withoutZone(), | 
|  | bits: b16, | 
|  | } | 
|  | } | 
|  |  | 
|  | // Addr returns p's IP address. | 
|  | func (p Prefix) Addr() Addr { return p.ip } | 
|  |  | 
|  | // Bits returns p's prefix length. | 
|  | // | 
|  | // It reports -1 if invalid. | 
|  | func (p Prefix) Bits() int { return int(p.bits) } | 
|  |  | 
|  | // IsValid reports whether p.Bits() has a valid range for p.IP(). | 
|  | // If p.Addr() is the zero Addr, IsValid returns false. | 
|  | // Note that if p is the zero Prefix, then p.IsValid() == false. | 
|  | func (p Prefix) IsValid() bool { return !p.ip.isZero() && p.bits >= 0 && int(p.bits) <= p.ip.BitLen() } | 
|  |  | 
|  | func (p Prefix) isZero() bool { return p == Prefix{} } | 
|  |  | 
|  | // IsSingleIP reports whether p contains exactly one IP. | 
|  | func (p Prefix) IsSingleIP() bool { return p.bits != 0 && int(p.bits) == p.ip.BitLen() } | 
|  |  | 
|  | // ParsePrefix parses s as an IP address prefix. | 
|  | // The string can be in the form "192.168.1.0/24" or "2001:db8::/32", | 
|  | // the CIDR notation defined in RFC 4632 and RFC 4291. | 
|  | // | 
|  | // Note that masked address bits are not zeroed. Use Masked for that. | 
|  | func ParsePrefix(s string) (Prefix, error) { | 
|  | i := stringsLastIndexByte(s, '/') | 
|  | if i < 0 { | 
|  | return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): no '/'") | 
|  | } | 
|  | ip, err := ParseAddr(s[:i]) | 
|  | if err != nil { | 
|  | return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): " + err.Error()) | 
|  | } | 
|  | bitsStr := s[i+1:] | 
|  | bits, err := strconv.Atoi(bitsStr) | 
|  | if err != nil { | 
|  | return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + ": bad bits after slash: " + strconv.Quote(bitsStr)) | 
|  | } | 
|  | maxBits := 32 | 
|  | if ip.Is6() { | 
|  | maxBits = 128 | 
|  | } | 
|  | if bits < 0 || bits > maxBits { | 
|  | return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + ": prefix length out of range") | 
|  | } | 
|  | return PrefixFrom(ip, bits), nil | 
|  | } | 
|  |  | 
|  | // MustParsePrefix calls ParsePrefix(s) and panics on error. | 
|  | // It is intended for use in tests with hard-coded strings. | 
|  | func MustParsePrefix(s string) Prefix { | 
|  | ip, err := ParsePrefix(s) | 
|  | if err != nil { | 
|  | panic(err) | 
|  | } | 
|  | return ip | 
|  | } | 
|  |  | 
|  | // Masked returns p in its canonical form, with all but the high | 
|  | // p.Bits() bits of p.Addr() masked off. | 
|  | // | 
|  | // If p is zero or otherwise invalid, Masked returns the zero Prefix. | 
|  | func (p Prefix) Masked() Prefix { | 
|  | if m, err := p.ip.Prefix(int(p.bits)); err == nil { | 
|  | return m | 
|  | } | 
|  | return Prefix{} | 
|  | } | 
|  |  | 
|  | // Contains reports whether the network p includes ip. | 
|  | // | 
|  | // An IPv4 address will not match an IPv6 prefix. | 
|  | // A v6-mapped IPv6 address will not match an IPv4 prefix. | 
|  | // A zero-value IP will not match any prefix. | 
|  | // If ip has an IPv6 zone, Contains returns false, | 
|  | // because Prefixes strip zones. | 
|  | func (p Prefix) Contains(ip Addr) bool { | 
|  | if !p.IsValid() || ip.hasZone() { | 
|  | return false | 
|  | } | 
|  | if f1, f2 := p.ip.BitLen(), ip.BitLen(); f1 == 0 || f2 == 0 || f1 != f2 { | 
|  | return false | 
|  | } | 
|  | if ip.Is4() { | 
|  | // xor the IP addresses together; mismatched bits are now ones. | 
|  | // Shift away the number of bits we don't care about. | 
|  | // Shifts in Go are more efficient if the compiler can prove | 
|  | // that the shift amount is smaller than the width of the shifted type (64 here). | 
|  | // We know that p.bits is in the range 0..32 because p is Valid; | 
|  | // the compiler doesn't know that, so mask with 63 to help it. | 
|  | // Now truncate to 32 bits, because this is IPv4. | 
|  | // If all the bits we care about are equal, the result will be zero. | 
|  | return uint32((ip.addr.lo^p.ip.addr.lo)>>((32-p.bits)&63)) == 0 | 
|  | } else { | 
|  | // xor the IP addresses together. | 
|  | // Mask away the bits we don't care about. | 
|  | // If all the bits we care about are equal, the result will be zero. | 
|  | return ip.addr.xor(p.ip.addr).and(mask6(int(p.bits))).isZero() | 
|  | } | 
|  | } | 
|  |  | 
|  | // Overlaps reports whether p and o contain any IP addresses in common. | 
|  | // | 
|  | // If p and o are of different address families or either have a zero | 
|  | // IP, it reports false. Like the Contains method, a prefix with a | 
|  | // v6-mapped IPv4 IP is still treated as an IPv6 mask. | 
|  | func (p Prefix) Overlaps(o Prefix) bool { | 
|  | if !p.IsValid() || !o.IsValid() { | 
|  | return false | 
|  | } | 
|  | if p == o { | 
|  | return true | 
|  | } | 
|  | if p.ip.Is4() != o.ip.Is4() { | 
|  | return false | 
|  | } | 
|  | var minBits int16 | 
|  | if p.bits < o.bits { | 
|  | minBits = p.bits | 
|  | } else { | 
|  | minBits = o.bits | 
|  | } | 
|  | if minBits == 0 { | 
|  | return true | 
|  | } | 
|  | // One of these Prefix calls might look redundant, but we don't require | 
|  | // that p and o values are normalized (via Prefix.Masked) first, | 
|  | // so the Prefix call on the one that's already minBits serves to zero | 
|  | // out any remaining bits in IP. | 
|  | var err error | 
|  | if p, err = p.ip.Prefix(int(minBits)); err != nil { | 
|  | return false | 
|  | } | 
|  | if o, err = o.ip.Prefix(int(minBits)); err != nil { | 
|  | return false | 
|  | } | 
|  | return p.ip == o.ip | 
|  | } | 
|  |  | 
|  | // AppendTo appends a text encoding of p, | 
|  | // as generated by MarshalText, | 
|  | // to b and returns the extended buffer. | 
|  | func (p Prefix) AppendTo(b []byte) []byte { | 
|  | if p.isZero() { | 
|  | return b | 
|  | } | 
|  | if !p.IsValid() { | 
|  | return append(b, "invalid Prefix"...) | 
|  | } | 
|  |  | 
|  | // p.ip is non-nil, because p is valid. | 
|  | if p.ip.z == z4 { | 
|  | b = p.ip.appendTo4(b) | 
|  | } else { | 
|  | if p.ip.Is4In6() { | 
|  | b = append(b, "::ffff:"...) | 
|  | b = p.ip.Unmap().appendTo4(b) | 
|  | } else { | 
|  | b = p.ip.appendTo6(b) | 
|  | } | 
|  | } | 
|  |  | 
|  | b = append(b, '/') | 
|  | b = appendDecimal(b, uint8(p.bits)) | 
|  | return b | 
|  | } | 
|  |  | 
|  | // MarshalText implements the encoding.TextMarshaler interface, | 
|  | // The encoding is the same as returned by String, with one exception: | 
|  | // If p is the zero value, the encoding is the empty string. | 
|  | func (p Prefix) MarshalText() ([]byte, error) { | 
|  | var max int | 
|  | switch p.ip.z { | 
|  | case z0: | 
|  | case z4: | 
|  | max = len("255.255.255.255/32") | 
|  | default: | 
|  | max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0/128") | 
|  | } | 
|  | b := make([]byte, 0, max) | 
|  | b = p.AppendTo(b) | 
|  | return b, nil | 
|  | } | 
|  |  | 
|  | // UnmarshalText implements the encoding.TextUnmarshaler interface. | 
|  | // The IP address is expected in a form accepted by ParsePrefix | 
|  | // or generated by MarshalText. | 
|  | func (p *Prefix) UnmarshalText(text []byte) error { | 
|  | if len(text) == 0 { | 
|  | *p = Prefix{} | 
|  | return nil | 
|  | } | 
|  | var err error | 
|  | *p, err = ParsePrefix(string(text)) | 
|  | return err | 
|  | } | 
|  |  | 
|  | // MarshalBinary implements the encoding.BinaryMarshaler interface. | 
|  | // It returns Addr.MarshalBinary with an additional byte appended | 
|  | // containing the prefix bits. | 
|  | func (p Prefix) MarshalBinary() ([]byte, error) { | 
|  | b := p.Addr().withoutZone().marshalBinaryWithTrailingBytes(1) | 
|  | b[len(b)-1] = uint8(p.Bits()) | 
|  | return b, nil | 
|  | } | 
|  |  | 
|  | // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. | 
|  | // It expects data in the form generated by MarshalBinary. | 
|  | func (p *Prefix) UnmarshalBinary(b []byte) error { | 
|  | if len(b) < 1 { | 
|  | return errors.New("unexpected slice size") | 
|  | } | 
|  | var addr Addr | 
|  | err := addr.UnmarshalBinary(b[:len(b)-1]) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | *p = PrefixFrom(addr, int(b[len(b)-1])) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // String returns the CIDR notation of p: "<ip>/<bits>". | 
|  | func (p Prefix) String() string { | 
|  | if !p.IsValid() { | 
|  | return "invalid Prefix" | 
|  | } | 
|  | return p.ip.String() + "/" + itoa.Itoa(int(p.bits)) | 
|  | } |