#!/bin/bash # --- COLORES Y FORMATO --- RED=$'\e[0;31m' GREEN=$'\e[0;32m' YELLOW=$'\e[1;33m' CYAN=$'\e[0;36m' BOLD=$'\e[1m' NC=$'\e[0m' # --- NORMALIZACIÓN DE ARGUMENTOS --- EMAIL_LOCAL=$(echo "$1" | tr '[:upper:]' '[:lower:]') EMAIL_REMITENTE=$(echo "$2" | tr '[:upper:]' '[:lower:]') DOMAIN_REMITENTE=$(echo "$EMAIL_REMITENTE" | cut -d'@' -f2) if [[ -z "$EMAIL_LOCAL" ]]; then echo -e "${YELLOW}Uso: $0 [correo_remitente_opcional]${NC}" exit 1 fi DOMAIN_LOCAL=$(echo "$EMAIL_LOCAL" | cut -d'@' -f2) USER_LOCAL=$(grep -m 1 "^${DOMAIN_LOCAL}:" /etc/userdomains | cut -d':' -f2 | tr -d ' ') echo -e "${CYAN}${BOLD}=== DIAGNÓSTICO MAESTRO DE CORREO: $EMAIL_LOCAL ===${NC}" # 0. RECOPILACIÓN DE IPs PUBLIC_IP=$(curl -s --max-time 2 ifconfig.me) # 1. RESOLUCIÓN DNS Y MX LOCAL echo -e "\n${CYAN}[1] DNS y MX Local...${NC}" MX_IP=$(dig +short MX "$DOMAIN_LOCAL" | sort -n | head -n1 | xargs dig +short) echo -e " > MX IP: $MX_IP" if [[ "$MX_IP" == "$PUBLIC_IP" ]] || hostname -I | grep -q "$MX_IP"; then echo -e " > Registro MX: ${GREEN}[OK]${NC} Apunta a este servidor." else echo -e " > Registro MX: ${YELLOW}[AVISO]${NC} Apunta fuera ($MX_IP)." fi # 2. PRESENCIA LOCAL echo -e "\n${CYAN}[2] Verificando presencia local...${NC}" if [[ -z "$USER_LOCAL" ]]; then echo -e " > ${RED}[CRÍTICO] El dominio no está en este servidor.${NC}" echo -e "${NC}"; exit 1 fi echo -e " > Usuario cPanel: ${GREEN}$USER_LOCAL${NC}" # 3. ENRUTAMIENTO echo -e "\n${CYAN}[3] Verificando enrutamiento de Exim...${NC}" if grep -qP "^$DOMAIN_LOCAL$" /etc/localdomains; then echo -e " > Enrutamiento: ${GREEN}LOCAL${NC}" elif grep -qP "^$DOMAIN_LOCAL$" /etc/remotedomains; then echo -e " > Enrutamiento: ${YELLOW}REMOTE${NC}" fi # 4. ENTREGABILIDAD LOCAL (SPF/DKIM/DMARC) echo -e "\n${CYAN}[4] Seguridad del Dominio Local...${NC}" [[ -n $(dig +short TXT "$DOMAIN_LOCAL" | grep "v=spf1") ]] && echo -e " > SPF: ${GREEN}[OK]${NC}" || echo -e " > SPF: ${RED}[FALLA]${NC}" [[ -n $(dig +short TXT "default._domainkey.$DOMAIN_LOCAL") ]] && echo -e " > DKIM: ${GREEN}[OK]${NC}" || echo -e " > DKIM: ${YELLOW}[NO DETECTADO]${NC}" # 5. ANÁLISIS DEL REMITENTE (Solo si se provee el 2do argumento) if [[ -n "$EMAIL_REMITENTE" ]]; then echo -e "\n${CYAN}[5] Análisis Forense del Remitente: $EMAIL_REMITENTE${NC}" # 5a. Obtener IP del remitente (vía MX o SPF) SENDER_MX_IP=$(dig +short MX "$DOMAIN_REMITENTE" | sort -n | head -n1 | xargs dig +short | head -n1) # 5b. Firewall Check (CSF es prioridad en cPanel) if [ -x "$(command -v csf)" ]; then echo -e " > Firewall (CSF): Verificando bloqueo de IP $SENDER_MX_IP..." BLOCK_INFO=$(csf -g "$SENDER_MX_IP" | grep -E "DENY|BLOCK") if [[ -n "$BLOCK_INFO" ]]; then echo -e " ${RED}[ALERTA] La IP del remitente está BLOQUEADA en el firewall local.${NC}" else echo -e " ${GREEN}[OK]${NC} No hay bloqueos en CSF para $SENDER_MX_IP." fi else echo -e " > Firewall (iptables): Verificando..." iptables -L -n | grep -q "$SENDER_MX_IP" && echo -e " ${RED}[ALERTA] IP detectada en reglas de iptables.${NC}" || echo -e " ${GREEN}[OK]${NC} IP limpia." fi # 5c. Greylisting Check if [ -f "/var/cpanel/greylist/sqlite.db" ]; then GREY_CHECK=$(sqlite3 /var/cpanel/greylist/sqlite.db "SELECT status FROM records WHERE sender_ip='$SENDER_MX_IP' OR from_addr='$EMAIL_REMITENTE' LIMIT 1;" 2>/dev/null) if [[ "$GREY_CHECK" == "deferred" ]]; then echo -e " > Greylisting: ${YELLOW}[ACTIVO]${NC} El servidor ha pospuesto el correo temporalmente (proceso normal)." fi fi # 5d. Rechazos Tempranos (Rechazos antes del Message-ID) echo -e " > Buscando rechazos SMTP (HELO/SPF/RBL) en logs..." # FIX: Ahora busca específicamente la cuenta de correo del remitente y no el dominio para evitar falsos positivos REJECTIONS=$(grep -i "$EMAIL_REMITENTE" /var/log/exim_mainlog | grep -i "rejected" | tail -n 5) if [[ -n "$REJECTIONS" ]]; then echo -e "${RED} Mensajes rechazados encontrados para esta cuenta:${NC}" echo "$REJECTIONS" | sed -e "s/^/ /" -e "s/$EMAIL_REMITENTE/${BOLD}&${NC}/gI" else echo -e " ${GREEN}[OK]${NC} No se ven rechazos previos a la conexión para esta cuenta." fi fi # 6. CUOTAS Y ESPACIO echo -e "\n${CYAN}[6] Consultando uso de espacio...${NC}" QUOTA_INFO=$(whmapi1 accountsummary user="$USER_LOCAL") H_USED=$(echo "$QUOTA_INFO" | grep -m1 'diskused:' | awk '{print $2}' | tr -dc '0-9') H_LIMIT=$(echo "$QUOTA_INFO" | grep -m1 'disklimit:' | awk '{print $2}' | tr -dc '0-9') echo -e " > Hosting completo: Usado ${GREEN}${H_USED} MB${NC} / Límite ${H_LIMIT} MB" MAIL_DATA=$(uapi --user="$USER_LOCAL" Email list_pops_with_disk regex="^${EMAIL_LOCAL}$" 2>/dev/null) if echo "$MAIL_DATA" | grep -q "email: $EMAIL_LOCAL"; then B_USED=$(echo "$MAIL_DATA" | grep -m1 -E 'diskused|diskused:' | awk '{print $2}' | tr -dc '0-9') B_LIMIT=$(echo "$MAIL_DATA" | grep -m1 -E 'diskquota|diskquota:' | awk '{print $2}' | tr -dc '0-9') B_USED=${B_USED:-0} B_LIMIT=${B_LIMIT:-0} MB_USED=$(( B_USED / 1048576 )) if [[ "$B_LIMIT" -eq 0 ]]; then MB_LIMIT="Ilimitado" else MB_LIMIT="$(( B_LIMIT / 1048576 )) MB" fi echo -e " > Cuenta de correo: Usado ${GREEN}${MB_USED} MB${NC} / Límite ${MB_LIMIT}" else echo -e " > ${RED}[ERROR] No se pudo obtener la cuota de la cuenta.${NC}" fi # 7. RASTREO DE LOGS (FORENSE) echo -e "\n${CYAN}[7] Ciclo de Vida de Mensajes (Log)...${NC}" LOG_PATH="/var/log/exim_mainlog" if [[ -n "$EMAIL_REMITENTE" ]]; then MSG_IDS=$(grep -i "$EMAIL_LOCAL" "$LOG_PATH" | grep -i "$EMAIL_REMITENTE" | awk '{print $3}' | grep -E "^[a-zA-Z0-9-]{16,30}$" | tail -n 5 | sort -u) else MSG_IDS=$(grep -i "$EMAIL_LOCAL" "$LOG_PATH" | awk '{print $3}' | grep -E "^[a-zA-Z0-9-]{16,30}$" | tail -n 5 | sort -u) fi if [[ -z "$MSG_IDS" ]]; then echo -e " > ${YELLOW}No se encontraron transacciones completas (Message-IDs) recientes.${NC}" else for ID in $MSG_IDS; do echo -e "${CYAN}--- ID: $ID ---${NC}" if [[ -n "$EMAIL_REMITENTE" ]]; then grep "$ID" "$LOG_PATH" | sed -e "s/<=/${GREEN}<=${NC}/g" -e "s/=>/${RED}=>${NC}/g" -e "s/->/${YELLOW}->${NC}/g" -e "s/$EMAIL_LOCAL/${BOLD}&${NC}/gI" -e "s/$EMAIL_REMITENTE/${BOLD}&${NC}/gI" -e "s/$/${NC}/" else grep "$ID" "$LOG_PATH" | sed -e "s/<=/${GREEN}<=${NC}/g" -e "s/=>/${RED}=>${NC}/g" -e "s/->/${YELLOW}->${NC}/g" -e "s/$EMAIL_LOCAL/${BOLD}&${NC}/gI" -e "s/$/${NC}/" fi done fi # 8. SÍNTESIS FINAL echo -e "\n${CYAN}=== Conclusión del Diagnóstico ===${NC}" if [[ -n "$EMAIL_REMITENTE" && -z "$MSG_IDS" && -z "$REJECTIONS" ]]; then echo -e " > ${YELLOW}DIAGNÓSTICO:${NC} No hay rastro del correo. Si la IP no está bloqueada y el DNS del remitente es correcto, el problema probablemente está en el servidor de ORIGEN (no llegó a intentar la conexión o fue bloqueado por un firewall de red superior)." else echo -e " > ${GREEN}[FIN]${NC} Revisa los resultados anteriores para identificar el cuello de botella." fi echo -e "${NC}"