dnscrypt-proxy.setup 11.1 KB
Newer Older
1
#!/bin/sh
2 3 4 5 6 7 8 9 10
# Contributor: Stuart Cardall <developer@it-offshore.co.uk>
# dnscrypt-proxy setup script to choose DNS Resolver & install / configure / remove DNS Caching
###############################################################################################

config='/etc/conf.d/dnscrypt-proxy'
dhcpconfig='/etc/dhcp/dhclient.conf'
unboundconfig='/etc/unbound/unbound.conf'

SCRIPT=$(echo "`basename $0`")
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

NORMAL="\033[1;0m"
STRONG="\033[1;1m"
RED="\033[1;31m"
GREEN="\033[1;32m"

print_question() {
        local prompt="${STRONG}$1 ${RED}$2${NORMAL}"
        printf "${prompt} %s"
}

print_strong() {
        local prompt="${STRONG}$1 ${RED}$2${NORMAL}"
        printf "${prompt} %s\n"
}

print_green() {
        local prompt="${GREEN}${STRONG}$1 ${NORMAL}"
        printf "${prompt} %s\n"
}

print_table() {
        local choice="${RED}${STRONG}$1${NORMAL}"
	local resolver="${STRONG}$2"
	local location="${GREEN}$3"
36
	printf "${choice} ${resolver} ${location} %s\n"
37 38 39 40 41 42 43
}

die() {
    print_table "ERROR:" "$1" > /dev/null 1>&2
    exit 1
}

44 45 46
restart_interface(){
INTERFACES=$(echo | ifconfig | grep "Link encap" | sed '/lo/d' | cut -d"L" -f1)
print_question "\nChoose external interface to restart from the following:"
47
print_question "\n\n$INTERFACES" "[ default: eth0 ]"
48 49 50 51 52 53 54 55

while :
do
	read RESTART
	# Sanitize input
	export RESTART_CLEAN="`echo "${RESTART}" | tr -cd '[:[alnum]:]'`"

	if [ ! $RESTART ] ;then
56
		RESTART_CLEAN=eth0
57 58
	fi

59
	# tr will strip invalid input to nothing which passes grep
60 61 62 63 64 65 66
	if [ "$RESTART_CLEAN" != "" ] && echo "$INTERFACES" | grep -e "$RESTART_CLEAN" 1>/dev/null; then
		break
	else
		#move the cursor & clear the line
		echo -en "\033[1A\033[28C\022[K"
	fi
done
67 68
}

69
choose_ip(){
70
IPADDR=$(ifconfig |grep -B1 "inet addr" |awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' |awk -F" " '{ print $1 ": " $3 }'| sed 's/addr//')
71
if echo "$IPADDR" | grep -e "127.0.0.2" 1>/dev/null && which unbound 1> /dev/null; then
72 73
        defaultip='127.0.0.2'
	IPADDR_CHOICE=$(echo "$IPADDR" | sed '/lo::127.0.0.1:/d')
74
else
75 76 77 78 79
        defaultip='127.0.0.1'
	IPADDR_CHOICE=$(echo "$IPADDR" | sed '/lo:1::127.0.0.2:/d')
fi

print_question "\nChoose Dnscrypt IP from the following addresses:\n"
80
print_question "\n$IPADDR_CHOICE\t" "[ default: $defaultip ]"
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

while :
do
	read IP
	# Sanitize input
        export IP_CLEAN="`echo "${IP}" | tr -cd '[:xdigit:] [:\::] [:\.:]'`"
	if [ ! $IP ]; then
		IP_CLEAN=$defaultip
	fi
	# tr will strip invalid input to nothing which passes grep
	if [ "$IP_CLEAN" != "" ] && echo "$IPADDR_CHOICE" | grep -e "$IP_CLEAN" 1>/dev/null; then
		print_green "\nIP: $IP_CLEAN Selected"; break
	else
		#move the cursor & clear the line
		echo -en "\033[1A\033[49C\033[K"
	fi
done
98 99 100
}

choose_port(){
101 102 103 104 105 106
if grep -e "127.0.0.2" /etc/network/interfaces 1>/dev/null; then
	defaultport=40
else
	defaultport=53
fi

107
print_question "\nChoose Dnscrypt Port:" "[ default: $defaultport ]"
108
while :
109 110
do
        read DNSPORT
111 112
	# Sanitize input to an integer and assign to new variable
	export DNSPORT_CLEAN="`echo "${DNSPORT}" | tr -cd '[:[0-9]:]'`"
113
        if [ ! $DNSPORT ]; then
114
		DNSPORT_CLEAN=$defaultport
115 116
        fi

117 118 119 120
	if [ $DNSPORT_CLEAN -gt 0 2>/dev/null ] && [ $DNSPORT_CLEAN -le 65535 2>/dev/null ]; then
		print_green "\nPort: $DNSPORT_CLEAN Selected"; break
	else
		#move the cursor & clear the line
121
		echo -en "\033[1A\033[39C\033[K"
122
	fi
123 124 125 126
done
}

update_unbound(){
127 128
if [ -f $unboundconfig ]; then
	if grep "Settings from "$SCRIPT"" $unboundconfig 1>/dev/null; then
129
		#update forward zone
130 131 132 133
		START=$(sed -n "\%Settings from $SCRIPT%=" $unboundconfig)
		LINE=$(expr $START + 3 )
		sed "$LINE c \  forward-addr: $IP_CLEAN@$DNSPORT_CLEAN" $unboundconfig -i

134
	else
135
		# allow querying of localhost
136 137
		START=$(sed -n '/do-not-query-localhost:/=' $unboundconfig)
		sed "$START c \do-not-query-localhost: no #set by $SCRIPT" $unboundconfig -i
138
		# create catch all forward zone
139 140 141 142
		echo -e "##### Settings from $SCRIPT #####" >> $unboundconfig
		echo -e 'forward-zone:' >> $unboundconfig
		echo -e '  name: "."' >> $unboundconfig
		echo -e "  forward-addr: $IP_CLEAN@$DNSPORT_CLEAN" >> $unboundconfig
143
	fi
144
print_strong "\n$unboundconfig settings updated to:"
145
print_green "--------------------------------------------------------"
146 147
print_table "do-not-query-localhost: no"
print_table ""
148 149
print_table 'forward-zone:'
print_table '  name: "."'
150
print_table "  forward-addr: $IP_CLEAN@$DNSPORT_CLEAN"
151
print_green "--------------------------------------------------------"
152 153 154
fi
}

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
restart_services(){
# add / restart services - dnscrypt must be restarted first
echo ""
for srv in "dnscrypt-proxy" "unbound"; do
        if which $srv 1> /dev/null; then
                rc-status default | grep $srv 1> /dev/null
                if [ "$?" != "0" ]; then
                        print_green "Adding $srv to Default Run Level"
                        rc-update add $srv default
                fi
                rc-service $srv restart
        fi
done
}

modify_config(){
choose_ip; choose_port

# update dnscrypt listening ip & port
LINE=$(sed -n '/DNSCRYPT_LOCALIP=/=' $config)
sed "$LINE c DNSCRYPT_LOCALIP=$IP_CLEAN:$DNSPORT_CLEAN" $config -i

# update dhclient.conf
if [ -f $dhcpconfig ]; then
	if grep 'supersede domain-name-servers' $dhcpconfig 1>/dev/null; then
		LINE=$(sed -n '/supersede domain-name-servers/=' $dhcpconfig)
		sed "$LINE c supersede domain-name-servers $IP" $dhcpconfig -i
	else
		echo "supersede domain-name-servers $IP" >> $dhcpconfig
	fi
fi

# update resolv.conf & unbound
LINE=$(sed -n '/nameserver/=' /etc/resolv.conf)
sed "$LINE c nameserver 127.0.0.1" /etc/resolv.conf -i
if [ "$removecache" != "Y" ] && [ "$removecache" != "y" ]; then
	update_unbound
fi

restart_interface

print_strong "\n/etc/conf.d/dnscrypt-proxy Listening Address updated to:"
print_green "--------------------------------------------------------"
print_table "DNSCRYPT_LOCALIP=$IP_CLEAN:$DNSPORT_CLEAN"
print_green "--------------------------------------------------------\n"
}

rm_loopback(){
START=$(sed -n "\%Settings from $SCRIPT%=" /etc/network/interfaces)
LINE=$(expr $START + 4)
sed -i ''$START','$LINE'd' /etc/network/interfaces
print_green "2nd Loopback interface removed"
}

209 210
# END Functions ###################################################################################

211 212
# Do some sanity checking.
if [ $(/usr/bin/id -u) != "0" ]; then
213 214 215 216 217
   die 'DNScrypt Setup must be run by root'
fi

##### Download DNS Resolver details ################################################################

218
url='https://raw.githubusercontent.com/jedisct1/dnscrypt-proxy/master/dnscrypt-resolvers.csv'
219 220 221
output='/tmp/dnscrypt.list'

echo -e "Retrieving current list of free DNS Resolvers\n"
222
wget -q --no-check-certificate $url -O $output
223
sed -i 's|\"||g' $output
224

225
totalservers=$(cat $output | tail -n +2 | wc -l)
226 227 228

if [ $totalservers = 0 ]; then
	die "Could not contact $url"
229 230
fi

231 232
# colour table ##################################################################################

233
colourheading=$(awk 'BEGIN { format = "%-8s%-35s%-30s%-10s%-10s%-10s%-25s\n"
234 235
	printf format, "#", "Name", "Location", "DNSSEC", "No Logs", "Namecoin", "Resolver Address" }')

236 237 238
colourline=$(awk 'BEGIN { format = "%-8s%-35s%-30s%-10s%-10s%-10s%-25s\n"
	printf format, "----", "----------------------------------------", "------------------------------", "----------",\
			"----------", "----------", "-----------------------------------" }')
239 240 241 242

print_green "$colourheading"
print_green "$colourline"

243 244
tmpfile=$(mktemp)

245
cat $output | awk 'BEGIN{FS=""}{gsub(/,\ /,"\ "); print}' | tail -n +2 > $tmpfile
246

247
awk -F"\," 'BEGIN {format="%-8s%-35s%-30s%-10s%-10s%-10s%-25s\n"}{ printf format, "\["NR"\]",$1,$4,$8,$9,$10,$11}' $tmpfile
248 249 250 251 252 253 254

print_green "$colourline"
print_question "Please choose a DNS Resolver for dnscrypt-proxy to query:" "[1 - $totalservers]"

###### Process Input #############################################################################

while :
255
do
256 257 258
	read DNS
	# Sanitize input to an integer
	export DNS_CLEAN="`echo "${DNS}" | tr -cd '[:[0-9]:]'`"
259

260 261 262 263 264 265
	if [ $DNS_CLEAN -gt 0 2>/dev/null ] && [ $DNS_CLEAN -le $totalservers 2>/dev/null ]; then
		break
	else
		#move the cursor & clear the line
		echo -en "\033[1A\033[67C\033[K"
	fi
266 267
done

268 269 270
RESOLVER=$(cat $tmpfile | tr -d "\"" | tr "," ";" | sed -n "$DNS_CLEAN"p |awk -F';' '{print $11}')
PROVIDER=$(cat $tmpfile | tr -d "\"" | tr "," ";" | sed -n "$DNS_CLEAN"p |awk -F';' '{print $12}')
PUBKEY=$(cat $tmpfile | tr -d "\"" | tr "," ";" | sed -n "$DNS_CLEAN"p |awk -F';' '{print $13}')
271 272 273 274 275 276 277 278 279

######## END Changes ###########################################################################

if [ ! -f "$config" ]; then
	touch $config
	echo "DNSCRYPT_LOGFILE=/var/log/dnscrypt-proxy/dnscrypt-proxy.log" >> $config
	echo "DNSCRYPT_LOCALIP=127.0.0.1:53" >> $config
fi

280
# remove existing Resolver config
281
if grep "RESOLVER" $config 1> /dev/null; then
282
	sed -e '/RESOLVER/d' -e '/PROVIDER/d' -e '/PUBKEY/d' $config -i
283 284 285
fi

# update Resolver config
286 287 288
echo "RESOLVER=$RESOLVER" >> $config
echo "PROVIDER=$PROVIDER" >> $config
echo "PUBKEY=$PUBKEY" >> $config
289

290
print_strong "\nResolver Settings updated in:" "$config"
291
print_green "---------------------------------------------------------------------------------------------"
292 293
print_table "RESOLVER   :" "$RESOLVER"
print_table "PROVIDER   :" "$PROVIDER"
294
print_table "PUBLIC KEY :" "$PUBKEY"
295
print_green "---------------------------------------------------------------------------------------------"
296 297 298

# install unbound
if ! which unbound 1> /dev/null; then
299 300 301 302 303 304 305
	print_question "Install Unbound (Caching DNS Server)" "[ Y / N: Default ]"
	read installsrv
	if [ "$(echo $installsrv | tr '[A-Z]' '[a-z]')" = "y" ]; then
	      apk add -q unbound
	else
	      echo "nameserver 127.0.0.1" > /etc/resolv.conf
	fi
306 307
fi

308 309
# check for / setup secondary loopback for dns caching
if which unbound 1> /dev/null && ! grep "address 127.0.0.2" /etc/network/interfaces 1> /dev/null; then
310 311 312 313 314 315 316 317 318
	IP=127.0.0.2
	echo "##### Settings from $SCRIPT #####" >> /etc/network/interfaces
	echo "auto lo:1" >> /etc/network/interfaces
	echo "iface lo:1 inet static" >> /etc/network/interfaces
	echo "address $IP" >> /etc/network/interfaces
	echo "netmask 255.0.0.0" >> /etc/network/interfaces
	ifconfig lo:1 $IP up
fi

319
# modify caching
320 321 322 323 324 325 326 327
if grep "address 127.0.0.2" /etc/network/interfaces 1> /dev/null && [ ! $installsrv ]; then
	print_question "\nRemove DNS Caching (Unbound) / Secondary loopback device ?" "[ Y / N: Default ]"; read removecache
	if [ "$(echo $removecache | tr '[A-Z]' '[a-z]')" = "y" ]; then
		# remove loopback settings
		rm_loopback
		echo -e ""; rc-service unbound stop; apk del unbound
	else
		print_green "\nSecondary Loopback for DNS Caching configured @ 127.0.0.2"
328 329 330 331
		IP=127.0.0.2
	fi
fi

332 333 334 335 336 337 338 339 340 341 342 343
# modify ip / ports
if [ $installsrv ] || [ "$(echo $removecache | tr '[A-Z]' '[a-z]')" = "y" ]; then
	modify_config
elif grep -q 127.0.0.2 /etc/network/interfaces && ! which unbound 1> /dev/null; then
	rm_loopback
	kill $(cat /var/run/unbound/unbound.pid)
	modify_config
else
	print_question "\nModify dnscrypt-proxy ip / port ?" "[ Y / N: default ]"; read updateip
	if [ "$(echo $updateip | tr '[A-Z]' '[a-z]')" = "y" ]; then
		modify_config
	fi
344 345
fi

346 347 348
if [ "$RESTART_CLEAN" != "" ]; then
	ifdown $RESTART_CLEAN && ifup $RESTART_CLEAN
	print_green "Interface $RESTART_CLEAN restarted"
349 350
fi

351
restart_services
352

353
exit 0
354