1#!/bin/sh
2# update-anchor.sh, update a trust anchor.
3# Copyright 2008, W.C.A. Wijngaards
4# This file is BSD licensed, see doc/LICENSE.
5
6# which validating lookup to use.
7ubhost=unbound-host
8
9usage ( )
10{
11	echo "usage: update-anchor [-r hs] [-b] <zone name> <trust anchor file>"
12	echo "    performs an update of trust anchor file"
13	echo "    the trust anchor file is overwritten with the latest keys"
14	echo "    the trust anchor file should contain only keys for one zone"
15	echo "    -b causes keyfile to be made in bind format."
16	echo "       without -b the file is made in unbound format."
17	echo "    "
18	echo "alternate:"
19	echo "    update-anchor [-r hints] [-b] -d directory"
20	echo "    update all <zone>.anchor files in the directory."
21	echo "    "
22	echo "    name the files br.anchor se.anchor ..., and include them in"
23	echo "    the validating resolver config file."
24	echo "    put keys for the root in a file with the name root.anchor."
25	echo ""
26	echo "-r root.hints	use different root hints. Strict option order."
27	echo ""
28	echo "Exit code 0 means anchors updated, 1 no changes, others are errors."
29	exit 2
30}
31
32if test $# -eq 0; then
33	usage
34fi
35bindformat="no"
36filearg='-f'
37roothints=""
38if test X"$1" = "X-r"; then
39	shift
40	roothints="$1"
41	shift
42fi
43if test X"$1" = "X-b"; then
44	shift
45	bindformat="yes"
46	filearg='-F'
47fi
48if test $# -ne 2; then
49	echo "arguments wrong."
50	usage
51fi
52
53do_update ( ) {
54	# arguments: <zonename> <keyfile>
55	zonename="$1"
56	keyfile="$2"
57	tmpfile="/tmp/update-anchor.$$"
58	tmp2=$tmpfile.2
59	tmp3=$tmpfile.3
60	rh=""
61	if test -n "$roothints"; then
62		echo "server: root-hints: '$roothints'" > $tmp3
63		rh="-C $tmp3"
64	fi
65	$ubhost -v $rh $filearg "$keyfile" -t DNSKEY "$zonename" >$tmpfile
66	if test $? -ne 0; then
67		rm -f $tmpfile
68		echo "Error: Could not update zone $zonename anchor file $keyfile"
69		echo "Cause: $ubhost lookup failed" 
70		echo "    (Is the domain decommissioned? Is connectivity lost?)"
71		return 2
72	fi
73
74	# has the lookup been DNSSEC validated?
75	if grep '(secure)$' $tmpfile >/dev/null 2>&1; then
76		:
77	else
78		rm -f $tmpfile
79		echo "Error: Could not update zone $zonename anchor file $keyfile"
80		echo "Cause: result of lookup was not secure" 
81		echo "    (keys too far out of date? domain changed ownership? need root hints?)"
82		return 3
83	fi
84
85	if test $bindformat = "yes"; then
86		# are there any KSK keys on board?
87		echo 'trusted-keys {' > "$tmp2"
88		if grep ' has DNSKEY record 257' $tmpfile >/dev/null 2>&1; then
89			# store KSK keys in anchor file
90			grep '(secure)$' $tmpfile | \
91			grep ' has DNSKEY record 257' | \
92			sed -e 's/ (secure)$/";/' | \
93			sed -e 's/ has DNSKEY record \([0-9]*\) \([0-9]*\) \([0-9]*\) /. \1 \2 \3 "/' | \
94			sed -e 's/^\.\././' | sort >> "$tmp2"
95		else
96			# store all keys in the anchor file
97			grep '(secure)$' $tmpfile | \
98			sed -e 's/ (secure)$/";/' | \
99			sed -e 's/ has DNSKEY record \([0-9]*\) \([0-9]*\) \([0-9]*\) /. \1 \2 \3 "/' | \
100			sed -e 's/^\.\././' | sort >> "$tmp2"
101		fi
102		echo '};' >> "$tmp2"
103	else #not bindformat
104		# are there any KSK keys on board?
105		if grep ' has DNSKEY record 257' $tmpfile >/dev/null 2>&1; then
106			# store KSK keys in anchor file
107			grep '(secure)$' $tmpfile | \
108			grep ' has DNSKEY record 257' | \
109			sed -e 's/ (secure)$//' | \
110			sed -e 's/ has DNSKEY record /. IN DNSKEY /' | \
111			sed -e 's/^\.\././' | sort > "$tmp2"
112		else
113			# store all keys in the anchor file
114			grep '(secure)$' $tmpfile | \
115			sed -e 's/ (secure)$//' | \
116			sed -e 's/ has DNSKEY record /. IN DNSKEY /' | \
117			sed -e 's/^\.\././' | sort > "$tmp2"
118		fi
119	fi # endif-bindformat
120
121	# copy over if changed
122	diff $tmp2 $keyfile >/dev/null 2>&1
123	if test $? -eq 1; then   # 0 means no change, 2 means trouble.
124		cat $tmp2 > $keyfile
125		no_updated=0
126		echo "$zonename key file $keyfile updated."
127	else
128		echo "$zonename key file $keyfile unchanged."
129	fi
130
131	rm -f $tmpfile $tmp2 $tmp3
132}
133
134no_updated=1
135if test X"$1" = "X-d"; then
136	tdir="$2"
137	echo "start updating in $2"
138	for x in $tdir/*.anchor; do
139		if test `basename "$x"` = "root.anchor"; then
140			zname="."
141		else
142			zname=`basename "$x" .anchor`
143		fi
144		do_update "$zname" "$x"
145	done
146	echo "done updating in $2"
147else
148	# regular invocation
149	if test X"$1" = "X."; then
150		zname="$1"
151	else
152		# strip trailing dot from zone name
153		zname="`echo $1 | sed -e 's/\.$//'`"
154	fi
155	kfile="$2"
156	do_update $zname $kfile
157fi
158exit $no_updated
159