]> git.ipfire.org Git - ipfire-2.x.git/blobdiff - src/initscripts/system/unbound
unbound: Set EDNS buffer size to 1232 bytes
[ipfire-2.x.git] / src / initscripts / system / unbound
index 520525ea140c96971dfa72947cb6e7451cd287e2..1c9f4288ca485592e2c7d5aa0b3b7f8383a12ac4 100644 (file)
@@ -15,16 +15,20 @@ TEST_DOMAIN_FAIL="dnssec-failed.org"
 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}
 
@@ -41,6 +45,22 @@ read_name_servers() {
        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!"
@@ -48,7 +68,8 @@ config_header() {
 }
 
 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
 
@@ -66,25 +87,6 @@ update_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}
@@ -105,7 +107,7 @@ update_forwarders() {
                # 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
 
@@ -131,6 +133,13 @@ update_forwarders() {
        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
@@ -175,6 +184,14 @@ write_forward_conf() {
        (
                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
@@ -335,12 +352,6 @@ test_name_server() {
        # 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
@@ -367,7 +378,7 @@ ns_is_online() {
        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
@@ -375,11 +386,11 @@ ns_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
 }
 
@@ -389,43 +400,33 @@ ns_forwards_DNSKEY() {
        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() {
@@ -440,7 +441,7 @@ 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
@@ -473,7 +474,8 @@ disable_dnssec() {
 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)..."
@@ -482,8 +484,29 @@ fix_time_if_dns_fail() {
        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
@@ -680,38 +703,59 @@ write_safe_search_conf() {
                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
@@ -727,7 +771,6 @@ 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 $?
@@ -738,6 +781,11 @@ case "$1" in
                # 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
 
@@ -773,6 +821,19 @@ case "$1" in
                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}
 
@@ -801,16 +862,19 @@ case "$1" in
                        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