Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 103 additions & 36 deletions set-unbound-dns.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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:"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}" <<EOF || error_exit "Failed to write unbound configuration"
Expand Down Expand Up @@ -377,16 +401,17 @@ $( [ "$enable_ipv6" = "yes" ] && echo " private-address: fe80::/10" )
forward-zone:
name: "."
forward-first: no
forward-addr: ${primary_dns}
forward-addr: ${secondary_dns}
${forward_tls_line}
forward-addr: ${primary_dns}${dot_suffix}
forward-addr: ${secondary_dns}${dot_suffix}
EOF

if [ "$enable_ipv6" = "yes" ] && [ -n "$ipv6_primary_dns" ]; then
echo " forward-addr: ${ipv6_primary_dns}" >> "${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}"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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 ✅"
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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}"
Expand Down