]> git.ipfire.org Git - ipfire-2.x.git/blob - src/initscripts/system/unbound
unbound: Write upstream name servers to forward.conf
[ipfire-2.x.git] / src / initscripts / system / unbound
1 #!/bin/sh
2 # Begin $rc_base/init.d/unbound
3
4 # Description : Unbound DNS resolver boot script for IPfire
5 # Author : Marcel Lorenz <marcel.lorenz@ipfire.org>
6
7 . /etc/sysconfig/rc
8 . ${rc_functions}
9
10 TEST_DOMAIN="ipfire.org"
11
12 # This domain will never validate
13 TEST_DOMAIN_FAIL="dnssec-failed.org"
14
15 INSECURE_ZONES=
16 USE_FORWARDERS=1
17 ENABLE_SAFE_SEARCH=off
18 FORCE_TCP=off
19 FORCE_TLS=off
20
21 # Cache any local zones for 60 seconds
22 LOCAL_TTL=60
23
24 # Load optional configuration
25 [ -e "/etc/sysconfig/unbound" ] && . /etc/sysconfig/unbound
26
27 DIG_ARGS=()
28
29 if [ "${FORCE_TCP}" = "on" ]; then
30 DIG_ARGS+=( "+tcp" )
31 fi
32
33 ip_address_revptr() {
34 local addr=${1}
35
36 local a1 a2 a3 a4
37 IFS=. read -r a1 a2 a3 a4 <<< ${addr}
38
39 echo "${a4}.${a3}.${a2}.${a1}.in-addr.arpa"
40 }
41
42 read_name_servers() {
43 local i
44 for i in 1 2; do
45 echo "$(</var/ipfire/red/dns${i})"
46 done 2>/dev/null | xargs echo
47 }
48
49 check_red_has_carrier_and_ip() {
50 # Interface configured ?
51 [ ! -e "/var/ipfire/red/iface" ] && return 0;
52
53 # Interface present ?
54 [ ! -e "/sys/class/net/$(</var/ipfire/red/iface)" ] && return 0;
55
56 # has carrier ?
57 [ ! "$(</sys/class/net/$(</var/ipfire/red/iface)/carrier)" = "1" ] && return 0;
58
59 # has ip ?
60 [ "$(ip address show dev $(</var/ipfire/red/iface) | grep "inet")" = "" ] && return 0;
61
62 return 1;
63 }
64
65 config_header() {
66 echo "# This file is automatically generated and any changes"
67 echo "# will be overwritten. DO NOT EDIT!"
68 echo
69 }
70
71 update_forwarders() {
72 check_red_has_carrier_and_ip
73 if [ "${USE_FORWARDERS}" = "1" -a "${?}" = "1" ]; then
74 local forwarders
75 local broken_forwarders
76
77 local ns
78 for ns in $(read_name_servers); do
79 test_name_server ${ns} &>/dev/null
80 case "$?" in
81 # Only use DNSSEC-validating or DNSSEC-aware name servers
82 0|2)
83 forwarders="${forwarders} ${ns}"
84 ;;
85 *)
86 broken_forwarders="${broken_forwarders} ${ns}"
87 ;;
88 esac
89 done
90
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}
94 echo_warning
95 fi
96
97 if [ -n "${forwarders}" ]; then
98 boot_mesg "Configuring upstream name server(s): ${forwarders:1}" ${INFO}
99 echo_ok
100
101 # Make sure DNSSEC is activated
102 enable_dnssec
103
104 echo "${forwarders}" > /var/ipfire/red/dns
105 unbound-control -q forward ${forwarders}
106 return 0
107
108 # In case we have found no working forwarders
109 else
110 # Test if the recursor mode is available
111 if can_resolve_root; then
112 # Make sure DNSSEC is activated
113 enable_dnssec
114
115 boot_mesg "Falling back to recursor mode" ${WARNING}
116 echo_warning
117
118 # If not, we set DNSSEC in permissive mode and allow using all recursors
119 elif [ -n "${broken_forwarders}" ]; then
120 disable_dnssec
121
122 boot_mesg "DNSSEC has been set to permissive mode" ${FAILURE}
123 echo_failure
124
125 echo "${broken_forwarders}" > /var/ipfire/red/dns
126 unbound-control -q forward ${broken_forwarders}
127 return 0
128 fi
129 fi
130 fi
131
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
135 }
136
137 remove_forwarders() {
138 enable_dnssec
139 echo "local recursor" > /var/ipfire/red/dns
140 unbound-control -q forward off
141
142 }
143
144 own_hostname() {
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}"
149 fi
150
151 local address
152 for address in ${GREEN_ADDRESS} ${BLUE_ADDRESS} ${ORANGE_ADDRESS}; do
153 [ -n "${address}" ] || continue
154 [ "${address}" = "1.1.1.1" ] && continue
155
156 address=$(ip_address_revptr ${address})
157 unbound-control -q local_data "${address} ${LOCAL_TTL} IN PTR ${hostname}"
158 done
159 }
160
161 update_hosts() {
162 local enabled address hostname domainname generateptr
163
164 while IFS="," read -r enabled address hostname domainname generateptr; do
165 [ "${enabled}" = "on" ] || continue
166
167 # Build FQDN
168 local fqdn="${hostname}.${domainname}"
169
170 unbound-control -q local_data "${fqdn} ${LOCAL_TTL} IN A ${address}"
171
172 # Skip reverse resolution if the address equals the GREEN address
173 [ "${address}" = "${GREEN_ADDRESS}" ] && continue
174
175 # Skip reverse resolution if user requested not to do so
176 [ "${generateptr}" = "off" ] && continue
177
178 # Add RDNS
179 address=$(ip_address_revptr ${address})
180 unbound-control -q local_data "${address} ${LOCAL_TTL} IN PTR ${fqdn}"
181 done < /var/ipfire/main/hosts
182 }
183
184 write_forward_conf() {
185 (
186 config_header
187
188 # Force using TLS for upstream servers only
189 if [ "${FORCE_TLS}" = "on" ]; then
190 echo "# Force using TLS for upstream servers only"
191 echo "server:"
192 echo " tls-upstream: yes"
193 echo
194
195 # Force using TCP for upstream servers only
196 elif [ "${FORCE_TCP}" = "on" ]; then
197 echo "# Force using TCP for upstream servers only"
198 echo "server:"
199 echo " tcp-upstream: yes"
200 echo
201 fi
202
203 local insecure_zones="${INSECURE_ZONES}"
204
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
209
210 # Zones that end with .local are commonly used for internal
211 # zones and therefore not signed
212 case "${zone}" in
213 *.local)
214 insecure_zones="${insecure_zones} ${zone}"
215 ;;
216 *)
217 if [ "${disable_dnssec}" = "on" ]; then
218 insecure_zones="${insecure_zones} ${zone}"
219 fi
220 ;;
221 esac
222
223 echo "stub-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}"
228 else
229 echo " stub-host: ${server}"
230 fi
231 done
232 echo
233
234 # Make all reverse lookup zones transparent
235 case "${zone}" in
236 *.in-addr.arpa)
237 echo "server:"
238 echo " local-zone: \"${zone}\" transparent"
239 echo
240 ;;
241 esac
242 done < /var/ipfire/dnsforward/config
243
244 if [ -n "${insecure_zones}" ]; then
245 echo "server:"
246
247 for zone in ${insecure_zones}; do
248 echo " domain-insecure: ${zone}"
249 done
250 fi
251
252 echo "forward-zone:"
253 echo " name: \".\""
254
255 # Force using TLS only
256 if [ "${FORCE_TLS}" = "on" ]; then
257 echo " forward-tls-upstream: yes"
258 fi
259
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
265
266 # Set DNS server
267 if [ "${PROTO}" = "TLS" ]; then
268 if [ -n "${tls_hostname}" ]; then
269 echo " forward-addr: ${address}@853#${tls_hostname}"
270 fi
271 else
272 echo " forward-addr: ${address}"
273 fi
274 done < /var/ipfire/dns/servers
275 ) > /etc/unbound/forward.conf
276 }
277
278 write_tuning_conf() {
279 # https://www.unbound.net/documentation/howto_optimise.html
280
281 # Determine number of online processors
282 local processors=$(getconf _NPROCESSORS_ONLN)
283
284 # Determine number of slabs
285 local slabs=1
286 while [ ${slabs} -lt ${processors} ]; do
287 slabs=$(( ${slabs} * 2 ))
288 done
289
290 # Determine amount of system memory
291 local mem=$(get_memory_amount)
292
293 # In the worst case scenario, unbound can use double the
294 # amount of memory allocated to a cache due to malloc overhead
295
296 # Even larger systems with more than 8GB of RAM
297 if [ ${mem} -ge 8192 ]; then
298 mem=1024
299
300 # Extra large systems with more than 4GB of RAM
301 elif [ ${mem} -ge 4096 ]; then
302 mem=512
303
304 # Large systems with more than 2GB of RAM
305 elif [ ${mem} -ge 2048 ]; then
306 mem=256
307
308 # Medium systems with more than 1GB of RAM
309 elif [ ${mem} -ge 1024 ]; then
310 mem=128
311
312 # Small systems with less than 256MB of RAM
313 elif [ ${mem} -le 256 ]; then
314 mem=16
315
316 # Everything else
317 else
318 mem=64
319 fi
320
321 (
322 config_header
323
324 # We run one thread per processor
325 echo "num-threads: ${processors}"
326 echo "so-reuseport: yes"
327
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}"
333
334 # Slice up the cache
335 echo "rrset-cache-size: $(( ${mem} / 2 ))m"
336 echo "msg-cache-size: $(( ${mem} / 4 ))m"
337 echo "key-cache-size: $(( ${mem} / 4 ))m"
338
339 # Increase parallel queries
340 echo "outgoing-range: 8192"
341 echo "num-queries-per-thread: 4096"
342
343 # Use larger send/receive buffers
344 echo "so-sndbuf: 4m"
345 echo "so-rcvbuf: 4m"
346 ) > /etc/unbound/tuning.conf
347 }
348
349 get_memory_amount() {
350 local key val unit
351
352 while read -r key val unit; do
353 case "${key}" in
354 MemTotal:*)
355 # Convert to MB
356 echo "$(( ${val} / 1024 ))"
357 break
358 ;;
359 esac
360 done < /proc/meminfo
361 }
362
363 test_name_server() {
364 local ns=${1}
365 local args
366
367 # Return codes:
368 # 0 DNSSEC validating
369 # 1 Error: unreachable, etc.
370 # 2 DNSSEC aware
371 # 3 NOT DNSSEC-aware
372
373 # Exit when the server is not reachable
374 ns_is_online ${ns} || return 1
375
376 local errors
377 for rr in DNSKEY DS RRSIG; do
378 if ! ns_forwards_${rr} ${ns} ${args}; then
379 errors="${errors} ${rr}"
380 fi
381 done
382
383 if [ -n "${errors}" ]; then
384 echo >&2 "Unable to retrieve the following resource records from ${ns}: ${errors:1}"
385 return 3
386 fi
387
388 if ns_is_validating ${ns} ${args}; then
389 # Return 0 if validating
390 return 0
391 else
392 # Is DNSSEC-aware
393 return 2
394 fi
395 }
396
397 # Sends an A query to the nameserver w/o DNSSEC
398 ns_is_online() {
399 local ns=${1}
400 shift
401
402 dig "${DIG_ARGS[@]}" @${ns} +nodnssec A ${TEST_DOMAIN} $@ >/dev/null
403 }
404
405 # Resolving ${TEST_DOMAIN_FAIL} will fail if the nameserver is validating
406 ns_is_validating() {
407 local ns=${1}
408 shift
409
410 if ! dig "${DIG_ARGS[@]}" @${ns} A ${TEST_DOMAIN_FAIL} $@ | grep -q SERVFAIL; then
411 return 1
412 else
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 }'
415 fi
416 }
417
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() {
421 local ns=${1}
422 shift
423
424 dig "${DIG_ARGS[@]}" @${ns} DNSKEY ${TEST_DOMAIN} $@ | grep -qv SOA
425 }
426
427 ns_forwards_DS() {
428 local ns=${1}
429 shift
430
431 dig "${DIG_ARGS[@]}" @${ns} DS ${TEST_DOMAIN} $@ | grep -qv SOA
432 }
433
434 ns_forwards_RRSIG() {
435 local ns=${1}
436 shift
437
438 dig "${DIG_ARGS[@]}" @${ns} +dnssec A ${TEST_DOMAIN} $@ | grep -q RRSIG
439 }
440
441 ns_supports_tcp() {
442 local ns=${1}
443 shift
444
445 # If TCP is forced we know by now if the server responds to it
446 if [ "${FORCE_TCP}" = "on" ]; then
447 return 0
448 fi
449
450 dig "${DIG_ARGS[@]}" @${ns} +tcp A ${TEST_DOMAIN} $@ >/dev/null || return 1
451 }
452
453 get_root_nameservers() {
454 while read -r hostname ttl record address; do
455 # Searching for A records
456 [ "${record}" = "A" ] || continue
457
458 echo "${address}"
459 done < /etc/unbound/root.hints
460 }
461
462 can_resolve_root() {
463 local ns
464 for ns in $(get_root_nameservers); do
465 if dig "${DIG_ARGS[@]}" @${ns} +dnssec SOA . $@ >/dev/null; then
466 return 0
467 fi
468 done
469
470 # none of the servers was reachable
471 return 1
472 }
473
474 enable_dnssec() {
475 local status=$(unbound-control get_option val-permissive-mode)
476
477 # Log DNSSEC status
478 echo "on" > /var/ipfire/red/dnssec-status
479
480 # Don't do anything if DNSSEC is already activated
481 [ "${status}" = "no" ] && return 0
482
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 .
486 }
487
488 disable_dnssec() {
489 # Log DNSSEC status
490 echo "off" > /var/ipfire/red/dnssec-status
491
492 unbound-control -q set_option val-permissive-mode: yes
493 }
494
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
504 fi
505 fi
506 }
507
508 resolve() {
509 local hostname="${1}"
510
511 local found=0
512 local ns
513 for ns in $(read_name_servers); do
514 local answer
515 for answer in $(dig "${DIG_ARGS[@]}" +short "@${ns}" A "${hostname}"); do
516 found=1
517
518 # Filter out non-IP addresses
519 if [[ ! "${answer}" =~ \.$ ]]; then
520 echo "${answer}"
521 fi
522 done
523
524 # End loop when we have got something
525 [ ${found} -eq 1 ] && break
526 done
527 }
528
529 # Sets up Safe Search for various search engines
530 update_safe_search() {
531 local google_tlds=(
532 google.ad
533 google.ae
534 google.al
535 google.am
536 google.as
537 google.at
538 google.az
539 google.ba
540 google.be
541 google.bf
542 google.bg
543 google.bi
544 google.bj
545 google.bs
546 google.bt
547 google.by
548 google.ca
549 google.cat
550 google.cd
551 google.cf
552 google.cg
553 google.ch
554 google.ci
555 google.cl
556 google.cm
557 google.cn
558 google.co.ao
559 google.co.bw
560 google.co.ck
561 google.co.cr
562 google.co.id
563 google.co.il
564 google.co.in
565 google.co.jp
566 google.co.ke
567 google.co.kr
568 google.co.ls
569 google.com
570 google.co.ma
571 google.com.af
572 google.com.ag
573 google.com.ai
574 google.com.ar
575 google.com.au
576 google.com.bd
577 google.com.bh
578 google.com.bn
579 google.com.bo
580 google.com.br
581 google.com.bz
582 google.com.co
583 google.com.cu
584 google.com.cy
585 google.com.do
586 google.com.ec
587 google.com.eg
588 google.com.et
589 google.com.fj
590 google.com.gh
591 google.com.gi
592 google.com.gt
593 google.com.hk
594 google.com.jm
595 google.com.kh
596 google.com.kw
597 google.com.lb
598 google.com.ly
599 google.com.mm
600 google.com.mt
601 google.com.mx
602 google.com.my
603 google.com.na
604 google.com.nf
605 google.com.ng
606 google.com.ni
607 google.com.np
608 google.com.om
609 google.com.pa
610 google.com.pe
611 google.com.pg
612 google.com.ph
613 google.com.pk
614 google.com.pr
615 google.com.py
616 google.com.qa
617 google.com.sa
618 google.com.sb
619 google.com.sg
620 google.com.sl
621 google.com.sv
622 google.com.tj
623 google.com.tr
624 google.com.tw
625 google.com.ua
626 google.com.uy
627 google.com.vc
628 google.com.vn
629 google.co.mz
630 google.co.nz
631 google.co.th
632 google.co.tz
633 google.co.ug
634 google.co.uk
635 google.co.uz
636 google.co.ve
637 google.co.vi
638 google.co.za
639 google.co.zm
640 google.co.zw
641 google.cv
642 google.cz
643 google.de
644 google.dj
645 google.dk
646 google.dm
647 google.dz
648 google.ee
649 google.es
650 google.fi
651 google.fm
652 google.fr
653 google.ga
654 google.ge
655 google.gg
656 google.gl
657 google.gm
658 google.gp
659 google.gr
660 google.gy
661 google.hn
662 google.hr
663 google.ht
664 google.hu
665 google.ie
666 google.im
667 google.iq
668 google.is
669 google.it
670 google.je
671 google.jo
672 google.kg
673 google.ki
674 google.kz
675 google.la
676 google.li
677 google.lk
678 google.lt
679 google.lu
680 google.lv
681 google.md
682 google.me
683 google.mg
684 google.mk
685 google.ml
686 google.mn
687 google.ms
688 google.mu
689 google.mv
690 google.mw
691 google.ne
692 google.nl
693 google.no
694 google.nr
695 google.nu
696 google.pl
697 google.pn
698 google.ps
699 google.pt
700 google.ro
701 google.rs
702 google.ru
703 google.rw
704 google.sc
705 google.se
706 google.sh
707 google.si
708 google.sk
709 google.sm
710 google.sn
711 google.so
712 google.sr
713 google.st
714 google.td
715 google.tg
716 google.tk
717 google.tl
718 google.tm
719 google.tn
720 google.to
721 google.tt
722 google.vg
723 google.vu
724 google.ws
725 )
726
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
733
734 local domain
735 for domain in ${google_tlds[@]}; do
736 unbound-control local_zone_remove "${domain}"
737 done >/dev/null
738
739 # Nothing to do if safe search is not enabled
740 if [ "${ENABLE_SAFE_SEARCH}" != "on" ]; then
741 return 0
742 fi
743
744 # Bing
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}"
748 done >/dev/null
749
750 # DuckDuckGo
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}"
754 done >/dev/null
755
756 # Google
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}"
762 done >/dev/null
763 done
764
765 # Yandex
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}"
770 done >/dev/null
771 done
772
773 # YouTube
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}"
777 done >/dev/null
778
779 return 0
780 }
781
782 case "$1" in
783 start)
784 # Print a nicer messagen when unbound is already running
785 if pidofproc -s unbound; then
786 statusproc /usr/sbin/unbound
787 exit 0
788 fi
789
790 eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)
791
792 # Update configuration files
793 write_tuning_conf
794 write_forward_conf
795
796 boot_mesg "Starting Unbound DNS Proxy..."
797 loadproc /usr/sbin/unbound || exit $?
798
799 # Make own hostname resolveable
800 own_hostname
801
802 # Update any known forwarding name servers
803 update_forwarders
804
805 # Install Safe Search rules when the system is already online
806 if [ -e "/var/ipfire/red/active" ]; then
807 update_safe_search
808 fi
809
810 # Update hosts
811 update_hosts
812
813 fix_time_if_dns_fail
814 ;;
815
816 stop)
817 boot_mesg "Stopping Unbound DNS Proxy..."
818 killproc /usr/sbin/unbound
819 ;;
820
821 restart)
822 $0 stop
823 sleep 1
824 $0 start
825 ;;
826
827 status)
828 statusproc /usr/sbin/unbound
829 ;;
830
831 update-forwarders)
832 # Do not try updating forwarders when unbound is not running
833 if ! pgrep unbound &>/dev/null; then
834 exit 0
835 fi
836
837 update_forwarders
838
839 unbound-control flush_negative > /dev/null
840 unbound-control flush_bogus > /dev/null
841
842 fix_time_if_dns_fail
843 ;;
844
845 remove-forwarders)
846 # Do not try updating forwarders when unbound is not running
847 if ! pgrep unbound &>/dev/null; then
848 exit 0
849 fi
850
851 remove_forwarders
852
853 unbound-control flush_negative > /dev/null
854 unbound-control flush_bogus > /dev/null
855 ;;
856
857
858 resolve)
859 resolve "${2}"
860 ;;
861
862 update-safe-search)
863 update_safe_search
864 ;;
865
866 *)
867 echo "Usage: $0 {start|stop|restart|status|update-forwarders|remove-forwarders|resolve|update-safe-search}"
868 exit 1
869 ;;
870 esac
871
872 # End $rc_base/init.d/unbound