diff --git a/set-unbound-dns.sh b/set-unbound-dns.sh index af69913..eefc1f1 100644 --- a/set-unbound-dns.sh +++ b/set-unbound-dns.sh @@ -12,6 +12,7 @@ NC='\033[0m' # No Color # addresses are not provided. ipv6_primary_dns="" ipv6_secondary_dns="" +use_dot="no" # Function to display error and exit error_exit() { @@ -103,6 +104,7 @@ check_connectivity choose_dns_provider() { local choice local valid_input=false + local dot_choice echo -e "\n${BLUE}=== DNS Provider Selection ===${NC}" echo -e "Please select a DNS provider to use:" @@ -232,6 +234,20 @@ choose_dns_provider() { error_exit "Script aborted by user" fi fi + + # Ask if DNS-over-TLS should be enabled for upstream forwarding + while true; do + read -p "Enable DNS-over-TLS (DoT) when forwarding to upstream DNS? (y/n): " dot_choice + if [[ $dot_choice =~ ^[Yy]$ ]]; then + use_dot="yes" + break + elif [[ $dot_choice =~ ^[Nn]$ ]]; then + use_dot="no" + break + else + warning "Invalid choice. Please enter y or n." + fi + done } # Function to choose IP mode @@ -341,6 +357,14 @@ if [ ! -d "${CONF_DIR}" ]; then mkdir -p "${CONF_DIR}" || error_exit "Failed to create unbound configuration directory" fi outrange=$(( cores * 1250 )) +dot_suffix="" +forward_tls_line="" + +if [ "$use_dot" = "yes" ]; then + dot_suffix="@853" + forward_tls_line=" forward-tls-upstream: yes" +fi + # Write Unbound configuration echo "Creating unbound configuration file..." cat > "${CONF_FILE}" <> "${CONF_FILE}" + echo " forward-addr: ${ipv6_primary_dns}${dot_suffix}" >> "${CONF_FILE}" fi if [ "$enable_ipv6" = "yes" ] && [ -n "$ipv6_secondary_dns" ]; then - echo " forward-addr: ${ipv6_secondary_dns}" >> "${CONF_FILE}" + echo " forward-addr: ${ipv6_secondary_dns}${dot_suffix}" >> "${CONF_FILE}" fi echo -e "\n${BLUE}=== Checking Unbound configuration ===${NC}" @@ -459,8 +484,11 @@ fi # output is skipped. Add a trailing `true` to force a zero exit status so the # redirection succeeds regardless of the selected mode. if ! { + echo "# Generated by set-unbound-dns.sh to direct traffic to local Unbound" [ "$enable_ipv4" = "yes" ] && echo "nameserver 127.0.0.1" [ "$enable_ipv6" = "yes" ] && echo "nameserver ::1" + echo "options edns0 trust-ad" # keep EDNS support and accept AD bit from Unbound + echo "options attempts:2 timeout:3" # avoid long resolver delays if Unbound is unreachable true } > /etc/resolv.conf; then error_exit "Failed to create new resolv.conf file" @@ -549,88 +577,105 @@ update_dns() { local provider_name=$3 local ipv6_primary_dns="${4:-}" local ipv6_secondary_dns="${5:-}" - + local use_dot="${6:-no}" + # Validate DNS servers if ! validate_ip "$primary_dns"; then error_exit "Invalid primary DNS IP address format: $primary_dns" fi - + if ! validate_ip "$secondary_dns"; then error_exit "Invalid secondary DNS IP address format: $secondary_dns" fi - + if [ -n "$ipv6_primary_dns" ] && ! validate_ipv6 "$ipv6_primary_dns"; then error_exit "Invalid primary IPv6 DNS address format: $ipv6_primary_dns" fi - + if [ -n "$ipv6_secondary_dns" ] && ! validate_ipv6 "$ipv6_secondary_dns"; then error_exit "Invalid secondary IPv6 DNS address format: $ipv6_secondary_dns" fi - + # Unlock resolv.conf first if ! chattr -i /etc/resolv.conf 2>/dev/null; then warning "Failed to remove immutable flag from /etc/resolv.conf or flag doesn't exist" fi - + # Check if unbound.conf exists if [ ! -f /etc/unbound/unbound.conf ]; then error_exit "Unbound configuration file not found. Is Unbound installed?" fi - + # Create backup of unbound.conf cp /etc/unbound/unbound.conf /etc/unbound/unbound.conf.backup.$(date +%Y%m%d%H%M%S) || warning "Failed to create backup of unbound.conf" - + # Update unbound configuration if ! sed -i "/forward-addr:/d" /etc/unbound/unbound.conf; then error_exit "Failed to update unbound configuration - could not remove existing forward-addr lines" fi - - if ! sed -i "/forward-first:/a\\ forward-addr: ${primary_dns} # Primary DNS\\n forward-addr: ${secondary_dns} # Secondary DNS" /etc/unbound/unbound.conf; then + if ! sed -i "/forward-tls-upstream:/d" /etc/unbound/unbound.conf; then + error_exit "Failed to update unbound configuration - could not remove existing forward-tls-upstream lines" + fi + + local dot_suffix="" + local tls_insert="" + if [ "$use_dot" = "yes" ]; then + dot_suffix="@853" + tls_insert=" forward-tls-upstream: yes\n" + fi + + if ! sed -i "/forward-first:/a\${tls_insert} forward-addr: ${primary_dns}${dot_suffix} # Primary DNS\n forward-addr: ${secondary_dns}${dot_suffix}# Secondary DNS" /etc/unbound/unbound.conf; then error_exit "Failed to update unbound configuration - could not add new forward-addr lines" fi - + # Add IPv6 DNS servers if provided if [ -n "$ipv6_primary_dns" ]; then - if ! sed -i "/forward-addr: ${secondary_dns}/a\\ forward-addr: ${ipv6_primary_dns} # Primary IPv6 DNS" /etc/unbound/unbound.conf; then + if ! sed -i "/forward-addr: ${secondary_dns}${dot_suffix}/a\ forward-addr: ${ipv6_primary_dns}${dot_suffix} # Primary IPv6 DNS" /etc/unbound/unbound.conf; then error_exit "Failed to update unbound configuration - could not add primary IPv6 DNS" fi fi - + if [ -n "$ipv6_secondary_dns" ]; then - if ! sed -i "/forward-addr: ${ipv6_primary_dns:-${secondary_dns}}/a\\ forward-addr: ${ipv6_secondary_dns} # Secondary IPv6 DNS" /etc/unbound/unbound.conf; then + if ! sed -i "/forward-addr: ${ipv6_primary_dns:-${secondary_dns}}${dot_suffix}/a\ forward-addr: ${ipv6_secondary_dns}${dot_suffix} # Secondary IPv6 DNS" /etc/unbound/unbound.conf; then error_exit "Failed to update unbound configuration - could not add secondary IPv6 DNS" fi fi - + # Verify configuration if ! unbound-checkconf; then error_exit "Updated unbound configuration is invalid. Restoring from backup..." cp /etc/unbound/unbound.conf.backup.* /etc/unbound/unbound.conf error_exit "Configuration restored from backup, but DNS update failed." fi - + # Restart unbound if ! systemctl restart unbound; then error_exit "Failed to restart unbound service" fi - + # Lock resolv.conf again if ! chattr +i /etc/resolv.conf 2>/dev/null; then warning "Failed to set immutable flag on /etc/resolv.conf" fi - + success "DNS settings updated to ${provider_name}" echo -e "Primary IPv4: ${primary_dns}" echo -e "Secondary IPv4: ${secondary_dns}" - + + if [ "$use_dot" = "yes" ]; then + echo -e "Upstream transport: DNS-over-TLS (port 853)" + else + echo -e "Upstream transport: Standard UDP/TCP" + fi + if [ -n "$ipv6_primary_dns" ]; then echo -e "Primary IPv6: ${ipv6_primary_dns}" fi - + if [ -n "$ipv6_secondary_dns" ]; then echo -e "Secondary IPv6: ${ipv6_secondary_dns}" fi - + # Test DNS if dig @127.0.0.1 google.com +short +timeout=5 +tries=2 | grep -q .; then success "DNS test successful ✅" @@ -647,11 +692,28 @@ show_current_dns() { else echo "Unbound configuration file not found" fi - + echo -e "\n${BLUE}Current resolv.conf:${NC}" cat /etc/resolv.conf } +# Ask whether to enable DNS-over-TLS for upstream resolvers +ask_dot_preference() { + local choice + while true; do + read -p "Enable DNS-over-TLS (DoT) for upstream DNS? (y/n): " choice + if [[ $choice =~ ^[Yy]$ ]]; then + echo "yes" + return + elif [[ $choice =~ ^[Nn]$ ]]; then + echo "no" + return + else + warning "Invalid choice. Please enter y or n." + fi + done +} + # Menu echo -e "${BLUE}===== DNS Management Tool =====${NC}" show_current_dns @@ -670,34 +732,38 @@ read -p "Enter your choice [1-7]: " choice case $choice in 1) read -p "Include IPv6 DNS servers for Cloudflare? (y/n): " include_ipv6 + use_dot_choice=$(ask_dot_preference) if [[ $include_ipv6 =~ ^[Yy]$ ]]; then - update_dns "1.1.1.1" "1.0.0.1" "Cloudflare" "2606:4700:4700::1111" "2606:4700:4700::1001" + update_dns "1.1.1.1" "1.0.0.1" "Cloudflare" "2606:4700:4700::1111" "2606:4700:4700::1001" "$use_dot_choice" else - update_dns "1.1.1.1" "1.0.0.1" "Cloudflare" + update_dns "1.1.1.1" "1.0.0.1" "Cloudflare" "" "" "$use_dot_choice" fi ;; 2) read -p "Include IPv6 DNS servers for Google? (y/n): " include_ipv6 + use_dot_choice=$(ask_dot_preference) if [[ $include_ipv6 =~ ^[Yy]$ ]]; then - update_dns "8.8.8.8" "8.8.4.4" "Google" "2001:4860:4860::8888" "2001:4860:4860::8844" + update_dns "8.8.8.8" "8.8.4.4" "Google" "2001:4860:4860::8888" "2001:4860:4860::8844" "$use_dot_choice" else - update_dns "8.8.8.8" "8.8.4.4" "Google" + update_dns "8.8.8.8" "8.8.4.4" "Google" "" "" "$use_dot_choice" fi ;; 3) read -p "Include IPv6 DNS servers for Quad9? (y/n): " include_ipv6 + use_dot_choice=$(ask_dot_preference) if [[ $include_ipv6 =~ ^[Yy]$ ]]; then - update_dns "9.9.9.9" "149.112.112.112" "Quad9" "2620:fe::fe" "2620:fe::9" + update_dns "9.9.9.9" "149.112.112.112" "Quad9" "2620:fe::fe" "2620:fe::9" "$use_dot_choice" else - update_dns "9.9.9.9" "149.112.112.112" "Quad9" + update_dns "9.9.9.9" "149.112.112.112" "Quad9" "" "" "$use_dot_choice" fi ;; 4) read -p "Include IPv6 DNS servers for OpenDNS? (y/n): " include_ipv6 + use_dot_choice=$(ask_dot_preference) if [[ $include_ipv6 =~ ^[Yy]$ ]]; then - update_dns "208.67.222.222" "208.67.220.220" "OpenDNS" "2620:119:35::35" "2620:119:53::53" + update_dns "208.67.222.222" "208.67.220.220" "OpenDNS" "2620:119:35::35" "2620:119:53::53" "$use_dot_choice" else - update_dns "208.67.222.222" "208.67.220.220" "OpenDNS" + update_dns "208.67.222.222" "208.67.220.220" "OpenDNS" "" "" "$use_dot_choice" fi ;; 5) @@ -749,8 +815,9 @@ case $choice in fi done fi - - update_dns "$primary_dns" "$secondary_dns" "Custom" "$ipv6_primary_dns" "$ipv6_secondary_dns" + use_dot_choice=$(ask_dot_preference) + + update_dns "$primary_dns" "$secondary_dns" "Custom" "$ipv6_primary_dns" "$ipv6_secondary_dns" "$use_dot_choice" ;; 6) echo -e "\n${BLUE}=== Checking DNS Status ===${NC}"