#!/bin/sh
# TAILMON (TAILMON.SH) is an all-in-one script that is optimized to install, maintain and monitor a Tailscale service and
# connection from your Asus-Merlin FW router. It provides the basic steps needed to install and implement a successful
# connection to your tailnet. It allows for 2 different modes of operation: Kernel and Userspace modes. Depending on your
# needs, you can also enable exit node and subnet route advertisements. Separately, TAILMON functions as a Tailscale
# monitor application that will sit in the background (using the -screen utility), and will restart the Tailscale service
# should it happen to go down. Many thanks to: @jksmurf, @ColinTaylor, @Aiadi, and @kuki68ster for all their help, input
# and testing of this script!
#Preferred standard router binaries path
export PATH="/sbin:/bin:/usr/sbin:/usr/bin:$PATH"
#Static Variables - please do not change
version="1.0.19"
beta=0
apppath="/jffs/scripts/tailmon.sh" # Static path to the app
config="/jffs/addons/tailmon.d/tailmon.cfg" # Static path to the config file
dlverpath="/jffs/addons/tailmon.d/version.txt" # Static path to the version file
logfile="/jffs/addons/tailmon.d/tailmon.log" # Static path to the log
routerboot=0
tsinstalled=0
keepalive=0
timerloop=60
logsize=2000
autostart=0
amtmemailsuccess=0
amtmemailfailure=0
exitnode=0
advroutes=1
accroutes=0
persistentsettings=0
tsoperatingmode="Userspace"
precmd=""
args="--tun=userspace-networking --state=/opt/var/tailscaled.state --statedir=/opt/var/lib/tailscale"
preargs="nohup"
routes="$(nvram get lan_ipaddr | cut -d"." -f1-3).0/24"
customcmdline=""
#AMTM Email Notification Variables
readonly scriptFileName="${0##*/}"
readonly scriptFileNTag="${scriptFileName%.*}"
readonly CEM_LIB_TAG="master"
readonly CEM_LIB_URL="https://raw.githubusercontent.com/Martinski4GitHub/CustomMiscUtils/${CEM_LIB_TAG}/EMail"
readonly CUSTOM_EMAIL_LIBDir="/jffs/addons/shared-libs"
readonly CUSTOM_EMAIL_LIBName="CustomEMailFunctions.lib.sh"
readonly CUSTOM_EMAIL_LIBFile="${CUSTOM_EMAIL_LIBDir}/$CUSTOM_EMAIL_LIBName"
# Color variables
CBlack="\e[1;30m"
InvBlack="\e[1;40m"
CRed="\e[1;31m"
InvRed="\e[1;41m"
CGreen="\e[1;32m"
InvGreen="\e[1;42m"
CDkGray="\e[1;90m"
InvDkGray="\e[1;100m"
InvLtGray="\e[1;47m"
CYellow="\e[1;33m"
InvYellow="\e[1;43m"
CBlue="\e[1;34m"
InvBlue="\e[1;44m"
CMagenta="\e[1;35m"
CCyan="\e[1;36m"
InvCyan="\e[1;46m"
CWhite="\e[1;37m"
InvWhite="\e[1;107m"
CClear="\e[0m"
# -------------------------------------------------------------------------------------------------------------------------
# FUNCTIONS BEGIN
# -------------------------------------------------------------------------------------------------------------------------
# -------------------------------------------------------------------------------------------------------------------------
# LogoNM is a function that displays the BACKUPMON script name in a cool ASCII font without menu options
logoNM ()
{
clear
echo ""
echo ""
echo ""
echo -e "${CDkGray} _________ ______ __ _______ _ __"
echo -e " /_ __/ | / _/ / / |/ / __ \/ | / /"
echo -e " / / / /| | / // / / /|_/ / / / / |/ /"
echo -e " / / / ___ |_/ // /___/ / / / /_/ / /| /"
echo -e " /_/ /_/ |_/___/_____/_/ /_/\____/_/ |_/ v$version"
echo ""
echo ""
printf "\r ${CGreen} [ INITIALIZING ] ${CClear}"
sleep 1
clear
echo ""
echo ""
echo ""
echo -e "${CYellow} _________ ______ __ _______ _ __"
echo -e " /_ __/ | / _/ / / |/ / __ \/ | / /"
echo -e " / / / /| | / // / / /|_/ / / / / |/ /"
echo -e " / / / ___ |_/ // /___/ / / / /_/ / /| /"
echo -e " /_/ /_/ |_/___/_____/_/ /_/\____/_/ |_/ v$version"
echo ""
echo ""
printf "\r ${CGreen}[ INITIALIZING ... DONE ]${CClear}"
sleep 1
printf "\r ${CGreen} [ LOADING... ] ${CClear}"
sleep 1
}
logoNMexit ()
{
clear
echo ""
echo ""
echo ""
echo -e "${CYellow} _________ ______ __ _______ _ __"
echo -e " /_ __/ | / _/ / / |/ / __ \/ | / /"
echo -e " / / / /| | / // / / /|_/ / / / / |/ /"
echo -e " / / / ___ |_/ // /___/ / / / /_/ / /| /"
echo -e " /_/ /_/ |_/___/_____/_/ /_/\____/_/ |_/ v$version"
echo ""
echo ""
printf "\r ${CGreen} [ SHUTTING DOWN ] ${CClear}"
sleep 1
clear
echo ""
echo ""
echo ""
echo -e "${CDkGray} _________ ______ __ _______ _ __"
echo -e " /_ __/ | / _/ / / |/ / __ \/ | / /"
echo -e " / / / /| | / // / / /|_/ / / / / |/ /"
echo -e " / / / ___ |_/ // /___/ / / / /_/ / /| /"
echo -e " /_/ /_/ |_/___/_____/_/ /_/\____/_/ |_/ v$version"
echo ""
echo ""
printf "\r ${CGreen} [ SHUTTING DOWN ] ${CClear}"
sleep 1
printf "\r ${CDkGray} [ GOODBYE... ] ${CClear}\n\n"
sleep 1
}
# -------------------------------------------------------------------------------------------------------------------------
# Promptyn is a simple function that accepts y/n input
promptyn()
{ # No defaults, just y or n
while true; do
read -p "$1" -n 1 -r yn
case "${yn}" in
[Yy]* ) return 0 ;;
[Nn]* ) return 1 ;;
* ) echo -e "\nPlease answer y or n.";;
esac
done
}
# -------------------------------------------------------------------------------------------------------------------------
# Spinner is a script that provides a small indicator on the screen to show script activity
spinner()
{
spins=$1
spin=0
totalspins=$((spins / 4))
while [ $spin -le $totalspins ]; do
for spinchar in / - \\ \|; do
printf "\r$spinchar"
sleep 1
done
spin=$((spin+1))
done
printf "\r"
}
# -------------------------------------------------------------------------------------------------------------------------
# Preparebar and Progressbar is a script that provides a nice progressbar to show script activity
preparebar()
{
barlen=$1
barspaces=$(printf "%*s" "$1")
barchars=$(printf "%*s" "$1" | tr ' ' "$2")
}
progressbaroverride()
{
insertspc=" "
bypasswancheck=0
if [ $1 -eq -1 ]; then
printf "\r $barspaces\r"
else
if [ ! -z $7 ] && [ $1 -ge $7 ]; then
barch=$(($7*barlen/$2))
barsp=$((barlen-barch))
progr=$((100*$1/$2))
else
barch=$(($1*barlen/$2))
barsp=$((barlen-barch))
progr=$((100*$1/$2))
fi
if [ ! -z $6 ]; then AltNum=$6; else AltNum=$1; fi
if [ "$5" == "Standard" ]; then
printf " ${CWhite}${InvDkGray}$AltNum${4} / ${progr}%%${CClear} [${CGreen}e${CClear}=Exit] [Selection? ${InvGreen} ${CClear}${CGreen}]\r${CClear}" "$barchars" "$barspaces"
fi
fi
# Borrowed this wonderful keypress capturing mechanism from @Eibgrad... thank you! :)
key_press=''; read -rsn1 -t 1 key_press < "$(tty 0>&2)"
if [ $key_press ]; then
case $key_press in
[Aa]) vconfig;;
[Cc]) vsetup;;
[Dd]) tsdown;;
[Ee]) logoNMexit; echo -e "${CClear}\n"; exit 0;;
[Kk]) vconfig;;
[Ll]) vlogs;;
[Mm]) timerloopconfig;;
[Oo]) if [ "$tsoperatingmode" == "Custom" ]; then customconfig; fi;;
[Rr]) restarttsc;;
[Ss]) startts;;
[Tt]) stopts;;
[Uu]) tsup;;
*) timer=$timerloop;;
esac
fi
}
# -------------------------------------------------------------------------------------------------------------------------
# Initial setup menu
initialsetup()
{
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} TAILMON Initial Setup ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} TAILMON has not been configured yet, and Tailscale will need to be installed and${CClear}"
echo -e "${InvGreen} ${CClear} configured. You can choose between 'Express Install' and 'Advanced Install'.${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} 1) Express Install will automatically download and install Tailscale, choosing the${CClear}"
echo -e "${InvGreen} ${CClear} 'Userspace' mode of operation and configures it to advertise routes of your local${CClear}"
echo -e "${InvGreen} ${CClear} subnet by default. A URL prompt will appear which will require you to copy this link"
echo -e "${InvGreen} ${CClear} into your browser to connect this device to your tailnet."
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} 2) Advanced Install will launch the TAILMON Setup/Configuration Menu, and allows${CClear}"
echo -e "${InvGreen} ${CClear} you to manually choose your preferred settings, such as 'Kernel' vs. 'Userspace'${CClear}"
echo -e "${InvGreen} ${CClear} mode, and letting you pick the exit node option along with additional subnets."
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Before starting, please familiarize yourself with how Tailscale works. Please use${CClear}"
echo -e "${InvGreen} ${CClear} @ColinTaylor's Wiki available here:${CClear}"
echo -e "${InvGreen} ${CClear} https://github.com/RMerl/asuswrt-merlin.ng/wiki/Installing-Tailscale-through-Entware${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} It is also advised to have an account set and ready to go on https://tailscale.com${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
read -p "Please select? (1=Express Install, 2=Advanced Install, e=Exit): " SelectSetup
case $SelectSetup in
1)
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: TAILMON Express Install initiated." >> $logfile
expressinstall;;
2)
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: TAILMON Advanced Install initiated." >> $logfile
exec sh /jffs/scripts/tailmon.sh -setup;;
[Ee]) echo -e "${CClear}"; echo ""; exit 0;;
esac
}
# -------------------------------------------------------------------------------------------------------------------------
# Expressinstall script
expressinstall()
{
echo ""
echo -e "Ready to Express Install Tailscale?"
if promptyn "[y/n]: "
then
if [ -d "/opt" ]; then # Does entware exist? If yes proceed, if no error out.
echo ""
echo -e "\n${CGreen}Updating Entware Packages...${CClear}"
echo ""
opkg update
echo ""
echo -e "Installing Entware ${CGreen}CoreUtils-Timeout${CClear} Package...${CClear}"
echo ""
opkg install coreutils-timeout
echo ""
echo -e "Installing Entware ${CGreen}Screen${CClear} Package...${CClear}"
echo ""
opkg install screen
echo ""
echo -e "${CGreen}Installing Tailscale Package(s)...${CClear}"
echo ""
archker=$(opkg print-architecture | grep "armv7-2.6")
if [ -z "$archker" ]; then
opkg install tailscale
else
opkg install tailscale_nohf #install special tailscale package for arm7 kernel 2.6
fi
echo ""
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Entware package installed." >> $logfile
else
clear
echo -e "${CRed}ERROR: Entware was not found on this router...${CClear}"
echo -e "Please install Entware using the AMTM utility before proceeding..."
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - ERROR: Entware was not found installed on router. Please investigate." >> $logfile
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
exit 1
fi
else
echo ""
echo -e "${CClear}"
exit 0
fi
echo ""
echo -e "${CGreen}Applying settings for Userspace mode of operation...${CClear}"
tsoperatingmode="Userspace"
precmd=""
args="--tun=userspace-networking --state=/opt/var/tailscaled.state --statedir=/opt/var/lib/tailscale"
preargs="nohup"
saveconfig
echo ""
echo -e "${CGreen}Applying settings to Tailscale service and connection...${CClear}"
if [ -f "/opt/bin/tailscale" ]; then
#make mods to the S06tailscaled service for Userspace mode
if [ "$tsoperatingmode" == "Userspace" ]; then
sed -i "s/^ARGS=.*/ARGS=\"--tun=userspace-networking\ --state=\/opt\/var\/tailscaled.state\ --statedir=\/opt\/var\/lib\/tailscale\"/" "/opt/etc/init.d/S06tailscaled"
sed -i "s/^PREARGS=.*/PREARGS=\"nohup\"/" "/opt/etc/init.d/S06tailscaled"
sed -i -e '/^PRECMD=/d' "/opt/etc/init.d/S06tailscaled"
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Userspace Mode settings have been applied." >> $logfile
#remove firewall-start entry if found
if [ -f /jffs/scripts/firewall-start ]; then
if grep -q -F "if [ -x /opt/bin/tailscale ]; then tailscale down; tailscale up; fi" /jffs/scripts/firewall-start; then
sed -i -e '/tailscale down/d' /jffs/scripts/firewall-start
fi
fi
fi
else
echo ""
echo -e "${CRed}ERROR: Tailscale binary was not found. Please check Entware and router/drive for errors.${CClear}"
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - ERROR: Tailscale binaries not found on router. Please investigate." >> $logfile
exit 1
fi
echo ""
echo -e "${CGreen}Starting Tailscale service...${CClear}"
echo ""
/opt/etc/init.d/S06tailscaled start
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Service started." >> $logfile
echo ""
echo ""
echo -e "${CGreen}Starting Tailscale connection...${CClear}"
echo ""
echo -e "${CGreen}Please be prepared to copy and paste the link below into your browser, and connect this device"
echo -e "to your tailnet (Tailscale Network)${CClear}"
echo ""
advroutescmd="--advertise-routes=$routes"
echo -e "${CGreen}Executing: tailscale up $advroutescmd${CClear}"
echo ""
tailscale up $advroutescmd
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Connection started." >> $logfile
echo ""
echo ""
echo -e "${CGreen}Express Install Completed Successfully!${CClear}"
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
exec sh /jffs/scripts/tailmon.sh -noswitch
echo -e "${CClear}"
exit 0
}
# -------------------------------------------------------------------------------------------------------------------------
# Install script
installts()
{
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Install Tailscale ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} This installer will download and install Tailscale from the Entware respository."
echo -e "${InvGreen} ${CClear} It will also check for any prerequisites before install commences."
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
echo -e "Install Tailscale?"
if promptyn "[y/n]: "
then
if [ -d "/opt" ]; then # Does entware exist? If yes proceed, if no error out.
echo ""
echo -e "\n${CGreen}Updating Entware Packages...${CClear}"
echo ""
opkg update
echo ""
echo -e "${CGreen}Installing Tailscale Package(s)...${CClear}"
echo ""
archker=$(opkg print-architecture | grep "armv7-2.6")
if [ -z "$archker" ]; then
opkg install tailscale
else
opkg install tailscale_nohf #install special tailscale package for arm7 kernel 2.6
fi
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Entware package installed." >> $logfile
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
else
clear
echo -e "${CRed}ERROR: Entware was not found on this router...${CClear}"
echo -e "Please install Entware using the AMTM utility before proceeding..."
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - ERROR: Entware was not found on router. Please investigate." >> $logfile
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
exit 1
fi
fi
resettimer=1
}
# -------------------------------------------------------------------------------------------------------------------------
# Uninstall script
uninstallts()
{
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Uninstall Tailscale ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} This uninstaller utility will remove Tailscale Entware packages from your router"
echo -e "${InvGreen} ${CClear} along with all files and modifications made to Tailscale."
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
echo -e "Uninstall Tailscale?"
if promptyn "[y/n]: "
then
if [ -f /opt/bin/tailscale ]; then
if [ -d "/opt" ]; then # Does entware exist? If yes proceed, if no error out.
echo ""
echo -e "\n${CGreen}Shutting down Tailscale...${CClear}"
tailscale logout
tailscale down
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Connection shut down and logged out." >> $logfile
/opt/etc/init.d/S06tailscaled stop
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Service shut down." >> $logfile
echo ""
echo -e "\n${CGreen}Removing firewall-start entries...${CClear}"
#remove firewall-start entry if found
if [ -f /jffs/scripts/firewall-start ]; then
if grep -q -F "if [ -x /opt/bin/tailscale ]; then tailscale down; tailscale up; fi" /jffs/scripts/firewall-start; then
sed -i -e '/tailscale down/d' /jffs/scripts/firewall-start
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: firewall-start entries removed." >> $logfile
fi
fi
echo ""
echo -e "\n${CGreen}Updating Entware Packages...${CClear}"
echo ""
opkg update
echo ""
echo -e "${CGreen}Uninstalling Entware Tailscale Package(s)...${CClear}"
echo ""
archker=$(opkg print-architecture | grep "armv7-2.6")
if [ -z "$archker" ]; then
opkg remove tailscale
else
opkg remove tailscale_nohf #remove special tailscale package for arm7 kernel 2.6
fi
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Entware package removed." >> $logfile
# Removed the various folders tailscale could hide
rm -f /opt/var/tailscaled.state >/dev/null 2>&1
rm -r /opt/var/lib/tailscale >/dev/null 2>&1
rm -r /opt/var/run/tailscale >/dev/null 2>&1
rm -r /var/run/tailscale >/dev/null 2>&1
rm -r /var/lib/tailscale >/dev/null 2>&1
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale files and folders removed." >> $logfile
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
else
clear
echo -e "${CRed}ERROR: Entware was not found on this router...${CClear}"
echo -e "Please install Entware using the AMTM utility before proceeding..."
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - ERROR: Entware not found on router. Please investigate." >> $logfile
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
exit 1
fi
else
echo ""
echo -e "\n${CGreen}Tailscale was not found installed on this router.${CClear}"
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
fi
fi
resettimer=1
}
# -------------------------------------------------------------------------------------------------------------------------
# start service script
startts()
{
printf "\33[2K\r"
printf "${CGreen}\r[Starting Tailscale Service]"
sleep 1
printf "\33[2K\r"
echo -e "${CGreen}Messages:"
echo ""
/opt/etc/init.d/S06tailscaled start
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Service started." >> $logfile
echo ""
resettimer=1
}
# -------------------------------------------------------------------------------------------------------------------------
# stop service script
stopts()
{
printf "\33[2K\r"
printf "${CGreen}\r[Stopping Tailscale Service]"
sleep 1
printf "\33[2K\r"
echo -e "${CGreen}Messages:"
echo ""
/opt/etc/init.d/S06tailscaled stop
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Service stopped." >> $logfile
echo ""
resettimer=1
}
# -------------------------------------------------------------------------------------------------------------------------
# restart service and connection
restarttsc()
{
printf "\33[2K\r"
printf "${CGreen}\r[Restarting Tailscale Service/Connection]${CClear}"
sleep 1
tsdown
stopts
#make mods to the S06tailscaled service for Userspace mode
if [ "$tsoperatingmode" == "Userspace" ]; then
applyuserspacemode
#make mods to the S06tailscaled service for Kernel mode
elif [ "$tsoperatingmode" == "Kernel" ]; then
applykernelmode
#make mods to the S06tailscaled service for Custom mode
elif [ "$tsoperatingmode" == "Custom" ]; then
applycustomchanges
fi
startts
tsup
echo ""
printf "\33[2K\r"
printf "${CGreen}\r[Tailscale Service/Connection Successfully Restarted]${CClear}"
echo -e "\n"
read -rsp $'Press any key to continue...\n' -n1 key
}
# -------------------------------------------------------------------------------------------------------------------------
# Tailscale reset connection routine
tsreset()
{
printf "\33[2K\r"
printf "${CGreen}\r[Initiating Forced Tailscale Connection Reset]"
sleep 1
echo -e "\n"
echo -e "${CRed}WARNING:${CClear} Executing this function will send a 'tailscale up --reset' command which "
echo -e "will reset any default switches that are configured on your Tailscale connection. "
echo -e "This action may be necessary at times when these switches are inadvertently set and "
echo -e "registered with Tailscale, or due to switch functionality being altered or changed "
echo -e "by the Tailscale developers themselves. Once the '--reset' switch has been sent, "
echo -e "TAILMON will reinitialize the connection back to its regular defaults."
echo ""
echo -e "${CRed}PLEASE NOTE:${CClear} If you have configured any custom commandline switches that you want "
echo -e "to reset, you would need to run your own custom Tailscale command in a separate "
echo -e "prompt to disable the switch that is currently enabled. Please know that the switch "
echo -e "itself is not removed, but basically disabled. Please consider finding more info at "
echo -e "the https://tailscale.com/kb site for other references. Examples: "
echo -e "${CGreen}tailscale up --accept-routes=false${CClear} -or-"
echo -e "${CGreen}tailscale up --advertise-routes=${CClear}"
echo ""
echo -e "Reset Tailscale Connection?"
if promptyn "[y/n]: "
then
echo -e "\n"
tsdown
echo "Executing: tailscale up --reset"
echo ""
tailscale up --reset
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Connection Reset using --reset switch." >> $logfile
echo ""
tsdown
tsup
echo ""
printf "\33[2K\r"
printf "${CGreen}\r[Tailscale Connection Successfully Reset]${CClear}"
echo -e "\n"
read -rsp $'Press any key to continue...\n' -n1 key
fi
}
# -------------------------------------------------------------------------------------------------------------------------
# Tailscale connection reset
tsresetc()
{
printf "\33[2K\r"
printf "${CGreen}\r[Resetting Tailscale Connection]"
sleep 1
printf "\33[2K\r"
echo -e "${CGreen}Messages:${CClear}"
echo ""
echo "Executing: tailscale up --reset"
echo ""
tailscale up --reset
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Connection Reset using --reset switch." >> $logfile
resettimer=1
echo -e "\n"
read -rsp $'Press any key to continue...\n' -n1 key
}
# -------------------------------------------------------------------------------------------------------------------------
# Tailscale connection up
tsup()
{
printf "\33[2K\r"
printf "${CGreen}\r[Activating Tailscale Connection]"
sleep 1
printf "\33[2K\r"
if [ $exitnode -eq 1 ]; then exitnodecmd="--advertise-exit-node "; else exitnodecmd=""; fi
if [ $advroutes -eq 1 ]; then advroutescmd="--advertise-routes=$routes "; else advroutescmd=""; fi
if [ $accroutes -eq 1 ]; then accroutescmd="--accept-routes"; else accroutescmd=""; fi
echo -e "${CGreen}Messages:${CClear}"
echo ""
if [ "$tsoperatingmode" == "Custom" ]; then
echo "Executing: tailscale up $customcmdline"
echo ""
tailscale up $customcmdline
else
echo "Executing: tailscale up $exitnodecmd$advroutescmd$accroutescmd"
echo ""
tailscale up $exitnodecmd$advroutescmd$accroutescmd
fi
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Connection started." >> $logfile
resettimer=1
}
# -------------------------------------------------------------------------------------------------------------------------
# Tailscale connection down
tsdown()
{
printf "\33[2K\r"
printf "${CGreen}\r[Bringing Tailscale Connection Down]"
sleep 1
printf "\33[2K\r"
echo -e "${CGreen}Messages:${CClear}"
echo ""
echo "Executing: tailscale down"
echo ""
tailscale down
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale Connection stopped." >> $logfile
resettimer=1
}
# -------------------------------------------------------------------------------------------------------------------------
# Force Tailscale Binary update
tsupdate()
{
printf "\33[2K\r"
printf "${CGreen}\r[Updating Tailscale Binary]"
sleep 1
printf "\33[2K\r"
echo -e "${CGreen}Messages:${CClear}"
echo ""
echo "Executing: tailscale update"
echo ""
tailscale update
echo ""
echo -e "Restart Tailscale?"
if promptyn "[y/n]: "
then
restarttsc
fi
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Tailscale binary updated to latest available version." >> $logfile
resettimer=1
}
# -------------------------------------------------------------------------------------------------------------------------
# autostart lets you enable the ability for tailmon to autostart after a router reboot
autostart()
{
while true; do
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Reboot Protection ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Please indicate below if you would like to enable TAILMON to autostart after a"
echo -e "${InvGreen} ${CClear} router reboot. This will ensure continued, uninterrupted Tailscale monitoring."
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} (Default = Disabled)"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo -e "${InvGreen} ${CClear}"
if [ "$autostart" == "0" ]; then
echo -e "${InvGreen} ${CClear} Current: ${CRed}Disabled${CClear}"
elif [ "$autostart" == "1" ]; then
echo -e "${InvGreen} ${CClear} Current: ${CGreen}Enabled${CClear}"
fi
echo ""
read -p 'Enable Reboot Protection? (0=No, 1=Yes, e=Exit): ' autostart1
if [ "$autostart1" == "" ] || [ -z "$autostart1" ]; then autostart=0; else autostart="$autostart1"; fi # Using default value on enter keypress
if [ "$autostart" == "0" ]; then
if [ -f /jffs/scripts/post-mount ]; then
sed -i -e '/tailmon.sh/d' /jffs/scripts/post-mount
autostart=0
echo ""
echo -e "${CGreen}[Modifying POST-MOUNT file]..."
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Reboot Protection Disabled" >> $logfile
saveconfig
sleep 1
timer=$timerloop
break
fi
elif [ "$autostart" == "1" ]; then
if [ -f /jffs/scripts/post-mount ]; then
if ! grep -q -F "(sleep 30 && /jffs/scripts/tailmon.sh -screen) & # Added by tailmon" /jffs/scripts/post-mount; then
echo "(sleep 30 && /jffs/scripts/tailmon.sh -screen) & # Added by tailmon" >> /jffs/scripts/post-mount
autostart=1
echo ""
echo -e "${CGreen}[Modifying POST-MOUNT file]..."
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Reboot Protection Enabled" >> $logfile
saveconfig
sleep 1
timer=$timerloop
break
else
autostart=1
saveconfig
sleep 1
fi
else
echo "#!/bin/sh" > /jffs/scripts/post-mount
echo "" >> /jffs/scripts/post-mount
echo "(sleep 30 && /jffs/scripts/tailmon.sh -screen) & # Added by tailmon" >> /jffs/scripts/post-mount
chmod 755 /jffs/scripts/post-mount
autostart=1
echo ""
echo -e "${CGreen}[Modifying POST-MOUNT file]..."
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Reboot Protection Enabled" >> $logfile
saveconfig
sleep 1
timer=$timerloop
break
fi
elif [ "$autostart" == "e" ]; then
timer=$timerloop
break
else
autostart=0
saveconfig
fi
done
}
# -------------------------------------------------------------------------------------------------------------------------
# timerloopconfig lets you configure how long you want the timer cycle to last between tailscale checks
timerloopconfig()
{
while true; do
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Timer Loop Configuration ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Please indicate how long the timer cycle should take between Tailscale Service and.${CClear}"
echo -e "${InvGreen} ${CClear} Connection checks."
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} (Default = 60 seconds)${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Current: ${CGreen}$timerloop sec${CClear}"
echo ""
read -p "Please enter value (1-999)? (e=Exit): " EnterTimerLoop
case $EnterTimerLoop in
[1-9])
timerloop=$EnterTimerLoop
saveconfig
timer=$timerloop
;;
[1-9][0-9])
timerloop=$EnterTimerLoop
saveconfig
timer=$timerloop
;;
[1-9][0-9][0-9])
timerloop=$EnterTimerLoop
saveconfig
timer=$timerloop
;;
*)
echo ""
echo -e "${CClear}[Exiting]"
timer=$timerloop
break
;;
esac
done
}
# -------------------------------------------------------------------------------------------------------------------------
# customconfig lets you edit the args and settings for tailscale
customconfig()
{
restartts=0
while true; do
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Custom Tailscale Configuration ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} This functionality allows you to choose your own Tailscale ARGS, PREARGS and PRECMD${CClear}"
echo -e "${InvGreen} ${CClear} entries, and allows you to modify the Tailscale connection commandline options.${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} ${CYellow}Proceed at your own risk!${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Current Operating Mode: ${CGreen}$tsoperatingmode${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Current values in Tailscale Service (/opt/etc/init.d/S06tailscaled):${CClear}"
s06args=$(cat /opt/etc/init.d/S06tailscaled | grep ^ARGS= | cut -d '=' -f 2-) 2>/dev/null
if [ -z "$s06args" ]; then
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(1)${CClear} ${CGreen}ARGS=\"\"${CClear}"
else
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(1)${CClear} ${CGreen}ARGS=$s06args${CClear}"
fi
s06preargs=$(cat /opt/etc/init.d/S06tailscaled | grep ^PREARGS= | cut -d '=' -f 2-) 2>/dev/null
if [ -z "$s06preargs" ]; then
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(2)${CClear} ${CGreen}PREARGS=\"\"${CClear}"
else
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(2)${CClear} ${CGreen}PREARGS=$s06preargs${CClear}"
fi
s06precmd=$(cat /opt/etc/init.d/S06tailscaled | grep ^PRECMD= | cut -d '=' -f 2-) 2>/dev/null
if [ -z "$s06precmd" ]; then
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(3)${CClear} ${CGreen}PRECMD=\"\"${CClear}"
else
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(3)${CClear} ${CGreen}PRECMD=$s06precmd${CClear}"
fi
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Current custom values being used for Tailscale Connection commandline:${CClear}"
if [ -z "$customcmdline" ]; then
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(4)${CClear} ${CGreen}CMD=\"\"${CClear}"
else
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(4)${CClear} ${CGreen}CMD=\"$customcmdline\"${CClear}"
fi
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
read -p "Please enter item to modify (1-4)? (e=Exit): " EnterTimerLoop
case $EnterTimerLoop in
1)
echo ""
echo -e "${CClear}When entering a custom statement, please do not use quotes or other abnormal characters."
echo -e "${CClear}Example: --tun=userspace-networking --state=/opt/var/tailscaled.state --statedir=/opt/var/lib/tailscale"
echo ""
read -p "Enter new ARGS= " EnterNewArgs
tsoperatingmode="Custom"
args=$EnterNewArgs
args_regexp="$(printf '%s' "$args" | sed -e 's/[]\/$*.^|[]/\\&/g' | sed ':a;N;$!ba;s,\n,\\n,g')"
sed -i "s/^ARGS=.*/ARGS=\"$args_regexp\"/" "/opt/etc/init.d/S06tailscaled"
saveconfig
timer=$timerloop
restartts=1
;;
2)
echo ""
echo -e "${CClear}When entering a custom statement, please do not use quotes or other abnormal characters."
echo -e "${CClear}Example: nohup"
echo ""
read -p "Enter new PREARGS= " EnterNewPreArgs
tsoperatingmode="Custom"
preargs=$EnterNewPreArgs
preargs_regexp="$(printf '%s' "$preargs" | sed -e 's/[]\/$*.^|[]/\\&/g' | sed ':a;N;$!ba;s,\n,\\n,g')"
sed -i "s/^PREARGS=.*/PREARGS=\"$preargs_regexp\"/" "/opt/etc/init.d/S06tailscaled"
saveconfig
timer=$timerloop
restartts=1
;;
3)
echo ""
echo -e "${CClear}When entering a custom statement, please do not use quotes or other abnormal characters."
echo -e "${CClear}Example: modprobe tun"
echo ""
read -p "Enter new PRECMD= " EnterNewPreCmd
tsoperatingmode="Custom"
precmd=$EnterNewPreCmd
precmd_regexp="$(printf '%s' "$precmd" | sed -e 's/[]\/$*.^|[]/\\&/g' | sed ':a;N;$!ba;s,\n,\\n,g')"
if ! grep -q -F "PRECMD=" /opt/etc/init.d/S06tailscaled; then
sed '5 i PRECMD=\"'"$precmd_regexp"'\"' /opt/etc/init.d/S06tailscaled > /opt/etc/init.d/S06tailscaled2
rm -f /opt/etc/init.d/S06tailscaled
mv /opt/etc/init.d/S06tailscaled2 /opt/etc/init.d/S06tailscaled
chmod 755 /opt/etc/init.d/S06tailscaled
else
sed -i "s/^PRECMD=.*/PRECMD=\"$precmd_regexp\"/" "/opt/etc/init.d/S06tailscaled"
fi
saveconfig
timer=$timerloop
restartts=1
;;
4)
echo ""
echo -e "${CClear}When entering a custom statement, please do not use quotes or other abnormal characters."
echo -e "${CClear}Example: --advertise-exit-node --advertise-routes=192.168.50.0/24,192.168.87.0/24"
echo ""
read -p "Enter new Commandline Options: " EnterNewCmdOptions
tsoperatingmode="Custom"
customcmdline=$EnterNewCmdOptions
saveconfig
timer=$timerloop
restartts=1
;;
*)
if [ -f "/opt/bin/tailscale" ]; then
if [ $restartts -eq 1 ]; then
echo ""
echo -e "Changing custom configuration options will require a restart of Tailscale. Restart now?"
if promptyn "[y/n]: "
then
echo ""
echo -e "\n${CGreen}Restarting Tailscale Service and Connection...${CClear}"
echo ""
tsdown
stopts
startts
tsup
fi
fi
fi
echo ""
echo -e "${CClear}[Exiting]"
timer=$timerloop
break
;;
esac
done
}
# -------------------------------------------------------------------------------------------------------------------------
# operating mode lets the user choose between userspace and kernel modes of operation
operatingmode()
{
restartts=0
while true; do
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Operating Mode Configuration ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Tailscale has 2 main modes of operation: 'Userspace' and 'Kernel' mode. By default,${CClear}"
echo -e "${InvGreen} ${CClear} the installer will configure Tailscale to operate in 'Userspace' mode, but in the${CClear}"
echo -e "${InvGreen} ${CClear} end, should not make much difference performance-wise based on the hardware available${CClear}"
echo -e "${InvGreen} ${CClear} in our routers. More info below:${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} In general, kernel mode (and thus only Linux, for now) should be used for heavily${CClear}"
echo -e "${InvGreen} ${CClear} used subnet routers, where 'heavy' is some combination of number of users, number${CClear}"
echo -e "${InvGreen} ${CClear} of flows, bandwidth. The userspace mode should be more than sufficient for smaller${CClear}"
echo -e "${InvGreen} ${CClear} numbers of users or low bandwidth. Even though Tailscale's userspace subnet routing${CClear}"
echo -e "${InvGreen} ${CClear} is not as optimized as the Linux kernel, it makes up for it slightly in being able${CClear}"
echo -e "${InvGreen} ${CClear} to avoid some context switches to the kernel.${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} A 3rd option (Custom) is also available, that allows you to enter your own custom${CClear}"
echo -e "${InvGreen} ${CClear} settings for the ARGS, PREARGS, PRECMD and Tailscale Commandline. ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear}${CYellow} NOTE: TAILMON will apply changes to modes after hitting the (e)xit key. If 'Custom'${CClear}"
echo -e "${InvGreen} ${CClear}${CYellow} operating mode is chosen, you will be presented with the option to edit custom${CClear}"
echo -e "${InvGreen} ${CClear}${CYellow} Tailscale settings after changes have been applied.${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} (Default = Userspace Mode)${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Current: ${CGreen}$tsoperatingmode${CClear}"
echo ""
read -p "Please enter value (1=Userspace, 2=Kernel, 3=Custom)? (e=Exit/Apply Changes): " EnterOperatingMode
case $EnterOperatingMode in
1)
if [ "$tsoperatingmode" != "Userspace" ]; then restartts=1; fi
echo -e "\n${CGreen}[Userspace Operating Mode Selected]"
sleep 1
tsoperatingmode="Userspace"
precmd=""
args="--tun=userspace-networking --state=/opt/var/tailscaled.state --statedir=/opt/var/lib/tailscale"
preargs="nohup"
customcmdline=""
saveconfig
timer=$timerloop
;;
2)
if [ "$tsoperatingmode" != "Kernel" ]; then restartts=1; fi
echo -e "\n${CGreen}[Kernel Operating Mode Selected]"
sleep 1
tsoperatingmode="Kernel"
precmd="modprobe tun"
args="--state=/opt/var/tailscaled.state --statedir=/opt/var/lib/tailscale"
preargs="nohup"
customcmdline=""
saveconfig
timer=$timerloop
;;
3)
if [ "$tsoperatingmode" != "Custom" ]; then restartts=1; fi
echo -e "\n${CGreen}[Custom Operating Mode Selected]"
sleep 1
tsoperatingmode="Custom"
precmd="modprobe tun"
args="--state=/opt/var/tailscaled.state --statedir=/opt/var/lib/tailscale"
preargs="nohup"
if [ $exitnode -eq 1 ]; then exitnodecmd="--advertise-exit-node "; else exitnodecmd=""; fi
if [ $advroutes -eq 1 ]; then advroutescmd="--advertise-routes=$routes"; else advroutescmd=""; fi
customcmdline="$exitnodecmd$advroutescmd"
saveconfig
timer=$timerloop
;;
*)
if [ -f "/opt/bin/tailscale" ]; then
if [ $restartts -eq 1 ]; then
echo ""
echo -e "Changing operating modes will require a restart of Tailscale. Restart now?"
if promptyn "[y/n]: "
then
echo ""
echo -e "\n${CGreen}Restarting Tailscale Service and Connection...${CClear}"
echo ""
tsdown
stopts
#make mods to the S06tailscaled service for Userspace mode
if [ "$tsoperatingmode" == "Userspace" ]; then
applyuserspacemode
#make mods to the S06tailscaled service for Kernel mode
elif [ "$tsoperatingmode" == "Kernel" ]; then
applykernelmode
#make mods to the S06tailscaled service for Custom mode
elif [ "$tsoperatingmode" == "Custom" ]; then
applycustommode
fi
startts
tsup
if [ "$tsoperatingmode" == "Custom" ]; then
echo ""
echo -e "Would you like to customize your Tailscale settings now?"
if promptyn "[y/n]: "
then
customconfig
fi
fi
fi
echo ""
echo -e "${CClear}[Exiting]"
timer=$timerloop
break
else
echo ""
echo -e "${CClear}[Exiting]"
timer=$timerloop
break
fi
fi
;;
esac
done
}
# -------------------------------------------------------------------------------------------------------------------------
# applyuserspacemode applies the standard settings for the Userspace operating mode
applyuserspacemode()
{
sed -i "s/^ARGS=.*/ARGS=\"--tun=userspace-networking\ --state=\/opt\/var\/tailscaled.state\ --statedir=\/opt\/var\/lib\/tailscale\"/" "/opt/etc/init.d/S06tailscaled"
sed -i "s/^PREARGS=.*/PREARGS=\"nohup\"/" "/opt/etc/init.d/S06tailscaled"
sed -i -e '/^PRECMD=/d' "/opt/etc/init.d/S06tailscaled"
#remove firewall-start entry if found
if [ -f /jffs/scripts/firewall-start ]; then
if grep -q -F "if [ -x /opt/bin/tailscale ]; then tailscale down; tailscale up; fi" /jffs/scripts/firewall-start; then
sed -i -e '/tailscale down/d' /jffs/scripts/firewall-start
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: firewall-start entries removed." >> $logfile
fi
fi
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Userspace Mode settings have been applied." >> $logfile
sendmessage 0 "Tailscale Operating Mode Userspace"
}
# -------------------------------------------------------------------------------------------------------------------------
# applykernelmode applies the standard settings for the Kernel operating mode
applykernelmode()
{
if ! grep -q -F "PRECMD=" /opt/etc/init.d/S06tailscaled; then
sed '5 i PRECMD=\"modprobe tun\"' /opt/etc/init.d/S06tailscaled > /opt/etc/init.d/S06tailscaled2
rm -f /opt/etc/init.d/S06tailscaled
mv /opt/etc/init.d/S06tailscaled2 /opt/etc/init.d/S06tailscaled
chmod 755 /opt/etc/init.d/S06tailscaled
else
sed -i "s/^PRECMD=.*/PRECMD=\"modprobe tun\"/" "/opt/etc/init.d/S06tailscaled"
fi
sed -i "s/^ARGS=.*/ARGS=\"--state=\/opt\/var\/tailscaled.state\ --statedir=\/opt\/var\/lib\/tailscale\"/" "/opt/etc/init.d/S06tailscaled"
sed -i "s/^PREARGS=.*/PREARGS=\"nohup\"/" "/opt/etc/init.d/S06tailscaled"
#modify/create firewall-start
if [ -f /jffs/scripts/firewall-start ]; then
if ! grep -q -F "if [ -x /opt/bin/tailscale ]; then tailscale down; tailscale up; fi" /jffs/scripts/firewall-start; then
echo "if [ -x /opt/bin/tailscale ]; then tailscale down; tailscale up; fi # Added by TAILMON" >> /jffs/scripts/firewall-start
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: firewall-start entries created." >> $logfile
fi
else
echo "#!/bin/sh" > /jffs/scripts/firewall-start
echo "" >> /jffs/scripts/firewall-start
echo "if [ -x /opt/bin/tailscale ]; then tailscale down; tailscale up; fi # Added by TAILMON" >> /jffs/scripts/firewall-start
chmod 0755 /jffs/scripts/firewall-start
fi
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Kernel Mode settings have been applied." >> $logfile
sendmessage 0 "Tailscale Operating Mode Kernel"
}
# -------------------------------------------------------------------------------------------------------------------------
# applycustommode applies the standard settings for the Custom operating mode which initially mimics Kernel mode
applycustommode()
{
if ! grep -q -F "PRECMD=" /opt/etc/init.d/S06tailscaled; then
sed '5 i PRECMD=\"modprobe tun\"' /opt/etc/init.d/S06tailscaled > /opt/etc/init.d/S06tailscaled2
rm -f /opt/etc/init.d/S06tailscaled
mv /opt/etc/init.d/S06tailscaled2 /opt/etc/init.d/S06tailscaled
chmod 755 /opt/etc/init.d/S06tailscaled
else
sed -i "s/^PRECMD=.*/PRECMD=\"modprobe tun\"/" "/opt/etc/init.d/S06tailscaled"
fi
sed -i "s/^ARGS=.*/ARGS=\"--state=\/opt\/var\/tailscaled.state\ --statedir=\/opt\/var\/lib\/tailscale\"/" "/opt/etc/init.d/S06tailscaled"
sed -i "s/^PREARGS=.*/PREARGS=\"nohup\"/" "/opt/etc/init.d/S06tailscaled"
#modify/create firewall-start
if [ -f /jffs/scripts/firewall-start ]; then
if ! grep -q -F "if [ -x /opt/bin/tailscale ]; then tailscale down; tailscale up; fi" /jffs/scripts/firewall-start; then
echo "if [ -x /opt/bin/tailscale ]; then tailscale down; tailscale up; fi # Added by TAILMON" >> /jffs/scripts/firewall-start
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: firewall-start entries created." >> $logfile
fi
else
echo "#!/bin/sh" > /jffs/scripts/firewall-start
echo "" >> /jffs/scripts/firewall-start
echo "if [ -x /opt/bin/tailscale ]; then tailscale down; tailscale up; fi # Added by TAILMON" >> /jffs/scripts/firewall-start
chmod 0755 /jffs/scripts/firewall-start
fi
if [ $exitnode -eq 1 ]; then exitnodecmd="--advertise-exit-node "; else exitnodecmd=""; fi
if [ $advroutes -eq 1 ]; then advroutescmd="--advertise-routes=$routes"; else advroutescmd=""; fi
customcmdline="$exitnodecmd$advroutescmd"
saveconfig
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Custom Mode settings have been applied." >> $logfile
sendmessage 0 "Tailscale Operating Mode Custom"
}
# -------------------------------------------------------------------------------------------------------------------------
# applycustomchanges applies the custom settings for the Custom operating mode that may have been changed by the user
applycustomchanges()
{
precmd_regexp="$(printf '%s' "$precmd" | sed -e 's/[]\/$*.^|[]/\\&/g' | sed ':a;N;$!ba;s,\n,\\n,g')"
if ! grep -q -F "PRECMD=" /opt/etc/init.d/S06tailscaled; then
sed '5 i PRECMD=\"'"$precmd_regexp"'\"' /opt/etc/init.d/S06tailscaled > /opt/etc/init.d/S06tailscaled2
rm -f /opt/etc/init.d/S06tailscaled
mv /opt/etc/init.d/S06tailscaled2 /opt/etc/init.d/S06tailscaled
chmod 755 /opt/etc/init.d/S06tailscaled
else
sed -i "s/^PRECMD=.*/PRECMD=\"$precmd_regexp\"/" "/opt/etc/init.d/S06tailscaled"
fi
args_regexp="$(printf '%s' "$args" | sed -e 's/[]\/$*.^|[]/\\&/g' | sed ':a;N;$!ba;s,\n,\\n,g')"
sed -i "s/^ARGS=.*/ARGS=\"$args_regexp\"/" "/opt/etc/init.d/S06tailscaled"
preargs_regexp="$(printf '%s' "$preargs" | sed -e 's/[]\/$*.^|[]/\\&/g' | sed ':a;N;$!ba;s,\n,\\n,g')"
sed -i "s/^PREARGS=.*/PREARGS=\"$preargs_regexp\"/" "/opt/etc/init.d/S06tailscaled"
saveconfig
timer=$timerloop
restartts=1
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Custom Mode changes have been applied." >> $logfile
sendmessage 0 "Tailscale Operating Mode Custom"
}
# -------------------------------------------------------------------------------------------------------------------------
# exitnodets provide a menu interface to allow for selection of router becoming an exitnode
exitnodets()
{
clear
if [ $exitnode -eq 0 ]; then exitnodedisp="No"; elif [ $exitnode -eq 1 ]; then exitnodedisp="Yes"; fi
echo -e "${InvGreen} ${InvDkGray}${CWhite} Configure Router as Exit Node ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} A Tailscale Exit Node is a feature that lets you route all non-Tailscale internet"
echo -e "${InvGreen} ${CClear} traffic through a specific device on your Tailscale network (known as a tailnet)."
echo -e "${InvGreen} ${CClear} The device routing your traffic (this router) is called an 'exit node'. Please"
echo -e "${InvGreen} ${CClear} indicate below if you want to enable this feature"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} (Default = No)"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Current: ${CGreen}$exitnodedisp${CClear}"
echo ""
echo -e "Configure Router as Exit Node?"
if promptyn "[y/n]: "
then
exitnode=1
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Device has been configured as Exit Node." >> $logfile
else
exitnode=0
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Exit Node configuration has been disabled." >> $logfile
fi
saveconfig
timer=$timerloop
if [ "$exitnodedisp" == "No" ] && [ $exitnode -eq 1 ]; then
echo ""
echo -e "\nChanging exit node configuration options will require a restart of Tailscale. Restart now?"
if promptyn "[y/n]: "
then
echo ""
echo -e "\n${CGreen}Restarting Tailscale Service and Connection...${CClear}"
echo ""
tsdown
stopts
startts
tsup
fi
fi
if [ "$exitnodedisp" == "Yes" ] && [ $exitnode -eq 0 ]; then
echo ""
echo -e "\nChanging exit node configuration options will require a restart of Tailscale. Restart now?"
if promptyn "[y/n]: "
then
echo ""
echo -e "\n${CGreen}Restarting Tailscale Service and Connection...${CClear}"
echo ""
tsdown
stopts
startts
tsup
fi
fi
}
# -------------------------------------------------------------------------------------------------------------------------
# advroutests provide a menu interface to allow for entry of advertised routes
advroutests()
{
clear
if [ $advroutes -eq 0 ]; then advroutesdisp="No"; elif [ $advroutes -eq 1 ]; then advroutesdisp="Yes"; fi
echo -e "${InvGreen} ${InvDkGray}${CWhite} Advertise Routes on this Router ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Tailscale can act as a 'subnet router' that allow you to access multiple devices"
echo -e "${InvGreen} ${CClear} located on your particular subnet through Tailscale. Subnet routers act as a"
echo -e "${InvGreen} ${CClear} gateway, relaying traffic from your Tailscale network onto your physical subnet."
echo -e "${InvGreen} ${CClear} If you need access to other devices, such as NAS, routers, computers, printers,"
echo -e "${InvGreen} ${CClear} etc. without the need to install Tailscale software on them, it would be"
echo -e "${InvGreen} ${CClear} recommended to enable this feature. Please indicate your choice below."
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} (Default = Yes)"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Current: ${CGreen}$advroutesdisp${CClear}"
echo -e "${InvGreen} ${CClear} ROUTE(S): ${CGreen}$routes${CClear}"
echo ""
echo -e "Advertise Routes?"
if promptyn "[y/n]: "
then
echo ""
echo ""
echo -e "${InvGreen} ${InvDkGray}${CWhite} Advertise Routes on this Router ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Please indicate what subnet you want to advertise to your Tailscale network."
echo -e "${InvGreen} ${CClear} Typically, you would enter the current subnet of what your router is currently"
echo -e "${InvGreen} ${CClear} configured for, ex: 192.168.50.0/24. Should you want to advertise multiple"
echo -e "${InvGreen} ${CClear} subnets that are accessible by your router, comma-delimit them in this way:"
echo -e "${InvGreen} ${CClear} 192.168.50.0/24,192.168.87.0/24,10.0.100.0/16"
echo -e "${InvGreen} ${CClear}"
echo -en "${InvGreen} ${CClear} (Default = "; echo -e "$(nvram get lan_ipaddr | cut -d"." -f1-3).0/24)"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
read -p "Please enter valid IP4 subnet range? (e=Exit): " routeinput
if [ "$routeinput" == "e" ]; then
echo -e "\n[Exiting]"; sleep 1
elif [ -z "$routeinput" ]; then
advroutes=1
routes=$(nvram get lan_ipaddr | cut -d"." -f1-3).0/24
saveconfig
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Advertised routes enabled." >> $logfile
else
advroutes=1
routes=$routeinput
saveconfig
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Advertised routes enabled." >> $logfile
fi
else
advroutes=0
routes=""
saveconfig
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Advertised routes disabled." >> $logfile
fi
timer=$timerloop
if [ "$advroutesdisp" == "No" ] && [ $advroutes -eq 1 ]; then
echo ""
echo -e "\nChanging exit node configuration options will require a restart of Tailscale. Restart now?"
if promptyn "[y/n]: "
then
echo ""
echo -e "\n${CGreen}Restarting Tailscale Service and Connection...${CClear}"
echo ""
tsdown
stopts
startts
tsup
fi
fi
if [ "$advroutesdisp" == "Yes" ] && [ $advroutes -eq 0 ]; then
echo ""
echo -e "\nChanging exit node configuration options will require a restart of Tailscale. Restart now?"
if promptyn "[y/n]: "
then
echo ""
echo -e "\n${CGreen}Restarting Tailscale Service and Connection...${CClear}"
echo ""
tsdown
stopts
startts
tsup
fi
fi
}
# -------------------------------------------------------------------------------------------------------------------------
# accroutests provide a menu interface to allow for entry to accept linux routes
accroutests()
{
clear
if [ $accroutes -eq 0 ]; then accroutesdisp="No"; elif [ $accroutes -eq 1 ]; then accroutesdisp="Yes"; fi
echo -e "${InvGreen} ${InvDkGray}${CWhite} Accept Site-to-Site Functionality on this Router ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Clients on Android, iOS, macOS, tvOS, and Windows automatically pick up your new"
echo -e "${InvGreen} ${CClear} subnet routes. Only Linux clients using the --accept-routes flag discover the new"
echo -e "${InvGreen} ${CClear} routes automatically because the default is to use only the Tailscale IP addresses."
echo -e "${InvGreen} ${CClear} This option provides for the basic functionality to allow for site-to-site routing"
echo -e "${InvGreen} ${CClear} and communication between networks. Advanced troubleshooting skills may be required"
echo -e "${InvGreen} ${CClear} when enabling this option. Please indicate 'y' or 'n' below."
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} (Default = No)"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Current: ${CGreen}$accroutesdisp${CClear}"
echo ""
echo -e "Accept Routes?"
if promptyn "[y/n]: "
then
accroutes=1
saveconfig
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Accepted Linux routes enabled." >> $logfile
else
accroutes=0
saveconfig
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Accepted Linux routes disabled." >> $logfile
fi
timer=$timerloop
if [ "$accroutesdisp" == "No" ] && [ $accroutes -eq 1 ]; then
echo ""
echo -e "\nChanging routing configuration options will require a restart of Tailscale. Restart now?"
if promptyn "[y/n]: "
then
echo ""
echo -e "\n${CGreen}Restarting Tailscale Service and Connection...${CClear}"
echo ""
tsdown
stopts
startts
tsup
sleep 3
fi
fi
if [ "$accroutesdisp" == "Yes" ] && [ $accroutes -eq 0 ]; then
echo ""
echo -e "\nChanging routing configuration options will require a restart of Tailscale. Restart now?"
if promptyn "[y/n]: "
then
echo ""
echo -e "\n${CGreen}Restarting Tailscale Service and Connection...${CClear}"
echo ""
tsdown
stopts
startts
tsresetc
tsup
sleep 3
fi
fi
}
# -------------------------------------------------------------------------------------------------------------------------
# amtmevents lets you pick success or failure amtm email notification selections
amtmevents()
{
while true; do
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} AMTM Email Notifications ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Please indicate if you would like TAILMON to send you email notifications for${CClear}"
echo -e "${InvGreen} ${CClear} Tailscale service/connection failures, or successes, or both? PLEASE NOTE: This${CClear}"
echo -e "${InvGreen} ${CClear} does require that AMTM email has been set up successfully under AMTM -> em (email${CClear}"
echo -e "${InvGreen} ${CClear} settings). Once you are able to send and receive test emails from AMTM, you may${CClear}"
echo -e "${InvGreen} ${CClear} use this functionality in TAILMON. Additionally, this functionality will download${CClear}"
echo -e "${InvGreen} ${CClear} an AMTM email interface library courtesey of @Martinsky, and will be located${CClear}"
echo -e "${InvGreen} ${CClear} under a new common shared library folder called: /jffs/addons/shared-libs.${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Use the corresponding ${CGreen}()${CClear} key to enable/disable email event notifications:${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
if [ "$amtmemailsuccess" == "1" ]; then amtmemailsuccessdisp="${CGreen}Y${CCyan}"; else amtmemailsuccess=0; amtmemailsuccessdisp="${CRed}N${CCyan}"; fi
if [ "$amtmemailfailure" == "1" ]; then amtmemailfailuredisp="${CGreen}Y${CCyan}"; else amtmemailfailure=0; amtmemailfailuredisp="${CRed}N${CCyan}"; fi
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}Tailscale Success Event Notifications${CClear} ${CGreen}(1) -${CClear} $amtmemailsuccessdisp${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}Tailscale Failure Event Notifications${CClear} ${CGreen}(2) -${CClear} $amtmemailfailuredisp${CClear}"
echo ""
read -p "Please select? (1-2, e=Exit, t=Test Email): " SelectSlot
case $SelectSlot in
1) if [ "$amtmemailsuccess" == "0" ]; then amtmemailsuccess=1; amtmemailsuccessdisp="${CGreen}Y${CCyan}"; elif [ "$amtmemailsuccess" == "1" ]; then amtmemailsuccess=0; amtmemailsuccessdisp="${CRed}N${CCyan}"; fi;;
2) if [ "$amtmemailfailure" == "0" ]; then amtmemailfailure=1; amtmemailfailuredisp="${CGreen}Y${CCyan}"; elif [ "$amtmemailfailure" == "1" ]; then amtmemailfailure=0; amtmemailfailuredisp="${CRed}N${CCyan}"; fi;;
[Tt])
if [ -f "$CUSTOM_EMAIL_LIBFile" ]
then
. "$CUSTOM_EMAIL_LIBFile"
if [ -z "${CEM_LIB_VERSION:+xSETx}" ] || \
_CheckLibraryUpdates_CEM_ "$CUSTOM_EMAIL_LIBDir" quiet
then
_DownloadCEMLibraryFile_ "update"
fi
else
_DownloadCEMLibraryFile_ "install"
fi
cemIsFormatHTML=true
cemIsVerboseMode=true ## true OR false ##
emailBodyTitle="Testing Email Notification"
emailSubject="TEST: TAILMON Email Notification"
tmpEMailBodyFile="/tmp/var/tmp/tmpEMailBody_${scriptFileNTag}.$$.TXT"
{
printf "This is a TEST to check & verify if sending email notifications is working well from TAILMON.\n"
} > "$tmpEMailBodyFile"
_SendEMailNotification_ "TAILMON v$version" "$emailSubject" "$tmpEMailBodyFile" "$emailBodyTitle"
echo ""
echo ""
read -rsp $'Press any key to acknowledge...\n' -n1 key
;;
[Ee])
saveconfig
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: AMTM Email notification configuration saved" >> $logfile
timer=$timerloop
break;;
esac
done
}
# -------------------------------------------------------------------------------------------------------------------------
########################################################################
# AMTM Email Notification Functionality generously donated by @Martinski!
#
# Creation Date: 2020-Jun-11 [Martinski W.]
# Last Modified: 2024-Feb-07 [Martinski W.]
# Modified for TAILMON Purposes [Viktor Jaep]
########################################################################
#-----------------------------------------------------------#
_DownloadCEMLibraryFile_()
{
local msgStr retCode
case "$1" in
update) msgStr="Updating" ;;
install) msgStr="Installing" ;;
*) return 1 ;;
esac
printf "\33[2K\r"
printf "${CGreen}\r[INFO: ${msgStr} the shared AMTM email library script file to support email notifications...]${CClear}"
echo -e "$(date +'%b %d %Y %X') $(nvram get lan_hostname) TAILMON[$$] - INFO: ${msgStr} the shared AMTM email library script file to support email notifications..." >> $logfile
mkdir -m 755 -p "$CUSTOM_EMAIL_LIBDir"
curl -kLSs --retry 3 --retry-delay 5 --retry-connrefused \
"${CEM_LIB_URL}/$CUSTOM_EMAIL_LIBName" -o "$CUSTOM_EMAIL_LIBFile"
curlCode="$?"
if [ "$curlCode" -eq 0 ] && [ -f "$CUSTOM_EMAIL_LIBFile" ]
then
retCode=0
chmod 755 "$CUSTOM_EMAIL_LIBFile"
. "$CUSTOM_EMAIL_LIBFile"
#printf "\nDone.\n"
else
retCode=1
printf "\33[2K\r"
printf "${CRed}\r[ERROR: Unable to download the shared library script file ($CUSTOM_EMAIL_LIBName).]${CClear}"
echo -e "$(date +'%b %d %Y %X') $(nvram get lan_hostname) TAILMON[$$] - **ERROR**: Unable to download the shared AMTM email library script file [$CUSTOM_EMAIL_LIBName]." >> $logfile
fi
return "$retCode"
}
#-----------------------------------------------------------#
# ARG1: The email name/alias to be used as "FROM_NAME"
# ARG2: The email Subject string.
# ARG3: Full path of file containing the email Body text.
# ARG4: The email Body Title string [OPTIONAL].
#-----------------------------------------------------------#
_SendEMailNotification_()
{
if [ -z "${amtmIsEMailConfigFileEnabled:+xSETx}" ]
then
printf "\33[2K\r"
printf "${CRed}\r[ERROR: Email library script ($CUSTOM_EMAIL_LIBFile) *NOT* FOUND.]${CClear}"
sleep 5
echo -e "$(date +'%b %d %Y %X') $(nvram get lan_hostname) TAILMON[$$] - **ERROR**: Email library script [$CUSTOM_EMAIL_LIBFile] *NOT* FOUND." >> $logfile
return 1
fi
if [ $# -lt 3 ] || [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]
then
printf "\33[2K\r"
printf "${CRed}\r[ERROR: INSUFFICIENT email parameters]${CClear}"
sleep 5
echo -e "$(date +'%b %d %Y %X') $(nvram get lan_hostname) TAILMON[$$] - **ERROR**: INSUFFICIENT email parameters." >> $logfile
return 1
fi
local retCode emailBodyTitleStr=""
[ $# -gt 3 ] && [ -n "$4" ] && emailBodyTitleStr="$4"
FROM_NAME="$1"
_SendEMailNotification_CEM_ "$2" "-F=$3" "$emailBodyTitleStr"
retCode="$?"
if [ "$retCode" -eq 0 ]
then
printf "\33[2K\r"
printf "${CGreen}\r[Email notification was sent successfully ($2)]${CClear}"
echo -e "$(date +'%b %d %Y %X') $(nvram get lan_hostname) TAILMON[$$] - INFO: Email notification was sent successfully [$2]" >> $logfile
sleep 5
else
printf "\33[2K\r"
printf "${CRed}\r[ERROR: Failure to send email notification (Error Code: $retCode - $2).]${CClear}"
echo -e "$(date +'%b %d %Y %X') $(nvram get lan_hostname) TAILMON[$$] - **ERROR**: Failure to send email notification [$2]" >> $logfile
sleep 5
fi
return "$retCode"
}
# -------------------------------------------------------------------------------------------------------------------------
# sendmessage is a function that sends an AMTM email based on activity within VPNMON-R3
# $1 = Success/Failure 0/1
# $2 = Component
# $3 = VPN Slot
sendmessage ()
{
#If AMTM email functionality is disabled, return back to the function call
if [ "$amtmemailsuccess" == "0" ] && [ "$amtmemailfailure" == "0" ]; then
return
fi
#Load, install or update the shared AMTM Email integration library
if [ -f "$CUSTOM_EMAIL_LIBFile" ]
then
. "$CUSTOM_EMAIL_LIBFile"
if [ -z "${CEM_LIB_VERSION:+xSETx}" ] || \
_CheckLibraryUpdates_CEM_ "$CUSTOM_EMAIL_LIBDir" quiet
then
_DownloadCEMLibraryFile_ "update"
fi
else
_DownloadCEMLibraryFile_ "install"
fi
cemIsFormatHTML=true
cemIsVerboseMode=false
tmpEMailBodyFile="/tmp/var/tmp/tmpEMailBody_${scriptFileNTag}.$$.TXT"
#Pick the scenario and send email
if [ "$1" == "1" ] && [ "$amtmemailfailure" == "1" ]; then
if [ "$2" == "Tailscale Service settings out-of-sync" ]; then
emailSubject="ALERT: Tailscale Service settings out-of-sync"
emailBodyTitle="ALERT: Tailscale Service settings out-of-sync"
{
printf "Date/Time: $(date +'%b %d %Y %X')\n"
printf "\n"
printf "ALERT: TAILMON is currently recovering from out-of-sync settings issues! TAILMON has detected\n"
printf "that the Tailscale service settings are not in sync with the TAILMON config. This could be due to a\n"
printf "Tailscale update. TAILMON has fixed the settings and restarted the Tailscale service/connection.\n"
printf "\n"
} > "$tmpEMailBodyFile"
elif [ "$2" == "Tailscale Service Restarted" ]; then
emailSubject="FAILURE: Tailscale Service Restarted"
emailBodyTitle="FAILURE: Tailscale Service Restarted"
{
printf "Date/Time: $(date +'%b %d %Y %X')\n"
printf "\n"
printf "FAILURE: TAILMON has detected that the Tailscale service was dead and not connected. TAILMON.\n"
printf "has reset the service, and reestablished a connection to your Tailnet. Please investigate if this\n"
printf "behavior continues to persist.\n"
printf "\n"
} > "$tmpEMailBodyFile"
elif [ "$2" == "Router has been restarted" ]; then
emailSubject="WARNING: Router Has Unexpectedly Restarted"
emailBodyTitle="WARNING: Router Has Unexpectedly Restarted"
{
printf "Date/Time: $(date +'%b %d %Y %X')\n"
printf "\n"
printf "WARNING: TAILMON has detected that the router may have rebooted or was restarted. TAILMON.\n"
printf "has reset the service, and reestablished a connection to your Tailnet. Please investigate if this\n"
printf "behavior continues to persist.\n"
printf "\n"
} > "$tmpEMailBodyFile"
fi
_SendEMailNotification_ "TAILMON v$version" "$emailSubject" "$tmpEMailBodyFile" "$emailBodyTitle"
fi
if [ "$1" == "0" ] && [ "$amtmemailsuccess" == "1" ]; then
if [ "$2" == "Tailscale Operating Mode Userspace" ]; then
emailSubject="SUCCESS: Tailscale Operating Mode changed to Userspace Mode"
emailBodyTitle="SUCCESS: Tailscale Operating Mode changed to Userspace Mode"
{
printf "Date/Time: $(date +'%b %d %Y %X')\n"
printf "\n"
printf "SUCCESS: TAILMON has changed Tailscale Operating Mode to Userspace mode.\n"
printf "\n"
} > "$tmpEMailBodyFile"
elif [ "$2" == "Tailscale Operating Mode Kernel" ]; then
emailSubject="SUCCESS: Tailscale Operating Mode changed to Kernel Mode"
emailBodyTitle="SUCCESS: Tailscale Operating Mode changed to Kernel Mode"
{
printf "Date/Time: $(date +'%b %d %Y %X')\n"
printf "\n"
printf "SUCCESS: TAILMON has changed Tailscale Operating Mode to Kernel mode\n"
printf "\n"
} > "$tmpEMailBodyFile"
elif [ "$2" == "Tailscale Operating Mode Custom" ]; then
emailSubject="SUCCESS: Tailscale Operating Mode changed to Custom Mode"
emailBodyTitle="SUCCESS: Tailscale Operating Mode changed to Custom Mode"
{
printf "Date/Time: $(date +'%b %d %Y %X')\n"
printf "\n"
printf "SUCCESS: TAILMON has changed Tailscale Operating Mode to Custom mode\n"
printf "\n"
} > "$tmpEMailBodyFile"
fi
_SendEMailNotification_ "TAILMON v$version" "$emailSubject" "$tmpEMailBodyFile" "$emailBodyTitle"
fi
}
# -------------------------------------------------------------------------------------------------------------------------
# installdependencies checks for existence of entware, and if so proceed and install the packages, then run tailmon -config
installdependencies()
{
clear
if [ -f "/opt/bin/timeout" ] && [ -f "/opt/sbin/screen" ]; then
vconfig
else
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Install Dependencies ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Missing dependencies required by TAILMON will be installed during this process."
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
echo -e "TAILMON has some dependencies in order to function correctly, namely, CoreUtils-Timeout"
echo -e "and the Screen utility. These utilities require you to have Entware already installed"
echo -e "using the AMTM tool. If Entware is present, the Timeout and Screen utilities will"
echo -e "automatically be downloaded and installed during this process."
echo ""
echo -e "${CGreen}CoreUtils-Timeout${CClear} is a utility that provides more stability for certain routers (like"
echo -e "the RT-AC86U) which has a tendency to randomly hang scripts running on this router model."
echo ""
echo -e "${CGreen}Screen${CClear} is a utility that allows you to run SSH scripts in a standalone environment"
echo -e "directly on the router itself, instead of running your commands or a script from a network-"
echo -e "attached SSH client. This can provide greater stability due to it running on the router"
echo -e "itself."
echo ""
[ -z "$($timeoutcmd$timeoutsec nvram get odmpid)" ] && RouterModel="$($timeoutcmd$timeoutsec nvram get productid)" || RouterModel="$($timeoutcmd$timeoutsec nvram get odmpid)" # Thanks @thelonelycoder for this logic
echo -e "Your router model is: ${CGreen}$RouterModel${CClear}"
echo ""
echo -e "Ready to install?"
if promptyn "[y/n]: "
then
if [ -d "/opt" ]; then # Does entware exist? If yes proceed, if no error out.
echo ""
echo -e "\n${CClear}Updating Entware Packages..."
echo ""
opkg update
echo ""
echo -e "Installing Entware ${CGreen}CoreUtils-Timeout${CClear} Package...${CClear}"
echo ""
opkg install coreutils-timeout
echo ""
echo -e "Installing Entware ${CGreen}Screen${CClear} Package...${CClear}"
echo ""
opkg install screen
echo ""
echo -e "Install completed..."
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Entware dependencies installed." >> $logfile
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
echo ""
echo -e "Executing Configuration Utility..."
sleep 1
vconfig
else
clear
echo -e "${CRed}ERROR: Entware was not found on this router...${CClear}"
echo -e "Please install Entware using the AMTM utility before proceeding..."
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - ERROR: Entware was not found installed on router. Please investigate." >> $logfile
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
exit 1
fi
else
echo ""
echo -e "\n${CClear}[Exiting]"
echo ""
sleep 1
exit 0
fi
fi
}
# -------------------------------------------------------------------------------------------------------------------------
# reinstalldependencies force re-installs the entware packages
reinstalldependencies()
{
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Re-install Dependencies ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Missing dependencies required by TAILMON will be re-installed during this process."
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
echo -e "Would you like to re-install the CoreUtils-Timeout and the Screen utility? These"
echo -e "utilities require you to have Entware already installed using the AMTM tool. If Entware"
echo -e "is present, the Timeout and Screen utilities will be uninstalled, downloaded and re-"
echo -e "installed during this setup process..."
echo ""
echo -e "${CGreen}CoreUtils-Timeout${CClear} is a utility that provides more stability for certain routers (like"
echo -e "the RT-AC86U) which has a tendency to randomly hang scripts running on this router"
echo -e "model."
echo ""
echo -e "${CGreen}Screen${CClear} is a utility that allows you to run SSH scripts in a standalone environment"
echo -e "directly on the router itself, instead of running your commands or a script from a"
echo -e "network-attached SSH client. This can provide greater stability due to it running on"
echo -e "the router itself."
echo ""
[ -z "$($timeoutcmd$timeoutsec nvram get odmpid)" ] && RouterModel="$($timeoutcmd$timeoutsec nvram get productid)" || RouterModel="$($timeoutcmd$timeoutsec nvram get odmpid)" # Thanks @thelonelycoder for this logic
echo -e "Your router model is: ${CGreen}$RouterModel${CClear}"
echo ""
echo -e "Force Re-install?"
if promptyn "[y/n]: "
then
if [ -d "/opt" ]; then # Does entware exist? If yes proceed, if no error out.
echo ""
echo -e "\nUpdating Entware Packages..."
echo ""
opkg update
echo ""
echo -e "Force Re-installing Entware ${CGreen}CoreUtils-Timeout${CClear} Package..."
echo ""
opkg install --force-reinstall coreutils-timeout
echo ""
echo -e "Force Re-installing Entware ${CGreen}Screen${CClear} Package..."
echo ""
opkg install --force-reinstall screen
echo ""
echo -e "Re-install completed..."
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Entware dependencies re-installed." >> $logfile
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
else
clear
echo -e "${CRed}ERROR: Entware was not found on this router...${CClear}"
echo -e "Please install Entware using the AMTM utility before proceeding..."
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - ERROR: Entware was not found installed on router. Please investigate." >> $logfile
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
exit 1
fi
fi
}
# -------------------------------------------------------------------------------------------------------------------------
# vsetup provide a menu interface to allow for initial component installs, uninstall, etc.
vsetup()
{
if [ ! -f "/opt/bin/timeout" ] || [ ! -f "/opt/sbin/screen" ]; then
installdependencies
fi
while true; do
clear # Initial Setup
if [ -f $config ]; then
source $config
else
saveconfig
fi
if [ -f "/opt/bin/tailscale" ]; then tsinstalleddisp="Installed"; else tsinstalleddisp="Not Installed"; fi
if [ $exitnode -eq 0 ]; then exitnodedisp="No"; elif [ $exitnode -eq 1 ]; then exitnodedisp="Yes"; fi
if [ $advroutes -eq 0 ]; then advroutesdisp="No"; elif [ $advroutes -eq 1 ]; then advroutesdisp="Yes ($routes)"; fi
if [ $accroutes -eq 0 ]; then accroutesdisp="No"; elif [ $accroutes -eq 1 ]; then accroutesdisp="Yes"; fi
tsver=$(tailscale version | awk 'NR==1 {print $1}') >/dev/null 2>&1
if [ -z "$tsver" ]; then tsver="0.00"; fi
echo -e "${InvGreen} ${InvDkGray}${CWhite} TAILMON Main Setup and Configuration Menu ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Please choose from the various options below, which allow you to perform high level${CClear}"
echo -e "${InvGreen} ${CClear} actions in the management of the TAILMON script.${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 1)${CClear} : Install Tailscale Entware Package(s) : ${CGreen}$tsinstalleddisp${CClear}"
printf "\33[2K\r"
printf "${CGreen}\r[Checking Services...Stand By]"
/opt/etc/init.d/S06tailscaled check >/dev/null 2>&1
tsservice=$?
if [ $tsservice -ne 0 ]; then tsservicedisp="Stopped"; else tsservicedisp="Started"; fi
tailscale status >/dev/null 2>&1
tsconn=$?
if [ $tsconn -ne 0 ]; then tsconndisp="Disconnected"; else tsconndisp="Connected"; fi
printf "\33[2K\r"
if [ "$tsinstalleddisp" == "Installed" ]; then
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} |-${CClear}-- ${InvGreen}${CWhite}(R)${CClear}e-${InvGreen}${CWhite}(S)${CClear}tart / S${InvGreen}${CWhite}(T)${CClear}op Tailscale Service${CClear} |--- ${CGreen}$tsservicedisp${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} |-${CClear}-- ${InvGreen}${CWhite}(U)${CClear}p / ${InvGreen}${CWhite}(D)${CClear}own Tailscale Connection${CClear} |--- ${CGreen}$tsconndisp${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} |-${CClear}-- U${InvGreen}${CWhite}(P)${CClear}date Tailscale Binary to latest version |--- ${CGreen}v$tsver${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} |-${CClear}-- ${InvGreen}${CWhite}(I)${CClear}ssue Connection '--reset' Command${CClear}"
fi
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 2)${CClear} : Uninstall Tailscale Entware Package(s)${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 3)${CClear} : Set Tailscale Operating Mode : ${CGreen}$tsoperatingmode${CClear}"
if [ "$tsoperatingmode" == "Custom" ]; then
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} |-${CClear}-- Edit Custom ${InvGreen}${CWhite}(O)${CClear}peration Mode Settings${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 4)${CClear}${CDkGray} : Configure this Router as Exit Node : $exitnodedisp${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 5)${CClear}${CDkGray} : Advertise Routes on this router : $advroutesdisp${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 6)${CClear}${CDkGray} : Accept Routes on this router : $accroutesdisp${CClear}"
else
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 4)${CClear} : Configure this Router as Exit Node : ${CGreen}$exitnodedisp${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 5)${CClear} : Advertise Routes on this router : ${CGreen}$advroutesdisp${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 6)${CClear} : Enable Site-to-Site functionality on router : ${CGreen}$accroutesdisp${CClear}"
fi
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 7)${CClear} : Custom configuration options for TAILMON${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 8)${CClear} : Force reinstall Entware dependencies${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( 9)${CClear} : Check for latest updates${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(10)${CClear} : Uninstall TAILMON${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} | ${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( L)${CClear} : Launch TAILMON in Monitoring Mode${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( M)${CClear} : Launch TAILMON in Monitoring Mode using SCREEN${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} | ${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}( e)${CClear} : Exit${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
if [ "$tsinstalleddisp" == "Installed" ]; then
if [ "$tsoperatingmode" == "Custom" ]; then
read -p "Please select? (1-10, R/S/T/U/D/P/I/O/L/M, e=Exit): " SelectSlot
else
read -p "Please select? (1-10, R/S/T/U/D/P/I/L/M, e=Exit): " SelectSlot
fi
else
read -p "Please select? (1-10, L/M, e=Exit): " SelectSlot
fi
case $SelectSlot in
[Rr]) echo ""; restarttsc;;
[Ss]) echo ""; startts;;
[Tt]) echo ""; stopts;;
[Uu]) echo ""; tsup;;
[Dd]) echo ""; tsdown;;
[Ll]) exec sh /jffs/scripts/tailmon.sh -noswitch;;
[Mm]) exec sh /jffs/scripts/tailmon.sh -screen -now;;
[Oo]) if [ "$tsoperatingmode" == "Custom" ]; then
customconfig
fi ;;
[Pp]) echo ""; tsupdate;;
[Ii]) echo ""; tsreset;;
1) installts;;
2) uninstallts;;
3) if [ -f "/opt/bin/tailscale" ]; then operatingmode; fi;;
4) if [ "$tsoperatingmode" != "Custom" ]; then
if [ -f "/opt/bin/tailscale" ]; then exitnodets; fi
fi ;;
5) if [ "$tsoperatingmode" != "Custom" ]; then
if [ -f "/opt/bin/tailscale" ]; then advroutests; fi
fi ;;
6) if [ "$tsoperatingmode" != "Custom" ]; then
if [ -f "/opt/bin/tailscale" ]; then accroutests; fi
fi ;;
7) installdependencies;;
8) reinstalldependencies;;
9) vupdate;;
10) vuninstall;;
[Ee]) echo ""; timer=$timerloop; break;;
esac
done
}
# -------------------------------------------------------------------------------------------------------------------------
# vconfig is a function that provides a UI to choose various options for tailmon
vconfig()
{
# Grab the TAILMON config file and read it in
if [ -f $config ]; then
source $config
else
initialsetup
fi
while true; do
if [ $keepalive -eq 0 ]; then
keepalivedisp="No"
else
keepalivedisp="Yes"
fi
if [ $persistentsettings -eq 0 ]; then
persistentsettingsdisp="No"
else
persistentsettingsdisp="Yes"
fi
if [ "$amtmemailsuccess" == "0" ] && [ "$amtmemailfailure" == "0" ]; then
amtmemailsuccfaildisp="Disabled"
elif [ "$amtmemailsuccess" == "1" ] && [ "$amtmemailfailure" == "0" ]; then
amtmemailsuccfaildisp="Success"
elif [ "$amtmemailsuccess" == "0" ] && [ "$amtmemailfailure" == "1" ]; then
amtmemailsuccfaildisp="Failure"
elif [ "$amtmemailsuccess" == "1" ] && [ "$amtmemailfailure" == "1" ]; then
amtmemailsuccfaildisp="Success, Failure"
else
amtmemailsuccfaildisp="Disabled"
fi
if [ $autostart -eq 0 ]; then
autostartdisp="Disabled"
elif [ $autostart -eq 1 ]; then
autostartdisp="Enabled"
fi
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} TAILMON Configuration Option ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Please choose from the various options below, which allow you to modify certain${CClear}"
echo -e "${InvGreen} ${CClear} customizable parameters that affect the operation of this script.${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(1)${CClear} : Keep Tailscale Service Alive : ${CGreen}$keepalivedisp"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(2)${CClear} : Timer Check Loop Interval : ${CGreen}${timerloop}sec"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(3)${CClear} : Custom Event Log size (rows) : ${CGreen}$logsize"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(4)${CClear} : AMTM Email Notifications on Success/Failure : ${CGreen}$amtmemailsuccfaildisp"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(5)${CClear} : Keep settings on Tailscale Entware updates : ${CGreen}$persistentsettingsdisp"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(6)${CClear} : Autostart TAILMON on Reboot : ${CGreen}$autostartdisp"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite} | ${CClear}"
echo -e "${InvGreen} ${CClear} ${InvDkGray}${CWhite}(e)${CClear} : Exit${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
read -p "Please select? (1-6, e=Exit): " SelectSlot
case $SelectSlot in
1)
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Keep Tailscale Service Alive ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Please indicate if you want TAILMON to check the status of the Tailscale Service${CClear}"
echo -e "${InvGreen} ${CClear} and restart it if necessary? While Tailscale overall is fairly stable, there are${CClear}"
echo -e "${InvGreen} ${CClear} instances where the service with terminate."
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} (Default = Yes)${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
echo -e "${CClear}Current: ${CGreen}$keepalivedisp${CClear}"
echo ""
echo -e "Keep Alive?"
if promptyn "[y/n]: "
then
keepalive=1
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: TAILMON keepalive enabled." >> $logfile
else
keepalive=0
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: TAILMON keepalive disabled." >> $logfile
fi
saveconfig
;;
2) timerloopconfig
;;
3)
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Custom Event Log Size ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Please indicate below how large you would like your Event Log to grow. I'm a poet${CClear}"
echo -e "${InvGreen} ${CClear} and didn't even know it. By default, with 2000 rows, you will have many months of${CClear}"
echo -e "${InvGreen} ${CClear} Event Log data."
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Use 0 to Disable, max number of rows is 9999. (Default = 2000)"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
echo -e "${CClear}Current: ${CGreen}$logsize${CClear}"
echo ""
read -p "Please enter Log Size (in rows)? (0-9999, e=Exit): " NEWLOGSIZE
if [ "$NEWLOGSIZE" == "e" ]; then
echo -e "\n[Exiting]"; sleep 1
elif [ $NEWLOGSIZE -ge 0 ] && [ $NEWLOGSIZE -le 9999 ]; then
logsize=$NEWLOGSIZE
saveconfig
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: Event log size configured for $logsize rows." >> $logfile
else
logsize=2000
saveconfig
fi
;;
4)
amtmevents
source $config
;;
5)
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Keep Settings Persistent on Tailscale Entware Updates ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} Please indicate if you want TAILMON to check the Tailscale Service settings on${CClear}"
echo -e "${InvGreen} ${CClear} a regular basis to determine if settings are out-of-sync due to a possible${CClear}"
echo -e "${InvGreen} ${CClear} Tailscale Entware upgrade? A common side-effect after updating the Tailscale${CClear}"
echo -e "${InvGreen} ${CClear} Entware package is that it will remove your previously configured settings,${CClear}"
echo -e "${InvGreen} ${CClear} which could cause your router to no longer participate on your tailnet.${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} (Default = No)${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
echo -e "${CClear}Current: ${CGreen}$persistentsettingsdisp${CClear}"
echo ""
echo -e "Keep Settings Persistent?"
if promptyn "[y/n]: "
then
persistentsettings=1
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: TAILMON Keep Settings Persistent enabled." >> $logfile
else
persistentsettings=0
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: TAILMON Keep Settings Persistent disabled." >> $logfile
fi
saveconfig
;;
6) autostart;;
[Ee]) echo -e "${CClear}\n[Exiting]"; sleep 1; resettimer=1; break ;;
esac
done
}
# -------------------------------------------------------------------------------------------------------------------------
# vupdate is a function that provides a UI to check for script updates and allows you to install the latest version...
vupdate()
{
updatecheck # Check for the latest version from source repository
while true; do
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Update Utility ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} This utility allows you to check, download and install updates"
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
echo -e "Current Version: ${CGreen}$version${CClear}"
echo -e "Updated Version: ${CGreen}$DLversion${CClear}"
echo ""
if [ "$version" == "$DLversion" ]
then
echo -e "You are on the latest version! Would you like to download anyways? This will overwrite${CClear}"
echo -e "your local copy with the current build.${CClear}"
if promptyn "[y/n]: "; then
echo ""
echo -e "\nDownloading TAILMON ${CGreen}v$DLversion${CClear}"
curl --silent --retry 3 --connect-timeout 3 --max-time 5 --retry-delay 1 --retry-all-errors --fail "https://raw.githubusercontent.com/ViktorJp/TAILMON/main/tailmon.sh" -o "/jffs/scripts/tailmon.sh" && chmod 755 "/jffs/scripts/tailmon.sh"
echo ""
echo -e "Download successful!${CClear}"
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: TAILMON update successfully downloaded and installed." >> $logfile
echo ""
read -rsp $'Press any key to restart TAILMON...\n' -n1 key
exec /jffs/scripts/tailmon.sh -setup
else
echo ""
echo ""
echo -e "Exiting Update Utility...${CClear}"
sleep 1
return
fi
else
echo -e "Score! There is a new version out there! Would you like to update?${CClear}"
if promptyn "[y/n]: "; then
echo ""
echo -e "\nDownloading TAILMON ${CGreen}v$DLversion${CClear}"
curl --silent --retry 3 --connect-timeout 3 --max-time 6 --retry-delay 1 --retry-all-errors --fail "https://raw.githubusercontent.com/ViktorJp/TAILMON/main/tailmon.sh" -o "/jffs/scripts/tailmon.sh" && chmod 755 "/jffs/scripts/tailmon.sh"
echo ""
echo -e "Download successful!${CClear}"
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: TAILMON update successfully downloaded and installed." >> $logfile
echo ""
read -rsp $'Press any key to restart TAILMON...\n' -n1 key
exec /jffs/scripts/tailmon.sh -setup
else
echo ""
echo ""
echo -e "Exiting Update Utility...${CClear}"
sleep 1
return
fi
fi
done
}
# -------------------------------------------------------------------------------------------------------------------------
# updatecheck is a function that downloads the latest update version file, and compares it with what's currently installed
updatecheck()
{
# Download the latest version file from the source repository
curl --silent --retry 3 --connect-timeout 3 --max-time 6 --retry-delay 1 --retry-all-errors --fail "https://raw.githubusercontent.com/ViktorJp/TAILMON/main/version.txt" -o "/jffs/addons/tailmon.d/version.txt"
if [ -f $dlverpath ]
then
# Read in its contents for the current version file
DLversion=$(cat $dlverpath)
# Compare the new version with the old version and log it
if [ "$beta" == "1" ]; then # Check if Dev/Beta Mode is enabled and disable notification message
UpdateNotify=0
elif [ "$DLversion" != "$version" ]; then
DLversionPF=$(printf "%-8s" $DLversion)
versionPF=$(printf "%-8s" $version)
UpdateNotify="${InvYellow} ${InvDkGray}${CWhite} Update available: v$versionPF -> v$DLversionPF ${CClear}"
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: New TAILMON v$DLversion available for download/install." >> $logfile
else
UpdateNotify=0
fi
fi
}
# -------------------------------------------------------------------------------------------------------------------------
# vuninstall is a function that uninstalls and removes all traces of tailmon/tailscale from your router...
vuninstall()
{
while true; do
clear
echo -e "${InvGreen} ${InvDkGray}${CWhite} Uninstall Utility ${CClear}"
echo -e "${InvGreen} ${CClear}"
echo -e "${InvGreen} ${CClear} You are about to uninstall TAILMON and optionally, Tailscale from your router! This"
echo -e "${InvGreen} ${CClear} action is irreversible."
echo -e "${InvGreen} ${CClear}${CDkGray}---------------------------------------------------------------------------------------${CClear}"
echo ""
echo -e "Do you wish to proceed?${CClear}"
if promptyn "[y/n]: "; then
echo ""
echo -e "\nAre you sure? Please type 'y' to validate you wish to proceed.${CClear}"
if promptyn "[y/n]: "; then
#Remove and uninstall files/directories
rm -f -r /jffs/addons/tailmon.d >/dev/null 2>&1
rm -f /jffs/scripts/tailmon.sh >/dev/null 2>&1
sed -i -e '/tailmon.sh/d' /jffs/scripts/post-mount >/dev/null 2>&1
echo ""
echo -e "\n${CGreen}TAILMON has been uninstalled...${CClear}"
echo ""
if [ -f "/opt/bin/tailscale" ]; then
echo -e "Would you also like to uninstall Tailscale from your router?"
if promptyn "[y/n]: "; then
if [ -d "/opt" ]; then # Does entware exist? If yes proceed, if no error out.
echo ""
echo -e "\n${CGreen}Shutting down Tailscale...${CClear}"
tailscale logout
tailscale down
/opt/etc/init.d/S06tailscaled stop
echo ""
echo -e "\n${CGreen}Removing firewall-start entries...${CClear}"
#remove firewall-start entry if found
if [ -f /jffs/scripts/firewall-start ]; then
if grep -q -F "if [ -x /opt/bin/tailscale ]; then tailscale down; tailscale up; fi" /jffs/scripts/firewall-start; then
sed -i -e '/tailscale down/d' /jffs/scripts/firewall-start
fi
fi
echo -e "\n${CGreen}Updating Entware Packages...${CClear}"
echo ""
opkg update
echo ""
echo -e "${CGreen}Uninstalling Entware Tailscale Package(s)...${CClear}"
echo ""
archker=$(opkg print-architecture | grep "armv7-2.6")
if [ -z "$archker" ]; then
opkg remove tailscale
else
opkg remove tailscale_nohf #remove special tailscale package for arm7 kernel 2.6
fi
rm -f /opt/var/tailscaled.state >/dev/null 2>&1
rm -r /opt/var/lib/tailscale >/dev/null 2>&1
rm -r /opt/var/run/tailscale >/dev/null 2>&1
rm -r /var/run/tailscale >/dev/null 2>&1
rm -r /var/lib/tailscale >/dev/null 2>&1
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
echo ""
echo -e "${CClear}"
exit 0
break
else
clear
echo -e "${CRed}ERROR: Entware was not found on this router...${CClear}"
echo -e "Please install Entware using the AMTM utility before proceeding..."
echo ""
read -rsp $'Press any key to continue...\n' -n1 key
exit 1
fi
exit 0
else
echo ""
echo -e "\nExiting Uninstall Utility...${CClear}"
sleep 1
echo ""
echo -e "${CClear}"
exit 0
fi
fi
exit 0
else
echo ""
echo -e "\nExiting Uninstall Utility...${CClear}"
sleep 1
return
fi
fi
done
}
# -------------------------------------------------------------------------------------------------------------------------
# vlogs is a function that calls the nano text editor to view the TAILMON log file
vlogs()
{
export TERM=linux
nano +999999 --linenumbers $logfile
timer=$timerloop
trimlogs
}
# -------------------------------------------------------------------------------------------------------------------------
# trimlogs will cut down log size (in rows) based on custom value
trimlogs()
{
if [ $logsize -gt 0 ]; then
currlogsize=$(wc -l $logfile | awk '{ print $1 }' ) # Determine the number of rows in the log
if [ $currlogsize -gt $logsize ] # If it's bigger than the max allowed, tail/trim it!
then
echo "$(tail -$logsize $logfile)" > $logfile
fi
fi
}
# -------------------------------------------------------------------------------------------------------------------------
# saveconfig saves the tailmon.cfg file after every major change, and applies that to the script on the fly
saveconfig()
{
{ echo 'keepalive='$keepalive
echo 'timerloop='$timerloop
echo 'logsize='$logsize
echo 'autostart='$autostart
echo 'amtmemailsuccess='$amtmemailsuccess
echo 'amtmemailfailure='$amtmemailfailure
echo 'tsoperatingmode="'"$tsoperatingmode"'"'
echo 'persistentsettings='$persistentsettings
echo 'exitnode='$exitnode
echo 'advroutes='$advroutes
echo 'accroutes='$accroutes
echo 'precmd="'"$precmd"'"'
echo 'args="'"$args"'"'
echo 'preargs="'"$preargs"'"'
echo 'routes="'"$routes"'"'
echo 'customcmdline="'"$customcmdline"'"'
} > $config
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - INFO: TAILMON config has been updated." >> $logfile
}
# -------------------------------------------------------------------------------------------------------------------------
# Begin main commandline switch logic
# -------------------------------------------------------------------------------------------------------------------------
# Check for updates
updatecheck
# Check and see if any commandline option is being used
if [ $# -eq 0 ]
then
clear
exec sh /jffs/scripts/tailmon.sh -noswitch
exit 0
fi
# Check and see if an invalid commandline option is being used
if [ "$1" == "-h" ] || [ "$1" == "-help" ] || [ "$1" == "-setup" ] || [ "$1" == "-bw" ] || [ "$1" == "-noswitch" ] || [ "$1" == "-screen" ] || [ "$1" == "-now" ]
then
clear
else
clear
echo ""
echo "TAILMON v$version"
echo ""
echo "Exiting due to invalid commandline options!"
echo "(run 'tailmon.sh -h' for help)"
echo ""
echo -e "${CClear}"
exit 0
fi
# Check to see if the help option is being called
if [ "$1" == "-h" ] || [ "$1" == "-help" ]
then
clear
echo ""
echo "TAILMON v$version Commandline Option Usage:"
echo ""
echo "tailmon -h | -help"
echo "tailmon -setup"
echo "tailmon -bw"
echo "tailmon -screen"
echo "tailmon -screen -now"
echo ""
echo " -h | -help (this output)"
echo " -setup (displays the setup menu)"
echo " -bw (runs tailmon in monochrome mode)"
echo " -screen (runs tailmon in screen background)"
echo " -screen -now (runs tailmon in screen background immediately)"
echo ""
echo -e "${CClear}"
exit 0
fi
# Check to see if a second command is being passed to remove color
if [ "$1" == "-bw" ] || [ "$2" == "-bw" ]
then
blackwhite
fi
# Check to see if the -now parameter is being called to bypass the screen timer
if [ "$2" == "-now" ]
then
bypassscreentimer=1
fi
# Check to see if the setup option is being called
if [ "$1" == "-setup" ]
then
# Create the necessary folder/file structure for tailmon under /jffs/addons
if [ ! -d "/jffs/addons/tailmon.d" ]; then
mkdir -p "/jffs/addons/tailmon.d"
fi
logoNM
vsetup
exit 0
fi
# Check to see if the screen option is being called and run operations normally using the screen utility
if [ "$1" == "-screen" ]
then
screen -wipe >/dev/null 2>&1 # Kill any dead screen sessions
sleep 1
ScreenSess=$(screen -ls | grep "tailmon" | awk '{print $1}' | cut -d . -f 1)
if [ -z $ScreenSess ]; then
if [ "$bypassscreentimer" == "1" ]; then
screen -dmS "tailmon" $apppath -noswitch
sleep 1
screen -r tailmon
else
clear
echo -e "${CClear}Executing ${CGreen}TAILMON v$version${CClear} using the SCREEN utility..."
echo ""
echo -e "${CClear}IMPORTANT:"
echo -e "${CClear}In order to keep TAILMON running in the background,"
echo -e "${CClear}properly exit the SCREEN session by using: ${CGreen}CTRL-A + D${CClear}"
echo ""
screen -dmS "tailmon" $apppath -noswitch
sleep 5
screen -r tailmon
exit 0
fi
else
if [ "$bypassscreentimer" == "1" ]; then
sleep 1
else
clear
echo -e "${CClear}Connecting to existing ${CGreen}TAILMON v$version${CClear} SCREEN session...${CClear}"
echo ""
echo -e "${CClear}IMPORTANT:${CClear}"
echo -e "${CClear}In order to keep TAILMON running in the background,${CClear}"
echo -e "${CClear}properly exit the SCREEN session by using: ${CGreen}CTRL-A + D${CClear}"
echo ""
echo -e "${CClear}Switching to the SCREEN session in T-5 sec...${CClear}"
echo -e "${CClear}"
spinner 5
fi
fi
screen -dr $ScreenSess
exit 0
fi
# Check to see if the noswitch option is being called
if [ "$1" == "-noswitch" ]
then
clear #last switch before the main program starts
if [ ! -f $cfgpath ]; then
initialsetup
fi
fi
# -------------------------------------------------------------------------------------------------------------------------
# Begin TAILMON Main Loop
# -------------------------------------------------------------------------------------------------------------------------
#DEBUG=; set -x # uncomment/comment to enable/disable debug mode
#{ # uncomment/comment to enable/disable debug mode
# Create the necessary folder/file structure for tailmon under /jffs/addons
if [ ! -d "/jffs/addons/tailmon.d" ]; then
mkdir -p "/jffs/addons/tailmon.d"
fi
# Check for and add an alias for TAILMON
if ! grep -F "sh /jffs/scripts/tailmon.sh" /jffs/configs/profile.add >/dev/null 2>/dev/null; then
echo "alias tailmon=\"sh /jffs/scripts/tailmon.sh\" # added by tailmon" >> /jffs/configs/profile.add
fi
if [ ! -f "/opt/bin/timeout" ] || [ ! -f "/opt/sbin/screen" ]; then
installdependencies
fi
if [ -f "/opt/bin/timeout" ] # If the timeout utility is available then use it and assign variables
then
timeoutcmd="timeout "
timeoutsec="10"
timeoutlng="60"
else
timeoutcmd=""
timeoutsec=""
timeoutlng=""
fi
while true; do
# Grab the TAILMON config file and read it in
if [ -f $config ]; then
source $config
else
initialsetup
fi
if [ -f "/opt/bin/tailscale" ]; then
tsinstalled=1
clear
if [ $keepalive -eq 1 ]; then
keepalivedisp="Yes"
else
keepalivedisp="No"
fi
if [ "$amtmemailsuccess" == "0" ] && [ "$amtmemailfailure" == "0" ]; then
amtmdisp="${CDkGray}Disabled "
elif [ "$amtmemailsuccess" == "1" ] && [ "$amtmemailfailure" == "0" ]; then
amtmdisp="${CGreen}Success "
elif [ "$amtmemailsuccess" == "0" ] && [ "$amtmemailfailure" == "1" ]; then
amtmdisp="${CGreen}Failure "
elif [ "$amtmemailsuccess" == "1" ] && [ "$amtmemailfailure" == "1" ]; then
amtmdisp="${CGreen}Success, Failure"
else
amtmdisp="${CDkGray}Disabled "
fi
tzone=$(date +%Z)
tzonechars=$(echo ${#tzone})
if [ $tzonechars = 1 ]; then tzspaces=" ";
elif [ $tzonechars = 2 ]; then tzspaces=" ";
elif [ $tzonechars = 3 ]; then tzspaces=" ";
elif [ $tzonechars = 4 ]; then tzspaces=" ";
elif [ $tzonechars = 5 ]; then tzspaces=" "; fi
#Display tailmon Update Notifications
if [ "$UpdateNotify" != "0" ]; then echo -e "$UpdateNotify"; fi
tsver=$(tailscale version | awk 'NR==1 {print $1}') >/dev/null 2>&1
if [ -z "$tsver" ]; then tsver="0.00"; fi
#Display tailmon client header
echo -en "${InvGreen} ${InvDkGray} TAILMON - v"
printf "%-8s" $version
echo -e " ${CWhite}Operations Menu ${InvDkGray} $tzspaces$(date) ${CClear}"
echo -e "${InvGreen} ${CClear} ${CGreen}(R)${CClear}e-${CGreen}(S)${CClear}tart / S${CGreen}(T)${CClear}op Tailscale Service ${InvGreen} ${CClear} ${CGreen}(C)${CClear}onfiguration Menu / Main Setup Menu${CClear}"
echo -e "${InvGreen} ${CClear} Tailscale Connection ${CGreen}(U)${CClear}p / ${CGreen}(D)${CClear}own ${InvGreen} ${CClear} ${CGreen}(L)${CClear}og Viewer / Trim Log Size (rows): ${CGreen}$logsize${CClear}"
if [ "$tsoperatingmode" == "Custom" ]; then
echo -e "${InvGreen} ${CClear} Custom ${CGreen}(O)${CClear}peration Mode Settings ${InvGreen} ${CClear} ${CGreen}(K)${CClear}eep Tailscale Service Alive: ${CGreen}$keepalivedisp${CClear}"
else
echo -e "${InvGreen} ${CClear} ${CDkGray}Custom (O)peration Mode Settings${CClear} ${InvGreen} ${CClear} ${CGreen}(K)${CClear}eep Tailscale Service Alive: ${CGreen}$keepalivedisp${CClear}"
fi
echo -e "${InvGreen} ${CClear} ${CGreen}(A)${CClear}MTM Email Notifications: $amtmdisp ${InvGreen} ${CClear} Ti${CGreen}(M)${CClear}er Check Loop Interval: ${CGreen}${timerloop}sec${CClear}"
echo -e "${InvGreen} ${CClear}${CDkGray}--------------------------------------------------------------------------------------------------------------${CClear}"
echo ""
echo -en "${InvDkGray}${CWhite}Tailscale Service v"
printf "%-8s" $tsver
echo -e " ${CClear}"
/opt/etc/init.d/S06tailscaled check
tsservice=$?
echo ""
echo -e "${InvDkGray}${CWhite}Tailscale Connection Status: ${CClear}"
tailscale status
echo ""
if [ "$tsoperatingmode" == "Userspace" ]; then
echo -e "${InvDkGray}${CWhite}Tailscale Service Options (Userspace Mode) ${CClear}"
echo -e "${CWhite}ARGS: ${CGreen}$args"
echo -e "${CWhite}PREARGS: ${CGreen}$preargs"
elif [ "$tsoperatingmode" == "Kernel" ]; then
echo -e "${InvDkGray}${CWhite}Tailscale Service Options (Kernel Mode) ${CClear}"
echo -e "${CWhite}PRECMD: ${CGreen}$precmd"
echo -e "${CWhite}ARGS: ${CGreen}$args"
echo -e "${CWhite}PREARGS: ${CGreen}$preargs"
elif [ "$tsoperatingmode" == "Custom" ]; then
echo -e "${InvDkGray}${CWhite}Tailscale Service Options (Custom Mode) ${CClear}"
echo -e "${CWhite}PRECMD: ${CGreen}$precmd"
echo -e "${CWhite}ARGS: ${CGreen}$args"
echo -e "${CWhite}PREARGS: ${CGreen}$preargs"
fi
echo ""
echo -e "${InvDkGray}${CWhite}Tailscale Connection Commandline ${CClear}"
if [ "$tsoperatingmode" == "Custom" ]; then
echo -e "${CWhite}${CGreen}$customcmdline${CClear}"
else
if [ $exitnode -eq 1 ]; then exitnodecmd="--advertise-exit-node "; else exitnodecmd=""; fi
if [ $advroutes -eq 1 ]; then advroutescmd="--advertise-routes=$routes "; else advroutescmd=""; fi
if [ $accroutes -eq 1 ]; then accroutescmd="--accept-routes"; else accroutescmd=""; fi
echo -e "${CWhite}${CGreen}$exitnodecmd$advroutescmd$accroutescmd${CClear}"
fi
echo ""
#read -rsp $'Press any key to continue...\n' -n1 key
else
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - ERROR: Tailscale binaries not found. Please investigate." >> $logfile
tsinstalled=0
exec sh /jffs/scripts/tailmon.sh -setup
fi
#Determine if S06tailscaled service settings have changed
if [ $tsinstalled -eq 1 ] && [ $persistentsettings -eq 1 ]; then
s06args=$(cat /opt/etc/init.d/S06tailscaled | grep ^ARGS= | cut -d '=' -f 2-) 2>/dev/null
tailmonargs="\"$args\""
if [ "$s06args" != "$tailmonargs" ]; then
printf "\33[2K\r"
printf "${CGreen}\r[Tailscale Service settings out-of-sync]"
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - ERROR: Tailscale Service settings are out-of-sync." >> $logfile
sleep 1
tsdown
stopts
#make mods to the S06tailscaled service for Userspace mode
if [ "$tsoperatingmode" == "Userspace" ]; then
applyuserspacemode
#make mods to the S06tailscaled service for Kernel mode
elif [ "$tsoperatingmode" == "Kernel" ]; then
applykernelmode
#make mods to the S06tailscaled service for Custom mode
elif [ "$tsoperatingmode" == "Custom" ]; then
applycustomchanges
fi
printf "\33[2K\r"
printf "${CGreen}\r[Tailscale Service settings synced]"
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - ERROR: Tailscale Service settings synced." >> $logfile
sleep 1
startts
tsup
echo ""
sendmessage 1 "Tailscale Service settings out-of-sync"
resettimer=1
fi
fi
#Determine if Tailscale service is down
if [ $tsinstalled -eq 1 ] && [ $keepalive -eq 1 ]; then
if [ $tsservice -ne 0 ]; then
printf "\33[2K\r"
printf "${CGreen}\r[Tailscale Service appears dead]"
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - ERROR: Tailscale Service appears dead." >> $logfile
sleep 1
startts
tsup
resettimer=1
echo ""
sendmessage 1 "Tailscale Service Restarted"
fi
fi
#Determine if router rebooted
#uptime=$(awk '{printf("%03dd %02dh %02dm %02ds\n",($1/60/60/24),($1/60/60%24),($1/60%60),($1%60))}' /proc/uptime)
uptimedays=$(awk '{printf("%1d\n",($1/60/60/24))}' /proc/uptime)
uptimehrs=$(awk '{printf("%1d\n",($1/60/60%24))}' /proc/uptime)
uptimemins=$(awk '{printf("%1d\n",($1/60%60))}' /proc/uptime)
if [ $uptimedays -eq 0 ] && [ $uptimehrs -eq 0 ] && [ $uptimemins -le 10 ] && [ $routerboot -eq 0 ]; then
# Router must have rebooted and send a notification
printf "\33[2K\r"
printf "${CGreen}\r[Router appears to have been restarted]"
echo -e "$(date +'%b %d %Y %X') $($timeoutcmd$timeoutsec nvram get lan_hostname) TAILMON[$$] - WARNING: Router appears to have been unexpectedly restarted." >> $logfile
sleep 1
echo ""
sendmessage 1 "Router has been restarted"
routerboot=1
fi
#display a standard timer
if [ "$resettimer" == "0" ]; then
timer=0
while [ $timer -ne $timerloop ]
do
timer=$(($timer+1))
preparebar 46 "|"
progressbaroverride $timer $timerloop "" "s" "Standard"
if [ "$resettimer" == "1" ]; then timer=$timerloop; fi
done
fi
resettimer=0
done
exit 0