require "time"
module AsyncDNS
class Settings
@local_domain : String?
@reload_period : Time::Span
@last_reload : Time?
property static_hosts, nameservers, local_domain, search_domains, uses_tcp
getter timeout, max_attempts, abs_num_dots
def timeout=(timeout)
raise ArgumentError.new("timeout must be positive") if timeout < 0
@timeout = timeout
end
def max_attempts=(max_attempts)
if max_attempts < 0
raise ArgumentError.new("max_attempts must be positive")
end
@max_attempts = max_attempts
end
def abs_num_dots=(abs_num_dots)
if abs_num_dots < 0
raise ArgumentError.new("abs_num_dots must be positive")
end
@abs_num_dots = abs_num_dots
end
def initialize
@static_hosts = Hash(String, Array(String)).new
@nameservers = [] of String
@search_domains = [] of String
@timeout = Time::Span.new(seconds: 2)
@max_attempts = 3
@abs_num_dots = 1
@uses_tcp = false
@reload_period = Time::Span.new(seconds: 2)
self.reload
end
def reload
{% if flag?(:unix) %}
self.parse_hosts "/etc/hosts"
self.parse_resolv_conf "/etc/resolv.conf"
{% else %}
{% raise "Your OS is not supported by AsyncDNS" %}
{% end %}
end
def parse_hosts(path)
@static_hosts.clear
File.each_line(path, chomp: true) do |line|
pos = line.index('#')
line = line[0, pos] if pos
split = line.split(/[ \t]/, remove_empty: true)
next if split.size < 2
address = split[0]
split[1, split.size - 1].each do |host|
addresses = @static_hosts[host]?
if addresses.nil?
addresses = [] of String
@static_hosts[host] = addresses
end
addresses << address
end
end
end
def parse_resolv_conf(path)
@nameservers.clear
@local_domain = nil
@search_domains.clear
File.each_line(path, chomp: true) do |line|
pos = line.index(/[#;]/)
line = line[0, pos] if pos
split = line.split(/[ \t]/, remove_empty: true)
next if split.size < 2
case split[0]
when "nameserver"
next if split.size != 2
@nameservers << split[1]
when "domain"
next if split.size != 2
@local_domain = split[1]
when "search"
@search_domains = split[1, split.size - 1]
when "options"
split[1, split.size - 1].each { |option| parse_resolv_option(option) }
end
end
end
private def parse_resolv_option(option)
if option.starts_with?("ndots:")
@abs_num_dots = option[6, option.size - 6].to_i
elsif option.starts_with?("timeout:")
@timeout = Time::Span.new(seconds: option[8, option.size - 8].to_i)
elsif option.starts_with?("attempts:")
@max_attempts = option[9, option.size - 9].to_i
elsif option.starts_with?("reload-period:")
@reload_period = Time::Span.new(
seconds: option[14, option.size - 14].to_i)
elsif option = "tcp"
@uses_tcp = true
end
end
end
end