gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/renter/hostdb/hosttree/addressfilter.go (about) 1 package hosttree 2 3 import ( 4 "fmt" 5 "net" 6 7 "gitlab.com/SiaPrime/SiaPrime/modules" 8 ) 9 10 const ( 11 // IPv4FilterRange is the number of bits within an IP address (starting 12 // from the left) which have to be unique for the host not to be filtered. 13 IPv4FilterRange = 24 14 // IPv6FilterRange is the number of bits within an IP address (starting 15 // from the left) which have to be unique for the host not to be filtered. 16 IPv6FilterRange = 54 17 ) 18 19 // Filter filters host addresses which belong to the same subnet to 20 // avoid selecting hosts from the same region. 21 type Filter struct { 22 filter map[string]struct{} 23 resolver modules.Resolver 24 } 25 26 // NewFilter creates a new addressFilter object. 27 func NewFilter(resolver modules.Resolver) *Filter { 28 return &Filter{ 29 filter: make(map[string]struct{}), 30 resolver: resolver, 31 } 32 } 33 34 // Add adds a host to the filter. This will resolve the hostname into one 35 // or more IP addresses, extract the subnets used by those addresses and 36 // add the subnets to the filter. Add doesn't return an error, but if the 37 // addresses of a host can't be resolved it will be handled as if the host 38 // had no addresses associated with it. 39 func (af *Filter) Add(host modules.NetAddress) { 40 // Translate the hostname to one or multiple IPs. If the argument is an IP 41 // address LookupIP will just return that IP. 42 addresses, err := af.resolver.LookupIP(host.Host()) 43 if err != nil { 44 return 45 } 46 // If any of the addresses is blocked we ignore the host. 47 for _, ip := range addresses { 48 // Set the filterRange according to the type of IP address. 49 var filterRange int 50 if ip.To4() != nil { 51 filterRange = IPv4FilterRange 52 } else { 53 filterRange = IPv6FilterRange 54 } 55 // Get the subnet. 56 _, ipnet, err := net.ParseCIDR(fmt.Sprintf("%s/%d", ip.String(), filterRange)) 57 if err != nil { 58 continue 59 } 60 // Add the subnet to the map. 61 af.filter[ipnet.String()] = struct{}{} 62 } 63 } 64 65 // Filtered checks if a host uses a subnet that is already in use by a host 66 // that was previously added to the filter. If it is in use, or if the host is 67 // associated with 2 addresses of the same type (e.g. IPv4 and IPv4) or if it 68 // is associated with more than 2 addresses, Filtered will return 'true'. 69 func (af *Filter) Filtered(host modules.NetAddress) bool { 70 // Translate the hostname to one or multiple IPs. If the argument is an IP 71 // address LookupIP will just return that IP. 72 addresses, err := af.resolver.LookupIP(host.Host()) 73 if err != nil { 74 return true 75 } 76 // If the hostname is associated with more than 2 addresses we filter it 77 if len(addresses) > 2 { 78 return true 79 } 80 // If the hostname is associated with 2 addresses of the same type, we 81 // filter it. 82 if (len(addresses) == 2) && (len(addresses[0]) == len(addresses[1])) { 83 return true 84 } 85 // If any of the addresses is blocked we ignore the host. 86 for _, ip := range addresses { 87 // Set the filterRange according to the type of IP address. 88 var filterRange int 89 if ip.To4() != nil { 90 filterRange = IPv4FilterRange 91 } else { 92 filterRange = IPv6FilterRange 93 } 94 95 // Get the subnet. 96 _, ipnet, err := net.ParseCIDR(fmt.Sprintf("%s/%d", ip.String(), filterRange)) 97 if err != nil { 98 continue 99 } 100 // Check if the subnet is in the map. If it is, we filter the host. 101 if _, exists := af.filter[ipnet.String()]; exists { 102 return true 103 } 104 } 105 return false 106 } 107 108 // Reset clears the filter's contents. 109 func (af *Filter) Reset() { 110 af.filter = make(map[string]struct{}) 111 }