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
20 # Cache any local zones for 60 seconds
24 EDNS_DEFAULT_BUFFER_SIZE
=4096
26 # Load optional configuration
27 [ -e "/etc/sysconfig/unbound" ] && .
/etc
/sysconfig
/unbound
31 if [ "${FORCE_TCP}" = "on" ]; then
39 IFS
=.
read -r a1 a2 a3 a4
<<< ${addr}
41 echo "${a4}.${a3}.${a2}.${a1}.in-addr.arpa"
47 echo "$(</var/ipfire/red/dns${i})"
48 done 2>/dev
/null |
xargs echo
51 check_red_has_carrier_and_ip
() {
52 # Interface configured ?
53 [ ! -e "/var/ipfire/red/iface" ] && return 0;
56 [ ! -e "/sys/class/net/$(</var/ipfire/red/iface)" ] && return 0;
59 [ ! "$(</sys/class/net/$(</var/ipfire/red/iface)/carrier)" = "1" ] && return 0;
62 [ "$(ip address show dev $(</var/ipfire/red/iface) | grep "inet
")" = "" ] && return 0;
68 echo "# This file is automatically generated and any changes"
69 echo "# will be overwritten. DO NOT EDIT!"
74 check_red_has_carrier_and_ip
75 if [ "${USE_FORWARDERS}" = "1" -a "${?}" = "1" ]; then
77 local broken_forwarders
80 for ns
in $
(read_name_servers
); do
81 test_name_server
${ns} &>/dev
/null
83 # Only use DNSSEC-validating or DNSSEC-aware name servers
85 forwarders
="${forwarders} ${ns}"
88 broken_forwarders
="${broken_forwarders} ${ns}"
93 # Determine EDNS buffer size
94 local new_edns_buffer_size
=${EDNS_DEFAULT_BUFFER_SIZE}
96 for ns
in ${forwarders}; do
97 local edns_buffer_size
=$
(ns_determine_edns_buffer_size
${ns})
98 if [ -n "${edns_buffer_size}" ]; then
99 if [ ${edns_buffer_size} -lt ${new_edns_buffer_size} ]; then
100 new_edns_buffer_size
=${edns_buffer_size}
105 if [ ${new_edns_buffer_size} -lt ${EDNS_DEFAULT_BUFFER_SIZE} ]; then
106 boot_mesg
"EDNS buffer size reduced to ${new_edns_buffer_size}" ${WARNING}
109 unbound-control
-q set_option edns-buffer-size
: ${new_edns_buffer_size}
112 # Show warning for any broken upstream name servers
113 if [ -n "${broken_forwarders}" ]; then
114 boot_mesg
"Ignoring broken upstream name server(s): ${broken_forwarders:1}" ${WARNING}
118 if [ -n "${forwarders}" ]; then
119 boot_mesg
"Configuring upstream name server(s): ${forwarders:1}" ${INFO}
122 # Make sure DNSSEC is activated
125 echo "${forwarders}" > /var
/ipfire
/red
/dns
126 unbound-control
-q forward
${forwarders}
129 # In case we have found no working forwarders
131 # Test if the recursor mode is available
132 if can_resolve_root
+bufsize
=${new_edns_buffer_size}; then
133 # Make sure DNSSEC is activated
136 boot_mesg
"Falling back to recursor mode" ${WARNING}
139 # If not, we set DNSSEC in permissive mode and allow using all recursors
140 elif [ -n "${broken_forwarders}" ]; then
143 boot_mesg
"DNSSEC has been set to permissive mode" ${FAILURE}
146 echo "${broken_forwarders}" > /var
/ipfire
/red
/dns
147 unbound-control
-q forward
${broken_forwarders}
153 # If forwarders cannot be used we run in recursor mode
154 echo "local recursor" > /var
/ipfire
/red
/dns
155 unbound-control
-q forward off
158 remove_forwarders
() {
160 echo "local recursor" > /var
/ipfire
/red
/dns
161 unbound-control
-q forward off
166 local hostname
=$
(hostname
-f)
167 # 1.1.1.1 is reserved for unused green, skip this
168 if [ -n "${GREEN_ADDRESS}" -a "${GREEN_ADDRESS}" != "1.1.1.1" ]; then
169 unbound-control
-q local_data
"${hostname} ${LOCAL_TTL} IN A ${GREEN_ADDRESS}"
173 for address
in ${GREEN_ADDRESS} ${BLUE_ADDRESS} ${ORANGE_ADDRESS}; do
174 [ -n "${address}" ] ||
continue
175 [ "${address}" = "1.1.1.1" ] && continue
177 address
=$
(ip_address_revptr
${address})
178 unbound-control
-q local_data
"${address} ${LOCAL_TTL} IN PTR ${hostname}"
183 local enabled address hostname domainname generateptr
185 while IFS
="," read -r enabled address hostname domainname generateptr
; do
186 [ "${enabled}" = "on" ] ||
continue
189 local fqdn
="${hostname}.${domainname}"
191 unbound-control
-q local_data
"${fqdn} ${LOCAL_TTL} IN A ${address}"
193 # Skip reverse resolution if the address equals the GREEN address
194 [ "${address}" = "${GREEN_ADDRESS}" ] && continue
196 # Skip reverse resolution if user requested not to do so
197 [ "${generateptr}" = "off" ] && continue
200 address
=$
(ip_address_revptr
${address})
201 unbound-control
-q local_data
"${address} ${LOCAL_TTL} IN PTR ${fqdn}"
202 done < /var
/ipfire
/main
/hosts
205 write_forward_conf
() {
209 # Force using TCP for upstream servers only
210 if [ "${FORCE_TCP}" = "on" ]; then
211 echo "# Force using TCP for upstream servers only"
213 echo " tcp-upstream: yes"
217 local insecure_zones
="${INSECURE_ZONES}"
219 local enabled zone server servers remark disable_dnssec rest
220 while IFS
="," read -r enabled zone servers remark disable_dnssec rest
; do
221 # Line must be enabled.
222 [ "${enabled}" = "on" ] ||
continue
224 # Zones that end with .local are commonly used for internal
225 # zones and therefore not signed
228 insecure_zones
="${insecure_zones} ${zone}"
231 if [ "${disable_dnssec}" = "on" ]; then
232 insecure_zones
="${insecure_zones} ${zone}"
237 # Reverse-lookup zones must be stubs
241 echo " name: ${zone}"
242 for server
in ${servers//|/ }; do
243 if [[ ${server} =~ ^
[0-9]+\.
[0-9]+\.
[0-9]+\.
[0-9]+$
]]; then
244 echo " stub-addr: ${server}"
246 echo " stub-host: ${server}"
251 echo " local-zone: \"${zone}\" transparent"
256 echo " name: ${zone}"
257 for server
in ${servers//|/ }; do
258 if [[ ${server} =~ ^
[0-9]+\.
[0-9]+\.
[0-9]+\.
[0-9]+$
]]; then
259 echo " forward-addr: ${server}"
261 echo " forward-host: ${server}"
267 done < /var
/ipfire
/dnsforward
/config
269 if [ -n "${insecure_zones}" ]; then
272 for zone
in ${insecure_zones}; do
273 echo " domain-insecure: ${zone}"
276 ) > /etc
/unbound
/forward.conf
279 write_tuning_conf
() {
280 # https://www.unbound.net/documentation/howto_optimise.html
282 # Determine number of online processors
283 local processors
=$
(getconf _NPROCESSORS_ONLN
)
285 # Determine number of slabs
287 while [ ${slabs} -lt ${processors} ]; do
288 slabs
=$
(( ${slabs} * 2 ))
291 # Determine amount of system memory
292 local mem
=$
(get_memory_amount
)
294 # In the worst case scenario, unbound can use double the
295 # amount of memory allocated to a cache due to malloc overhead
297 # Even larger systems with more than 8GB of RAM
298 if [ ${mem} -ge 8192 ]; then
301 # Extra large systems with more than 4GB of RAM
302 elif [ ${mem} -ge 4096 ]; then
305 # Large systems with more than 2GB of RAM
306 elif [ ${mem} -ge 2048 ]; then
309 # Medium systems with more than 1GB of RAM
310 elif [ ${mem} -ge 1024 ]; then
313 # Small systems with less than 256MB of RAM
314 elif [ ${mem} -le 256 ]; then
325 # We run one thread per processor
326 echo "num-threads: ${processors}"
327 echo "so-reuseport: yes"
329 # Adjust number of slabs
330 echo "infra-cache-slabs: ${slabs}"
331 echo "key-cache-slabs: ${slabs}"
332 echo "msg-cache-slabs: ${slabs}"
333 echo "rrset-cache-slabs: ${slabs}"
336 echo "rrset-cache-size: $(( ${mem} / 2 ))m"
337 echo "msg-cache-size: $(( ${mem} / 4 ))m"
338 echo "key-cache-size: $(( ${mem} / 4 ))m"
340 # Increase parallel queries
341 echo "outgoing-range: 8192"
342 echo "num-queries-per-thread: 4096"
344 # Use larger send/receive buffers
347 ) > /etc
/unbound
/tuning.conf
350 get_memory_amount
() {
353 while read -r key val unit
; do
357 echo "$(( ${val} / 1024 ))"
369 # 0 DNSSEC validating
370 # 1 Error: unreachable, etc.
374 # Exit when the server is not reachable
375 ns_is_online
${ns} ||
return 1
377 # Determine the maximum edns buffer size that works
378 local edns_buffer_size
=$
(ns_determine_edns_buffer_size
${ns})
379 if [ -n "${edns_buffer_size}" ]; then
380 args
="${args} +bufsize=${edns_buffer_size}"
384 for rr
in DNSKEY DS RRSIG
; do
385 if ! ns_forwards_
${rr} ${ns} ${args}; then
386 errors
="${errors} ${rr}"
390 if [ -n "${errors}" ]; then
391 echo >&2 "Unable to retrieve the following resource records from ${ns}: ${errors:1}"
395 if ns_is_validating
${ns} ${args}; then
396 # Return 0 if validating
404 # Sends an A query to the nameserver w/o DNSSEC
409 dig "${DIG_ARGS[@]}" @${ns} +nodnssec A ${TEST_DOMAIN} $@ >/dev/null
412 # Resolving ${TEST_DOMAIN_FAIL} will fail if the nameserver is validating
417 if ! dig "${DIG_ARGS[@]}" @${ns} A ${TEST_DOMAIN_FAIL} $@ |
grep -q SERVFAIL
; then
420 # Determine if NS replies with "ad" data flag if DNSSEC enabled
421 dig "${DIG_ARGS[@]}" @${ns} +dnssec SOA ${TEST_DOMAIN} $@ | awk -F: '/\;\;\ flags\:/ { s=1; if (/\ ad/) s=0; exit s }'
425 # Checks if we can retrieve the DNSKEY for this domain.
426 # dig will print the SOA if nothing was found
427 ns_forwards_DNSKEY() {
431 dig "${DIG_ARGS[@]}" @${ns} DNSKEY ${TEST_DOMAIN} $@ |
grep -qv SOA
438 dig "${DIG_ARGS[@]}" @${ns} DS ${TEST_DOMAIN} $@ | grep -qv SOA
441 ns_forwards_RRSIG() {
445 dig "${DIG_ARGS[@]}" @${ns} +dnssec A ${TEST_DOMAIN} $@ |
grep -q RRSIG
452 # If TCP is forced we know by now if the server responds to it
453 if [ "${FORCE_TCP}" = "on" ]; then
457 dig "${DIG_ARGS[@]}" @${ns} +tcp A ${TEST_DOMAIN} $@ >/dev/null || return 1
460 ns_determine_edns_buffer_size() {
465 for b in 4096 2048 1500 1480 1464 1400 1280 512; do
466 if dig "${DIG_ARGS[@]}" @${ns} +dnssec +bufsize=${b} A ${TEST_DOMAIN} $@
>/dev
/null
; then
475 get_root_nameservers
() {
476 while read -r hostname ttl record address
; do
477 # Searching for A records
478 [ "${record}" = "A" ] ||
continue
481 done < /etc
/unbound
/root.hints
486 for ns
in $
(get_root_nameservers
); do
487 if dig "${DIG_ARGS[@]}" @
${ns} +dnssec SOA . $@
>/dev
/null
; then
492 # none of the servers was reachable
497 local status
=$
(unbound-control get_option val-permissive-mode
)
500 echo "on" > /var
/ipfire
/red
/dnssec-status
502 # Don't do anything if DNSSEC is already activated
503 [ "${status}" = "no" ] && return 0
505 # Activate DNSSEC and flush cache with any stale and unvalidated data
506 unbound-control
-q set_option val-permissive-mode
: no
507 unbound-control
-q flush_zone .
512 echo "off" > /var
/ipfire
/red
/dnssec-status
514 unbound-control
-q set_option val-permissive-mode
: yes
517 fix_time_if_dns_fail
() {
518 # If DNS still not work try to init ntp with
519 # hardcoded ntp.ipfire.org (81.3.27.46)
520 check_red_has_carrier_and_ip
521 if [ -e "/var/ipfire/red/iface" -a "${?}" = "1" ]; then
522 host 0.ipfire.pool.ntp.org
> /dev
/null
2>&1
523 if [ "${?}" != "0" ]; then
524 boot_mesg
"DNS still not functioning... Trying to sync time with ntp.ipfire.org (81.3.27.46)..."
525 loadproc
/usr
/local
/bin
/settime
81.3.27.46
531 local hostname
="${1}"
535 for ns
in $
(read_name_servers
); do
537 for answer
in $
(dig "${DIG_ARGS[@]}" +short "@${ns}" A "${hostname}"); do
540 # Filter out non-IP addresses
541 if [[ ! "${answer}" =~ \.$
]]; then
546 # End loop when we have got something
547 [ ${found} -eq 1 ] && break
551 # Sets up Safe Search for various search engines
552 write_safe_search_conf
() {
750 # Nothing to do if safe search is not enabled
751 if [ "${ENABLE_SAFE_SEARCH}" != "on" ]; then
755 # This all belongs into the server: section
759 echo " local-zone: bing.com transparent"
760 for address
in $
(resolve
"strict.bing.com"); do
761 echo " local-data: \"www.bing.com ${LOCAL_TTL} IN A ${address}\""
765 echo " local-zone: duckduckgo.com typetransparent"
766 for address
in $
(resolve
"safe.duckduckgo.com"); do
767 echo " local-data: \"duckduckgo.com ${LOCAL_TTL} IN A ${address}\""
771 addresses
="$(resolve "forcesafesearch.google.com
")"
773 for domain
in ${google_tlds[@]}; do
774 echo " local-zone: ${domain} transparent"
775 for address
in ${addresses}; do
776 echo " local-data: \"www.${domain} ${LOCAL_TTL} IN A ${address}\""
781 for domain
in yandex.com yandex.ru
; do
782 echo " local-zone: ${domain} typetransparent"
783 for address
in $
(resolve
"familysearch.${domain}"); do
784 echo " local-data: \"${domain} ${LOCAL_TTL} IN A ${address}\""
789 echo " local-zone: youtube.com transparent"
790 for address
in $
(resolve
"restrictmoderate.youtube.com"); do
791 echo " local-data: \"www.youtube.com ${LOCAL_TTL} IN A ${address}\""
793 ) > /etc
/unbound
/safe-search.conf
798 # Print a nicer messagen when unbound is already running
799 if pidofproc
-s unbound
; then
800 statusproc
/usr
/sbin
/unbound
804 eval $
(/usr
/local
/bin
/readhash
/var
/ipfire
/ethernet
/settings
)
806 # Update configuration files
809 write_safe_search_conf
811 boot_mesg
"Starting Unbound DNS Proxy..."
812 loadproc
/usr
/sbin
/unbound ||
exit $?
814 # Make own hostname resolveable
817 # Update any known forwarding name servers
827 boot_mesg
"Stopping Unbound DNS Proxy..."
828 killproc
/usr
/sbin
/unbound
838 statusproc
/usr
/sbin
/unbound
842 # Do not try updating forwarders when unbound is not running
843 if ! pgrep unbound
&>/dev
/null
; then
849 unbound-control flush_negative
> /dev
/null
850 unbound-control flush_bogus
> /dev
/null
856 # Do not try updating forwarders when unbound is not running
857 if ! pgrep unbound
&>/dev
/null
; then
863 unbound-control flush_negative
> /dev
/null
864 unbound-control flush_bogus
> /dev
/null
871 test_name_server
${ns}
876 echo "${ns} is validating"
879 echo "${ns} is DNSSEC-aware"
882 echo "${ns} is NOT DNSSEC-aware"
885 echo "Test failed for an unknown reason"
890 if ns_supports_tcp
${ns}; then
891 echo "${ns} supports TCP fallback"
893 echo "${ns} does not support TCP fallback"
896 edns_buffer_size
=$
(ns_determine_edns_buffer_size
${ns})
897 if [ -n "${edns_buffer_size}" ]; then
898 echo "EDNS buffer size for ${ns}: ${edns_buffer_size}"
909 echo "Usage: $0 {start|stop|restart|status|update-forwarders|remove-forwarders|test-name-server|resolve}"
914 # End $rc_base/init.d/unbound