2 # Begin $rc_base/init.d/unbound
4 # Description : Unbound DNS resolver boot script for IPfire
5 # Author : Marcel Lorenz <marcel.lorenz@ipfire.org>
10 TEST_DOMAIN
="ipfire.org"
12 # This domain will never validate
13 TEST_DOMAIN_FAIL
="dnssec-failed.org"
17 ENABLE_SAFE_SEARCH
=off
21 # Cache any local zones for 60 seconds
24 # Load optional configuration
25 [ -e "/etc/sysconfig/unbound" ] && .
/etc
/sysconfig
/unbound
29 if [ "${FORCE_TCP}" = "on" ]; then
37 IFS
=.
read -r a1 a2 a3 a4
<<< ${addr}
39 echo "${a4}.${a3}.${a2}.${a1}.in-addr.arpa"
45 echo "$(</var/ipfire/red/dns${i})"
46 done 2>/dev
/null |
xargs echo
49 check_red_has_carrier_and_ip
() {
50 # Interface configured ?
51 [ ! -e "/var/ipfire/red/iface" ] && return 0;
54 [ ! -e "/sys/class/net/$(</var/ipfire/red/iface)" ] && return 0;
57 [ ! "$(</sys/class/net/$(</var/ipfire/red/iface)/carrier)" = "1" ] && return 0;
60 [ "$(ip address show dev $(</var/ipfire/red/iface) | grep "inet
")" = "" ] && return 0;
66 echo "# This file is automatically generated and any changes"
67 echo "# will be overwritten. DO NOT EDIT!"
72 check_red_has_carrier_and_ip
73 if [ "${USE_FORWARDERS}" = "1" -a "${?}" = "1" ]; then
75 local broken_forwarders
78 for ns
in $
(read_name_servers
); do
79 test_name_server
${ns} &>/dev
/null
81 # Only use DNSSEC-validating or DNSSEC-aware name servers
83 forwarders
="${forwarders} ${ns}"
86 broken_forwarders
="${broken_forwarders} ${ns}"
91 # Show warning for any broken upstream name servers
92 if [ -n "${broken_forwarders}" ]; then
93 boot_mesg
"Ignoring broken upstream name server(s): ${broken_forwarders:1}" ${WARNING}
97 if [ -n "${forwarders}" ]; then
98 boot_mesg
"Configuring upstream name server(s): ${forwarders:1}" ${INFO}
101 # Make sure DNSSEC is activated
104 echo "${forwarders}" > /var
/ipfire
/red
/dns
105 unbound-control
-q forward
${forwarders}
108 # In case we have found no working forwarders
110 # Test if the recursor mode is available
111 if can_resolve_root
; then
112 # Make sure DNSSEC is activated
115 boot_mesg
"Falling back to recursor mode" ${WARNING}
118 # If not, we set DNSSEC in permissive mode and allow using all recursors
119 elif [ -n "${broken_forwarders}" ]; then
122 boot_mesg
"DNSSEC has been set to permissive mode" ${FAILURE}
125 echo "${broken_forwarders}" > /var
/ipfire
/red
/dns
126 unbound-control
-q forward
${broken_forwarders}
132 # If forwarders cannot be used we run in recursor mode
133 echo "local recursor" > /var
/ipfire
/red
/dns
134 unbound-control
-q forward off
137 remove_forwarders
() {
139 echo "local recursor" > /var
/ipfire
/red
/dns
140 unbound-control
-q forward off
145 local hostname
=$
(hostname
-f)
146 # 1.1.1.1 is reserved for unused green, skip this
147 if [ -n "${GREEN_ADDRESS}" -a "${GREEN_ADDRESS}" != "1.1.1.1" ]; then
148 unbound-control
-q local_data
"${hostname} ${LOCAL_TTL} IN A ${GREEN_ADDRESS}"
152 for address
in ${GREEN_ADDRESS} ${BLUE_ADDRESS} ${ORANGE_ADDRESS}; do
153 [ -n "${address}" ] ||
continue
154 [ "${address}" = "1.1.1.1" ] && continue
156 address
=$
(ip_address_revptr
${address})
157 unbound-control
-q local_data
"${address} ${LOCAL_TTL} IN PTR ${hostname}"
162 local enabled address hostname domainname generateptr
164 while IFS
="," read -r enabled address hostname domainname generateptr
; do
165 [ "${enabled}" = "on" ] ||
continue
168 local fqdn
="${hostname}.${domainname}"
170 unbound-control
-q local_data
"${fqdn} ${LOCAL_TTL} IN A ${address}"
172 # Skip reverse resolution if the address equals the GREEN address
173 [ "${address}" = "${GREEN_ADDRESS}" ] && continue
175 # Skip reverse resolution if user requested not to do so
176 [ "${generateptr}" = "off" ] && continue
179 address
=$
(ip_address_revptr
${address})
180 unbound-control
-q local_data
"${address} ${LOCAL_TTL} IN PTR ${fqdn}"
181 done < /var
/ipfire
/main
/hosts
184 write_forward_conf
() {
188 # Force using TLS for upstream servers only
189 if [ "${FORCE_TLS}" = "on" ]; then
190 echo "# Force using TLS for upstream servers only"
192 echo " tls-upstream: yes"
195 # Force using TCP for upstream servers only
196 elif [ "${FORCE_TCP}" = "on" ]; then
197 echo "# Force using TCP for upstream servers only"
199 echo " tcp-upstream: yes"
203 local insecure_zones
="${INSECURE_ZONES}"
205 local enabled zone server servers remark disable_dnssec rest
206 while IFS
="," read -r enabled zone servers remark disable_dnssec rest
; do
207 # Line must be enabled.
208 [ "${enabled}" = "on" ] ||
continue
210 # Zones that end with .local are commonly used for internal
211 # zones and therefore not signed
214 insecure_zones
="${insecure_zones} ${zone}"
217 if [ "${disable_dnssec}" = "on" ]; then
218 insecure_zones
="${insecure_zones} ${zone}"
223 # Reverse-lookup zones must be stubs
227 echo " name: ${zone}"
228 for server
in ${servers//|/ }; do
229 if [[ ${server} =~ ^
[0-9]+\.
[0-9]+\.
[0-9]+\.
[0-9]+$
]]; then
230 echo " stub-addr: ${server}"
232 echo " stub-host: ${server}"
237 echo " local-zone: \"${zone}\" transparent"
242 echo " name: ${zone}"
243 for server
in ${servers//|/ }; do
244 if [[ ${server} =~ ^
[0-9]+\.
[0-9]+\.
[0-9]+\.
[0-9]+$
]]; then
245 echo " forward-addr: ${server}"
247 echo " forward-host: ${server}"
253 done < /var
/ipfire
/dnsforward
/config
255 if [ -n "${insecure_zones}" ]; then
258 for zone
in ${insecure_zones}; do
259 echo " domain-insecure: ${zone}"
262 ) > /etc
/unbound
/forward.conf
265 write_tuning_conf
() {
266 # https://www.unbound.net/documentation/howto_optimise.html
268 # Determine number of online processors
269 local processors
=$
(getconf _NPROCESSORS_ONLN
)
271 # Determine number of slabs
273 while [ ${slabs} -lt ${processors} ]; do
274 slabs
=$
(( ${slabs} * 2 ))
277 # Determine amount of system memory
278 local mem
=$
(get_memory_amount
)
280 # In the worst case scenario, unbound can use double the
281 # amount of memory allocated to a cache due to malloc overhead
283 # Even larger systems with more than 8GB of RAM
284 if [ ${mem} -ge 8192 ]; then
287 # Extra large systems with more than 4GB of RAM
288 elif [ ${mem} -ge 4096 ]; then
291 # Large systems with more than 2GB of RAM
292 elif [ ${mem} -ge 2048 ]; then
295 # Medium systems with more than 1GB of RAM
296 elif [ ${mem} -ge 1024 ]; then
299 # Small systems with less than 256MB of RAM
300 elif [ ${mem} -le 256 ]; then
311 # We run one thread per processor
312 echo "num-threads: ${processors}"
313 echo "so-reuseport: yes"
315 # Adjust number of slabs
316 echo "infra-cache-slabs: ${slabs}"
317 echo "key-cache-slabs: ${slabs}"
318 echo "msg-cache-slabs: ${slabs}"
319 echo "rrset-cache-slabs: ${slabs}"
322 echo "rrset-cache-size: $(( ${mem} / 2 ))m"
323 echo "msg-cache-size: $(( ${mem} / 4 ))m"
324 echo "key-cache-size: $(( ${mem} / 4 ))m"
326 # Increase parallel queries
327 echo "outgoing-range: 8192"
328 echo "num-queries-per-thread: 4096"
330 # Use larger send/receive buffers
333 ) > /etc
/unbound
/tuning.conf
336 get_memory_amount
() {
339 while read -r key val unit
; do
343 echo "$(( ${val} / 1024 ))"
355 # 0 DNSSEC validating
356 # 1 Error: unreachable, etc.
360 # Exit when the server is not reachable
361 ns_is_online
${ns} ||
return 1
364 for rr
in DNSKEY DS RRSIG
; do
365 if ! ns_forwards_
${rr} ${ns} ${args}; then
366 errors
="${errors} ${rr}"
370 if [ -n "${errors}" ]; then
371 echo >&2 "Unable to retrieve the following resource records from ${ns}: ${errors:1}"
375 if ns_is_validating
${ns} ${args}; then
376 # Return 0 if validating
384 # Sends an A query to the nameserver w/o DNSSEC
389 dig "${DIG_ARGS[@]}" @${ns} +nodnssec A ${TEST_DOMAIN} $@ >/dev/null
392 # Resolving ${TEST_DOMAIN_FAIL} will fail if the nameserver is validating
397 if ! dig "${DIG_ARGS[@]}" @${ns} A ${TEST_DOMAIN_FAIL} $@ |
grep -q SERVFAIL
; then
400 # Determine if NS replies with "ad" data flag if DNSSEC enabled
401 dig "${DIG_ARGS[@]}" @${ns} +dnssec SOA ${TEST_DOMAIN} $@ | awk -F: '/\;\;\ flags\:/ { s=1; if (/\ ad/) s=0; exit s }'
405 # Checks if we can retrieve the DNSKEY for this domain.
406 # dig will print the SOA if nothing was found
407 ns_forwards_DNSKEY() {
411 dig "${DIG_ARGS[@]}" @${ns} DNSKEY ${TEST_DOMAIN} $@ |
grep -qv SOA
418 dig "${DIG_ARGS[@]}" @${ns} DS ${TEST_DOMAIN} $@ | grep -qv SOA
421 ns_forwards_RRSIG() {
425 dig "${DIG_ARGS[@]}" @${ns} +dnssec A ${TEST_DOMAIN} $@ |
grep -q RRSIG
432 # If TCP is forced we know by now if the server responds to it
433 if [ "${FORCE_TCP}" = "on" ]; then
437 dig "${DIG_ARGS[@]}" @${ns} +tcp A ${TEST_DOMAIN} $@ >/dev/null || return 1
440 get_root_nameservers() {
441 while read -r hostname ttl record address; do
442 # Searching for A records
443 [ "${record}" = "A
" ] || continue
446 done < /etc/unbound/root.hints
451 for ns in $(get_root_nameservers); do
452 if dig "${DIG_ARGS[@]}" @${ns} +dnssec SOA . $@ >/dev/null; then
457 # none of the servers was reachable
462 local status=$(unbound-control get_option val-permissive-mode)
465 echo "on
" > /var/ipfire/red/dnssec-status
467 # Don't do anything if DNSSEC is already activated
468 [ "${status}" = "no
" ] && return 0
470 # Activate DNSSEC and flush cache with any stale and unvalidated data
471 unbound-control -q set_option val-permissive-mode: no
472 unbound-control -q flush_zone .
477 echo "off
" > /var/ipfire/red/dnssec-status
479 unbound-control -q set_option val-permissive-mode: yes
482 fix_time_if_dns_fail() {
483 # If DNS still not work try to init ntp with
484 # hardcoded ntp.ipfire.org (81.3.27.46)
485 check_red_has_carrier_and_ip
486 if [ -e "/var
/ipfire
/red
/iface
" -a "${?}" = "1" ]; then
487 host 0.ipfire.pool.ntp.org > /dev/null 2>&1
488 if [ "${?}" != "0" ]; then
489 boot_mesg "DNS still not functioning... Trying to sync
time with ntp.ipfire.org
(81.3.27.46)...
"
490 loadproc /usr/local/bin/settime 81.3.27.46
496 local hostname="${1}"
500 for ns in $(read_name_servers); do
502 for answer in $(dig "${DIG_ARGS[@]}" +short "@${ns}" A "${hostname}"); do
505 # Filter out non-IP addresses
506 if [[ ! "${answer}" =~ \.$ ]]; then
511 # End loop when we have got something
512 [ ${found} -eq 1 ] && break
516 # Sets up Safe Search for various search engines
517 update_safe_search() {
714 # Cleanup previous settings
715 unbound-control local_zone_remove "bing.com
" >/dev/null
716 unbound-control local_zone_remove "duckduckgo.com
" >/dev/null
717 unbound-control local_zone_remove "yandex.com
" >/dev/null
718 unbound-control local_zone_remove "yandex.ru
" >/dev/null
719 unbound-control local_zone_remove "youtube.com
" >/dev/null
722 for domain in ${google_tlds[@]}; do
723 unbound-control local_zone_remove "${domain}"
726 # Nothing to do if safe search is not enabled
727 if [ "${ENABLE_SAFE_SEARCH}" != "on
" ]; then
732 unbound-control bing.com transparent >/dev/null
733 for address in $(resolve "strict.bing.com
"); do
734 unbound-control local_data "www.bing.com
${LOCAL_TTL} IN A
${address}"
738 unbound-control local_zone duckduckgo.com typetransparent >/dev/null
739 for address in $(resolve "safe.duckduckgo.com
"); do
740 unbound-control local_data "duckduckgo.com
${LOCAL_TTL} IN A
${address}"
744 local addresses="$
(resolve
"forcesafesearch.google.com")"
745 for domain in ${google_tlds[@]}; do
746 unbound-control local_zone "${domain}" transparent >/dev/null
747 for address in ${addresses}; do
748 unbound-control local_data: "www.
${domain} ${LOCAL_TTL} IN A ${address}"
753 for domain in yandex.com yandex.ru; do
754 unbound-control local_zone "${domain}" typetransparent >/dev/null
755 for address in $(resolve "familysearch.
${domain}"); do
756 unbound-control local_data "${domain} ${LOCAL_TTL} IN A ${address}"
761 unbound-control local_zone youtube.com transparent >/dev/null
762 for address in $(resolve "restrictmoderate.youtube.com
"); do
763 unbound-control local_data "www.youtube.com
${LOCAL_TTL} IN A
${address}"
771 # Print a nicer messagen when unbound is already running
772 if pidofproc -s unbound; then
773 statusproc /usr/sbin/unbound
777 eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)
779 # Update configuration files
783 boot_mesg "Starting Unbound DNS Proxy...
"
784 loadproc /usr/sbin/unbound || exit $?
786 # Make own hostname resolveable
789 # Update any known forwarding name servers
792 # Install Safe Search rules when the system is already online
793 if [ -e "/var
/ipfire
/red
/active
" ]; then
804 boot_mesg "Stopping Unbound DNS Proxy...
"
805 killproc /usr/sbin/unbound
815 statusproc /usr/sbin/unbound
819 # Do not try updating forwarders when unbound is not running
820 if ! pgrep unbound &>/dev/null; then
826 unbound-control flush_negative > /dev/null
827 unbound-control flush_bogus > /dev/null
833 # Do not try updating forwarders when unbound is not running
834 if ! pgrep unbound &>/dev/null; then
840 unbound-control flush_negative > /dev/null
841 unbound-control flush_bogus > /dev/null
848 test_name_server ${ns}
853 echo "${ns} is validating
"
856 echo "${ns} is DNSSEC-aware
"
859 echo "${ns} is NOT DNSSEC-aware
"
862 echo "Test failed
for an unknown reason
"
867 if ns_supports_tcp ${ns}; then
868 echo "${ns} supports TCP fallback
"
870 echo "${ns} does not support TCP fallback
"
885 echo "Usage
: $0 {start|stop|restart|status|update-forwarders|remove-forwarders|test-name-server|resolve|update-safe-search
}"
890 # End $rc_base/init.d/unbound