class Dyndnsd::Updater::ZoneTransferServer
Constants
- DEFAULT_SERVER_LISTENS
Public Class Methods
new(domain, updater_params)
click to toggle source
@param domain [String] @param updater_params [Hash{String => Object}]
# File lib/dyndnsd/updater/zone_transfer_server.rb, line 15 def initialize(domain, updater_params) @domain = domain @server_listens = self.class.parse_endpoints(updater_params['server_listens'] || DEFAULT_SERVER_LISTENS) @notify_targets = (updater_params['send_notifies'] || []).map { |e| self.class.parse_endpoints([e]) } @zone_rr_ttl = updater_params['zone_ttl'] @zone_nameservers = updater_params['zone_nameservers'].map { |n| Resolv::DNS::Name.create(n) } @zone_email_address = Resolv::DNS::Name.create(updater_params['zone_email_address']) @zone_additional_ips = updater_params['zone_additional_ips'] || [] @server = ZoneTransferServerHelper.new(@server_listens, @domain) # run Async::DNS server in background thread Thread.new do @server.run end end
parse_endpoints(endpoint_list)
click to toggle source
converts into suitable parameter form for Async::DNS::Resolver or Async::DNS::Server
@param endpoint_list [Array<String>] @return [Array{Array{Object}}]
# File lib/dyndnsd/updater/zone_transfer_server.rb, line 90 def self.parse_endpoints(endpoint_list) endpoint_list.map { |addr_string| addr_string.split('@') } .map { |addr_parts| [addr_parts[0], addr_parts[1].to_i || 53] } .map { |addr| [:tcp, :udp].map { |type| [type] + addr } } .flatten(1) end
Public Instance Methods
update(db)
click to toggle source
@param db [Dyndnsd::Database] @return [void]
# File lib/dyndnsd/updater/zone_transfer_server.rb, line 36 def update(db) Helper.span('updater_update') do |span| span.set_attribute('dyndnsd.updater.name', self.class.name&.split('::')&.last || 'None') soa_rr = Resolv::DNS::Resource::IN::SOA.new( @zone_nameservers[0], @zone_email_address, db['serial'], 10_800, # 3h 300, # 5m 604_800, # 1w 3_600 # 1h ) default_options = {ttl: @zone_rr_ttl} # array containing all resource records for an AXFR request in the right order rrs = [] # AXFR responses need to start with zone's SOA RR rrs << [soa_rr, default_options] # return RRs for all of the zone's nameservers @zone_nameservers.each do |ns| rrs << [Resolv::DNS::Resource::IN::NS.new(ns), default_options] end # return A/AAAA RRs for all additional IPv4s/IPv6s for the domain itself @zone_additional_ips.each do |ip| rrs << [create_addr_rr_for_ip(ip), default_options] end # return A/AAAA RRs for the dyndns hostnames db['hosts'].each do |hostname, ips| ips.each do |ip| rrs << [create_addr_rr_for_ip(ip), default_options.merge({name: hostname})] end end # AXFR responses need to end with zone's SOA RR again rrs << [soa_rr, default_options] # point Async::DNS server thread's variable to this new RR array @server.axfr_rrs = rrs # only send DNS NOTIFY if there really was a change if db.changed? send_dns_notify end end end
Private Instance Methods
create_addr_rr_for_ip(ip_string)
click to toggle source
creates correct Resolv::DNS::Resource object for IP address type
@param ip_string [String] @return [Resolv::DNS::Resource::IN::A,Resolv::DNS::Resource::IN::AAAA]
# File lib/dyndnsd/updater/zone_transfer_server.rb, line 103 def create_addr_rr_for_ip(ip_string) ip = IPAddr.new(ip_string).native if ip.ipv6? Resolv::DNS::Resource::IN::AAAA.new(ip.to_s) else Resolv::DNS::Resource::IN::A.new(ip.to_s) end end
send_dns_notify()
click to toggle source
@return [void]
# File lib/dyndnsd/updater/zone_transfer_server.rb, line 116 def send_dns_notify Async::Reactor.run do @notify_targets.each do |notify_target| target = Async::DNS::Resolver.new(notify_target) # assemble DNS NOTIFY message request = Resolv::DNS::Message.new(SecureRandom.random_number(2**16)) request.opcode = Resolv::DNS::OpCode::Notify request.add_question("#{@domain}.", Resolv::DNS::Resource::IN::SOA) _response = target.dispatch_request(request) end end end