#!/bin/bash LISTADDR="http://www.vpngate.net/api/iphone/" LISTFILE="servers" DATADIR="/usr/share/vpngate" RETVAL="" DIALOG="dialog" OPENVPN="openvpn" LAST_MNU_MAIN="" LAST_MNU_SORT="" LAST_MNU_SORT_DIR="" LAST_MNU_VPNCONNECT="" VPN_LOGIN="vpn" VPN_PASS="vpn" AUTH_FILE="vpngate.auth" AUTH_DIR="$DATADIR" LOG_FILE="" LOG_TTYN="" RMLOG=0 LOG_APPEND=0 menu_main() { OK_C=0 ESC_C=255 CANCEL_C=1 $DIALOG --clear --title "MAIN MENU" \ --default-item "$LAST_MNU_MAIN" \ --menu "Select action:" 20 51 9 \ "U" "Update VPN List" \ "S" "Sort List by..." \ "I" "Sort direction..." \ "O" "VPN Options..." \ "C" "Connect VPN..." \ "D" "Disconnect..." \ "R" "Reconnect..." \ "A" "About..." \ "X" "Exit" 2>"$DATADIR/dlgres.tmp" RETVAL=$? case "$RETVAL" in $OK_C) RETVAL=`cat "$DATADIR/dlgres.tmp"` LAST_MNU_MAIN="$RETVAL" ;; $ESC_C) rm "$DATADIR/dlgres.tmp" exit ;; $CANCEL_C) rm "$DATADIR/dlgres.tmp" exit ;; esac } menu_sort() { MNUFILE="$DATADIR/sortmenu.txt" OK_C=0 ESC_C=255 CANCEL_C=1 if [ ! -e "$MNUFILE" ]; then messagebox "ERROR" "File $MNUFILE not found! \n \ Data not downloaded?" return 1 fi if [ -e "$DATADIR/sort.field" ]; then LAST_MNU_SORT=`cat "$DATADIR/sort.field"|xargs` fi $DIALOG --clear \ --default-item "$LAST_MNU_SORT" \ --title "Sort field" \ --menu "Select option:" \ 20 51 10 \ --file "$MNUFILE" 2>"$DATADIR/dlgres.tmp" RETVAL=$? case "$RETVAL" in $OK_C) RETVAL=`cat "$DATADIR/dlgres.tmp"` if [ "$RETVAL" == "B" ]; then #back to main menu, not change sort return 1 else echo "$RETVAL" >"$DATADIR/sort.field" fi ;; $ESC_C) return 1;; $CANCEL_C) return 1;; esac } menu_sort_dir() { OK_C=0 ESC_C=255 CANCEL_C=1 if [ -e "$DATADIR/sort.order" ]; then LAST_MNU_SORT_DIR=`cat "$DATADIR/sort.order"|xargs` fi $DIALOG --clear --title "Sort direction" \ --default-item "$LAST_MNU_SORT_DIR" \ --menu "Select direction:" 20 51 4 \ "A" "Ascending" \ "D" "Descending" \ "B" "Back to main menu" 2>"$DATADIR/dlgres.tmp" RETVAL=$? case "$RETVAL" in $OK_C) RETVAL=`cat "$DATADIR/dlgres.tmp"` if [ "$RETVAL" == "B" ]; then #back to main menu, not change sort return 1 else echo "$RETVAL" >"$DATADIR/sort.order" fi ;; $ESC_C) return 1;; $CANCEL_C) return 1;; esac } menu_vpnconnect() { OK_C=0 ESC_C=255 CANCEL_C=1 EXTRA_C=3 MNUFILE="$DATADIR/vpnmenu.txt" if [ ! -e "$DATADIR/$LISTFILE" ]; then messagebox "ERROR" "File $DATADIR/$LISTFILE not found! \n / VPN Data not downloaded?" return fi cat "$DATADIR/$LISTFILE" | awk -F, \ '{ HOST_NAME = $1; IP = $2; SCORE = $3; PING = $4; SPEED = $5; COUNTRY = $6; COUNTRYSHORT = $7; NUMVPNSESSION = $8; UPTIME = $9; TOTALUSERS = $10; TOTALTRAFFIC = $11; LOGTYPE = $12; OPERATOR = $13; MSG = $14; printf \ "\"%i %s(%s,%s)\" \"%s|%s|%s|%s\"" \ " \"Uptime:%s Users:%s Traffic:%s Log:%s\" \\\n", ++j, HOST_NAME, IP, COUNTRYSHORT, SCORE, PING, SPEED, NUMVPNSESSION, UPTIME, TOTALUSERS, TOTALTRAFFIC, LOGTYPE; }' > $MNUFILE #build dynamic menu from file $DIALOG --clear \ --item-help \ --extra-button \ --extra-label "Info" \ --column-separator "|" \ --title "Select VPN" \ --default-item "$LAST_MNU_VPNCONNECT" \ --menu "Select VPN: HostName (IP, Country Code) Score Ping Speed Sessions" \ 20 76 10 \ --file "$MNUFILE" 2>"$DATADIR/dlgres.tmp" RETVAL=$? case "$RETVAL" in $OK_C) RETVAL=`cat "$DATADIR/dlgres.tmp"` LAST_MNU_VPNCONNECT="$RETVAL" return 0 ;; $ESC_C) return 1;; $CANCEL_C) return 1;; $EXTRA_C) RETVAL=`cat "$DATADIR/dlgres.tmp"` show_vpndata "$RETVAL" LAST_MNU_VPNCONNECT="$RETVAL" return 2 esac } messagebox() #1 - title $2 - message { $DIALOG --title "$1" --msgbox "$2" 10 41 } yesnobox() #1 - title $2 - message { OK_C=0 ESC_C=255 CANCEL_C=1 ERROR_C=254 $DIALOG --title "$1" --yesno "$2" 10 41 RETVAL=$? case "$RETVAL" in $OK_C) RETVAL="YES" return 0 ;; $ESC_C) RETVAL="NO" return 0 ;; $CANCEL_C) RETVAL="NO" return 0 ;; $ERROR_C) messagebox "ERROR!" "Dialog error!" exit 1 esac } show_process() #$1 - message { PROCLOG="$PROCLOG$1" $DIALOG --title "Process" --infobox "$PROCLOG" 20 70 } edit_options() { OK_C=0 ESC_C=255 CANCEL_C=1 ERROR_C=254 INPUTFILE="$DATADIR/options.txt" if [ ! -e "$INPUTFILE" ]; then touch "$INPUTFILE" fi $DIALOG --title "Edit options ($INPUTFILE)" \ --fixed-font --editbox $INPUTFILE 0 0 2>"$DATADIR/dlgres.tmp" RETVAL=$? case "$RETVAL" in $OK_C) #save options rm "$DATADIR/options.txt" mv "$DATADIR/dlgres.tmp" "$DATADIR/options.txt" return 0 ;; $ESC_C) return 1;; $CANCEL_C) return 1;; $ERROR_C) messagebox "ERROR" "Dialog error!" return 2 ;; esac } show_vpndata() #$1 - string number from Select VPN dialog { STRNO=`echo "$1"|awk '{print $1}'` TMPSTRING=`sed -n "$STRNO"p "$DATADIR/$LISTFILE"` eval $(echo $TMPSTRING|awk -F "," '{print "HOST_NAME="dq $1 dq; print "IP="dq $2 dq;print "SCORE=" dq $3 dq;print "PING=" dq $4 dq; print "SPEED=" dq $5 dq;print "COUNTRY=" dq $6 dq; print "COUNTRYSHORT=" dq $7 dq; print "NUMVPNSESSION=" dq $8 dq; print "UPTIME=" dq $9 dq;print "TOTALUSERS=" dq $10 dq; print "TOTALTRAFFIC=" dq $11 dq;print "LOGTYPE=" dq $12 dq; print "OPERATOR=" dq $13 dq;print "MSG=" dq $14 dq }' dq='"') VPNDATA=" Host name: $HOST_NAME\n IP: $IP\n Score: $SCORE\n" VPNDATA=$VPNDATA" Ping: $PING\n Speed: $SPEED\n Country: $COUNTRY\n" VPNDATA=$VPNDATA" Country code: $COUNTRYSHORT\n VPN sessions: $NUMVPNSESSION\n" VPNDATA=$VPNDATA" Uptime: $UPTIME\n Total users: $TOTALUSERS\n" VPNDATA=$VPNDATA" Total traffic: $TOTALTRAFFIC\n Log type: $LOGTYPE\n" VPNDATA=$VPNDATA" Operator: $OPERATOR\n Message: $MSG\n" $DIALOG --title "Information" \ --infobox "$VPNDATA \n Press any key..." 25 50 read -n 1 -s -r } build_sortmenu() #$1 - DB (CSV) header { if [ -e "$DATADIR/sortmenu.txt" ]; then rm "$DATADIR/sortmenu.txt" fi IFS_=$IFS IFS=$'\n' J=0 for TMPSTRING in $(echo "$1"|sed -e $'s~,~\\n~g'); do let "J+=1" B64=`echo "$TMPSTRING"|grep -c 'Base64'` if [ $B64 -ne 0 ]; then continue fi MENUSTR="\"$J\" \"$TMPSTRING\" \\" echo "$MENUSTR" >> "$DATADIR/sortmenu.txt" done IFS=$IFS_ } update_vpnlist() { show_process "Download VPN List...\n" wget --progress=dot -O "$DATADIR/$LISTFILE" --tries=3 --timeout=30 "$LISTADDR" 2>&1 |\ stdbuf -o0 awk '/[.] +[0-9][0-9]?[0-9]?%/ { print substr($0,63,3) }' | \ dialog --gauge "Download VPN List from $LISTADDR" 10 100 RETVAL=$? MINSIZE="10" #minimal file size (in bytes) #check file size CURSIZE=`du -sb "$DATADIR/$LISTFILE"|awk '{print $1}'` if [ "$CURSIZE" -le "MINSIZE" ]; then RETVAL="9" fi case "$RETVAL" in 0) show_process "OK\n" ;; 1) messagebox "Error" "Generic error ($RETVAL)" ;; 2) messagebox "Error" "Command line or config error ($RETVAL)" ;; 3) messagebox "Error" "I/O error ($RETVAL)" ;; 4) messagebox "Error" "Network failure ($RETVAL)" ;; 5) messagebox "Error" "SSL verification failure ($RETVAL)" ;; 6) messagebox "Error" "Username/password authentication failure ($RETVAL)" ;; 7) messagebox "Error" "Protocol error ($RETVAL)" ;; 8) messagebox "Error" "Server error ($RETVAL)" ;; 9) messagebox "Error" "Small file size ($CURSIZE <= minimal file size $MINSIZE). Download error?" ;; *) messagebox "Error" "Unknow error ($RETVAL)" ;; esac #remove wrong file if exist if [ "$RETVAL" -ne 0 ];then if [ -e "$DATADIR/$LISTFILE" ];then rm "$DATADIR/$LISTFILE" return "$RETVAL" fi fi show_process "Converting WIN --> Linux...\n" sed -i 's~\x0D$~~' "$DATADIR/$LISTFILE" show_process "Removing * strings...\n" sed -i '/^*/d' "$DATADIR/$LISTFILE" TMPSTRING=`grep '^#' "$DATADIR/$LISTFILE"` build_sortmenu "$TMPSTRING" show_process "Remove header from database...\n" sed -i '/^#/d' "$DATADIR/$LISTFILE" show_process "Remove old sort settings...\n" rm "$DATADIR/sort.field" rm "$DATADIR/sort.order" show_process "Complete!\nPress any key to return in main menu..." read -n 1 -s -r } sort_data() { SORTFIELD="" SORTDIR="" if [ ! -e "$DATADIR/$LISTFILE" ]; then messagebox "ERROR" "File $DATADIR/$LISTFILE not found! \n / VPN Data not downloaded?" return fi if [ ! -e "$DATADIR/sort.field" ]; then SORTFIELD="1" else SORTFIELD=`cat "$DATADIR/sort.field" | xargs` fi if [ ! -e "$DATADIR/sort.order" ]; then SORTDIR="A" else SORTDIR=`cat "$DATADIR/sort.order" | xargs` fi if [ -z "$SORTFIELD" ];then SORTFIELD="1" fi if [ -z "$SORTDIR" ];then SORTDIR="A" fi PROCLOG="" if [ "$SORTDIR" == "A" ];then show_process "Sort direction: Ascending\n" else show_process "Sort direction: Descending\n" fi FIELD_NAME=`cat "$DATADIR/header.txt"|grep -w "$SORTFIELD"` show_process "Field name: $FIELD_NAME\n" show_process "Sorting...\n" if [ "$SORTDIR" == "A" ];then sort -k$SORTFIELD -t"," "$DATADIR/$LISTFILE" > "$DATADIR/$LISTFILE.tmp" else sort -k$SORTFIELD -r -t"," "$DATADIR/$LISTFILE" > "$DATADIR/$LISTFILE.tmp" fi rm "$DATADIR/$LISTFILE" mv "$DATADIR/$LISTFILE.tmp" "$DATADIR/$LISTFILE" show_process "Complete!\nPress any key to return in main menu..." read -n 1 -s -r } prepare_connect() #$1 - selected VPN { #get VPN string from VPN database STRNO=`echo "$1"|awk '{print $1}'` TMPSTRING=`sed -n "$STRNO"p "$DATADIR/$LISTFILE"` #get base64 encoded config echo "$TMPSTRING"|awk -F "," '{print $15}' >"$DATADIR/base64.tmp" #decode config base64 -d "$DATADIR/base64.tmp" > "$DATADIR/vpngate.ovpn" rm "$DATADIR/base64.tmp" #change Windows line endings to Linux line endings sed -i 's/\r$//' "$DATADIR/vpngate.ovpn" #write auth file echo "$VPN_LOGIN" > "$AUTH_DIR/$AUTH_FILE" echo "$VPN_PASS" >> "$AUTH_DIR/$AUTH_FILE" #remove comments grep -o '^[^#]*' "$DATADIR/vpngate.ovpn" >"$DATADIR/vpngate.tmp" rm "$DATADIR/vpngate.ovpn" mv "$DATADIR/vpngate.tmp" "$DATADIR/vpngate.ovpn" #add (or replace) VPN options IFS_=$IFS IFS=$'\n' for TMPSTRING in $(cat "$DATADIR/options.txt"); do TMPSTRING=`echo "$TMPSTRING"` if [ -z "$TMPSTRING" ]; then continue fi CMND_ST=`echo "$TMPSTRING" |awk '{print $1}'` CMND_COUNT=`grep -c -w "$CMND_ST" "$DATADIR/vpngate.ovpn"` #echo "$CMND_ST $CMND_COUNT" if [ "$CMND_COUNT" -eq 0 ];then #not found, add sed -i -e "1 s%^%$TMPSTRING\n%" "$DATADIR/vpngate.ovpn" else #found, replace sed -i "s%^ *$CMND_ST.*%$TMPSTRING%" "$DATADIR/vpngate.ovpn" fi done IFS=$IFS_ } ovpn_down() { CH_S[0]='-' #pseudographic items CH_S[1]='/' CH_S[2]='|' CH_S[3]='\' CTR=0 PGNO=0 pkill $OPENVPN while [ "$CTR" -ne "1" ];do CTR=`ps ax|grep -c "$OPENVPN"` dialog --sleep 1 \ --title "Disconnecting" \ --infobox "Wait for shutdown Openvpn:${CH_S[PGNO]}" 3 35 let "PGNO=PGNO+1" if [ "$PGNO" -eq 4 ];then PGNO=0 fi done } ovpn_up() { OVPN_CMD="$OPENVPN --config $DATADIR/vpngate.ovpn" if [ -z "$LOG_FILE" ]; then LOG_FILE="$DATADIR/log.tmp" RMLOG=1 LOG_APPEND=0 fi if [ -z "$LOG_TTYN" ];then #no TTY, only log if [ "$LOG_APPEND" -eq 1 ];then #append log $OVPN_CMD >>"$LOG_FILE" & else #new log $OVPN_CMD >"$LOG_FILE" & fi else #log and tty if [ "$LOG_APPEND" -eq 1 ];then #append log $OVPN_CMD |tee -a "$LOG_FILE" >/dev/tty"$LOG_TTYN" & else #new log $OVPN_CMD |tee "$LOG_FILE" >/dev/tty"$LOG_TTYN" & fi fi $DIALOG --title "Connection log" "$@" \ --exit-label "Return to main menu" \ --tailbox "$LOG_FILE" 24 70 if [ "$RMLOG" -eq 1 ]; then rm "$LOG_FILE" fi } check_soft() { #check software $1 >/dev/null 2>/dev/null RETVAL=$? if [ "$RETVAL" -eq 126 ]; then echo "$1 access denied or not execute file!" exit 1 fi if [ "$RETVAL" -eq 127 ]; then echo "$1 not found!" echo "Install software or set path to software in script variable $2." exit 1 fi } check_soft "$DIALOG" "DIALOG" #check dialog utility check_soft "$OPENVPN" "OPENVPN" #check openvpn utility mkdir -p "$DATADIR" while [ 1 -eq 1 ];do menu_main case "$RETVAL" in "U") PROCLOG="" update_vpnlist ;; "S") menu_sort if [ $? -eq 1 ];then continue fi sort_data ;; "I") menu_sort_dir if [ $? -eq 1 ];then continue fi sort_data ;; "O") edit_options if [ $? -eq 0 ];then messagebox "Saved" "Options saved!" fi ;; "C") if [ ! -e "$DATADIR/$LISTFILE" ]; then $DIALOG --title "Information" \ --infobox "Loading, please wait..." 5 30 build_vpnmenu if [ $? -eq 1 ];then continue fi fi RC=2 while [ "$RC" -eq 2 ];do menu_vpnconnect #return to VPN Connect menu after info request RC=$? done if [ "$RC" -eq 0 ];then #connect prepare_connect "$RETVAL" ovpn_down ovpn_up continue fi ;; "D") yesnobox "Disconnect" "Disconnect VPN?" if [ "$RETVAL" == "YES" ]; then ovpn_down fi ;; "R") #reconnect if [ ! -e "$DATADIR/vpngate.ovpn" ]; then messagebox "Error" "File $DATADIR/vpngate.ovpn not found. Select VPN." continue fi yesnobox "Reconnect" "Reconnect VPN?" if [ "$RETVAL" == "YES" ]; then ovpn_down ovpn_up fi ;; "A") #about messagebox "About" " vpngate.net console client \n support site tolik-punkoff.com\n lj.rossia.org/users/hex_laden\n Telegram: @eternalsavage\n\n (L) ChaosSoft 2020" ;; "X") clear exit 0 ;; esac done