Lots of updates

This commit is contained in:
Dan Milne
2025-11-11 16:54:52 +11:00
parent 26216da9ca
commit cc8213f87a
41 changed files with 1463 additions and 614 deletions

View File

@@ -133,25 +133,11 @@ class NetworkRange < ApplicationRecord
# Find nearest parent with intelligence data
def parent_with_intelligence
# Use Postgres network operators to find parent ranges directly
cidr_str = network.to_s
if cidr_str.include?('/')
addr_parts = network_address.split('.')
case addr_parts.length
when 4 # IPv4
new_prefix = [prefix_length - 8, 16].max
parent_cidr = "#{addr_parts[0]}.#{addr_parts[1]}.#{addr_parts[2]}.0/#{new_prefix}"
else # IPv6 - skip for now
nil
end
else
nil
end
return nil unless parent_cidr
NetworkRange.where("network <<= ?::inet AND masklen(network) < ?", parent_cidr, prefix_length)
.where.not(asn: nil)
# Find all parent ranges (networks that contain this network)
# and look for any with intelligence data, ordered by specificity
NetworkRange.where("?::inet <<= network", network.to_s)
.where("masklen(network) < ?", prefix_length)
.where("(asn IS NOT NULL OR company IS NOT NULL OR country IS NOT NULL OR is_datacenter = true OR is_vpn = true OR is_proxy = true)")
.order("masklen(network) DESC")
.first
end
@@ -238,6 +224,28 @@ class NetworkRange < ApplicationRecord
self.additional_data = hash.to_json
end
# Network data accessors for different data sources
# network_data is a JSONB column with namespaced data:
# {
# geolite: {...}, # MaxMind GeoLite2 data
# ipapi: {...}, # IPAPI.is enrichment data
# abuseipdb: {...}, # Future: AbuseIPDB data
# shodan: {...} # Future: Shodan data
# }
def network_data_for(source)
network_data&.dig(source.to_s) || {}
end
def set_network_data(source, data)
self.network_data ||= {}
self.network_data[source.to_s] = data
end
# Check if we have network data from a specific source
def has_network_data_from?(source)
network_data&.key?(source.to_s) && network_data[source.to_s].present?
end
# String representations
def to_s
cidr
@@ -267,6 +275,19 @@ class NetworkRange < ApplicationRecord
rules.enabled.where("expires_at IS NULL OR expires_at > ?", Time.current)
end
# Check if this network range needs WAF policy evaluation
# Returns true if:
# - Never been evaluated, OR
# - Any WafPolicy has been updated since last evaluation
def needs_policy_evaluation?
return true if policies_evaluated_at.nil?
latest_policy_update = WafPolicy.maximum(:updated_at)
return false if latest_policy_update.nil? # No policies exist
policies_evaluated_at < latest_policy_update
end
private
def set_default_source