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}"
224 echo " name: ${zone}"
225 for server
in ${servers//|/ }; do
226 if [[ ${server} =~ ^
[0-9]+\.
[0-9]+\.
[0-9]+\.
[0-9]+$
]]; then
227 echo " stub-addr: ${server}"
229 echo " stub-host: ${server}"
234 # Make all reverse lookup zones transparent
238 echo " local-zone: \"${zone}\" transparent"
242 done < /var
/ipfire
/dnsforward
/config
244 if [ -n "${insecure_zones}" ]; then
247 for zone
in ${insecure_zones}; do
248 echo " domain-insecure: ${zone}"
255 # Force using TLS only
256 if [ "${FORCE_TLS}" = "on" ]; then
257 echo " forward-tls-upstream: yes"
260 # Add upstream name servers
261 local id address tls_hostname enabled remark
262 while IFS
="," read -r id address tls_hostname enabled remark
; do
263 # Skip disabled servers
264 [ "${enabled}" != "enabled" ] && continue
267 if [ "${PROTO}" = "TLS" ]; then
268 if [ -n "${tls_hostname}" ]; then
269 echo " forward-addr: ${address}@853#${tls_hostname}"
272 echo " forward-addr: ${address}"
274 done < /var
/ipfire
/dns
/servers
275 ) > /etc
/unbound
/forward.conf
278 write_tuning_conf
() {
279 # https://www.unbound.net/documentation/howto_optimise.html
281 # Determine number of online processors
282 local processors
=$
(getconf _NPROCESSORS_ONLN
)
284 # Determine number of slabs
286 while [ ${slabs} -lt ${processors} ]; do
287 slabs
=$
(( ${slabs} * 2 ))
290 # Determine amount of system memory
291 local mem
=$
(get_memory_amount
)
293 # In the worst case scenario, unbound can use double the
294 # amount of memory allocated to a cache due to malloc overhead
296 # Even larger systems with more than 8GB of RAM
297 if [ ${mem} -ge 8192 ]; then
300 # Extra large systems with more than 4GB of RAM
301 elif [ ${mem} -ge 4096 ]; then
304 # Large systems with more than 2GB of RAM
305 elif [ ${mem} -ge 2048 ]; then
308 # Medium systems with more than 1GB of RAM
309 elif [ ${mem} -ge 1024 ]; then
312 # Small systems with less than 256MB of RAM
313 elif [ ${mem} -le 256 ]; then
324 # We run one thread per processor
325 echo "num-threads: ${processors}"
326 echo "so-reuseport: yes"
328 # Adjust number of slabs
329 echo "infra-cache-slabs: ${slabs}"
330 echo "key-cache-slabs: ${slabs}"
331 echo "msg-cache-slabs: ${slabs}"
332 echo "rrset-cache-slabs: ${slabs}"
335 echo "rrset-cache-size: $(( ${mem} / 2 ))m"
336 echo "msg-cache-size: $(( ${mem} / 4 ))m"
337 echo "key-cache-size: $(( ${mem} / 4 ))m"
339 # Increase parallel queries
340 echo "outgoing-range: 8192"
341 echo "num-queries-per-thread: 4096"
343 # Use larger send/receive buffers
346 ) > /etc
/unbound
/tuning.conf
349 get_memory_amount
() {
352 while read -r key val unit
; do
356 echo "$(( ${val} / 1024 ))"
368 # 0 DNSSEC validating
369 # 1 Error: unreachable, etc.
373 # Exit when the server is not reachable
374 ns_is_online
${ns} ||
return 1
377 for rr
in DNSKEY DS RRSIG
; do
378 if ! ns_forwards_
${rr} ${ns} ${args}; then
379 errors
="${errors} ${rr}"
383 if [ -n "${errors}" ]; then
384 echo >&2 "Unable to retrieve the following resource records from ${ns}: ${errors:1}"
388 if ns_is_validating
${ns} ${args}; then
389 # Return 0 if validating
397 # Sends an A query to the nameserver w/o DNSSEC
402 dig "${DIG_ARGS[@]}" @${ns} +nodnssec A ${TEST_DOMAIN} $@ >/dev/null
405 # Resolving ${TEST_DOMAIN_FAIL} will fail if the nameserver is validating
410 if ! dig "${DIG_ARGS[@]}" @${ns} A ${TEST_DOMAIN_FAIL} $@ |
grep -q SERVFAIL
; then
413 # Determine if NS replies with "ad" data flag if DNSSEC enabled
414 dig "${DIG_ARGS[@]}" @${ns} +dnssec SOA ${TEST_DOMAIN} $@ | awk -F: '/\;\;\ flags\:/ { s=1; if (/\ ad/) s=0; exit s }'
418 # Checks if we can retrieve the DNSKEY for this domain.
419 # dig will print the SOA if nothing was found
420 ns_forwards_DNSKEY() {
424 dig "${DIG_ARGS[@]}" @${ns} DNSKEY ${TEST_DOMAIN} $@ |
grep -qv SOA
431 dig "${DIG_ARGS[@]}" @${ns} DS ${TEST_DOMAIN} $@ | grep -qv SOA
434 ns_forwards_RRSIG() {
438 dig "${DIG_ARGS[@]}" @${ns} +dnssec A ${TEST_DOMAIN} $@ |
grep -q RRSIG
445 # If TCP is forced we know by now if the server responds to it
446 if [ "${FORCE_TCP}" = "on" ]; then
450 dig "${DIG_ARGS[@]}" @${ns} +tcp A ${TEST_DOMAIN} $@ >/dev/null || return 1
453 get_root_nameservers() {
454 while read -r hostname ttl record address; do
455 # Searching for A records
456 [ "${record}" = "A
" ] || continue
459 done < /etc/unbound/root.hints
464 for ns in $(get_root_nameservers); do
465 if dig "${DIG_ARGS[@]}" @${ns} +dnssec SOA . $@ >/dev/null; then
470 # none of the servers was reachable
475 local status=$(unbound-control get_option val-permissive-mode)
478 echo "on
" > /var/ipfire/red/dnssec-status
480 # Don't do anything if DNSSEC is already activated
481 [ "${status}" = "no
" ] && return 0
483 # Activate DNSSEC and flush cache with any stale and unvalidated data
484 unbound-control -q set_option val-permissive-mode: no
485 unbound-control -q flush_zone .
490 echo "off
" > /var/ipfire/red/dnssec-status
492 unbound-control -q set_option val-permissive-mode: yes
495 fix_time_if_dns_fail() {
496 # If DNS still not work try to init ntp with
497 # hardcoded ntp.ipfire.org (81.3.27.46)
498 check_red_has_carrier_and_ip
499 if [ -e "/var
/ipfire
/red
/iface
" -a "${?}" = "1" ]; then
500 host 0.ipfire.pool.ntp.org > /dev/null 2>&1
501 if [ "${?}" != "0" ]; then
502 boot_mesg "DNS still not functioning... Trying to sync
time with ntp.ipfire.org
(81.3.27.46)...
"
503 loadproc /usr/local/bin/settime 81.3.27.46
509 local hostname="${1}"
513 for ns in $(read_name_servers); do
515 for answer in $(dig "${DIG_ARGS[@]}" +short "@${ns}" A "${hostname}"); do
518 # Filter out non-IP addresses
519 if [[ ! "${answer}" =~ \.$ ]]; then
524 # End loop when we have got something
525 [ ${found} -eq 1 ] && break
529 # Sets up Safe Search for various search engines
530 update_safe_search() {
727 # Cleanup previous settings
728 unbound-control local_zone_remove "bing.com
" >/dev/null
729 unbound-control local_zone_remove "duckduckgo.com
" >/dev/null
730 unbound-control local_zone_remove "yandex.com
" >/dev/null
731 unbound-control local_zone_remove "yandex.ru
" >/dev/null
732 unbound-control local_zone_remove "youtube.com
" >/dev/null
735 for domain in ${google_tlds[@]}; do
736 unbound-control local_zone_remove "${domain}"
739 # Nothing to do if safe search is not enabled
740 if [ "${ENABLE_SAFE_SEARCH}" != "on
" ]; then
745 unbound-control bing.com transparent >/dev/null
746 for address in $(resolve "strict.bing.com
"); do
747 unbound-control local_data "www.bing.com
${LOCAL_TTL} IN A
${address}"
751 unbound-control local_zone duckduckgo.com typetransparent >/dev/null
752 for address in $(resolve "safe.duckduckgo.com
"); do
753 unbound-control local_data "duckduckgo.com
${LOCAL_TTL} IN A
${address}"
757 local addresses="$
(resolve
"forcesafesearch.google.com")"
758 for domain in ${google_tlds[@]}; do
759 unbound-control local_zone "${domain}" transparent >/dev/null
760 for address in ${addresses}; do
761 unbound-control local_data: "www.
${domain} ${LOCAL_TTL} IN A ${address}"
766 for domain in yandex.com yandex.ru; do
767 unbound-control local_zone "${domain}" typetransparent >/dev/null
768 for address in $(resolve "familysearch.
${domain}"); do
769 unbound-control local_data "${domain} ${LOCAL_TTL} IN A ${address}"
774 unbound-control local_zone youtube.com transparent >/dev/null
775 for address in $(resolve "restrictmoderate.youtube.com
"); do
776 unbound-control local_data "www.youtube.com
${LOCAL_TTL} IN A
${address}"
784 # Print a nicer messagen when unbound is already running
785 if pidofproc -s unbound; then
786 statusproc /usr/sbin/unbound
790 eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)
792 # Update configuration files
796 boot_mesg "Starting Unbound DNS Proxy...
"
797 loadproc /usr/sbin/unbound || exit $?
799 # Make own hostname resolveable
802 # Update any known forwarding name servers
805 # Install Safe Search rules when the system is already online
806 if [ -e "/var
/ipfire
/red
/active
" ]; then
817 boot_mesg "Stopping Unbound DNS Proxy...
"
818 killproc /usr/sbin/unbound
828 statusproc /usr/sbin/unbound
832 # Do not try updating forwarders when unbound is not running
833 if ! pgrep unbound &>/dev/null; then
839 unbound-control flush_negative > /dev/null
840 unbound-control flush_bogus > /dev/null
846 # Do not try updating forwarders when unbound is not running
847 if ! pgrep unbound &>/dev/null; then
853 unbound-control flush_negative > /dev/null
854 unbound-control flush_bogus > /dev/null
867 echo "Usage
: $0 {start|stop|restart|status|update-forwarders|remove-forwarders|resolve|update-safe-search
}"
872 # End $rc_base/init.d/unbound