Minor change in the code structure.
This commit is contained in:
parent
519533c02d
commit
1e66262884
4
TODO.md
4
TODO.md
@ -9,6 +9,10 @@ TODO:
|
||||
* (server) Resource Records to add, del and modify
|
||||
* (server) Zone validity on modification
|
||||
* (client) check for errors in the list of possible returned messages
|
||||
- optimization: RAMOnly-DB for connected users
|
||||
1. dnsmanagerd should be able to (un)subscribe for a user data
|
||||
2. avoid requests to AuthD (don't ask for user data twice)
|
||||
3. AuthD should send updates on a user in real-time
|
||||
|
||||
DONE:
|
||||
|
||||
|
39
src/exceptions.cr
Normal file
39
src/exceptions.cr
Normal file
@ -0,0 +1,39 @@
|
||||
module DNSManager
|
||||
class Exception < ::Exception
|
||||
end
|
||||
|
||||
class NotLoggedException < ::Exception
|
||||
end
|
||||
|
||||
class NoOwnershipException < ::Exception
|
||||
end
|
||||
|
||||
class AuthorizationException < ::Exception
|
||||
end
|
||||
|
||||
class UnknownUserException < ::Exception
|
||||
end
|
||||
|
||||
class RRReadOnlyException < ::Exception
|
||||
property domain : String
|
||||
property rr : DNSManager::Storage::Zone::ResourceRecord
|
||||
def initialize(@domain, @rr)
|
||||
end
|
||||
end
|
||||
|
||||
class CannotCheckPermissionsException < ::Exception
|
||||
property uid : UserDataID
|
||||
property resource : String
|
||||
def initialize(@uid, @resource)
|
||||
end
|
||||
end
|
||||
|
||||
class DomainNotFoundException < ::Exception
|
||||
end
|
||||
|
||||
class RRNotFoundException < ::Exception
|
||||
end
|
||||
|
||||
class TokenNotFoundException < ::Exception
|
||||
end
|
||||
end
|
356
src/main.cr
356
src/main.cr
@ -3,309 +3,99 @@ require "option_parser"
|
||||
|
||||
require "ipc"
|
||||
require "ipc/json"
|
||||
|
||||
require "authd"
|
||||
require "baguette-crystal-base"
|
||||
|
||||
require "./config"
|
||||
|
||||
module DNSManager
|
||||
class Exception < ::Exception
|
||||
end
|
||||
class DomainNotFoundException < ::Exception
|
||||
end
|
||||
class UnknownUserException < ::Exception
|
||||
end
|
||||
class RRReadOnlyException < ::Exception
|
||||
property domain : String
|
||||
property rr : DNSManager::Storage::Zone::ResourceRecord
|
||||
def initialize(@domain, @rr)
|
||||
end
|
||||
end
|
||||
class CannotCheckPermissionsException < ::Exception
|
||||
property uid : UserDataID
|
||||
property resource : String
|
||||
def initialize(@uid, @resource)
|
||||
end
|
||||
end
|
||||
class AuthorizationException < ::Exception
|
||||
end
|
||||
class NoOwnershipException < ::Exception
|
||||
end
|
||||
class NotLoggedException < ::Exception
|
||||
end
|
||||
class RRNotFoundException < ::Exception
|
||||
end
|
||||
class TokenNotFoundException < ::Exception
|
||||
end
|
||||
end
|
||||
|
||||
require "./service"
|
||||
|
||||
require "./storage.cr"
|
||||
require "./network.cr"
|
||||
|
||||
# First option parsing, same with all Baguette (service) applications.
|
||||
simulation, no_configuration, configuration_file = Baguette::Configuration.option_parser
|
||||
|
||||
class DNSManager::Service < IPC
|
||||
property configuration : Baguette::Configuration::DNSManager
|
||||
getter storage : DNSManager::Storage
|
||||
getter logged_users : Hash(Int32, AuthD::User::Public)
|
||||
|
||||
property authd : AuthD::Client
|
||||
|
||||
def initialize(@configuration)
|
||||
super()
|
||||
@storage = DNSManager::Storage.new @configuration.storage_directory, @configuration.recreate_indexes
|
||||
|
||||
@logged_users = Hash(Int32, AuthD::User::Public).new
|
||||
|
||||
# TODO: auth service isn't in the FDs pool.
|
||||
# If the service crashes, dnsmanagerd won't know it.
|
||||
@authd = AuthD::Client.new
|
||||
response = authd.login? @configuration.login, @configuration.pass.not_nil!
|
||||
case response
|
||||
when AuthD::Response::Login
|
||||
uid = response.uid
|
||||
token = response.token
|
||||
Baguette::Log.info "Authenticated as #{@configuration.login} #{uid}, token: #{token}"
|
||||
else
|
||||
@authd.close
|
||||
raise "Cannot authenticate to authd with login #{@configuration.login}: #{response}."
|
||||
end
|
||||
|
||||
@storage.dnsmanagerd = self
|
||||
self.timer @configuration.ipc_timer
|
||||
self.service_init @configuration.service_name
|
||||
end
|
||||
|
||||
def get_logged_user(event : IPC::Event)
|
||||
@logged_users[event.fd]?
|
||||
end
|
||||
|
||||
def decode_token(token : String)
|
||||
@authd.decode_token token
|
||||
end
|
||||
|
||||
def is_admin?(uid : UInt32) : Bool
|
||||
perms = check_permissions uid, "*"
|
||||
(perms == AuthD::User::PermissionLevel::Admin)
|
||||
end
|
||||
|
||||
def check_permissions(uid : UInt32, resource : String) : AuthD::User::PermissionLevel
|
||||
response = @authd.check_permission uid, "dnsmanager", resource
|
||||
case response
|
||||
when AuthD::Response::PermissionCheck
|
||||
return response.permission
|
||||
end
|
||||
raise CannotCheckPermissionsException.new uid, resource
|
||||
rescue e
|
||||
Baguette::Log.error "error while checking permissions: #{e}"
|
||||
raise CannotCheckPermissionsException.new uid, resource
|
||||
end
|
||||
|
||||
def assert_permissions!(uid : UInt32, resource : String, perms : AuthD::User::PermissionLevel)
|
||||
if check_permissions(uid, resource) < perms
|
||||
raise AuthorizationException.new
|
||||
end
|
||||
end
|
||||
|
||||
def handle_request(event : IPC::Event)
|
||||
request_start = Time.utc
|
||||
|
||||
array = event.message.not_nil!
|
||||
slice = Slice.new array.to_unsafe, array.size
|
||||
message = IPCMessage::TypedMessage.deserialize slice
|
||||
request = DNSManager.requests.parse_ipc_json message.not_nil!
|
||||
|
||||
if request.nil?
|
||||
raise "unknown request type"
|
||||
end
|
||||
|
||||
reqname = request.class.name.sub /^DNSManager::Request::/, ""
|
||||
|
||||
response = begin
|
||||
request.handle self, event
|
||||
rescue e : AuthorizationException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} authorization error"
|
||||
Response::Error.new "authorization error"
|
||||
rescue e : DomainNotFoundException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} domain not found"
|
||||
Response::DomainNotFound.new
|
||||
rescue e : CannotCheckPermissionsException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} cannot check permissions of user '#{e.uid}' on resource '#{e.resource}'"
|
||||
Response::InsufficientRights.new
|
||||
rescue e : UnknownUserException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} unknown user"
|
||||
Response::UnknownUser.new
|
||||
rescue e : NoOwnershipException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} no ownership error"
|
||||
Response::NoOwnership.new
|
||||
rescue e : NotLoggedException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} user not logged"
|
||||
Response::Error.new "user not logged"
|
||||
rescue e : RRNotFoundException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} RR not found"
|
||||
Response::RRNotFound.new
|
||||
rescue e : TokenNotFoundException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} Token not found"
|
||||
Response::Error.new "token not found"
|
||||
rescue e : RRReadOnlyException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} RR is read only"
|
||||
Response::RRReadOnly.new e.domain, e.rr
|
||||
rescue e # Generic case
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} generic error #{e}"
|
||||
Response::Error.new "generic error"
|
||||
end
|
||||
|
||||
# If clients sent requests with an “id” field, it is copied
|
||||
# in the responses. Allows identifying responses easily.
|
||||
response.id = request.id
|
||||
|
||||
schedule event.fd, response
|
||||
|
||||
duration = Time.utc - request_start
|
||||
|
||||
response_name = response.class.name.sub /^DNSManager::Response::/, ""
|
||||
|
||||
if response.is_a? DNSManager::Response::Error
|
||||
Baguette::Log.warning "fd #{"%4d" % event.fd} (#{duration}) #{reqname} >> #{response_name} (#{response.reason})"
|
||||
else
|
||||
if reqname != "KeepAlive" || @configuration.print_keepalive
|
||||
Baguette::Log.debug "fd #{"%4d" % event.fd} (#{duration}) #{reqname} >> #{response_name}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
Baguette::Log.title "Starting #{@configuration.service_name}"
|
||||
|
||||
self.loop do |event|
|
||||
begin
|
||||
case event.type
|
||||
when LibIPC::EventType::Timer
|
||||
Baguette::Log.debug "Timer." if @configuration.print_ipc_timer
|
||||
|
||||
when LibIPC::EventType::Connection
|
||||
Baguette::Log.debug "New connection!" if @configuration.print_ipc_connection
|
||||
|
||||
when LibIPC::EventType::Disconnection
|
||||
Baguette::Log.debug "Disconnection from #{event.fd}." if @configuration.print_ipc_disconnection
|
||||
@logged_users.delete event.fd
|
||||
|
||||
when LibIPC::EventType::MessageTx
|
||||
Baguette::Log.debug "Message sent to #{event.fd}." if @configuration.print_ipc_message_sent
|
||||
|
||||
when LibIPC::EventType::MessageRx
|
||||
Baguette::Log.debug "Message received from #{event.fd}." if @configuration.print_ipc_message_received
|
||||
handle_request event
|
||||
|
||||
else
|
||||
Baguette::Log.warning "Unhandled IPC event: #{event.class}."
|
||||
if event.responds_to?(:fd)
|
||||
fd = event.fd
|
||||
Baguette::Log.warning "closing #{fd}"
|
||||
close fd
|
||||
@logged_users.delete fd
|
||||
end
|
||||
end
|
||||
|
||||
rescue exception
|
||||
Baguette::Log.error "exception: #{typeof(exception)} - #{exception.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
# DNSManagerd configuration.
|
||||
configuration = if no_configuration
|
||||
Baguette::Log.info "do not load a configuration file."
|
||||
Baguette::Configuration::DNSManager.new
|
||||
else
|
||||
# In case there is a configuration file helping with the parameters.
|
||||
Baguette::Configuration::DNSManager.get(configuration_file) ||
|
||||
Baguette::Configuration::DNSManager.new
|
||||
end
|
||||
|
||||
|
||||
def main
|
||||
|
||||
# First option parsing, same with all Baguette (service) applications.
|
||||
simulation, no_configuration, configuration_file = Baguette::Configuration.option_parser
|
||||
|
||||
# DNSManagerd configuration.
|
||||
configuration = if no_configuration
|
||||
Baguette::Log.info "do not load a configuration file."
|
||||
Baguette::Configuration::DNSManager.new
|
||||
else
|
||||
# In case there is a configuration file helping with the parameters.
|
||||
Baguette::Configuration::DNSManager.get(configuration_file) ||
|
||||
Baguette::Configuration::DNSManager.new
|
||||
OptionParser.parse do |parser|
|
||||
parser.on "-v verbosity-level", "--verbosity level", "Verbosity." do |opt|
|
||||
Baguette::Log.info "Verbosity level: #{opt}"
|
||||
configuration.verbosity = opt.to_i
|
||||
end
|
||||
|
||||
|
||||
OptionParser.parse do |parser|
|
||||
parser.on "-v verbosity-level", "--verbosity level", "Verbosity." do |opt|
|
||||
Baguette::Log.info "Verbosity level: #{opt}"
|
||||
configuration.verbosity = opt.to_i
|
||||
end
|
||||
|
||||
# IPC Service options
|
||||
parser.on "-s service_name", "--service_name service_name", "Service name (IPC)." do |service_name|
|
||||
Baguette::Log.info "Service name: #{service_name}"
|
||||
configuration.service_name = service_name
|
||||
end
|
||||
|
||||
parser.on "-r storage_directory", "--root storage_directory", "Storage directory." do |storage_directory|
|
||||
Baguette::Log.info "Storage directory: #{storage_directory}"
|
||||
configuration.storage_directory = storage_directory
|
||||
end
|
||||
|
||||
parser.on "-l login", "--login login", "DNS manager authd login." do |login|
|
||||
Baguette::Log.info "Authd login for dnsmanager: #{login}"
|
||||
configuration.login = login
|
||||
end
|
||||
|
||||
parser.on "-p pass", "--pass pass", "DNS manager authd pass." do |pass|
|
||||
Baguette::Log.info "Authd pass (not echoed)"
|
||||
configuration.pass = pass
|
||||
end
|
||||
|
||||
parser.on "-h", "--help", "Show this help" do
|
||||
puts parser
|
||||
exit 0
|
||||
end
|
||||
# IPC Service options
|
||||
parser.on "-s service_name", "--service_name service_name", "Service name (IPC)." do |service_name|
|
||||
Baguette::Log.info "Service name: #{service_name}"
|
||||
configuration.service_name = service_name
|
||||
end
|
||||
|
||||
unless File.directory? configuration.template_directory
|
||||
Baguette::Log.warning "template directory '#{configuration.template_directory}' doesn't exist"
|
||||
if File.directory? "./templates"
|
||||
Baguette::Log.info "using template directory './templates'"
|
||||
configuration.template_directory = "./templates"
|
||||
else
|
||||
Baguette::Log.error "tried template directory './templates', but doesn't exist either"
|
||||
Baguette::Log.error "no template directory detected, quitting"
|
||||
exit 1
|
||||
end
|
||||
parser.on "-r storage_directory", "--root storage_directory", "Storage directory." do |storage_directory|
|
||||
Baguette::Log.info "Storage directory: #{storage_directory}"
|
||||
configuration.storage_directory = storage_directory
|
||||
end
|
||||
|
||||
dir = configuration.template_directory
|
||||
accepted_domains = configuration.accepted_domains
|
||||
|
||||
unless accepted_domains
|
||||
Baguette::Log.error "Not even a single accepted domain configured. Probably an error."
|
||||
exit 1
|
||||
parser.on "-l login", "--login login", "DNS manager authd login." do |login|
|
||||
Baguette::Log.info "Authd login for dnsmanager: #{login}"
|
||||
configuration.login = login
|
||||
end
|
||||
|
||||
accepted_domains.each do |domain|
|
||||
template_file = "#{dir}/#{domain}.json"
|
||||
zone = DNSManager::Storage::Zone.from_json File.read "#{template_file}"
|
||||
puts "default zone for #{domain}: #{zone}"
|
||||
rescue e
|
||||
Baguette::Log.error "error reading template #{template_file}: #{e}"
|
||||
exit 1
|
||||
parser.on "-p pass", "--pass pass", "DNS manager authd pass." do |pass|
|
||||
Baguette::Log.info "Authd pass (not echoed)"
|
||||
configuration.pass = pass
|
||||
end
|
||||
|
||||
if simulation
|
||||
pp! configuration
|
||||
parser.on "-h", "--help", "Show this help" do
|
||||
puts parser
|
||||
exit 0
|
||||
end
|
||||
|
||||
unless configuration.pass
|
||||
Baguette::Log.error "no pass found"
|
||||
Baguette::Log.error "Should be present in dnsmanager.yml or via command line arguments (-p)"
|
||||
exit 1
|
||||
end
|
||||
|
||||
service = DNSManager::Service.new configuration
|
||||
service.run
|
||||
end
|
||||
|
||||
main
|
||||
unless File.directory? configuration.template_directory
|
||||
Baguette::Log.warning "template directory '#{configuration.template_directory}' doesn't exist"
|
||||
if File.directory? "./templates"
|
||||
Baguette::Log.info "using template directory './templates'"
|
||||
configuration.template_directory = "./templates"
|
||||
else
|
||||
Baguette::Log.error "tried template directory './templates', but doesn't exist either"
|
||||
Baguette::Log.error "no template directory detected, quitting"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
dir = configuration.template_directory
|
||||
accepted_domains = configuration.accepted_domains
|
||||
|
||||
unless accepted_domains
|
||||
Baguette::Log.error "Not even a single accepted domain configured. Probably an error."
|
||||
exit 1
|
||||
end
|
||||
|
||||
accepted_domains.each do |domain|
|
||||
template_file = "#{dir}/#{domain}.json"
|
||||
zone = DNSManager::Storage::Zone.from_json File.read "#{template_file}"
|
||||
puts "default zone for #{domain}: #{zone}"
|
||||
rescue e
|
||||
Baguette::Log.error "error reading template #{template_file}: #{e}"
|
||||
exit 1
|
||||
end
|
||||
|
||||
if simulation
|
||||
pp! configuration
|
||||
exit 0
|
||||
end
|
||||
|
||||
unless configuration.pass
|
||||
Baguette::Log.error "no pass found"
|
||||
Baguette::Log.error "Should be present in dnsmanager.yml or via command line arguments (-p)"
|
||||
exit 1
|
||||
end
|
||||
|
||||
service = DNSManager::Service.new configuration
|
||||
service.run
|
||||
|
172
src/service.cr
172
src/service.cr
@ -1,5 +1,175 @@
|
||||
require "ipc"
|
||||
|
||||
# Useful to enable the client to be built.
|
||||
require "baguette-crystal-base"
|
||||
require "./config"
|
||||
require "./exceptions"
|
||||
|
||||
class DNSManager::Service < IPC
|
||||
property configuration : Baguette::Configuration::DNSManager
|
||||
getter storage : DNSManager::Storage
|
||||
getter logged_users : Hash(Int32, AuthD::User::Public)
|
||||
|
||||
property authd : AuthD::Client
|
||||
|
||||
def initialize(@configuration)
|
||||
super()
|
||||
@storage = DNSManager::Storage.new @configuration.storage_directory, @configuration.recreate_indexes
|
||||
|
||||
@logged_users = Hash(Int32, AuthD::User::Public).new
|
||||
|
||||
# TODO: auth service isn't in the FDs pool.
|
||||
# If the service crashes, dnsmanagerd won't know it.
|
||||
@authd = AuthD::Client.new
|
||||
response = authd.login? @configuration.login, @configuration.pass.not_nil!
|
||||
case response
|
||||
when AuthD::Response::Login
|
||||
uid = response.uid
|
||||
token = response.token
|
||||
Baguette::Log.info "Authenticated as #{@configuration.login} #{uid}, token: #{token}"
|
||||
else
|
||||
@authd.close
|
||||
raise "Cannot authenticate to authd with login #{@configuration.login}: #{response}."
|
||||
end
|
||||
|
||||
@storage.dnsmanagerd = self
|
||||
self.timer @configuration.ipc_timer
|
||||
self.service_init @configuration.service_name
|
||||
end
|
||||
|
||||
def get_logged_user(event : IPC::Event)
|
||||
@logged_users[event.fd]?
|
||||
end
|
||||
|
||||
def decode_token(token : String)
|
||||
@authd.decode_token token
|
||||
end
|
||||
|
||||
def is_admin?(uid : UInt32) : Bool
|
||||
perms = check_permissions uid, "*"
|
||||
(perms == AuthD::User::PermissionLevel::Admin)
|
||||
end
|
||||
|
||||
def check_permissions(uid : UInt32, resource : String) : AuthD::User::PermissionLevel
|
||||
response = @authd.check_permission uid, "dnsmanager", resource
|
||||
case response
|
||||
when AuthD::Response::PermissionCheck
|
||||
return response.permission
|
||||
end
|
||||
raise CannotCheckPermissionsException.new uid, resource
|
||||
rescue e
|
||||
Baguette::Log.error "error while checking permissions: #{e}"
|
||||
raise CannotCheckPermissionsException.new uid, resource
|
||||
end
|
||||
|
||||
def assert_permissions!(uid : UInt32, resource : String, perms : AuthD::User::PermissionLevel)
|
||||
if check_permissions(uid, resource) < perms
|
||||
raise AuthorizationException.new
|
||||
end
|
||||
end
|
||||
|
||||
def handle_request(event : IPC::Event)
|
||||
request_start = Time.utc
|
||||
|
||||
array = event.message.not_nil!
|
||||
slice = Slice.new array.to_unsafe, array.size
|
||||
message = IPCMessage::TypedMessage.deserialize slice
|
||||
request = DNSManager.requests.parse_ipc_json message.not_nil!
|
||||
|
||||
if request.nil?
|
||||
raise "unknown request type"
|
||||
end
|
||||
|
||||
reqname = request.class.name.sub /^DNSManager::Request::/, ""
|
||||
|
||||
response = begin
|
||||
request.handle self, event
|
||||
rescue e : AuthorizationException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} authorization error"
|
||||
Response::Error.new "authorization error"
|
||||
rescue e : DomainNotFoundException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} domain not found"
|
||||
Response::DomainNotFound.new
|
||||
rescue e : CannotCheckPermissionsException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} cannot check permissions of user '#{e.uid}' on resource '#{e.resource}'"
|
||||
Response::InsufficientRights.new
|
||||
rescue e : UnknownUserException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} unknown user"
|
||||
Response::UnknownUser.new
|
||||
rescue e : NoOwnershipException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} no ownership error"
|
||||
Response::NoOwnership.new
|
||||
rescue e : NotLoggedException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} user not logged"
|
||||
Response::Error.new "user not logged"
|
||||
rescue e : RRNotFoundException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} RR not found"
|
||||
Response::RRNotFound.new
|
||||
rescue e : TokenNotFoundException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} Token not found"
|
||||
Response::Error.new "token not found"
|
||||
rescue e : RRReadOnlyException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} RR is read only"
|
||||
Response::RRReadOnly.new e.domain, e.rr
|
||||
rescue e # Generic case
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} generic error #{e}"
|
||||
Response::Error.new "generic error"
|
||||
end
|
||||
|
||||
# If clients sent requests with an “id” field, it is copied
|
||||
# in the responses. Allows identifying responses easily.
|
||||
response.id = request.id
|
||||
|
||||
schedule event.fd, response
|
||||
|
||||
duration = Time.utc - request_start
|
||||
|
||||
response_name = response.class.name.sub /^DNSManager::Response::/, ""
|
||||
|
||||
if response.is_a? DNSManager::Response::Error
|
||||
Baguette::Log.warning "fd #{"%4d" % event.fd} (#{duration}) #{reqname} >> #{response_name} (#{response.reason})"
|
||||
else
|
||||
if reqname != "KeepAlive" || @configuration.print_keepalive
|
||||
Baguette::Log.debug "fd #{"%4d" % event.fd} (#{duration}) #{reqname} >> #{response_name}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
Baguette::Log.title "Starting #{@configuration.service_name}"
|
||||
|
||||
self.loop do |event|
|
||||
begin
|
||||
case event.type
|
||||
when LibIPC::EventType::Timer
|
||||
Baguette::Log.debug "Timer." if @configuration.print_ipc_timer
|
||||
|
||||
when LibIPC::EventType::Connection
|
||||
Baguette::Log.debug "New connection!" if @configuration.print_ipc_connection
|
||||
|
||||
when LibIPC::EventType::Disconnection
|
||||
Baguette::Log.debug "Disconnection from #{event.fd}." if @configuration.print_ipc_disconnection
|
||||
@logged_users.delete event.fd
|
||||
|
||||
when LibIPC::EventType::MessageTx
|
||||
Baguette::Log.debug "Message sent to #{event.fd}." if @configuration.print_ipc_message_sent
|
||||
|
||||
when LibIPC::EventType::MessageRx
|
||||
Baguette::Log.debug "Message received from #{event.fd}." if @configuration.print_ipc_message_received
|
||||
handle_request event
|
||||
|
||||
else
|
||||
Baguette::Log.warning "Unhandled IPC event: #{event.class}."
|
||||
if event.responds_to?(:fd)
|
||||
fd = event.fd
|
||||
Baguette::Log.warning "closing #{fd}"
|
||||
close fd
|
||||
@logged_users.delete fd
|
||||
end
|
||||
end
|
||||
|
||||
rescue exception
|
||||
Baguette::Log.error "exception: #{typeof(exception)} - #{exception.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -71,6 +71,9 @@ class DNSManager::Storage
|
||||
end
|
||||
end
|
||||
|
||||
# Generate Bind9 zone files.
|
||||
# The file is written in a temporary file then moved, enabling safe manipulation of the file
|
||||
# since its content always will be consistent even if not up-to-date.
|
||||
def generate_bind9_zonefile(domain : String) : Nil
|
||||
zone = zone_must_exist! domain
|
||||
|
||||
@ -87,7 +90,8 @@ class DNSManager::Storage
|
||||
File.rename filename_wip, filename_final
|
||||
end
|
||||
|
||||
# Only an admin can access this function.
|
||||
# Request to generate a zone file.
|
||||
# Only an admin can access this function, so there is no need to verify user's authorizations a second time.
|
||||
def generate_zonefile(domain : String) : IPC::JSON
|
||||
generate_bind9_zonefile domain
|
||||
Response::Success.new
|
||||
@ -102,6 +106,7 @@ class DNSManager::Storage
|
||||
Response::Success.new
|
||||
end
|
||||
|
||||
# Provides the generated zone file to a user.
|
||||
def get_generated_zonefile(user_id : UserDataID, domain : String) : IPC::JSON
|
||||
zone = zone_must_exist! domain
|
||||
user_should_own! user_id, zone.domain
|
||||
@ -111,8 +116,8 @@ class DNSManager::Storage
|
||||
Response::GeneratedZone.new domain, (String.new io.buffer, io.pos)
|
||||
end
|
||||
|
||||
# Adds a new domain.
|
||||
def new_domain(user_id : UserDataID, domain : String) : IPC::JSON
|
||||
|
||||
accepted_domains = dnsmanagerd.configuration.accepted_domains.not_nil!
|
||||
template_directory = dnsmanagerd.configuration.template_directory
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
require "authd"
|
||||
require "ipc"
|
||||
|
||||
require "../src/client.cr"
|
||||
require "http/server"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user