Project

General

Profile

Download (3.37 KB) Statistics
| Branch: | Tag: | Revision:
require "proxy/dns"
require 'resolv'
require 'checks'
require 'rubygems' if USE_GEMS
require 'win32/open3'

module Proxy::DNS
class Dnscmd < Record

include Proxy::Log
include Proxy::Util
attr_reader :resolver

def initialize options = {}
super(options)
end

# create({ :fqdn => "node01.lab", :value => "192.168.100.2"}
# create({ :fqdn => "node01.lab", :value => "3.100.168.192.in-addr.arpa",
# :type => "PTR"}
def create
@resolver = Resolv::DNS.new(:nameserver => @server)
case @type
when "A"
if ip = dns_find(@fqdn)
raise(Proxy::DNS::Collision, "#{@fqdn} is already used by #{ip}") unless ip == @value
else
zone = @fqdn.sub(/[^.]+./,'')
msg = "Added DNS entry #{@fqdn} => #{@value}"
cmd = "/RecordAdd #{zone} #{@fqdn}. A #{@value}"
execute(cmd, msg)
end
when "PTR"
if name = dns_find(@value)
raise(Proxy::DNS::Collision, "#{@value} is already used by #{name}") unless name == @fqdn
else
# TODO: determine reverse zone names, #4025
return true
end
end
end

# remove({ :fqdn => "node01.lab", :value => "192.168.100.2"}
# remove({ :fqdn => "node01.lab", :value => "3.100.168.192.in-addr.arpa"}
def remove
case @type
when "A"
zone = @fqdn.sub(/[^.]+./,'')
msg = "Removed DNS entry #{@fqdn} => #{@value}"
cmd = "/RecordDelete #{zone} #{@fqdn}. A /f"
execute(cmd, msg)
when "PTR"
# TODO: determine reverse zone names, #4025
return true
end
end

private

def execute cmd, msg=nil, error_only=false
tsecs = 5
response = nil
interpreter = SETTINGS.x86_64 ? 'c:\windows\sysnative\cmd.exe' : 'c:\windows\system32\cmd.exe'
command = interpreter + ' /c c:\Windows\System32\dnscmd.exe ' + "#{@server} #{cmd}"

std_in = std_out = std_err = nil
begin
timeout(tsecs) do
logger.debug "executing: #{command}"
std_in, std_out, std_err = Open3.popen3(command)
response = std_out.readlines
response += std_err.readlines
end
rescue TimeoutError
raise Proxy::DNS::Error.new("dnscmd did not respond within #{tsecs} seconds")
ensure
std_in.close unless std_in.nil?
std_out.close unless std_in.nil?
std_err.close unless std_in.nil?
end
report msg, response, error_only
end

def report msg, response, error_only
if response.grep(/completed successfully/).empty?
logger.error "Dnscmd failed:\n" + response.join("\n")
msg.sub! /Removed/, "remove"
msg.sub! /Added/, "add"
match = ""
msg = "Failed to #{msg}"
raise Proxy::DNS::Error.new(msg)
else
logger.info msg unless error_only
end
rescue Proxy::DNS::Error
raise
rescue
logger.error "Dnscmd failed:\n" + (response.is_a?(Array) ? response.join("\n") : "Response was not an array! #{response}")
raise Proxy::DNS::Error.new("Unknown error while processing '#{msg}'")
end

def dns_find key
if match = key.match(/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/)
resolver.getname(match[1..4].reverse.join(".")).to_s
else
resolver.getaddress(key).to_s
end
rescue Resolv::ResolvError
false
end
end
end
(2-2/5)