Find supernets, don't create them
This commit is contained in:
@@ -517,41 +517,53 @@ validate :targets_must_be_array
|
||||
country = network_range.country || network_range.inherited_intelligence[:country]
|
||||
return network_range unless country
|
||||
|
||||
# Walk up from current prefix to /8 (IPv4) or /32 to /1 (IPv6)
|
||||
current_prefix = network_range.prefix_length
|
||||
max_prefix = network_range.ipv4? ? 8 : 1
|
||||
# Check if this network has IPAPI data with a larger CIDR (asn.route or ipapi_returned_cidr)
|
||||
ipapi_cidr = network_range.network_data&.dig('ipapi', 'asn', 'route') ||
|
||||
network_range.network_data&.dig('ipapi_returned_cidr')
|
||||
|
||||
current_prefix.step(-1, -1).each do |prefix|
|
||||
break if prefix < max_prefix
|
||||
|
||||
candidate = network_range.find_or_create_ancestor_at_prefix(prefix)
|
||||
# Check if candidate has geo data (either direct or inherited)
|
||||
candidate_country = candidate.country || (candidate.persisted? ? candidate.inherited_intelligence[:country] : nil)
|
||||
|
||||
# For virtual (unpersisted) ancestors, we need to check if any existing records in that range have the country
|
||||
if candidate_country.nil? && !candidate.persisted?
|
||||
# Query database to see if networks in this range have the same country
|
||||
country_check = NetworkRange.where("network <<= ?", candidate.cidr)
|
||||
.where.not(country: nil)
|
||||
.select(:country)
|
||||
.distinct
|
||||
# If all networks in this range have the same country, we can use it
|
||||
if country_check.count == 1 && country_check.first.country == country
|
||||
candidate_country = country
|
||||
if ipapi_cidr && ipapi_cidr != network_range.cidr
|
||||
# IPAPI returned a larger network - use it if it exists
|
||||
existing = NetworkRange.find_by(network: ipapi_cidr)
|
||||
if existing
|
||||
existing_country = existing.country || existing.inherited_intelligence[:country]
|
||||
if existing_country == country
|
||||
Rails.logger.debug "Using IPAPI CIDR #{existing.cidr} instead of #{network_range.cidr} (both #{country})"
|
||||
return existing
|
||||
end
|
||||
end
|
||||
|
||||
# If ancestor has same country, use it (persist if virtual)
|
||||
if candidate_country == country
|
||||
if !candidate.persisted?
|
||||
candidate.save!
|
||||
Rails.logger.info "Created ancestor network range #{candidate.cidr} for country #{country}"
|
||||
else
|
||||
# Create the IPAPI network range if it doesn't exist
|
||||
begin
|
||||
ipapi_network = NetworkRange.create!(
|
||||
network: ipapi_cidr,
|
||||
source: 'inherited',
|
||||
country: country
|
||||
)
|
||||
Rails.logger.info "Created IPAPI network range #{ipapi_cidr} for country #{country}"
|
||||
return ipapi_network
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
# Race condition - another process created it
|
||||
existing = NetworkRange.find_by(network: ipapi_cidr)
|
||||
return existing || network_range
|
||||
end
|
||||
Rails.logger.debug "Expanded #{network_range.cidr} to #{candidate.cidr} (both #{country})"
|
||||
return candidate
|
||||
end
|
||||
end
|
||||
|
||||
# Fallback: Look for existing parent networks with IPAPI data and same country
|
||||
# Query for all networks that contain this network and have IPAPI data
|
||||
parent_with_ipapi = NetworkRange.where(
|
||||
"?::inet << network", network_range.cidr
|
||||
).where(
|
||||
"network_data ? 'ipapi' AND " \
|
||||
"network_data -> 'ipapi' ->> 'location' ->> 'country_code' = ?",
|
||||
country
|
||||
).order("masklen(network) DESC").first
|
||||
|
||||
if parent_with_ipapi
|
||||
Rails.logger.debug "Found existing IPAPI parent #{parent_with_ipapi.cidr} for #{network_range.cidr} (both #{country})"
|
||||
return parent_with_ipapi
|
||||
end
|
||||
|
||||
# No expansion possible - use original network
|
||||
network_range
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user