209 lines
5.7 KiB
Bash
209 lines
5.7 KiB
Bash
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 -N -b main -i "$SECRET_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'
|
||
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="${db_file:3}"
|
||
run named-checkzone "$domain" "$db_file"
|
||
done
|
||
|
||
echo 'Restart named'
|
||
rm /etc/bind/*.jnl || true
|
||
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 [ -z "$(grep '[^;].*(IN)?.*NS.*$default_dns_name' "$new_db_file")" ] ; then
|
||
echo "@ NS $default_dns_name" >> "$new_db_file"
|
||
fi
|
||
|
||
# Add DS record
|
||
if [ -n "$(ls "$DATA_DIR/keys/K$domain"*.key)" ] ; then
|
||
echo ""
|
||
#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
|
||
}
|