Project

General

Profile

« Previous | Next » 

Revision 157c68c9

Added by Marc Dequènes about 15 years ago

  • ID 157c68c922e40f82f4bf567b4139c48cb7eda82a

[evol] implement changing a zone

View differences:

lib/cyborghood/services/dns.rb
require 'fileutils'
module CyborgHood
module Services
class DNS
attr_reader :zone
attr_accessor :content
def initialize(zone)
@zone = zone
@config = Config.instance
@content = nil
# ensure we can find the needed programs (should be handled somewhere else)
ENV['PATH'] = (ENV['PATH'].split(":") + ["/sbin", "/usr/sbin", "/usr/local/sbin"]).uniq.join(":")
end
def read_zone
file = @config.dns.master_zone_pattern.gsub("#ZONE#", @zone)
# TODO: should be checked at startup time
raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: pattern is constant") if file == @config.dns.master_zone_pattern
filename = @config.dns.master_zone_pattern.gsub("#ZONE#", @zone)
# TODO: should be checked at startup time
raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: pattern is constant") if filename == @config.dns.master_zone_pattern
begin
File.read(file)
@content = File.read(filename)
rescue
raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@zone}' cannot be read (nonexistent or lack of permission)")
end
end
def serial
filename = @config.dns.master_zone_pattern.gsub("#ZONE#", @zone)
# TODO: should be checked at startup time
raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: pattern is constant") if filename == @config.dns.master_zone_pattern
case @config.dns.nameserver || :bind
when :bind
output = []
begin
IO.popen("named-checkzone -i none '#{@zone}' #{filename}") do |fp|
output << fp.gets.chomp! until fp.eof?
end
rescue
raise CyberError.new(:unrecoverable, "services/dns", "zone serial for '#{@zone}' could not be found")
end
if $? == 0
serial = nil
output.each do |l|
if l =~ /: loaded serial (\d+)$/
serial = $1
break
end
end
if serial
serial
else
raise CyberError.new(:unrecoverable, "services/dns", "no serial returned")
end
else
nil
end
else
# TODO: should be checked at startup time
raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: unknown nameserver")
end
end
def check_zone_file(filename)
case @config.dns.nameserver || :bind
when :bind
output = []
begin
IO.popen("named-checkzone '#{@zone}' #{filename}") do |fp|
output << fp.gets.chomp! until fp.eof?
end
rescue
raise CyberError.new(:unrecoverable, "services/dns", "zone '#{@zone}' could not be checked")
end
if $? == 0
serial = nil
messages = []
output.each do |l|
next if l == "OK"
if l =~ /: loaded serial (\d+)$/
serial = $1
next
end
messages << l
end
if serial
return {:ok => true, :serial => serial, :warnings => messages}.to_ostruct
else
raise CyberError.new(:unrecoverable, "services/dns", "zone validated but no serial returned")
end
else
return {:ok => false, :errors => messages}.to_ostruct
end
else
# TODO: should be checked at startup time
raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: unknown nameserver")
end
end
def write_zone_from_file(new_zone_filename)
filename = @config.dns.master_zone_pattern.gsub("#ZONE#", @zone)
# TODO: should be checked at startup time
raise CyberError.new(:unrecoverable, "services/dns", "erroneous configuration: pattern is constant") if filename == @config.dns.master_zone_pattern
FileUtils.cp(new_zone_filename, filename)
end
end
end
end
postman
$: << "./lib"
#require 'socket'
#require 'fileutils'
#require 'tempfile'
require 'tempfile'
require 'shellwords'
require 'cyborghood/imap'
require 'cyborghood/mail'
......
ok = false
end
when "SET"
result.message = "Command not yet implemented."
case cmdline.shift.upcase
when "ZONE"
zone = cmdline.shift.downcase
dom = CyborgHood::DnsDomain.new(zone)
logger.info "User requesting zone content for '#{zone}'"
if dom.hosted?
if dom.managed_by? user
logger.info "User is manager of the zone"
srv_dns = CyborgHood::Services::DNS.new(zone)
content_ref = cmdline.shift.downcase
if content_ref =~ /^@(\d+)$/
part_ref = $1.to_i
if (1..refs.size).include? part_ref
part = refs[part_ref]
if part.content_type == "text/plain"
f = Tempfile.new(zone)
f.write(part.body)
f.close
logger.debug "Created temporary zone file '#{f.path}'"
srv_dns = CyborgHood::Services::DNS.new(zone)
current_serial = srv_dns.serial
logger.debug "Current serial: #{current_serial}"
result = srv_dns.check_zone_file(f.path)
if result.ok
logger.debug "New serial: #{result.serial}"
# allow new serial or missing serial (to allow creating a new zone or replacing a broken zone)
if current_serial.nil? or result.serial > current_serial
begin
srv_dns.write_zone_from_file(f.path)
logger.info "zone changed"
rescue
logger.debug "Writing zone file failed"
raise
ensure
f.close!
end
else
logger.info "zone serial is not superior to current serial"
result.message = "Zone serial is not superior to current serial."
f.close!
return result
end
else
logger.info "new zone file is invalid"
result.message = "invalid zone data"
f.close!
return result
end
f.close!
else
logger.info "attachment for zone is not plain text"
result.message = "Attachment has wrong type."
return result
end
else
logger.info "attachement for zone not found"
result.message = "Attachment number not found."
return result
end
else
ok = false
end
else
logger.info "User is not allowed to manage the zone"
result.message = "You are not allowed to manage this zone."
end
else
logger.info "Zone not hosted"
result.message "This zone is not hosted here."
end
else
ok = false
end
else
ok = false
end

Also available in: Unified diff