Last active
November 8, 2023 14:13
-
-
Save smhdhsn/fe2c9f334e3d0db1f6102991ddc694a0 to your computer and use it in GitHub Desktop.
shecan.ir configurator.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /bin/bash -e | |
##################################################### | |
# DNS configurator # | |
##################################################### | |
# Responds to a list of syscall. | |
trap "error 'Exiting now...'" SIGINT SIGQUIT | |
# CLI options (IRREPLACEABLE). | |
readonly bold=`tput bold` | |
readonly reset=`tput sgr0` | |
readonly red=`tput setaf 1` | |
readonly blue=`tput setaf 4` | |
readonly cyan=`tput setaf 6` | |
readonly grey=`tput setaf 8` | |
# Prints out a given message. | |
# NOTE: the second param determines if the message should be postfixed with (\r|\n). | |
function out { | |
if [[ $2 ]]; then | |
echo -ne "${1}\r" | |
else | |
echo -ne "${1}\n" | |
fi | |
} | |
# Modifies a success message. | |
# NOTE: prints out the message to /dev/stdout | |
# NOTE: second parameter determines if the message should be prefixed | |
function success { | |
local prefix='[+] ' | |
if [[ $2 ]]; then | |
msg="${cyan}${bold}${prefix}${reset}${blue}${1}${reset}" | |
else | |
msg="${blue}${1}${reset}" | |
fi | |
out "$msg" $3 >> /dev/stdout | |
} | |
# Modifies an info message. | |
# NOTE: prints out the message to /dev/stdout | |
# NOTE: second parameter determines if the message should be prefixed | |
function info { | |
local prefix='[*] ' | |
if [[ $2 ]]; then | |
msg="${cyan}${bold}${prefix}${reset}${grey}${1}${reset}" | |
else | |
msg="${grey}${1}${reset}" | |
fi | |
out "$msg" $3 >> /dev/stdout | |
} | |
# Modifies an error message. | |
# NOTE: prints out the message to /dev/stderr | |
# NOTE: second parameter determines if the message should be prefixed | |
function error { | |
local prefix='[-] ' | |
if [[ $2 ]]; then | |
msg="${cyan}${bold}${prefix}${reset}${red}${1}${reset}" | |
else | |
msg="${red}${1}${reset}" | |
fi | |
out "$msg" $3 >> /dev/stderr \ | |
&& exit 1 | |
} | |
# Prints out the usage guide of this script. | |
function usage { | |
echo -e "Usage: $0 OPTION ARGUMENT [OPTION ARGUMENT]... | |
-a\tRead configurations from specified address. | |
-f\tChoose file to extract configurations from. | |
-i\tSpecify hook to extract configurations with. | |
-m\tChange application flow. [${FLOW_ADD}, ${FLOW_REMOVE}, ${FLOW_UPDATE}, ${FLOW_STATUS}]" >> /dev/stdout | |
} | |
# Makes print functions irreplaceable. | |
readonly -f usage success error info out | |
# RegEx pattern for validating IPv4. (IRREPLACEABLE) | |
readonly ipRegEx="((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])" | |
# Default path to DNS configurations. | |
readonly configFilePath="/etc/resolv.conf" | |
# DNS configurator's identifier. (IRREPLACEABLE) | |
readonly appFlag='#DNS_CONFIGURATOR' | |
# Key for configuring a DNS. | |
readonly configKey="nameserver" | |
# This section holds keys of application's flow. | |
# status: Checks if any configurations are already applied by this script. | |
# update: Removes old configurations and adds new configurations. | |
# remove: Removes old configurations. | |
# add: Adds new configurations. | |
readonly FLOW_STATUS="status" | |
readonly FLOW_UPDATE="update" | |
readonly FLOW_REMOVE="remove" | |
readonly FLOW_ADD="add" | |
# This section holds keys of application's source of configurations. | |
# file: Reads configurations from file. | |
# url: Extracts configurations from url. | |
readonly SOURCE_FILE="file" | |
readonly SOURCE_URL="url" | |
# Default url to get DNS configurations from. | |
url='https://shecan.ir' | |
# Default hook for catching DNS configurations. | |
hook='shecan-dns-ips' | |
# Default application's source form extracting configurations. | |
configSource=$SOURCE_URL | |
# Default application flow. | |
flow=$FLOW_ADD | |
# Gets the program's source of configurations based on input. | |
function getSource { | |
configSource=$2 | |
if [[ $configSource == $SOURCE_FILE ]]; then | |
configFile=$1 | |
elif [[ $configSource == $SOURCE_URL ]]; then | |
url=$1 | |
fi | |
} | |
# Gets the program's flow based on input. | |
function getFlow { | |
if grep -qE "\b(${FLOW_ADD}|${FLOW_REMOVE}|${FLOW_UPDATE}|${FLOW_STATUS})\b" <<< $1; then | |
flow=$1 | |
else | |
usage; exit 1 | |
fi | |
} | |
# Writes given addresses to the local DNS configuration file. | |
function write { | |
for address in $@; do | |
if ! grep -Exq "${configKey}\s+${address}\s+${appFlag}$" $configFilePath; then | |
sudo sed -i "$(grep -n "${configKey}" ${configFilePath} | cut -f 1 -d ':' | head -n 1)i\\${configKey} ${address} \\t${appFlag}" $configFilePath | |
fi | |
done | |
} | |
# Removes old DNS configurations from local DNS configuration file. (Identifies old configurations with app flag) | |
function remove { | |
sudo sed -i "/${appFlag}$/d" $configFilePath | |
} | |
# Makes managing functions irreplaceable. | |
readonly -f getSource getFlow write remove | |
# Gets arguments from input. | |
while getopts "a:f:i:m:h" arg; do | |
case $arg in | |
a ) | |
getSource $OPTARG $SOURCE_URL | |
;; | |
f ) | |
getSource $OPTARG $SOURCE_FILE | |
;; | |
i ) | |
hook=$OPTARG | |
;; | |
m ) | |
getFlow $OPTARG | |
;; | |
h ) | |
usage; exit | |
;; | |
* ) | |
usage; exit 1 | |
;; | |
esac | |
done | |
# Checks if the chosen flow requires removing old configurations. | |
if [[ $flow == $FLOW_UPDATE || $flow == $FLOW_REMOVE ]]; then | |
{ # This section removes old configurations from local DNS configuration file. | |
remove \ | |
&& success "Old configurations have been removed." true | |
} || { | |
error "Error on removing old configuration files." true | |
} | |
# If the flow is 'off' the application needs to be terminated. | |
if [[ $flow == $FLOW_REMOVE ]]; then | |
info "All configurations has been removed."; exit | |
fi | |
elif [[ $flow == $FLOW_STATUS ]]; then | |
if grep -Fq "${appFlag}" "${configFilePath}"; then | |
info "Configurations are ${blue}active${reset}."; exit | |
else | |
info "Configurations are ${red}inactive${reset}."; exit | |
fi | |
fi | |
# This section is responsible for chosing the source of configurations [URL, FILE]. | |
if [[ $configSource == $SOURCE_FILE ]]; then | |
{ # This section fetches payload from FILE. | |
info "Reading file..." true true \ | |
&& payload=$(cat $configFile) \ | |
&& success "File has been read." true | |
} || { | |
error "Error on reading file." true | |
} | |
elif [[ $configSource == $SOURCE_URL ]]; then | |
{ # This section fetches payload from URL. | |
info "Fetching payload..." true true \ | |
&& payload=$(curl -sX GET ${url} | grep ${hook}) \ | |
&& success "Payload has been fetched." true | |
} || { | |
error "Error on fetching payload." true | |
} | |
fi | |
{ # This section extracts DNS configurations from payload. | |
info "Extracting configurations..." true true \ | |
&& addresses=$(grep -oE ${ipRegEx} <<< ${payload}) \ | |
&& success "Configurations have been extracted." true | |
} || { | |
error "Error on extracting configurations." true | |
} | |
{ # This section writes new configurations to the local DNS configuration file. | |
write $addresses \ | |
&& success "Local DNS configuration file has been updated." true | |
} || { | |
error "Error on editing local DNS configuration file." true | |
} | |
info "Enjoy your freedom :)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment