github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/p2p/distip/net.go (about) 1 package distip 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "net" 8 "sort" 9 ) 10 11 var ( 12 lan4, lan6, special4, special6 Netlist 13 errInvalid = errors.New("invalid IP") 14 errUnspecified = errors.New("zero address") 15 errSpecial = errors.New("special network") 16 errLoopback = errors.New("loopback address from non-loopback host") 17 errLAN = errors.New("LAN address from WAN host") 18 ) 19 20 // Netlist is a list of IP networks. 21 type Netlist []net.IPNet 22 23 func init() { 24 // Lists from RFC 5735, RFC 5156, 25 // https://www.iana.org/assignments/iana-ipv4-special-registry/ 26 lan4.Add("0.0.0.0/8") // "This" network 27 lan4.Add("10.0.0.0/8") // Private Use 28 lan4.Add("172.16.0.0/12") // Private Use 29 lan4.Add("192.168.0.0/16") // Private Use 30 lan6.Add("fe80::/10") // Link-Local 31 lan6.Add("fc00::/7") // Unique-Local 32 special4.Add("192.0.0.0/29") // IPv4 Service Continuity 33 special4.Add("192.0.0.9/32") // PCP Anycast 34 special4.Add("192.0.0.170/32") // NAT64/DNS64 Discovery 35 special4.Add("192.0.0.171/32") // NAT64/DNS64 Discovery 36 special4.Add("192.0.2.0/24") // TEST-NET-1 37 special4.Add("192.31.196.0/24") // AS112 38 special4.Add("192.52.193.0/24") // AMT 39 special4.Add("192.88.99.0/24") // 6to4 Relay Anycast 40 special4.Add("192.175.48.0/24") // AS112 41 special4.Add("198.18.0.0/15") // Device Benchmark Testing 42 special4.Add("198.51.100.0/24") // TEST-NET-2 43 special4.Add("203.0.113.0/24") // TEST-NET-3 44 special4.Add("255.255.255.255/32") // Limited Broadcast 45 46 // http://www.iana.org/assignments/iana-ipv6-special-registry/ 47 special6.Add("100::/64") 48 special6.Add("2001::/32") 49 special6.Add("2001:1::1/128") 50 special6.Add("2001:2::/48") 51 special6.Add("2001:3::/32") 52 special6.Add("2001:4:112::/48") 53 special6.Add("2001:5::/32") 54 special6.Add("2001:10::/28") 55 special6.Add("2001:20::/28") 56 special6.Add("2001:db8::/32") 57 special6.Add("2002::/16") 58 } 59 60 // Add parses a CIDR mask and appends it to the list. It panics for invalid masks and is 61 // intended to be used for setting up static lists. 62 func (l *Netlist) Add(cidr string) { 63 _, n, err := net.ParseCIDR(cidr) 64 if err != nil { 65 panic(err) 66 } 67 *l = append(*l, *n) 68 } 69 70 // Contains reports whether the given IP is contained in the list. 71 func (l *Netlist) Contains(ip net.IP) bool { 72 if l == nil { 73 return false 74 } 75 for _, net := range *l { 76 if net.Contains(ip) { 77 return true 78 } 79 } 80 return false 81 } 82 83 // IsLAN reports whether an IP is a local network address. 84 func IsLAN(ip net.IP) bool { 85 if ip.IsLoopback() { 86 return true 87 } 88 if v4 := ip.To4(); v4 != nil { 89 return lan4.Contains(v4) 90 } 91 return lan6.Contains(ip) 92 } 93 94 // IsSpecialNetwork reports whether an IP is located in a special-use network range 95 // This includes broadcast, multicast and documentation addresses. 96 func IsSpecialNetwork(ip net.IP) bool { 97 if ip.IsMulticast() { 98 return true 99 } 100 if v4 := ip.To4(); v4 != nil { 101 return special4.Contains(v4) 102 } 103 return special6.Contains(ip) 104 } 105 106 // CheckRelayIP reports whether an IP relayed from the given sender IP 107 // is a valid connection target. 108 // 109 // There are four rules: 110 // - Special network addresses are never valid. 111 // - Loopback addresses are OK if relayed by a loopback host. 112 // - LAN addresses are OK if relayed by a LAN host. 113 // - All other addresses are always acceptable. 114 func CheckRelayIP(sender, addr net.IP) error { 115 if len(addr) != net.IPv4len && len(addr) != net.IPv6len { 116 return errInvalid 117 } 118 if addr.IsUnspecified() { 119 return errUnspecified 120 } 121 if IsSpecialNetwork(addr) { 122 return errSpecial 123 } 124 if addr.IsLoopback() && !sender.IsLoopback() { 125 return errLoopback 126 } 127 if IsLAN(addr) && !IsLAN(sender) { 128 return errLAN 129 } 130 return nil 131 } 132 133 // DistinctNetSet tracks IPs, ensuring that at most N of them 134 // fall into the same network range. 135 type DistinctNetSet struct { 136 Subnet uint // number of common prefix bits 137 Limit uint // maximum number of IPs in each subnet 138 139 members map[string]uint 140 buf net.IP 141 } 142 143 // Add adds an IP address to the set. It returns false (and doesn't add the IP) if the 144 // number of existing IPs in the defined range exceeds the limit. 145 func (s *DistinctNetSet) Add(ip net.IP) bool { 146 key := string(s.key(ip)) 147 n := s.members[key] 148 if n < s.Limit { 149 s.members[key] = n + 1 150 return true 151 } 152 return false 153 } 154 155 // Remove removes an IP from the set. 156 func (s *DistinctNetSet) Remove(ip net.IP) { 157 key := string(s.key(ip)) 158 if n, ok := s.members[key]; ok { 159 if n == 1 { 160 delete(s.members, key) 161 } else { 162 s.members[key] = n - 1 163 } 164 } 165 } 166 167 // Contains whether the given IP is contained in the set. 168 func (s DistinctNetSet) Contains(ip net.IP) bool { 169 key := string(s.key(ip)) 170 _, ok := s.members[key] 171 return ok 172 } 173 174 // Len returns the number of tracked IPs. 175 func (s DistinctNetSet) Len() uint { 176 n := uint(0) 177 for _, i := range s.members { 178 n += i 179 } 180 return n 181 } 182 183 // key encodes the map key for an address into a temporary buffer. 184 // 185 // The first byte of key is '4' or '6' to distinguish IPv4/IPv6 address types. 186 // The remainder of the key is the IP, truncated to the number of bits. 187 func (s *DistinctNetSet) key(ip net.IP) net.IP { 188 // Lazily initialize storage. 189 if s.members == nil { 190 s.members = make(map[string]uint) 191 s.buf = make(net.IP, 17) 192 } 193 // Canonicalize ip and bits. 194 typ := byte('6') 195 if ip4 := ip.To4(); ip4 != nil { 196 typ, ip = '4', ip4 197 } 198 bits := s.Subnet 199 if bits > uint(len(ip)*8) { 200 bits = uint(len(ip) * 8) 201 } 202 // Encode the prefix into s.buf. 203 nb := int(bits / 8) 204 mask := ^byte(0xFF >> (bits % 8)) 205 s.buf[0] = typ 206 buf := append(s.buf[:1], ip[:nb]...) 207 if nb < len(ip) && mask != 0 { 208 buf = append(buf, ip[nb]&mask) 209 } 210 return buf 211 } 212 213 // String implements fmt.Stringer 214 func (s DistinctNetSet) String() string { 215 var buf bytes.Buffer 216 buf.WriteString("{") 217 keys := make([]string, 0, len(s.members)) 218 for k := range s.members { 219 keys = append(keys, k) 220 } 221 sort.Strings(keys) 222 for i, k := range keys { 223 var ip net.IP 224 if k[0] == '4' { 225 ip = make(net.IP, 4) 226 } else { 227 ip = make(net.IP, 16) 228 } 229 copy(ip, k[1:]) 230 fmt.Fprintf(&buf, "%vĂ—%d", ip, s.members[k]) 231 if i != len(keys)-1 { 232 buf.WriteString(" ") 233 } 234 } 235 buf.WriteString("}") 236 return buf.String() 237 }