# frozen_string_literal: true
#
# ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
#
# Copyright (c) 2022-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# ronin-db-activerecord is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ronin-db-activerecord is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ronin-db-activerecord. If not, see .
#
require 'ronin/db/model'
module Ronin
module DB
#
# Represents an ASN range.
#
class ASN < ActiveRecord::Base
include Model
# @!attribute [rw] id
# The primary key of the ASN range.
#
# @return [Integer]
attribute :id, :integer
# @!attribute [rw] version
# Whether the ASN range represents an IPv4 or IPv6 range.
#
# @return [Integer]
attribute :version, :integer
validates :version, presence: true,
inclusion: {in: [4, 6]}
# @!attribute [rw] range_start
# The starting IP address of the ASN range.
#
# @return [String]
attribute :range_start, :string
validates :range_start, presence: true
# @!attribute [rw] range_end
# The ending IP address of the ASN range.
#
# @return [String]
attribute :range_end, :string
validates :range_end, presence: true
# @!attribute [r] range_start_hton
# The starting IP address of the ASN range, but in network byte-order.
#
# @return [String]
attribute :range_start_hton, :binary
# @!attribute [r] range_end_hton
# The ending IP address of the ASN range, but in network byte-order.
#
# @return [String]
attribute :range_end_hton, :binary
before_save :set_hton
# @!attribute [rw] number
# The ASN number.
#
# @return [Integer]
attribute :number, :integer
validates :number, presence: true,
uniqueness: {scope: [:range_start, :range_end]}
# @!attribute [rw] country_code
# The country code of the ASN.
#
# @return [String]
attribute :country_code, :string
# @!attribute [rw] name
# The organization the ASN is currently assigned to.
#
# @return [String]
attribute :name, :string
#
# Searches for all IPv4 ASNs.
#
# @return [Array]
# The IPv4 ASNs.
#
# @api public
#
def self.v4
where(version: 4)
end
#
# Searches for all IPv6 ASNs.
#
# @return [Array]
# The IPv6 ASNs.
#
# @api public
#
def self.v6
where(version: 6)
end
#
# Searches for all ASNs with the matching AS number.
#
# @param [Integer] number
# The AS number to search for.
#
# @return [Array]
#
def self.with_number(number)
where(number: number)
end
#
# Searches for all ASNs with the matching country code.
#
# @param [String] country_code
# The two letter country code to search for.
#
# @return [Array]
#
def self.with_country_code(country_code)
where(country_code: country_code)
end
#
# Searches for all ASNs with the matching name.
#
# @param [String] name
# The name to search for.
#
# @return [Array]
#
def self.with_name(name)
where(name: name)
end
#
# Queries the ASN that contains the given IP address.
#
# @param [IPAddr, String] ip
#
# @return [ASN, nil]
#
def self.containing_ip(ip)
ip = IPAddr.new(ip) unless ip.kind_of?(IPAddr)
ip_hton = ip.hton
range_start_hton = self.arel_table[:range_start_hton]
range_end_hton = self.arel_table[:range_end_hton]
where(range_start_hton.lteq(ip_hton).and(range_end_hton.gteq(ip_hton))).first
end
#
# @return [IPAddr, nil]
#
def range_start_ipaddr
@range_start_ipaddr ||= if self.range_start
IPAddr.new(self.range_start)
end
end
#
# @return [IPAddr, nil]
#
def range_end_ipaddr
@range_end_ipaddr ||= if self.range_end
IPAddr.new(self.range_end)
end
end
#
# Queries all IP addresses within the ASN IP range.
#
# @return [Array]
#
def ip_addresses
IPAddress.between(range_start,range_end)
end
private
#
# Sets the `range_start_hton` and `range_end_hton` attributes.
#
def set_hton
self.range_start_hton = range_start_ipaddr.hton
self.range_end_hton = range_end_ipaddr.hton
end
end
end
end
require 'ronin/db/ip_address'