decred.org/dcrdex@v1.0.5/dex/ip.go (about) 1 // This code is available on the terms of the project LICENSE.md file, 2 // also available online at https://blueoakcouncil.org/license/1.0.0. 3 4 package dex 5 6 import ( 7 "net" 8 "strings" 9 ) 10 11 // IPKey is a IP address byte array. 12 type IPKey [net.IPv6len]byte 13 14 // NewIPKey parses an IP address string into an IPKey. For an IPV6 address, this 15 // drops the interface identifier, which is the second half of the address. The 16 // first half of the address comprises 48-bits for the prefix, which is the 17 // public topology of a network that is assigned by an ISP, and 16-bits for the 18 // Site-Level Aggregation Identifier (SLA). However, any number of the SLA bits 19 // may be assigned by a provider, potentially giving a single link the freedom 20 // to use multiple subnets, thus expanding the set of addresses they may use 21 // freely. As such, IPv6 addresses with just the interface bits masked may not 22 // be sufficient to identify a single remote uplink. 23 func NewIPKey(addr string) IPKey { 24 host, _, err := net.SplitHostPort(addr) 25 if err == nil && host != "" { 26 addr = host 27 } else { 28 // If SplitHostPort failed, IPv6 addresses may still have brackets. 29 addr = strings.Trim(addr, "[]") 30 } 31 32 ip := net.ParseIP(addr) 33 if ip == nil { 34 return IPKey{} // i.e. net.IPv6unspecified 35 } 36 // IPv4 is encoded in a net.IP of length IPv6len as 37 // 00:00:00:00:00:00:00:00:00:00:ff:ff:xx:xx:xx:xx 38 // Thus, must copy all 16 bytes for IPv4. 39 N := net.IPv6len 40 if ip.To4() == nil && !ip.Equal(net.IPv6loopback) { 41 // Drop the last 64 bits (interface) of non-loopback IPv6 addresses. 42 N = net.IPv6len / 2 // i.e. ip = ip.Mask(net.CIDRMask(64, 128)) 43 } 44 var ipKey IPKey 45 copy(ipKey[:], ip[:N]) 46 return ipKey 47 } 48 49 // String returns a readable IP address representation of the IPKey. This is 50 // done by copying the bytes of the IPKey array, and invoking the 51 // net.(IP).String method. As such it is inefficient and should not be invoked 52 // repeatedly or in hot paths. 53 func (ipk IPKey) String() string { 54 return net.IP(ipk[:]).String() 55 } 56 57 // PrefixV6 returns the first 48-bits of an IPv6 address, or nil for an IPv4 58 // address. This may be used to identify multiple remote hosts from the same 59 // public topology but different subnets. A heuristic may be defined to treat 60 // hosts with the same prefix as the same host if there are many such hosts. 61 func (ipk IPKey) PrefixV6() *IPKey { 62 if net.IP(ipk[:]).To4() != nil { 63 return nil 64 } 65 var prefix IPKey 66 copy(prefix[:], ipk[:6]) // 48 bit prefix 67 return &prefix 68 } 69 70 // IsLoopback reports whether the IPKey represents a loopback address. 71 func (ipk IPKey) IsLoopback() bool { 72 return net.IP(ipk[:]).IsLoopback() 73 } 74 75 // IsUnspecified reports whether the IPKey is zero (unspecified). 76 func (ipk IPKey) IsUnspecified() bool { 77 return ipk == IPKey{} // net.IP(ipk[:]).Equal(net.IPv6unspecified) 78 }