Compare commits
10 commits
30d5f1d4a3
...
a13d9e8e84
| Author | SHA1 | Date | |
|---|---|---|---|
| a13d9e8e84 | |||
| 7f6a04e89e | |||
| f92cadf634 | |||
| d9da42eeeb | |||
| 96eb605682 | |||
| c476d89f69 | |||
| 65dfa736f4 | |||
| 6404946d15 | |||
| ae1aeedc2f | |||
| c4374c05be |
21 changed files with 448 additions and 104 deletions
15
apparmor.d/boilerplate
Normal file
15
apparmor.d/boilerplate
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# This file is related to the `Baguette` project (authd, dnsmanagerd…).
|
||||
# It is a way to avoid the long and complex default configuration files provided
|
||||
# by the system. Allowed operations can be known in a matter of seconds.
|
||||
|
||||
# Accept basically all available libraries.
|
||||
@{BASE_LIBS}=/{,usr/,usr/local/}lib{,32,64}/*.so* /usr/lib/x86_64*/*.so* /etc/ld*
|
||||
|
||||
# Enable reading files from different places required by the libraries I use,
|
||||
# which may be the Crystal standard library itself.
|
||||
@{BASE_RO}=/dev/{,u}random /dev/pts/* /proc/** /etc/localtime /usr/share/zoneinfo/**
|
||||
@{BASE_RW}=/dev/{null,zero,full}
|
||||
|
||||
# Found in other profiles:
|
||||
# Recent glibc uses /dev/full in preference to /dev/null for programs
|
||||
# that don't have open fds at exec().
|
||||
27
apparmor.d/dnsmanager
Normal file
27
apparmor.d/dnsmanager
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Main configuration directory.
|
||||
@{MAIN_CONF_DIR}=@{HOME}/.config/baguette
|
||||
|
||||
# Main configuration files.
|
||||
@{AUTHD_CONFIG}=@{MAIN_CONF_DIR}/auth.yml
|
||||
@{DNSMANAGERD_CONFIG}=@{MAIN_CONF_DIR}/dnsmanager.yml
|
||||
|
||||
# Databases.
|
||||
@{AUTHD_DB_PATH}=@{HOME}/tmp/db-authd
|
||||
@{DNSMANAGERD_DB_PATH}=@{HOME}/tmp/db-dnsmanagerd
|
||||
|
||||
# Key to encrypt passwords.
|
||||
@{AUTHD_DB_KEY}=@{MAIN_CONF_DIR}/authd-db-key
|
||||
|
||||
# DNS templates (read-only entries).
|
||||
@{DNSMANAGERD_TEMPLATES}=@{MAIN_CONF_DIR}/templates/*.json
|
||||
|
||||
# Logs.
|
||||
@{LOGS_DIR}=@{HOME}/tmp/logs
|
||||
@{AUTHD_LOGS}=@{LOGS_DIR}/auth
|
||||
@{DNSMANAGERD_LOGS}=@{LOGS_DIR}/dnsmanager
|
||||
|
||||
# Mailer for authd.
|
||||
@{MAILER}=/{usr,usr/local}/bin/mailer
|
||||
|
||||
# IPC-related directory (see libipc(7)).
|
||||
@{LIBIPC_DIR}=/tmp/.libipc-run/
|
||||
30
apparmor.d/usr.local.bin.dnsmanagerd
Normal file
30
apparmor.d/usr.local.bin.dnsmanagerd
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
include <dnsmanager>
|
||||
include <boilerplate>
|
||||
|
||||
/usr/local/bin/dnsmanagerd flags=(enforce) {
|
||||
# See the file `boilerplate`.
|
||||
@{BASE_LIBS} mr,
|
||||
@{BASE_RO} r,
|
||||
@{BASE_RW} rw,
|
||||
|
||||
# Allow IPC-related unix sockets.
|
||||
owner @{LIBIPC_DIR}/* rwk,
|
||||
|
||||
# Enable all unix socket operations. TODO: restrict this even further?
|
||||
unix,
|
||||
|
||||
# Deny networking (udp and tcp).
|
||||
deny network tcp,
|
||||
deny network udp,
|
||||
|
||||
# Configuration and DNS templates.
|
||||
owner @{DNSMANAGERD_CONFIG} r,
|
||||
owner @{DNSMANAGERD_TEMPLATES} r,
|
||||
|
||||
# Database and logs.
|
||||
owner @{DNSMANAGERD_DB_PATH}/** rwkl,
|
||||
owner @{DNSMANAGERD_LOGS} w,
|
||||
}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
# Configuration to put in ~/.config/baguette/dnsmanager.yml or in /etc/baguette/dnsmanager.yml
|
||||
|
||||
# Path to the log file. By default, everything is just printed on screen.
|
||||
log_file: /var/log/baguette/dnsmanager.log
|
||||
|
||||
# `dnsmanagerd` needs to connect itself to authd(1) with an admin account to then authenticate its users.
|
||||
# login: dnsmanager
|
||||
pass: secret
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ COMMAND:
|
|||
.Bl -tag -width " print functions"
|
||||
.It Li maintenance
|
||||
Maintenance operation of the website
|
||||
|
||||
.br
|
||||
Example:
|
||||
.Ar admin maintenance Subject
|
||||
.Op value
|
||||
|
|
@ -52,7 +52,7 @@ for Verbosity is the verbosity-level [0-4].
|
|||
|
||||
.It Li genzone
|
||||
Generate a zone file
|
||||
|
||||
.br
|
||||
Usage:
|
||||
.Ar admin genzone domain
|
||||
.br
|
||||
|
|
@ -61,13 +61,19 @@ Example:
|
|||
|
||||
.It Li genall
|
||||
Generate all zone files
|
||||
|
||||
.br
|
||||
Usage:
|
||||
.Ar admin genall
|
||||
|
||||
.It Li exit
|
||||
Kill the service.
|
||||
.br
|
||||
Usage:
|
||||
.Ar admin exit
|
||||
|
||||
.It Li provide-domain
|
||||
Create a domain for someone
|
||||
|
||||
.br
|
||||
Usage:
|
||||
.Ar admin provide-domain login domain
|
||||
.br
|
||||
|
|
@ -76,7 +82,7 @@ Example:
|
|||
|
||||
.It Li migration-script
|
||||
Migrate domains from dnsmanager v1; this shouldn't be a concern for anyone.
|
||||
|
||||
.br
|
||||
Usage:
|
||||
.Ar admin migration-script user-db.txt
|
||||
.br
|
||||
|
|
@ -97,7 +103,7 @@ COMMAND:
|
|||
.Bl -tag -width " print functions"
|
||||
.It Li domain
|
||||
Domain operations
|
||||
|
||||
.br
|
||||
Available commands:
|
||||
.br
|
||||
.Em user domain add domain No [domain...]
|
||||
|
|
@ -108,12 +114,12 @@ Available commands:
|
|||
|
||||
.It Li zonefile
|
||||
Get a the generated zonefile
|
||||
|
||||
.br
|
||||
Usage:
|
||||
.Em user zonefile domain No [domain...]
|
||||
.It Li zone
|
||||
Zone operations
|
||||
|
||||
.br
|
||||
Usage:
|
||||
.br
|
||||
.Em user zone add No <file> [<file>...]
|
||||
|
|
@ -125,7 +131,7 @@ Usage:
|
|||
.Em user zone list
|
||||
.It Li rr
|
||||
Zone Resource Record operations
|
||||
|
||||
.br
|
||||
Usage:
|
||||
.br
|
||||
.Em user rr add No [A|AAAA|CNAME|MX|SRV|TXT|NS]
|
||||
|
|
@ -236,12 +242,12 @@ a command-line-interface client for
|
|||
a DNS manager service using
|
||||
.Xr authd
|
||||
to handle users (authentication, authorization, preferences and profile)
|
||||
.
|
||||
.It
|
||||
.Xr dodb 7
|
||||
a document database library used in
|
||||
.Xr authd .
|
||||
.El
|
||||
|
||||
The Document-oriented DataBase (DoDB) library used in
|
||||
.Xr dnsmanagerd .
|
||||
.br
|
||||
.Lk https://git.baguette.netlib.re/Baguette/dodb.cr dodb
|
||||
|
||||
.Sh Limitations
|
||||
TODO: expand the documentation
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ accepted_domains:
|
|||
.in
|
||||
|
||||
In this example, indexes are recreated, which is related to the
|
||||
.Xr dodb 7
|
||||
document database, see the related manual page to learn more.
|
||||
.Xr DoDB
|
||||
document database, see the related documentation to learn more.
|
||||
Also, there is a list of accepted domains for
|
||||
.Xr dnsmanagerd
|
||||
to handle.
|
||||
|
|
@ -61,94 +61,116 @@ The following presents the complete list of configuration file variables.
|
|||
Generic
|
||||
.Xr libipc 7
|
||||
related variables:
|
||||
.
|
||||
|
||||
.Bl -tag -width " print functions" -compact
|
||||
.It Li ipc_timer
|
||||
Int32, 30_000 (30 seconds)
|
||||
.
|
||||
Int32, 30_000
|
||||
.br
|
||||
The IPC timer wakes the process by default every 30 seconds.
|
||||
There is no much point changing this value since nothing is executed periodically anyway, at least for now.
|
||||
|
||||
.It Li verbosity
|
||||
Int32, 4 ([0-4],
|
||||
Int32, 4
|
||||
.br
|
||||
[0-4],
|
||||
.Dq 0
|
||||
being quiet and
|
||||
.Dq 4
|
||||
meaning printing debug values)
|
||||
.
|
||||
.It Li print functions
|
||||
Print functions enable to select messages to print, for example by printing a message each time a message is received while ignoring keepalive messages.
|
||||
meaning printing debug values.
|
||||
|
||||
.Bl -tag -width " print_ipc_message_received" -compact
|
||||
.It Li print_ipc_timer
|
||||
Bool, false
|
||||
.It Li print_ipc_connection
|
||||
Bool, false
|
||||
.It Li print_ipc_disconnection
|
||||
Bool, false
|
||||
.It Li print_ipc_extra_socket
|
||||
Bool, false
|
||||
.It Li print_ipc_message_received
|
||||
Bool, false
|
||||
.It Li print_ipc_message_sent
|
||||
Bool, false
|
||||
.It Li print_ipc_switch
|
||||
Bool, false
|
||||
.It Li print_ipc_error
|
||||
Bool, true
|
||||
.It Li print_ipc_exception
|
||||
Bool, true
|
||||
.It Li print_keepalive
|
||||
Bool, false
|
||||
.El
|
||||
.
|
||||
.It Li ipc_messages_to_show
|
||||
Array of
|
||||
.Vt Baguette::Configuration::IPC::MESSAGE ,
|
||||
[ERROR, EXCEPTION]
|
||||
|
||||
Types of IPC messages to print, for example all connections.
|
||||
This is mainly for debug since it is very low-level.
|
||||
High-level messages are more relevant to log.
|
||||
By default, errors and exceptions are logged.
|
||||
|
||||
See
|
||||
.Xr Baguette-crystal-base ,
|
||||
which includes the
|
||||
.Vt Baguette::Configuration::IPC::MESSAGE
|
||||
definition.
|
||||
This type has an alias in
|
||||
.Xr dnsmanager :
|
||||
.Vt IPCMESSAGE .
|
||||
|
||||
.It Li service_name
|
||||
String,
|
||||
.Dq dnsmanager
|
||||
.br
|
||||
.Xr libipc 7
|
||||
unix socket name.
|
||||
.El
|
||||
|
||||
Specific
|
||||
.Xr dnsmanagerd
|
||||
variables:
|
||||
.Bl -tag -width "template_directory" -compact
|
||||
.It Li service_name
|
||||
String,
|
||||
.Dq dnsmanager
|
||||
(\c
|
||||
.Xr libipc 7
|
||||
unix socket name)
|
||||
.It Li log_file
|
||||
String?,
|
||||
.Em none
|
||||
.br
|
||||
Path to the log file.
|
||||
|
||||
.It Li messages_to_mask
|
||||
Array of
|
||||
.Vt DNSManager::MESSAGE ,
|
||||
.Em [ KEEPALIVE ]
|
||||
.br
|
||||
List of high-level
|
||||
.Em dnsmanagerd
|
||||
messages to mask in the logs.
|
||||
.br
|
||||
The type
|
||||
.Vt DNSManager::MESSAGE
|
||||
has an alias:
|
||||
.Vt DNSMESSAGE .
|
||||
|
||||
.It Li recreate_indexes
|
||||
Bool, false (see
|
||||
.Xr dodb 7
|
||||
man-page)
|
||||
Bool, false
|
||||
.br
|
||||
See
|
||||
.Xr DoDB
|
||||
documentation.
|
||||
|
||||
.It Li storage_directory
|
||||
String,
|
||||
.Pa ./db-dnsmanagerd
|
||||
(see
|
||||
.Xr dodb 7
|
||||
man-page)
|
||||
.br
|
||||
See
|
||||
.Xr DoDB
|
||||
documentation.
|
||||
|
||||
.It Li login
|
||||
String,
|
||||
.Dq dnsmanager
|
||||
.br
|
||||
.Xr dnsmanagerd
|
||||
needs to connect itself to
|
||||
.Xr authd 1
|
||||
with an admin account to then authenticate its users.
|
||||
|
||||
String,
|
||||
.Dq dnsmanager
|
||||
.It Li pass
|
||||
String?,
|
||||
.Em none
|
||||
|
||||
.It Li template_directory
|
||||
String,
|
||||
.Pa /etc/dnsmanager/templates
|
||||
.br
|
||||
New domains require to load a template so users won't have to enter some necessary entries themselves.
|
||||
For example, SOA and NS RRs are pre-loaded and updated by an administrator when required.
|
||||
.br
|
||||
See
|
||||
.Pa tools/write-template-zone-file.cr
|
||||
|
||||
String,
|
||||
.Pa /etc/dnsmanager/templates
|
||||
|
||||
.It Li accepted_domains
|
||||
List of all accepted domains. Example: netlib.re.
|
||||
|
||||
Array of String, []
|
||||
.br
|
||||
List of all accepted domains. Example: netlib.re.
|
||||
.El
|
||||
|
||||
.Sh Options
|
||||
|
|
@ -191,10 +213,9 @@ Recreate database indexes (symbolic links).
|
|||
Path of the directory where the
|
||||
.Xr dnsmanagerd
|
||||
database is stored.
|
||||
See
|
||||
.Xr dodb 7
|
||||
for more information.
|
||||
.
|
||||
See the
|
||||
.Xr DoDB
|
||||
documentation.
|
||||
|
||||
.It Fl -accepted-domains No domains
|
||||
Accepted domains, coma separated.
|
||||
|
|
@ -257,24 +278,30 @@ a command-line-interface client for
|
|||
.
|
||||
.It Xr mailer 1
|
||||
a simple executable to send mails based on templates
|
||||
.
|
||||
.It Xr dodb 7
|
||||
a document database library used in
|
||||
.Xr authd .
|
||||
.El
|
||||
|
||||
The Document-oriented DataBase (DoDB) library used in
|
||||
.Xr dnsmanagerd .
|
||||
.br
|
||||
.Lk https://git.baguette.netlib.re/Baguette/dodb.cr dodb
|
||||
|
||||
The online service
|
||||
.Dq netlib.re
|
||||
provides an interface for the
|
||||
.Xr dnsmanagerd
|
||||
daemon.
|
||||
.br
|
||||
.Lk https://netlib.re netlib.re
|
||||
.Lk https://www.netlib.re netlib.re
|
||||
|
||||
The source code of the web interface:
|
||||
.br
|
||||
.Lk https://git.baguette.netlib.re/Baguette/dnsmanager-webclient web-client
|
||||
|
||||
The logging and configuration library for the whole
|
||||
.Dq baguette
|
||||
project.
|
||||
.br
|
||||
.Lk https://git.baguette.netlib.re/Baguette/baguette-crystal-base baguette-crystal-base
|
||||
|
||||
.Sh Limitations
|
||||
TODO: expand the documentation
|
||||
|
|
|
|||
|
|
@ -181,6 +181,11 @@ class DNSManager::Client < IPC
|
|||
parse_message [ Response::Success ], read
|
||||
end
|
||||
|
||||
def admin_exit
|
||||
request = Request::Exit.new
|
||||
send_now request
|
||||
end
|
||||
|
||||
#
|
||||
# Utils
|
||||
#
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class Actions
|
|||
@the_call["admin-migration-script"] = ->admin_migration_script
|
||||
@the_call["admin-generate-all-zonefiles"] = ->admin_generate_all_zonefiles
|
||||
@the_call["admin-provide-domain"] = ->admin_provide_domain
|
||||
@the_call["admin-exit"] = ->admin_exit
|
||||
|
||||
# Domain operations.
|
||||
@the_call["user-domain-add"] = ->user_domain_add
|
||||
|
|
@ -155,6 +156,12 @@ class Actions
|
|||
puts "error for provide_domain: #{e.message}"
|
||||
end
|
||||
|
||||
def admin_exit
|
||||
@dnsmanagerd.admin_exit
|
||||
rescue e
|
||||
puts "error for provide_domain: #{e.message}"
|
||||
end
|
||||
|
||||
def user_domain_add
|
||||
domains = Context.args.not_nil!
|
||||
domains.each do |domain|
|
||||
|
|
|
|||
|
|
@ -131,6 +131,14 @@ def parsing_cli(authd_config : Baguette::Configuration::Auth)
|
|||
parser.banner = "COMMAND: admin migration-script user-db.txt"
|
||||
unrecognized_args_to_context_args.call parser, 1, nil
|
||||
end
|
||||
|
||||
# Kill the service.
|
||||
parser.on("exit", "Kill the service.") do
|
||||
Baguette::Log.info "kill the service."
|
||||
Context.command = "admin-exit"
|
||||
parser.banner = "COMMAND: exit"
|
||||
unrecognized_args_to_context_args.call parser, nil, 0
|
||||
end
|
||||
end
|
||||
|
||||
# User section.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@ class IPC::JSON
|
|||
def handle(service : IPC, event : IPC::Event)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
io << self.class.name.sub /[^:]+::[^:]+::/, ""
|
||||
end
|
||||
end
|
||||
|
||||
module DNSManager
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@ class DNSManager::Request
|
|||
def initialize(@subject)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (subject: #{@subject}, int: #{@int}, string: #{@string})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -72,6 +77,11 @@ class DNSManager::Request
|
|||
def initialize(@domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -81,4 +91,23 @@ class DNSManager::Request
|
|||
end
|
||||
end
|
||||
DNSManager.requests << GenerateZoneFile
|
||||
|
||||
IPC::JSON.message Exit, 248 do
|
||||
def initialize
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
dnsmanagerd.storage.user_must_be_admin! user.uid
|
||||
|
||||
Baguette::Log.warning "exit requested, bye"
|
||||
exit 0
|
||||
end
|
||||
end
|
||||
DNSManager.requests << Exit
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,6 +10,11 @@ class DNSManager::Request
|
|||
def initialize(@login, @domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (login: #{@login}, domain: #{@domain})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@ class DNSManager::Request
|
|||
def initialize(@domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event)
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -20,6 +25,11 @@ class DNSManager::Request
|
|||
def initialize(@domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event)
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -35,6 +45,11 @@ class DNSManager::Request
|
|||
def initialize(@domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event)
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -50,6 +65,11 @@ class DNSManager::Request
|
|||
def initialize(@uuid)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (uuid: #{@uuid})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event)
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ class DNSManager::Request
|
|||
def initialize(@domain, @rrid)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain}, rrid: #{@rrid})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -24,6 +29,11 @@ class DNSManager::Request
|
|||
def initialize(@token, @address)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (token: #{@token[0..15]}..., address: #{@address})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
dnsmanagerd.storage.use_token @token, @address
|
||||
end
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ class DNSManager::Request
|
|||
def initialize(@user_id = nil)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (user_id: #{@user_id})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event)
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ class DNSManager::Request
|
|||
def initialize(@domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -24,6 +29,11 @@ class DNSManager::Request
|
|||
def initialize(@domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -38,6 +48,11 @@ class DNSManager::Request
|
|||
def initialize(@zone)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (zone: #{@zone})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -52,6 +67,11 @@ class DNSManager::Request
|
|||
def initialize(@domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -77,6 +97,11 @@ class DNSManager::Request
|
|||
property domain : String
|
||||
property rr : DNSManager::Storage::Zone::ResourceRecord
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain}, rr: #{@rr.to_simple_s})"
|
||||
end
|
||||
|
||||
def initialize(@domain, @rr)
|
||||
end
|
||||
|
||||
|
|
@ -95,6 +120,11 @@ class DNSManager::Request
|
|||
def initialize(@domain, @rr)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain}, rr: #{@rr.to_simple_s})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -110,6 +140,11 @@ class DNSManager::Request
|
|||
def initialize(@domain, @rrid)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain}, rrid: #{@rrid})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
@ -124,6 +159,11 @@ class DNSManager::Request
|
|||
def initialize(@domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain})"
|
||||
end
|
||||
|
||||
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
|
||||
user = dnsmanagerd.get_logged_user event
|
||||
return Response::ErrorUserNotLogged.new unless user
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ class DNSManager::Response
|
|||
property reason : String | Array(String)
|
||||
def initialize(@reason)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (reason: #{@reason})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << Error
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ class DNSManager::Response
|
|||
property domain : String
|
||||
def initialize(@domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << DomainDeleted
|
||||
|
||||
|
|
@ -11,6 +16,11 @@ class DNSManager::Response
|
|||
property errors : Array(Storage::Zone::Error)
|
||||
def initialize(@errors)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (errors: #{@errors.join ","})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << InvalidZone
|
||||
|
||||
|
|
@ -18,6 +28,11 @@ class DNSManager::Response
|
|||
property domain : DNSManager::Storage::Domain
|
||||
def initialize(@domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain.name})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << DomainChanged
|
||||
|
||||
|
|
@ -25,6 +40,11 @@ class DNSManager::Response
|
|||
property zone : Storage::Zone
|
||||
def initialize(@zone)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (zone: #{@zone})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << Zone
|
||||
|
||||
|
|
@ -38,6 +58,11 @@ class DNSManager::Response
|
|||
property domains : Array(String)
|
||||
def initialize(@domains)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domains: #{@domains.join ","})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << DomainList
|
||||
|
||||
|
|
@ -45,6 +70,11 @@ class DNSManager::Response
|
|||
property domains : Array(String)
|
||||
def initialize(@domains)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domains: #{@domains.join ","})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << AcceptedDomains
|
||||
|
||||
|
|
@ -54,6 +84,11 @@ class DNSManager::Response
|
|||
property my_domains : Array(DNSManager::Storage::Domain)
|
||||
def initialize(@admin, @accepted_domains, @my_domains)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (admin: #{@admin})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << Logged
|
||||
|
||||
|
|
@ -61,6 +96,11 @@ class DNSManager::Response
|
|||
property domain : String
|
||||
def initialize(@domain)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << DomainAdded
|
||||
|
||||
|
|
@ -68,6 +108,11 @@ class DNSManager::Response
|
|||
property rrid : UInt32
|
||||
def initialize(@rrid)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (rrid: #{@rrid})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << RRDeleted
|
||||
|
||||
|
|
@ -76,6 +121,11 @@ class DNSManager::Response
|
|||
property rr : Storage::Zone::ResourceRecord
|
||||
def initialize(@domain, @rr)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain}, rr: #{@rr.to_simple_s})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << RRAdded
|
||||
|
||||
|
|
@ -84,6 +134,11 @@ class DNSManager::Response
|
|||
property errors : Array(Storage::Zone::Error)
|
||||
def initialize(@errors)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (errors: #{@errors.join ","})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << InvalidRR
|
||||
|
||||
|
|
@ -92,6 +147,11 @@ class DNSManager::Response
|
|||
property rr : Storage::Zone::ResourceRecord
|
||||
def initialize(@domain, @rr)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain}, rr: #{@rr.to_simple_s})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << RRUpdated
|
||||
|
||||
|
|
@ -100,6 +160,11 @@ class DNSManager::Response
|
|||
property rr : Storage::Zone::ResourceRecord
|
||||
def initialize(@domain, @rr)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain}, rr: #{@rr.to_simple_s})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << RRReadOnly
|
||||
|
||||
|
|
@ -108,6 +173,11 @@ class DNSManager::Response
|
|||
property zonefile : String
|
||||
def initialize(@domain, @zonefile)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domain: #{@domain})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << GeneratedZone
|
||||
|
||||
|
|
@ -115,6 +185,11 @@ class DNSManager::Response
|
|||
property domains : Array(String)
|
||||
def initialize(@domains)
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
super io
|
||||
io << " (domains: #{@domains.join ","})"
|
||||
end
|
||||
end
|
||||
DNSManager.responses << OrphanDomainList
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,16 +10,15 @@ class Array(T)
|
|||
end
|
||||
end
|
||||
|
||||
# WIP: select (dynamically) messages to mask
|
||||
|
||||
module DNSManager
|
||||
# Select messages to mask in the logs (when everything goes well, of course).
|
||||
# No need to flood the logs with keepalive messages or periodic token use, for instance.
|
||||
enum MESSAGE
|
||||
KEEPALIVE
|
||||
# TODO
|
||||
USETOKEN
|
||||
end
|
||||
end
|
||||
|
||||
alias IPCMESSAGE = Baguette::Configuration::IPC::MESSAGE
|
||||
alias DNSMESSAGE = DNSManager::MESSAGE
|
||||
|
||||
class DNSManager::Service < IPC
|
||||
|
|
@ -51,7 +50,7 @@ class DNSManager::Service < IPC
|
|||
when AuthD::Response::Login
|
||||
uid = response.uid
|
||||
token = response.token
|
||||
Baguette::Log.info "Authenticated as #{@configuration.login} #{uid}, token: #{token}"
|
||||
Baguette::Log.info "Authenticated as #{@configuration.login} #{uid}, token: #{token[0..15]}..."
|
||||
else
|
||||
@authd.close
|
||||
raise "Cannot authenticate to authd with login #{@configuration.login}: #{response}."
|
||||
|
|
@ -62,8 +61,11 @@ class DNSManager::Service < IPC
|
|||
self.service_init @configuration.service_name
|
||||
end
|
||||
|
||||
def get_logged_user(event : IPC::Event)
|
||||
@logged_users[event.fd]?
|
||||
def get_logged_user(fd : Int32) : AuthD::User::Public?
|
||||
@logged_users[fd]?
|
||||
end
|
||||
def get_logged_user(event : IPC::Event) : AuthD::User::Public?
|
||||
get_logged_user event.fd
|
||||
end
|
||||
|
||||
def decode_token(token : String)
|
||||
|
|
@ -93,6 +95,17 @@ class DNSManager::Service < IPC
|
|||
end
|
||||
end
|
||||
|
||||
# `log_user_info` provides a string composed from either the user
|
||||
# id in case the user was authenticated or the file descriptor of
|
||||
# the connection.
|
||||
def log_user_info(fd : Int32) : String
|
||||
if user = get_logged_user fd
|
||||
"userid #{user.uid}"
|
||||
else
|
||||
"fd #{"%4d" % fd}"
|
||||
end
|
||||
end
|
||||
|
||||
def handle_request(event : IPC::Event)
|
||||
request_start = Time.utc
|
||||
|
||||
|
|
@ -106,41 +119,43 @@ class DNSManager::Service < IPC
|
|||
end
|
||||
|
||||
reqname = request.class.name.sub /^DNSManager::Request::/, ""
|
||||
connection_info_str = log_user_info event.fd
|
||||
|
||||
response = begin
|
||||
request.handle self, event
|
||||
rescue e : AuthorizationException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} authorization error"
|
||||
Baguette::Log.error "(#{connection_info_str}) #{request} authorization error"
|
||||
Response::Error.new "authorization error"
|
||||
rescue e : DomainNotFoundException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} domain not found"
|
||||
Baguette::Log.error "(#{connection_info_str}) #{request} 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}'"
|
||||
Baguette::Log.error "(#{connection_info_str}) #{request} 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"
|
||||
Baguette::Log.error "(#{connection_info_str}) #{request} unknown user"
|
||||
Response::UnknownUser.new
|
||||
rescue e : NoOwnershipException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} no ownership error"
|
||||
Baguette::Log.error "(#{connection_info_str}) #{request} no ownership error"
|
||||
Response::NoOwnership.new
|
||||
rescue e : NotLoggedException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} user not logged"
|
||||
Baguette::Log.error "(#{connection_info_str}) #{request} user not logged"
|
||||
Response::Error.new "user not logged"
|
||||
rescue e : RRNotFoundException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} RR not found"
|
||||
Baguette::Log.error "(#{connection_info_str}) #{request} RR not found"
|
||||
Response::RRNotFound.new
|
||||
rescue e : TokenNotFoundException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} Token not found"
|
||||
Baguette::Log.error "(#{connection_info_str}) #{request} Token not found"
|
||||
Response::Error.new "token not found"
|
||||
rescue e : RRReadOnlyException
|
||||
Baguette::Log.error "(fd #{"%4d" % event.fd}) #{reqname} RR is read only"
|
||||
Baguette::Log.error "(#{connection_info_str}) #{request} 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}"
|
||||
Baguette::Log.error "(#{connection_info_str}) #{request} generic error #{e}"
|
||||
Response::Error.new "generic error"
|
||||
end
|
||||
|
||||
respname = response.class.name.sub /^DNSManager::Response::/, ""
|
||||
# If clients sent requests with an “id” field, it is copied
|
||||
# in the responses. Allows identifying responses easily.
|
||||
response.id = request.id
|
||||
|
|
@ -149,14 +164,14 @@ class DNSManager::Service < IPC
|
|||
|
||||
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})"
|
||||
Baguette::Log.warning "(#{connection_info_str}) (#{duration}) #{request} >> #{response}"
|
||||
else
|
||||
if reqname != "KeepAlive" || should_display? DNSMESSAGE::KEEPALIVE
|
||||
Baguette::Log.debug "fd #{"%4d" % event.fd} (#{duration}) #{reqname} >> #{response_name}"
|
||||
end
|
||||
# Different cases where we want to simply avoid logging redundant messages.
|
||||
return if reqname == "KeepAlive" && ! should_display? DNSMESSAGE::KEEPALIVE
|
||||
return if reqname == "UseToken" && respname == "Success" && ! should_display? DNSMESSAGE::USETOKEN
|
||||
|
||||
Baguette::Log.debug "(#{connection_info_str}) (#{duration}) #{request} >> #{response}"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@ require "./service.cr"
|
|||
require "dodb"
|
||||
|
||||
class DNSManager::Storage
|
||||
getter domains : DODB::Storage::Cached(Domain)
|
||||
getter domains : DODB::Storage::Common(Domain)
|
||||
getter domains_by_name : DODB::Trigger::IndexCached(Domain)
|
||||
getter domains_by_share_key : DODB::Trigger::IndexCached(Domain)
|
||||
getter domains_by_transfer_key : DODB::Trigger::IndexCached(Domain)
|
||||
getter domains_by_owners : DODB::Trigger::Tags(Domain)
|
||||
|
||||
getter zones : DODB::Storage::Cached(Zone)
|
||||
getter zones : DODB::Storage::Common(Zone)
|
||||
getter zones_by_domain : DODB::Trigger::IndexCached(Zone)
|
||||
|
||||
getter tokens : DODB::Storage::Cached(Token)
|
||||
getter tokens : DODB::Storage::Common(Token)
|
||||
getter tokens_by_uuid : DODB::Trigger::IndexCached(Token)
|
||||
getter tokens_by_domain : DODB::Trigger::Partition(Token)
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ class DNSManager::Storage
|
|||
end
|
||||
|
||||
def initialize(@root : String, reindex : Bool = false)
|
||||
@domains = DODB::Storage::Cached(Domain).new "#{@root}/domains"
|
||||
@domains = DODB::Storage::Common(Domain).new "#{@root}/domains", 5_000
|
||||
@domains_by_name = @domains.new_index "name", &.name
|
||||
@domains_by_share_key = @domains.new_index "share-key", do |d|
|
||||
if k = d.share_key
|
||||
|
|
@ -49,9 +49,9 @@ class DNSManager::Storage
|
|||
end
|
||||
end
|
||||
@domains_by_owners = @domains.new_tags "owners", &.owners.map &.to_s
|
||||
@zones = DODB::Storage::Cached(Zone).new "#{@root}/zones"
|
||||
@zones = DODB::Storage::Common(Zone).new "#{@root}/zones", 5_000
|
||||
@zones_by_domain = @zones.new_index "domain", &.domain
|
||||
@tokens = DODB::Storage::Cached(Token).new "#{@root}/tokens"
|
||||
@tokens = DODB::Storage::Common(Token).new "#{@root}/tokens", 5_000
|
||||
@tokens_by_uuid = @tokens.new_index "uuid", &.uuid
|
||||
@tokens_by_domain = @tokens.new_partition "domain", &.domain
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,10 @@ class DNSManager::Storage::Zone
|
|||
[] of Error
|
||||
end
|
||||
|
||||
def to_simple_s
|
||||
"(rrid #{@rrid}, '#{@name}' #{@rrtype})"
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
io << "(#{ "%4d" % @rrid }) "
|
||||
io << "#{ "%.30s" % @name} #{ "%6d" % @ttl} #{ "%.10s" % @rrtype } #{ "%.30s" % @target}\n"
|
||||
|
|
@ -913,6 +917,10 @@ class DNSManager::Storage::Zone
|
|||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
io << "ZONE #{@domain} (#{@resources.size} rr)"
|
||||
end
|
||||
|
||||
def pretty_print(io : IO)
|
||||
io << "DOMAIN #{@domain}.\n"
|
||||
@resources.each do |rr|
|
||||
io << rr
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue