GenerateAllZoneFiles + GenerateZoneFile: working as expected.

This commit is contained in:
Philippe Pittoli 2024-02-25 04:13:18 +01:00
parent 5ba3bb2559
commit bd0c3d5fdd
7 changed files with 91 additions and 18 deletions

View File

@ -110,6 +110,12 @@ class DNSManager::Client < IPC
parse_message [ Response::Success ], read parse_message [ Response::Success ], read
end end
def generate_all_zonefiles
request = Request::GenerateAllZoneFiles.new
send_now request
parse_message [ Response::Success ], read
end
# #
# Utils # Utils
# #

View File

@ -35,6 +35,7 @@ class Actions
# Maintenance. # Maintenance.
@the_call["admin-maintenance"] = ->admin_maintenance @the_call["admin-maintenance"] = ->admin_maintenance
@the_call["admin-generate-zonefile"] = ->admin_generate_zonefile @the_call["admin-generate-zonefile"] = ->admin_generate_zonefile
@the_call["admin-generate-all-zonefiles"] = ->admin_generate_all_zonefiles
# Domain operations. # Domain operations.
@the_call["user-domain-add"] = ->user_domain_add @the_call["user-domain-add"] = ->user_domain_add
@ -85,11 +86,17 @@ class Actions
pp! domain pp! domain
pp! @dnsmanagerd.generate_zonefile domain pp! @dnsmanagerd.generate_zonefile domain
rescue e rescue e
puts "error for user_domain_add: #{e.message}" puts "error for generate_zonefile: #{e.message}"
end end
end end
end end
def admin_generate_all_zonefiles
pp! @dnsmanagerd.generate_all_zonefiles
rescue e
puts "error for generate_all_zonefiles: #{e.message}"
end
def user_domain_add def user_domain_add
domains = Context.args.not_nil! domains = Context.args.not_nil!
domains.each do |domain| domains.each do |domain|
@ -236,7 +243,7 @@ def main
logged_message = dnsmanagerd.login token logged_message = dnsmanagerd.login token
case logged_message case logged_message
when DNSManager::Response::Logged when DNSManager::Response::Logged
Baguette::Log.info "logged to dnsmanagerd" Baguette::Log.info "logged to dnsmanagerd as '#{login}'"
Baguette::Log.debug "from logging message, accepted domains:" Baguette::Log.debug "from logging message, accepted domains:"
logged_message.accepted_domains.each do |d| logged_message.accepted_domains.each do |d|
Baguette::Log.debug "- #{d}" Baguette::Log.debug "- #{d}"

View File

@ -106,6 +106,14 @@ def parsing_cli(authd_config : Baguette::Configuration::Auth)
unrecognized_args_to_context_args.call parser, nil, 1 unrecognized_args_to_context_args.call parser, nil, 1
end end
# Generate all zone files.
parser.on("genall", "Generate all zone files.") do
Baguette::Log.info "generate all zone files on the server."
Context.command = "admin-generate-all-zonefiles"
parser.banner = "COMMAND: admin genall"
unrecognized_args_to_context_args.call parser, 0, nil
end
end end
# User section. # User section.

View File

@ -20,8 +20,7 @@ class DNSManager::Request
user = dnsmanagerd.get_logged_user event user = dnsmanagerd.get_logged_user event
return Response::ErrorUserNotLogged.new unless user return Response::ErrorUserNotLogged.new unless user
# This request means serious business. return Response::InsufficientRights.new unless user.admin
# TODO: check for admin.
case @subject case @subject
when Subject::Verbosity when Subject::Verbosity
@ -39,7 +38,25 @@ class DNSManager::Request
end end
DNSManager.requests << Maintenance DNSManager.requests << Maintenance
IPC::JSON.message GenerateZoneFile, 100 do # Generate all zone files.
# TODO: should conveniently skip already generated zones.
IPC::JSON.message GenerateAllZoneFiles, 100 do
def initialize()
end
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
user = dnsmanagerd.get_logged_user event
return Response::ErrorUserNotLogged.new unless user
udata = dnsmanagerd.storage.get_user_data user
return Response::InsufficientRights.new unless udata.admin
dnsmanagerd.storage.generate_all_zonefiles
end
end
DNSManager.requests << GenerateAllZoneFiles
# Force the generation of a zone file.
IPC::JSON.message GenerateZoneFile, 101 do
property domain : String property domain : String
def initialize(@domain) def initialize(@domain)
@ -49,11 +66,9 @@ class DNSManager::Request
user = dnsmanagerd.get_logged_user event user = dnsmanagerd.get_logged_user event
return Response::ErrorUserNotLogged.new unless user return Response::ErrorUserNotLogged.new unless user
return Response::Error.new "unauthorized" unless user.admin udata = dnsmanagerd.storage.get_user_data user
# This request means serious business. return Response::InsufficientRights.new unless udata.admin
# TODO: check for admin. dnsmanagerd.storage.generate_zonefile @domain
Response::Error.new "not implemented"
end end
end end
DNSManager.requests << GenerateZoneFile DNSManager.requests << GenerateZoneFile

View File

@ -10,4 +10,10 @@ class DNSManager::Response
end end
end end
DNSManager.responses << NoOwnership DNSManager.responses << NoOwnership
IPC::JSON.message InsufficientRights, 52 do
def initialize
end
end
DNSManager.responses << InsufficientRights
end end

View File

@ -12,12 +12,19 @@ class DNSManager::Storage
getter zones : DODB::CachedDataBase(Zone) getter zones : DODB::CachedDataBase(Zone)
getter zones_by_domain : DODB::Index(Zone) getter zones_by_domain : DODB::Index(Zone)
getter root : String
getter zonefiledir : String
def initialize(@root : String, reindex : Bool = false) def initialize(@root : String, reindex : Bool = false)
@user_data = DODB::CachedDataBase(UserData).new "#{@root}/user-data" @user_data = DODB::CachedDataBase(UserData).new "#{@root}/user-data"
@user_data_by_uid = @user_data.new_index "uid", &.uid.to_s @user_data_by_uid = @user_data.new_index "uid", &.uid.to_s
@zones = DODB::CachedDataBase(Zone).new "#{@root}/zones" @zones = DODB::CachedDataBase(Zone).new "#{@root}/zones"
@zones_by_domain = @zones.new_index "domain", &.domain @zones_by_domain = @zones.new_index "domain", &.domain
@zonefiledir = "#{@root}/bind9-zones"
# TODO: create the directory
Dir.mkdir_p @zonefiledir
Baguette::Log.info "storage initialized" Baguette::Log.info "storage initialized"
if reindex if reindex
@ -55,6 +62,29 @@ class DNSManager::Storage
user_data user_data
end end
# Only an admin can access this function.
def generate_all_zonefiles() : IPC::JSON
Baguette::Log.info "writing all zone files in #{@zonefiledir}/"
zones.each do |zone|
File.open("#{@zonefiledir}/#{zone.domain}", "w") do |file|
zone.to_bind9 file
end
end
Response::Success.new
end
# Only an admin can access this function.
def generate_zonefile(domain : String) : IPC::JSON
zone = zones_by_domain.get? domain
return Response::DomainNotFound.new unless zone
Baguette::Log.info "writing zone file #{@zonefiledir}/#{zone.domain}"
File.open("#{@zonefiledir}/#{zone.domain}", "w") do |file|
zone.to_bind9 file
end
Response::Success.new
end
def new_domain(accepted_domains : Array(String), def new_domain(accepted_domains : Array(String),
template_directory : String, template_directory : String,
user_id : Int32, user_id : Int32,

View File

@ -97,12 +97,13 @@ class DNSManager::Storage::Zone
end end
def to_bind9(io : IO) def to_bind9(io : IO)
io << "#{name} #{ttl} IN SOA (#{mname} #{rname}\n" # No "name" because the name of the SOA RR is the origin (FQDN).
io << "\t\t#{serial } ; serial\n" io << "@ #{ttl} IN SOA (#{mname} #{rname}\n"
io << "\t\t#{refresh} ; refresh\n" io << "\t\t#{ "%10d" % serial } ; serial\n"
io << "\t\t#{retry } ; retry\n" io << "\t\t#{ "%10d" % refresh} ; refresh\n"
io << "\t\t#{expire } ; expire\n" io << "\t\t#{ "%10d" % retry } ; retry\n"
io << "\t\t#{minttl } ; minttl\n" io << "\t\t#{ "%10d" % expire } ; expire\n"
io << "\t\t#{ "%10d" % minttl } ; minttl\n"
io << "\t)\n" io << "\t)\n"
end end
@ -331,14 +332,14 @@ class DNSManager::Storage::Zone
end end
def to_s(io : IO) def to_s(io : IO)
io << "domain: #{@domain}\n" io << "DOMAIN #{@domain}.\n"
@resources.each do |rr| @resources.each do |rr|
io << rr io << rr
end end
end end
def to_bind9(io : IO) def to_bind9(io : IO)
io << "DOMAIN: #{@domain}\n" io << "$ORIGIN #{@domain}.\n"
@resources.each do |rr| @resources.each do |rr|
rr.to_bind9 io rr.to_bind9 io
end end