| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919 |
- // Copyright 2020 The Inet.Af 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 netaddr contains a IP address type that's in many ways
- // better than the Go standard library's net.IP type. Building on that
- // IP type, the package also contains IPPrefix, IPPort, IPRange, and
- // IPSet types.
- //
- // Notably, this package's IP type takes less memory, is immutable,
- // comparable (supports == and being a map key), and more. See
- // https://github.com/inetaf/netaddr for background.
- //
- // IPv6 Zones
- //
- // IP and IPPort are the only types in this package that support IPv6
- // zones. Other types silently drop any passed-in zones.
- package netaddr // import "inet.af/netaddr"
- import (
- "encoding/binary"
- "errors"
- "fmt"
- "math"
- "net"
- "sort"
- "strconv"
- "strings"
- "go4.org/intern"
- )
- // 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
- // netaddr.IP: 24 bytes (zone is per-name singleton, shared across all users)
- // IP represents an IPv4 or IPv6 address (with or without a scoped
- // addressing zone), similar to Go's net.IP or net.IPAddr.
- //
- // Unlike net.IP or net.IPAddr, the netaddr.IP is a comparable value
- // type (it supports == and can be a map key) and is immutable.
- // Its memory representation is 24 bytes on 64-bit machines (the same
- // size as a Go slice header) for both IPv4 and IPv6 address.
- type IP struct {
- // addr are 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 the IP zero value).
- // 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() IP { return IPv6Raw([16]byte{0: 0xff, 1: 0x02, 15: 0x01}) }
- // IPv6Unspecified returns the IPv6 unspecified address ::.
- func IPv6Unspecified() IP { return IP{z: z6noz} }
- // IPv4 returns the IP of the IPv4 address a.b.c.d.
- func IPv4(a, b, c, d uint8) IP {
- return IP{
- addr: uint128{0, 0xffff00000000 | uint64(a)<<24 | uint64(b)<<16 | uint64(c)<<8 | uint64(d)},
- z: z4,
- }
- }
- // IPv6Raw returns the IPv6 address given by the bytes in addr,
- // without an implicit Unmap call to unmap any v6-mapped IPv4
- // address.
- func IPv6Raw(addr [16]byte) IP {
- return IP{
- addr: uint128{
- binary.BigEndian.Uint64(addr[:8]),
- binary.BigEndian.Uint64(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) IP {
- return IP{
- addr: uint128{
- binary.BigEndian.Uint64(addr[:8]),
- binary.BigEndian.Uint64(addr[8:]),
- },
- z: z6noz,
- }
- }
- // IPFrom16 returns the IP address given by the bytes in addr,
- // unmapping any v6-mapped IPv4 address.
- //
- // It is equivalent to calling IPv6Raw(addr).Unmap().
- func IPFrom16(addr [16]byte) IP {
- return IPv6Raw(addr).Unmap()
- }
- // IPFrom4 returns the IPv4 address given by the bytes in addr.
- // It is equivalent to calling IPv4(addr[0], addr[1], addr[2], addr[3]).
- func IPFrom4(addr [4]byte) IP {
- return IPv4(addr[0], addr[1], addr[2], addr[3])
- }
- // ParseIP 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 ParseIP(s string) (IP, 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 IP{}, parseIPError{in: s, msg: "missing IPv6 address"}
- }
- }
- return IP{}, parseIPError{in: s, msg: "unable to parse IP"}
- }
- // MustParseIP calls ParseIP(s) and panics on error.
- // It is intended for use in tests with hard-coded strings.
- func MustParseIP(s string) IP {
- ip, err := ParseIP(s)
- if err != nil {
- panic(err)
- }
- return ip
- }
- type parseIPError struct {
- in string // the string given to ParseIP
- msg string // an explanation of the parse failure
- at string // optionally, the unparsed portion of in at which the error occurred.
- }
- func (err parseIPError) Error() string {
- if err.at != "" {
- return fmt.Sprintf("ParseIP(%q): %s (at %q)", err.in, err.msg, err.at)
- }
- return fmt.Sprintf("ParseIP(%q): %s", err.in, err.msg)
- }
- // parseIPv4 parses s as an IPv4 address (in form "192.168.0.1").
- func parseIPv4(s string) (ip IP, err error) {
- var fields [3]uint8
- var val, pos int
- for i := 0; i < len(s); i++ {
- if s[i] >= '0' && s[i] <= '9' {
- val = val*10 + int(s[i]) - '0'
- if val > 255 {
- return IP{}, parseIPError{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 IP{}, parseIPError{in: s, msg: "IPv4 field must have at least one digit", at: s[i:]}
- }
- // 1.2.3.4.5
- if pos == 3 {
- return IP{}, parseIPError{in: s, msg: "IPv4 address too long"}
- }
- fields[pos] = uint8(val)
- pos++
- val = 0
- } else {
- return IP{}, parseIPError{in: s, msg: "unexpected character", at: s[i:]}
- }
- }
- if pos < 3 {
- return IP{}, parseIPError{in: s, msg: "IPv4 address too short"}
- }
- return IPv4(fields[0], fields[1], fields[2], uint8(val)), nil
- }
- // parseIPv6 parses s as an IPv6 address (in form "2001:db8::68").
- func parseIPv6(in string) (IP, 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 := strings.IndexByte(s, '%')
- if i != -1 {
- s, zone = s[:i], s[i+1:]
- if zone == "" {
- // Not allowed to have an empty zone if explicitly specified.
- return IP{}, parseIPError{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 IP{}, parseIPError{in: in, msg: "IPv6 field has value >=2^16", at: s}
- }
- }
- if off == 0 {
- // No digits found, fail.
- return IP{}, parseIPError{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 IP{}, parseIPError{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 IP{}, parseIPError{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 IP{}, parseIPError{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 IP{}, parseIPError{in: in, msg: "unexpected character, want colon", at: s}
- } else if len(s) == 1 {
- return IP{}, parseIPError{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 IP{}, parseIPError{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 IP{}, parseIPError{in: in, msg: "trailing garbage after address", at: s}
- }
- // If didn't parse enough, expand ellipsis.
- if i < 16 {
- if ellipsis < 0 {
- return IP{}, parseIPError{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 IP{}, parseIPError{in: in, msg: "the :: must expand to at least one field of zeros"}
- }
- return IPv6Raw(ip).WithZone(zone), nil
- }
- // FromStdIP returns an IP from the standard library's IP type.
- //
- // If std is invalid, ok is false.
- //
- // FromStdIP implicitly unmaps IPv6-mapped IPv4 addresses. That is, if
- // len(std) == 16 and contains an IPv4 address, only the IPv4 part is
- // returned, without the IPv6 wrapper. This is the common form returned by
- // the standard library's ParseIP: https://play.golang.org/p/qdjylUkKWxl.
- // To convert a standard library IP without the implicit unmapping, use
- // FromStdIPRaw.
- func FromStdIP(std net.IP) (ip IP, ok bool) {
- ret, ok := FromStdIPRaw(std)
- if ret.Is4in6() {
- ret.z = z4
- }
- return ret, ok
- }
- // FromStdIPRaw returns an IP from the standard library's IP type.
- // If std is invalid, ok is false.
- // Unlike FromStdIP, FromStdIPRaw does not do an implicit Unmap if
- // len(std) == 16 and contains an IPv6-mapped IPv4 address.
- func FromStdIPRaw(std net.IP) (ip IP, ok bool) {
- switch len(std) {
- case 4:
- return IPv4(std[0], std[1], std[2], std[3]), true
- case 16:
- return ipv6Slice(std), true
- }
- return IP{}, false
- }
- // v4 returns the i'th byte of ip. If ip is not an IPv4, v4 returns
- // unspecified garbage.
- func (ip IP) 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 IP) 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 IP) 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 IP) IsZero() bool {
- // Faster than comparing ip == IP{}, but effectively equivalent,
- // as there's no way to make an IP with a nil z from this package.
- return ip.z == z0
- }
- // IsValid whether the IP is an initialized value and not the IP
- // type's zero value.
- //
- // Note that both "0.0.0.0" and "::" are valid, non-zero values.
- func (ip IP) IsValid() bool { return ip.z != z0 }
- // BitLen returns the number of bits in the IP address:
- // 32 for IPv4 or 128 for IPv6.
- // For the zero value (see IP.IsZero), it returns 0.
- // For IP4-mapped IPv6 addresses, it returns 128.
- func (ip IP) BitLen() uint8 {
- 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 IP) 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 IP.Less method.
- func (ip IP) Compare(ip2 IP) int {
- f1, f2 := ip.BitLen(), ip2.BitLen()
- if f1 < f2 {
- return -1
- }
- if f1 > f2 {
- return 1
- }
- if hi1, hi2 := ip.addr.hi, ip2.addr.hi; hi1 < hi2 {
- return -1
- } else if hi1 > hi2 {
- return 1
- }
- if lo1, lo2 := ip.addr.lo, ip2.addr.lo; lo1 < lo2 {
- return -1
- } else if lo1 > lo2 {
- return 1
- }
- if ip.Is6() {
- za, zb := ip.Zone(), ip2.Zone()
- if za < zb {
- return -1
- } else 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 IP) Less(ip2 IP) bool { return ip.Compare(ip2) == -1 }
- func (ip IP) lessOrEq(ip2 IP) bool { return ip.Compare(ip2) <= 0 }
- // ipZone returns the standard library net.IP from ip, as well
- // as the zone.
- // The optional reuse IP provides memory to reuse.
- func (ip IP) ipZone(reuse net.IP) (stdIP net.IP, zone string) {
- base := reuse[:0]
- switch {
- case ip.z == z0:
- return nil, ""
- case ip.Is4():
- a4 := ip.As4()
- return append(base, a4[:]...), ""
- default:
- a16 := ip.As16()
- return append(base, a16[:]...), ip.Zone()
- }
- }
- // IPAddr returns the net.IPAddr representation of an IP. The returned value is
- // always non-nil, but the IPAddr.IP will be nil if ip is the zero value.
- // If ip contains a zone identifier, IPAddr.Zone is populated.
- func (ip IP) IPAddr() *net.IPAddr {
- stdIP, zone := ip.ipZone(nil)
- return &net.IPAddr{IP: stdIP, Zone: zone}
- }
- // Is4 reports whether ip is an IPv4 address.
- //
- // It returns false for IP4-mapped IPv6 addresses. See IP.Unmap.
- func (ip IP) Is4() bool {
- return ip.z == z4
- }
- // Is4in6 reports whether ip is an IPv4-mapped IPv6 address.
- func (ip IP) 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 IP) 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, regardless
- // of its type.
- func (ip IP) Unmap() IP {
- 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 it's returned unchanged.
- func (ip IP) WithZone(zone string) IP {
- if !ip.Is6() {
- return ip
- }
- if zone == "" {
- ip.z = z6noz
- return ip
- }
- ip.z = intern.GetByString(zone)
- return ip
- }
- // noZone unconditionally strips the zone from IP.
- // It's similar to WithZone, but small enough to be inlinable.
- func (ip IP) withoutZone() IP {
- if !ip.Is6() {
- return ip
- }
- ip.z = z6noz
- return ip
- }
- // hasZone reports whether IP has an IPv6 zone.
- func (ip IP) hasZone() bool {
- return ip.z != z0 && ip.z != z4 && ip.z != z6noz
- }
- // IsLinkLocalUnicast reports whether ip is a link-local unicast address.
- // If ip is the zero value, it will return false.
- func (ip IP) 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. If ip is the zero value,
- // it will return false.
- func (ip IP) 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. If ip is the zero
- // value, it will return false.
- func (ip IP) 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. If ip is the zero value or an IPv4 address, it will return
- // false.
- func (ip IP) 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.
- // If ip is the zero value, it will return false.
- func (ip IP) 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. If ip is the zero
- // value, it will return false.
- //
- // For reference, see RFC 1122, RFC 4291, and RFC 4632.
- func (ip IP) IsGlobalUnicast() bool {
- if ip.z == z0 {
- // Invalid or zero-value.
- return false
- }
- // Match the stdlib's IsGlobalUnicast logic. Notably private IPv4 addresses
- // and ULA IPv6 addresses are still considered "global unicast".
- if ip.Is4() && (ip == IPv4(0, 0, 0, 0) || ip == IPv4(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 the standard library's net.IP.IsPrivate.
- func (ip IP) 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 IP zero value is not an unspecified address. Use IsZero to
- // check for the zero value instead.
- func (ip IP) IsUnspecified() bool {
- return ip == IPv4(0, 0, 0, 0) || ip == IPv6Unspecified()
- }
- // Prefix applies a CIDR mask of leading bits to IP, producing an IPPrefix
- // of the specified length. If IP is the zero value, a zero-value IPPrefix and
- // a nil error are returned. If bits is larger than 32 for an IPv4 address or
- // 128 for an IPv6 address, an error is returned.
- func (ip IP) Prefix(bits uint8) (IPPrefix, error) {
- effectiveBits := bits
- switch ip.z {
- case z0:
- return IPPrefix{}, nil
- case z4:
- if bits > 32 {
- return IPPrefix{}, fmt.Errorf("prefix length %d too large for IPv4", bits)
- }
- effectiveBits += 96
- default:
- if bits > 128 {
- return IPPrefix{}, fmt.Errorf("prefix length %d too large for IPv6", bits)
- }
- }
- ip.addr = ip.addr.and(mask6[effectiveBits])
- return IPPrefixFrom(ip, bits), nil
- }
- // Netmask applies a bit mask to IP, producing an IPPrefix. If IP is the
- // zero value, a zero-value IPPrefix and a nil error are returned. If the
- // netmask length is not 4 for IPv4 or 16 for IPv6, an error is
- // returned. If the netmask is non-contiguous, an error is returned.
- func (ip IP) Netmask(mask []byte) (IPPrefix, error) {
- l := len(mask)
- switch ip.z {
- case z0:
- return IPPrefix{}, nil
- case z4:
- if l != net.IPv4len {
- return IPPrefix{}, fmt.Errorf("netmask length %d incorrect for IPv4", l)
- }
- default:
- if l != net.IPv6len {
- return IPPrefix{}, fmt.Errorf("netmask length %d incorrect for IPv6", l)
- }
- }
- ones, bits := net.IPMask(mask).Size()
- if ones == 0 && bits == 0 {
- return IPPrefix{}, errors.New("netmask is non-contiguous")
- }
- return ip.Prefix(uint8(ones))
- }
- // 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 IP) As16() [16]byte {
- var ret [16]byte
- binary.BigEndian.PutUint64(ret[:8], ip.addr.hi)
- binary.BigEndian.PutUint64(ret[8:], ip.addr.lo)
- return ret
- }
- // As4 returns an IPv4 or IPv4-in-IPv6 address in its 4 byte representation.
- // If ip is the IP zero value or an IPv6 address, As4 panics.
- // Note that 0.0.0.0 is not the zero value.
- func (ip IP) As4() [4]byte {
- if ip.z == z4 || ip.Is4in6() {
- var ret [4]byte
- binary.BigEndian.PutUint32(ret[:], uint32(ip.addr.lo))
- return ret
- }
- if ip.z == z0 {
- panic("As4 called on IP zero value")
- }
- panic("As4 called on IPv6 address")
- }
- // Next returns the IP following ip.
- // If there is none, it returns the IP zero value.
- func (ip IP) Next() IP {
- ip.addr = ip.addr.addOne()
- if ip.Is4() {
- if uint32(ip.addr.lo) == 0 {
- // Overflowed.
- return IP{}
- }
- } else {
- if ip.addr.isZero() {
- // Overflowed
- return IP{}
- }
- }
- return ip
- }
- // Prior returns the IP before ip.
- // If there is none, it returns the IP zero value.
- func (ip IP) Prior() IP {
- if ip.Is4() {
- if uint32(ip.addr.lo) == 0 {
- return IP{}
- }
- } else if ip.addr.isZero() {
- return IP{}
- }
- ip.addr = ip.addr.subOne()
- return ip
- }
- // String returns the string form of the IP address ip.
- // It returns one of 4 forms:
- //
- // - "invalid IP", if ip is the zero value
- // - IPv4 dotted decimal ("192.0.2.1")
- // - IPv6 ("2001:db8::1")
- // - IPv6 with zone ("fe80:db8::1%eth0")
- //
- // Note that unlike the Go standard library's IP.String method,
- // IP4-mapped IPv6 addresses do not format as dotted decimals.
- func (ip IP) String() string {
- switch ip.z {
- case z0:
- return "zero IP"
- case z4:
- return ip.string4()
- default:
- return ip.string6()
- }
- }
- // AppendTo appends a text encoding of ip,
- // as generated by MarshalText,
- // to b and returns the extended buffer.
- func (ip IP) AppendTo(b []byte) []byte {
- switch ip.z {
- case z0:
- return b
- case z4:
- return ip.appendTo4(b)
- default:
- 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 IP) string4() string {
- const max = len("255.255.255.255")
- ret := make([]byte, 0, max)
- ret = ip.appendTo4(ret)
- return string(ret)
- }
- func (ip IP) 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 IP) 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 IP) 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 IP) 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 value, the encoding is the empty string.
- func (ip IP) 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)
- return ip.appendTo6(b), nil
- }
- }
- // UnmarshalText implements the encoding.TextUnmarshaler interface.
- // The IP address is expected in a form accepted by ParseIP.
- // It returns an error if *ip is not the IP zero value.
- func (ip *IP) UnmarshalText(text []byte) error {
- if ip.z != z0 {
- return errors.New("refusing to Unmarshal into non-zero IP")
- }
- if len(text) == 0 {
- return nil
- }
- var err error
- *ip, err = ParseIP(string(text))
- return err
- }
- // MarshalBinary implements the encoding.BinaryMarshaler interface.
- func (ip IP) MarshalBinary() ([]byte, error) {
- switch ip.z {
- case z0:
- return nil, nil
- case z4:
- b := ip.As4()
- return b[:], nil
- default:
- b16 := ip.As16()
- b := b16[:]
- if z := ip.Zone(); z != "" {
- b = append(b, []byte(z)...)
- }
- return b, nil
- }
- }
- // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
- func (ip *IP) UnmarshalBinary(b []byte) error {
- if ip.z != z0 {
- return errors.New("refusing to Unmarshal into non-zero IP")
- }
- n := len(b)
- switch {
- case n == 0:
- return nil
- case n == 4:
- *ip = IPv4(b[0], b[1], b[2], b[3])
- return nil
- case n == 16:
- *ip = ipv6Slice(b)
- return nil
- case n > 16:
- *ip = ipv6Slice(b[:16]).WithZone(string(b[16:]))
- return nil
- }
- return fmt.Errorf("unexpected ip size: %v", len(b))
- }
- // IPPort is an IP and a port number.
- type IPPort struct {
- ip IP
- port uint16
- }
- // IPPortFrom returns an IPPort with IP ip and port port.
- // It does not allocate.
- func IPPortFrom(ip IP, port uint16) IPPort { return IPPort{ip: ip, port: port} }
- // WithIP returns an IPPort with IP ip and port p.Port().
- func (p IPPort) WithIP(ip IP) IPPort { return IPPort{ip: ip, port: p.port} }
- // WithIP returns an IPPort with IP p.IP() and port port.
- func (p IPPort) WithPort(port uint16) IPPort { return IPPort{ip: p.ip, port: port} }
- // IP returns p's IP.
- func (p IPPort) IP() IP { return p.ip }
- // Port returns p's port.
- func (p IPPort) Port() uint16 { return p.port }
- // splitIPPort 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 splitIPPort(s string) (ip, port string, v6 bool, err error) {
- i := strings.LastIndexByte(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
- }
- // ParseIPPort parses s as an IPPort.
- //
- // It doesn't do any name resolution, and ports must be numeric.
- func ParseIPPort(s string) (IPPort, error) {
- var ipp IPPort
- ip, port, v6, err := splitIPPort(s)
- if err != nil {
- return ipp, err
- }
- port16, err := strconv.ParseUint(port, 10, 16)
- if err != nil {
- return ipp, fmt.Errorf("invalid port %q parsing %q", port, s)
- }
- ipp.port = uint16(port16)
- ipp.ip, err = ParseIP(ip)
- if err != nil {
- return IPPort{}, err
- }
- if v6 && ipp.ip.Is4() {
- return IPPort{}, fmt.Errorf("invalid ip:port %q, square brackets can only be used with IPv6 addresses", s)
- } else if !v6 && ipp.ip.Is6() {
- return IPPort{}, fmt.Errorf("invalid ip:port %q, IPv6 addresses must be surrounded by square brackets", s)
- }
- return ipp, nil
- }
- // MustParseIPPort calls ParseIPPort(s) and panics on error.
- // It is intended for use in tests with hard-coded strings.
- func MustParseIPPort(s string) IPPort {
- ip, err := ParseIPPort(s)
- if err != nil {
- panic(err)
- }
- return ip
- }
- // IsZero reports whether p is its zero value.
- func (p IPPort) IsZero() bool { return p == IPPort{} }
- // IsValid reports whether p.IP() is valid.
- // All ports are valid, including zero.
- func (p IPPort) IsValid() bool { return p.ip.IsValid() }
- // Valid reports whether p.IP() is valid.
- // All ports are valid, including zero.
- //
- // Deprecated: use the correctly named and identical IsValid method instead.
- func (p IPPort) Valid() bool { return p.IsValid() }
- func (p IPPort) String() string {
- switch p.ip.z {
- case z0:
- return "invalid IPPort"
- case z4:
- a := p.ip.As4()
- return fmt.Sprintf("%d.%d.%d.%d:%d", a[0], a[1], a[2], a[3], p.port)
- default:
- // TODO: this could be more efficient allocation-wise:
- return net.JoinHostPort(p.ip.String(), strconv.Itoa(int(p.port)))
- }
- }
- // AppendTo appends a text encoding of p,
- // as generated by MarshalText,
- // to b and returns the extended buffer.
- func (p IPPort) AppendTo(b []byte) []byte {
- switch p.ip.z {
- case z0:
- return b
- case z4:
- b = p.ip.appendTo4(b)
- default:
- 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.IP() is the zero value, the encoding is the empty string.
- func (p IPPort) 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 IPPort is expected in a form accepted by
- // ParseIPPort. It returns an error if *p is not the IPPort zero
- // value.
- func (p *IPPort) UnmarshalText(text []byte) error {
- if p.ip.z != z0 || p.port != 0 {
- return errors.New("refusing to Unmarshal into non-zero IPPort")
- }
- if len(text) == 0 {
- return nil
- }
- var err error
- *p, err = ParseIPPort(string(text))
- return err
- }
- // FromStdAddr maps the components of a standard library TCPAddr or
- // UDPAddr into an IPPort.
- func FromStdAddr(stdIP net.IP, port int, zone string) (_ IPPort, ok bool) {
- ip, ok := FromStdIP(stdIP)
- if !ok || port < 0 || port > math.MaxUint16 {
- return
- }
- ip = ip.Unmap()
- if zone != "" {
- if ip.Is4() {
- ok = false
- return
- }
- ip = ip.WithZone(zone)
- }
- return IPPort{ip: ip, port: uint16(port)}, true
- }
- // UDPAddr returns a standard library net.UDPAddr from p.
- // The returned value is always non-nil. If p.IP() is the zero
- // value, then UDPAddr.IP is nil.
- //
- // UDPAddr necessarily does two allocations. If you have an existing
- // UDPAddr already allocated, see UDPAddrAt.
- func (p IPPort) UDPAddr() *net.UDPAddr {
- ret := &net.UDPAddr{
- Port: int(p.port),
- }
- ret.IP, ret.Zone = p.ip.ipZone(nil)
- return ret
- }
- // UDPAddrAt is like UDPAddr, but reuses the provided UDPAddr, which
- // must be non-nil. If at.IP has a capacity of 16, UDPAddrAt is
- // allocation-free. It returns at to facilitate using this method as a
- // wrapper.
- func (p IPPort) UDPAddrAt(at *net.UDPAddr) *net.UDPAddr {
- at.Port = int(p.port)
- at.IP, at.Zone = p.ip.ipZone(at.IP)
- return at
- }
- // TCPAddr returns a standard library net.TCPAddr from p.
- // The returned value is always non-nil. If p.IP() is the zero
- // value, then TCPAddr.IP is nil.
- func (p IPPort) TCPAddr() *net.TCPAddr {
- ip, zone := p.ip.ipZone(nil)
- return &net.TCPAddr{
- IP: ip,
- Port: int(p.port),
- Zone: zone,
- }
- }
- // IPPrefix is an IP address prefix (CIDR) representing an IP network.
- //
- // The first Bits() of IP() are specified. The remaining bits match any address.
- // The range of Bits() is [0,32] for IPv4 or [0,128] for IPv6.
- type IPPrefix struct {
- ip IP
- bits uint8
- }
- // IPPrefixFrom returns an IPPrefix with IP ip and provided bits prefix length.
- // It does not allocate.
- func IPPrefixFrom(ip IP, bits uint8) IPPrefix {
- return IPPrefix{
- ip: ip.withoutZone(),
- bits: bits,
- }
- }
- // IP returns p's IP.
- func (p IPPrefix) IP() IP { return p.ip }
- // Bits returns p's prefix length.
- func (p IPPrefix) Bits() uint8 { return p.bits }
- // IsValid reports whether whether p.Bits() has a valid range for p.IP().
- // If p.IP() is zero, Valid returns false.
- func (p IPPrefix) IsValid() bool { return !p.ip.IsZero() && p.bits <= p.ip.BitLen() }
- // Valid reports whether whether p.Bits() has a valid range for p.IP().
- // If p.IP() is zero, Valid returns false.
- //
- // Deprecated: use the correctly named and identical IsValid method instead.
- func (p IPPrefix) Valid() bool { return p.IsValid() }
- // IsZero reports whether p is its zero value.
- func (p IPPrefix) IsZero() bool { return p == IPPrefix{} }
- // IsSingleIP reports whether p contains exactly one IP.
- func (p IPPrefix) IsSingleIP() bool { return p.bits != 0 && p.bits == p.ip.BitLen() }
- // FromStdIPNet returns an IPPrefix from the standard library's IPNet type.
- // If std is invalid, ok is false.
- func FromStdIPNet(std *net.IPNet) (prefix IPPrefix, ok bool) {
- ip, ok := FromStdIP(std.IP)
- if !ok {
- return IPPrefix{}, false
- }
- if l := len(std.Mask); l != net.IPv4len && l != net.IPv6len {
- // Invalid mask.
- return IPPrefix{}, false
- }
- ones, bits := std.Mask.Size()
- if ones == 0 && bits == 0 {
- // IPPrefix does not support non-contiguous masks.
- return IPPrefix{}, false
- }
- return IPPrefix{
- ip: ip,
- bits: uint8(ones),
- }, true
- }
- // ParseIPPrefix 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 ParseIPPrefix(s string) (IPPrefix, error) {
- i := strings.LastIndexByte(s, '/')
- if i < 0 {
- return IPPrefix{}, fmt.Errorf("netaddr.ParseIPPrefix(%q): no '/'", s)
- }
- ip, err := ParseIP(s[:i])
- if err != nil {
- return IPPrefix{}, fmt.Errorf("netaddr.ParseIPPrefix(%q): %v", s, err)
- }
- s = s[i+1:]
- bits, err := strconv.Atoi(s)
- if err != nil {
- return IPPrefix{}, fmt.Errorf("netaddr.ParseIPPrefix(%q): bad prefix: %v", s, err)
- }
- maxBits := 32
- if ip.Is6() {
- maxBits = 128
- }
- if bits < 0 || bits > maxBits {
- return IPPrefix{}, fmt.Errorf("netaddr.ParseIPPrefix(%q): prefix length out of range", s)
- }
- return IPPrefixFrom(ip, uint8(bits)), nil
- }
- // MustParseIPPrefix calls ParseIPPrefix(s) and panics on error.
- // It is intended for use in tests with hard-coded strings.
- func MustParseIPPrefix(s string) IPPrefix {
- ip, err := ParseIPPrefix(s)
- if err != nil {
- panic(err)
- }
- return ip
- }
- // Masked returns p in its canonical form, with bits of p.IP() not in p.Bits() masked off.
- // If p is zero or otherwise invalid, Masked returns the zero value.
- func (p IPPrefix) Masked() IPPrefix {
- if m, err := p.ip.Prefix(p.bits); err == nil {
- return m
- }
- return IPPrefix{}
- }
- // Range returns the inclusive range of IPs that p covers.
- //
- // If p is zero or otherwise invalid, Range returns the zero value.
- func (p IPPrefix) Range() IPRange {
- p = p.Masked()
- if p.IsZero() {
- return IPRange{}
- }
- return IPRangeFrom(p.ip, p.lastIP())
- }
- // IPNet returns the net.IPNet representation of an IPPrefix.
- // The returned value is always non-nil.
- // Any zone identifier is dropped in the conversion.
- func (p IPPrefix) IPNet() *net.IPNet {
- if !p.IsValid() {
- return &net.IPNet{}
- }
- stdIP, _ := p.ip.ipZone(nil)
- return &net.IPNet{
- IP: stdIP,
- Mask: net.CIDRMask(int(p.bits), int(p.ip.BitLen())),
- }
- }
- // 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 IPPrefixes strip zones.
- func (p IPPrefix) Contains(ip IP) 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[p.bits]).isZero()
- }
- }
- // Overlaps reports whether p and o overlap at all.
- //
- // 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.
- //
- // If either has a Bits of zero, it returns true.
- func (p IPPrefix) Overlaps(o IPPrefix) bool {
- if !p.IsValid() || !o.IsValid() {
- return false
- }
- if p == o {
- return true
- }
- if p.ip.Is4() != o.ip.Is4() {
- return false
- }
- var minBits uint8
- 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 IPPrefix.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(minBits); err != nil {
- return false
- }
- if o, err = o.ip.Prefix(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 IPPrefix) AppendTo(b []byte) []byte {
- if p.IsZero() {
- return b
- }
- if !p.IsValid() {
- return append(b, "invalid IPPrefix"...)
- }
- // p.IP is non-zero, because p is valid.
- if p.ip.z == z4 {
- b = p.ip.appendTo4(b)
- } else {
- b = p.ip.appendTo6(b)
- }
- b = append(b, '/')
- b = appendDecimal(b, 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 IPPrefix) 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 ParseIPPrefix.
- // It returns an error if *p is not the IPPrefix zero value.
- func (p *IPPrefix) UnmarshalText(text []byte) error {
- if *p != (IPPrefix{}) {
- return errors.New("refusing to Unmarshal into non-zero IPPrefix")
- }
- if len(text) == 0 {
- return nil
- }
- var err error
- *p, err = ParseIPPrefix(string(text))
- return err
- }
- // String returns the CIDR notation of p: "<ip>/<bits>".
- func (p IPPrefix) String() string {
- if p.IsZero() {
- return "zero IPPrefix"
- }
- if !p.IsValid() {
- return "invalid IPPrefix"
- }
- return fmt.Sprintf("%s/%d", p.ip, p.bits)
- }
- // lastIP returns the last IP in the prefix.
- func (p IPPrefix) lastIP() IP {
- if !p.IsValid() {
- return IP{}
- }
- a16 := p.ip.As16()
- var off uint8
- var bits uint8 = 128
- if p.ip.Is4() {
- off = 12
- bits = 32
- }
- for b := p.bits; b < bits; b++ {
- byteNum, bitInByte := b/8, 7-(b%8)
- a16[off+byteNum] |= 1 << uint(bitInByte)
- }
- if p.ip.Is4() {
- return IPFrom16(a16)
- } else {
- return IPv6Raw(a16) // doesn't unmap
- }
- }
- // IPRange represents an inclusive range of IP addresses
- // from the same address family.
- //
- // The From() and To() IPs are inclusive bounds, both included in the
- // range.
- //
- // To be valid, the From() and To() values must be non-zero, have matching
- // address families (IPv4 vs IPv6), and From() must be less than or equal to To().
- // IPv6 zones are stripped out and ignored.
- // An invalid range may be ignored.
- type IPRange struct {
- // from is the initial IP address in the range.
- from IP
- // to is the final IP address in the range.
- to IP
- }
- // IPRangeFrom returns an IPRange from from to to.
- // It does not allocate.
- func IPRangeFrom(from, to IP) IPRange {
- return IPRange{
- from: from.withoutZone(),
- to: to.withoutZone(),
- }
- }
- // From returns the lower bound of r.
- func (r IPRange) From() IP { return r.from }
- // To returns the upper bound of r.
- func (r IPRange) To() IP { return r.to }
- // ParseIPRange parses a range out of two IPs separated by a hyphen.
- //
- // It returns an error if the range is not valid.
- func ParseIPRange(s string) (IPRange, error) {
- var r IPRange
- h := strings.IndexByte(s, '-')
- if h == -1 {
- return r, fmt.Errorf("no hyphen in range %q", s)
- }
- from, to := s[:h], s[h+1:]
- var err error
- r.from, err = ParseIP(from)
- if err != nil {
- return r, fmt.Errorf("invalid From IP %q in range %q", from, s)
- }
- r.from = r.from.withoutZone()
- r.to, err = ParseIP(to)
- if err != nil {
- return r, fmt.Errorf("invalid To IP %q in range %q", to, s)
- }
- r.to = r.to.withoutZone()
- if !r.IsValid() {
- return r, fmt.Errorf("range %v to %v not valid", r.from, r.to)
- }
- return r, nil
- }
- // MustParseIPRange calls ParseIPRange(s) and panics on error.
- // It is intended for use in tests with hard-coded strings.
- func MustParseIPRange(s string) IPRange {
- r, err := ParseIPRange(s)
- if err != nil {
- panic(err)
- }
- return r
- }
- // String returns a string representation of the range.
- //
- // For a valid range, the form is "From-To" with a single hyphen
- // separating the IPs, the same format recognized by
- // ParseIPRange.
- func (r IPRange) String() string {
- if r.IsValid() {
- return fmt.Sprintf("%s-%s", r.from, r.to)
- }
- if r.from.IsZero() || r.to.IsZero() {
- return "zero IPRange"
- }
- return "invalid IPRange"
- }
- // AppendTo appends a text encoding of r,
- // as generated by MarshalText,
- // to b and returns the extended buffer.
- func (r IPRange) AppendTo(b []byte) []byte {
- if r.IsZero() {
- return b
- }
- b = r.from.AppendTo(b)
- b = append(b, '-')
- b = r.to.AppendTo(b)
- return b
- }
- // MarshalText implements the encoding.TextMarshaler interface,
- // The encoding is the same as returned by String, with one exception:
- // If ip is the zero value, the encoding is the empty string.
- func (r IPRange) MarshalText() ([]byte, error) {
- if r.IsZero() {
- return []byte(""), nil
- }
- var max int
- if r.from.z == z4 {
- max = len("255.255.255.255-255.255.255.255")
- } else {
- max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
- }
- b := make([]byte, 0, max)
- return r.AppendTo(b), nil
- }
- // UnmarshalText implements the encoding.TextUnmarshaler interface.
- // The IP range is expected in a form accepted by ParseIPRange.
- // It returns an error if *r is not the IPRange zero value.
- func (r *IPRange) UnmarshalText(text []byte) error {
- if *r != (IPRange{}) {
- return errors.New("refusing to Unmarshal into non-zero IPRange")
- }
- if len(text) == 0 {
- return nil
- }
- var err error
- *r, err = ParseIPRange(string(text))
- return err
- }
- // IsZero reports whether r is the zero value of the IPRange type.
- func (r IPRange) IsZero() bool {
- return r == IPRange{}
- }
- // IsValid reports whether r.From() and r.To() are both non-zero and
- // obey the documented requirements: address families match, and From
- // is less than or equal to To.
- func (r IPRange) IsValid() bool {
- return !r.from.IsZero() &&
- r.from.z == r.to.z &&
- !r.to.Less(r.from)
- }
- // Valid reports whether r.From() and r.To() are both non-zero and
- // obey the documented requirements: address families match, and From
- // is less than or equal to To.
- //
- // Deprecated: use the correctly named and identical IsValid method instead.
- func (r IPRange) Valid() bool { return r.IsValid() }
- // Contains reports whether the range r includes addr.
- //
- // An invalid range always reports false.
- //
- // If ip has an IPv6 zone, Contains returns false,
- // because IPPrefixes strip zones.
- func (r IPRange) Contains(addr IP) bool {
- return r.IsValid() && !addr.hasZone() && r.contains(addr)
- }
- // contains is like Contains, but without the validity check.
- // addr must not have a zone.
- func (r IPRange) contains(addr IP) bool {
- return r.from.Compare(addr) <= 0 && r.to.Compare(addr) >= 0
- }
- // less reports whether r is "before" other. It is before if r.From()
- // is before other.From(). If they're equal, then the larger range
- // (higher To()) comes first.
- func (r IPRange) less(other IPRange) bool {
- if cmp := r.from.Compare(other.from); cmp != 0 {
- return cmp < 0
- }
- return other.to.Less(r.to)
- }
- // entirelyBefore returns whether r lies entirely before other in IP
- // space.
- func (r IPRange) entirelyBefore(other IPRange) bool {
- return r.to.Less(other.from)
- }
- // entirelyWithin returns whether r is entirely contained within
- // other.
- func (r IPRange) coveredBy(other IPRange) bool {
- return other.from.lessOrEq(r.from) && r.to.lessOrEq(other.to)
- }
- // inMiddleOf returns whether r is inside other, but not touching the
- // edges of other.
- func (r IPRange) inMiddleOf(other IPRange) bool {
- return other.from.Less(r.from) && r.to.Less(other.to)
- }
- // overlapsStartOf returns whether r entirely overlaps the start of
- // other, but not all of other.
- func (r IPRange) overlapsStartOf(other IPRange) bool {
- return r.from.lessOrEq(other.from) && r.to.Less(other.to)
- }
- // overlapsEndOf returns whether r entirely overlaps the end of
- // other, but not all of other.
- func (r IPRange) overlapsEndOf(other IPRange) bool {
- return other.from.Less(r.from) && other.to.lessOrEq(r.to)
- }
- // mergeIPRanges returns the minimum and sorted set of IP ranges that
- // cover r.
- func mergeIPRanges(rr []IPRange) (out []IPRange, valid bool) {
- // Always return a copy of r, to avoid aliasing slice memory in
- // the caller.
- switch len(rr) {
- case 0:
- return nil, true
- case 1:
- return []IPRange{rr[0]}, true
- }
- sort.Slice(rr, func(i, j int) bool { return rr[i].less(rr[j]) })
- out = make([]IPRange, 1, len(rr))
- out[0] = rr[0]
- for _, r := range rr[1:] {
- prev := &out[len(out)-1]
- switch {
- case !r.IsValid():
- // Invalid ranges make no sense to merge, refuse to
- // perform.
- return nil, false
- case prev.to.Next() == r.from:
- // prev and r touch, merge them.
- //
- // prev r
- // f------tf-----t
- prev.to = r.to
- case prev.to.Less(r.from):
- // No overlap and not adjacent (per previous case), no
- // merging possible.
- //
- // prev r
- // f------t f-----t
- out = append(out, r)
- case prev.to.Less(r.to):
- // Partial overlap, update prev
- //
- // prev
- // f------t
- // f-----t
- // r
- prev.to = r.to
- default:
- // r entirely contained in prev, nothing to do.
- //
- // prev
- // f--------t
- // f-----t
- // r
- }
- }
- return out, true
- }
- // Overlaps reports whether p and o overlap at all.
- //
- // If p and o are of different address families or either are invalid,
- // it reports false.
- func (r IPRange) Overlaps(o IPRange) bool {
- return r.IsValid() &&
- o.IsValid() &&
- r.from.Compare(o.to) <= 0 &&
- o.from.Compare(r.to) <= 0
- }
- // prefixMaker returns a address-family-corrected IPPrefix from a and bits,
- // where the input bits is always in the IPv6-mapped form for IPv4 addresses.
- type prefixMaker func(a uint128, bits uint8) IPPrefix
- // Prefixes returns the set of IPPrefix entries that covers r.
- //
- // If either of r's bounds are invalid, in the wrong order, or if
- // they're of different address families, then Prefixes returns nil.
- //
- // Prefixes necessarily allocates. See AppendPrefixes for a version that uses
- // memory you provide.
- func (r IPRange) Prefixes() []IPPrefix {
- return r.AppendPrefixes(nil)
- }
- // AppendPrefixes is an append version of IPRange.Prefixes. It appends
- // the IPPrefix entries that cover r to dst.
- func (r IPRange) AppendPrefixes(dst []IPPrefix) []IPPrefix {
- if !r.IsValid() {
- return nil
- }
- return appendRangePrefixes(dst, r.prefixFrom128AndBits, r.from.addr, r.to.addr)
- }
- func (r IPRange) prefixFrom128AndBits(a uint128, bits uint8) IPPrefix {
- ip := IP{addr: a, z: r.from.z}
- if r.from.Is4() {
- bits -= 12 * 8
- }
- return IPPrefix{ip, bits}
- }
- // aZeroBSet is whether, after the common bits, a is all zero bits and
- // b is all set (one) bits.
- func comparePrefixes(a, b uint128) (common uint8, aZeroBSet bool) {
- common = a.commonPrefixLen(b)
- // See whether a and b, after their common shared bits, end
- // in all zero bits or all one bits, respectively.
- if common == 128 {
- return common, true
- }
- m := mask6[common]
- return common, (a.xor(a.and(m)).isZero() &&
- b.or(m) == uint128{^uint64(0), ^uint64(0)})
- }
- // Prefix returns r as an IPPrefix, if it can be presented exactly as such.
- // If r is not valid or is not exactly equal to one prefix, ok is false.
- func (r IPRange) Prefix() (p IPPrefix, ok bool) {
- if !r.IsValid() {
- return
- }
- if common, ok := comparePrefixes(r.from.addr, r.to.addr); ok {
- return r.prefixFrom128AndBits(r.from.addr, common), true
- }
- return
- }
- func appendRangePrefixes(dst []IPPrefix, makePrefix prefixMaker, a, b uint128) []IPPrefix {
- common, ok := comparePrefixes(a, b)
- if ok {
- // a to b represents a whole range, like 10.50.0.0/16.
- // (a being 10.50.0.0 and b being 10.50.255.255)
- return append(dst, makePrefix(a, common))
- }
- // Otherwise recursively do both halves.
- dst = appendRangePrefixes(dst, makePrefix, a, a.bitsSetFrom(common+1))
- dst = appendRangePrefixes(dst, makePrefix, b.bitsClearedFrom(common+1), b)
- return dst
- }
|