Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save alamin-mahamud/b5c48400e6e1b7a8950001300db8fccd to your computer and use it in GitHub Desktop.

Select an option

Save alamin-mahamud/b5c48400e6e1b7a8950001300db8fccd to your computer and use it in GitHub Desktop.
test-dns.sh
#!/bin/bash
#
# DNS Fallback Resolution Test Script with Error Handling
# Handles communication errors and timeouts properly
#
# Configuration
declare -A SAFETY_MODES
SAFETY_MODES["LOW"]="203.190.10.114 203.190.10.115"
SAFETY_MODES["MEDIUM"]="203.190.10.116 203.190.10.117"
SAFETY_MODES["HIGH"]="203.190.10.118 203.190.10.119"
# Test domains
TEST_DOMAINS=(
"google.com:legitimate"
"github.com:legitimate"
"wikipedia.org:legitimate"
"bet365.com:gambling"
"pornhub.com:adult"
"thepiratebay.org:torrent"
"malware-test.com:malicious"
)
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'
# Statistics
declare -A stats
stats["total"]=0
stats["success"]=0
stats["blocked"]=0
stats["failed"]=0
stats["fallback_used"]=0
stats["comm_errors"]=0
stats["timeouts"]=0
# Error types
ERROR_TIMEOUT="TIMEOUT"
ERROR_NETWORK="NETWORK_ERROR"
ERROR_REFUSED="CONNECTION_REFUSED"
ERROR_UNREACHABLE="UNREACHABLE"
# DNS query timeout (seconds)
DNS_TIMEOUT=2
# Enhanced DNS resolution with detailed error handling
resolve_dns_with_errors() {
local dns_server=$1
local domain=$2
local timeout_val=${3:-$DNS_TIMEOUT}
# Create a temporary file for error capture
local error_file=$(mktemp)
local result_file=$(mktemp)
# Run dig with timeout and capture both stdout and stderr
timeout $timeout_val dig @"$dns_server" "$domain" +short +tries=1 +time=$timeout_val 2>"$error_file" >"$result_file"
local exit_code=$?
local result=$(head -1 "$result_file" 2>/dev/null)
local error_msg=$(cat "$error_file" 2>/dev/null)
# Clean up temp files
rm -f "$error_file" "$result_file"
# Analyze the exit code and error message
local status=""
local error_type=""
if [[ $exit_code -eq 124 ]]; then
# Timeout command exit code
status="ERROR"
error_type="$ERROR_TIMEOUT"
elif [[ $exit_code -ne 0 ]]; then
# Other errors
if [[ "$error_msg" =~ "connection refused" ]]; then
status="ERROR"
error_type="$ERROR_REFUSED"
elif [[ "$error_msg" =~ "network unreachable" ]] || [[ "$error_msg" =~ "host unreachable" ]]; then
status="ERROR"
error_type="$ERROR_UNREACHABLE"
elif [[ "$error_msg" =~ "communications error" ]]; then
status="ERROR"
error_type="$ERROR_NETWORK"
else
status="ERROR"
error_type="UNKNOWN_ERROR"
fi
elif [[ -z "$result" ]]; then
# Empty result could mean blocked or NXDOMAIN
# Try to check if it's a valid empty response vs error
if timeout $timeout_val dig @"$dns_server" "$domain" +short +tries=1 | grep -q "NXDOMAIN"; then
status="NXDOMAIN"
result="NXDOMAIN"
else
status="BLOCKED"
result="BLOCKED"
fi
else
# Success
status="SUCCESS"
fi
echo "${status}|${result}|${error_type}"
}
# DNS resolution with fallback and error handling
resolve_with_fallback() {
local mode=$1
local domain=$2
local ips=(${SAFETY_MODES[$mode]})
local result=""
local used_ip=""
local fallback_used=0
local error_details=""
local all_errors=""
for i in "${!ips[@]}"; do
local ip="${ips[$i]}"
local dns_response=$(resolve_dns_with_errors "$ip" "$domain")
IFS='|' read -r status result error_type <<< "$dns_response"
if [[ "$status" == "SUCCESS" ]]; then
used_ip=$ip
if [[ $i -gt 0 ]]; then
fallback_used=1
((stats["fallback_used"]++))
fi
break
elif [[ "$status" == "BLOCKED" ]] || [[ "$status" == "NXDOMAIN" ]]; then
used_ip=$ip
break
else
# Communication error - try fallback
all_errors="${all_errors}${ip}:${error_type} "
((stats["comm_errors"]++))
if [[ "$error_type" == "$ERROR_TIMEOUT" ]]; then
((stats["timeouts"]++))
fi
# Log the error
echo -e "${CYAN}[DEBUG]${NC} ${ip} failed: ${error_type}, trying fallback..." >&2
fi
done
if [[ -z "$used_ip" ]]; then
result="FAILED"
used_ip="all_failed"
error_details="$all_errors"
fi
echo "$result|$used_ip|$fallback_used|$error_details"
}
# Print test result with error details
print_result() {
local test_num=$1
local mode=$2
local domain=$3
local category=$4
local result=$5
local used_ip=$6
local fallback=$7
local error_details=$8
printf "[Test %3d] Mode: %-6s Domain: %-25s " "$test_num" "$mode" "$domain"
if [[ "$result" == "FAILED" ]]; then
echo -e "${RED}FAILED${NC} - All IPs failed"
if [[ -n "$error_details" ]]; then
echo -e " ${CYAN}Error details: ${error_details}${NC}"
fi
((stats["failed"]++))
elif [[ "$result" == "BLOCKED" ]]; then
echo -e "${YELLOW}BLOCKED${NC} by $used_ip"
((stats["blocked"]++))
elif [[ "$result" == "NXDOMAIN" ]]; then
echo -e "${YELLOW}NXDOMAIN${NC} from $used_ip"
((stats["failed"]++))
else
if [[ $fallback -eq 1 ]]; then
echo -e "${GREEN}RESOLVED${NC} via ${YELLOW}fallback${NC} $used_ip → $result"
else
echo -e "${GREEN}RESOLVED${NC} via $used_ip → $result"
fi
((stats["success"]++))
fi
((stats["total"]++))
}
# Health check function
health_check() {
echo -e "\n${BLUE}=== DNS Server Health Check ===${NC}"
for mode in "LOW" "MEDIUM" "HIGH"; do
echo -e "\n${YELLOW}$mode Mode Servers:${NC}"
local ips=(${SAFETY_MODES[$mode]})
for ip in "${ips[@]}"; do
echo -n " $ip: "
# Quick health check with 1 second timeout
local response=$(resolve_dns_with_errors "$ip" "google.com" 1)
IFS='|' read -r status result error_type <<< "$response"
if [[ "$status" == "SUCCESS" ]]; then
echo -e "${GREEN}HEALTHY${NC} (Response: $result)"
elif [[ "$status" == "ERROR" ]]; then
echo -e "${RED}UNHEALTHY${NC} ($error_type)"
else
echo -e "${YELLOW}UNKNOWN${NC}"
fi
done
done
echo ""
}
# Continuous monitoring mode
monitor_mode() {
echo -e "${PURPLE}=== Continuous DNS Monitoring ===${NC}"
echo "Press Ctrl+C to stop"
echo ""
local test_count=0
while true; do
clear
echo -e "${PURPLE}DNS Monitor - $(date)${NC}"
echo "========================================"
# Show server status
for mode in "LOW" "MEDIUM" "HIGH"; do
local ips=(${SAFETY_MODES[$mode]})
echo -e "\n${YELLOW}$mode Mode:${NC}"
for domain in "google.com" "bet365.com"; do
local result_data=$(resolve_with_fallback "$mode" "$domain")
IFS='|' read -r result used_ip fallback error_details <<< "$result_data"
if [[ "$result" == "FAILED" ]]; then
echo -e " $domain: ${RED}✗ FAILED${NC} - $error_details"
elif [[ "$result" == "BLOCKED" ]]; then
echo -e " $domain: ${YELLOW}⚠ BLOCKED${NC}"
else
local fallback_indicator=""
[[ $fallback -eq 1 ]] && fallback_indicator="${YELLOW}[F]${NC}"
echo -e " $domain: ${GREEN}✓${NC} $result via $used_ip $fallback_indicator"
fi
done
done
# Statistics
echo -e "\n${BLUE}Statistics:${NC}"
echo "Total Queries: ${stats["total"]}"
echo "Communication Errors: ${stats["comm_errors"]} (Timeouts: ${stats["timeouts"]})"
echo "Fallbacks Used: ${stats["fallback_used"]}"
#sleep 5
((test_count++))
done
}
# Run single test
run_test() {
local test_num=$1
local mode=$2
local domain=$3
local category=$4
local result_data=$(resolve_with_fallback "$mode" "$domain")
IFS='|' read -r result used_ip fallback error_details <<< "$result_data"
print_result "$test_num" "$mode" "$domain" "$category" "$result" "$used_ip" "$fallback" "$error_details"
}
# Main test loop
run_tests() {
local test_count=0
local target_tests=100
echo -e "${PURPLE}Running $target_tests DNS tests with fallback...${NC}\n"
while [[ $test_count -lt $target_tests ]]; do
for mode in "LOW" "MEDIUM" "HIGH"; do
# Pick a random domain
local domain_entry=${TEST_DOMAINS[$RANDOM % ${#TEST_DOMAINS[@]}]}
IFS=':' read -r domain category <<< "$domain_entry"
((test_count++))
run_test "$test_count" "$mode" "$domain" "$category"
[[ $test_count -ge $target_tests ]] && break 2
# Small delay between tests
# sleep 0.1
done
done
}
# Stress test mode
stress_test() {
echo -e "${RED}=== Stress Test Mode ===${NC}"
echo "This will simulate various failure conditions"
echo ""
# Test 1: Unreachable IP
echo -e "${YELLOW}Test 1: Unreachable IP${NC}"
local bad_ip="192.168.255.255"
echo "Testing with unreachable IP: $bad_ip"
local response=$(resolve_dns_with_errors "$bad_ip" "google.com" 2)
IFS='|' read -r status result error_type <<< "$response"
echo "Result: Status=$status, Error=$error_type"
echo ""
# Test 2: All servers down simulation
echo -e "${YELLOW}Test 2: All servers down${NC}"
local saved_low="${SAFETY_MODES["LOW"]}"
SAFETY_MODES["LOW"]="192.168.255.255 192.168.255.254"
local result_data=$(resolve_with_fallback "LOW" "google.com")
IFS='|' read -r result used_ip fallback error_details <<< "$result_data"
echo "Result: $result"
echo "Errors: $error_details"
SAFETY_MODES["LOW"]="$saved_low"
}
# Print statistics
print_stats() {
echo -e "\n${PURPLE}========================================"
echo "Test Statistics"
echo "========================================${NC}"
echo "Total Tests: ${stats["total"]}"
echo -e "${GREEN}Successful: ${stats["success"]}${NC}"
echo -e "${YELLOW}Blocked: ${stats["blocked"]}${NC}"
echo -e "${RED}Failed: ${stats["failed"]}${NC}"
echo "Fallback Used: ${stats["fallback_used"]}"
echo -e "${CYAN}Communication Errors: ${stats["comm_errors"]}${NC}"
echo " - Timeouts: ${stats["timeouts"]}"
if [[ ${stats["total"]} -gt 0 ]]; then
local success_rate=$(( (stats["success"] * 100) / stats["total"] ))
local fallback_rate=$(( (stats["fallback_used"] * 100) / stats["total"] ))
local error_rate=$(( (stats["comm_errors"] * 100) / stats["total"] ))
echo ""
echo "Success Rate: ${success_rate}%"
echo "Fallback Rate: ${fallback_rate}%"
echo "Error Rate: ${error_rate}%"
fi
}
# Main function
main() {
case "${1:-}" in
"health")
health_check
;;
"monitor")
monitor_mode
;;
"stress")
stress_test
;;
"quick")
health_check
echo -e "${BLUE}Running quick test...${NC}"
for i in {1..10}; do
run_test "$i" "LOW" "google.com" "legitimate"
done
print_stats
;;
*)
health_check
run_tests
print_stats
;;
esac
}
# Check dependencies
if ! command -v dig >/dev/null 2>&1; then
echo "${RED}Error: 'dig' command not found. Please install dnsutils/bind-utils.${NC}"
exit 1
fi
# Run main
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment