443 lines
12 KiB
Bash
Executable File
443 lines
12 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# "$Revision: 1.5 $"
|
|
|
|
# Synopsis:
|
|
# -v be verbose
|
|
# -t test; generate new files but do not install them
|
|
# -d domain choose a NIS domain other than the current NIS domain
|
|
# -i file use the contents of 'file' instead of `ypcat hosts`
|
|
# /etc/hosts is the most likely file.
|
|
# -n nets blank separated, quoted list of network numbers to generate
|
|
# .rev files, even if no host of the target domain is on
|
|
# them. For example, -n "192.26.81 192.99.44"
|
|
# -N nets blank separated, quoted list of networks to exclude
|
|
# from .rev files
|
|
# -m first-last,mask first and last IP addresses of subnet with mask
|
|
# -h hosts blank separated, quoted list of hosts on which
|
|
# 'rsh host -l guest ypcat hosts' will produce interesing
|
|
# hostnames.
|
|
# -H name hostname of this machine, if not available by the
|
|
# hostname command.
|
|
# -A ouraddr IP address of this machine, if not available by looking
|
|
# up the hostname of this machine in /etc/hosts.
|
|
# -s prf MX preference for ourself
|
|
# -x 'prf xchg' a pair of MX exchanger and preference, as in
|
|
# -x '10 foo.foo.com.'
|
|
# additional pairs can be given with additional occurances
|
|
# of -x
|
|
# -O dir save previous versions of data files in this directory
|
|
|
|
|
|
# This script generates data files for the BIND DNS nameserver, named, from
|
|
# a file (e.g. /etc/hosts) or a NIS hostname database. Because it can use
|
|
# NIS to obtain the data, the DNS master need not run on the same machine
|
|
# as the NIS master.
|
|
|
|
# This script is usually run from cron if it is generating the DNS database
|
|
# files from /etc/hosts. If cooperating with NIS, it is usually run
|
|
# from /var/yp/local.make.script. A sample local.make.script can
|
|
# be found in /var/named/mkdns.
|
|
|
|
# It uses two prototype SOA files, domain.soa (where "domain" is the NIS
|
|
# domain) and hosts.soa, to generate SOA records. It modifies the words
|
|
# SERIALNUMBER, HOSTNAME, and HOSTADDR in the prototypes, so that the
|
|
# prototypes can serve for more than one domain. Sample SOA prototype
|
|
# files are also in the examples directory.
|
|
|
|
# Besides generating the hosts data file and the reverse map data file, it
|
|
# also modifies the named.boot file to point to the other files. These
|
|
# modifications of the named.boot file are delimited by a pair of lines,
|
|
# allowing this script to modify only the part of named.boot that it owns.
|
|
|
|
# "Foreign" DNS hosts that happen to be in the the NIS or /etc/hosts input
|
|
# can be excluded from the results, even if the foreigners have aliases in
|
|
# the target domain. This is the purpose of the -N arg.
|
|
|
|
# Much of the complexity of this script comes from generating CNAME
|
|
# records and the reverse maps. Both are done with awk scripts. The
|
|
# difficulty with the CNAME records is recognizing only those aliases that
|
|
# should appear in the DNS database. The difficulty with the reverse maps
|
|
# is generating separate files for each of the IN-ADDR.ARPA domains implied
|
|
# by the set of host numbers present in the input data.
|
|
|
|
# When new versions of the files have been generated, this script
|
|
# installs them only if they differ substantitively. If it does install
|
|
# new files, it signals the nameserver daemon.
|
|
|
|
|
|
|
|
USAGE="`basename $0`: [-vt] [-d domain] [-i file] [-n nets] [-N nets] [-h hosts] [-H ourname] [-A ouraddr] [-s prf] [-x 'prf xchg'] "
|
|
|
|
if [ -x /usr/bin/domainname ]
|
|
then
|
|
domain=`domainname`
|
|
fi
|
|
|
|
name=`hostname | sed -e "s/^[^.]*$/&.$domain/"`
|
|
olddir=old
|
|
|
|
while getopts "vtd:i:n:N:m:h:H:A:s:x:O:" c; do
|
|
case $c in
|
|
v) set -x;;
|
|
t) dotest="y";;
|
|
d) domain=`echo "$OPTARG" | tr '[A-Z]' [a-z]'`;;
|
|
i) ifile="$OPTARG"
|
|
if test ! -f $ifile; then
|
|
echo "`basename $0`: $OPTARG: no such file"
|
|
exit 1
|
|
fi
|
|
;;
|
|
n) nets="$nets "`echo "$OPTARG" | sed -e 's@[^ ]*@/^&./bprint@g'`;;
|
|
N) nets="$nets "`echo "$OPTARG" | sed -e 's@[^ ]*@/^&./d@g'`;;
|
|
m) if test -z "$masks"; then
|
|
masks="$OPTARG"
|
|
else
|
|
masks="$masks $OPTARG"
|
|
fi
|
|
;;
|
|
h) hosts="$hosts $OPTARG";;
|
|
H) name="$OPTARG";;
|
|
A) addr="$OPTARG";;
|
|
s) mypref="$OPTARG";;
|
|
x) mxs="$mxs\t\t\t MX `echo $OPTARG | sed 's/ */ \\\t/'`\n";;
|
|
O) olddir="$OPTARG"
|
|
if test ! -d "$olddir"; then
|
|
echo "`basename $0`: $OPTARG: no such directory"
|
|
exit 1
|
|
fi
|
|
;;
|
|
\?) echo $USAGE; exit 1;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$domain" ]
|
|
then
|
|
echo "please used -d option to specify domain name"
|
|
exit
|
|
fi
|
|
|
|
shift `expr $OPTIND - 1`
|
|
if test "$#" != 0; then
|
|
echo $USAGE
|
|
exit 1
|
|
fi
|
|
|
|
if test -n "$dotest"; then
|
|
tmpfile="/tmp/mkdns.tmp"
|
|
tmp2file="/tmp/gen2n"
|
|
tmp3file="/tmp/gen3n"
|
|
tmpsoa="/tmp/gensoa"
|
|
tmpsed="/tmp/gensed"
|
|
testdir=/tmp/
|
|
else
|
|
tmpfile="/tmp/mkdns$$"
|
|
tmp2file="/tmp/gen2n$$"
|
|
tmp3file="/tmp/gen3n$$"
|
|
tmpsoa="/tmp/gensoa$$"
|
|
tmpsed="/tmp/gensed$$"
|
|
testdir=""
|
|
rem="$tmpfile $tmp2file $tmp3file $tmpsoa $tmpsed"
|
|
trap "/bin/rm -f $rem" 0 1 2 15
|
|
fi
|
|
|
|
cd /var/named
|
|
|
|
# chose short version of domain name
|
|
subdomain=`expr "$domain" : '\([^.]*\)\..*'`
|
|
|
|
# literalized version
|
|
litdomain=`echo ".$domain" | sed 's/\./\\\./g'`
|
|
|
|
# find our network address, the addresss of the server
|
|
if test "$addr" = ""; then
|
|
addr=`egrep "^[0-9.]*[ ][ ]*$name[. ]|^[0-9.]*[ ][ ]*[ ]$name'$'" /etc/hosts \
|
|
| sed -e '2,$d' -e "s/[ ].*//"`
|
|
fi
|
|
new="new"
|
|
hostfile="$subdomain.hosts"
|
|
revfile="$subdomain.%s.rev"
|
|
nboot="named.boot"
|
|
nnboot="$testdir$nboot.$new"
|
|
soa="$subdomain.soa"
|
|
|
|
if test -f $testdir${subdomain}*.$new $nnboot $rem; then
|
|
# remove previous crop of new files
|
|
rm -f $testdir${subdomain}*.$new $nnboot $rem
|
|
fi
|
|
|
|
|
|
# generate a sed script to find network numbers and hostnames for the
|
|
# interesting networks.
|
|
echo "s/ \{2,\}/ /g" > $tmpsed
|
|
echo "/^[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\} [^ ]/!d" >> $tmpsed
|
|
echo "s/^\([^.]*\).\([^.]*\).\([^.]*\).\([^ ]*\) \([^ ]*\).*/\1 \2 \3 \4 \5/" >> $tmpsed
|
|
echo "$nets" | tr ' ' '\12' | sed -e '/^$/d' -e 's/\./ /g' >> $tmpsed
|
|
|
|
|
|
if test ! -s "$soa"; then
|
|
echo "`basename $0`: $soa is missing"
|
|
exit 1
|
|
fi
|
|
serial=`date '+%y%j%H%M'`
|
|
sed -e "s/SERIALNUMBER/$serial/g" \
|
|
-e "s/HOSTNAME/$name/g" -e "s/HOSTADDR/$addr/g" $soa > $tmpsoa
|
|
|
|
if test ! -s "$nboot"; then
|
|
echo "`basename $0`: $nboot is missing"
|
|
exit 1
|
|
fi
|
|
fline="; do not delete this 1st line--generated by mkdns"
|
|
lline="; do not delete this 2nd line--generated by mkdns"
|
|
sed -e "/^$fline/,"'$d' $nboot > $nnboot
|
|
echo "$fline" >> $nnboot
|
|
|
|
# Generate the SOA records.
|
|
cp $tmpsoa $testdir$hostfile.$new
|
|
if test -s ${subdomain}.hosts.soa; then
|
|
sed -e "s/SERIALNUMBER/$serial/g" \
|
|
-e "s/HOSTNAME/$name/g" -e "s/HOSTADDR/$addr/g" \
|
|
${subdomain}.hosts.soa >> $testdir$hostfile.$new
|
|
fi
|
|
|
|
|
|
# Get the data from NIS
|
|
|
|
if test $ifile; then
|
|
cat $ifile | tr '[A-Z] ' '[a-z] ' > $tmpfile
|
|
else
|
|
#it seems to take more than one try to get a server
|
|
ypcat -d $domain hosts.byaddr 2>/dev/null \
|
|
| tr '[A-Z] ' '[a-z] ' >$tmpfile
|
|
# it sometimes takes a while to find a server
|
|
if test ! -s "$tmpfile"; then
|
|
sleep 5
|
|
ypcat -d $domain hosts.byaddr | tr '[A-Z] ' '[a-z] ' >$tmpfile
|
|
if test ! -s "$tmpfile"; then
|
|
echo "`basename $0`: unable to obtain NIS host information"
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
cp $tmpfile $tmp3file
|
|
for nm in $hosts; do
|
|
rsh $nm -n -l guest ypcat hosts > $tmp2file
|
|
if test ! -s $tmp2file; then
|
|
echo "`basename $0`: no hosts from $nm"
|
|
exit 1
|
|
fi
|
|
cat $tmp2file | tr '[A-Z] ' '[a-z] ' >> $tmp3file
|
|
done
|
|
|
|
|
|
# Delete non-host lines, add a trailing blank, and remove extra blanks.
|
|
# Delete hosts at least one of whose names does not include the
|
|
# target domain.
|
|
# Delete aliases with the wrong domain name.
|
|
# Remove the domain from all names.
|
|
# Remove domain-names of the wrong domain.
|
|
# Then replace the periods in the address with blanks.
|
|
sed -e "/^[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\} /!d" \
|
|
-e "s/.*/& /" -e "s/ \{2,\}/ /g" \
|
|
-e "/ [^.]*$litdomain /!d" \
|
|
-e "s/$litdomain / /g" \
|
|
-e "s/ [^ ]*\.[^ ]*//g" \
|
|
-e "/^[0-9.]* *$/d" \
|
|
-e "s/^\([^.]*\).\([^.]*\).\([^.]*\)./\1 \2 \3 /" \
|
|
-e "s/ \{2,\}/ /g" \
|
|
$tmp3file \
|
|
| sort -u -n +1n -2 +2n -3 +3n -4 \
|
|
| nawk 'BEGIN {
|
|
new = "'"$new"'"
|
|
hostfile = "'"$hostfile"'"
|
|
newhostfile = "'"$testdir$hostfile.$new"'"
|
|
domain = "'"$domain"'"
|
|
newnboot = "'"$nnboot"'"
|
|
tmpsed = "'"$tmpsed"'"
|
|
mypref = "'"$mypref"'"
|
|
mxs = "'"$mxs"'"
|
|
|
|
printf "primary %-30s %s\n",
|
|
domain, hostfile >> newnboot
|
|
}
|
|
|
|
{
|
|
host = $5
|
|
|
|
printf "%-23s IN A %s\n", host,
|
|
($1 "." $2 "." $3 "." $4) >> newhostfile
|
|
if (mypref != "") {
|
|
printf "\t\t\t MX %-2d \t%s\n",
|
|
mypref, host >> newhostfile
|
|
}
|
|
printf mxs >> newhostfile
|
|
for (i = 6; i <= NF; i++) {
|
|
for (j = 5; j < i; j++) {
|
|
if ($i == $j)
|
|
break
|
|
}
|
|
if (j >= i) {
|
|
printf "%-23s IN CNAME\t%s\n", $i,
|
|
host >> newhostfile
|
|
}
|
|
}
|
|
|
|
newpat = "/^" $1 " "
|
|
if ($1 >= 128) {
|
|
newpat = newpat $2 " "
|
|
if ($1 >= 192) {
|
|
newpat = newpat $3 " "
|
|
}
|
|
}
|
|
if (newpat != pat) {
|
|
pat = newpat
|
|
print (pat "/bprint") >> tmpsed
|
|
}
|
|
}'
|
|
|
|
|
|
echo "d\n:print" >> $tmpsed
|
|
sed -f $tmpsed $tmp3file \
|
|
| sort -u -n +1n -2 +2n -3 +3n -4 \
|
|
| nawk 'BEGIN {
|
|
OFMT = "%10.0f"
|
|
|
|
new = "'"$new"'"
|
|
testdir = "'"$testdir"'"
|
|
revfile = "'"$revfile"'"
|
|
domain = "'"$domain"'"
|
|
newnboot = "'"$nnboot"'"
|
|
tmpsoa = "'"$tmpsoa"'"
|
|
net = -1
|
|
maskz = 256*256*256*256
|
|
maska = 256*256*256
|
|
maskb = 256*256
|
|
maskc = 256
|
|
|
|
split("'"$masks"'", t, " ")
|
|
for (i in t) {
|
|
split(t[i], m, ",")
|
|
if (m[1] ~ /\./) {
|
|
split(m[1], a, ".")
|
|
m[1] = ((a[1] * 256 + a[2]) * 256 + a[3]) * 256 + a[4]
|
|
}
|
|
if (m[2] ~ /\./) {
|
|
split(m[2], a, ".")
|
|
m[2] = ((a[1] * 256 + a[2]) * 256 + a[3]) * 256 + a[4]
|
|
}
|
|
if (m[3] ~ /\./) {
|
|
split(m[3], a, ".")
|
|
m[3] = ((a[1] * 256 + a[2]) * 256 + a[3]) * 256 + a[4]
|
|
}
|
|
m[3] = maskz - m[3]
|
|
masks[m[1]] = m[3]
|
|
hi[m[1]] = m[2]
|
|
}
|
|
}
|
|
|
|
func revhost(n,mask) {
|
|
n %= mask
|
|
r = n%256
|
|
n = int(n/256)
|
|
if (mask > maskc) {
|
|
r = r "." (n%256)
|
|
n = int(n/256)
|
|
if (mask > maskb) {
|
|
r = r "." (n%256)
|
|
n = int(n/256)
|
|
if (mask > maska) {
|
|
r = r "." (n%256)
|
|
}
|
|
}
|
|
}
|
|
return r
|
|
}
|
|
|
|
{
|
|
host = $5
|
|
addr = (($1 * 256 + $2) * 256 + $3) * 256 + $4
|
|
|
|
if ($1 == "127" && $2 == "0" && $3 == "0") {
|
|
netmask = maskc
|
|
} else {
|
|
if (host !~ /\./) host = host "." domain
|
|
if ($1 < 128) {
|
|
netmask = maska
|
|
} else if ($1 < 192) {
|
|
netmask = maskb
|
|
} else {
|
|
netmask = maskc
|
|
}
|
|
for (lo in masks) {
|
|
if (addr >= lo && addr <= hi[lo]) {
|
|
netmask = masks[lo]
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
newnet = int(addr/netmask)
|
|
if (newnet != net) {
|
|
if (curfile != "") {
|
|
close(curfile)
|
|
}
|
|
net = newnet
|
|
revnet = revhost(net,int(maskz/netmask))
|
|
curfile = sprintf(revfile,revnet)
|
|
printf "primary %-30s %s\n",
|
|
(revnet ".IN-ADDR.ARPA"), curfile >> newnboot
|
|
curfile = (testdir curfile "." new)
|
|
system("cp " tmpsoa " " curfile)
|
|
}
|
|
printf "%-10s IN PTR %s.\n",
|
|
revhost(addr,netmask), host >> curfile
|
|
}'
|
|
|
|
echo "$lline" >> $nnboot
|
|
sed -e "1,/^$lline/d" $nboot >> $nnboot
|
|
|
|
if test "$dotest"; then
|
|
exit 0
|
|
fi
|
|
|
|
|
|
# do not stop now
|
|
trap "" 1 2 15
|
|
|
|
# delete obsolete files
|
|
if test -d "$olddir" -a -n "$dotest"; then
|
|
for oldnm in ${subdomain}*.hosts ${subdomain}*.rev $nboot; do
|
|
if test -f $oldnm -a ! -f $oldnm.$new; then
|
|
oldnms="$oldnms $oldnm"
|
|
rm -f $olddir/$oldnm
|
|
mv $oldnm $olddir/$oldnm
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# install new versions
|
|
for newnm in ${testdir}${subdomain}*.new $nnboot; do
|
|
oldnm=`expr $newnm : '\(.*\)\.'"$new"`
|
|
if cmp -s $newnm $oldnm; then
|
|
rm -f $newnm
|
|
elif test ! -f $oldnm; then
|
|
mv -f $newnm $oldnm
|
|
elif test 0 -ne `diff $newnm $oldnm \
|
|
| sed -e '/^[-0-9]/d' -e '/^[<>][0-9; ]*Serial$/d' \
|
|
| wc -l`; then : ;
|
|
if test -d "$olddir"; then
|
|
rm -f $olddir/$oldnm
|
|
ln $oldnm $olddir/$oldnm
|
|
fi
|
|
mv -f $newnm $oldnm
|
|
else
|
|
rm -f $newnm
|
|
fi
|
|
done
|
|
|
|
rm -f $oldnms
|
|
|
|
killall 1 named
|
|
exit 0
|