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"
15 # Cache any local zones for 60 seconds
19 eval $
(/usr
/local
/bin
/readhash
/var
/ipfire
/dns
/settings
)
23 if [ "${PROTO}" = "TCP" ]; then
31 IFS
=.
read -r a1 a2 a3 a4
<<< ${addr}
33 echo "${a4}.${a3}.${a2}.${a1}.in-addr.arpa"
39 echo "$(</var/ipfire/red/dns${i})"
40 done 2>/dev
/null |
xargs echo
43 check_red_has_carrier_and_ip
() {
44 # Interface configured ?
45 [ ! -e "/var/ipfire/red/iface" ] && return 0;
48 [ ! -e "/sys/class/net/$(</var/ipfire/red/iface)" ] && return 0;
51 [ ! "$(</sys/class/net/$(</var/ipfire/red/iface)/carrier)" = "1" ] && return 0;
54 [ "$(ip address show dev $(</var/ipfire/red/iface) | grep "inet
")" = "" ] && return 0;
60 echo "# This file is automatically generated and any changes"
61 echo "# will be overwritten. DO NOT EDIT!"
66 check_red_has_carrier_and_ip
67 if [ "${?}" = "1" ]; then
69 local broken_forwarders
72 for ns
in $
(read_name_servers
); do
73 test_name_server
${ns} &>/dev
/null
75 # Only use DNSSEC-validating or DNSSEC-aware name servers
77 forwarders
="${forwarders} ${ns}"
80 broken_forwarders
="${broken_forwarders} ${ns}"
85 # Show warning for any broken upstream name servers
86 if [ -n "${broken_forwarders}" ]; then
87 boot_mesg
"Ignoring broken upstream name server(s): ${broken_forwarders:1}" ${WARNING}
91 if [ -n "${forwarders}" ]; then
92 boot_mesg
"Configuring upstream name server(s): ${forwarders:1}" ${INFO}
95 # Make sure DNSSEC is activated
98 echo "${forwarders}" > /var
/ipfire
/red
/dns
99 unbound-control
-q forward
${forwarders}
102 # In case we have found no working forwarders
104 # Test if the recursor mode is available
105 if can_resolve_root
; then
106 # Make sure DNSSEC is activated
109 boot_mesg
"Falling back to recursor mode" ${WARNING}
112 # If not, we set DNSSEC in permissive mode and allow using all recursors
113 elif [ -n "${broken_forwarders}" ]; then
116 boot_mesg
"DNSSEC has been set to permissive mode" ${FAILURE}
119 echo "${broken_forwarders}" > /var
/ipfire
/red
/dns
120 unbound-control
-q forward
${broken_forwarders}
126 # If forwarders cannot be used we run in recursor mode
127 echo "local recursor" > /var
/ipfire
/red
/dns
128 unbound-control
-q forward off
131 remove_forwarders
() {
133 echo "local recursor" > /var
/ipfire
/red
/dns
134 unbound-control
-q forward off
139 local hostname
=$
(hostname
-f)
140 # 1.1.1.1 is reserved for unused green, skip this
141 if [ -n "${GREEN_ADDRESS}" -a "${GREEN_ADDRESS}" != "1.1.1.1" ]; then
142 unbound-control
-q local_data
"${hostname} ${LOCAL_TTL} IN A ${GREEN_ADDRESS}"
146 for address
in ${GREEN_ADDRESS} ${BLUE_ADDRESS} ${ORANGE_ADDRESS}; do
147 [ -n "${address}" ] ||
continue
148 [ "${address}" = "1.1.1.1" ] && continue
150 address
=$
(ip_address_revptr
${address})
151 unbound-control
-q local_data
"${address} ${LOCAL_TTL} IN PTR ${hostname}"
156 local enabled address hostname domainname generateptr
158 while IFS
="," read -r enabled address hostname domainname generateptr
; do
159 [ "${enabled}" = "on" ] ||
continue
162 local fqdn
="${hostname}.${domainname}"
164 unbound-control
-q local_data
"${fqdn} ${LOCAL_TTL} IN A ${address}"
166 # Skip reverse resolution if the address equals the GREEN address
167 [ "${address}" = "${GREEN_ADDRESS}" ] && continue
169 # Skip reverse resolution if user requested not to do so
170 [ "${generateptr}" = "off" ] && continue
173 address
=$
(ip_address_revptr
${address})
174 unbound-control
-q local_data
"${address} ${LOCAL_TTL} IN PTR ${fqdn}"
175 done < /var
/ipfire
/main
/hosts
178 write_forward_conf
() {
182 # Force using TCP for upstream servers only
183 if [ "${PROTO}" = "TCP" ]; then
184 echo "# Force using TCP for upstream servers only"
186 echo " tcp-upstream: yes"
190 local insecure_zones
=""
192 local enabled zone server servers remark disable_dnssec rest
193 while IFS
="," read -r enabled zone servers remark disable_dnssec rest
; do
194 # Line must be enabled.
195 [ "${enabled}" = "on" ] ||
continue
197 # Zones that end with .local are commonly used for internal
198 # zones and therefore not signed
201 insecure_zones
="${insecure_zones} ${zone}"
204 if [ "${disable_dnssec}" = "on" ]; then
205 insecure_zones
="${insecure_zones} ${zone}"
211 echo " name: ${zone}"
212 for server
in ${servers//|/ }; do
213 if [[ ${server} =~ ^
[0-9]+\.
[0-9]+\.
[0-9]+\.
[0-9]+$
]]; then
214 echo " stub-addr: ${server}"
216 echo " stub-host: ${server}"
221 # Make all reverse lookup zones transparent
225 echo " local-zone: \"${zone}\" transparent"
229 done < /var
/ipfire
/dnsforward
/config
231 if [ -n "${insecure_zones}" ]; then
234 for zone
in ${insecure_zones}; do
235 echo " domain-insecure: ${zone}"
242 # Force using TLS only
243 if [ "${PROTO}" = "TLS" ]; then
244 echo " forward-tls-upstream: yes"
247 # Add upstream name servers
248 local id address tls_hostname enabled remark
249 while IFS
="," read -r id address tls_hostname enabled remark
; do
250 # Skip disabled servers
251 [ "${enabled}" != "enabled" ] && continue
254 if [ "${PROTO}" = "TLS" ]; then
255 if [ -n "${tls_hostname}" ]; then
256 echo " forward-addr: ${address}@853#${tls_hostname}"
259 echo " forward-addr: ${address}"
261 done < /var
/ipfire
/dns
/servers
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 [ "${PROTO}" = "TCP" ]; 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
854 echo "Usage
: $0 {start|stop|restart|status|update-forwarders|remove-forwarders|resolve|update-safe-search
}"
859 # End $rc_base/init.d/unbound