summarylogtreecommitdiffstats
path: root/dnsch.sh
blob: 5b967f87ebbf4b2417f0a40aa444f030923f47b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#!/bin/bash

# Check if the script is run as root
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root" 
   exit 1
fi

# Backup the original resolv.conf file only if a backup doesn't exist yet
if [[ ! -e /etc/resolv.conf.bak ]]; then
    cp /etc/resolv.conf /etc/resolv.conf.bak
fi

# Function to print usage instructions
usage() {
    echo "Usage: $0 {g|sh|ag|cf|403|bg|rd|el} [-c|--clear] [-s|--set] [-p|--ping] [-r|--restore]" # TODO: make this use the dnsList?
    exit 1
}

# Function to calculate average ping time for a given DNS server
get_average_ping() {
    local dns=$1

    avg=$(ping -c 4 -q "$dns" | tail -1 | awk '{print $4}' | cut -d '/' -f 2)
    if [ -z "$avg" ]; then
        echo "9999"
    else
        echo "$avg"
    fi
}
# Verify the number of arguments provided
if [[ $# -lt 1 ]]; then
    usage
fi

# A list of all DNSs
declare -A dnsList
dnsList["g",0]="8.8.8.8"; dnsList["g",1]="8.8.4.4"; dnsList["g","name"]="Google"
dnsList["sh",0]="178.22.122.100"; dnsList["sh",1]="185.51.200.2"; dnsList["sh","name"]="Shecan"
dnsList["ag",0]="94.140.14.14"; dnsList["ag",1]="94.140.15.15"; dnsList["ag","name"]="AdGuard"
dnsList["cf",0]="1.1.1.1"; dnsList["cf",1]="1.0.0.1"; dnsList["cf","name"]="Cloudflare"
dnsList["403",0]="10.202.10.202"; dnsList["403",1]="10.202.10.102"; dnsList["403","name"]="403"
dnsList["bg",0]="185.55.226.26"; dnsList["bg",1]="185.55.225.25"; dnsList["bg","name"]="Begzar"
dnsList["rd",0]="10.202.10.10"; dnsList["rd",1]="10.202.10.11"; dnsList["rd","name"]="Radar"
dnsList["el",0]="78.157.42.100"; dnsList["el",1]="78.157.42.101"; dnsList["el","name"]="Electro"

# Parse the arguments
if [[ $1 == "-s" || $1 == "--set" ]]; then
    # Check if exactly two IP addresses are provided
    if [[ $# -ne 3 ]]; then
        usage
    fi
    # Set the nameservers based on provided IP addresses
    nameservers=("nameserver $2" "nameserver $3")
elif [[ $1 == "-r" || $1 == "--restore" ]]; then
    cp /etc/resolv.conf.bak /etc/resolv.conf # Restors the backup.
    echo "Restored the resolv.conf to what it was before the dnsch."
    exit 0
elif [[ $1 == "-p" || $1 == "--ping" ]]; then
    # Declare an array to hold each dns (bash is stupid).
    echo "this command may take a few minutes please wait ... "
    declare -a firstKeys=()

    for key in "${!dnsList[@]}"; do
        firstKey="${key%,*}" 
        if [[ ! " ${firstKeys[@]} " =~ " ${firstKey} " ]]; then
            firstKeys+=("$firstKey")
        fi
    done

    # Create an associative array to store the pings and addresses
    declare -A pings

    # Going through each dns and getting average ping for each address
    for dns in "${firstKeys[@]}"; do
        ping0=$(get_average_ping ${dnsList[$dns,0]})
        ping1=$(get_average_ping ${dnsList[$dns,1]})
        result=$(echo "scale=3; ($ping0 + $ping1) / 2" | bc)
        pings["$dns"]="$result"
    done

    # Sort the pings in ascending order
    sortedPings=$(sort -t = -nk 2 <<<"${!pings[@]}")

    # Print the sorted pings
    for ping in $sortedPings; do
        dns=${ping%%=*}
        ping=${pings[$dns]}
        echo "${dnsList[$dns,name]}: $ping ms"
    done
    exit 0
elif [[ $1 == "-c" || $1 == "--clear" ]]; then
    nameservers=()
else
    # Add the nameservers based on the previous list
    nameservers=("nameserver ${dnsList[$1,0]}" "nameserver ${dnsList[$1,1]}")
    # If the dns wasn't in the list, throw an error
    if [ "${nameservers[0]}" == "nameserver " ]; then
        echo "Invalid option: $1"
        usage
    fi
fi

# Remove all existing nameservers and add new ones atomically
# This avoids potential issues with an empty or partial file
{
    > /etc/resolv.conf.new
    for ns in "${nameservers[@]}"; do
        echo "$ns"
    done
} > /etc/resolv.conf.new

# Safely move the new file to the actual resolv.conf location
mv -f /etc/resolv.conf.new /etc/resolv.conf || { echo "Failed to update resolv.conf"; exit 1; }

# Confirm the changes
echo "The resolv.conf file has been updated:"
cat /etc/resolv.conf