INSECURE_ZONES=
USE_FORWARDERS=1
ENABLE_SAFE_SEARCH=off
+FORCE_TCP=off
# Cache any local zones for 60 seconds
LOCAL_TTL=60
-# EDNS buffer size
-EDNS_DEFAULT_BUFFER_SIZE=4096
-
# Load optional configuration
[ -e "/etc/sysconfig/unbound" ] && . /etc/sysconfig/unbound
+DIG_ARGS=()
+
+if [ "${FORCE_TCP}" = "on" ]; then
+ DIG_ARGS+=( "+tcp" )
+fi
+
ip_address_revptr() {
local addr=${1}
done 2>/dev/null | xargs echo
}
+check_red_has_carrier_and_ip() {
+ # Interface configured ?
+ [ ! -e "/var/ipfire/red/iface" ] && return 0;
+
+ # Interface present ?
+ [ ! -e "/sys/class/net/$(</var/ipfire/red/iface)" ] && return 0;
+
+ # has carrier ?
+ [ ! "$(</sys/class/net/$(</var/ipfire/red/iface)/carrier)" = "1" ] && return 0;
+
+ # has ip ?
+ [ "$(ip address show dev $(</var/ipfire/red/iface) | grep "inet")" = "" ] && return 0;
+
+ return 1;
+}
+
config_header() {
echo "# This file is automatically generated and any changes"
echo "# will be overwritten. DO NOT EDIT!"
}
update_forwarders() {
- if [ "${USE_FORWARDERS}" = "1" -a -e "/var/ipfire/red/active" ]; then
+ check_red_has_carrier_and_ip
+ if [ "${USE_FORWARDERS}" = "1" -a "${?}" = "1" ]; then
local forwarders
local broken_forwarders
esac
done
- # Determine EDNS buffer size
- local new_edns_buffer_size=${EDNS_DEFAULT_BUFFER_SIZE}
-
- for ns in ${forwarders}; do
- local edns_buffer_size=$(ns_determine_edns_buffer_size ${ns})
- if [ -n "${edns_buffer_size}" ]; then
- if [ ${edns_buffer_size} -lt ${new_edns_buffer_size} ]; then
- new_edns_buffer_size=${edns_buffer_size}
- fi
- fi
- done
-
- if [ ${new_edns_buffer_size} -lt ${EDNS_DEFAULT_BUFFER_SIZE} ]; then
- boot_mesg "EDNS buffer size reduced to ${new_edns_buffer_size}" ${WARNING}
- echo_warning
-
- unbound-control -q set_option edns-buffer-size: ${new_edns_buffer_size}
- fi
-
# Show warning for any broken upstream name servers
if [ -n "${broken_forwarders}" ]; then
boot_mesg "Ignoring broken upstream name server(s): ${broken_forwarders:1}" ${WARNING}
# In case we have found no working forwarders
else
# Test if the recursor mode is available
- if can_resolve_root +bufsize=${new_edns_buffer_size}; then
+ if can_resolve_root; then
# Make sure DNSSEC is activated
enable_dnssec
unbound-control -q forward off
}
+remove_forwarders() {
+ enable_dnssec
+ echo "local recursor" > /var/ipfire/red/dns
+ unbound-control -q forward off
+
+}
+
own_hostname() {
local hostname=$(hostname -f)
# 1.1.1.1 is reserved for unused green, skip this
(
config_header
+ # Force using TCP for upstream servers only
+ if [ "${FORCE_TCP}" = "on" ]; then
+ echo "# Force using TCP for upstream servers only"
+ echo "server:"
+ echo " tcp-upstream: yes"
+ echo
+ fi
+
local insecure_zones="${INSECURE_ZONES}"
local enabled zone server servers remark disable_dnssec rest
# Exit when the server is not reachable
ns_is_online ${ns} || return 1
- # Determine the maximum edns buffer size that works
- local edns_buffer_size=$(ns_determine_edns_buffer_size ${ns})
- if [ -n "${edns_buffer_size}" ]; then
- args="${args} +bufsize=${edns_buffer_size}"
- fi
-
local errors
for rr in DNSKEY DS RRSIG; do
if ! ns_forwards_${rr} ${ns} ${args}; then
local ns=${1}
shift
- dig @${ns} +nodnssec A ${TEST_DOMAIN} $@ >/dev/null
+ dig "${DIG_ARGS[@]}" @${ns} +nodnssec A ${TEST_DOMAIN} $@ >/dev/null
}
# Resolving ${TEST_DOMAIN_FAIL} will fail if the nameserver is validating
local ns=${1}
shift
- if ! dig @${ns} A ${TEST_DOMAIN_FAIL} $@ | grep -q SERVFAIL; then
+ if ! dig "${DIG_ARGS[@]}" @${ns} A ${TEST_DOMAIN_FAIL} $@ | grep -q SERVFAIL; then
return 1
else
# Determine if NS replies with "ad" data flag if DNSSEC enabled
- dig @${ns} +dnssec SOA ${TEST_DOMAIN} $@ | awk -F: '/\;\;\ flags\:/ { s=1; if (/\ ad/) s=0; exit s }'
+ dig "${DIG_ARGS[@]}" @${ns} +dnssec SOA ${TEST_DOMAIN} $@ | awk -F: '/\;\;\ flags\:/ { s=1; if (/\ ad/) s=0; exit s }'
fi
}
local ns=${1}
shift
- dig @${ns} DNSKEY ${TEST_DOMAIN} $@ | grep -qv SOA
+ dig "${DIG_ARGS[@]}" @${ns} DNSKEY ${TEST_DOMAIN} $@ | grep -qv SOA
}
ns_forwards_DS() {
local ns=${1}
shift
- dig @${ns} DS ${TEST_DOMAIN} $@ | grep -qv SOA
+ dig "${DIG_ARGS[@]}" @${ns} DS ${TEST_DOMAIN} $@ | grep -qv SOA
}
ns_forwards_RRSIG() {
local ns=${1}
shift
- dig @${ns} +dnssec A ${TEST_DOMAIN} $@ | grep -q RRSIG
+ dig "${DIG_ARGS[@]}" @${ns} +dnssec A ${TEST_DOMAIN} $@ | grep -q RRSIG
}
ns_supports_tcp() {
local ns=${1}
shift
- dig @${ns} +tcp A ${TEST_DOMAIN} $@ >/dev/null || return 1
-}
-
-ns_determine_edns_buffer_size() {
- local ns=${1}
- shift
-
- local b
- for b in 4096 2048 1500 1480 1464 1400 1280 512; do
- if dig @${ns} +dnssec +bufsize=${b} A ${TEST_DOMAIN} $@ >/dev/null; then
- echo "${b}"
- return 0
- fi
- done
+ # If TCP is forced we know by now if the server responds to it
+ if [ "${FORCE_TCP}" = "on" ]; then
+ return 0
+ fi
- return 1
+ dig "${DIG_ARGS[@]}" @${ns} +tcp A ${TEST_DOMAIN} $@ >/dev/null || return 1
}
get_root_nameservers() {
can_resolve_root() {
local ns
for ns in $(get_root_nameservers); do
- if dig @${ns} +dnssec SOA . $@ >/dev/null; then
+ if dig "${DIG_ARGS[@]}" @${ns} +dnssec SOA . $@ >/dev/null; then
return 0
fi
done
fix_time_if_dns_fail() {
# If DNS still not work try to init ntp with
# hardcoded ntp.ipfire.org (81.3.27.46)
- if [ -e /var/ipfire/red/active ]; then
+ check_red_has_carrier_and_ip
+ if [ -e "/var/ipfire/red/iface" -a "${?}" = "1" ]; then
host 0.ipfire.pool.ntp.org > /dev/null 2>&1
if [ "${?}" != "0" ]; then
boot_mesg "DNS still not functioning... Trying to sync time with ntp.ipfire.org (81.3.27.46)..."
fi
}
+resolve() {
+ local hostname="${1}"
+
+ local found=0
+ local ns
+ for ns in $(read_name_servers); do
+ local answer
+ for answer in $(dig "${DIG_ARGS[@]}" +short "@${ns}" A "${hostname}"); do
+ found=1
+
+ # Filter out non-IP addresses
+ if [[ ! "${answer}" =~ \.$ ]]; then
+ echo "${answer}"
+ fi
+ done
+
+ # End loop when we have got something
+ [ ${found} -eq 1 ] && break
+ done
+}
+
# Sets up Safe Search for various search engines
-write_safe_search_conf() {
+update_safe_search() {
local google_tlds=(
google.ad
google.ae
google.ws
)
- (
- # Nothing to do if safe search is not enabled
- if [ "${ENABLE_SAFE_SEARCH}" != "on" ]; then
- exit 0
- fi
+ # 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
- # This all belongs into the server: section
- echo "server:"
+ local domain
+ for domain in ${google_tlds[@]}; do
+ unbound-control local_zone_remove "${domain}"
+ done >/dev/null
- # Bing
- echo " local-zone: bing.com transparent"
- echo " local-data: \"www.bing.com CNAME strict.bing.com.\""
+ # Nothing to do if safe search is not enabled
+ if [ "${ENABLE_SAFE_SEARCH}" != "on" ]; then
+ return 0
+ fi
- # DuckDuckGo
- echo " local-zone: duckduckgo.com transparent"
- echo " local-data: \"duckduckgo.com CNAME safe.duckduckgo.com.\""
+ # 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
- # Google
- local domain
- for domain in ${google_tlds[@]}; do
- echo " local-zone: ${domain} transparent"
- echo " local-data: \"www.${domain} CNAME forcesafesearch.google.com.\""
- 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
- # Yandex
- echo " local-zone: yandex.ru transparent"
- echo " local-data: \"yandex.ru A 213.180.193.56\""
+ # 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
- # YouTube
- echo " local-zone: youtube.com transparent"
- echo " local-data: \"www.youtube.com CNAME restrictmoderate.youtube.com.\""
- ) > /etc/unbound/safe-search.conf
+ return 0
}
case "$1" in
# Update configuration files
write_tuning_conf
write_forward_conf
- write_safe_search_conf
boot_mesg "Starting Unbound DNS Proxy..."
loadproc /usr/sbin/unbound || exit $?
# Update any known forwarding name servers
update_forwarders
+ # 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
fix_time_if_dns_fail
;;
+ remove-forwarders)
+ # Do not try updating forwarders when unbound is not running
+ if ! pgrep unbound &>/dev/null; then
+ exit 0
+ fi
+
+ remove_forwarders
+
+ unbound-control flush_negative > /dev/null
+ unbound-control flush_bogus > /dev/null
+ ;;
+
+
test-name-server)
ns=${2}
echo "${ns} does not support TCP fallback"
fi
- edns_buffer_size=$(ns_determine_edns_buffer_size ${ns})
- if [ -n "${edns_buffer_size}" ]; then
- echo "EDNS buffer size for ${ns}: ${edns_buffer_size}"
- fi
-
exit ${ret}
;;
+ resolve)
+ resolve "${2}"
+ ;;
+
+ update-safe-search)
+ update_safe_search
+ ;;
+
*)
- echo "Usage: $0 {start|stop|restart|status|update-forwarders|test-name-server}"
+ echo "Usage: $0 {start|stop|restart|status|update-forwarders|remove-forwarders|test-name-server|resolve|update-safe-search}"
exit 1
;;
esac