jean-cloud-services/services/ns1.jean-cloud.org/helper_functions.sh
2024-10-16 11:41:44 +02:00

209 lines
5.7 KiB
Bash
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

set -euo pipefail
. driglibash-base
fakeresolve_ip_list () {
if [ "$#" -ne 1 ] ; then
die "Usage: fakeresolve_ip_list <name>"
fi
grep -oP "^$1[[:space:]]+(IN)?[[:space:]]+A{1,4}[[:space:]]+\K[^;\s]+" "$debian_bind_confdir/$server_zone_file" | tr '\n' ';'
}
prepare () {
# Install dependencies
apt install -y bind9 &>/dev/null
# Create Directories
if [ -n "$keydir" ] ; then
mkdir -p "$keydir"
chown bind:bind "$keydir" -R
chown bind:bind "$debian_bind_confdir" -R
fi
echo 'Sync the git repo'
run sudo -u bind git_update.sh -r main -o "-i $DATA_DIR/gitkey" -d "$debian_bind_confdir" 'ssh://git@git.jean-cloud.net:22529/adrian/dnszones.git'
cd /etc/bind
echo 'Prepare bind: Remove autogenerated part from bind conf files'
rm /etc/bind/*.jnl &>/dev/null || true
sed -i -n "/$autoconf_separator/q;p" "$debian_bind_confdir"/*
echo 'Put the separator back'
for file in $( ls "$debian_bind_confdir"/template.db.* | grep -v '.signed$\|.jbk$\|.jnl$') ; do
echo "$autoconf_separator" >> "$file"
done
}
restart () {
echo 'Check named conf'
run named-checkconf "$debian_bind_confdir/named.conf"
for db_file in $(list_db_files) ; do
domain="$(basename "$db_file")"
domain="${domain:3}"
run named-checkzone "$domain" "$db_file"
done
echo 'Restart named'
systemctl restart named
}
# Function that simulate a DNS resolve by reading bind zone file
# Returns all the record line:
# @ IN A X.X.X.X
fakeresolve () {
if [ "$#" -ne 1 ] ; then
die "Usage: fakeresolve <name>"
fi
name="$1"
zonefile="$debian_bind_confdir/$server_zone_file"
# Split full name if there are dots
shortname="$name"
if [ -n "$(echo "$name" | grep -o '\.')" ] ; then
shortname="$(echo "$name" | grep -Po '^.*(?=\.[^\.]+\.[^\.]+$)' || true)"
fi
grep -v -e '^[[:space:]]*;' "$zonefile" |grep -oP "^[[:space:]]*$shortname\K[[:space:]]*(IN)?[[:space:]]*A{1,4}[[:space:]]*[\S;]+" | sed 's/^/@/'
}
# Function that add DNS record in the right file
addbindline () {
if [ "$#" -ne 2 ] ; then
die "Usage: addbindline <name> <target_cname>"
fi
name="$1"
target="$2"
# extract the truc.com part
domain="$(echo "$name" | grep -o '[^\.]\+\.[^\.]\+$' || true)"
[ -z "$domain" ] && return 0
# extract the subdomain part (www)
shortname="$(echo "$name" | grep -Po '^.*(?=\.[^\.]+\.[^\.]+$)' || true)"
# bind DB file
bindfile="$debian_bind_confdir/db.$domain"
# Only append if db file exists
[ ! -f "$bindfile" ] && return 0
# BTW allow ACME DNS update
token="#JC-ACME $domain"
acme_dns="grant letsencrypt.key. name _acme-challenge.$name. TXT;"
sed -i "s/\([[:space:]]*\)$token/\1$acme_dns\n\1$token/" "$debian_bind_confdir/named.conf.local"
# TODO check if name already existst with a different target
# Hard since we are resolving targets now…
# CNAME are forbiden for empty shortnames, so we must resolve the target IPs
# For performance reasons, we just put plain IP everywhere
# to put aliases in place of ip juste do the following if $shortname is empty:
#line_in_file "$shortname CNAME $target." "$bindfile"
while read line ; do
if [ -n "$shortname" ] ; then
line="$(echo "$line" | sed "s/@/$shortname/")"
fi
line_in_file "$line" "$bindfile"
done < <(fakeresolve "$target")
}
list_template_db_files () {
ls "$debian_bind_confdir"/template.db.*
}
list_db_files () {
ls "$debian_bind_confdir"/db.* | grep -v -e '.jbk$' -e '.signed$' -e '.signed.jnl'
}
create_primary_files () {
# Compact the default SOA
SOA="$(grep -o '^[^;]*' SOA | sed -z -e 's/[[:space:]]\{2,\}/ /g' -e 's/\n/\\n/')"
line_in_file "include \"$DATA_DIR/letsencrypt.key\";" "$debian_bind_confdir/named.conf"
for file in $(list_template_db_files) ; do
domain="$(basename "$file" | sed 's/template.db.//')"
new_db_file="$(echo "$file" | sed 's/template.db./db./')"
# Set the default SOA if needed
sed "s/^;JC_AUTOSOA$/$SOA/" "$file" > "$new_db_file"
# Set serial
serial="$(date '+%s')"
sed -i "s/\(@ SOA [^(]*( \)[0-9]\+/\1$serial/" "$new_db_file"
# Add this dns server if not present
if ! grep -q '[^;].*(IN)?.*NS.*' "$new_db_file" ; then
cat default_ns >> "$new_db_file"
fi
# Add DS record
#if [ -n "$(ls "$DATA_DIR/keys/K$domain"*.key)" ] ; then
#dnssec-dsfromkey "$DATA_DIR/keys/K$domain"*.key | sed "s/${domain}./@/" >> "$new_db_file"
#fi
# Populate named.conf.local
cat >> "$debian_bind_confdir/named.conf.local" <<-EOF
zone "$domain" {
# Zone file
type master;
file "$new_db_file";
# Secondary conf
# https://kb.isc.org/docs/aa-00723
#allow-update { !{!{$secondary_ips};any;}; key update-key; };
allow-transfer { $secondary_ips };
also-notify { $secondary_ips };
notify yes;
# DNSSEC
dnssec-policy default;
inline-signing yes;
key-directory "$DATA_DIR/keys";
# ACME autorizations
update-policy {
#JC-ACME $domain
};
};
EOF
done
echo 'Find every used domain and add them to bind db'
while IFS=';' read -r id username service target
do
addbindline "$service" "$target"
nginxfile="/docker/$service/nginx_server.conf"
if [ -f "$nginxfile" ] ; then
for name in $(extract_domain_nginx_conf.sh "$nginxfile" | template.sh "/docker/$service/.env") ; do
addbindline "$name" "$target"
done
fi
done < <(grep -v '^#' /docker/services.csv)
}
create_secondary_files () {
primary_ips="$(echo "$primary_ips" | sed 's/^;//')"
for file in "$debian_bind_confdir"/template.db.* ; do
file="$(echo "$file" | sed -e 's/template.db.//' -e "s#$debian_bind_confdir#/var/lib/bind/#")"
domain="$(basename "$file")"
echo -n "
zone \"$domain\" {
masters { $primary_ips };
type slave;
file \"$file\";
};" >> "$debian_bind_confdir/named.conf.local"
done
}