]> git.ipfire.org Git - ipfire-2.x.git/blob - src/initscripts/system/unbound
unbound: Only launch one process
[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 # Cache any local zones for 60 seconds
11 LOCAL_TTL=60
12
13 # Load configuration
14 eval $(/usr/local/bin/readhash /var/ipfire/dns/settings)
15 eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)
16
17 ip_address_revptr() {
18 local addr=${1}
19
20 local a1 a2 a3 a4
21 IFS=. read -r a1 a2 a3 a4 <<< ${addr}
22
23 echo "${a4}.${a3}.${a2}.${a1}.in-addr.arpa"
24 }
25
26 read_name_servers() {
27 # Read name servers from ISP
28 if [ "${USE_ISP_NAMESERVERS}" = "on" -a "${PROTO}" != "TLS" ]; then
29 local i
30 for i in 1 2; do
31 echo "$(</var/run/dns${i})"
32 done 2>/dev/null
33 fi
34
35 # Read configured name servers
36 local id address tls_hostname enabled remark
37 while IFS="," read -r id address tls_hostname enabled remark; do
38 [ "${enabled}" != "enabled" ] && continue
39
40 if [ "${PROTO}" = "TLS" ]; then
41 if [ -n "${tls_hostname}" ]; then
42 echo "${address}@853#${tls_hostname}"
43 fi
44 else
45 echo "${address}"
46 fi
47 done < /var/ipfire/dns/servers
48 }
49
50 config_header() {
51 echo "# This file is automatically generated and any changes"
52 echo "# will be overwritten. DO NOT EDIT!"
53 echo
54 }
55
56 write_hosts_conf() {
57 (
58 config_header
59
60 # Make own hostname resolveable
61 # 1.1.1.1 is reserved for unused green, skip this
62 if [ -n "${GREEN_ADDRESS}" -a "${GREEN_ADDRESS}" != "1.1.1.1" ]; then
63 echo "local-data: \"${HOSTNAME} ${LOCAL_TTL} IN A ${GREEN_ADDRESS}\""
64 fi
65
66 local address
67 for address in ${GREEN_ADDRESS} ${BLUE_ADDRESS} ${ORANGE_ADDRESS}; do
68 [ -n "${address}" ] || continue
69 [ "${address}" = "1.1.1.1" ] && continue
70
71 address=$(ip_address_revptr ${address})
72 echo "local-data: \"${address} ${LOCAL_TTL} IN PTR ${HOSTNAME}\""
73 done
74
75 # Add all hosts
76 local enabled address hostname domainname generateptr
77 while IFS="," read -r enabled address hostname domainname generateptr; do
78 [ "${enabled}" = "on" ] || continue
79
80 # Build FQDN
81 local fqdn="${hostname}.${domainname}"
82 echo "local-data: \"${fqdn} ${LOCAL_TTL} IN A ${address}\""
83
84 # Skip reverse resolution if the address equals the GREEN address
85 [ "${address}" = "${GREEN_ADDRESS}" ] && continue
86
87 # Skip reverse resolution if user requested not to do so
88 [ "${generateptr}" = "off" ] && continue
89
90 # Add RDNS
91 address=$(ip_address_revptr ${address})
92 echo "local-data: \"${address} ${LOCAL_TTL} IN PTR ${fqdn}\""
93 done < /var/ipfire/main/hosts
94 ) > /etc/unbound/hosts.conf
95 }
96
97 write_forward_conf() {
98 (
99 config_header
100
101 # Enable strict QNAME minimisation
102 if [ "${QNAME_MIN}" = "strict" ]; then
103 echo "server:"
104 echo " qname-minimisation-strict: yes"
105 echo
106 fi
107
108 # Force using TCP for upstream servers only
109 if [ "${PROTO}" = "TCP" ]; then
110 echo "# Force using TCP for upstream servers only"
111 echo "server:"
112 echo " tcp-upstream: yes"
113 echo
114 fi
115
116 local insecure_zones=""
117
118 local enabled zone server servers remark disable_dnssec rest
119 while IFS="," read -r enabled zone servers remark disable_dnssec rest; do
120 # Line must be enabled.
121 [ "${enabled}" = "on" ] || continue
122
123 # Zones that end with .local are commonly used for internal
124 # zones and therefore not signed
125 case "${zone}" in
126 *.local)
127 insecure_zones="${insecure_zones} ${zone}"
128 ;;
129 *)
130 if [ "${disable_dnssec}" = "on" ]; then
131 insecure_zones="${insecure_zones} ${zone}"
132 fi
133 ;;
134 esac
135
136 echo "stub-zone:"
137 echo " name: ${zone}"
138 for server in ${servers//|/ }; do
139 if [[ ${server} =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
140 echo " stub-addr: ${server}"
141 else
142 echo " stub-host: ${server}"
143 fi
144 done
145 echo
146
147 # Make all reverse lookup zones transparent
148 case "${zone}" in
149 *.in-addr.arpa)
150 echo "server:"
151 echo " local-zone: \"${zone}\" transparent"
152 echo
153 ;;
154 esac
155 done < /var/ipfire/dnsforward/config
156
157 if [ -n "${insecure_zones}" ]; then
158 echo "server:"
159
160 for zone in ${insecure_zones}; do
161 echo " domain-insecure: ${zone}"
162 done
163 fi
164
165 # Read name servers.
166 nameservers=$(read_name_servers)
167
168 # Only write forward zones if any nameservers are configured.
169 #
170 # Otherwise fall-back into recursor mode.
171 if [ -n "${nameservers}" ]; then
172
173 echo "forward-zone:"
174 echo " name: \".\""
175
176 # Force using TLS only
177 if [ "${PROTO}" = "TLS" ]; then
178 echo " forward-tls-upstream: yes"
179 fi
180
181 # Add upstream name servers
182 local ns
183 for ns in ${nameservers}; do
184 echo " forward-addr: ${ns}"
185 done
186 fi
187
188 ) > /etc/unbound/forward.conf
189 }
190
191 write_tuning_conf() {
192 # https://www.unbound.net/documentation/howto_optimise.html
193
194 # Determine amount of system memory
195 local mem=$(get_memory_amount)
196
197 # In the worst case scenario, unbound can use double the
198 # amount of memory allocated to a cache due to malloc overhead
199
200 # Even larger systems with more than 8GB of RAM
201 if [ ${mem} -ge 8192 ]; then
202 mem=1024
203
204 # Extra large systems with more than 4GB of RAM
205 elif [ ${mem} -ge 4096 ]; then
206 mem=512
207
208 # Large systems with more than 2GB of RAM
209 elif [ ${mem} -ge 2048 ]; then
210 mem=256
211
212 # Medium systems with more than 1GB of RAM
213 elif [ ${mem} -ge 1024 ]; then
214 mem=128
215
216 # Small systems with less than 256MB of RAM
217 elif [ ${mem} -le 256 ]; then
218 mem=16
219
220 # Everything else
221 else
222 mem=64
223 fi
224
225 (
226 config_header
227
228 # Slice up the cache
229 echo "rrset-cache-size: $(( ${mem} / 2 ))m"
230 echo "msg-cache-size: $(( ${mem} / 4 ))m"
231 echo "key-cache-size: $(( ${mem} / 4 ))m"
232
233 # Increase parallel queries
234 echo "outgoing-range: 8192"
235 echo "num-queries-per-thread: 4096"
236
237 # Use larger send/receive buffers
238 echo "so-sndbuf: 4m"
239 echo "so-rcvbuf: 4m"
240 ) > /etc/unbound/tuning.conf
241 }
242
243 get_memory_amount() {
244 local key val unit
245
246 while read -r key val unit; do
247 case "${key}" in
248 MemTotal:*)
249 # Convert to MB
250 echo "$(( ${val} / 1024 ))"
251 break
252 ;;
253 esac
254 done < /proc/meminfo
255 }
256
257 fix_time_if_dns_fails() {
258 # If DNS is working, everything is fine
259 if resolve "ping.ipfire.org" &>/dev/null; then
260 return 0
261 fi
262
263 # Try to sync time with a known time server
264 boot_mesg "DNS not functioning... Trying to sync time with ntp.ipfire.org (81.3.27.46)..."
265 loadproc /usr/local/bin/settime 81.3.27.46
266 }
267
268 resolve() {
269 local hostname="${1}"
270 local found=1
271
272 local answer
273 for answer in $(dig +short A "${hostname}"); do
274 # Filter out non-IP addresses
275 if [[ ! "${answer}" =~ \.$ ]]; then
276 found=0
277 echo "${answer}"
278 fi
279 done
280
281 return ${found}
282 }
283
284 # Sets up Safe Search for various search engines
285 update_safe_search() {
286 local google_tlds=(
287 google.ad
288 google.ae
289 google.al
290 google.am
291 google.as
292 google.at
293 google.az
294 google.ba
295 google.be
296 google.bf
297 google.bg
298 google.bi
299 google.bj
300 google.bs
301 google.bt
302 google.by
303 google.ca
304 google.cat
305 google.cd
306 google.cf
307 google.cg
308 google.ch
309 google.ci
310 google.cl
311 google.cm
312 google.cn
313 google.co.ao
314 google.co.bw
315 google.co.ck
316 google.co.cr
317 google.co.id
318 google.co.il
319 google.co.in
320 google.co.jp
321 google.co.ke
322 google.co.kr
323 google.co.ls
324 google.com
325 google.co.ma
326 google.com.af
327 google.com.ag
328 google.com.ai
329 google.com.ar
330 google.com.au
331 google.com.bd
332 google.com.bh
333 google.com.bn
334 google.com.bo
335 google.com.br
336 google.com.bz
337 google.com.co
338 google.com.cu
339 google.com.cy
340 google.com.do
341 google.com.ec
342 google.com.eg
343 google.com.et
344 google.com.fj
345 google.com.gh
346 google.com.gi
347 google.com.gt
348 google.com.hk
349 google.com.jm
350 google.com.kh
351 google.com.kw
352 google.com.lb
353 google.com.ly
354 google.com.mm
355 google.com.mt
356 google.com.mx
357 google.com.my
358 google.com.na
359 google.com.nf
360 google.com.ng
361 google.com.ni
362 google.com.np
363 google.com.om
364 google.com.pa
365 google.com.pe
366 google.com.pg
367 google.com.ph
368 google.com.pk
369 google.com.pr
370 google.com.py
371 google.com.qa
372 google.com.sa
373 google.com.sb
374 google.com.sg
375 google.com.sl
376 google.com.sv
377 google.com.tj
378 google.com.tr
379 google.com.tw
380 google.com.ua
381 google.com.uy
382 google.com.vc
383 google.com.vn
384 google.co.mz
385 google.co.nz
386 google.co.th
387 google.co.tz
388 google.co.ug
389 google.co.uk
390 google.co.uz
391 google.co.ve
392 google.co.vi
393 google.co.za
394 google.co.zm
395 google.co.zw
396 google.cv
397 google.cz
398 google.de
399 google.dj
400 google.dk
401 google.dm
402 google.dz
403 google.ee
404 google.es
405 google.fi
406 google.fm
407 google.fr
408 google.ga
409 google.ge
410 google.gg
411 google.gl
412 google.gm
413 google.gp
414 google.gr
415 google.gy
416 google.hn
417 google.hr
418 google.ht
419 google.hu
420 google.ie
421 google.im
422 google.iq
423 google.is
424 google.it
425 google.je
426 google.jo
427 google.kg
428 google.ki
429 google.kz
430 google.la
431 google.li
432 google.lk
433 google.lt
434 google.lu
435 google.lv
436 google.md
437 google.me
438 google.mg
439 google.mk
440 google.ml
441 google.mn
442 google.ms
443 google.mu
444 google.mv
445 google.mw
446 google.ne
447 google.nl
448 google.no
449 google.nr
450 google.nu
451 google.pl
452 google.pn
453 google.ps
454 google.pt
455 google.ro
456 google.rs
457 google.ru
458 google.rw
459 google.sc
460 google.se
461 google.sh
462 google.si
463 google.sk
464 google.sm
465 google.sn
466 google.so
467 google.sr
468 google.st
469 google.td
470 google.tg
471 google.tk
472 google.tl
473 google.tm
474 google.tn
475 google.to
476 google.tt
477 google.vg
478 google.vu
479 google.ws
480 )
481
482 # Cleanup previous settings
483 unbound-control local_zone_remove "bing.com" >/dev/null
484 unbound-control local_zone_remove "duckduckgo.com" >/dev/null
485 unbound-control local_zone_remove "yandex.com" >/dev/null
486 unbound-control local_zone_remove "yandex.ru" >/dev/null
487 unbound-control local_zone_remove "youtube.com" >/dev/null
488
489 local domain
490 for domain in ${google_tlds[@]}; do
491 unbound-control local_zone_remove "${domain}"
492 done >/dev/null
493
494 # Nothing to do if safe search is not enabled
495 if [ "${ENABLE_SAFE_SEARCH}" != "on" ]; then
496 return 0
497 fi
498
499 # Bing
500 unbound-control bing.com transparent >/dev/null
501 for address in $(resolve "strict.bing.com"); do
502 unbound-control local_data "www.bing.com ${LOCAL_TTL} IN A ${address}"
503 done >/dev/null
504
505 # DuckDuckGo
506 unbound-control local_zone duckduckgo.com typetransparent >/dev/null
507 for address in $(resolve "safe.duckduckgo.com"); do
508 unbound-control local_data "duckduckgo.com ${LOCAL_TTL} IN A ${address}"
509 done >/dev/null
510
511 # Google
512 local addresses="$(resolve "forcesafesearch.google.com")"
513 for domain in ${google_tlds[@]}; do
514 unbound-control local_zone "${domain}" transparent >/dev/null
515 for address in ${addresses}; do
516 unbound-control local_data "www.${domain} ${LOCAL_TTL} IN A ${address}"
517 done >/dev/null
518 done
519
520 # Yandex
521 for domain in yandex.com yandex.ru; do
522 unbound-control local_zone "${domain}" typetransparent >/dev/null
523 for address in $(resolve "familysearch.${domain}"); do
524 unbound-control local_data "${domain} ${LOCAL_TTL} IN A ${address}"
525 done >/dev/null
526 done
527
528 # YouTube
529 unbound-control local_zone youtube.com transparent >/dev/null
530 for address in $(resolve "restrictmoderate.youtube.com"); do
531 unbound-control local_data "www.youtube.com ${LOCAL_TTL} IN A ${address}"
532 done >/dev/null
533
534 return 0
535 }
536
537 case "$1" in
538 start)
539 # Print a nicer messagen when unbound is already running
540 if pidofproc -s unbound; then
541 statusproc /usr/sbin/unbound
542 exit 0
543 fi
544
545 # Update configuration files
546 write_tuning_conf
547 write_hosts_conf
548 write_forward_conf
549
550 boot_mesg "Starting Unbound DNS Proxy..."
551 loadproc /usr/sbin/unbound || exit $?
552
553 # Install Safe Search rules when the system is already online
554 if [ -e "/var/ipfire/red/active" ]; then
555 update_safe_search
556 fi
557 ;;
558
559 stop)
560 boot_mesg "Stopping Unbound DNS Proxy..."
561 killproc /usr/sbin/unbound
562 ;;
563
564 restart)
565 $0 stop
566 sleep 1
567 $0 start
568 ;;
569 reload|update-forwarders)
570 # Update configuration files
571 write_forward_conf
572 write_hosts_conf
573
574 # Call unbound-control and perform the reload
575 /usr/sbin/unbound-control -q reload
576
577 # Dummy Resolve to wait for unbound
578 resolve "ping.ipfire.org" &>/dev/null
579
580 if [ "$1" = "update-forwarders" ]; then
581 # Make sure DNS works at this point
582 fix_time_if_dns_fails
583 fi
584
585 # Update Safe Search rules if the system is online.
586 if [ -e "/var/ipfire/red/active" ]; then
587 update_safe_search
588 fi
589 ;;
590
591 status)
592 statusproc /usr/sbin/unbound
593 ;;
594
595 resolve)
596 resolve "${2}" || exit $?
597 ;;
598
599 *)
600 echo "Usage: $0 {start|stop|restart|reload|status|resolve|update-forwarders}"
601 exit 1
602 ;;
603 esac
604
605 # End $rc_base/init.d/unbound