2021-01-04 20:53:39 +01:00
#!/bin/sh
2021-07-08 00:39:48 +02:00
# SPDX-License-Identifier: GPL-3.0
#
# freifunk-franken dns-scipts (c) 2021 Blackyfff
2021-01-04 20:53:39 +01:00
GetZoneFileSerial( ) {
2021-01-14 20:46:10 +01:00
if [ -f " $1 " ] ; then
INSOASpec = "^\s*\S\+\s\+\([0-9]*\s\)\?\s*IN\s\+SOA\s\+"
FirstSOALineAndFollowing = "/" " $INSOASpec " "/,\$!d;"
RemoveComments = " :a;s/;.* $//g; "
RemoveLineBreaks = ":a;N;\$!ba;s/\n//g;"
SearchPrintSerial = "s/" " $INSOASpec " "\S\+\s\+\S\+\s\+\((\s\)\?\s*\([0-9]*\).*/\3/i"
ZoneSerial = $( sed -e " $FirstSOALineAndFollowing " " $RemoveComments " " $RemoveLineBreaks " " $SearchPrintSerial " " $1 " )
fi
2021-01-04 20:53:39 +01:00
echo " ${ ZoneSerial :- 0 } "
}
2021-06-27 22:51:24 +02:00
InsertZoneToViews( ) {
Views = " $1 "
ZoneFilesFolder = " $2 "
Domain = " $3 "
SourceFile = " $4 "
TempFolder = " $5 "
DNSSECPolicy = " $6 "
for View in $Views ; do
ZoneFile = " $ZoneFilesFolder " "db." " $View " "." " $Domain "
[ -f " $ZoneFile " ] || ln -s " $SourceFile " " $ZoneFile "
InsertZoneToIncludeFile " $Domain " " $ZoneFile " " $TempFolder " " $View " ".conf" " $DNSSECPolicy "
done
}
2021-01-15 17:12:33 +01:00
InsertZoneToIncludeFile( ) {
if [ ! -f " $3 " ] ; then
2021-01-19 17:49:06 +01:00
{
echo "zone \"" " $1 " "\" {"
echo " type master;"
2021-02-08 01:34:03 +01:00
[ -n " $4 " ] && echo " dnssec-policy $4 " ";"
2021-01-19 17:49:06 +01:00
echo " file \"" " $2 " "\";"
echo "};"
} > " $3 "
2021-01-15 17:12:33 +01:00
else
2021-02-08 01:34:03 +01:00
[ -n " $4 " ] && Extra = " dnssec-policy $4 " ";\n" || Extra = ""
2021-01-15 17:12:33 +01:00
sed -i " 1i\
zone \" "" $1 "" \" { \n \
2021-02-08 01:34:03 +01:00
type master; \n "" $Extra \
2021-01-15 17:12:33 +01:00
file \" "" $2 "" \" ; \n \
} ; " " $3 "
fi
}
2021-06-27 22:51:24 +02:00
GetAllNameservers( ) {
sed -ne 's/^\s*' " $2 " '\s\+\([0-9]*\s\)\?\s*[Ii][Nn]\s\+[Nn][Ss]\s\+\(\S\+\)/\3/p' " $3 " | \
2021-03-10 00:02:15 +01:00
sed -e 's/\([^.]\)$/\1\.' " $1 " '\./g;s/\.$//g'
}
2021-06-27 22:51:24 +02:00
GetAllSubNameservers( ) {
Domain = " $( SEDifyHostname " $1 " ) "
SubDomain = " $( SEDifyHostname " $2 " ) "
GetAllNameservers " $1 " " $SubDomain " "\(\." " $Domain " "\.\)\?" " $3 "
}
2021-03-10 00:02:15 +01:00
GetAllZoneNameservers( ) {
2021-06-27 22:51:24 +02:00
Domain = "" " $( SEDifyHostname " $1 " ) "
GetAllNameservers " $1 " "\(@\|" " $Domain " "\.\)" " $2 "
2021-03-10 00:02:15 +01:00
}
2021-01-15 17:12:33 +01:00
GetReverseZoneFileFromZone( ) {
echo "db." " $( echo " $1 " | awk -F. '{ printf $(NF-2);for(i=NF-3;i>0;--i) printf "."$i}' ) "
}
2021-01-14 20:46:10 +01:00
FillIPv4MissingBlocks( ) {
echo " $1 " | sed -ne 's/^\([^.]\+\)\.\(\([^.]\+\)\.\)\?\(\([^.]\+\)\.\)\?\([^.]\+\)$/\1.\3.\5.\6/p' | sed -r 's/\.\./\.0\./g;s/\.\./\.0\./g'
}
GetReverseIPv4Domains( ) {
IPFilled = " $( FillIPv4MissingBlocks " ${ 1 %/* } " ) "
Mask = " ${ 1 ##*/ } "
Statics = $(( Mask / 8 ))
Filler = $(( Mask % 8 ))
RevDomain = " $( echo " $IPFilled " | awk -F. '{for(i=' " $Statics " ';i>0;--i)printf "."$i}' ) " ".in-addr.arpa."
if [ $Filler -eq 0 ] ; then
echo " ${ RevDomain #. } "
else
2021-01-19 17:49:06 +01:00
Filler = $(( 8 - Filler))
2021-06-27 22:51:24 +02:00
Filler = $(( 1 << $Filler ))
2021-01-14 20:46:10 +01:00
Start = $( echo " $IPFilled " | awk -F. '{printf $' " $(( Statics+1)) " '}' )
Start = $(( Start - Start % Filler))
for Sub in $( seq $Start $(( Start + Filler - 1 )) ) ; do
echo " $Sub " " $RevDomain "
done
fi
}
FillIPv6Zeroes( ) {
2021-01-19 17:49:06 +01:00
echo " $1 " | awk -F: 'BEGIN{OFS=""}{FillCount=9-NF; for(i=1;i<=NF;i++){if(length($i)!=0||i==1||i==NF) {$i=substr(("0000" $i), length($i)+1);} else {for(j=1;j<=FillCount;j++){$i=($i "0000");}}}; print}'
2021-01-14 20:46:10 +01:00
}
GetReverseIPv6Domains( ) {
IPFilled = " $( FillIPv6Zeroes " $( echo " ${ 1 %/* } " | awk '{print tolower($0)}' ) " ) "
Mask = " ${ 1 ##*/ } "
Statics = $(( Mask / 4 ))
Filler = $(( Mask % 4 ))
2021-01-19 17:49:06 +01:00
RevDomain = " $( echo " $IPFilled " | awk 'BEGIN{FS=""}{for(i=' " $Statics " ';i>0;i--) printf "." $i;}' ) " ".ip6.arpa."
2021-01-14 20:46:10 +01:00
if [ $Filler -eq 0 ] ; then
echo " ${ RevDomain #. } "
else
2021-01-19 17:49:06 +01:00
Filler = $(( 4 - Filler))
2021-06-27 22:51:24 +02:00
Filler = $(( 1 << $Filler ))
2021-01-19 17:49:06 +01:00
Start = " $( printf %d 0x" $( echo " $IPFilled " | awk 'BEGIN{FS=""}{printf $' " $(( Statics+1)) " '}' ) " ) "
2021-01-14 20:46:10 +01:00
Start = $(( Start - Start % Filler))
for Sub in $( seq $Start $(( Start + Filler - 1 )) ) ; do
echo " $( printf %x " $Sub " ) " " $RevDomain "
done
fi
}
GetReverseDomains( ) {
Subnet = " $1 "
if IsValidIPv4Subnet " $Subnet " ; then
GetReverseIPv4Domains " $Subnet "
elif IsValidIPv6Subnet " $Subnet " ; then
GetReverseIPv6Domains " $Subnet "
2021-01-19 17:49:06 +01:00
else
TraceErrAndExit " $1 " " is no valid Subnet"
2021-01-14 20:46:10 +01:00
fi
}
2021-01-21 19:21:25 +01:00
ExpandHostname( ) {
Hostname = " $1 "
[ -n " ${ Hostname ##*. } " ] && Hostname = " $Hostname " "." " $2 "
echo " $Hostname "
}
2021-06-27 22:51:24 +02:00
SEDifyHostname( ) {
echo " $1 " | sed -r 's/\./\\\./g'
}
2021-01-14 20:46:10 +01:00
GetServernameSEDEntry( ) {
CommunityName = " $1 "
ServerName = " $DNSSCRIPT_SERVER_NAME "
if [ -z " ${ ServerName ##* $CommunityName } " ] ; then
ServerName = "\(" " $ServerName " ".\|" " ${ ServerName %*. $CommunityName } " "\)"
else
ServerName = "\(" " $ServerName " ".\)"
fi
2021-06-27 22:51:24 +02:00
SEDifyHostname " $ServerName "
2021-01-14 20:46:10 +01:00
}
2021-01-21 19:21:25 +01:00
NormalizeZoneFileFormatting( ) {
2021-03-10 00:02:15 +01:00
awk ' BEGIN{ FS = "\t" } { l = length( $1 ) ; f = substr( " " , 1+length( $1 ) ) ;
2021-01-21 19:21:25 +01:00
s = substr( " " , 1+length( $2 ) ) ;
x = substr( $0 ,length( $1 ) +length( $2 ) +3) ;
print $1 f " " $2 s " " x} '
}
2021-01-14 20:46:10 +01:00
GetOwnGlueRecords( ) {
ServerName = " $DNSSCRIPT_SERVER_NAME "
2021-02-08 01:34:03 +01:00
if [ -z " ${ ServerName ##* $2 } " ] ; then
ServerName = " ${ ServerName %. $2 } "
sed -ne 's/^\s*' " $( GetServernameSEDEntry " $1 " ) " '\s\+[Ii][Nn]\s\+\([Aa]\|[Aa]\{4\}\)\s\+\(.*\)$/' " $ServerName " '\tIN \2\t\3/p' " $3 " | \
NormalizeZoneFileFormatting
2021-01-14 20:46:10 +01:00
fi
}
GetOwnHoods( ) {
2021-02-01 20:59:32 +01:00
Entries = " $( sed -ne "s/^\s*\(\S*\).*\s\+[Ii][Nn]\s\+[Nn][Ss]\s\+" " $( GetServernameSEDEntry " $1 " ) " "\s*;\s*Subnets:\s*\([^;]*\)/\1 \3/p" " $2 " ) "
Entries = " $( echo " $Entries " | sed -e '/^[eE][xX][tT][eE][rR][nN]\s/d' | sed -r 's/\s+/#/g' ) "
2021-01-14 20:46:10 +01:00
echo " $Entries "
}
IsValidIPv4Subnet( ) {
[ -n " $( echo " $1 " | sed -e '/[^/]*\/\([12]\?[0-9]\|3[0-2]\)$/!d' ) " ] && IsValidIPv4 " ${ 1 %/* } "
return $?
}
IsValidIPv4( ) {
[ -n " $( echo " $1 " | sed -e '/^\(\(25[0-5]\|\(2[0-4]\|1[0-9]\|[1-9]\)\?[0-9]\)\.\)\{0,3\}\(25[0-5]\|\(2[0-4]\|1[0-9]\|[1-9]\)\?[0-9]\)$/!d' ) " ]
return $?
}
IsValidIPv6Subnet( ) {
[ -n " $( echo " $1 " | sed -e '/[^/]*\/\([1-9]\?[0-9]\|1\([01][0-9]\|2[0-8]\)\)$/!d' ) " ] && IsValidIPv6 " ${ 1 %/* } "
return $?
}
IsValidIPv6( ) {
Max8BlocksMax4Hex = " /^\([0-9a-fA-F]\{0,4\}[:]\{1,2\}\)\{1,7\}[0-9a-fA-F]\{0,4\} $/!d; "
MaxOneDoubleColon = " /^.*::.*::.* $/d; "
SingleColon8BlocksOrNoSingleColonBeginEnd = " /^\(\([^:]\+:\)\{7\}[^:]\+\|\(\|[^:].*\)::\(\|.*[^:]\)\) $/!d "
[ -n " $( echo " $1 " | sed -e " $Max8BlocksMax4Hex " " $MaxOneDoubleColon " " $SingleColon8BlocksOrNoSingleColonBeginEnd " ) " ]
return $?
}
IPv4IsInSubnet( ) {
IPFilled = " $( FillIPv4MissingBlocks " $1 " ) "
SubnetIPFilled = " $( FillIPv4MissingBlocks " ${ 2 %/* } " ) "
Mask = " ${ 2 ##*/ } "
Statics = $(( Mask / 8 ))
BlockMask = $(( Mask % 8 ))
IPStaticPart = " $( echo " $IPFilled " | awk -F. '{for(i=' " $Statics " ';i>0;--i)printf "."$i}' ) "
SubnetStaticPart = " $( echo " $SubnetIPFilled " | awk -F. '{for(i=' " $Statics " ';i>0;--i) printf "."$i}' ) "
AreEqual = " $( [ " $IPStaticPart " = " $SubnetStaticPart " ] ; echo " $? " ) "
if [ $AreEqual -eq 0 ] && [ $BlockMask -ne 0 ] ; then
2021-01-19 17:49:06 +01:00
BlockMask = $(( 8 - BlockMask))
2021-06-27 22:51:24 +02:00
BlockMask = $(( - 1 << $BlockMask ))
2021-01-14 20:46:10 +01:00
IPBlock = $( echo " $IPFilled " | awk -F. '{printf $' " $(( Statics+1)) " '}' )
SubnetBlock = $( echo " $SubnetIPFilled " | awk -F. '{printf $' " $(( Statics+1)) " '}' )
2021-01-19 17:49:06 +01:00
IPBlock = $(( IPBlock & BlockMask))
SubnetBlock = $(( SubnetBlock & BlockMask))
2021-01-14 20:46:10 +01:00
AreEqual = " $( [ $IPBlock -eq $SubnetBlock ] ; echo " $? " ) "
fi
2021-01-04 20:53:39 +01:00
2021-01-14 20:46:10 +01:00
return $AreEqual
2021-03-10 00:02:15 +01:00
}
GetOwnKeysForZone ( ) {
DNSSECKeyFolder = " $1 "
Domain = " $2 "
if [ -n " $DNSSECKeyFolder " ] ; then
for OwnKeyFile in " $DNSSECKeyFolder " "K" " $Domain " ".+" *".key" ; do
2021-07-23 00:14:10 +02:00
Removed = " $( sed -ne 's/^; Delete: \(\S\{12\}\).*/\1/p' " $OwnKeyFile " ) "
if [ -n " $Removed " ] ; then
Removed = " $( date -u -d " $Removed " '+%s' ) "
CurDate = " $( date -u '+%s' ) "
if [ $(( CurDate - Removed)) -le 172800 ] ; then
Removed = ""
fi
fi
if [ -z " $Removed " ] ; then
sed -ne '/^;/d;s/^' " $Domain " '\.\s\+\([0-9]*\s\)\?\s*[Ii][Nn]\s\+[Dd][Nn][Ss][Kk][Ee][Yy]\s\+\(.*\)$/_dnsseckeys\.' " $Domain " '\.\tIN TXT\t\"\2\"/p' " $OwnKeyFile " | \
NormalizeZoneFileFormatting
fi
2021-03-10 00:02:15 +01:00
done
fi
}
UpdateDNSSECEntryCache ( ) {
Domain = " $1 "
ZoneTempFolder = " $2 "
CachedZoneFile = " $3 "
DNSSECKeyFolder = " $4 "
UpdateMaster = 0
Nameservers = " $( GetAllZoneNameservers " $Domain " " $CachedZoneFile " ) "
mkdir -p " $ZoneTempFolder "
for KeyFile in " $ZoneTempFolder " *; do
2021-07-23 00:14:10 +02:00
[ " $KeyFile " = " $ZoneTempFolder " "*" ] || \
mv " $KeyFile " " $ZoneTempFolder " "Old" " ${ KeyFile ##* $ZoneTempFolder } "
2021-03-10 00:02:15 +01:00
done
2021-07-23 00:14:10 +02:00
if [ -n " $DNSSECKeyFolder " ] ; then
for Nameserver in $Nameservers ; do
if [ " $Nameserver " = " $DNSSCRIPT_SERVER_NAME " ] ; then
DNSKEYS = " $( GetOwnKeysForZone " $DNSSECKeyFolder " " $Domain " ) "
else
DNSKEYS = " $( delv @" $Nameserver " _dnsseckeys." $Domain " TXT 2>/dev/null | \
sed -ne '/^;/d;s/^.*\sIN\s\+TXT\s\+"\(.*\)"$/' " $Domain " '.\tIN DNSKEY\t\1/p' | \
NormalizeZoneFileFormatting ) "
fi
if [ -n " $DNSKEYS " ] && [ " $DNSKEYS " != " $( cat " $ZoneTempFolder " "OldKeys." " $Nameserver " 2>/dev/null) " ] ; then
echo " $DNSKEYS " > " $ZoneTempFolder " "Keys." " $Nameserver "
UpdateMaster = 1
elif [ -f " $ZoneTempFolder " "OldKeys." " $Nameserver " ] ; then
mv " $ZoneTempFolder " "OldKeys." " $Nameserver " " $ZoneTempFolder " "Keys." " $Nameserver "
fi
done
fi
2021-03-10 00:02:15 +01:00
2021-06-27 22:51:24 +02:00
SEDDomain = " $( SEDifyHostname " $Domain " ) "
2021-03-10 00:02:15 +01:00
ChildServers = " $( sed -ne '/^\s*\(@\|' " $SEDDomain " '\.\)\s/!s/^\s*\(\S\+\)\s\+\([0-9]*\s\)\?\s*[Ii][Nn]\s\+[Nn][Ss]\s\+\(\S\+\);\?.*$/\1#\3/p' " $CachedZoneFile " | \
sed -e 's/\([^.]\)$/\1\.' " $Domain " '\./g;s/\.$//g;s/\([^.]\)#/\1\.' " $Domain " '\.#/g;s/\.#/#/g' ) "
for ChildServer in $ChildServers ; do
DNSKEYS = " $( delv @" ${ ChildServer ##* \# } " " ${ ChildServer %% \# * } " CDS 2>/dev/null | \
sed -ne '/^;/d;s/^.*\sIN\s\+CDS\s\+\(.*\)$/' " ${ ChildServer %% \# * } " '.\tIN DS\t\1/p' | \
NormalizeZoneFileFormatting ) "
if [ -n " $DNSKEYS " ] ; then
DNSKEYS = " $( echo " $DNSKEYS " | sed -e '/\sIN\s\+DS\s\+0\s\+0\s\+0\s\+0/d' ) "
if [ " $DNSKEYS " != " $( cat " $ZoneTempFolder " "OldChildKeys." " $ChildServer " 2>/dev/null) " ] ; then
[ -z " $DNSKEYS " ] || echo " $DNSKEYS " > " $ZoneTempFolder " "ChildKeys." " $ChildServer "
UpdateMaster = 1
elif [ -n " $DNSKEYS " ] ; then
mv " $ZoneTempFolder " "OldChildKeys." " $ChildServer " " $ZoneTempFolder " "ChildKeys." " $ChildServer "
elif [ -f " $ZoneTempFolder " "OldKeys." " $Nameserver " ] ; then
UpdateMaster = 1
fi
elif [ -f " $ZoneTempFolder " "OldChildKeys." " $Nameserver " ] ; then
mv " $ZoneTempFolder " "OldChildKeys." " $ChildServer " " $ZoneTempFolder " "ChildKeys." " $ChildServer "
fi
done
for KeyFile in " $ZoneTempFolder " "Old" *; do
2021-07-23 00:14:10 +02:00
[ " $KeyFile " = " $ZoneTempFolder " "Old*" ] || \
2021-03-10 00:02:15 +01:00
rm -f " $KeyFile "
done
echo " $UpdateMaster "
2021-01-14 20:46:10 +01:00
}
2021-01-04 20:53:39 +01:00
ReloadZone( ) {
2021-07-23 00:14:10 +02:00
if [ -n " $2 " ] ; then
if [ $(( DNSSCRIPT_BIND_RELOAD_VER)) -eq 0 ] ; then
systemctl reload bind9 >/dev/null
elif [ $(( DNSSCRIPT_BIND_RELOAD_VER)) -eq 1 ] ; then
for Zone in $2 ; do
rndc reload " $1 " IN " $Zone " 2>"/tmp/dnsscript_rndcerr" >/dev/null || \
2021-07-27 01:47:58 +02:00
[ -n " $3 " ] && grep -q "failed: out of range" "/tmp/dnsscript_rndcerr" && \
rndc sync -clean " $1 " IN " $Zone " >/dev/null || \
touch "/tmp/dnsscript-forcereconf"
2021-07-23 00:14:10 +02:00
rm -f "/tmp/dnsscript_rndcerr"
done
elif [ $(( DNSSCRIPT_BIND_RELOAD_VER)) -eq 2 ] ; then
/etc/init.d/named reload >/dev/null
fi
2021-01-04 20:53:39 +01:00
fi
2021-01-19 17:49:06 +01:00
}
TraceErrAndExit( ) {
echo " $1 " 1>& 2
exit 1
2021-01-15 17:12:33 +01:00
}