class Nslookupot::Resolver

Public Class Methods

new( server: '1.1.1.1', port: 853, hostname: 'cloudflare-dns.com', check_sni: true ) click to toggle source

@param server [String] @param port [Integer] @param hostname [String] @param check_sni [bool]

# File lib/nslookupot/resolver.rb, line 9
def initialize(
  server: '1.1.1.1',
  port: 853,
  hostname: 'cloudflare-dns.com',
  check_sni: true
)
  @server = server
  @port = port
  @hostname = hostname # for SNI
  @check_sni = check_sni
end

Public Instance Methods

resolve_address(name) click to toggle source

@param name [String]

@return [Resolv::IPv4 | Resolv::IPv6]

# File lib/nslookupot/resolver.rb, line 24
def resolve_address(name)
  resolve_resources(name, Resolv::DNS::Resource::IN::A).first.address
end
resolve_addresses(name) click to toggle source

@param name [String]

@return [Array of Resolv::IPv4 | Resolv::IPv6]

# File lib/nslookupot/resolver.rb, line 31
def resolve_addresses(name)
  resolve_resources(name, Resolv::DNS::Resource::IN::A).map(&:address)
end
resolve_resources(name, typeclass) click to toggle source

@param name [String] @param typeclass [Resolv::DNS::Resource::IN constant]

@return [Array of Resolv::DNS::Resource]

# File lib/nslookupot/resolver.rb, line 39
def resolve_resources(name, typeclass)
  sock = gen_sock
  send_msg(sock, name, typeclass)
  msg = recv_msg(sock)
  sock.close

  msg.answer.map(&:last)
end

Private Instance Methods

gen_sock() click to toggle source

@return [OpenSSL::SSL::SSLSocket]

# File lib/nslookupot/resolver.rb, line 76
def gen_sock
  ts = TCPSocket.new(@server, @port)
  ctx = OpenSSL::SSL::SSLContext.new
  ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION
  ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
  ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION \
    if defined? OpenSSL::SSL::TLS1_3_VERSION
  ctx.alpn_protocols = ['dot']
  sock = OpenSSL::SSL::SSLSocket.new(ts, ctx)
  sock.sync_close = true
  if @check_sni
    sock.hostname = @hostname
    sock.connect
    sock.post_connection_check(@hostname)
  else
    sock.connect
  end

  sock
end
recv_msg(sock) click to toggle source

@param sock [OpenSSL::SSL::SSLSocket]

@return [Resolv::DNS::Message]

# File lib/nslookupot/resolver.rb, line 53
def recv_msg(sock)
  # The message is prefixed with a two byte length field which gives the
  # message length, excluding the two byte length field.
  #
  # https://tools.ietf.org/html/rfc1035#section-4.2.2
  l = sock.read(2).unpack1('n')

  Resolv::DNS::Message.decode(sock.read(l))
end
send_msg(sock, name, typeclass) click to toggle source

@param sock [OpenSSL::SSL::SSLSocket] @param name [String] @param typeclass [Resolv::DNS::Resource::IN constant]

# File lib/nslookupot/resolver.rb, line 66
def send_msg(sock, name, typeclass)
  q = Resolv::DNS::Message.new
  q.rd = 1 # recursion desired
  q.add_question(name, typeclass)
  # The message is prefixed with a two byte length field
  message = [q.encode.length].pack('n') + q.encode
  sock.write(message)
end