# # Copyright (c) 2006-2021 Hal Brodigan (postmodern.mod3 at gmail.com) # # This file is part of ronin. # # Ronin is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ronin 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ronin. If not, see . # require 'ronin/extensions/ip_addr' require 'ronin/extensions/resolv' require 'ronin/model/importable' require 'ronin/address' require 'ronin/host_name' require 'ipaddr' module Ronin # # Represents IP addresses that can be stored in the {Database}. # class IPAddress < Address include Model::Importable # The IP Address property :address, IPAddress, :required => true, :unique => true # Type of the address property :version, Integer, :set => [4, 6], :default => lambda { |ip_addr,version| if ip_addr.address if ip_addr.address.ipv6? then 6 else 4 end end } # The MAC Addresses associations has 0..n, :ip_address_mac_addresses, :model => 'IPAddressMACAddress' # The MAC Addresses associated with the IP Address has 0..n, :mac_addresses, :through => :ip_address_mac_addresses, :model => 'MACAddress' # The host-names that the IP Address serves has 0..n, :host_name_ip_addresses, :model => 'HostNameIPAddress' # The host-names associated with the IP Address has 0..n, :host_names, :through => :host_name_ip_addresses # Open ports of the host has 0..n, :open_ports # Ports of the host has 0..n, :ports, :through => :open_ports # Any OS guesses against the IP Address has 0..n, :os_guesses, :model => 'OSGuess' # Any OSes that the IP Address might be running has 0..n, :oses, :through => :os_guesses, :model => 'OS', :via => :os # # Extracts and parses IP addresses from text. # # @param [String] text # The text to parse. # # @param [Symbol, Integer] version # Specifies whether to parse IPv4 or IPv6 addresses. # # @yield [ip] # The given block will be passed each extracted IP address. # # @yieldparam [IPAddress] ip # An extracted IP Address from the text. # # @see https://ronin-rb.dev/docs/ronin-support/IPAddr.html#extract-class_method # # @since 1.3.0 # # @api public # def self.extract(text,version=nil) return enum_for(__method__,text,version).to_a unless block_given? IPAddr.extract(text,version) do |ip| yield parse(ip) end return nil end # # Searches for all IPv4 addresses. # # @return [Array] # The IPv4 addresses. # # @since 1.0.0 # # @api public # def self.v4 all(:version => 4) end # # Searches for all IPv6 addresses. # # @return [Array] # The IPv6 addresses. # # @since 1.0.0 # # @api public # def self.v6 all(:version => 6) end # # Searches for all IP addresses associated with specific MAC addresses. # # @param [Array, String] macs # The MAC address(es) to search for. # # @return [Array] # The matching IP addresses. # # @since 1.0.0 # # @api public # def self.with_macs(macs) all('mac_addresses.address' => macs) end # # Searches for IP addresses associated with the given host names. # # @param [Array, String] names # The host name(s) to search for. # # @return [Array] # The matching IP addresses. # # @since 1.0.0 # # @api public # def self.with_hosts(names) all('host_names.address' => names) end # # Searches for IP addresses with the given open ports. # # @param [Array, Integer] numbers # The port number(s) to search for. # # @return [Array] # The matching IP addresses. # # @since 1.0.0 # # @api public # def self.with_ports(numbers) all('ports.number' => numbers) end # # Looks up the host name to multiple IP addresses. # # @param [String] name # The host name to look up. # # @param [String] nameserver # Optional nameserver to query. # # @return [Array] # The new or previously saved IP Addresses for the host name. # # @since 1.0.0 # # @api public # def self.lookup(name,nameserver=nil) host = HostName.first_or_new(:address => name) resolver = Resolv.resolver(nameserver) ips = begin resolver.getaddresses(name) rescue [] end ips.map! do |addr| IPAddress.first_or_create( :address => addr, :host_names => [host] ) end return ips end # # Performs a reverse lookup on the IP address. # # @param [String] nameserver # Optional nameserver to query. # # @return [Array] # The host-names associated with the IP Address. # # @since 1.0.0 # # @api public # def lookup!(nameserver=nil) resolver = Resolv.resolver(nameserver) hosts = begin resolver.getnames(self.address.to_s) rescue [] end hosts.map! do |name| HostName.first_or_create( :address => name, :ip_addresses => [self] ) end return hosts end # # The MAC Address that was most recently used by the IP Address. # # @return [MacAddress] # The MAC Address that most recently used the IP Address. # # @since 1.0.0 # # @api public # def recent_mac_address self.ip_address_mac_addresses.all( :order => [:created_at.desc] ).mac_addresses.first end # # The host-name that was most recently used by the IP Address. # # @return [HostName] # The host-name that most recently used by the IP Address. # # @since 1.0.0 # # @api public # def recent_host_name self.host_name_ip_addresses.all( :order => [:created_at.desc] ).host_names.first end # # The Operating System that was most recently guessed for the IP # Address. # # @return [OS] # The Operating System that most recently was guessed. # # @since 1.0.0 # # @api public # def recent_os_guess self.os_guesses.all(:order => [:created_at.desc]).oses.first end # # Determines when the IP address was last scanned. # # @return [Time, nil] # The time the IP address was last scanned at. # # @since 1.0.0 # # @api public # def last_scanned_at last_scanned_port = self.open_ports.first( :order => [:last_scanned_at.desc] ) return last_scanned_port.last_scanned_at if last_scanned_port end # # Converts the address to an IP address object. # # @return [IPAddr] # The IPAddr object representing either the IPv4 or IPv6 address. # # @since 1.0.0 # # @api public # def to_ip self.address end # # Converts the address to an Integer. # # @return [Integer] # The network representation of the IP address. # # @since 1.0.0 # # @api public # def to_i self.address.to_i end end end