77# Licencia: PolyForm Noncommercial License 1.0.0
88# Copyright: (c) 2026 LadyKernel
99# -------------------------------------------------------------------------
10- # Se permite el uso personal y educativo gratuito.
1110# El uso comercial o empresarial requiere autorización previa.
12- #
1311# Consultas de licencias o uso profesional: hola@lksys.es
1412# -------------------------------------------------------------------------
1513
16- # --- 1. SEGURIDAD DE EJECUCIÓN (Fail-safe) ---
1714set -euo pipefail
18- # Restringimos el PATH para evitar Path Hijacking
1915export PATH=" /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
2016
21- # --- 2 . RUTAS ABSOLUTAS DE HERRAMIENTAS (Anti-suplantación) ---
17+ # --- 1 . RUTAS ---
2218CURL=" /usr/bin/curl"
2319JQ=" /usr/bin/jq"
2420AWK=" /usr/bin/awk"
@@ -29,152 +25,113 @@ CHMOD="/usr/bin/chmod"
2925STAT=" /usr/bin/stat"
3026SED=" /usr/bin/sed"
3127GREP=" /usr/bin/grep"
32-
33- # Aseguramos formato numérico internacional
28+ REPO_URL=" https://github.com/LadyKernel/MyIronGuard"
3429export LC_ALL=C
3530
36- # --- 3. CARGA SEGURA DE CONFIGURACIÓN ---
31+ # --- 2. CONFIGURACIÓN ---
3732DIR=" $( cd " $( dirname " ${BASH_SOURCE[0]} " ) " && pwd) "
3833ENV_FILE=" $DIR /.env"
3934
4035if [ -f " $ENV_FILE " ]; then
41- # Hardening: El .env solo debe ser legible por el dueño (600)
4236 PERMS=$( $STAT -c " %a" " $ENV_FILE " )
4337 [ " $PERMS " -ne 600 ] && $CHMOD 600 " $ENV_FILE "
44-
45- # Limpiamos retornos de carro y cargamos variables
4638 $SED -i ' s/\r//g' " $ENV_FILE "
47- # Cargamos variables evitando que fallen si hay líneas vacías o comentarios
48- set -a
49- # shellcheck disable=SC1090
50- . " $ENV_FILE "
51- set +a
39+ set -a; . " $ENV_FILE " ; set +a
5240else
53- echo " ❌ Error: Archivo .env no encontrado en $DIR " >&2
54- exit 1
41+ echo " ❌ Error: .env no encontrado." >&2 ; exit 1
5542fi
5643
57- # Validaciones de variables críticas
5844INTERFACE=${INTERFACE:- " ens6" }
5945LIMITE_DIARIO=${LIMITE_DIARIO:- 0.1}
6046LIMITE_MENSUAL=${LIMITE_MENSUAL:- 900}
6147PRECIO_GB=${PRECIO_GB:- 0}
6248TOKEN=${TOKEN:- " " }
6349CHAT_ID=${CHAT_ID:- " " }
50+ UMBRAL_ALERTA=${UMBRAL_ALERTA:- 0.9}
51+ STEP_D=0.05
52+ STEP_M=0.1
6453
6554STATE_DIA=" $DIR /.alert_state_dia_${INTERFACE} .txt"
6655STATE_MES=" $DIR /.alert_state_mes_${INTERFACE} .txt"
56+ CONTROL_MES=" $DIR /.last_month_${INTERFACE} .txt"
6757
68- # --- 4. VERIFICACIÓN DE DEPENDENCIAS ---
69- for cmd in " $CURL " " $JQ " " $AWK " " $VNSTAT " ; do
70- if [ ! -x " $cmd " ]; then
71- echo " ❌ Error: No se encuentra o no es ejecutable: $cmd " >&2
72- exit 1
73- fi
74- done
58+ # --- 3. LÓGICA DE RESET MENSUAL ---
59+ MES_ACTUAL=$( $DATE +%m)
60+ [ -f " $CONTROL_MES " ] || echo " $MES_ACTUAL " > " $CONTROL_MES "
61+ [ -f " $STATE_DIA " ] || echo " 0" > " $STATE_DIA "
62+ [ -f " $STATE_MES " ] || echo " 0" > " $STATE_MES "
63+
64+ if [ " $MES_ACTUAL " != " $( cat " $CONTROL_MES " ) " ]; then
65+ echo " 0" > " $STATE_DIA "
66+ echo " 0" > " $STATE_MES "
67+ echo " $MES_ACTUAL " > " $CONTROL_MES "
68+ [ -t 1 ] && echo " ♻️ Cambio de mes detectado. Reiniciando contadores."
69+ fi
7570
76- # --- 5. CAPTURA Y PROCESAMIENTO ---
77- # Actualizamos vnstat
71+ # --- 4. CAPTURA Y PROCESAMIENTO ---
7872$VNSTAT -u -i " $INTERFACE " > /dev/null 2>&1 || true
7973JSON_DATA=$( $VNSTAT -i " $INTERFACE " --json 2> /dev/null)
80-
81- if [ -z " $JSON_DATA " ] || [ " $JSON_DATA " == " null" ]; then
82- echo " ❌ Error: Datos de vnstat vacíos para $INTERFACE " >&2
83- exit 1
84- fi
74+ [ -z " $JSON_DATA " ] || [ " $JSON_DATA " == " null" ] && exit 1
8575
8676DIVISOR=1073741824
77+ calc_gb () { $AWK " BEGIN {printf \" %.2f\" , $1 / $DIVISOR }" ; }
8778
88- # Extracción de bytes con JQ
8979RX_D=$( echo " $JSON_DATA " | $JQ -r ' (.interfaces[0].traffic.day // .interfaces[0].traffic.days) | last | .rx // 0' )
9080TX_D=$( echo " $JSON_DATA " | $JQ -r ' (.interfaces[0].traffic.day // .interfaces[0].traffic.days) | last | .tx // 0' )
9181RX_M=$( echo " $JSON_DATA " | $JQ -r ' (.interfaces[0].traffic.month // .interfaces[0].traffic.months) | last | .rx // 0' )
9282TX_M=$( echo " $JSON_DATA " | $JQ -r ' (.interfaces[0].traffic.month // .interfaces[0].traffic.months) | last | .tx // 0' )
9383
94- # Cálculos con AWK
95- calc_gb () { $AWK " BEGIN {printf \" %.2f\" , $1 / $DIVISOR }" ; }
96-
97- RX_DIA_GB=$( calc_gb " $RX_D " )
98- TX_DIA_GB=$( calc_gb " $TX_D " )
99- TOTAL_DIA_GB=$( awk " BEGIN {printf \" %.2f\" , $RX_DIA_GB + $TX_DIA_GB }" )
100-
101- RX_MES_GB=$( calc_gb " $RX_M " )
102- TX_MES_GB=$( calc_gb " $TX_M " )
103- TOTAL_MES_GB=$( awk " BEGIN {printf \" %.2f\" , $RX_MES_GB + $TX_MES_GB }" )
104-
105- # --- 6. LÓGICA DE ALERTAS ---
106- [ -f " $STATE_DIA " ] || echo " 0" > " $STATE_DIA "
107- [ -f " $STATE_MES " ] || echo " 0" > " $STATE_MES "
108- $CHMOD 600 " $STATE_DIA " " $STATE_MES "
84+ TOTAL_DIA_GB=$( awk " BEGIN {printf \" %.2f\" , $( calc_gb " $RX_D " ) + $( calc_gb " $TX_D " ) }" )
85+ TOTAL_MES_GB=$( awk " BEGIN {printf \" %.2f\" , $( calc_gb " $RX_M " ) + $( calc_gb " $TX_M " ) }" )
10986
87+ # --- 5. LÓGICA DE ALERTAS ---
11088ULTIMO_ALERTA_DIA=$( cat " $STATE_DIA " )
11189ULTIMO_ALERTA_MES=$( cat " $STATE_MES " )
11290
113- AVISO_DIA=$( awk -v t=" $TOTAL_DIA_GB " -v l=" $LIMITE_DIARIO " -v u=" $ULTIMO_ALERTA_DIA " ' BEGIN {print (t > l && t >= u + 0.05) ? 1 : 0}' )
114- AVISO_MES=$( awk -v t=" $TOTAL_MES_GB " -v l=" $LIMITE_MENSUAL " -v u=" $ULTIMO_ALERTA_MES " ' BEGIN {print (t > l && t >= u + 0.1) ? 1 : 0}' )
91+ ES_CRITICO=$( awk -v td=" $TOTAL_DIA_GB " -v ld=" $LIMITE_DIARIO " -v tm=" $TOTAL_MES_GB " -v lm=" $LIMITE_MENSUAL " -v u=" $UMBRAL_ALERTA " ' BEGIN {print (td >= (ld*u) || tm >= (lm*u)) ? 1 : 0}' )
92+ AVISO_DIA=$( awk -v t=" $TOTAL_DIA_GB " -v l=" $LIMITE_DIARIO " -v u=" $UMBRAL_ALERTA " -v last=" $ULTIMO_ALERTA_DIA " -v s=" $STEP_D " ' BEGIN { inc=(t>=last+s); cross_u=(t>=l*u && last<l*u); print (inc || cross_u) ? 1 : 0 }' )
93+ AVISO_MES=$( awk -v t=" $TOTAL_MES_GB " -v l=" $LIMITE_MENSUAL " -v u=" $UMBRAL_ALERTA " -v last=" $ULTIMO_ALERTA_MES " -v s=" $STEP_M " ' BEGIN { inc=(t>=last+s); cross_u=(t>=l*u && last<l*u); print (inc || cross_u) ? 1 : 0 }' )
11594
116- # --- 7 . SALIDA VISUAL (Modo Interactivo) ---
95+ # --- 6 . SALIDA VISUAL ---
11796if [ -t 1 ]; then
11897 echo " ======================================"
119- echo " 📊 MONITOR DE RED (Interfaz: $INTERFACE ) )"
98+ echo " 📊 MONITOR DE RED (Interfaz: $IFACE )"
12099 echo " ======================================"
121- echo " 📅 Tráfico HOY: $TOTAL_DIA_GB GB (Límite: $LIMITE_DIARIO GB)"
122- echo " 🗓️ Tráfico MES: $TOTAL_MES_GB GB (Límite: $LIMITE_MENSUAL GB)"
123- echo " 🔔 Último aviso Telegram (Hoy): ${ULTIMO_ALERTA_DIA} GB"
124- echo " 🔔 Último aviso Telegram (Mes): ${ULTIMO_ALERTA_MES} GB"
100+ echo " 📅 Tráfico HOY: $TOTAL_DIA_GB GB (Límite: $LIM_DIA GB)"
101+ echo " 🗓️ Tráfico MES: $TOTAL_MES_GB GB (Límite: $LIM_MES GB)"
125102 echo " --------------------------------------"
126- if [ " $AVISO_DIA " -eq 1 ] || [ " $AVISO_MES " -eq 1 ]; then
127- echo " ⚠️ LÍMITE SUPERADO - Preparando Telegram..."
128- else
129- echo " ✅ Estado: Bajo control."
130- fi
103+ echo " 🛡️ MyIronGuard v2.0 (PolyForm NC)"
104+ echo " 🏢 Empresa: hola@lksys.es"
105+ echo " ⭐ Si te gusta el script, apóyame con una estrella en:"
106+ echo -e " 🔗 \e[1;34mRepo: $REPO_URL \e[0m"
131107 echo " ======================================"
132108fi
133109
134- # --- 8. ENVÍO A TELEGRAM ---
135- if [ " $AVISO_DIA " -eq 1 ] || [ " $AVISO_MES " -eq 1 ]; then
136110
137- COSTE_ESTIMADO=$( awk -v tx=" $TOTAL_MES_GB " -v lim=" $LIMITE_MENSUAL " -v p=" $PRECIO_GB " \
138- ' BEGIN { if (tx > lim) printf "%.2f", (tx - lim) * p; else printf "0.00"; }' )
139-
140- formato_dinamico () {
141- local val=" $1 "
142- awk -v n=" $val " ' BEGIN { if (n < 1 && n > 0) printf "%.2f MB", n * 1024; else printf "%.2f GB", n; }'
143- }
111+ # --- 7. TELEGRAM ---
112+ if [ " $AVISO_DIA " -eq 1 ] || [ " $AVISO_MES " -eq 1 ]; then
113+ COSTE_ESTIMADO=$( awk -v tx=" $TOTAL_MES_GB " -v lim=" $LIMITE_MENSUAL " -v p=" $PRECIO_GB " ' BEGIN { if (tx > lim) printf "%.2f", (tx - lim) * p; else printf "0.00"; }' )
114+ formato_dinamico () { awk -v n=" $1 " ' BEGIN { if (n < 1 && n > 0) printf "%.2f MB", n * 1024; else printf "%.2f GB", n; }' ; }
144115
145- # Título fijo por seguridad y claridad
146- TITULO= " ⚠️ *ALERTA DE TRÁFICO GCLOUD* "
116+ [ " $ES_CRITICO " -eq 1 ] && TITULO= " ⚠️ *ALERTA VPS CRÍTICA (GCLOUD)* " || TITULO= " ⚠️ *ALERTA VPS (GCLOUD)* "
117+ FOOTER= $( [ " $ES_CRITICO " -eq 1 ] && echo -e " \n\n⭐ *¡Apoya el proyecto con una estrella!*\n $REPO_URL " || echo " " )
147118
148119 MENSAJE=" $TITULO
149120-------------------------------
150121📅 *CONSUMO DE HOY:*
151- 📥 Descarga: $( formato_dinamico " $RX_DIA_GB " )
152- 📤 Subida: $( formato_dinamico " $TX_DIA_GB " )
153122📊 Total Día: *$( formato_dinamico " $TOTAL_DIA_GB " ) * / $LIMITE_DIARIO GB
154123
155124🗓️ *CONSUMO DEL MES ($( $DATE +%B) ):*
156- 📥 Descarga: $( formato_dinamico " $RX_MES_GB " )
157- 📤 Subida: $( formato_dinamico " $TX_MES_GB " )
158125✨ Total Mes: *$( formato_dinamico " $TOTAL_MES_GB " ) * / $LIMITE_MENSUAL GB
159126💰 Coste Extra: *\$ ${COSTE_ESTIMADO} *
160127-------------------------------
161128🌐 Interfaz: $INTERFACE
162- 🖥️ Hostname: $( $HOSTNAME_CMD ) "
129+ 🖥️ Hostname: $( $HOSTNAME_CMD ) $FOOTER "
163130
164131 if [ -n " $TOKEN " ] && [ -n " $CHAT_ID " ]; then
165- # Generamos el JSON con JQ para neutralizar cualquier inyección en el mensaje
166132 PAYLOAD=$( $JQ -n --arg cid " $CHAT_ID " --arg txt " $MENSAJE " ' {chat_id: $cid, text: $txt, parse_mode: "Markdown"}' )
167-
168- RESPUESTA=$( $CURL -s -m 10 -X POST " https://api.telegram.org/bot$TOKEN /sendMessage" \
169- -H " Content-Type: application/json" \
170- -d " $PAYLOAD " )
171-
172- if echo " $RESPUESTA " | $GREP -q ' "ok":true' ; then
173- echo " $TOTAL_DIA_GB " > " $STATE_DIA "
174- echo " $TOTAL_MES_GB " > " $STATE_MES "
175- else
176- echo " ❌ Error enviando a Telegram: $RESPUESTA " >&2
177- fi
133+ $CURL -s -m 10 -X POST " https://api.telegram.org/bot$TOKEN /sendMessage" -H " Content-Type: application/json" -d " $PAYLOAD " > /dev/null
134+ echo " $TOTAL_DIA_GB " > " $STATE_DIA "
135+ echo " $TOTAL_MES_GB " > " $STATE_MES "
178136 fi
179137fi
180-
0 commit comments