From b3085eed7814aac702383e56a01323d23ff5734d Mon Sep 17 00:00:00 2001 From: Philippe Pittoli Date: Tue, 29 Jul 2025 12:12:16 +0200 Subject: [PATCH] Delegation (WIP). --- src/storage.cr | 27 +++++---------------------- src/storage/zone.cr | 12 ++++++++++++ src/util.cr | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 22 deletions(-) create mode 100644 src/util.cr diff --git a/src/storage.cr b/src/storage.cr index 425cd97..493a597 100644 --- a/src/storage.cr +++ b/src/storage.cr @@ -4,17 +4,9 @@ require "uuid/json" require "baguette-crystal-base" require "./service.cr" +require "./util.cr" require "dodb" -def safe_write(filename : String, &block) - filename_wip = "#{filename}.wip" - File.open(filename_wip, "w") do |file| - yield file - end - # Rename WIP filename to final file name. - File.rename filename_wip, filename -end - class DNSManager::Storage getter domains : DODB::Storage::Common(Domain) getter domains_by_name : DODB::Trigger::IndexCached(Domain) @@ -461,22 +453,13 @@ class DNSManager::Storage return Response::InvalidDomainName.new unless Zone.is_domain_valid? nameserver1 return Response::InvalidDomainName.new unless Zone.is_domain_valid? nameserver2 - # Wipes the domain from dnsmanager (generated zone file, tokens). - wipe_domain user_id, domain_name - - remove_bind9_zonefile domain_name + # Wipes the zone from dnsmanager (zone db entry, generated zone file, tokens). + wipe_zone user_id, domain_name # Creates the new zone. zone = Zone.new domain_name zone.delegation = Zone::Delegation.new nameserver1, nameserver2 - - filename = "#{@delegationdir}/#{domain_name}" - Baguette::Log.info "New delegation file: #{filename}" - safe_write filename do |file| - zone.to_delegation file - rescue e : NoDelegation - Baguette::Log.error "domain #{domain_name}: trying to delegate but doesn't have delegation parameters" - end + zone.update_delegation @delegationdir # Once the new delegation file has been written, the script generating the (root) zone file must # be informed by touching a file (named "delegation token file" in the source code). @@ -561,7 +544,7 @@ class DNSManager::Storage zone end - # WARNING: this function removes a domain with all its related data (zone file, delegation file, indexes, etc.). + # WARNING: this function removes a zone with all its related data (zone file, delegation file, indexes, etc.). # # RATIONALE: wipe_zone can be used to renew to remove zone-related content (the entry in the zone db, tokens # and generated zone file) while preserving the entry in the domain db. diff --git a/src/storage/zone.cr b/src/storage/zone.cr index fa7f8dd..bc7a927 100644 --- a/src/storage/zone.cr +++ b/src/storage/zone.cr @@ -1,4 +1,5 @@ require "ipaddress" +require "../util.cr" # Domains cannot be parsed using regexes. # Yet, that will be good enough for now. @@ -55,6 +56,17 @@ class DNSManager::Storage::Zone def_clone end + # Update the delegation file. + def update_delegation(delegation_directory : String) + filename = "#{delegation_directory}/#{@domain}" + Baguette::Log.info "New delegation file: #{filename}" + safe_write filename do |file| + to_delegation file + rescue e : NoDelegation + Baguette::Log.error "domain #{domain}: trying to delegate but doesn't have delegation parameters" + end + end + def to_delegation(io : IO) if delegation = @delegation io << "#{@domain}. 1800 IN NS #{delegation.nameserver1}\n" diff --git a/src/util.cr b/src/util.cr new file mode 100644 index 0000000..6d7f78c --- /dev/null +++ b/src/util.cr @@ -0,0 +1,14 @@ +# Writes to a file "safely": a temporary file is generated then the file is moved. +# +# RATIONALE: several problems can occur while writing in a file. +# Using a temporary file prevents database corruption if a writting error occurs. +# Also, moving the temporary file to its final path enables to only read fully-written files +# (once the file is opened the content won't change). +def safe_write(filename : String, &block) + filename_wip = "#{filename}.wip" + File.open(filename_wip, "w") do |file| + yield file + end + # Rename WIP filename to final file name. + File.rename filename_wip, filename +end