menu.sh 120 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876
  1. #!/bin/bash
  2. C_RESET=$'\033[0m'
  3. C_BOLD=$'\033[1m'
  4. C_DIM=$'\033[2m'
  5. C_UL=$'\033[4m'
  6. # Premium Color Palette
  7. C_RED=$'\033[38;5;196m' # Bright Red
  8. C_GREEN=$'\033[38;5;46m' # Neon Green
  9. C_YELLOW=$'\033[38;5;226m' # Bright Yellow
  10. C_BLUE=$'\033[38;5;39m' # Deep Sky Blue
  11. C_PURPLE=$'\033[38;5;135m' # Light Purple
  12. C_CYAN=$'\033[38;5;51m' # Cyan
  13. C_WHITE=$'\033[38;5;255m' # Bright White
  14. C_GRAY=$'\033[38;5;245m' # Gray
  15. C_ORANGE=$'\033[38;5;208m' # Orange
  16. # Semantic Aliases
  17. C_TITLE=$C_PURPLE
  18. C_CHOICE=$C_CYAN
  19. C_PROMPT=$C_BLUE
  20. C_WARN=$C_YELLOW
  21. C_DANGER=$C_RED
  22. C_STATUS_A=$C_GREEN
  23. C_STATUS_I=$C_GRAY
  24. C_ACCENT=$C_ORANGE
  25. DB_DIR="/etc/firewallfalcon"
  26. DB_FILE="$DB_DIR/users.db"
  27. INSTALL_FLAG_FILE="$DB_DIR/.install"
  28. BADVPN_SERVICE_FILE="/etc/systemd/system/badvpn.service"
  29. BADVPN_BUILD_DIR="/root/badvpn-build"
  30. HAPROXY_CONFIG="/etc/haproxy/haproxy.cfg"
  31. NGINX_CONFIG_FILE="/etc/nginx/sites-available/default"
  32. SSL_CERT_DIR="/etc/firewallfalcon/ssl"
  33. SSL_CERT_FILE="$SSL_CERT_DIR/firewallfalcon.pem"
  34. NGINX_PORTS_FILE="$DB_DIR/nginx_ports.conf"
  35. DNSTT_SERVICE_FILE="/etc/systemd/system/dnstt.service"
  36. DNSTT_BINARY="/usr/local/bin/dnstt-server"
  37. DNSTT_KEYS_DIR="/etc/firewallfalcon/dnstt"
  38. DNSTT_CONFIG_FILE="$DB_DIR/dnstt_info.conf"
  39. DNS_INFO_FILE="$DB_DIR/dns_info.conf"
  40. UDP_CUSTOM_DIR="/root/udp"
  41. UDP_CUSTOM_SERVICE_FILE="/etc/systemd/system/udp-custom.service"
  42. SSH_BANNER_FILE="/etc/bannerssh"
  43. FALCONPROXY_SERVICE_FILE="/etc/systemd/system/falconproxy.service"
  44. FALCONPROXY_BINARY="/usr/local/bin/falconproxy"
  45. FALCONPROXY_CONFIG_FILE="$DB_DIR/falconproxy_config.conf"
  46. LIMITER_SCRIPT="/usr/local/bin/firewallfalcon-limiter.sh"
  47. LIMITER_SERVICE="/etc/systemd/system/firewallfalcon-limiter.service"
  48. # --- ZiVPN Variables ---
  49. ZIVPN_DIR="/etc/zivpn"
  50. ZIVPN_BIN="/usr/local/bin/zivpn"
  51. ZIVPN_SERVICE_FILE="/etc/systemd/system/zivpn.service"
  52. ZIVPN_CONFIG_FILE="$ZIVPN_DIR/config.json"
  53. ZIVPN_CERT_FILE="$ZIVPN_DIR/zivpn.crt"
  54. ZIVPN_KEY_FILE="$ZIVPN_DIR/zivpn.key"
  55. DESEC_TOKEN="V55cFY8zTictLCPfviiuX5DHjs15"
  56. DESEC_DOMAIN="firewallfalcon.thefirewoods.org"
  57. SELECTED_USER=""
  58. UNINSTALL_MODE="interactive"
  59. if [[ $EUID -ne 0 ]]; then
  60. echo -e "${C_RED}❌ Error: This script requires root privileges to run.${C_RESET}"
  61. exit 1
  62. fi
  63. # Mandatory Dependency Check (Added jq and curl)
  64. check_environment() {
  65. # Mandatory Dependency Check (Added jq and curl)
  66. for cmd in bc jq curl wget; do
  67. if ! command -v $cmd &> /dev/null; then
  68. echo -e "${C_YELLOW}⚠️ Warning: '$cmd' not found. Installing...${C_RESET}"
  69. apt-get update > /dev/null 2>&1 && apt-get install -y $cmd || {
  70. echo -e "${C_RED}❌ Error: Failed to install '$cmd'. Please install it manually.${C_RESET}"
  71. exit 1
  72. }
  73. fi
  74. done
  75. }
  76. initial_setup() {
  77. echo -e "${C_BLUE}⚙️ Initializing FirewallFalcon Manager setup...${C_RESET}"
  78. check_environment
  79. mkdir -p "$DB_DIR"
  80. touch "$DB_FILE"
  81. mkdir -p "$SSL_CERT_DIR"
  82. echo -e "${C_BLUE}🔹 Configuring user limiter service...${C_RESET}"
  83. setup_limiter_service
  84. if [ ! -f "$INSTALL_FLAG_FILE" ]; then
  85. touch "$INSTALL_FLAG_FILE"
  86. fi
  87. echo -e "${C_GREEN}✅ Setup finished.${C_RESET}"
  88. }
  89. _is_valid_ipv4() {
  90. local ip=$1
  91. if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
  92. return 0
  93. else
  94. return 1
  95. fi
  96. }
  97. check_and_open_firewall_port() {
  98. local port="$1"
  99. local protocol="${2:-tcp}"
  100. local firewall_detected=false
  101. if command -v ufw &> /dev/null && ufw status | grep -q "Status: active"; then
  102. firewall_detected=true
  103. if ! ufw status | grep -qw "$port/$protocol"; then
  104. echo -e "${C_YELLOW}🔥 UFW firewall is active and port ${port}/${protocol} is closed.${C_RESET}"
  105. read -p "👉 Do you want to open this port now? (y/n): " confirm
  106. if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
  107. ufw allow "$port/$protocol"
  108. echo -e "${C_GREEN}✅ Port ${port}/${protocol} has been opened in UFW.${C_RESET}"
  109. else
  110. echo -e "${C_RED}❌ Warning: Port ${port}/${protocol} was not opened. The service may not work correctly.${C_RESET}"
  111. return 1
  112. fi
  113. else
  114. echo -e "${C_GREEN}✅ Port ${port}/${protocol} is already open in UFW.${C_RESET}"
  115. fi
  116. fi
  117. if command -v firewall-cmd &> /dev/null && systemctl is-active --quiet firewalld; then
  118. firewall_detected=true
  119. if ! firewall-cmd --list-ports --permanent | grep -qw "$port/$protocol"; then
  120. echo -e "${C_YELLOW}🔥 firewalld is active and port ${port}/${protocol} is not open.${C_RESET}"
  121. read -p "👉 Do you want to open this port now? (y/n): " confirm
  122. if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
  123. firewall-cmd --add-port="$port/$protocol" --permanent
  124. firewall-cmd --reload
  125. echo -e "${C_GREEN}✅ Port ${port}/${protocol} has been opened in firewalld.${C_RESET}"
  126. else
  127. echo -e "${C_RED}❌ Warning: Port ${port}/${protocol} was not opened. The service may not work correctly.${C_RESET}"
  128. return 1
  129. fi
  130. else
  131. echo -e "${C_GREEN}✅ Port ${port}/${protocol} is already open in firewalld.${C_RESET}"
  132. fi
  133. fi
  134. if ! $firewall_detected; then
  135. echo -e "${C_BLUE}ℹ️ No active firewall (UFW or firewalld) detected. Assuming ports are open.${C_RESET}"
  136. fi
  137. return 0
  138. }
  139. check_and_free_ports() {
  140. local ports_to_check=("$@")
  141. for port in "${ports_to_check[@]}"; do
  142. echo -e "\n${C_BLUE}🔎 Checking if port $port is available...${C_RESET}"
  143. local conflicting_process_info
  144. conflicting_process_info=$(ss -lntp | grep ":$port\s" || ss -lunp | grep ":$port\s")
  145. if [[ -n "$conflicting_process_info" ]]; then
  146. local conflicting_pid
  147. conflicting_pid=$(echo "$conflicting_process_info" | grep -oP 'pid=\K[0-9]+' | head -n 1)
  148. local conflicting_name
  149. conflicting_name=$(echo "$conflicting_process_info" | grep -oP 'users:\(\("(\K[^"]+)' | head -n 1)
  150. echo -e "${C_YELLOW}⚠️ Warning: Port $port is in use by process '${conflicting_name:-unknown}' (PID: ${conflicting_pid:-N/A}).${C_RESET}"
  151. read -p "👉 Do you want to attempt to stop this process? (y/n): " kill_confirm
  152. if [[ "$kill_confirm" == "y" || "$kill_confirm" == "Y" ]]; then
  153. echo -e "${C_GREEN}🛑 Stopping process PID $conflicting_pid...${C_RESET}"
  154. systemctl stop "$(ps -p "$conflicting_pid" -o comm=)" &>/dev/null || kill -9 "$conflicting_pid"
  155. sleep 2
  156. if ss -lntp | grep -q ":$port\s" || ss -lunp | grep -q ":$port\s"; then
  157. echo -e "${C_RED}❌ Failed to free port $port. Please handle it manually. Aborting.${C_RESET}"
  158. return 1
  159. else
  160. echo -e "${C_GREEN}✅ Port $port has been successfully freed.${C_RESET}"
  161. fi
  162. else
  163. echo -e "${C_RED}❌ Cannot proceed without freeing port $port. Aborting.${C_RESET}"
  164. return 1
  165. fi
  166. else
  167. echo -e "${C_GREEN}✅ Port $port is free to use.${C_RESET}"
  168. fi
  169. done
  170. return 0
  171. }
  172. setup_limiter_service() {
  173. # Updated logic: No logging, smart 120s lockout
  174. cat > "$LIMITER_SCRIPT" << 'EOF'
  175. #!/bin/bash
  176. DB_FILE="/etc/firewallfalcon/users.db"
  177. # Loop continuously with optimized sleep
  178. while true; do
  179. if [[ ! -f "$DB_FILE" ]]; then
  180. sleep 30
  181. continue
  182. fi
  183. current_ts=$(date +%s)
  184. # Cache active users to minimize pgrep calls inside loop
  185. # Get count of sshd processes per user in one go is hard in bash without map,
  186. # so we optimize the per-user check.
  187. while IFS=: read -r user pass expiry limit; do
  188. [[ -z "$user" || "$user" == \#* ]] && continue
  189. # 1. Active Check (Skip if user has no processes to save CPU)
  190. # pgrep -u is relatively cheap, but let's be smart.
  191. # If connection limit is huge, we might not care.
  192. # --- Expiry Check ---
  193. # Only check expiry if we have a valid expiry date
  194. if [[ "$expiry" != "Never" && "$expiry" != "" ]]; then
  195. expiry_ts=$(date -d "$expiry" +%s 2>/dev/null || echo 0)
  196. if [[ $expiry_ts -lt $current_ts && $expiry_ts -ne 0 ]]; then
  197. if ! passwd -S "$user" | grep -q " L "; then
  198. usermod -L "$user" &>/dev/null
  199. killall -u "$user" -9 &>/dev/null
  200. fi
  201. continue
  202. fi
  203. fi
  204. # --- Connection Limit Check ---
  205. # Optimization: pgrep -c is faster than pipe to wc
  206. online_count=$(pgrep -c -u "$user" sshd)
  207. if ! [[ "$limit" =~ ^[0-9]+$ ]]; then limit=1; fi
  208. if [[ "$online_count" -gt "$limit" ]]; then
  209. if ! passwd -S "$user" | grep -q " L "; then
  210. usermod -L "$user" &>/dev/null
  211. killall -u "$user" -9 &>/dev/null
  212. (sleep 120; usermod -U "$user" &>/dev/null) &
  213. else
  214. killall -u "$user" -9 &>/dev/null
  215. fi
  216. fi
  217. done < "$DB_FILE"
  218. # Sleep increased to 25 seconds to reduce CPU load
  219. sleep 25
  220. done
  221. EOF
  222. chmod +x "$LIMITER_SCRIPT"
  223. cat > "$LIMITER_SERVICE" << EOF
  224. [Unit]
  225. Description=FirewallFalcon Active User Limiter
  226. After=network.target
  227. [Service]
  228. Type=simple
  229. ExecStart=$LIMITER_SCRIPT
  230. Restart=always
  231. RestartSec=5
  232. [Install]
  233. WantedBy=multi-user.target
  234. EOF
  235. # Force kill any old limiter process to prevent systemctl restart hanging
  236. pkill -f "firewallfalcon-limiter" 2>/dev/null
  237. if ! systemctl is-active --quiet firewallfalcon-limiter; then
  238. systemctl daemon-reload
  239. systemctl enable firewallfalcon-limiter &>/dev/null
  240. systemctl start firewallfalcon-limiter --no-block &>/dev/null
  241. else
  242. # Restart if already running to apply new logic
  243. systemctl restart firewallfalcon-limiter --no-block &>/dev/null
  244. fi
  245. }
  246. generate_dns_record() {
  247. echo -e "\n${C_BLUE}⚙️ Generating a random domain...${C_RESET}"
  248. if ! command -v jq &> /dev/null; then
  249. echo -e "${C_YELLOW}⚠️ jq not found, attempting to install...${C_RESET}"
  250. apt-get update > /dev/null 2>&1 && apt-get install -y jq || {
  251. echo -e "${C_RED}❌ Failed to install jq. Cannot manage DNS records.${C_RESET}"
  252. return 1
  253. }
  254. fi
  255. local SERVER_IPV4
  256. SERVER_IPV4=$(curl -s -4 icanhazip.com)
  257. if ! _is_valid_ipv4 "$SERVER_IPV4"; then
  258. echo -e "\n${C_RED}❌ Error: Could not retrieve a valid public IPv4 address from icanhazip.com.${C_RESET}"
  259. echo -e "${C_YELLOW}ℹ️ Please check your server's network connection and DNS resolver settings.${C_RESET}"
  260. echo -e " Output received: '$SERVER_IPV4'"
  261. return 1
  262. fi
  263. local SERVER_IPV6
  264. SERVER_IPV6=$(curl -s -6 icanhazip.com --max-time 5)
  265. local RANDOM_SUBDOMAIN="vps-$(head /dev/urandom | tr -dc a-z0-9 | head -c 8)"
  266. local FULL_DOMAIN="$RANDOM_SUBDOMAIN.$DESEC_DOMAIN"
  267. local HAS_IPV6="false"
  268. local API_DATA
  269. API_DATA=$(printf '[{"subname": "%s", "type": "A", "ttl": 3600, "records": ["%s"]}]' "$RANDOM_SUBDOMAIN" "$SERVER_IPV4")
  270. if [[ -n "$SERVER_IPV6" ]]; then
  271. local aaaa_record
  272. aaaa_record=$(printf ',{"subname": "%s", "type": "AAAA", "ttl": 3600, "records": ["%s"]}' "$RANDOM_SUBDOMAIN" "$SERVER_IPV6")
  273. API_DATA="${API_DATA%?}${aaaa_record}]"
  274. HAS_IPV6="true"
  275. fi
  276. local CREATE_RESPONSE
  277. CREATE_RESPONSE=$(curl -s -w "%{http_code}" -X POST "https://desec.io/api/v1/domains/$DESEC_DOMAIN/rrsets/" \
  278. -H "Authorization: Token $DESEC_TOKEN" -H "Content-Type: application/json" \
  279. --data "$API_DATA")
  280. local HTTP_CODE=${CREATE_RESPONSE: -3}
  281. local RESPONSE_BODY=${CREATE_RESPONSE:0:${#CREATE_RESPONSE}-3}
  282. if [[ "$HTTP_CODE" -ne 201 ]]; then
  283. echo -e "${C_RED}❌ Failed to create DNS records. API returned HTTP $HTTP_CODE.${C_RESET}"
  284. if ! echo "$RESPONSE_BODY" | jq . > /dev/null 2>&1; then
  285. echo "Raw Response: $RESPONSE_BODY"
  286. else
  287. echo "Response: $RESPONSE_BODY" | jq
  288. fi
  289. return 1
  290. fi
  291. cat > "$DNS_INFO_FILE" <<-EOF
  292. SUBDOMAIN="$RANDOM_SUBDOMAIN"
  293. FULL_DOMAIN="$FULL_DOMAIN"
  294. HAS_IPV6="$HAS_IPV6"
  295. EOF
  296. echo -e "\n${C_GREEN}✅ Successfully created domain: ${C_YELLOW}$FULL_DOMAIN${C_RESET}"
  297. }
  298. delete_dns_record() {
  299. if [ ! -f "$DNS_INFO_FILE" ]; then
  300. echo -e "\n${C_YELLOW}ℹ️ No domain to delete.${C_RESET}"
  301. return
  302. fi
  303. echo -e "\n${C_BLUE}🗑️ Deleting DNS records...${C_RESET}"
  304. source "$DNS_INFO_FILE"
  305. if [[ -z "$SUBDOMAIN" ]]; then
  306. echo -e "${C_RED}❌ Could not read record details from config file. Skipping deletion.${C_RESET}"
  307. return
  308. fi
  309. curl -s -X DELETE "https://desec.io/api/v1/domains/$DESEC_DOMAIN/rrsets/$SUBDOMAIN/A/" \
  310. -H "Authorization: Token $DESEC_TOKEN" > /dev/null
  311. if [[ "$HAS_IPV6" == "true" ]]; then
  312. curl -s -X DELETE "https://desec.io/api/v1/domains/$DESEC_DOMAIN/rrsets/$SUBDOMAIN/AAAA/" \
  313. -H "Authorization: Token $DESEC_TOKEN" > /dev/null
  314. fi
  315. echo -e "\n${C_GREEN}✅ Deleted domain: ${C_YELLOW}$FULL_DOMAIN${C_RESET}"
  316. rm -f "$DNS_INFO_FILE"
  317. }
  318. dns_menu() {
  319. clear; show_banner
  320. echo -e "${C_BOLD}${C_PURPLE}--- 🌐 DNS Domain Management ---${C_RESET}"
  321. if [ -f "$DNS_INFO_FILE" ]; then
  322. source "$DNS_INFO_FILE"
  323. echo -e "\nℹ️ A domain already exists for this server:"
  324. echo -e " - ${C_CYAN}Domain:${C_RESET} ${C_YELLOW}$FULL_DOMAIN${C_RESET}"
  325. echo
  326. read -p "👉 Do you want to DELETE this domain? (y/n): " choice
  327. if [[ "$choice" == "y" || "$choice" == "Y" ]]; then
  328. delete_dns_record
  329. else
  330. echo -e "\n${C_YELLOW}❌ Action cancelled.${C_RESET}"
  331. fi
  332. else
  333. echo -e "\nℹ️ No domain has been generated for this server yet."
  334. echo
  335. read -p "👉 Do you want to generate a new random domain now? (y/n): " choice
  336. if [[ "$choice" == "y" || "$choice" == "Y" ]]; then
  337. generate_dns_record
  338. else
  339. echo -e "\n${C_YELLOW}❌ Action cancelled.${C_RESET}"
  340. fi
  341. fi
  342. }
  343. _select_user_interface() {
  344. local title="$1"
  345. clear; show_banner
  346. echo -e "${C_BOLD}${C_PURPLE}${title}${C_RESET}\n"
  347. if [[ ! -s $DB_FILE ]]; then
  348. echo -e "${C_YELLOW}ℹ️ No users found in the database.${C_RESET}"
  349. SELECTED_USER="NO_USERS"; return
  350. fi
  351. read -p "👉 Enter a search term (or press Enter to list all): " search_term
  352. if [[ -z "$search_term" ]]; then
  353. mapfile -t users < <(cut -d: -f1 "$DB_FILE" | sort)
  354. else
  355. mapfile -t users < <(cut -d: -f1 "$DB_FILE" | grep -i "$search_term" | sort)
  356. fi
  357. if [ ${#users[@]} -eq 0 ]; then
  358. echo -e "\n${C_YELLOW}ℹ️ No users found matching your criteria.${C_RESET}"
  359. SELECTED_USER="NO_USERS"; return
  360. fi
  361. echo -e "\nPlease select a user:\n"
  362. for i in "${!users[@]}"; do
  363. printf " ${C_GREEN}[%2d]${C_RESET} %s\n" "$((i+1))" "${users[$i]}"
  364. done
  365. echo -e "\n ${C_RED} [ 0]${C_RESET} ↩️ Cancel and return to main menu"
  366. echo
  367. local choice
  368. while true; do
  369. read -p "👉 Enter the number of the user: " choice
  370. if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 0 ] && [ "$choice" -le "${#users[@]}" ]; then
  371. if [ "$choice" -eq 0 ]; then
  372. SELECTED_USER=""; return
  373. else
  374. SELECTED_USER="${users[$((choice-1))]}"; return
  375. fi
  376. else
  377. echo -e "${C_RED}❌ Invalid selection. Please try again.${C_RESET}"
  378. fi
  379. done
  380. }
  381. get_user_status() {
  382. local username="$1"
  383. if ! id "$username" &>/dev/null; then echo -e "${C_RED}Not Found${C_RESET}"; return; fi
  384. local expiry_date=$(grep "^$username:" "$DB_FILE" | cut -d: -f3)
  385. if passwd -S "$username" 2>/dev/null | grep -q " L "; then echo -e "${C_YELLOW}🔒 Locked${C_RESET}"; return; fi
  386. local expiry_ts=$(date -d "$expiry_date" +%s 2>/dev/null || echo 0)
  387. local current_ts=$(date +%s)
  388. if [[ $expiry_ts -lt $current_ts ]]; then echo -e "${C_RED}🗓️ Expired${C_RESET}"; return; fi
  389. echo -e "${C_GREEN}🟢 Active${C_RESET}"
  390. }
  391. create_user() {
  392. clear; show_banner
  393. echo -e "${C_BOLD}${C_PURPLE}--- ✨ Create New SSH User ---${C_RESET}"
  394. read -p "👉 Enter username (or '0' to cancel): " username
  395. if [[ "$username" == "0" ]]; then
  396. echo -e "\n${C_YELLOW}❌ User creation cancelled.${C_RESET}"
  397. return
  398. fi
  399. if [[ -z "$username" ]]; then
  400. echo -e "\n${C_RED}❌ Error: Username cannot be empty.${C_RESET}"
  401. return
  402. fi
  403. if id "$username" &>/dev/null || grep -q "^$username:" "$DB_FILE"; then
  404. echo -e "\n${C_RED}❌ Error: User '$username' already exists.${C_RESET}"; return
  405. fi
  406. local password=""
  407. while true; do
  408. read -p "🔑 Enter new password: " password
  409. if [[ -z "$password" ]]; then
  410. echo -e "${C_RED}❌ Password cannot be empty. Please try again.${C_RESET}"
  411. else
  412. break
  413. fi
  414. done
  415. read -p "🗓️ Enter account duration (in days): " days
  416. if ! [[ "$days" =~ ^[0-9]+$ ]]; then echo -e "\n${C_RED}❌ Invalid number.${C_RESET}"; return; fi
  417. read -p "📶 Enter simultaneous connection limit: " limit
  418. if ! [[ "$limit" =~ ^[0-9]+$ ]]; then echo -e "\n${C_RED}❌ Invalid number.${C_RESET}"; return; fi
  419. local expire_date
  420. expire_date=$(date -d "+$days days" +%Y-%m-%d)
  421. useradd -m -s /usr/sbin/nologin "$username"; echo "$username:$password" | chpasswd; chage -E "$expire_date" "$username"
  422. echo "$username:$password:$expire_date:$limit" >> "$DB_FILE"
  423. clear; show_banner
  424. echo -e "${C_GREEN}✅ User '$username' created successfully!${C_RESET}\n"
  425. echo -e " - 👤 Username: ${C_YELLOW}$username${C_RESET}"
  426. echo -e " - 🔑 Password: ${C_YELLOW}$password${C_RESET}"
  427. echo -e " - 🗓️ Expires on: ${C_YELLOW}$expire_date${C_RESET}"
  428. echo -e " - 📶 Connection Limit: ${C_YELLOW}$limit${C_RESET}"
  429. echo -e " ${C_DIM}(Active monitoring service will enforce this limit)${C_RESET}"
  430. # Auto-ask for config generation
  431. echo
  432. read -p "👉 Do you want to generate a client connection config for this user? (y/n): " gen_conf
  433. if [[ "$gen_conf" == "y" || "$gen_conf" == "Y" ]]; then
  434. generate_client_config "$username" "$password"
  435. fi
  436. }
  437. delete_user() {
  438. _select_user_interface "--- 🗑️ Delete a User (from DB) ---"
  439. local username=$SELECTED_USER
  440. if [[ "$username" == "NO_USERS" ]] || [[ -z "$username" ]]; then
  441. if [[ "$username" == "NO_USERS" ]]; then
  442. echo -e "\n${C_YELLOW}ℹ️ No users found in database.${C_RESET}"
  443. fi
  444. read -p "👉 Type username to MANUALLY delete (or '0' to cancel): " manual_user
  445. if [[ "$manual_user" == "0" ]] || [[ -z "$manual_user" ]]; then
  446. echo -e "\n${C_YELLOW}❌ Action cancelled.${C_RESET}"
  447. return
  448. fi
  449. username="$manual_user"
  450. if ! id "$username" &>/dev/null; then
  451. echo -e "\n${C_RED}❌ Error: User '$username' does not exist on this system.${C_RESET}"
  452. return
  453. fi
  454. if grep -q "^$username:" "$DB_FILE"; then
  455. echo -e "\n${C_YELLOW}ℹ️ User '$username' is in the database. Please use the normal selection method.${C_RESET}"
  456. echo -e " For safety, manual deletion is only for users NOT in the database."
  457. return
  458. fi
  459. echo -e "${C_YELLOW}⚠️ User '$username' exists on the system but is NOT in the database.${C_RESET}"
  460. fi
  461. read -p "👉 Are you sure you want to PERMANENTLY delete '$username'? (y/n): " confirm
  462. if [[ "$confirm" != "y" ]]; then echo -e "\n${C_YELLOW}❌ Deletion cancelled.${C_RESET}"; return; fi
  463. echo -e "${C_BLUE}🔌 Force killing active connections for $username...${C_RESET}"
  464. killall -u "$username" -9 &>/dev/null
  465. sleep 1
  466. userdel -r "$username" &>/dev/null
  467. if [ $? -eq 0 ]; then
  468. echo -e "\n${C_GREEN}✅ System user '$username' has been deleted.${C_RESET}"
  469. else
  470. echo -e "\n${C_RED}❌ Failed to delete system user '$username'.${C_RESET}"
  471. fi
  472. sed -i "/^$username:/d" "$DB_FILE"
  473. echo -e "${C_GREEN}✅ User '$username' has been completely removed.${C_RESET}"
  474. }
  475. edit_user() {
  476. _select_user_interface "--- ✏️ Edit a User ---"
  477. local username=$SELECTED_USER
  478. if [[ "$username" == "NO_USERS" ]] || [[ -z "$username" ]]; then return; fi
  479. while true; do
  480. clear; show_banner; echo -e "${C_BOLD}${C_PURPLE}--- Editing User: ${C_YELLOW}$username${C_PURPLE} ---${C_RESET}"
  481. echo -e "\nSelect a detail to edit:\n"
  482. printf " ${C_GREEN}[ 1]${C_RESET} %-35s\n" "🔑 Change Password"
  483. printf " ${C_GREEN}[ 2]${C_RESET} %-35s\n" "🗓️ Change Expiration Date"
  484. printf " ${C_GREEN}[ 3]${C_RESET} %-35s\n" "📶 Change Connection Limit"
  485. echo -e "\n ${C_RED}[ 0]${C_RESET} ✅ Finish Editing"; echo; read -p "👉 Enter your choice: " edit_choice
  486. case $edit_choice in
  487. 1)
  488. local new_pass=""
  489. while true; do
  490. read -p "Enter new password: " new_pass
  491. if [[ -z "$new_pass" ]]; then
  492. echo -e "${C_RED}❌ Password cannot be empty. Please try again.${C_RESET}"
  493. else
  494. break
  495. fi
  496. done
  497. echo "$username:$new_pass" | chpasswd
  498. local current_line; current_line=$(grep "^$username:" "$DB_FILE"); local expiry; expiry=$(echo "$current_line" | cut -d: -f3); local limit; limit=$(echo "$current_line" | cut -d: -f4)
  499. sed -i "s/^$username:.*/$username:$new_pass:$expiry:$limit/" "$DB_FILE"
  500. echo -e "\n${C_GREEN}✅ Password for '$username' changed successfully.${C_RESET}"
  501. echo -e "New Password: ${C_YELLOW}$new_pass${C_RESET}"
  502. ;;
  503. 2) read -p "Enter new duration (in days from today): " days
  504. if [[ "$days" =~ ^[0-9]+$ ]]; then
  505. local new_expire_date; new_expire_date=$(date -d "+$days days" +%Y-%m-%d); chage -E "$new_expire_date" "$username"
  506. local current_line; current_line=$(grep "^$username:" "$DB_FILE"); local pass; pass=$(echo "$current_line" | cut -d: -f2); local limit; limit=$(echo "$current_line" | cut -d: -f4)
  507. sed -i "s/^$username:.*/$username:$pass:$new_expire_date:$limit/" "$DB_FILE"
  508. echo -e "\n${C_GREEN}✅ Expiration for '$username' set to ${C_YELLOW}$new_expire_date${C_RESET}."
  509. else echo -e "\n${C_RED}❌ Invalid number of days.${C_RESET}"; fi ;;
  510. 3) read -p "Enter new simultaneous connection limit: " new_limit
  511. if [[ "$new_limit" =~ ^[0-9]+$ ]]; then
  512. local current_line; current_line=$(grep "^$username:" "$DB_FILE"); local pass; pass=$(echo "$current_line" | cut -d: -f2); local expiry; expiry=$(echo "$current_line" | cut -d: -f3)
  513. sed -i "s/^$username:.*/$username:$pass:$expiry:$new_limit/" "$DB_FILE"
  514. echo -e "\n${C_GREEN}✅ Connection limit for '$username' set to ${C_YELLOW}$new_limit${C_RESET}."
  515. else echo -e "\n${C_RED}❌ Invalid limit.${C_RESET}"; fi ;;
  516. 0) return ;;
  517. *) echo -e "\n${C_RED}❌ Invalid option.${C_RESET}" ;;
  518. esac
  519. echo -e "\nPress ${C_YELLOW}[Enter]${C_RESET} to continue editing..." && read -r
  520. done
  521. }
  522. lock_user() {
  523. _select_user_interface "--- 🔒 Lock a User (from DB) ---"
  524. local u=$SELECTED_USER
  525. if [[ "$u" == "NO_USERS" ]] || [[ -z "$u" ]]; then
  526. if [[ "$u" == "NO_USERS" ]]; then
  527. echo -e "\n${C_YELLOW}ℹ️ No users found in database.${C_RESET}"
  528. fi
  529. read -p "👉 Type username to MANUALLY lock (or '0' to cancel): " manual_user
  530. if [[ "$manual_user" == "0" ]] || [[ -z "$manual_user" ]]; then
  531. echo -e "\n${C_YELLOW}❌ Action cancelled.${C_RESET}"
  532. return
  533. fi
  534. u="$manual_user"
  535. if ! id "$u" &>/dev/null; then
  536. echo -e "\n${C_RED}❌ Error: User '$u' does not exist on this system.${C_RESET}"
  537. return
  538. fi
  539. if grep -q "^$u:" "$DB_FILE"; then
  540. echo -e "\n${C_YELLOW}ℹ️ User '$u' is in the database. Use the normal selection method.${C_RESET}"
  541. else
  542. echo -e "${C_YELLOW}⚠️ User '$u' exists on the system but is NOT in the database.${C_RESET}"
  543. fi
  544. fi
  545. usermod -L "$u"
  546. if [ $? -eq 0 ]; then
  547. killall -u "$u" -9 &>/dev/null
  548. echo -e "\n${C_GREEN}✅ User '$u' has been locked and active sessions killed.${C_RESET}"
  549. else
  550. echo -e "\n${C_RED}❌ Failed to lock user '$u'.${C_RESET}"
  551. fi
  552. }
  553. unlock_user() {
  554. _select_user_interface "--- 🔓 Unlock a User (from DB) ---"
  555. local u=$SELECTED_USER
  556. if [[ "$u" == "NO_USERS" ]] || [[ -z "$u" ]]; then
  557. if [[ "$u" == "NO_USERS" ]]; then
  558. echo -e "\n${C_YELLOW}ℹ️ No users found in database.${C_RESET}"
  559. fi
  560. read -p "👉 Type username to MANUALLY unlock (or '0' to cancel): " manual_user
  561. if [[ "$manual_user" == "0" ]] || [[ -z "$manual_user" ]]; then
  562. echo -e "\n${C_YELLOW}❌ Action cancelled.${C_RESET}"
  563. return
  564. fi
  565. u="$manual_user"
  566. if ! id "$u" &>/dev/null; then
  567. echo -e "\n${C_RED}❌ Error: User '$u' does not exist on this system.${C_RESET}"
  568. return
  569. fi
  570. if grep -q "^$u:" "$DB_FILE"; then
  571. echo -e "\n${C_YELLOW}ℹ️ User '$u' is in the database. Use the normal selection method.${C_RESET}"
  572. else
  573. echo -e "${C_YELLOW}⚠️ User '$u' exists on the system but is NOT in the database.${C_RESET}"
  574. fi
  575. fi
  576. usermod -U "$u"
  577. if [ $? -eq 0 ]; then
  578. echo -e "\n${C_GREEN}✅ User '$u' has been unlocked.${C_RESET}"
  579. else
  580. echo -e "\n${C_RED}❌ Failed to unlock user '$u'.${C_RESET}"
  581. fi
  582. }
  583. list_users() {
  584. clear; show_banner
  585. if [[ ! -s "$DB_FILE" ]]; then
  586. echo -e "\n${C_YELLOW}ℹ️ No users are currently being managed.${C_RESET}"
  587. return
  588. fi
  589. echo -e "${C_BOLD}${C_PURPLE}--- 📋 Managed Users ---${C_RESET}"
  590. echo -e "${C_CYAN}======================================================================${C_RESET}"
  591. printf "${C_BOLD}${C_WHITE}%-20s | %-12s | %-15s | %-20s${C_RESET}\n" "USERNAME" "EXPIRES" "CONNECTIONS" "STATUS"
  592. echo -e "${C_CYAN}----------------------------------------------------------------------${C_RESET}"
  593. while IFS=: read -r user pass expiry limit; do
  594. local online_count
  595. online_count=$(pgrep -u "$user" sshd | wc -l)
  596. local status
  597. status=$(get_user_status "$user")
  598. local plain_status
  599. plain_status=$(echo -e "$status" | sed 's/\x1b\[[0-9;]*m//g')
  600. local connection_string="$online_count / $limit"
  601. local line_color="$C_WHITE"
  602. case $plain_status in
  603. *"Active"*) line_color="$C_GREEN" ;;
  604. *"Locked"*) line_color="$C_YELLOW" ;;
  605. *"Expired"*) line_color="$C_RED" ;;
  606. *"Not Found"*) line_color="$C_DIM" ;;
  607. esac
  608. printf "${line_color}%-20s ${C_RESET}| ${C_YELLOW}%-12s ${C_RESET}| ${C_CYAN}%-15s ${C_RESET}| %-20s\n" "$user" "$expiry" "$connection_string" "$status"
  609. done < <(sort "$DB_FILE")
  610. echo -e "${C_CYAN}======================================================================${C_RESET}\n"
  611. }
  612. renew_user() {
  613. _select_user_interface "--- 🔄 Renew a User ---"; local u=$SELECTED_USER; if [[ "$u" == "NO_USERS" || -z "$u" ]]; then return; fi
  614. read -p "👉 Enter number of days to extend the account: " days; if ! [[ "$days" =~ ^[0-9]+$ ]]; then echo -e "\n${C_RED}❌ Invalid number.${C_RESET}"; return; fi
  615. local new_expire_date; new_expire_date=$(date -d "+$days days" +%Y-%m-%d); chage -E "$new_expire_date" "$u"
  616. local line; line=$(grep "^$u:" "$DB_FILE"); local pass; pass=$(echo "$line"|cut -d: -f2); local limit; limit=$(echo "$line"|cut -d: -f4)
  617. sed -i "s/^$u:.*/$u:$pass:$new_expire_date:$limit/" "$DB_FILE"
  618. echo -e "\n${C_GREEN}✅ User '$u' has been renewed. New expiration date is ${C_YELLOW}${new_expire_date}${C_RESET}."
  619. }
  620. cleanup_expired() {
  621. clear; show_banner
  622. echo -e "${C_BOLD}${C_PURPLE}--- 🧹 Cleanup Expired Users ---${C_RESET}"
  623. local expired_users=()
  624. local current_ts
  625. current_ts=$(date +%s)
  626. if [[ ! -s "$DB_FILE" ]]; then
  627. echo -e "\n${C_GREEN}✅ User database is empty. No expired users found.${C_RESET}"
  628. return
  629. fi
  630. while IFS=: read -r user pass expiry limit; do
  631. local expiry_ts
  632. expiry_ts=$(date -d "$expiry" +%s 2>/dev/null || echo 0)
  633. if [[ $expiry_ts -lt $current_ts && $expiry_ts -ne 0 ]]; then
  634. expired_users+=("$user")
  635. fi
  636. done < "$DB_FILE"
  637. if [ ${#expired_users[@]} -eq 0 ]; then
  638. echo -e "\n${C_GREEN}✅ No expired users found.${C_RESET}"
  639. return
  640. fi
  641. echo -e "\nThe following users have expired: ${C_RED}${expired_users[*]}${C_RESET}"
  642. read -p "👉 Do you want to delete all of them? (y/n): " confirm
  643. if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
  644. for user in "${expired_users[@]}"; do
  645. echo " - Deleting ${C_YELLOW}$user...${C_RESET}"
  646. killall -u "$user" -9 &>/dev/null
  647. userdel -r "$user" &>/dev/null
  648. sed -i "/^$user:/d" "$DB_FILE"
  649. done
  650. echo -e "\n${C_GREEN}✅ Expired users have been cleaned up.${C_RESET}"
  651. else
  652. echo -e "\n${C_YELLOW}❌ Cleanup cancelled.${C_RESET}"
  653. fi
  654. }
  655. backup_user_data() {
  656. clear; show_banner
  657. echo -e "${C_BOLD}${C_PURPLE}--- 💾 Backup User Data ---${C_RESET}"
  658. read -p "👉 Enter path for backup file [/root/firewallfalcon_users.tar.gz]: " backup_path
  659. backup_path=${backup_path:-/root/firewallfalcon_users.tar.gz}
  660. if [ ! -d "$DB_DIR" ] || [ ! -s "$DB_FILE" ]; then
  661. echo -e "\n${C_YELLOW}ℹ️ No user data found to back up.${C_RESET}"
  662. return
  663. fi
  664. echo -e "\n${C_BLUE}⚙️ Backing up user database and settings to ${C_YELLOW}$backup_path${C_RESET}..."
  665. tar -czf "$backup_path" -C "$(dirname "$DB_DIR")" "$(basename "$DB_DIR")"
  666. if [ $? -eq 0 ]; then
  667. echo -e "\n${C_GREEN}✅ SUCCESS: User data backup created at ${C_YELLOW}$backup_path${C_RESET}"
  668. else
  669. echo -e "\n${C_RED}❌ ERROR: Backup failed.${C_RESET}"
  670. fi
  671. }
  672. restore_user_data() {
  673. clear; show_banner
  674. echo -e "${C_BOLD}${C_PURPLE}--- 📥 Restore User Data ---${C_RESET}"
  675. read -p "👉 Enter the full path to the user data backup file [/root/firewallfalcon_users.tar.gz]: " backup_path
  676. backup_path=${backup_path:-/root/firewallfalcon_users.tar.gz}
  677. if [ ! -f "$backup_path" ]; then
  678. echo -e "\n${C_RED}❌ ERROR: Backup file not found at '$backup_path'.${C_RESET}"
  679. return
  680. fi
  681. echo -e "\n${C_RED}${C_BOLD}⚠️ WARNING:${C_RESET} This will overwrite all current users and settings."
  682. echo -e "It will restore user accounts, passwords, limits, and expiration dates from the backup file."
  683. read -p "👉 Are you absolutely sure you want to proceed? (y/n): " confirm
  684. if [[ "$confirm" != "y" ]]; then echo -e "\n${C_YELLOW}❌ Restore cancelled.${C_RESET}"; return; fi
  685. local temp_dir
  686. temp_dir=$(mktemp -d)
  687. echo -e "\n${C_BLUE}⚙️ Extracting backup file to a temporary location...${C_RESET}"
  688. tar -xzf "$backup_path" -C "$temp_dir"
  689. if [ $? -ne 0 ]; then
  690. echo -e "\n${C_RED}❌ ERROR: Failed to extract backup file. Aborting.${C_RESET}"
  691. rm -rf "$temp_dir"
  692. return
  693. fi
  694. local restored_db_file="$temp_dir/firewallfalcon/users.db"
  695. if [ ! -f "$restored_db_file" ]; then
  696. echo -e "\n${C_RED}❌ ERROR: users.db not found in the backup. Cannot restore user accounts.${C_RESET}"
  697. rm -rf "$temp_dir"
  698. return
  699. fi
  700. echo -e "${C_BLUE}⚙️ Overwriting current user database...${C_RESET}"
  701. mkdir -p "$DB_DIR"
  702. cp "$restored_db_file" "$DB_FILE"
  703. if [ -d "$temp_dir/firewallfalcon/ssl" ]; then
  704. cp -r "$temp_dir/firewallfalcon/ssl" "$DB_DIR/"
  705. fi
  706. if [ -d "$temp_dir/firewallfalcon/dnstt" ]; then
  707. cp -r "$temp_dir/firewallfalcon/dnstt" "$DB_DIR/"
  708. fi
  709. if [ -f "$temp_dir/firewallfalcon/dns_info.conf" ]; then
  710. cp "$temp_dir/firewallfalcon/dns_info.conf" "$DB_DIR/"
  711. fi
  712. if [ -f "$temp_dir/firewallfalcon/dnstt_info.conf" ]; then
  713. cp "$temp_dir/firewallfalcon/dnstt_info.conf" "$DB_DIR/"
  714. fi
  715. if [ -f "$temp_dir/firewallfalcon/falconproxy_config.conf" ]; then
  716. cp "$temp_dir/firewallfalcon/falconproxy_config.conf" "$DB_DIR/"
  717. fi
  718. echo -e "${C_BLUE}⚙️ Re-synchronizing system accounts with the restored database...${C_RESET}"
  719. while IFS=: read -r user pass expiry limit; do
  720. echo "Processing user: ${C_YELLOW}$user${C_RESET}"
  721. if ! id "$user" &>/dev/null; then
  722. echo " - User does not exist in system. Creating..."
  723. useradd -m -s /usr/sbin/nologin "$user"
  724. fi
  725. echo " - Setting password..."
  726. echo "$user:$pass" | chpasswd
  727. echo " - Setting expiration to $expiry..."
  728. chage -E "$expiry" "$user"
  729. echo " - Connection limit is $limit (enforced by PAM)"
  730. done < "$DB_FILE"
  731. rm -rf "$temp_dir"
  732. echo -e "\n${C_GREEN}✅ SUCCESS: User data restore completed.${C_RESET}"
  733. }
  734. _enable_banner_in_sshd_config() {
  735. echo -e "\n${C_BLUE}⚙️ Configuring sshd_config...${C_RESET}"
  736. sed -i.bak -E 's/^( *Banner *).*/#\1/' /etc/ssh/sshd_config
  737. if ! grep -q -E "^Banner $SSH_BANNER_FILE" /etc/ssh/sshd_config; then
  738. echo -e "\n# FirewallFalcon SSH Banner\nBanner $SSH_BANNER_FILE" >> /etc/ssh/sshd_config
  739. fi
  740. echo -e "${C_GREEN}✅ sshd_config updated.${C_RESET}"
  741. }
  742. _restart_ssh() {
  743. echo -e "\n${C_BLUE}🔄 Restarting SSH service to apply changes...${C_RESET}"
  744. local ssh_service_name=""
  745. if [ -f /lib/systemd/system/sshd.service ]; then
  746. ssh_service_name="sshd.service"
  747. elif [ -f /lib/systemd/system/ssh.service ]; then
  748. ssh_service_name="ssh.service"
  749. else
  750. echo -e "${C_RED}❌ Could not find sshd.service or ssh.service. Cannot restart SSH.${C_RESET}"
  751. return 1
  752. fi
  753. systemctl restart "${ssh_service_name}"
  754. if [ $? -eq 0 ]; then
  755. echo -e "${C_GREEN}✅ SSH service ('${ssh_service_name}') restarted successfully.${C_RESET}"
  756. else
  757. echo -e "${C_RED}❌ Failed to restart SSH service ('${ssh_service_name}'). Please check 'journalctl -u ${ssh_service_name}' for errors.${C_RESET}"
  758. fi
  759. }
  760. set_ssh_banner_paste() {
  761. clear; show_banner
  762. echo -e "${C_BOLD}${C_PURPLE}--- 📋 Paste SSH Banner ---${C_RESET}"
  763. echo -e "Paste your banner code below. Press ${C_YELLOW}[Ctrl+D]${C_RESET} when you are finished."
  764. echo -e "${C_DIM}The current banner (if any) will be overwritten.${C_RESET}"
  765. echo -e "--------------------------------------------------"
  766. cat > "$SSH_BANNER_FILE"
  767. chmod 644 "$SSH_BANNER_FILE"
  768. echo -e "\n--------------------------------------------------"
  769. echo -e "\n${C_GREEN}✅ Banner content saved from paste.${C_RESET}"
  770. _enable_banner_in_sshd_config
  771. _restart_ssh
  772. echo -e "\nPress ${C_YELLOW}[Enter]${C_RESET} to return..." && read -r
  773. }
  774. view_ssh_banner() {
  775. clear; show_banner
  776. echo -e "${C_BOLD}${C_PURPLE}--- 👁️ Current SSH Banner ---${C_RESET}"
  777. if [ -f "$SSH_BANNER_FILE" ]; then
  778. echo -e "\n${C_CYAN}--- BEGIN BANNER ---${C_RESET}"
  779. cat "$SSH_BANNER_FILE"
  780. echo -e "${C_CYAN}---- END BANNER ----${C_RESET}"
  781. else
  782. echo -e "\n${C_YELLOW}ℹ️ No banner file found at $SSH_BANNER_FILE.${C_RESET}"
  783. fi
  784. echo -e "\nPress ${C_YELLOW}[Enter]${C_RESET} to return..." && read -r
  785. }
  786. remove_ssh_banner() {
  787. clear; show_banner
  788. echo -e "${C_BOLD}${C_PURPLE}--- 🗑️ Remove SSH Banner ---${C_RESET}"
  789. read -p "👉 Are you sure you want to disable and remove the SSH banner? (y/n): " confirm
  790. if [[ "$confirm" != "y" ]]; then
  791. echo -e "\n${C_YELLOW}❌ Action cancelled.${C_RESET}"
  792. echo -e "\nPress ${C_YELLOW}[Enter]${C_RESET} to return..." && read -r
  793. return
  794. fi
  795. if [ -f "$SSH_BANNER_FILE" ]; then
  796. rm -f "$SSH_BANNER_FILE"
  797. echo -e "\n${C_GREEN}✅ Removed banner file: $SSH_BANNER_FILE${C_RESET}"
  798. else
  799. echo -e "\n${C_YELLOW}ℹ️ No banner file to remove.${C_RESET}"
  800. fi
  801. echo -e "\n${C_BLUE}⚙️ Disabling banner in sshd_config...${C_RESET}"
  802. sed -i.bak -E "s/^( *Banner\s+$SSH_BANNER_FILE)/#\1/" /etc/ssh/sshd_config
  803. echo -e "${C_GREEN}✅ Banner disabled in configuration.${C_RESET}"
  804. _restart_ssh
  805. echo -e "\nPress ${C_YELLOW}[Enter]${C_RESET} to return..." && read -r
  806. }
  807. ssh_banner_menu() {
  808. while true; do
  809. show_banner
  810. local banner_status
  811. if grep -q -E "^\s*Banner\s+$SSH_BANNER_FILE" /etc/ssh/sshd_config && [ -f "$SSH_BANNER_FILE" ]; then
  812. banner_status="${C_STATUS_A}(Active)${C_RESET}"
  813. else
  814. banner_status="${C_STATUS_I}(Inactive)${C_RESET}"
  815. fi
  816. echo -e "\n ${C_TITLE}═════════════════[ ${C_BOLD}🎨 SSH Banner Management ${banner_status} ${C_RESET}${C_TITLE}]═════════════════${C_RESET}"
  817. printf " ${C_CHOICE}[ 1]${C_RESET} %-40s\n" "📋 Paste or Edit Banner"
  818. printf " ${C_CHOICE}[ 2]${C_RESET} %-40s\n" "👁️ View Current Banner"
  819. printf " ${C_DANGER}[ 3]${C_RESET} %-40s\n" "🗑️ Disable and Remove Banner"
  820. echo -e " ${C_DIM}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~${C_RESET}"
  821. echo -e " ${C_WARN}[ 0]${C_RESET} ↩️ Return to Main Menu"
  822. echo
  823. read -p "$(echo -e ${C_PROMPT}"👉 Select an option: "${C_RESET})" choice
  824. case $choice in
  825. 1) set_ssh_banner_paste ;;
  826. 2) view_ssh_banner ;;
  827. 3) remove_ssh_banner ;;
  828. 0) return ;;
  829. *) echo -e "\n${C_RED}❌ Invalid option.${C_RESET}" && sleep 2 ;;
  830. esac
  831. done
  832. }
  833. install_udp_custom() {
  834. clear; show_banner
  835. echo -e "${C_BOLD}${C_PURPLE}--- 🚀 Installing udp-custom ---${C_RESET}"
  836. if [ -f "$UDP_CUSTOM_SERVICE_FILE" ]; then
  837. echo -e "\n${C_YELLOW}ℹ️ udp-custom is already installed.${C_RESET}"
  838. return
  839. fi
  840. echo -e "\n${C_GREEN}⚙️ Creating directory for udp-custom...${C_RESET}"
  841. rm -rf "$UDP_CUSTOM_DIR"
  842. mkdir -p "$UDP_CUSTOM_DIR"
  843. echo -e "\n${C_GREEN}⚙️ Detecting system architecture...${C_RESET}"
  844. local arch
  845. arch=$(uname -m)
  846. local binary_url=""
  847. if [[ "$arch" == "x86_64" ]]; then
  848. binary_url="https://github.com/firewallfalcons/FirewallFalcon-Manager/raw/main/udp/udp-custom-linux-amd64"
  849. echo -e "${C_BLUE}ℹ️ Detected x86_64 (amd64) architecture.${C_RESET}"
  850. elif [[ "$arch" == "aarch64" || "$arch" == "arm64" ]]; then
  851. binary_url="https://github.com/firewallfalcons/FirewallFalcon-Manager/raw/main/udp/udp-custom-linux-arm"
  852. echo -e "${C_BLUE}ℹ️ Detected ARM64 architecture.${C_RESET}"
  853. else
  854. echo -e "\n${C_RED}❌ Unsupported architecture: $arch. Cannot install udp-custom.${C_RESET}"
  855. rm -rf "$UDP_CUSTOM_DIR"
  856. return
  857. fi
  858. echo -e "\n${C_GREEN}📥 Downloading udp-custom binary...${C_RESET}"
  859. wget -q --show-progress -O "$UDP_CUSTOM_DIR/udp-custom" "$binary_url"
  860. if [ $? -ne 0 ]; then
  861. echo -e "\n${C_RED}❌ Failed to download the udp-custom binary.${C_RESET}"
  862. rm -rf "$UDP_CUSTOM_DIR"
  863. return
  864. fi
  865. chmod +x "$UDP_CUSTOM_DIR/udp-custom"
  866. echo -e "\n${C_GREEN}📝 Creating default config.json...${C_RESET}"
  867. cat > "$UDP_CUSTOM_DIR/config.json" <<EOF
  868. {
  869. "listen": ":36712",
  870. "stream_buffer": 33554432,
  871. "receive_buffer": 83886080,
  872. "auth": {
  873. "mode": "passwords"
  874. }
  875. }
  876. EOF
  877. chmod 644 "$UDP_CUSTOM_DIR/config.json"
  878. echo -e "\n${C_GREEN}📝 Creating systemd service file...${C_RESET}"
  879. cat > "$UDP_CUSTOM_SERVICE_FILE" <<EOF
  880. [Unit]
  881. Description=UDP Custom by FirewallFalcon
  882. After=network.target
  883. [Service]
  884. User=root
  885. Type=simple
  886. ExecStart=$UDP_CUSTOM_DIR/udp-custom server -exclude 53,5300
  887. WorkingDirectory=$UDP_CUSTOM_DIR/
  888. Restart=always
  889. RestartSec=2s
  890. [Install]
  891. WantedBy=default.target
  892. EOF
  893. echo -e "\n${C_GREEN}▶️ Enabling and starting udp-custom service...${C_RESET}"
  894. systemctl daemon-reload
  895. systemctl enable udp-custom.service
  896. systemctl start udp-custom.service
  897. sleep 2
  898. if systemctl is-active --quiet udp-custom; then
  899. echo -e "\n${C_GREEN}✅ SUCCESS: udp-custom is installed and active.${C_RESET}"
  900. else
  901. echo -e "\n${C_RED}❌ ERROR: udp-custom service failed to start.${C_RESET}"
  902. echo -e "${C_YELLOW}ℹ️ Displaying last 15 lines of the service log for diagnostics:${C_RESET}"
  903. journalctl -u udp-custom.service -n 15 --no-pager
  904. fi
  905. }
  906. uninstall_udp_custom() {
  907. echo -e "\n${C_BOLD}${C_PURPLE}--- 🗑️ Uninstalling udp-custom ---${C_RESET}"
  908. if [ ! -f "$UDP_CUSTOM_SERVICE_FILE" ]; then
  909. echo -e "${C_YELLOW}ℹ️ udp-custom is not installed, skipping.${C_RESET}"
  910. return
  911. fi
  912. echo -e "${C_GREEN}🛑 Stopping and disabling udp-custom service...${C_RESET}"
  913. systemctl stop udp-custom.service >/dev/null 2>&1
  914. systemctl disable udp-custom.service >/dev/null 2>&1
  915. echo -e "${C_GREEN}🗑️ Removing systemd service file...${C_RESET}"
  916. rm -f "$UDP_CUSTOM_SERVICE_FILE"
  917. systemctl daemon-reload
  918. echo -e "${C_GREEN}🗑️ Removing udp-custom directory and files...${C_RESET}"
  919. rm -rf "$UDP_CUSTOM_DIR"
  920. echo -e "${C_GREEN}✅ udp-custom has been uninstalled successfully.${C_RESET}"
  921. }
  922. install_badvpn() {
  923. clear; show_banner
  924. echo -e "${C_BOLD}${C_PURPLE}--- 🚀 Installing badvpn (udpgw) ---${C_RESET}"
  925. if [ -f "$BADVPN_SERVICE_FILE" ]; then
  926. echo -e "\n${C_YELLOW}ℹ️ badvpn is already installed.${C_RESET}"
  927. return
  928. fi
  929. check_and_open_firewall_port 7300 udp || return
  930. echo -e "\n${C_GREEN}🔄 Updating package lists...${C_RESET}"
  931. apt-get update
  932. echo -e "\n${C_GREEN}📦 Installing all required packages...${C_RESET}"
  933. apt-get install -y cmake g++ make screen git build-essential libssl-dev libnspr4-dev libnss3-dev pkg-config
  934. echo -e "\n${C_GREEN}📥 Cloning badvpn from github...${C_RESET}"
  935. git clone https://github.com/ambrop72/badvpn.git "$BADVPN_BUILD_DIR"
  936. cd "$BADVPN_BUILD_DIR" || { echo -e "${C_RED}❌ Failed to change directory to build folder.${C_RESET}"; return; }
  937. echo -e "\n${C_GREEN}⚙️ Running CMake...${C_RESET}"
  938. cmake . || { echo -e "${C_RED}❌ CMake configuration failed.${C_RESET}"; rm -rf "$BADVPN_BUILD_DIR"; return; }
  939. echo -e "\n${C_GREEN}🛠️ Compiling source...${C_RESET}"
  940. make || { echo -e "${C_RED}❌ Compilation (make) failed.${C_RESET}"; rm -rf "$BADVPN_BUILD_DIR"; return; }
  941. local badvpn_binary
  942. badvpn_binary=$(find "$BADVPN_BUILD_DIR" -name "badvpn-udpgw" -type f | head -n 1)
  943. if [[ -z "$badvpn_binary" || ! -f "$badvpn_binary" ]]; then
  944. echo -e "${C_RED}❌ ERROR: Could not find the compiled 'badvpn-udpgw' binary after compilation.${C_RESET}"
  945. rm -rf "$BADVPN_BUILD_DIR"
  946. return
  947. fi
  948. echo -e "${C_GREEN}ℹ️ Found binary at: $badvpn_binary${C_RESET}"
  949. chmod +x "$badvpn_binary"
  950. echo -e "\n${C_GREEN}📝 Creating systemd service file...${C_RESET}"
  951. cat > "$BADVPN_SERVICE_FILE" <<-EOF
  952. [Unit]
  953. Description=BadVPN UDP Gateway
  954. After=network.target
  955. [Service]
  956. ExecStart=$badvpn_binary --listen-addr 0.0.0.0:7300 --max-clients 1000 --max-connections-for-client 8
  957. User=root
  958. Restart=always
  959. RestartSec=3
  960. [Install]
  961. WantedBy=multi-user.target
  962. EOF
  963. echo -e "\n${C_GREEN}▶️ Enabling and starting badvpn service...${C_RESET}"
  964. systemctl daemon-reload
  965. systemctl enable badvpn.service
  966. systemctl start badvpn.service
  967. sleep 2
  968. if systemctl is-active --quiet badvpn; then
  969. echo -e "\n${C_GREEN}✅ SUCCESS: badvpn (udpgw) is installed and active on port 7300.${C_RESET}"
  970. else
  971. echo -e "\n${C_RED}❌ ERROR: badvpn service failed to start.${C_RESET}"
  972. echo -e "${C_YELLOW}ℹ️ Displaying last 15 lines of the service log for diagnostics:${C_RESET}"
  973. journalctl -u badvpn.service -n 15 --no-pager
  974. fi
  975. }
  976. uninstall_badvpn() {
  977. echo -e "\n${C_BOLD}${C_PURPLE}--- 🗑️ Uninstalling badvpn (udpgw) ---${C_RESET}"
  978. if [ ! -f "$BADVPN_SERVICE_FILE" ]; then
  979. echo -e "${C_YELLOW}ℹ️ badvpn is not installed, skipping.${C_RESET}"
  980. return
  981. fi
  982. echo -e "${C_GREEN}🛑 Stopping and disabling badvpn service...${C_RESET}"
  983. systemctl stop badvpn.service >/dev/null 2>&1
  984. systemctl disable badvpn.service >/dev/null 2>&1
  985. echo -e "${C_GREEN}🗑️ Removing systemd service file...${C_RESET}"
  986. rm -f "$BADVPN_SERVICE_FILE"
  987. systemctl daemon-reload
  988. echo -e "${C_GREEN}🗑️ Removing badvpn build directory...${C_RESET}"
  989. rm -rf "$BADVPN_BUILD_DIR"
  990. echo -e "${C_GREEN}✅ badvpn has been uninstalled successfully.${C_RESET}"
  991. }
  992. install_ssl_tunnel() {
  993. clear; show_banner
  994. echo -e "${C_BOLD}${C_PURPLE}--- 🚀 Installing SSL Tunnel (HAProxy) for SSH ---${C_RESET}"
  995. if ! command -v haproxy &> /dev/null; then
  996. echo -e "\n${C_YELLOW}⚠️ HAProxy not found. Installing...${C_RESET}"
  997. apt-get update && apt-get install -y haproxy || { echo -e "${C_RED}❌ Failed to install HAProxy.${C_RESET}"; return; }
  998. fi
  999. read -p "👉 Enter the port for the SSL tunnel [444]: " ssl_port
  1000. ssl_port=${ssl_port:-444}
  1001. if ! [[ "$ssl_port" =~ ^[0-9]+$ ]] || [ "$ssl_port" -lt 1 ] || [ "$ssl_port" -gt 65535 ]; then
  1002. echo -e "\n${C_RED}❌ Invalid port number. Aborting.${C_RESET}"
  1003. return
  1004. fi
  1005. check_and_free_ports "$ssl_port" || return
  1006. check_and_open_firewall_port "$ssl_port" || return
  1007. if [ -f "$SSL_CERT_FILE" ]; then
  1008. read -p "SSL certificate already exists. Overwrite? (y/n): " overwrite_cert
  1009. if [[ "$overwrite_cert" != "y" ]]; then
  1010. echo -e "${C_YELLOW}ℹ️ Using existing certificate.${C_RESET}"
  1011. else
  1012. rm -f "$SSL_CERT_FILE"
  1013. fi
  1014. fi
  1015. if [ ! -f "$SSL_CERT_FILE" ]; then
  1016. echo -e "\n${C_GREEN}🔐 Generating self-signed SSL certificate...${C_RESET}"
  1017. openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
  1018. -keyout "$SSL_CERT_FILE" -out "$SSL_CERT_FILE" \
  1019. -subj "/CN=@FIREWALLFALCON" \
  1020. >/dev/null 2>&1 || { echo -e "${C_RED}❌ Failed to generate SSL certificate.${C_RESET}"; return; }
  1021. echo -e "${C_GREEN}✅ Certificate created: ${C_YELLOW}$SSL_CERT_FILE${C_RESET}"
  1022. fi
  1023. echo -e "\n${C_GREEN}📝 Creating HAProxy configuration for port $ssl_port...${C_RESET}"
  1024. cat > "$HAPROXY_CONFIG" <<-EOF
  1025. global
  1026. log /dev/log local0
  1027. log /dev/log local1 notice
  1028. chroot /var/lib/haproxy
  1029. stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
  1030. stats timeout 30s
  1031. user haproxy
  1032. group haproxy
  1033. daemon
  1034. defaults
  1035. log global
  1036. mode tcp
  1037. option tcplog
  1038. option dontlognull
  1039. timeout connect 5000
  1040. timeout client 50000
  1041. timeout server 50000
  1042. frontend ssh_ssl_in
  1043. bind *:$ssl_port ssl crt $SSL_CERT_FILE
  1044. mode tcp
  1045. default_backend ssh_backend
  1046. backend ssh_backend
  1047. mode tcp
  1048. server ssh_server 127.0.0.1:22
  1049. EOF
  1050. echo -e "\n${C_GREEN}▶️ Reloading and starting HAProxy service...${C_RESET}"
  1051. systemctl daemon-reload
  1052. systemctl restart haproxy
  1053. sleep 2
  1054. if systemctl is-active --quiet haproxy; then
  1055. echo -e "\n${C_GREEN}✅ SUCCESS: SSL Tunnel is active.${C_RESET}"
  1056. echo -e "Clients can now connect to this server's IP on port ${C_YELLOW}${ssl_port}${C_RESET} using an SSL/TLS tunnel."
  1057. else
  1058. echo -e "\n${C_RED}❌ ERROR: HAProxy service failed to start.${C_RESET}"
  1059. echo -e "${C_YELLOW}ℹ️ Displaying HAProxy status for diagnostics:${C_RESET}"
  1060. systemctl status haproxy --no-pager
  1061. fi
  1062. }
  1063. uninstall_ssl_tunnel() {
  1064. echo -e "\n${C_BOLD}${C_PURPLE}--- 🗑️ Uninstalling SSL Tunnel ---${C_RESET}"
  1065. if ! command -v haproxy &> /dev/null; then
  1066. echo -e "${C_YELLOW}ℹ️ HAProxy not installed, skipping.${C_RESET}"
  1067. return
  1068. fi
  1069. echo -e "${C_GREEN}🛑 Stopping HAProxy service...${C_RESET}"
  1070. systemctl stop haproxy >/dev/null 2>&1
  1071. if [ -f "$HAPROXY_CONFIG" ]; then
  1072. echo -e "${C_GREEN}📝 Restoring default/empty HAProxy config...${C_RESET}"
  1073. cat > "$HAPROXY_CONFIG" <<-EOF
  1074. global
  1075. log /dev/log local0
  1076. log /dev/log local1 notice
  1077. defaults
  1078. log global
  1079. EOF
  1080. fi
  1081. if [ -f "$SSL_CERT_FILE" ]; then
  1082. local delete_cert="y"
  1083. if [[ "$UNINSTALL_MODE" != "silent" ]]; then
  1084. read -p "👉 Delete the SSL certificate at $SSL_CERT_FILE? (y/n): " delete_cert
  1085. fi
  1086. if [[ "$delete_cert" == "y" ]]; then
  1087. echo -e "${C_GREEN}🗑️ Removing SSL certificate...${C_RESET}"
  1088. rm -f "$SSL_CERT_FILE"
  1089. fi
  1090. fi
  1091. echo -e "${C_GREEN}✅ SSL Tunnel has been uninstalled.${C_RESET}"
  1092. }
  1093. show_dnstt_details() {
  1094. if [ -f "$DNSTT_CONFIG_FILE" ]; then
  1095. source "$DNSTT_CONFIG_FILE"
  1096. echo -e "\n${C_GREEN}=====================================================${C_RESET}"
  1097. echo -e "${C_GREEN} 📡 DNSTT Connection Details ${C_RESET}"
  1098. echo -e "${C_GREEN}=====================================================${C_RESET}"
  1099. echo -e "\n${C_WHITE}Your connection details:${C_RESET}"
  1100. echo -e " - ${C_CYAN}Tunnel Domain:${C_RESET} ${C_YELLOW}$TUNNEL_DOMAIN${C_RESET}"
  1101. echo -e " - ${C_CYAN}Public Key:${C_RESET} ${C_YELLOW}$PUBLIC_KEY${C_RESET}"
  1102. if [[ -n "$FORWARD_DESC" ]]; then
  1103. echo -e " - ${C_CYAN}Forwarding To:${C_RESET} ${C_YELLOW}$FORWARD_DESC${C_RESET}"
  1104. else
  1105. echo -e " - ${C_CYAN}Forwarding To:${C_RESET} ${C_YELLOW}Unknown (config_missing)${C_RESET}"
  1106. fi
  1107. if [[ -n "$MTU_VALUE" ]]; then
  1108. echo -e " - ${C_CYAN}MTU Value:${C_RESET} ${C_YELLOW}$MTU_VALUE${C_RESET}"
  1109. fi
  1110. if [[ "$DNSTT_RECORDS_MANAGED" == "false" && -n "$NS_DOMAIN" ]]; then
  1111. echo -e " - ${C_CYAN}NS Record:${C_RESET} ${C_YELLOW}$NS_DOMAIN${C_RESET}"
  1112. fi
  1113. if [[ "$FORWARD_DESC" == *"V2Ray"* ]]; then
  1114. echo -e " - ${C_CYAN}Action Required:${C_RESET} ${C_YELLOW}Ensure a V2Ray service (vless/vmess/trojan) listens on port 8787 (no TLS)${C_RESET}"
  1115. elif [[ "$FORWARD_DESC" == *"SSH"* ]]; then
  1116. echo -e " - ${C_CYAN}Action Required:${C_RESET} ${C_YELLOW}Ensure your SSH client is configured to use the DNS tunnel.${C_RESET}"
  1117. fi
  1118. echo -e "\n${C_DIM}Use these details in your client configuration.${C_RESET}"
  1119. else
  1120. echo -e "\n${C_YELLOW}ℹ️ DNSTT configuration file not found. Details are unavailable.${C_RESET}"
  1121. fi
  1122. }
  1123. install_dnstt() {
  1124. clear; show_banner
  1125. echo -e "${C_BOLD}${C_PURPLE}--- 📡 DNSTT (DNS Tunnel) Management ---${C_RESET}"
  1126. if [ -f "$DNSTT_SERVICE_FILE" ]; then
  1127. echo -e "\n${C_YELLOW}ℹ️ DNSTT is already installed.${C_RESET}"
  1128. show_dnstt_details
  1129. return
  1130. fi
  1131. # --- FIX: Force release of Port 53 / Disable systemd-resolved ---
  1132. echo -e "${C_GREEN}⚙️ Forcing release of Port 53 (stopping systemd-resolved)...${C_RESET}"
  1133. systemctl stop systemd-resolved >/dev/null 2>&1
  1134. systemctl disable systemd-resolved >/dev/null 2>&1
  1135. rm -f /etc/resolv.conf
  1136. echo "nameserver 8.8.8.8" | tee /etc/resolv.conf > /dev/null
  1137. # ----------------------------------------------------------------
  1138. echo -e "\n${C_BLUE}🔎 Checking if port 53 (UDP) is available...${C_RESET}"
  1139. if ss -lunp | grep -q ':53\s'; then
  1140. if [[ $(ps -p $(ss -lunp | grep ':53\s' | grep -oP 'pid=\K[0-9]+') -o comm=) == "systemd-resolve" ]]; then
  1141. echo -e "${C_YELLOW}⚠️ Warning: Port 53 is in use by 'systemd-resolved'.${C_RESET}"
  1142. echo -e "${C_YELLOW}This is the system's DNS stub resolver. It must be disabled to run DNSTT.${C_RESET}"
  1143. read -p "👉 Allow the script to automatically disable it and reconfigure DNS? (y/n): " resolve_confirm
  1144. if [[ "$resolve_confirm" == "y" || "$resolve_confirm" == "Y" ]]; then
  1145. echo -e "${C_GREEN}⚙️ Stopping and disabling systemd-resolved to free port 53...${C_RESET}"
  1146. systemctl stop systemd-resolved
  1147. systemctl disable systemd-resolved
  1148. chattr -i /etc/resolv.conf &>/dev/null
  1149. rm -f /etc/resolv.conf
  1150. echo "nameserver 8.8.8.8" > /etc/resolv.conf
  1151. chattr +i /etc/resolv.conf
  1152. echo -e "${C_GREEN}✅ Port 53 has been freed and DNS set to 8.8.8.8.${C_RESET}"
  1153. else
  1154. echo -e "${C_RED}❌ Cannot proceed without freeing port 53. Aborting.${C_RESET}"
  1155. return
  1156. fi
  1157. else
  1158. check_and_free_ports "53" || return
  1159. fi
  1160. else
  1161. echo -e "${C_GREEN}✅ Port 53 (UDP) is free to use.${C_RESET}"
  1162. fi
  1163. check_and_open_firewall_port 53 udp || return
  1164. local forward_port=""
  1165. local forward_desc=""
  1166. echo -e "\n${C_BLUE}Please choose where DNSTT should forward traffic:${C_RESET}"
  1167. echo -e " ${C_GREEN}[ 1]${C_RESET} ➡️ Forward to local SSH service (port 22)"
  1168. echo -e " ${C_GREEN}[ 2]${C_RESET} ➡️ Forward to local V2Ray backend (port 8787)"
  1169. read -p "👉 Enter your choice [2]: " fwd_choice
  1170. fwd_choice=${fwd_choice:-2}
  1171. if [[ "$fwd_choice" == "1" ]]; then
  1172. forward_port="22"
  1173. forward_desc="SSH (port 22)"
  1174. echo -e "${C_GREEN}ℹ️ DNSTT will forward to SSH on 127.0.0.1:22.${C_RESET}"
  1175. elif [[ "$fwd_choice" == "2" ]]; then
  1176. forward_port="8787"
  1177. forward_desc="V2Ray (port 8787)"
  1178. echo -e "${C_GREEN}ℹ️ DNSTT will forward to V2Ray on 127.0.0.1:8787.${C_RESET}"
  1179. else
  1180. echo -e "${C_RED}❌ Invalid choice. Aborting.${C_RESET}"
  1181. return
  1182. fi
  1183. local FORWARD_TARGET="127.0.0.1:$forward_port"
  1184. local NS_DOMAIN=""
  1185. local TUNNEL_DOMAIN=""
  1186. local DNSTT_RECORDS_MANAGED="true"
  1187. local NS_SUBDOMAIN=""
  1188. local TUNNEL_SUBDOMAIN=""
  1189. local HAS_IPV6="false"
  1190. read -p "👉 Auto-generate DNS records or use custom ones? (auto/custom) [auto]: " dns_choice
  1191. dns_choice=${dns_choice:-auto}
  1192. if [[ "$dns_choice" == "custom" ]]; then
  1193. DNSTT_RECORDS_MANAGED="false"
  1194. read -p "👉 Enter your full nameserver domain (e.g., ns1.yourdomain.com): " NS_DOMAIN
  1195. if [[ -z "$NS_DOMAIN" ]]; then echo -e "\n${C_RED}❌ Nameserver domain cannot be empty. Aborting.${C_RESET}"; return; fi
  1196. read -p "👉 Enter your full tunnel domain (e.g., tun.yourdomain.com): " TUNNEL_DOMAIN
  1197. if [[ -z "$TUNNEL_DOMAIN" ]]; then echo -e "\n${C_RED}❌ Tunnel domain cannot be empty. Aborting.${C_RESET}"; return; fi
  1198. else
  1199. echo -e "\n${C_BLUE}⚙️ Configuring DNS records for DNSTT...${C_RESET}"
  1200. local SERVER_IPV4
  1201. SERVER_IPV4=$(curl -s -4 icanhazip.com)
  1202. if ! _is_valid_ipv4 "$SERVER_IPV4"; then
  1203. echo -e "\n${C_RED}❌ Error: Could not retrieve a valid public IPv4 address from icanhazip.com.${C_RESET}"
  1204. echo -e "${C_YELLOW}ℹ️ Please check your server's network connection and DNS resolver settings.${C_RESET}"
  1205. echo -e " Output received: '$SERVER_IPV4'"
  1206. return 1
  1207. fi
  1208. local SERVER_IPV6
  1209. SERVER_IPV6=$(curl -s -6 icanhazip.com --max-time 5)
  1210. local RANDOM_STR
  1211. RANDOM_STR=$(head /dev/urandom | tr -dc a-z0-9 | head -c 6)
  1212. NS_SUBDOMAIN="ns-$RANDOM_STR"
  1213. TUNNEL_SUBDOMAIN="tun-$RANDOM_STR"
  1214. NS_DOMAIN="$NS_SUBDOMAIN.$DESEC_DOMAIN"
  1215. TUNNEL_DOMAIN="$TUNNEL_SUBDOMAIN.$DESEC_DOMAIN"
  1216. local API_DATA
  1217. API_DATA=$(printf '[{"subname": "%s", "type": "A", "ttl": 3600, "records": ["%s"]}, {"subname": "%s", "type": "NS", "ttl": 3600, "records": ["%s."]}]' \
  1218. "$NS_SUBDOMAIN" "$SERVER_IPV4" "$TUNNEL_SUBDOMAIN" "$NS_DOMAIN")
  1219. if [[ -n "$SERVER_IPV6" ]]; then
  1220. local aaaa_record
  1221. aaaa_record=$(printf ',{"subname": "%s", "type": "AAAA", "ttl": 3600, "records": ["%s"]}' "$NS_SUBDOMAIN" "$SERVER_IPV6")
  1222. API_DATA="${API_DATA%?}${aaaa_record}]"
  1223. HAS_IPV6="true"
  1224. fi
  1225. local CREATE_RESPONSE
  1226. CREATE_RESPONSE=$(curl -s -w "%{http_code}" -X POST "https://desec.io/api/v1/domains/$DESEC_DOMAIN/rrsets/" \
  1227. -H "Authorization: Token $DESEC_TOKEN" -H "Content-Type: application/json" \
  1228. --data "$API_DATA")
  1229. local HTTP_CODE=${CREATE_RESPONSE: -3}
  1230. local RESPONSE_BODY=${CREATE_RESPONSE:0:${#CREATE_RESPONSE}-3}
  1231. if [[ "$HTTP_CODE" -ne 201 ]]; then
  1232. echo -e "${C_RED}❌ Failed to create DNSTT records. API returned HTTP $HTTP_CODE.${C_RESET}"
  1233. echo "Response: $RESPONSE_BODY" | jq
  1234. return 1
  1235. fi
  1236. fi
  1237. read -p "👉 Enter MTU value (e.g., 512, 1200) or press [Enter] for default: " mtu_value
  1238. local mtu_string=""
  1239. if [[ "$mtu_value" =~ ^[0-9]+$ ]]; then
  1240. mtu_string=" -mtu $mtu_value"
  1241. echo -e "${C_GREEN}ℹ️ Using MTU: $mtu_value${C_RESET}"
  1242. else
  1243. mtu_value=""
  1244. echo -e "${C_YELLOW}ℹ️ Using default MTU.${C_RESET}"
  1245. fi
  1246. echo -e "\n${C_BLUE}📥 Downloading pre-compiled DNSTT server binary...${C_RESET}"
  1247. local arch
  1248. arch=$(uname -m)
  1249. local binary_url=""
  1250. if [[ "$arch" == "x86_64" ]]; then
  1251. binary_url="https://dnstt.network/dnstt-server-linux-amd64"
  1252. echo -e "${C_BLUE}ℹ️ Detected x86_64 (amd64) architecture.${C_RESET}"
  1253. elif [[ "$arch" == "aarch64" || "$arch" == "arm64" ]]; then
  1254. binary_url="https://dnstt.network/dnstt-server-linux-arm64"
  1255. echo -e "${C_BLUE}ℹ️ Detected ARM64 architecture.${C_RESET}"
  1256. else
  1257. echo -e "\n${C_RED}❌ Unsupported architecture: $arch. Cannot install DNSTT.${C_RESET}"
  1258. return
  1259. fi
  1260. curl -sL "$binary_url" -o "$DNSTT_BINARY"
  1261. if [ $? -ne 0 ]; then
  1262. echo -e "\n${C_RED}❌ Failed to download the DNSTT binary.${C_RESET}"
  1263. return
  1264. fi
  1265. chmod +x "$DNSTT_BINARY"
  1266. echo -e "${C_BLUE}🔐 Generating cryptographic keys...${C_RESET}"
  1267. mkdir -p "$DNSTT_KEYS_DIR"
  1268. "$DNSTT_BINARY" -gen-key -privkey-file "$DNSTT_KEYS_DIR/server.key" -pubkey-file "$DNSTT_KEYS_DIR/server.pub"
  1269. if [[ ! -f "$DNSTT_KEYS_DIR/server.key" ]]; then echo -e "${C_RED}❌ Failed to generate DNSTT keys.${C_RESET}"; return; fi
  1270. local PUBLIC_KEY
  1271. PUBLIC_KEY=$(cat "$DNSTT_KEYS_DIR/server.pub")
  1272. echo -e "\n${C_BLUE}📝 Creating systemd service...${C_RESET}"
  1273. cat > "$DNSTT_SERVICE_FILE" <<-EOF
  1274. [Unit]
  1275. Description=DNSTT (DNS Tunnel) Server for $forward_desc
  1276. After=network.target
  1277. [Service]
  1278. Type=simple
  1279. User=root
  1280. ExecStart=$DNSTT_BINARY -udp :53$mtu_string -privkey-file $DNSTT_KEYS_DIR/server.key $TUNNEL_DOMAIN $FORWARD_TARGET
  1281. Restart=always
  1282. RestartSec=3
  1283. [Install]
  1284. WantedBy=multi-user.target
  1285. EOF
  1286. echo -e "\n${C_BLUE}💾 Saving configuration and starting service...${C_RESET}"
  1287. cat > "$DNSTT_CONFIG_FILE" <<-EOF
  1288. NS_SUBDOMAIN="$NS_SUBDOMAIN"
  1289. TUNNEL_SUBDOMAIN="$TUNNEL_SUBDOMAIN"
  1290. NS_DOMAIN="$NS_DOMAIN"
  1291. TUNNEL_DOMAIN="$TUNNEL_DOMAIN"
  1292. PUBLIC_KEY="$PUBLIC_KEY"
  1293. FORWARD_DESC="$forward_desc"
  1294. DNSTT_RECORDS_MANAGED="$DNSTT_RECORDS_MANAGED"
  1295. HAS_IPV6="$HAS_IPV6"
  1296. MTU_VALUE="$mtu_value"
  1297. EOF
  1298. systemctl daemon-reload
  1299. systemctl enable dnstt.service
  1300. systemctl start dnstt.service
  1301. sleep 2
  1302. if systemctl is-active --quiet dnstt.service; then
  1303. echo -e "\n${C_GREEN}✅ SUCCESS: DNSTT has been installed and started!${C_RESET}"
  1304. show_dnstt_details
  1305. else
  1306. echo -e "\n${C_RED}❌ ERROR: DNSTT service failed to start.${C_RESET}"
  1307. journalctl -u dnstt.service -n 15 --no-pager
  1308. fi
  1309. }
  1310. uninstall_dnstt() {
  1311. echo -e "\n${C_BOLD}${C_PURPLE}--- 🗑️ Uninstalling DNSTT ---${C_RESET}"
  1312. if [ ! -f "$DNSTT_SERVICE_FILE" ]; then
  1313. echo -e "${C_YELLOW}ℹ️ DNSTT does not appear to be installed, skipping.${C_RESET}"
  1314. return
  1315. fi
  1316. local confirm="y"
  1317. if [[ "$UNINSTALL_MODE" != "silent" ]]; then
  1318. read -p "👉 Are you sure you want to uninstall DNSTT? This will delete DNS records if they were auto-generated. (y/n): " confirm
  1319. fi
  1320. if [[ "$confirm" != "y" ]]; then
  1321. echo -e "\n${C_YELLOW}❌ Uninstallation cancelled.${C_RESET}"
  1322. return
  1323. fi
  1324. echo -e "${C_BLUE}🛑 Stopping and disabling DNSTT service...${C_RESET}"
  1325. systemctl stop dnstt.service > /dev/null 2>&1
  1326. systemctl disable dnstt.service > /dev/null 2>&1
  1327. if [ -f "$DNSTT_CONFIG_FILE" ]; then
  1328. source "$DNSTT_CONFIG_FILE"
  1329. if [[ "$DNSTT_RECORDS_MANAGED" == "true" ]]; then
  1330. echo -e "${C_BLUE}🗑️ Removing auto-generated DNS records...${C_RESET}"
  1331. curl -s -X DELETE "https://desec.io/api/v1/domains/$DESEC_DOMAIN/rrsets/$TUNNEL_SUBDOMAIN/NS/" \
  1332. -H "Authorization: Token $DESEC_TOKEN" > /dev/null
  1333. curl -s -X DELETE "https://desec.io/api/v1/domains/$DESEC_DOMAIN/rrsets/$NS_SUBDOMAIN/A/" \
  1334. -H "Authorization: Token $DESEC_TOKEN" > /dev/null
  1335. if [[ "$HAS_IPV6" == "true" ]]; then
  1336. curl -s -X DELETE "https://desec.io/api/v1/domains/$DESEC_DOMAIN/rrsets/$NS_SUBDOMAIN/AAAA/" \
  1337. -H "Authorization: Token $DESEC_TOKEN" > /dev/null
  1338. fi
  1339. echo -e "${C_GREEN}✅ DNS records have been removed.${C_RESET}"
  1340. else
  1341. echo -e "${C_YELLOW}⚠️ DNS records were manually configured. Please delete them from your DNS provider.${C_RESET}"
  1342. fi
  1343. fi
  1344. echo -e "${C_BLUE}🗑️ Removing service files and binaries...${C_RESET}"
  1345. rm -f "$DNSTT_SERVICE_FILE"
  1346. rm -f "$DNSTT_BINARY"
  1347. rm -rf "$DNSTT_KEYS_DIR"
  1348. rm -f "$DNSTT_CONFIG_FILE"
  1349. systemctl daemon-reload
  1350. echo -e "${C_YELLOW}ℹ️ Making /etc/resolv.conf writable again...${C_RESET}"
  1351. chattr -i /etc/resolv.conf &>/dev/null
  1352. echo -e "\n${C_GREEN}✅ DNSTT has been successfully uninstalled.${C_RESET}"
  1353. }
  1354. install_falcon_proxy() {
  1355. clear; show_banner
  1356. echo -e "${C_BOLD}${C_PURPLE}--- 🦅 Installing Falcon Proxy (Websockets/Socks) ---${C_RESET}"
  1357. if [ -f "$FALCONPROXY_SERVICE_FILE" ]; then
  1358. echo -e "\n${C_YELLOW}ℹ️ Falcon Proxy is already installed.${C_RESET}"
  1359. if [ -f "$FALCONPROXY_CONFIG_FILE" ]; then
  1360. source "$FALCONPROXY_CONFIG_FILE"
  1361. echo -e " It is configured to run on port(s): ${C_YELLOW}$PORTS${C_RESET}"
  1362. echo -e " Installed Version: ${C_YELLOW}${INSTALLED_VERSION:-Unknown}${C_RESET}"
  1363. fi
  1364. read -p "👉 Do you want to reinstall/update? (y/n): " confirm_reinstall
  1365. if [[ "$confirm_reinstall" != "y" ]]; then return; fi
  1366. fi
  1367. echo -e "\n${C_BLUE}🌐 Fetching available versions from GitHub...${C_RESET}"
  1368. local releases_json=$(curl -s "https://api.github.com/repos/firewallfalcons/FirewallFalcon-Manager/releases")
  1369. if [[ -z "$releases_json" || "$releases_json" == "[]" ]]; then
  1370. echo -e "${C_RED}❌ Error: Could not fetch releases. Check internet or API limits.${C_RESET}"
  1371. return
  1372. fi
  1373. # Extract tag names
  1374. mapfile -t versions < <(echo "$releases_json" | jq -r '.[].tag_name')
  1375. if [ ${#versions[@]} -eq 0 ]; then
  1376. echo -e "${C_RED}❌ No releases found in the repository.${C_RESET}"
  1377. return
  1378. fi
  1379. echo -e "\n${C_CYAN}Select a version to install:${C_RESET}"
  1380. for i in "${!versions[@]}"; do
  1381. printf " ${C_GREEN}[%2d]${C_RESET} %s\n" "$((i+1))" "${versions[$i]}"
  1382. done
  1383. echo -e " ${C_RED} [ 0]${C_RESET} ↩️ Cancel"
  1384. local choice
  1385. while true; do
  1386. read -p "👉 Enter version number [1]: " choice
  1387. choice=${choice:-1}
  1388. if [[ "$choice" == "0" ]]; then return; fi
  1389. if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -le "${#versions[@]}" ]; then
  1390. SELECTED_VERSION="${versions[$((choice-1))]}"
  1391. break
  1392. else
  1393. echo -e "${C_RED}❌ Invalid selection.${C_RESET}"
  1394. fi
  1395. done
  1396. local ports
  1397. read -p "👉 Enter port(s) for Falcon Proxy (e.g., 8080 or 8080 8888) [8080]: " ports
  1398. ports=${ports:-8080}
  1399. local port_array=($ports)
  1400. for port in "${port_array[@]}"; do
  1401. if ! [[ "$port" =~ ^[0-9]+$ ]] || [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
  1402. echo -e "\n${C_RED}❌ Invalid port number: $port. Aborting.${C_RESET}"
  1403. return
  1404. fi
  1405. check_and_free_ports "$port" || return
  1406. check_and_open_firewall_port "$port" tcp || return
  1407. done
  1408. echo -e "\n${C_GREEN}⚙️ Detecting system architecture...${C_RESET}"
  1409. local arch=$(uname -m)
  1410. local binary_name=""
  1411. if [[ "$arch" == "x86_64" ]]; then
  1412. binary_name="falconproxy"
  1413. echo -e "${C_BLUE}ℹ️ Detected x86_64 (amd64) architecture.${C_RESET}"
  1414. elif [[ "$arch" == "aarch64" || "$arch" == "arm64" ]]; then
  1415. binary_name="falconproxyarm"
  1416. echo -e "${C_BLUE}ℹ️ Detected ARM64 architecture.${C_RESET}"
  1417. else
  1418. echo -e "\n${C_RED}❌ Unsupported architecture: $arch. Cannot install Falcon Proxy.${C_RESET}"
  1419. return
  1420. fi
  1421. # Construct download URL based on selected version
  1422. local download_url="https://github.com/firewallfalcons/FirewallFalcon-Manager/releases/download/$SELECTED_VERSION/$binary_name"
  1423. echo -e "\n${C_GREEN}📥 Downloading Falcon Proxy $SELECTED_VERSION ($binary_name)...${C_RESET}"
  1424. wget -q --show-progress -O "$FALCONPROXY_BINARY" "$download_url"
  1425. if [ $? -ne 0 ]; then
  1426. echo -e "\n${C_RED}❌ Failed to download the binary. Please ensure version $SELECTED_VERSION has asset '$binary_name'.${C_RESET}"
  1427. return
  1428. fi
  1429. chmod +x "$FALCONPROXY_BINARY"
  1430. echo -e "\n${C_GREEN}📝 Creating systemd service file...${C_RESET}"
  1431. cat > "$FALCONPROXY_SERVICE_FILE" <<EOF
  1432. [Unit]
  1433. Description=Falcon Proxy ($SELECTED_VERSION)
  1434. After=network.target
  1435. [Service]
  1436. User=root
  1437. Type=simple
  1438. ExecStart=$FALCONPROXY_BINARY -p $ports
  1439. Restart=always
  1440. RestartSec=2s
  1441. [Install]
  1442. WantedBy=default.target
  1443. EOF
  1444. echo -e "\n${C_GREEN}💾 Saving configuration...${C_RESET}"
  1445. cat > "$FALCONPROXY_CONFIG_FILE" <<EOF
  1446. PORTS="$ports"
  1447. INSTALLED_VERSION="$SELECTED_VERSION"
  1448. EOF
  1449. echo -e "\n${C_GREEN}▶️ Enabling and starting Falcon Proxy service...${C_RESET}"
  1450. systemctl daemon-reload
  1451. systemctl enable falconproxy.service
  1452. systemctl restart falconproxy.service
  1453. sleep 2
  1454. if systemctl is-active --quiet falconproxy; then
  1455. echo -e "\n${C_GREEN}✅ SUCCESS: Falcon Proxy $SELECTED_VERSION is installed and active.${C_RESET}"
  1456. echo -e " Listening on port(s): ${C_YELLOW}$ports${C_RESET}"
  1457. else
  1458. echo -e "\n${C_RED}❌ ERROR: Falcon Proxy service failed to start.${C_RESET}"
  1459. echo -e "${C_YELLOW}ℹ️ Displaying last 15 lines of the service log for diagnostics:${C_RESET}"
  1460. journalctl -u falconproxy.service -n 15 --no-pager
  1461. fi
  1462. }
  1463. uninstall_falcon_proxy() {
  1464. echo -e "\n${C_BOLD}${C_PURPLE}--- 🗑️ Uninstalling Falcon Proxy ---${C_RESET}"
  1465. if [ ! -f "$FALCONPROXY_SERVICE_FILE" ]; then
  1466. echo -e "${C_YELLOW}ℹ️ Falcon Proxy is not installed, skipping.${C_RESET}"
  1467. return
  1468. fi
  1469. echo -e "${C_GREEN}🛑 Stopping and disabling Falcon Proxy service...${C_RESET}"
  1470. systemctl stop falconproxy.service >/dev/null 2>&1
  1471. systemctl disable falconproxy.service >/dev/null 2>&1
  1472. echo -e "${C_GREEN}🗑️ Removing service file...${C_RESET}"
  1473. rm -f "$FALCONPROXY_SERVICE_FILE"
  1474. systemctl daemon-reload
  1475. echo -e "${C_GREEN}🗑️ Removing binary and config files...${C_RESET}"
  1476. rm -f "$FALCONPROXY_BINARY"
  1477. rm -f "$FALCONPROXY_CONFIG_FILE"
  1478. echo -e "${C_GREEN}✅ Falcon Proxy has been uninstalled successfully.${C_RESET}"
  1479. }
  1480. # --- ZiVPN Installation Logic ---
  1481. install_zivpn() {
  1482. clear; show_banner
  1483. echo -e "${C_BOLD}${C_PURPLE}--- 🚀 Installing ZiVPN (UDP/VPN) ---${C_RESET}"
  1484. if [ -f "$ZIVPN_SERVICE_FILE" ]; then
  1485. echo -e "\n${C_YELLOW}ℹ️ ZiVPN is already installed.${C_RESET}"
  1486. return
  1487. fi
  1488. echo -e "\n${C_GREEN}⚙️ Checking system architecture...${C_RESET}"
  1489. local arch=$(uname -m)
  1490. local zivpn_url=""
  1491. if [[ "$arch" == "x86_64" ]]; then
  1492. zivpn_url="https://github.com/zahidbd2/udp-zivpn/releases/download/udp-zivpn_1.4.9/udp-zivpn-linux-amd64"
  1493. echo -e "${C_BLUE}ℹ️ Detected AMD64/x86_64 architecture.${C_RESET}"
  1494. elif [[ "$arch" == "aarch64" ]]; then
  1495. zivpn_url="https://github.com/zahidbd2/udp-zivpn/releases/download/udp-zivpn_1.4.9/udp-zivpn-linux-arm64"
  1496. echo -e "${C_BLUE}ℹ️ Detected ARM64 architecture.${C_RESET}"
  1497. elif [[ "$arch" == "armv7l" || "$arch" == "arm" ]]; then
  1498. zivpn_url="https://github.com/zahidbd2/udp-zivpn/releases/download/udp-zivpn_1.4.9/udp-zivpn-linux-arm"
  1499. echo -e "${C_BLUE}ℹ️ Detected ARM architecture.${C_RESET}"
  1500. else
  1501. echo -e "${C_RED}❌ Unsupported architecture: $arch${C_RESET}"
  1502. return
  1503. fi
  1504. echo -e "\n${C_GREEN}📦 Downloading ZiVPN binary...${C_RESET}"
  1505. if ! wget -q --show-progress -O "$ZIVPN_BIN" "$zivpn_url"; then
  1506. echo -e "${C_RED}❌ Download failed. Check internet connection.${C_RESET}"
  1507. return
  1508. fi
  1509. chmod +x "$ZIVPN_BIN"
  1510. echo -e "\n${C_GREEN}⚙️ Configuring ZIVPN...${C_RESET}"
  1511. mkdir -p "$ZIVPN_DIR"
  1512. # Generate Certificates
  1513. echo -e "${C_BLUE}🔐 Generating self-signed certificates...${C_RESET}"
  1514. if ! command -v openssl &>/dev/null; then apt-get install -y openssl &>/dev/null; fi
  1515. openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
  1516. -subj "/C=US/ST=California/L=Los Angeles/O=Example Corp/OU=IT Department/CN=zivpn" \
  1517. -keyout "$ZIVPN_KEY_FILE" -out "$ZIVPN_CERT_FILE" 2>/dev/null
  1518. if [ ! -f "$ZIVPN_CERT_FILE" ]; then
  1519. echo -e "${C_RED}❌ Failed to generate certificates.${C_RESET}"
  1520. return
  1521. fi
  1522. # System Tuning
  1523. echo -e "${C_BLUE}🔧 Tuning system network parameters...${C_RESET}"
  1524. sysctl -w net.core.rmem_max=16777216 >/dev/null
  1525. sysctl -w net.core.wmem_max=16777216 >/dev/null
  1526. # Create Service
  1527. echo -e "${C_BLUE}📝 Creating systemd service file...${C_RESET}"
  1528. cat <<EOF > "$ZIVPN_SERVICE_FILE"
  1529. [Unit]
  1530. Description=zivpn VPN Server
  1531. After=network.target
  1532. [Service]
  1533. Type=simple
  1534. User=root
  1535. WorkingDirectory=$ZIVPN_DIR
  1536. ExecStart=$ZIVPN_BIN server -c $ZIVPN_CONFIG_FILE
  1537. Restart=always
  1538. RestartSec=3
  1539. Environment=ZIVPN_LOG_LEVEL=info
  1540. CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
  1541. AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
  1542. NoNewPrivileges=true
  1543. [Install]
  1544. WantedBy=multi-user.target
  1545. EOF
  1546. # Configure Passwords
  1547. echo -e "\n${C_YELLOW}🔑 ZiVPN Password Setup${C_RESET}"
  1548. read -p "👉 Enter passwords separated by commas (e.g., user1,user2) [Default: 'zi']: " input_config
  1549. if [ -n "$input_config" ]; then
  1550. IFS=',' read -r -a config_array <<< "$input_config"
  1551. # Ensure array format for JSON
  1552. json_passwords=$(printf '"%s",' "${config_array[@]}")
  1553. json_passwords="[${json_passwords%,}]"
  1554. else
  1555. json_passwords='["zi"]'
  1556. fi
  1557. # Create Config File
  1558. cat <<EOF > "$ZIVPN_CONFIG_FILE"
  1559. {
  1560. "listen": ":5667",
  1561. "cert": "$ZIVPN_CERT_FILE",
  1562. "key": "$ZIVPN_KEY_FILE",
  1563. "obfs":"zivpn",
  1564. "auth": {
  1565. "mode": "passwords",
  1566. "config": $json_passwords
  1567. }
  1568. }
  1569. EOF
  1570. echo -e "\n${C_GREEN}🚀 Starting ZiVPN Service...${C_RESET}"
  1571. systemctl daemon-reload
  1572. systemctl enable zivpn.service
  1573. systemctl start zivpn.service
  1574. # Port Forwarding / Firewall
  1575. echo -e "${C_BLUE}🔥 Configuring Firewall Rules (Redirecting 6000-19999 -> 5667)...${C_RESET}"
  1576. # Determine primary interface
  1577. local iface=$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)
  1578. if [ -n "$iface" ]; then
  1579. iptables -t nat -A PREROUTING -i "$iface" -p udp --dport 6000:19999 -j DNAT --to-destination :5667
  1580. # Note: IPTables rules are not persistent by default without iptables-persistent package
  1581. else
  1582. echo -e "${C_YELLOW}⚠️ Could not detect default interface for IPTables redirection.${C_RESET}"
  1583. fi
  1584. if command -v ufw &>/dev/null; then
  1585. ufw allow 6000:19999/udp >/dev/null
  1586. ufw allow 5667/udp >/dev/null
  1587. fi
  1588. # Cleanup
  1589. rm -f zi.sh zi2.sh 2>/dev/null
  1590. if systemctl is-active --quiet zivpn.service; then
  1591. echo -e "\n${C_GREEN}✅ ZiVPN Installed Successfully!${C_RESET}"
  1592. echo -e " - UDP Port: 5667 (Direct)"
  1593. echo -e " - UDP Ports: 6000-19999 (Forwarded)"
  1594. else
  1595. echo -e "\n${C_RED}❌ ZiVPN Service failed to start. Check logs: journalctl -u zivpn.service${C_RESET}"
  1596. fi
  1597. }
  1598. uninstall_zivpn() {
  1599. clear; show_banner
  1600. echo -e "${C_BOLD}${C_PURPLE}--- 🗑️ Uninstall ZiVPN ---${C_RESET}"
  1601. if [ ! -f "$ZIVPN_SERVICE_FILE" ] && [ ! -f "$ZIVPN_BIN" ]; then
  1602. echo -e "\n${C_YELLOW}ℹ️ ZiVPN does not appear to be installed.${C_RESET}"
  1603. return
  1604. fi
  1605. read -p "👉 Are you sure you want to uninstall ZiVPN? (y/n): " confirm
  1606. if [[ "$confirm" != "y" ]]; then echo -e "${C_YELLOW}Cancelled.${C_RESET}"; return; fi
  1607. echo -e "\n${C_BLUE}🛑 Stopping services...${C_RESET}"
  1608. systemctl stop zivpn.service 2>/dev/null
  1609. systemctl disable zivpn.service 2>/dev/null
  1610. echo -e "${C_BLUE}🗑️ Removing files...${C_RESET}"
  1611. rm -f "$ZIVPN_SERVICE_FILE"
  1612. rm -rf "$ZIVPN_DIR"
  1613. rm -f "$ZIVPN_BIN"
  1614. systemctl daemon-reload
  1615. # Clean cache (from original uninstall script logic)
  1616. echo -e "${C_BLUE}🧹 Cleaning memory cache...${C_RESET}"
  1617. sync; echo 3 > /proc/sys/vm/drop_caches
  1618. echo -e "\n${C_GREEN}✅ ZiVPN Uninstalled Successfully.${C_RESET}"
  1619. }
  1620. purge_nginx() {
  1621. local mode="$1"
  1622. if [[ "$mode" != "silent" ]]; then
  1623. clear; show_banner
  1624. echo -e "${C_BOLD}${C_PURPLE}--- 🔥 Purge Nginx Installation ---${C_RESET}"
  1625. if ! command -v nginx &> /dev/null; then
  1626. echo -e "\n${C_YELLOW}ℹ️ Nginx is not installed. Nothing to do.${C_RESET}"
  1627. return
  1628. fi
  1629. read -p "👉 This will COMPLETELY REMOVE Nginx and all its configuration files. Are you sure? (y/n): " confirm
  1630. if [[ "$confirm" != "y" ]]; then
  1631. echo -e "\n${C_YELLOW}❌ Uninstallation cancelled.${C_RESET}"
  1632. return
  1633. fi
  1634. fi
  1635. echo -e "\n${C_BLUE}🛑 Stopping Nginx service...${C_RESET}"
  1636. systemctl stop nginx >/dev/null 2>&1
  1637. echo -e "\n${C_BLUE}🗑️ Purging Nginx packages...${C_RESET}"
  1638. apt-get purge -y nginx nginx-common >/dev/null 2>&1
  1639. apt-get autoremove -y >/dev/null 2>&1
  1640. echo -e "\n${C_BLUE}🗑️ Removing leftover files...${C_RESET}"
  1641. rm -f /etc/ssl/certs/nginx-selfsigned.pem
  1642. rm -f /etc/ssl/private/nginx-selfsigned.key
  1643. rm -rf /etc/nginx
  1644. rm -f "${NGINX_CONFIG_FILE}.bak"
  1645. rm -f "${NGINX_CONFIG_FILE}.bak.certbot"
  1646. rm -f "${NGINX_CONFIG_FILE}.bak.selfsigned"
  1647. if [[ "$mode" != "silent" ]]; then
  1648. echo -e "\n${C_GREEN}✅ Nginx has been completely purged from the system.${C_RESET}"
  1649. fi
  1650. }
  1651. install_nginx_proxy() {
  1652. clear; show_banner
  1653. echo -e "${C_BOLD}${C_PURPLE}--- 🚀 Installing Nginx Main Proxy (Ports 80 & 443) ---${C_RESET}"
  1654. if command -v nginx &> /dev/null; then
  1655. echo -e "\n${C_YELLOW}⚠️ An existing Nginx installation was found.${C_RESET}"
  1656. read -p "👉 To ensure a clean setup, the existing Nginx will be purged. Continue? (y/n): " confirm_purge
  1657. if [[ "$confirm_purge" != "y" ]]; then
  1658. echo -e "\n${C_RED}❌ Installation cancelled.${C_RESET}"
  1659. return
  1660. fi
  1661. purge_nginx "silent"
  1662. fi
  1663. echo -e "\n${C_BLUE}📦 Installing Nginx package...${C_RESET}"
  1664. apt-get update && apt-get install -y nginx || { echo -e "${C_RED}❌ Failed to install Nginx.${C_RESET}"; return; }
  1665. check_and_free_ports "80" "443" || return
  1666. # --- Custom Port Selection ---
  1667. local tls_ports
  1668. read -p "👉 Enter TLS/SSL Port(s) [Default: 443]: " input_tls
  1669. if [[ -z "$input_tls" ]]; then tls_ports="443"; else tls_ports="$input_tls"; fi
  1670. local http_ports
  1671. read -p "👉 Enter HTTP/Non-TLS Port(s) [Default: 80]: " input_http
  1672. if [[ -z "$input_http" ]]; then http_ports="80"; else http_ports="$input_http"; fi
  1673. # Convert to arrays
  1674. read -a tls_ports_array <<< "$tls_ports"
  1675. read -a http_ports_array <<< "$http_ports"
  1676. # Process Ports: Free and Open
  1677. for port in "${tls_ports_array[@]}" "${http_ports_array[@]}"; do
  1678. if ! [[ "$port" =~ ^[0-9]+$ ]]; then echo -e "${C_RED}❌ Invalid port: $port${C_RESET}"; return; fi
  1679. check_and_free_ports "$port" || return
  1680. check_and_open_firewall_port "$port" tcp || return
  1681. done
  1682. echo -e "\n${C_GREEN}🔐 Generating self-signed SSL certificate for Nginx...${C_RESET}"
  1683. local SSL_CERT="/etc/ssl/certs/nginx-selfsigned.pem"
  1684. local SSL_KEY="/etc/ssl/private/nginx-selfsigned.key"
  1685. mkdir -p /etc/ssl/certs /etc/ssl/private
  1686. openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  1687. -keyout "$SSL_KEY" \
  1688. -out "$SSL_CERT" \
  1689. -subj "/CN=firewallfalcon.proxy" >/dev/null 2>&1 || { echo -e "${C_RED}❌ Failed to generate SSL certificate.${C_RESET}"; return; }
  1690. echo -e "\n${C_GREEN}📝 Applying Nginx reverse proxy configuration...${C_RESET}"
  1691. mv "$NGINX_CONFIG_FILE" "${NGINX_CONFIG_FILE}.bak" 2>/dev/null
  1692. # --- Generate Listen Directives ---
  1693. local listen_block=""
  1694. for port in "${http_ports_array[@]}"; do
  1695. listen_block="${listen_block} listen $port;\n listen [::]:$port;\n"
  1696. done
  1697. for port in "${tls_ports_array[@]}"; do
  1698. listen_block="${listen_block} listen $port ssl http2;\n listen [::]:$port ssl http2;\n"
  1699. done
  1700. cat > "$NGINX_CONFIG_FILE" <<EOF
  1701. server {
  1702. server_tokens off;
  1703. server_name _;
  1704. $(echo -e "$listen_block")
  1705. ssl_certificate /etc/ssl/certs/nginx-selfsigned.pem;
  1706. ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
  1707. ssl_protocols TLSv1.2 TLSv1.3;
  1708. ssl_ciphers HIGH:!aNULL:!eNULL:!MD5:!DES:!RC4:!ADH!SSLv3:!EXP!PSK!DSS;
  1709. resolver 8.8.8.8;
  1710. location ~ ^/(?<fwdport>\d+)/(?<fwdpath>.*)$ {
  1711. client_max_body_size 0;
  1712. client_body_timeout 1d;
  1713. grpc_read_timeout 1d;
  1714. grpc_socket_keepalive on;
  1715. proxy_read_timeout 1d;
  1716. proxy_http_version 1.1;
  1717. proxy_buffering off;
  1718. proxy_request_buffering off;
  1719. proxy_socket_keepalive on;
  1720. proxy_set_header Upgrade \$http_upgrade;
  1721. proxy_set_header Connection "upgrade";
  1722. proxy_set_header Host \$host;
  1723. proxy_set_header X-Real-IP \$remote_addr;
  1724. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  1725. if (\$content_type ~* "GRPC") { grpc_pass grpc://127.0.0.1:\$fwdport\$is_args\$args; break; }
  1726. proxy_pass http://127.0.0.1:\$fwdport\$is_args\$args;
  1727. break;
  1728. }
  1729. location / {
  1730. proxy_read_timeout 3600s;
  1731. proxy_buffering off;
  1732. proxy_request_buffering off;
  1733. proxy_http_version 1.1;
  1734. proxy_socket_keepalive on;
  1735. tcp_nodelay on;
  1736. tcp_nopush off;
  1737. proxy_pass http://127.0.0.1:8080;
  1738. proxy_set_header Upgrade \$http_upgrade;
  1739. proxy_set_header Connection "upgrade";
  1740. proxy_set_header Host \$host;
  1741. proxy_set_header X-Real-IP \$remote_addr;
  1742. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  1743. }
  1744. }
  1745. EOF
  1746. echo -e "\n${C_GREEN}▶️ Restarting Nginx service...${C_RESET}"
  1747. systemctl restart nginx
  1748. sleep 2
  1749. if systemctl is-active --quiet nginx; then
  1750. echo -e "\n${C_GREEN}✅ SUCCESS: Nginx Reverse Proxy is active.${C_RESET}"
  1751. echo -e " - TLS Ports: ${C_YELLOW}${tls_ports}${C_RESET}"
  1752. echo -e " - HTTP Ports: ${C_YELLOW}${http_ports}${C_RESET}"
  1753. # Save ports for future reference
  1754. echo "TLS_PORTS=\"$tls_ports\"" > "$NGINX_PORTS_FILE"
  1755. echo "HTTP_PORTS=\"$http_ports\"" >> "$NGINX_PORTS_FILE"
  1756. else
  1757. echo -e "\n${C_RED}❌ ERROR: Nginx service failed to start.${C_RESET}"
  1758. echo -e "${C_YELLOW}ℹ️ Displaying Nginx status for diagnostics:${C_RESET}"
  1759. systemctl status nginx --no-pager
  1760. echo -e "${C_YELLOW}🔄 Restoring previous Nginx config...${C_RESET}"
  1761. mv "${NGINX_CONFIG_FILE}.bak" "$NGINX_CONFIG_FILE" 2>/dev/null
  1762. fi
  1763. }
  1764. _install_certbot() {
  1765. if command -v certbot &> /dev/null; then
  1766. echo -e "${C_GREEN}✅ Certbot is already installed.${C_RESET}"
  1767. return 0
  1768. fi
  1769. echo -e "${C_YELLOW}⚠️ Certbot (for SSL) is not found.${C_RESET}"
  1770. read -p "👉 Do you want to install Certbot now? (y/n): " confirm_install
  1771. if [[ "$confirm_install" != "y" ]]; then
  1772. echo -e "${C_RED}❌ Installation skipped. Cannot proceed.${C_RESET}"
  1773. return 1
  1774. fi
  1775. echo -e "${C_BLUE}📦 Installing Certbot...${C_RESET}"
  1776. apt-get update > /dev/null 2>&1
  1777. apt-get install -y certbot || {
  1778. echo -e "${C_RED}❌ Failed to install Certbot.${C_RESET}"
  1779. return 1
  1780. }
  1781. echo -e "${C_GREEN}✅ Certbot installed successfully.${C_RESET}"
  1782. return 0
  1783. }
  1784. request_certbot_ssl() {
  1785. clear; show_banner
  1786. echo -e "${C_BOLD}${C_PURPLE}--- 🔒 Request Let's Encrypt SSL (Certbot) ---${C_RESET}"
  1787. if ! systemctl is-active --quiet nginx; then
  1788. echo -e "\n${C_RED}❌ Nginx is not running. Please ensure Nginx is installed and active.${C_RESET}"
  1789. return
  1790. fi
  1791. _install_certbot || return
  1792. echo
  1793. read -p "👉 Enter your domain name (e.g., vps.example.com): " domain_name
  1794. if [[ -z "$domain_name" ]]; then
  1795. echo -e "\n${C_RED}❌ Domain name cannot be empty. Aborting.${C_RESET}"
  1796. return
  1797. fi
  1798. read -p "👉 Enter your email address (for Let's Encrypt): " email
  1799. if [[ -z "$email" ]]; then
  1800. echo -e "\n${C_RED}❌ Email address cannot be empty. Aborting.${C_RESET}"
  1801. return
  1802. fi
  1803. echo -e "\n${C_BLUE}🛑 Stopping Nginx temporarily for validation...${C_RESET}"
  1804. systemctl stop nginx
  1805. sleep 2
  1806. if ss -lntp | grep -q ":80\s"; then
  1807. echo -e "${C_RED}❌ Failed to free port 80, another process might be using it. Aborting.${C_RESET}"
  1808. systemctl start nginx
  1809. return
  1810. fi
  1811. echo -e "\n${C_BLUE}🚀 Requesting certificate for ${C_YELLOW}$domain_name...${C_RESET}"
  1812. certbot certonly --standalone -d "$domain_name" --non-interactive --agree-tos -m "$email"
  1813. if [ $? -ne 0 ]; then
  1814. echo -e "\n${C_RED}❌ Certbot failed to obtain a certificate.${C_RESET}"
  1815. echo -e "${C_YELLOW}ℹ️ Please check your domain's DNS 'A' record points to this server's IP.${C_RESET}"
  1816. systemctl start nginx
  1817. return
  1818. fi
  1819. local SSL_CERT_LIVE="/etc/letsencrypt/live/$domain_name/fullchain.pem"
  1820. local SSL_KEY_LIVE="/etc/letsencrypt/live/$domain_name/privkey.pem"
  1821. if [ ! -f "$SSL_CERT_LIVE" ] || [ ! -f "$SSL_KEY_LIVE" ]; then
  1822. echo -e "\n${C_RED}❌ Certbot succeeded, but cert files not found at expected location.${C_RESET}"
  1823. systemctl start nginx
  1824. return
  1825. fi
  1826. echo -e "\n${C_GREEN}✅ Certificate obtained successfully!${C_RESET}"
  1827. echo -e "${C_BLUE}📝 Updating Nginx configuration...${C_RESET}"
  1828. cp "$NGINX_CONFIG_FILE" "${NGINX_CONFIG_FILE}.bak.selfsigned"
  1829. sed -i "s|server_name _;|server_name $domain_name;|" "$NGINX_CONFIG_FILE"
  1830. sed -i "s|ssl_certificate /etc/ssl/certs/nginx-selfsigned.pem;|ssl_certificate $SSL_CERT_LIVE;|" "$NGINX_CONFIG_FILE"
  1831. sed -i "s|ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;|ssl_certificate_key $SSL_KEY_LIVE;|" "$NGINX_CONFIG_FILE"
  1832. echo -e "\n${C_BLUE}▶️ Restarting Nginx with new certificate...${C_RESET}"
  1833. systemctl start nginx
  1834. sleep 2
  1835. if systemctl is-active --quiet nginx; then
  1836. echo -e "\n${C_GREEN}✅ SUCCESS: Nginx is active with your new Let's Encrypt certificate!${C_RESET}"
  1837. else
  1838. echo -e "\n${C_RED}❌ ERROR: Nginx failed to start with the new certificate.${C_RESET}"
  1839. echo -e "${C_YELLOW}🔄 Restoring self-signed certificate config...${C_RESET}"
  1840. mv "${NGINX_CONFIG_FILE}.bak.selfsigned" "$NGINX_CONFIG_FILE"
  1841. systemctl restart nginx
  1842. fi
  1843. }
  1844. nginx_proxy_menu() {
  1845. clear; show_banner
  1846. echo -e "${C_BOLD}${C_PURPLE}--- 🌐 Nginx Main Proxy Management ---${C_RESET}"
  1847. local active_status="${C_STATUS_I}Inactive${C_RESET}"
  1848. if systemctl is-active --quiet nginx; then
  1849. active_status="${C_STATUS_A}Active${C_RESET}"
  1850. fi
  1851. # Retrieve Ports Info
  1852. local ports_info=""
  1853. if [ -f "$NGINX_PORTS_FILE" ]; then
  1854. source "$NGINX_PORTS_FILE"
  1855. ports_info="\n ${C_DIM}TLS: $TLS_PORTS | HTTP: $HTTP_PORTS${C_RESET}"
  1856. fi
  1857. echo -e "\n${C_WHITE}Current Status: ${active_status}${ports_info}"
  1858. echo -e "\n${C_BOLD}Select an action:${C_RESET}\n"
  1859. if systemctl is-active --quiet nginx; then
  1860. printf " ${C_CHOICE}[ 1]${C_RESET} %-40s\n" "🛑 Stop Nginx Service"
  1861. printf " ${C_CHOICE}[ 2]${C_RESET} %-40s\n" "🔄 Restart Nginx Service"
  1862. printf " ${C_CHOICE}[ 3]${C_RESET} %-40s\n" "⚙️ Re-install/Re-configure (Change Ports)"
  1863. printf " ${C_CHOICE}[ 4]${C_RESET} %-40s\n" "🔒 Request/Renew SSL (Certbot)"
  1864. printf " ${C_CHOICE}[ 5]${C_RESET} %-40s\n" "🔥 Uninstall/Purge Nginx"
  1865. else
  1866. printf " ${C_CHOICE}[ 1]${C_RESET} %-40s\n" "▶️ Start Nginx Service"
  1867. printf " ${C_CHOICE}[ 3]${C_RESET} %-40s\n" "⚙️ Install/Configure Nginx"
  1868. printf " ${C_CHOICE}[ 5]${C_RESET} %-40s\n" "🔥 Uninstall/Purge Nginx"
  1869. fi
  1870. echo -e "\n ${C_WARN}[ 0]${C_RESET} ↩️ Return to previous menu"
  1871. echo
  1872. read -p "👉 Enter your choice: " choice
  1873. case $choice in
  1874. 1)
  1875. if systemctl is-active --quiet nginx; then
  1876. echo -e "\n${C_BLUE}🛑 Stopping Nginx...${C_RESET}"
  1877. systemctl stop nginx
  1878. echo -e "${C_GREEN}✅ Nginx stopped.${C_RESET}"
  1879. else
  1880. echo -e "\n${C_BLUE}▶️ Starting Nginx...${C_RESET}"
  1881. systemctl start nginx
  1882. if systemctl is-active --quiet nginx; then echo -e "${C_GREEN}✅ Nginx Started.${C_RESET}"; else echo -e "${C_RED}❌ Failed to start.${C_RESET}"; fi
  1883. fi
  1884. press_enter
  1885. ;;
  1886. 2)
  1887. echo -e "\n${C_BLUE}🔄 Restarting Nginx...${C_RESET}"
  1888. systemctl restart nginx
  1889. press_enter
  1890. ;;
  1891. 3)
  1892. install_nginx_proxy; press_enter
  1893. ;;
  1894. 4)
  1895. request_certbot_ssl; press_enter
  1896. ;;
  1897. 5)
  1898. purge_nginx; press_enter
  1899. ;;
  1900. 0) return ;;
  1901. *) invalid_option ;;
  1902. esac
  1903. }
  1904. install_xui_panel() {
  1905. clear; show_banner
  1906. echo -e "${C_BOLD}${C_PURPLE}--- 🚀 Install X-UI Panel ---${C_RESET}"
  1907. echo -e "\nThis will download and run the official installation script for X-UI."
  1908. echo -e "Choose an installation option:\n"
  1909. echo -e "Choose an installation option:\n"
  1910. printf " ${C_GREEN}[ 1]${C_RESET} %-40s\n" "Install the latest version of X-UI"
  1911. printf " ${C_GREEN}[ 2]${C_RESET} %-40s\n" "Install a specific version of X-UI"
  1912. echo -e "\n ${C_RED}[ 0]${C_RESET} ❌ Cancel Installation"
  1913. echo
  1914. read -p "👉 Select an option: " choice
  1915. case $choice in
  1916. 1)
  1917. echo -e "\n${C_BLUE}⚙️ Installing the latest version...${C_RESET}"
  1918. bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/master/install.sh)
  1919. ;;
  1920. 2)
  1921. read -p "👉 Enter the version to install (e.g., 1.8.0): " version
  1922. if [[ -z "$version" ]]; then
  1923. echo -e "\n${C_RED}❌ Version number cannot be empty.${C_RESET}"
  1924. return
  1925. fi
  1926. echo -e "\n${C_BLUE}⚙️ Installing version ${C_YELLOW}$version...${C_RESET}"
  1927. VERSION=$version bash <(curl -Ls "https://raw.githubusercontent.com/alireza0/x-ui/$version/install.sh") "$version"
  1928. ;;
  1929. 0)
  1930. echo -e "\n${C_YELLOW}❌ Installation cancelled.${C_RESET}"
  1931. ;;
  1932. *)
  1933. echo -e "\n${C_RED}❌ Invalid option.${C_RESET}"
  1934. ;;
  1935. esac
  1936. }
  1937. uninstall_xui_panel() {
  1938. clear; show_banner
  1939. echo -e "${C_BOLD}${C_PURPLE}--- 🗑️ Uninstall X-UI Panel ---${C_RESET}"
  1940. if ! command -v x-ui &> /dev/null; then
  1941. echo -e "\n${C_YELLOW}ℹ️ X-UI does not appear to be installed.${C_RESET}"
  1942. return
  1943. fi
  1944. read -p "👉 Are you sure you want to thoroughly uninstall X-UI? (y/n): " confirm
  1945. if [[ "$confirm" == "y" ]]; then
  1946. echo -e "\n${C_BLUE}⚙️ Running the default X-UI uninstaller first...${C_RESET}"
  1947. x-ui uninstall >/dev/null 2>&1
  1948. echo -e "\n${C_BLUE}🧹 Performing a full cleanup to ensure complete removal...${C_RESET}"
  1949. echo " - Stopping and disabling x-ui service..."
  1950. systemctl stop x-ui >/dev/null 2>&1
  1951. systemctl disable x-ui >/dev/null 2>&1
  1952. echo " - Removing x-ui files and directories..."
  1953. rm -f /etc/systemd/system/x-ui.service
  1954. rm -f /usr/local/bin/x-ui
  1955. rm -rf /usr/local/x-ui/
  1956. rm -rf /etc/x-ui/
  1957. echo " - Reloading systemd daemon..."
  1958. systemctl daemon-reload
  1959. echo -e "\n${C_GREEN}✅ X-UI has been thoroughly uninstalled.${C_RESET}"
  1960. else
  1961. echo -e "\n${C_YELLOW}❌ Uninstallation cancelled.${C_RESET}"
  1962. fi
  1963. }
  1964. show_banner() {
  1965. local os_name=$(grep -oP 'PRETTY_NAME="\K[^"]+' /etc/os-release || echo "Linux")
  1966. local up_time=$(uptime -p | sed 's/up //')
  1967. local ram_usage=$(free -m | awk '/^Mem:/{printf "%.2f", $3*100/$2}')
  1968. # Efficient CPU Load check (Load Average)
  1969. local cpu_load=$(cat /proc/loadavg | awk '{print $1}')
  1970. local online_users=0
  1971. # Optimize online user count: Get total active sshd procs roughly (may overcount if multiple procs per session but faster)
  1972. # Or just keep it if DB is small. Let's trust pgrep is okay for menu load.
  1973. if [[ -s "$DB_FILE" ]]; then
  1974. while IFS=: read -r user pass expiry limit; do
  1975. # Use pgrep -c for speed
  1976. local count=$(pgrep -c -u "$user" sshd)
  1977. online_users=$((online_users + count))
  1978. done < "$DB_FILE"
  1979. fi
  1980. local total_users=0
  1981. if [[ -s "$DB_FILE" ]]; then total_users=$(grep -c . "$DB_FILE"); fi
  1982. clear
  1983. echo
  1984. echo -e "${C_TITLE} FirewallFalcon Manager ${C_RESET}${C_DIM}| v3.5.0 Premium Edition${C_RESET}"
  1985. echo -e "${C_BLUE} ─────────────────────────────────────────────────────────${C_RESET}"
  1986. printf " ${C_GRAY}%-10s${C_RESET} %-20s ${C_GRAY}|${C_RESET} %s\n" "OS" "$os_name" "Uptime: $up_time"
  1987. printf " ${C_GRAY}%-10s${C_RESET} %-20s ${C_GRAY}|${C_RESET} %s\n" "Memory" "${ram_usage}% Used" "Online Sessions: ${C_WHITE}${online_users}${C_RESET}"
  1988. printf " ${C_GRAY}%-10s${C_RESET} %-20s ${C_GRAY}|${C_RESET} %s\n" "Users" "${total_users} Managed Accounts" "Sys Load (1m): ${C_GREEN}${cpu_load}${C_RESET}"
  1989. echo -e "${C_BLUE} ─────────────────────────────────────────────────────────${C_RESET}"
  1990. }
  1991. protocol_menu() {
  1992. while true; do
  1993. show_banner
  1994. local badvpn_status; if systemctl is-active --quiet badvpn; then badvpn_status="${C_STATUS_A}(Active)${C_RESET}"; else badvpn_status="${C_STATUS_I}(Inactive)${C_RESET}"; fi
  1995. local udp_custom_status; if systemctl is-active --quiet udp-custom; then udp_custom_status="${C_STATUS_A}(Active)${C_RESET}"; else udp_custom_status="${C_STATUS_I}(Inactive)${C_RESET}"; fi
  1996. local zivpn_status; if systemctl is-active --quiet zivpn.service; then zivpn_status="${C_STATUS_A}(Active)${C_RESET}"; else zivpn_status="${C_STATUS_I}(Inactive)${C_RESET}"; fi
  1997. local ssl_tunnel_text="SSL Tunnel (Port 444)"
  1998. local ssl_tunnel_status="${C_STATUS_I}(Inactive)${C_RESET}"
  1999. if systemctl is-active --quiet haproxy; then
  2000. local active_port
  2001. active_port=$(grep -oP 'bind \*:(\d+)' "$HAPROXY_CONFIG" 2>/dev/null | awk -F: '{print $2}')
  2002. if [[ -n "$active_port" ]]; then
  2003. ssl_tunnel_text="SSL Tunnel (Port $active_port)"
  2004. fi
  2005. ssl_tunnel_status="${C_STATUS_A}(Active)${C_RESET}"
  2006. fi
  2007. local dnstt_status; if systemctl is-active --quiet dnstt.service; then dnstt_status="${C_STATUS_A}(Active)${C_RESET}"; else dnstt_status="${C_STATUS_I}(Inactive)${C_RESET}"; fi
  2008. local falconproxy_status="${C_STATUS_I}(Inactive)${C_RESET}"
  2009. local falconproxy_ports=""
  2010. if systemctl is-active --quiet falconproxy; then
  2011. if [ -f "$FALCONPROXY_CONFIG_FILE" ]; then source "$FALCONPROXY_CONFIG_FILE"; fi
  2012. falconproxy_ports=" ($PORTS)"
  2013. falconproxy_status="${C_STATUS_A}(Active - ${INSTALLED_VERSION:-latest})${C_RESET}"
  2014. fi
  2015. local nginx_status; if systemctl is-active --quiet nginx; then nginx_status="${C_STATUS_A}(Active)${C_RESET}"; else nginx_status="${C_STATUS_I}(Inactive)${C_RESET}"; fi
  2016. local xui_status; if command -v x-ui &> /dev/null; then xui_status="${C_STATUS_A}(Installed)${C_RESET}"; else xui_status="${C_STATUS_I}(Not Installed)${C_RESET}"; fi
  2017. echo -e "\n ${C_TITLE}══════════════[ ${C_BOLD}🔌 PROTOCOL & PANEL MANAGEMENT ${C_RESET}${C_TITLE}]══════════════${C_RESET}"
  2018. echo -e " ${C_ACCENT}--- TUNNELLING PROTOCOLS---${C_RESET}"
  2019. printf " ${C_CHOICE}[ 1]${C_RESET} %-45s %s\n" "🚀 Install badvpn (UDP 7300)" "$badvpn_status"
  2020. printf " ${C_CHOICE}[ 2]${C_RESET} %-45s\n" "🗑️ Uninstall badvpn"
  2021. printf " ${C_CHOICE}[ 3]${C_RESET} %-45s %s\n" "🚀 Install udp-custom" "$udp_custom_status"
  2022. printf " ${C_CHOICE}[ 4]${C_RESET} %-45s\n" "🗑️ Uninstall udp-custom"
  2023. printf " ${C_CHOICE}[ 5]${C_RESET} %-45s %s\n" "🔒 Install ${ssl_tunnel_text}" "$ssl_tunnel_status"
  2024. printf " ${C_CHOICE}[ 6]${C_RESET} %-45s\n" "🗑️ Uninstall SSL Tunnel"
  2025. printf " ${C_CHOICE}[ 7]${C_RESET} %-45s %s\n" "📡 Install/View DNSTT (Port 53)" "$dnstt_status"
  2026. printf " ${C_CHOICE}[ 8]${C_RESET} %-45s\n" "🗑️ Uninstall DNSTT"
  2027. printf " ${C_CHOICE}[ 9]${C_RESET} %-45s %s\n" "🦅 Install Falcon Proxy (Select Version)" "$falconproxy_status"
  2028. printf " ${C_CHOICE}[10]${C_RESET} %-45s\n" "🗑️ Uninstall Falcon Proxy"
  2029. printf " ${C_CHOICE}[11]${C_RESET} %-45s %s\n" "🌐 Install/Manage Nginx Proxy (80/443)" "$nginx_status"
  2030. printf " ${C_CHOICE}[16]${C_RESET} %-45s %s\n" "🛡️ Install ZiVPN (UDP 5667)" "$zivpn_status"
  2031. printf " ${C_CHOICE}[17]${C_RESET} %-45s\n" "🗑️ Uninstall ZiVPN"
  2032. echo -e " ${C_ACCENT}--- 💻 MANAGEMENT PANELS ---${C_RESET}"
  2033. printf " ${C_CHOICE}[12]${C_RESET} %-45s %s\n" "💻 Install X-UI Panel" "$xui_status"
  2034. printf " ${C_CHOICE}[13]${C_RESET} %-45s\n" "🗑️ Uninstall X-UI Panel"
  2035. echo -e " ${C_DIM}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~${C_RESET}"
  2036. echo -e " ${C_WARN}[ 0]${C_RESET} ↩️ Return to Main Menu"
  2037. echo
  2038. read -p "$(echo -e ${C_PROMPT}"👉 Select an option: "${C_RESET})" choice
  2039. case $choice in
  2040. 1) install_badvpn; press_enter ;; 2) uninstall_badvpn; press_enter ;;
  2041. 3) install_udp_custom; press_enter ;; 4) uninstall_udp_custom; press_enter ;;
  2042. 5) install_ssl_tunnel; press_enter ;; 6) uninstall_ssl_tunnel; press_enter ;;
  2043. 7) install_dnstt; press_enter ;; 8) uninstall_dnstt; press_enter ;;
  2044. 9) install_falcon_proxy; press_enter ;; 10) uninstall_falcon_proxy; press_enter ;;
  2045. 11) nginx_proxy_menu ;;
  2046. 12) install_xui_panel; press_enter ;; 13) uninstall_xui_panel; press_enter ;;
  2047. 16) install_zivpn; press_enter ;; 17) uninstall_zivpn; press_enter ;;
  2048. 0) return ;;
  2049. *) invalid_option ;;
  2050. esac
  2051. done
  2052. }
  2053. install_dt_proxy_full() {
  2054. clear; show_banner
  2055. echo -e "${C_BOLD}${C_PURPLE}--- 🚀 Full DT Tunnel Installation ---${C_RESET}"
  2056. if [ -f "/usr/local/bin/main" ]; then
  2057. echo -e "\n${C_YELLOW}ℹ️ DT Proxy appears to be already installed.${C_RESET}"
  2058. echo -e "If you wish to reinstall, please uninstall it first."
  2059. return
  2060. fi
  2061. echo -e "\n${C_BLUE}--- Step 1 of 2: Installing DT Tunnel Mod ---${C_RESET}"
  2062. echo "This will download and run the prerequisite mod installer."
  2063. read -p "👉 Press [Enter] to continue or [Ctrl+C] to cancel."
  2064. if curl -sL https://raw.githubusercontent.com/firewallfalcons/ProxyMods/main/install.sh | bash; then
  2065. echo -e "\n${C_GREEN}✅ DT Tunnel Mod installed successfully.${C_RESET}"
  2066. else
  2067. echo -e "\n${C_RED}❌ ERROR: DT Tunnel Mod installation failed. Aborting.${C_RESET}"
  2068. return
  2069. fi
  2070. echo -e "\n${C_BLUE}--- Step 2 of 2: Installing DT Tunnel Proxy ---${C_RESET}"
  2071. echo "This will download and run the main DT Tunnel proxy installer."
  2072. read -p "👉 Press [Enter] to continue or [Ctrl+C] to cancel."
  2073. if bash <(curl -fsSL https://raw.githubusercontent.com/firewallfalcons/ProxyDT-Go-Releases/main/install.sh); then
  2074. echo -e "\n${C_GREEN}✅ DT Tunnel Proxy installed successfully.${C_RESET}"
  2075. echo -e "You can now manage it from the DT Proxy Management menu."
  2076. else
  2077. echo -e "\n${C_RED}❌ ERROR: DT Tunnel Proxy installation failed.${C_RESET}"
  2078. fi
  2079. }
  2080. launch_dt_proxy_menu() {
  2081. clear; show_banner
  2082. if [ -f "/usr/local/bin/main" ]; then
  2083. echo -e "\n${C_GREEN}✅ DT Proxy is installed. Launching its management panel...${C_RESET}"
  2084. sleep 2
  2085. /usr/local/bin/main
  2086. else
  2087. echo -e "\n${C_RED}❌ DT Proxy is not installed. Please use the install option first.${C_RESET}"
  2088. fi
  2089. }
  2090. uninstall_dt_proxy_full() {
  2091. clear; show_banner
  2092. echo -e "${C_BOLD}${C_PURPLE}--- 🗑️ Uninstall DT Proxy (Mod + Proxy) ---${C_RESET}"
  2093. if [ ! -f "/usr/local/bin/proxy" ] && [ ! -f "/usr/local/bin/main" ]; then
  2094. echo -e "\n${C_YELLOW}ℹ️ DT Proxy is not installed. Nothing to do.${C_RESET}"
  2095. return
  2096. fi
  2097. read -p "👉 Are you sure you want to PERMANENTLY delete DT Proxy and all its services? (y/n): " confirm
  2098. if [[ "$confirm" != "y" ]]; then
  2099. echo -e "\n${C_YELLOW}❌ Uninstallation cancelled.${C_RESET}"
  2100. return
  2101. fi
  2102. echo -e "\n${C_BLUE}🛑 Stopping and disabling all DT Proxy services...${C_RESET}"
  2103. systemctl list-units --type=service --state=running | grep 'proxy-' | awk '{print $1}' | xargs -r systemctl stop
  2104. systemctl list-unit-files --type=service | grep 'proxy-' | awk '{print $1}' | xargs -r systemctl disable
  2105. echo -e "\n${C_BLUE}🗑️ Removing files...${C_RESET}"
  2106. rm -f /etc/systemd/system/proxy-*.service
  2107. systemctl daemon-reload
  2108. rm -f /usr/local/bin/proxy
  2109. rm -f /usr/local/bin/main
  2110. rm -f "$HOME/.proxy_token"
  2111. rm -f /var/log/proxy-*.log
  2112. rm -f /usr/local/bin/install_mod
  2113. echo -e "\n${C_GREEN}✅ DT Proxy has been successfully uninstalled.${C_RESET}"
  2114. }
  2115. dt_proxy_menu() {
  2116. while true; do
  2117. show_banner
  2118. local dt_proxy_status
  2119. if [ -f "/usr/local/bin/main" ] && [ -f "/usr/local/bin/proxy" ]; then
  2120. dt_proxy_status="${C_STATUS_A}(Installed)${C_RESET}"
  2121. else
  2122. dt_proxy_status="${C_STATUS_I}(Not Installed)${C_RESET}"
  2123. fi
  2124. echo -e "\n ${C_TITLE}═════════════════[ ${C_BOLD}🚀 DT Proxy Management ${dt_proxy_status} ${C_RESET}${C_TITLE}]═════════════════${C_RESET}"
  2125. printf " ${C_CHOICE}[ 1]${C_RESET} %-45s\n" "🚀 Install DT Tunnel (Mod + Proxy)"
  2126. printf " ${C_CHOICE}[ 2]${C_RESET} %-45s\n" "▶️ Launch DT Tunnel Management Menu"
  2127. printf " ${C_DANGER}[ 3]${C_RESET} %-45s\n" "🗑️ Uninstall DT Tunnel (Mod + Proxy)"
  2128. echo -e " ${C_DIM}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~${C_RESET}"
  2129. echo -e " ${C_WARN}[ 0]${C_RESET} ↩️ Return to Main Menu"
  2130. echo
  2131. read -p "$(echo -e ${C_PROMPT}"👉 Select an option: "${C_RESET})" choice
  2132. case $choice in
  2133. 1) install_dt_proxy_full; press_enter ;;
  2134. 2) launch_dt_proxy_menu; press_enter ;;
  2135. 3) uninstall_dt_proxy_full; press_enter ;;
  2136. 0) return ;;
  2137. *) invalid_option ;;
  2138. esac
  2139. done
  2140. }
  2141. uninstall_script() {
  2142. clear; show_banner
  2143. echo -e "${C_RED}=====================================================${C_RESET}"
  2144. echo -e "${C_RED} 🔥 DANGER: UNINSTALL SCRIPT & ALL DATA 🔥 ${C_RESET}"
  2145. echo -e "${C_RED}=====================================================${C_RESET}"
  2146. echo -e "${C_YELLOW}This will PERMANENTLY remove this script and all its components, including:"
  2147. echo -e " - The main command ($(command -v menu))"
  2148. echo -e " - All configuration and user data ($DB_DIR)"
  2149. echo -e " - The active limiter service ($LIMITER_SERVICE)"
  2150. echo -e " - All installed services (badvpn, udp-custom, SSL Tunnel, Nginx, DNSTT, FalconProxy)"
  2151. echo -e "\n${C_RED}This action is irreversible.${C_RESET}"
  2152. echo ""
  2153. read -p "👉 Type 'yes' to confirm and proceed with uninstallation: " confirm
  2154. if [[ "$confirm" != "yes" ]]; then
  2155. echo -e "\n${C_GREEN}✅ Uninstallation cancelled.${C_RESET}"
  2156. return
  2157. fi
  2158. export UNINSTALL_MODE="silent"
  2159. echo -e "\n${C_BLUE}--- 💥 Starting Uninstallation 💥 ---${C_RESET}"
  2160. echo -e "\n${C_BLUE}🗑️ Removing active limiter service...${C_RESET}"
  2161. systemctl stop firewallfalcon-limiter &>/dev/null
  2162. systemctl disable firewallfalcon-limiter &>/dev/null
  2163. rm -f "$LIMITER_SERVICE"
  2164. rm -f "$LIMITER_SCRIPT"
  2165. chattr -i /etc/resolv.conf &>/dev/null
  2166. purge_nginx "silent"
  2167. uninstall_dnstt
  2168. uninstall_badvpn
  2169. uninstall_udp_custom
  2170. uninstall_ssl_tunnel
  2171. uninstall_falcon_proxy
  2172. uninstall_zivpn
  2173. delete_dns_record
  2174. echo -e "\n${C_BLUE}🔄 Reloading systemd daemon...${C_RESET}"
  2175. systemctl daemon-reload
  2176. echo -e "\n${C_BLUE}🗑️ Removing script and configuration files...${C_RESET}"
  2177. rm -rf "$BADVPN_BUILD_DIR"
  2178. rm -rf "$UDP_CUSTOM_DIR"
  2179. rm -rf "$DB_DIR"
  2180. rm -f "$(command -v menu)"
  2181. echo -e "\n${C_GREEN}=============================================${C_RESET}"
  2182. echo -e "${C_GREEN} Script has been successfully uninstalled. ${C_RESET}"
  2183. echo -e "${C_GREEN}=============================================${C_RESET}"
  2184. echo -e "\nAll associated files and services have been removed."
  2185. echo "The 'menu' command will no longer work."
  2186. exit 0
  2187. }
  2188. # --- NEW FEATURES ---
  2189. generate_client_config() {
  2190. local user=$1
  2191. local pass=$2
  2192. # Auto-detect Host
  2193. local host_ip=$(curl -s -4 icanhazip.com)
  2194. local host_domain="$host_ip"
  2195. if [ -f "$DNS_INFO_FILE" ]; then
  2196. local managed_domain=$(grep 'FULL_DOMAIN' "$DNS_INFO_FILE" | cut -d'"' -f2)
  2197. if [[ -n "$managed_domain" ]]; then host_domain="$managed_domain"; fi
  2198. fi
  2199. # Also check if Nginx Certbot is used
  2200. if [ -f "$NGINX_CONFIG_FILE" ]; then
  2201. local nginx_domain=$(grep -oP 'server_name \K[^\s;]+' "$NGINX_CONFIG_FILE" | head -n 1)
  2202. if [[ "$nginx_domain" != "_" && -n "$nginx_domain" ]]; then host_domain="$nginx_domain"; fi
  2203. fi
  2204. echo -e "\n${C_BOLD}${C_PURPLE}--- 📱 Client Connection Configuration ---${C_RESET}"
  2205. echo -e "${C_CYAN}Copy the details below to your clipboard:${C_RESET}\n"
  2206. echo -e "${C_YELLOW}========================================${C_RESET}"
  2207. echo -e "👤 ${C_BOLD}User Details${C_RESET}"
  2208. echo -e " • Username: ${C_WHITE}$user${C_RESET}"
  2209. echo -e " • Password: ${C_WHITE}$pass${C_RESET}"
  2210. echo -e " • Host/IP : ${C_WHITE}$host_domain${C_RESET}"
  2211. echo -e "${C_YELLOW}========================================${C_RESET}"
  2212. # 1. SSH Direct
  2213. echo -e "\n🔹 ${C_BOLD}SSH Direct${C_RESET}:"
  2214. echo -e " • Host: $host_domain"
  2215. echo -e " • Port: 22"
  2216. echo -e " • payload: (Standard SSH)"
  2217. # 2. SSL/TLS Tunnel (HAProxy or Nginx)
  2218. local ssl_port=""
  2219. local ssl_type=""
  2220. # Check HAProxy
  2221. if systemctl is-active --quiet haproxy; then
  2222. local haproxy_port=$(grep -oP 'bind \*:(\d+)' "$HAPROXY_CONFIG" 2>/dev/null | awk -F: '{print $2}')
  2223. if [[ -n "$haproxy_port" ]]; then ssl_port="$haproxy_port"; ssl_type="HAProxy"; fi
  2224. fi
  2225. # Check Nginx (Override if both exist, or show both)
  2226. if systemctl is-active --quiet nginx && [ -f "$NGINX_PORTS_FILE" ]; then
  2227. source "$NGINX_PORTS_FILE"
  2228. # Take the first TLS port
  2229. local nginx_ssl_port=$(echo "$TLS_PORTS" | awk '{print $1}')
  2230. if [[ -n "$nginx_ssl_port" ]]; then
  2231. if [[ -n "$ssl_port" ]]; then ssl_port="$ssl_port, $nginx_ssl_port"; else ssl_port="$nginx_ssl_port"; fi
  2232. ssl_type="Nginx/TLS"
  2233. fi
  2234. fi
  2235. if [[ -n "$ssl_port" ]]; then
  2236. echo -e "\n🔹 ${C_BOLD}SSL/TLS Tunnel ($ssl_type)${C_RESET}:"
  2237. echo -e " • Host: $host_domain"
  2238. echo -e " • Port(s): $ssl_port"
  2239. echo -e " • SNI (BugHost): $host_domain (or your preferred SNI)"
  2240. fi
  2241. # 3. UDP Custom
  2242. if systemctl is-active --quiet udp-custom; then
  2243. echo -e "\n🔹 ${C_BOLD}UDP Custom${C_RESET}:"
  2244. echo -e " • IP: $host_ip (Must use numeric IP)"
  2245. echo -e " • Port: 1-65535 (Exclude 53, 5300)"
  2246. echo -e " • Obfs: (None/Plain)"
  2247. fi
  2248. # 4. DNSTT
  2249. if systemctl is-active --quiet dnstt; then
  2250. if [ -f "$DNSTT_CONFIG_FILE" ]; then
  2251. source "$DNSTT_CONFIG_FILE"
  2252. echo -e "\n🔹 ${C_BOLD}DNSTT (SlowDNS)${C_RESET}:"
  2253. echo -e " • Nameserver: $TUNNEL_DOMAIN"
  2254. echo -e " • PubKey: $PUBLIC_KEY"
  2255. echo -e " • DNS IP: 1.1.1.1 / 8.8.8.8"
  2256. fi
  2257. fi
  2258. # 5. ZiVPN
  2259. if systemctl is-active --quiet zivpn; then
  2260. echo -e "\n🔹 ${C_BOLD}ZiVPN${C_RESET}:"
  2261. echo -e " • UDP Port: 5667"
  2262. echo -e " • Forwarded Ports: 6000-19999"
  2263. fi
  2264. echo -e "${C_YELLOW}========================================${C_RESET}"
  2265. press_enter
  2266. }
  2267. client_config_menu() {
  2268. _select_user_interface "--- 📱 Generate Client Config ---"
  2269. local u=$SELECTED_USER
  2270. if [[ "$u" == "NO_USERS" || -z "$u" ]]; then return; fi
  2271. # We need to find the password. It's in the DB.
  2272. local pass=$(grep "^$u:" "$DB_FILE" | cut -d: -f2)
  2273. generate_client_config "$u" "$pass"
  2274. }
  2275. # Lightweight Bash Monitor (No vnStat required)
  2276. simple_live_monitor() {
  2277. local iface=$1
  2278. echo -e "\n${C_BLUE}⚡ Starting Lightweight Traffic Monitor for $iface...${C_RESET}"
  2279. echo -e "${C_DIM}Press [Ctrl+C] to stop.${C_RESET}\n"
  2280. # Get initial values
  2281. local rx1=$(cat /sys/class/net/$iface/statistics/rx_bytes)
  2282. local tx1=$(cat /sys/class/net/$iface/statistics/tx_bytes)
  2283. printf "%-15s | %-15s\n" "⬇️ Download" "⬆️ Upload"
  2284. echo "-----------------------------------"
  2285. while true; do
  2286. sleep 1
  2287. local rx2=$(cat /sys/class/net/$iface/statistics/rx_bytes)
  2288. local tx2=$(cat /sys/class/net/$iface/statistics/tx_bytes)
  2289. # Calculate diffs
  2290. local rx_diff=$((rx2 - rx1))
  2291. local tx_diff=$((tx2 - tx1))
  2292. # Convert to KB/s
  2293. local rx_kbs=$((rx_diff / 1024))
  2294. local tx_kbs=$((tx_diff / 1024))
  2295. # Formatting for MB/s if > 1024 KB
  2296. if [ $rx_kbs -gt 1024 ]; then rx_fmt=$(awk "BEGIN {printf \"%.2f MB/s\", $rx_kbs/1024}"); else rx_fmt="${rx_kbs} KB/s"; fi
  2297. if [ $tx_kbs -gt 1024 ]; then tx_fmt=$(awk "BEGIN {printf \"%.2f MB/s\", $tx_kbs/1024}"); else tx_fmt="${tx_kbs} KB/s"; fi
  2298. printf "\r%-15s | %-15s" "$rx_fmt" "$tx_fmt"
  2299. # Reset for next loop
  2300. rx1=$rx2
  2301. tx1=$tx2
  2302. done
  2303. }
  2304. traffic_monitor_menu() {
  2305. clear; show_banner
  2306. echo -e "${C_BOLD}${C_PURPLE}--- 📈 Network Traffic Monitor ---${C_RESET}"
  2307. # Find active interface
  2308. local iface=$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)
  2309. echo -e "\nInterface: ${C_CYAN}${iface}${C_RESET}"
  2310. echo -e "\n${C_BOLD}Select a monitoring option:${C_RESET}\n"
  2311. printf " ${C_CHOICE}[ 1]${C_RESET} %-40s\n" "⚡ Live Monitor ${C_DIM}(Lightweight, No Install)${C_RESET}"
  2312. printf " ${C_CHOICE}[ 2]${C_RESET} %-40s\n" "📊 View Total Traffic Since Boot"
  2313. printf " ${C_CHOICE}[ 3]${C_RESET} %-40s\n" "📅 Daily/Monthly Logs ${C_DIM}(Requires vnStat)${C_RESET}"
  2314. echo -e "\n ${C_WARN}[ 0]${C_RESET} ↩️ Return"
  2315. echo
  2316. read -p "👉 Enter choice: " t_choice
  2317. case $t_choice in
  2318. 1)
  2319. simple_live_monitor "$iface"
  2320. ;;
  2321. 2)
  2322. local rx_total=$(cat /sys/class/net/$iface/statistics/rx_bytes)
  2323. local tx_total=$(cat /sys/class/net/$iface/statistics/tx_bytes)
  2324. local rx_mb=$((rx_total / 1024 / 1024))
  2325. local tx_mb=$((tx_total / 1024 / 1024))
  2326. echo -e "\n${C_BLUE}📊 Total Traffic (Since Boot):${C_RESET}"
  2327. echo -e " ⬇️ Download: ${C_WHITE}${rx_mb} MB${C_RESET}"
  2328. echo -e " ⬆️ Upload: ${C_WHITE}${tx_mb} MB${C_RESET}"
  2329. press_enter
  2330. ;;
  2331. 3)
  2332. # vnStat Logic
  2333. if ! command -v vnstat &> /dev/null; then
  2334. echo -e "\n${C_YELLOW}⚠️ vnStat is not installed.${C_RESET}"
  2335. echo -e " This tool provides persistent history (Daily/Monthly reports)."
  2336. echo -e " It is lightweight but requires installation."
  2337. read -p "👉 Install vnStat now? (y/n): " confirm
  2338. if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
  2339. echo -e "\n${C_BLUE}📦 Installing vnStat...${C_RESET}"
  2340. apt-get update >/dev/null 2>&1
  2341. apt-get install -y vnstat >/dev/null 2>&1
  2342. systemctl enable vnstat >/dev/null 2>&1
  2343. systemctl restart vnstat >/dev/null 2>&1
  2344. local default_iface=$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)
  2345. vnstat --add -i "$default_iface" >/dev/null 2>&1
  2346. echo -e "${C_GREEN}✅ Installed.${C_RESET}"
  2347. sleep 1
  2348. else
  2349. return
  2350. fi
  2351. fi
  2352. echo
  2353. vnstat -i "$iface"
  2354. echo -e "\n${C_DIM}Run 'vnstat -d' or 'vnstat -m' manually for specific views.${C_RESET}"
  2355. press_enter
  2356. ;;
  2357. *) return ;;
  2358. esac
  2359. }
  2360. torrent_block_menu() {
  2361. clear; show_banner
  2362. echo -e "${C_BOLD}${C_PURPLE}--- 🚫 Torrent Blocking (Anti-Torrent) ---${C_RESET}"
  2363. # Check status
  2364. local torrent_status="${C_STATUS_I}Disabled${C_RESET}"
  2365. if iptables -L FORWARD | grep -q "ipp2p"; then
  2366. torrent_status="${C_STATUS_A}Enabled${C_RESET}"
  2367. elif iptables -L OUTPUT | grep -q "BitTorrent"; then
  2368. # Fallback check for string matching
  2369. torrent_status="${C_STATUS_A}Enabled${C_RESET}"
  2370. fi
  2371. echo -e "\n${C_WHITE}Current Status: ${torrent_status}${C_RESET}"
  2372. echo -e "${C_DIM}This feature uses iptables string matching to block common torrent keywords.${C_RESET}"
  2373. echo -e "\n${C_BOLD}Select an action:${C_RESET}\n"
  2374. printf " ${C_CHOICE}[ 1]${C_RESET} %-40s\n" "🔒 Enable Torrent Blocking"
  2375. printf " ${C_CHOICE}[ 2]${C_RESET} %-40s\n" "🔓 Disable Torrent Blocking"
  2376. echo -e "\n ${C_WARN}[ 0]${C_RESET} ↩️ Return"
  2377. echo
  2378. read -p "👉 Enter choice: " b_choice
  2379. case $b_choice in
  2380. 1)
  2381. echo -e "\n${C_BLUE}🛡️ Applying Anti-Torrent rules...${C_RESET}"
  2382. # Clean old rules first to avoid duplicates
  2383. _flush_torrent_rules
  2384. # Block Common Torrent Ports/Keywords
  2385. # String matching using iptables extension
  2386. iptables -A FORWARD -m string --string "BitTorrent" --algo bm -j DROP
  2387. iptables -A FORWARD -m string --string "BitTorrent protocol" --algo bm -j DROP
  2388. iptables -A FORWARD -m string --string "peer_id=" --algo bm -j DROP
  2389. iptables -A FORWARD -m string --string ".torrent" --algo bm -j DROP
  2390. iptables -A FORWARD -m string --string "announce.php?passkey=" --algo bm -j DROP
  2391. iptables -A FORWARD -m string --string "torrent" --algo bm -j DROP
  2392. iptables -A FORWARD -m string --string "info_hash" --algo bm -j DROP
  2393. iptables -A FORWARD -m string --string "get_peers" --algo bm -j DROP
  2394. iptables -A FORWARD -m string --string "find_node" --algo bm -j DROP
  2395. # Same for OUTPUT to be safe
  2396. iptables -A OUTPUT -m string --string "BitTorrent" --algo bm -j DROP
  2397. iptables -A OUTPUT -m string --string "BitTorrent protocol" --algo bm -j DROP
  2398. iptables -A OUTPUT -m string --string "peer_id=" --algo bm -j DROP
  2399. iptables -A OUTPUT -m string --string ".torrent" --algo bm -j DROP
  2400. iptables -A OUTPUT -m string --string "announce.php?passkey=" --algo bm -j DROP
  2401. iptables -A OUTPUT -m string --string "torrent" --algo bm -j DROP
  2402. iptables -A OUTPUT -m string --string "info_hash" --algo bm -j DROP
  2403. iptables -A OUTPUT -m string --string "get_peers" --algo bm -j DROP
  2404. iptables -A OUTPUT -m string --string "find_node" --algo bm -j DROP
  2405. # Attempt to save if iptables-persistent exists
  2406. if dpkg -s iptables-persistent &>/dev/null; then
  2407. netfilter-persistent save &>/dev/null
  2408. fi
  2409. echo -e "${C_GREEN}✅ Torrent Blocking Enabled.${C_RESET}"
  2410. press_enter
  2411. ;;
  2412. 2)
  2413. echo -e "\n${C_BLUE}🔓 Removing Anti-Torrent rules...${C_RESET}"
  2414. _flush_torrent_rules
  2415. if dpkg -s iptables-persistent &>/dev/null; then
  2416. netfilter-persistent save &>/dev/null
  2417. fi
  2418. echo -e "${C_GREEN}✅ Torrent Blocking Disabled.${C_RESET}"
  2419. press_enter
  2420. ;;
  2421. *) return ;;
  2422. esac
  2423. }
  2424. _flush_torrent_rules() {
  2425. # Helper to remove rules containing specific strings
  2426. # This is a bit brute-force but effective for this script's scope
  2427. iptables -D FORWARD -m string --string "BitTorrent" --algo bm -j DROP 2>/dev/null
  2428. iptables -D FORWARD -m string --string "BitTorrent protocol" --algo bm -j DROP 2>/dev/null
  2429. iptables -D FORWARD -m string --string "peer_id=" --algo bm -j DROP 2>/dev/null
  2430. iptables -D FORWARD -m string --string ".torrent" --algo bm -j DROP 2>/dev/null
  2431. iptables -D FORWARD -m string --string "announce.php?passkey=" --algo bm -j DROP 2>/dev/null
  2432. iptables -D FORWARD -m string --string "torrent" --algo bm -j DROP 2>/dev/null
  2433. iptables -D FORWARD -m string --string "info_hash" --algo bm -j DROP 2>/dev/null
  2434. iptables -D FORWARD -m string --string "get_peers" --algo bm -j DROP 2>/dev/null
  2435. iptables -D FORWARD -m string --string "find_node" --algo bm -j DROP 2>/dev/null
  2436. iptables -D OUTPUT -m string --string "BitTorrent" --algo bm -j DROP 2>/dev/null
  2437. iptables -D OUTPUT -m string --string "BitTorrent protocol" --algo bm -j DROP 2>/dev/null
  2438. iptables -D OUTPUT -m string --string "peer_id=" --algo bm -j DROP 2>/dev/null
  2439. iptables -D OUTPUT -m string --string ".torrent" --algo bm -j DROP 2>/dev/null
  2440. iptables -D OUTPUT -m string --string "announce.php?passkey=" --algo bm -j DROP 2>/dev/null
  2441. iptables -D OUTPUT -m string --string "torrent" --algo bm -j DROP 2>/dev/null
  2442. iptables -D OUTPUT -m string --string "info_hash" --algo bm -j DROP 2>/dev/null
  2443. iptables -D OUTPUT -m string --string "get_peers" --algo bm -j DROP 2>/dev/null
  2444. iptables -D OUTPUT -m string --string "find_node" --algo bm -j DROP 2>/dev/null
  2445. }
  2446. auto_reboot_menu() {
  2447. clear; show_banner
  2448. echo -e "${C_BOLD}${C_PURPLE}--- 🔄 Auto-Reboot Management ---${C_RESET}"
  2449. # Check status
  2450. local cron_check=$(crontab -l 2>/dev/null | grep "systemctl reboot")
  2451. local status="${C_STATUS_I}Disabled${C_RESET}"
  2452. if [[ -n "$cron_check" ]]; then
  2453. status="${C_STATUS_A}Active (Midnight)${C_RESET}"
  2454. fi
  2455. echo -e "\n${C_WHITE}Current Status: ${status}${C_RESET}"
  2456. echo -e "\n${C_BOLD}Select an action:${C_RESET}\n"
  2457. printf " ${C_CHOICE}[ 1]${C_RESET} %-40s\n" "🕐 Enable Daily Reboot (00:00 midnight)"
  2458. printf " ${C_CHOICE}[ 2]${C_RESET} %-40s\n" "❌ Disable Auto-Reboot"
  2459. echo -e "\n ${C_WARN}[ 0]${C_RESET} ↩️ Return"
  2460. echo
  2461. read -p "👉 Enter choice: " r_choice
  2462. case $r_choice in
  2463. 1)
  2464. # Remove existing to prevent duplicates
  2465. (crontab -l 2>/dev/null | grep -v "systemctl reboot") | crontab -
  2466. # Add new job
  2467. (crontab -l 2>/dev/null; echo "0 0 * * * systemctl reboot") | crontab -
  2468. echo -e "\n${C_GREEN}✅ Auto-reboot scheduled for every day at 00:00.${C_RESET}"
  2469. press_enter
  2470. ;;
  2471. 2)
  2472. (crontab -l 2>/dev/null | grep -v "systemctl reboot") | crontab -
  2473. echo -e "\n${C_GREEN}✅ Auto-reboot disabled.${C_RESET}"
  2474. press_enter
  2475. ;;
  2476. *) return ;;
  2477. esac
  2478. }
  2479. press_enter() {
  2480. echo -e "\nPress ${C_YELLOW}[Enter]${C_RESET} to return to the menu..." && read -r
  2481. }
  2482. invalid_option() {
  2483. echo -e "\n${C_RED}❌ Invalid option.${C_RESET}" && sleep 1
  2484. }
  2485. main_menu() {
  2486. while true; do
  2487. export UNINSTALL_MODE="interactive"
  2488. show_banner
  2489. echo
  2490. echo -e " ${C_TITLE}═══════════════[ ${C_BOLD}👤 USER MANAGEMENT ${C_RESET}${C_TITLE}]═══════════════${C_RESET}"
  2491. printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "1" "Create New User" "5" "Unlock User Account"
  2492. printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "2" "Delete User" "6" "Edit User Details"
  2493. printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "3" "Renew User Account" "7" "List Managed Users"
  2494. printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "4" "Lock User Account" "8" "Generate Client Config"
  2495. echo
  2496. echo -e " ${C_TITLE}════════════[ ${C_BOLD}🌐 VPN & PROTOCOLS ${C_RESET}${C_TITLE}]═════════════${C_RESET}"
  2497. printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "9" "Protocol Manager" "11" "Traffic Monitor (Lite)"
  2498. printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "10" "DT Proxy Manager" "12" "Block Torrent (Anti-P2P)"
  2499. echo
  2500. echo -e " ${C_TITLE}════════════[ ${C_BOLD}⚙️ SYSTEM SETTINGS ${C_RESET}${C_TITLE}]═════════════${C_RESET}"
  2501. printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "13" "CloudFlare Free Domain" "16" "Backup User Data"
  2502. printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "14" "SSH Banner Config" "17" "Restore User Data"
  2503. printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "15" "Auto-Reboot Task" "18" "Cleanup Expired Users"
  2504. echo
  2505. echo -e " ${C_DANGER}═══════════════════[ ${C_BOLD}🔥 DANGER ZONE ${C_RESET}${C_DANGER}]═══════════════════${C_RESET}"
  2506. echo -e " ${C_DANGER}[99]${C_RESET} Uninstall Script ${C_WARN}[ 0]${C_RESET} Exit"
  2507. echo
  2508. read -p "$(echo -e ${C_PROMPT}"👉 Select an option: "${C_RESET})" choice
  2509. case $choice in
  2510. 1) create_user; press_enter ;;
  2511. 2) delete_user; press_enter ;;
  2512. 3) renew_user; press_enter ;;
  2513. 4) lock_user; press_enter ;;
  2514. 5) unlock_user; press_enter ;;
  2515. 6) edit_user; press_enter ;;
  2516. 7) list_users; press_enter ;;
  2517. 8) client_config_menu; press_enter ;;
  2518. 9) protocol_menu ;;
  2519. 10) dt_proxy_menu ;;
  2520. 11) traffic_monitor_menu ;;
  2521. 12) torrent_block_menu ;;
  2522. 13) dns_menu; press_enter ;;
  2523. 14) ssh_banner_menu ;;
  2524. 15) auto_reboot_menu ;;
  2525. 16) backup_user_data; press_enter ;;
  2526. 17) restore_user_data; press_enter ;;
  2527. 18) cleanup_expired; press_enter ;;
  2528. 99) uninstall_script ;;
  2529. 0) exit 0 ;;
  2530. *) invalid_option ;;
  2531. esac
  2532. done
  2533. }
  2534. if [[ "$1" == "--install-setup" ]]; then
  2535. initial_setup
  2536. exit 0
  2537. fi
  2538. main_menu