class AuthDnsCheck::Client

Client for performing authoritative DNS checks

@todo IPv6 not supported

Constants

DEFAULT_TYPES

Default record types for checks like all?

Attributes

default[R]

default resolver for finding authoritative name servers

overrides[R]

authoritative name server overrides

Public Class Methods

new(overrides: {}, default: Resolv::DNS.new("/etc/resolv.conf")) click to toggle source

Initialize a new Client

@param overrides [Hash<String,Array<Resolv::DNS>>] authoritative name server overrides.

Maps domain names to lists of name servers that should override those published for the domain.
The special domain name {Symbol} +:default+ may list the name servers that should override any other domain.

@param default [Resolv::DNS] default resolver for finding authoritative name servers.

Note that this is not the same as +overrides[:default]+.
# File lib/auth_dns_check/client.rb, line 24
def initialize(overrides: {}, default: Resolv::DNS.new("/etc/resolv.conf"))
  @overrides = overrides
  @default = default
end

Public Instance Methods

all?(fqdn, types: DEFAULT_TYPES) click to toggle source

Check authoritative agreement for a name

@param fqdn [String] the name to check @return [Boolean] whether all authoritative agree that fqdn has the same non-empty set of records @raise [Error] if authoritative name servers could not be found @todo Records of types other than A not yet supported

# File lib/auth_dns_check/client.rb, line 35
def all?(fqdn, types: DEFAULT_TYPES)
  non_empty_set = false
  types.all? { |type|
    resources = get_resources(fqdn, type: type)
    resources.all? do |x|
      non_empty_set = true unless x.empty?
      x == resources.first
    end
  } && non_empty_set
end
has_ip?(fqdn, ip) click to toggle source

Check authoritative agreement for the specific address for a name

@param fqdn [String] the name to check @param ip [String] the expected address @return [Boolean] whether all authoritative name servers agree that the only address of name is ip @raise [Error] if authoritative name servers could not be found

# File lib/auth_dns_check/client.rb, line 52
def has_ip?(fqdn, ip)
  answers = get_addresses(fqdn)
  answers.all? do |x|
    x.any? and x.all? { |i| i == ip }
  end
end

Private Instance Methods

authoritatives_for(zone) click to toggle source
# File lib/auth_dns_check/client.rb, line 104
def authoritatives_for(zone)
  overridden_authoritatives_for(zone) || overridden_authoritatives_for(:default) || default_authoritatives_for(zone)
end
default_authoritatives_for(zone) click to toggle source
# File lib/auth_dns_check/client.rb, line 112
def default_authoritatives_for(zone)
  @default.
    getresources(zone, Resolv::DNS::Resource::IN::NS).
    map(&:name).
    map(&:to_s).
    map { |x| @default.getaddresses(x) }.
    flatten.
    map(&:to_s).
    uniq.
    map { |x| Resolv::DNS.new(nameserver: x) }
end
find_zone(fqdn) { |zone| ... } click to toggle source
# File lib/auth_dns_check/client.rb, line 92
def find_zone(fqdn)
  zone = fqdn
  while zone
    auths = yield(zone)
    if auths and auths.any?
      break auths
    else
      _, zone = zone.split(".", 2)
    end
  end
end
get_addresses(fqdn) click to toggle source
# File lib/auth_dns_check/client.rb, line 79
def get_addresses(fqdn)
  get_authoritatives(fqdn).
    map { |x| x.getaddresses(fqdn) }.
    map { |x| x.collect(&:to_s).sort }
end
get_authoritatives(fqdn) click to toggle source
# File lib/auth_dns_check/client.rb, line 85
def get_authoritatives(fqdn)
  find_zone(fqdn) { |zone| overridden_authoritatives_for(zone) } or
    overridden_authoritatives_for(:default) or
    find_zone(fqdn) { |zone| default_authoritatives_for(zone) } or
    raise Error.new("no name servers found for #{fqdn}")
end
get_resources(fqdn, type:) click to toggle source
# File lib/auth_dns_check/client.rb, line 61
def get_resources(fqdn, type:)
  type_class = Resolv::DNS::Resource::IN::const_get(type)
  get_authoritatives(fqdn).
    map { |x| x.getresources(fqdn, type_class) }.
    map { |x| x.collect { |r| resource_to_s(r, type) }.sort }
end
overridden_authoritatives_for(zone) click to toggle source
# File lib/auth_dns_check/client.rb, line 108
def overridden_authoritatives_for(zone)
  @overrides[zone]
end
resource_to_s(r, type) click to toggle source
# File lib/auth_dns_check/client.rb, line 68
def resource_to_s(r, type)
  case type
  when "A"
    r.address.to_s
  when "TXT"
    r.data
  else
    raise "unsupported record type #{type}"
  end
end