# 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' require 'ronin/db/model/importable' require 'ronin/db/model/last_scanned_at' require 'active_record' require 'uri/rfc2396_parser' require 'strscan' module Ronin module DB # # Represents host names and their associated {IPAddress IP addresses}. # class HostName < ActiveRecord::Base include Model include Model::Importable include Model::LastScannedAt # @!attribute [rw] id # The primary ID of the host name. # # @return [Integer] attribute :id, :integer # @!attribute [rw] name # The address of the host name. # # @return [String] attribute :name, :string validates :name, presence: true, uniqueness: true, length: {maximum: 255}, format: { with: /\A#{URI::RFC2396_REGEXP::PATTERN::HOSTNAME}\z/, message: 'Must be a valid host-name' } # @!attribute [rw] created_at # When the host name was first created. # # @return [Time] attribute :created_at, :datetime # @!attribute [rw] host_name_ip_addresses # The IP Address associations. # # @return [Array] has_many :host_name_ip_addresses, dependent: :destroy, class_name: 'HostNameIPAddress' # @!attribute [rw] ip_addresses # The IP Addresses that host the host name. # # @return [Array] has_many :ip_addresses, through: :host_name_ip_addresses, class_name: 'IPAddress' # @!attribute [rw] open_ports # The open ports of the host. # # @return [Array] has_many :open_ports, through: :ip_addresses # @!attribute [rw] ports # The ports of the host. # # @return [Array] has_many :ports, through: :ip_addresses # @!attribute [rw] email_addresses # The email addresses that are associated with the host-name. # # @return [Array] has_many :email_addresses, dependent: :destroy # @!attribute [rw] urls # The URLs that point to this host name. # # @return [Array] has_many :urls, dependent: :destroy, class_name: 'URL' # # Looks up the host name. # # @param [String] name # The raw host name. # # @return [HostName, nil] # The found host name. # def self.lookup(name) find_by(name: name) end # # Creates a new host name. # # @param [String] name # The host name. # # @return [HostName] # The created host name record. # def self.import(name) create(name: name) end # # Searches for host names associated with the given IP address(es). # # @param [Array, String] ip # The IP address(es) to search for. # # @return [Array] # The matching host names. # # @api public # def self.with_ip_address(ip) joins(:ip_addresses).where(ip_addresses: {address: ip}) end # # Searches for host names with the given open port(s). # # @param [Array, Integer] number # The open port(s) to search for. # # @return [Array] # The matching host names. # # @api public # def self.with_port_number(number) joins(:ports).where(ports: {number: number}) end # # Searches for all host names under the Top-Level Domain (TLD). # # @param [String] name # The Top-Level Domain (TLD). # # @return [Array] # The matching host names. # # @api public # def self.with_tld(name) name_column = self.arel_table[:name] where(name_column.matches("%.#{sanitize_sql_like(name)}")) end # # Searches for all host names sharing a canonical domain name. # # @param [String] name # The canonical domain name to search for. # # @return [Array] # The matching host names. # # @api public # def self.with_domain(name) name_column = self.arel_table[:name] name = sanitize_sql_like(name) where(name: name).or(where(name_column.matches("%.#{name}"))) end # # The IP Address that was most recently used by the host name. # # @return [IPAddress] # The IP Address that most recently used by the host name. # # @api public # def recent_ip_address self.host_name_ip_addresses.order('created_at DESC').ip_addresses.first end # # Converts the host name to a String. # # @return [String] # The host name. # # @api public # def to_s self.name.to_s end end end end require 'ronin/db/host_name_ip_address' require 'ronin/db/ip_address'