menu.sh 148 KB

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