mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-12 12:15:52 +02:00
650 lines
13 KiB
Bash
650 lines
13 KiB
Bash
#!/bin/sh
|
|
# Begin $rc_base/init.d/unbound
|
|
|
|
# Description : Unbound DNS resolver boot script for IPfire
|
|
# Author : Marcel Lorenz <marcel.lorenz@ipfire.org>
|
|
|
|
. /etc/sysconfig/rc
|
|
. ${rc_functions}
|
|
|
|
TEST_DOMAIN="ipfire.org"
|
|
|
|
# This domain will never validate
|
|
TEST_DOMAIN_FAIL="dnssec-failed.org"
|
|
|
|
# Cache any local zones for 60 seconds
|
|
LOCAL_TTL=60
|
|
|
|
# Load configuration
|
|
eval $(/usr/local/bin/readhash /var/ipfire/dns/settings)
|
|
eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)
|
|
|
|
ip_address_revptr() {
|
|
local addr=${1}
|
|
|
|
local a1 a2 a3 a4
|
|
IFS=. read -r a1 a2 a3 a4 <<< ${addr}
|
|
|
|
echo "${a4}.${a3}.${a2}.${a1}.in-addr.arpa"
|
|
}
|
|
|
|
read_name_servers() {
|
|
# Read name servers from ISP
|
|
if [ "${USE_ISP_NAMESERVERS}" = "on" -a "${PROTO}" != "TLS" ]; then
|
|
local i
|
|
for i in 1 2; do
|
|
echo "$(</var/run/dns${i})"
|
|
done 2>/dev/null
|
|
fi
|
|
|
|
# Read configured name servers
|
|
local id address tls_hostname enabled remark
|
|
while IFS="," read -r id address tls_hostname enabled remark; do
|
|
[ "${enabled}" != "enabled" ] && continue
|
|
|
|
if [ "${PROTO}" = "TLS" ]; then
|
|
if [ -n "${tls_hostname}" ]; then
|
|
echo "${address}@853#${tls_hostname}"
|
|
fi
|
|
else
|
|
echo "${address}"
|
|
fi
|
|
done < /var/ipfire/dns/servers
|
|
}
|
|
|
|
config_header() {
|
|
echo "# This file is automatically generated and any changes"
|
|
echo "# will be overwritten. DO NOT EDIT!"
|
|
echo
|
|
}
|
|
|
|
own_hostname() {
|
|
local hostname=$(hostname -f)
|
|
# 1.1.1.1 is reserved for unused green, skip this
|
|
if [ -n "${GREEN_ADDRESS}" -a "${GREEN_ADDRESS}" != "1.1.1.1" ]; then
|
|
unbound-control -q local_data "${hostname} ${LOCAL_TTL} IN A ${GREEN_ADDRESS}"
|
|
fi
|
|
|
|
local address
|
|
for address in ${GREEN_ADDRESS} ${BLUE_ADDRESS} ${ORANGE_ADDRESS}; do
|
|
[ -n "${address}" ] || continue
|
|
[ "${address}" = "1.1.1.1" ] && continue
|
|
|
|
address=$(ip_address_revptr ${address})
|
|
unbound-control -q local_data "${address} ${LOCAL_TTL} IN PTR ${hostname}"
|
|
done
|
|
}
|
|
|
|
update_hosts() {
|
|
# Make own hostname resolveable
|
|
own_hostname
|
|
|
|
local enabled address hostname domainname generateptr
|
|
|
|
while IFS="," read -r enabled address hostname domainname generateptr; do
|
|
[ "${enabled}" = "on" ] || continue
|
|
|
|
# Build FQDN
|
|
local fqdn="${hostname}.${domainname}"
|
|
|
|
unbound-control -q local_data "${fqdn} ${LOCAL_TTL} IN A ${address}"
|
|
|
|
# Skip reverse resolution if the address equals the GREEN address
|
|
[ "${address}" = "${GREEN_ADDRESS}" ] && continue
|
|
|
|
# Skip reverse resolution if user requested not to do so
|
|
[ "${generateptr}" = "off" ] && continue
|
|
|
|
# Add RDNS
|
|
address=$(ip_address_revptr ${address})
|
|
unbound-control -q local_data "${address} ${LOCAL_TTL} IN PTR ${fqdn}"
|
|
done < /var/ipfire/main/hosts
|
|
}
|
|
|
|
write_forward_conf() {
|
|
(
|
|
config_header
|
|
|
|
# Enable strict QNAME minimisation
|
|
if [ "${QNAME_MIN}" = "strict" ]; then
|
|
echo "server:"
|
|
echo " qname-minimisation-strict: yes"
|
|
echo
|
|
fi
|
|
|
|
# Force using TCP for upstream servers only
|
|
if [ "${PROTO}" = "TCP" ]; then
|
|
echo "# Force using TCP for upstream servers only"
|
|
echo "server:"
|
|
echo " tcp-upstream: yes"
|
|
echo
|
|
fi
|
|
|
|
local insecure_zones=""
|
|
|
|
local enabled zone server servers remark disable_dnssec rest
|
|
while IFS="," read -r enabled zone servers remark disable_dnssec rest; do
|
|
# Line must be enabled.
|
|
[ "${enabled}" = "on" ] || continue
|
|
|
|
# Zones that end with .local are commonly used for internal
|
|
# zones and therefore not signed
|
|
case "${zone}" in
|
|
*.local)
|
|
insecure_zones="${insecure_zones} ${zone}"
|
|
;;
|
|
*)
|
|
if [ "${disable_dnssec}" = "on" ]; then
|
|
insecure_zones="${insecure_zones} ${zone}"
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
echo "stub-zone:"
|
|
echo " name: ${zone}"
|
|
for server in ${servers//|/ }; do
|
|
if [[ ${server} =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
echo " stub-addr: ${server}"
|
|
else
|
|
echo " stub-host: ${server}"
|
|
fi
|
|
done
|
|
echo
|
|
|
|
# Make all reverse lookup zones transparent
|
|
case "${zone}" in
|
|
*.in-addr.arpa)
|
|
echo "server:"
|
|
echo " local-zone: \"${zone}\" transparent"
|
|
echo
|
|
;;
|
|
esac
|
|
done < /var/ipfire/dnsforward/config
|
|
|
|
if [ -n "${insecure_zones}" ]; then
|
|
echo "server:"
|
|
|
|
for zone in ${insecure_zones}; do
|
|
echo " domain-insecure: ${zone}"
|
|
done
|
|
fi
|
|
|
|
echo "forward-zone:"
|
|
echo " name: \".\""
|
|
|
|
# Force using TLS only
|
|
if [ "${PROTO}" = "TLS" ]; then
|
|
echo " forward-tls-upstream: yes"
|
|
fi
|
|
|
|
# Add upstream name servers
|
|
local ns
|
|
for ns in $(read_name_servers); do
|
|
echo " forward-addr: ${ns}"
|
|
done
|
|
) > /etc/unbound/forward.conf
|
|
}
|
|
|
|
write_tuning_conf() {
|
|
# https://www.unbound.net/documentation/howto_optimise.html
|
|
|
|
# Determine number of online processors
|
|
local processors=$(getconf _NPROCESSORS_ONLN)
|
|
|
|
# Determine number of slabs
|
|
local slabs=1
|
|
while [ ${slabs} -lt ${processors} ]; do
|
|
slabs=$(( ${slabs} * 2 ))
|
|
done
|
|
|
|
# Determine amount of system memory
|
|
local mem=$(get_memory_amount)
|
|
|
|
# In the worst case scenario, unbound can use double the
|
|
# amount of memory allocated to a cache due to malloc overhead
|
|
|
|
# Even larger systems with more than 8GB of RAM
|
|
if [ ${mem} -ge 8192 ]; then
|
|
mem=1024
|
|
|
|
# Extra large systems with more than 4GB of RAM
|
|
elif [ ${mem} -ge 4096 ]; then
|
|
mem=512
|
|
|
|
# Large systems with more than 2GB of RAM
|
|
elif [ ${mem} -ge 2048 ]; then
|
|
mem=256
|
|
|
|
# Medium systems with more than 1GB of RAM
|
|
elif [ ${mem} -ge 1024 ]; then
|
|
mem=128
|
|
|
|
# Small systems with less than 256MB of RAM
|
|
elif [ ${mem} -le 256 ]; then
|
|
mem=16
|
|
|
|
# Everything else
|
|
else
|
|
mem=64
|
|
fi
|
|
|
|
(
|
|
config_header
|
|
|
|
# We run one thread per processor
|
|
echo "num-threads: ${processors}"
|
|
echo "so-reuseport: yes"
|
|
|
|
# Adjust number of slabs
|
|
echo "infra-cache-slabs: ${slabs}"
|
|
echo "key-cache-slabs: ${slabs}"
|
|
echo "msg-cache-slabs: ${slabs}"
|
|
echo "rrset-cache-slabs: ${slabs}"
|
|
|
|
# Slice up the cache
|
|
echo "rrset-cache-size: $(( ${mem} / 2 ))m"
|
|
echo "msg-cache-size: $(( ${mem} / 4 ))m"
|
|
echo "key-cache-size: $(( ${mem} / 4 ))m"
|
|
|
|
# Increase parallel queries
|
|
echo "outgoing-range: 8192"
|
|
echo "num-queries-per-thread: 4096"
|
|
|
|
# Use larger send/receive buffers
|
|
echo "so-sndbuf: 4m"
|
|
echo "so-rcvbuf: 4m"
|
|
) > /etc/unbound/tuning.conf
|
|
}
|
|
|
|
get_memory_amount() {
|
|
local key val unit
|
|
|
|
while read -r key val unit; do
|
|
case "${key}" in
|
|
MemTotal:*)
|
|
# Convert to MB
|
|
echo "$(( ${val} / 1024 ))"
|
|
break
|
|
;;
|
|
esac
|
|
done < /proc/meminfo
|
|
}
|
|
|
|
fix_time_if_dns_fails() {
|
|
# If DNS is working, everything is fine
|
|
if resolve "ping.ipfire.org" &>/dev/null; then
|
|
return 0
|
|
fi
|
|
|
|
# Try to sync time with a known time server
|
|
boot_mesg "DNS not functioning... Trying to sync time with ntp.ipfire.org (81.3.27.46)..."
|
|
loadproc /usr/local/bin/settime 81.3.27.46
|
|
}
|
|
|
|
resolve() {
|
|
local hostname="${1}"
|
|
|
|
local answer
|
|
for answer in $(dig +short A "${hostname}"); do
|
|
# Filter out non-IP addresses
|
|
if [[ ! "${answer}" =~ \.$ ]]; then
|
|
echo "${answer}"
|
|
fi
|
|
done
|
|
}
|
|
|
|
update_forwarders() {
|
|
# Do nothing when we do not use the ISP name servers
|
|
[ "${USE_ISP_NAMESERVERS}" != "on" ] && return 0
|
|
|
|
# We cannot update anything when using TLS
|
|
# Unbound will then try to connect to the servers using UDP on port 853
|
|
[ "${PROTO}" = "TLS" ] && return 0
|
|
|
|
# Update unbound about the new servers
|
|
local nameservers=( $(read_name_servers) )
|
|
if [ -n "${nameservers[*]}" ]; then
|
|
unbound-control -q forward "${nameservers[@]}"
|
|
else
|
|
unbound-control -q forward off
|
|
fi
|
|
}
|
|
|
|
# Sets up Safe Search for various search engines
|
|
update_safe_search() {
|
|
local google_tlds=(
|
|
google.ad
|
|
google.ae
|
|
google.al
|
|
google.am
|
|
google.as
|
|
google.at
|
|
google.az
|
|
google.ba
|
|
google.be
|
|
google.bf
|
|
google.bg
|
|
google.bi
|
|
google.bj
|
|
google.bs
|
|
google.bt
|
|
google.by
|
|
google.ca
|
|
google.cat
|
|
google.cd
|
|
google.cf
|
|
google.cg
|
|
google.ch
|
|
google.ci
|
|
google.cl
|
|
google.cm
|
|
google.cn
|
|
google.co.ao
|
|
google.co.bw
|
|
google.co.ck
|
|
google.co.cr
|
|
google.co.id
|
|
google.co.il
|
|
google.co.in
|
|
google.co.jp
|
|
google.co.ke
|
|
google.co.kr
|
|
google.co.ls
|
|
google.com
|
|
google.co.ma
|
|
google.com.af
|
|
google.com.ag
|
|
google.com.ai
|
|
google.com.ar
|
|
google.com.au
|
|
google.com.bd
|
|
google.com.bh
|
|
google.com.bn
|
|
google.com.bo
|
|
google.com.br
|
|
google.com.bz
|
|
google.com.co
|
|
google.com.cu
|
|
google.com.cy
|
|
google.com.do
|
|
google.com.ec
|
|
google.com.eg
|
|
google.com.et
|
|
google.com.fj
|
|
google.com.gh
|
|
google.com.gi
|
|
google.com.gt
|
|
google.com.hk
|
|
google.com.jm
|
|
google.com.kh
|
|
google.com.kw
|
|
google.com.lb
|
|
google.com.ly
|
|
google.com.mm
|
|
google.com.mt
|
|
google.com.mx
|
|
google.com.my
|
|
google.com.na
|
|
google.com.nf
|
|
google.com.ng
|
|
google.com.ni
|
|
google.com.np
|
|
google.com.om
|
|
google.com.pa
|
|
google.com.pe
|
|
google.com.pg
|
|
google.com.ph
|
|
google.com.pk
|
|
google.com.pr
|
|
google.com.py
|
|
google.com.qa
|
|
google.com.sa
|
|
google.com.sb
|
|
google.com.sg
|
|
google.com.sl
|
|
google.com.sv
|
|
google.com.tj
|
|
google.com.tr
|
|
google.com.tw
|
|
google.com.ua
|
|
google.com.uy
|
|
google.com.vc
|
|
google.com.vn
|
|
google.co.mz
|
|
google.co.nz
|
|
google.co.th
|
|
google.co.tz
|
|
google.co.ug
|
|
google.co.uk
|
|
google.co.uz
|
|
google.co.ve
|
|
google.co.vi
|
|
google.co.za
|
|
google.co.zm
|
|
google.co.zw
|
|
google.cv
|
|
google.cz
|
|
google.de
|
|
google.dj
|
|
google.dk
|
|
google.dm
|
|
google.dz
|
|
google.ee
|
|
google.es
|
|
google.fi
|
|
google.fm
|
|
google.fr
|
|
google.ga
|
|
google.ge
|
|
google.gg
|
|
google.gl
|
|
google.gm
|
|
google.gp
|
|
google.gr
|
|
google.gy
|
|
google.hn
|
|
google.hr
|
|
google.ht
|
|
google.hu
|
|
google.ie
|
|
google.im
|
|
google.iq
|
|
google.is
|
|
google.it
|
|
google.je
|
|
google.jo
|
|
google.kg
|
|
google.ki
|
|
google.kz
|
|
google.la
|
|
google.li
|
|
google.lk
|
|
google.lt
|
|
google.lu
|
|
google.lv
|
|
google.md
|
|
google.me
|
|
google.mg
|
|
google.mk
|
|
google.ml
|
|
google.mn
|
|
google.ms
|
|
google.mu
|
|
google.mv
|
|
google.mw
|
|
google.ne
|
|
google.nl
|
|
google.no
|
|
google.nr
|
|
google.nu
|
|
google.pl
|
|
google.pn
|
|
google.ps
|
|
google.pt
|
|
google.ro
|
|
google.rs
|
|
google.ru
|
|
google.rw
|
|
google.sc
|
|
google.se
|
|
google.sh
|
|
google.si
|
|
google.sk
|
|
google.sm
|
|
google.sn
|
|
google.so
|
|
google.sr
|
|
google.st
|
|
google.td
|
|
google.tg
|
|
google.tk
|
|
google.tl
|
|
google.tm
|
|
google.tn
|
|
google.to
|
|
google.tt
|
|
google.vg
|
|
google.vu
|
|
google.ws
|
|
)
|
|
|
|
# Cleanup previous settings
|
|
unbound-control local_zone_remove "bing.com" >/dev/null
|
|
unbound-control local_zone_remove "duckduckgo.com" >/dev/null
|
|
unbound-control local_zone_remove "yandex.com" >/dev/null
|
|
unbound-control local_zone_remove "yandex.ru" >/dev/null
|
|
unbound-control local_zone_remove "youtube.com" >/dev/null
|
|
|
|
local domain
|
|
for domain in ${google_tlds[@]}; do
|
|
unbound-control local_zone_remove "${domain}"
|
|
done >/dev/null
|
|
|
|
# Nothing to do if safe search is not enabled
|
|
if [ "${ENABLE_SAFE_SEARCH}" != "on" ]; then
|
|
return 0
|
|
fi
|
|
|
|
# Bing
|
|
unbound-control bing.com transparent >/dev/null
|
|
for address in $(resolve "strict.bing.com"); do
|
|
unbound-control local_data "www.bing.com ${LOCAL_TTL} IN A ${address}"
|
|
done >/dev/null
|
|
|
|
# DuckDuckGo
|
|
unbound-control local_zone duckduckgo.com typetransparent >/dev/null
|
|
for address in $(resolve "safe.duckduckgo.com"); do
|
|
unbound-control local_data "duckduckgo.com ${LOCAL_TTL} IN A ${address}"
|
|
done >/dev/null
|
|
|
|
# Google
|
|
local addresses="$(resolve "forcesafesearch.google.com")"
|
|
for domain in ${google_tlds[@]}; do
|
|
unbound-control local_zone "${domain}" transparent >/dev/null
|
|
for address in ${addresses}; do
|
|
unbound-control local_data: "www.${domain} ${LOCAL_TTL} IN A ${address}"
|
|
done >/dev/null
|
|
done
|
|
|
|
# Yandex
|
|
for domain in yandex.com yandex.ru; do
|
|
unbound-control local_zone "${domain}" typetransparent >/dev/null
|
|
for address in $(resolve "familysearch.${domain}"); do
|
|
unbound-control local_data "${domain} ${LOCAL_TTL} IN A ${address}"
|
|
done >/dev/null
|
|
done
|
|
|
|
# YouTube
|
|
unbound-control local_zone youtube.com transparent >/dev/null
|
|
for address in $(resolve "restrictmoderate.youtube.com"); do
|
|
unbound-control local_data "www.youtube.com ${LOCAL_TTL} IN A ${address}"
|
|
done >/dev/null
|
|
|
|
return 0
|
|
}
|
|
|
|
case "$1" in
|
|
start)
|
|
# Print a nicer messagen when unbound is already running
|
|
if pidofproc -s unbound; then
|
|
statusproc /usr/sbin/unbound
|
|
exit 0
|
|
fi
|
|
|
|
# Update configuration files
|
|
write_tuning_conf
|
|
write_forward_conf
|
|
|
|
boot_mesg "Starting Unbound DNS Proxy..."
|
|
loadproc /usr/sbin/unbound || exit $?
|
|
|
|
# Install Safe Search rules when the system is already online
|
|
if [ -e "/var/ipfire/red/active" ]; then
|
|
update_safe_search
|
|
fi
|
|
|
|
# Update hosts
|
|
update_hosts
|
|
;;
|
|
|
|
stop)
|
|
boot_mesg "Stopping Unbound DNS Proxy..."
|
|
killproc /usr/sbin/unbound
|
|
;;
|
|
|
|
restart)
|
|
$0 stop
|
|
sleep 1
|
|
$0 start
|
|
;;
|
|
reload)
|
|
# Update configuration files
|
|
write_tuning_conf
|
|
write_forward_conf
|
|
|
|
# Update Safe Search rules if the system is online.
|
|
if [ -e "/var/ipfire/red/active" ]; then
|
|
update_safe_search
|
|
fi
|
|
|
|
# Update hosts.
|
|
update_hosts
|
|
|
|
# Call unbound-control and perform the reload
|
|
/usr/sbin/unbound-control -q reload
|
|
;;
|
|
|
|
status)
|
|
statusproc /usr/sbin/unbound
|
|
;;
|
|
|
|
update-forwarders)
|
|
update_forwarders
|
|
|
|
# Make sure DNS works at this point
|
|
fix_time_if_dns_fails
|
|
|
|
# Update Safe Search settings
|
|
update_safe_search
|
|
;;
|
|
|
|
remove-forwarders)
|
|
update_forwarders
|
|
;;
|
|
|
|
resolve)
|
|
resolve "${2}"
|
|
;;
|
|
|
|
update-safe-search)
|
|
update_safe_search
|
|
;;
|
|
|
|
*)
|
|
echo "Usage: $0 {start|stop|restart|reload|status|resolve|update-forwarders|remove-forwarders|update-safe-search}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# End $rc_base/init.d/unbound
|