Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/rex/proto/dns/static_hostnames.rb
Views: 11704
# -*- coding: binary -*-12require 'rex/socket'3require 'forwardable'45module Rex6module Proto7module DNS8##9# This class manages statically defined hostnames for DNS resolution where each name is a mapping to an IPv4 and or10# an IPv6 address. A single hostname can only map to one address of each family.11##12class StaticHostnames13extend Forwardable1415def_delegators :@hostnames, :each, :each_with_index, :length, :empty?, :sort_by1617# @param [Hash<String, IPAddr>] hostnames The hostnames to IP address mappings to initialize with.18def initialize(hostnames: nil)19@hostnames = {}20if hostnames21hostnames.each do |hostname, ip_address|22add(hostname, ip_address)23end24end25end2627# Locate and parse a hosts file on the system. Only the first hostname to IP address definition is used which28# replicates the behavior of /etc/hosts on Linux. Loaded definitions are merged with existing definitions.29def parse_hosts_file30path = %w[31%WINDIR%\system32\drivers\etc\hosts32/etc/hosts33/data/data/com.termux/files/usr/etc/hosts34].find do |path|35path = File.expand_path(path)36File.file?(path) && File.readable?(path)37end38return unless path3940path = File.expand_path(path)41::IO.foreach(path) do |line|42words = line.split43next unless words.length > 1 && Rex::Socket.is_ip_addr?(words.first)4445ip_address = IPAddr.new(words.shift)46words.each do |hostname|47add(hostname, ip_address)48end49end50end5152# Get an IP address of the specified type for the hostname. Only the first address is returned in cases where53# multiple addresses are defined.54#55# @param [String] hostname The hostname to retrieve an address for.56# @param [Integer] type The family of address to return represented as a DNS type (either A or AAAA).57# @return Returns the IP address if it was found, otherwise nil.58# @rtype [IPAddr, nil]59def get1(hostname, type = Dnsruby::Types::A)60get(hostname, type).first61end6263# Get all IP addresses of the specified type for the hostname.64#65# @param [String] hostname The hostname to retrieve an address for.66# @param [Integer] type The family of address to return represented as a DNS type (either A or AAAA).67# @return Returns an array of IP addresses.68# @rtype [Array<IPAddr>]69def get(hostname, type = Dnsruby::Types::A)70hostname = hostname.downcase71@hostnames.fetch(hostname, {}).fetch(type, []).dup72end7374# Add an IP address for the specified hostname.75#76# @param [String] hostname The hostname whose IP address is being defined.77# @param [IPAddr, String] ip_address The IP address that is being defined for the hostname. If this value is a78# string, it will be converted to an IPAddr instance.79def add(hostname, ip_address)80unless self.class.is_valid_hostname?(hostname)81# it is important to validate the hostname because assumptions about what characters it may contain are made82# when saving and loading it from the configuration83raise ::ArgumentError.new("Invalid hostname: #{hostname}")84end8586ip_address = IPAddr.new(ip_address) if ip_address.is_a?(String) && Rex::Socket.is_ip_addr?(ip_address)8788hostname = hostname.downcase.delete_suffix('.')89this_host = @hostnames.fetch(hostname, {})90if ip_address.family == ::Socket::AF_INET91type = Dnsruby::Types::A92else93type = Dnsruby::Types::AAAA94end95this_type = this_host.fetch(type, [])96this_type << ip_address unless this_type.include?(ip_address)97this_host[type] = this_type98@hostnames[hostname] = this_host99nil100end101102# Delete an IP address for the specified hostname.103#104# @param [String] hostname The hostname whose IP address is being undefined.105# @param [IPAddr, String] ip_address The IP address that is being undefined. If this value is a string, it will be106# converted to an IPAddr instance.107def delete(hostname, ip_address)108ip_address = IPAddr.new(ip_address) if ip_address.is_a?(String) && Rex::Socket.is_ip_addr?(ip_address)109if ip_address.family == ::Socket::AF_INET110type = Dnsruby::Types::A111else112type = Dnsruby::Types::AAAA113end114115hostname = hostname.downcase116this_host = @hostnames.fetch(hostname, {})117this_type = this_host.fetch(type, [])118this_type.delete(ip_address)119if this_type.empty?120this_host.delete(type)121else122this_host[type] = this_type123end124if this_host.empty?125@hostnames.delete(hostname)126else127@hostnames[hostname] = this_host128end129130nil131end132133# Delete all hostname to IP address definitions.134def flush135@hostnames.clear136end137138def self.is_valid_hostname?(name)139# check if it appears to be a fully qualified domain name, e.g. www.metasploit.com140return true if Rex::Socket.is_name?(name)141142# check if it appears to at least be a valid hostname, e.g. localhost143return true if (name =~ /^([a-z0-9][a-z0-9\-]{0,61})?[a-z0-9]$/i) && (name =~ /\s/).nil?144145false146end147end148end149end150end151152153