Код: Выделить всё
#!/bin/bash
# ============================================================
# SSH MONITOR С АВТОБАНОМ (IPSet + Shorewall)
# ИНТЕРАКТИВНАЯ УСТАНОВКА - ВЕРСИЯ 15.0 (ФИНАЛЬНАЯ)
# ============================================================
# ПРОВЕРЕНО НА:
# - Ubuntu 26.04 LTS
# - Shorewall 5.2.8
# - IPSet v7.19
# - msmtp
# ============================================================
if [[ $EUID -ne 0 ]]; then
echo "❌ Ошибка: Запустите от root (sudo)"
exit 1
fi
# ==================== ЦВЕТА ====================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
print_header() {
echo ""
echo -e "${BLUE}========================================${NC}"
echo -e "${CYAN} $1${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""
}
print_success() { echo -e "${GREEN}✅ $1${NC}"; }
print_error() { echo -e "${RED}❌ $1${NC}"; }
print_info() { echo -e "${YELLOW}ℹ️ $1${NC}"; }
print_question() { echo -e "${CYAN}❓ $1${NC}"; }
# ==================== ФУНКЦИЯ ВВОДА ====================
get_input() {
local prompt="$1"
local default="$2"
local input=""
if [[ -n "$default" ]]; then
read -p "$prompt [$default]: " input
input="${input:-$default}"
else
read -p "$prompt: " input
fi
echo "$input"
}
# ==================== ПРОВЕРКА EMAIL ====================
validate_email() {
local email="$1"
[[ "$email" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]
}
# ==================== ПРОВЕРКА IP ====================
validate_ip() {
local ip="$1"
if [[ "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
return 0
elif [[ "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
return 0
else
return 1
fi
}
# ==================== ПРОВЕРКА ЗАВИСИМОСТЕЙ ====================
check_dependencies() {
print_header "📦 ПРОВЕРКА ЗАВИСИМОСТЕЙ"
local deps_ok=true
# ipset
if command -v ipset >/dev/null 2>&1; then
print_success "ipset установлен"
else
print_info "Устанавливаю ipset..."
apt update -qq && apt install -y ipset >/dev/null 2>&1
if command -v ipset >/dev/null 2>&1; then
print_success "ipset установлен"
else
print_error "Не удалось установить ipset"
deps_ok=false
fi
fi
# iptables
if command -v iptables >/dev/null 2>&1; then
print_success "iptables установлен"
else
print_error "iptables не найден"
deps_ok=false
fi
# Shorewall
if command -v shorewall >/dev/null 2>&1; then
print_success "Shorewall установлен ($(shorewall version))"
else
print_error "Shorewall не найден!"
print_info "Установите: apt install shorewall"
deps_ok=false
fi
# netfilter-persistent (опционально)
if command -v netfilter-persistent >/dev/null 2>&1; then
print_success "netfilter-persistent установлен"
else
print_info "Устанавливаю iptables-persistent..."
DEBIAN_FRONTEND=noninteractive apt install -y iptables-persistent >/dev/null 2>&1
if command -v netfilter-persistent >/dev/null 2>&1; then
print_success "netfilter-persistent установлен"
fi
fi
# Загружаем модули ядра
modprobe xt_set 2>/dev/null
modprobe ip_set 2>/dev/null
modprobe ip_set_hash_ip 2>/dev/null
if lsmod | grep -q "xt_set"; then
print_success "Модуль xt_set загружен"
else
print_error "Модуль xt_set не загружен"
deps_ok=false
fi
# Автозагрузка модулей
if [[ ! -f /etc/modules-load.d/ipset.conf ]]; then
cat > /etc/modules-load.d/ipset.conf << 'EOF'
xt_set
ip_set
ip_set_hash_ip
EOF
print_success "Модули добавлены в автозагрузку"
fi
if [[ "$deps_ok" == false ]]; then
print_error "Не все зависимости установлены"
exit 1
fi
echo ""
}
# ==================== НАСТРОЙКА ПОЧТЫ ====================
setup_mail() {
print_header "📧 НАСТРОЙКА ПОЧТЫ"
echo -e "${YELLOW}Хотите настроить отправку email?${NC}"
echo " 1) Да, настроить msmtp (рекомендуется)"
echo " 2) Нет, использовать существующие sendmail/mail"
echo " 3) Нет, только логи (без email)"
read -p "Выберите [1-3]: " mail_choice
case "$mail_choice" in
1)
if ! command -v msmtp >/dev/null 2>&1; then
print_info "Устанавливаю msmtp..."
apt update -qq && apt install -y msmtp msmtp-mta ca-certificates >/dev/null 2>&1
fi
if ! command -v msmtp >/dev/null 2>&1; then
print_error "Не удалось установить msmtp"
SMTP_FROM="ssh-alert@$(hostname -f)"
return 1
fi
print_success "msmtp установлен"
echo ""
SMTP_HOST=$(get_input "🌐 SMTP сервер" "smtp.padonak.su")
SMTP_PORT=$(get_input "🔌 SMTP порт" "587")
echo ""
echo -e "${YELLOW}Тип шифрования:${NC}"
echo " 1) STARTTLS (порт 587) - рекомендуется"
echo " 2) SSL/TLS (порт 465)"
echo " 3) Без шифрования (порт 25)"
read -p "Выберите [1-3]: " tls_choice
case "$tls_choice" in
1) SMTP_TLS="on"; SMTP_STARTTLS="on"; SMTP_TLS_TEXT="STARTTLS" ;;
2) SMTP_TLS="on"; SMTP_STARTTLS="off"; SMTP_TLS_TEXT="SSL/TLS" ;;
*) SMTP_TLS="off"; SMTP_STARTTLS="off"; SMTP_TLS_TEXT="Без шифрования" ;;
esac
print_success "Шифрование: $SMTP_TLS_TEXT"
echo ""
SMTP_USER=$(get_input "👤 SMTP логин" "alert@padonak.su")
read -sp "🔑 SMTP пароль: " SMTP_PASS
echo ""
if [[ -z "$SMTP_PASS" ]]; then
print_error "Пароль не может быть пустым!"
SMTP_FROM="ssh-alert@$(hostname -f)"
return 1
fi
SMTP_FROM=$(get_input "📧 Email отправителя" "$SMTP_USER")
cat > /etc/msmtprc << EOF
# ============================================================
# MSMTP Configuration
# Создан: $(date '+%Y-%m-%d %H:%M:%S')
# ============================================================
defaults
auth on
tls $SMTP_TLS
tls_starttls $SMTP_STARTTLS
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile /var/log/msmtp.log
account default
host $SMTP_HOST
port $SMTP_PORT
from $SMTP_FROM
user $SMTP_USER
password $SMTP_PASS
EOF
chmod 600 /etc/msmtprc
chown root:root /etc/msmtprc
print_success "Конфиг создан: /etc/msmtprc"
;;
2)
print_info "Используем существующие sendmail/mail"
SMTP_FROM="ssh-alert@$(hostname -f)"
SMTP_HOST=""
SMTP_PORT=""
SMTP_USER=""
SMTP_PASS=""
;;
*)
print_info "Почта не настроена, только логи"
SMTP_FROM="ssh-alert@$(hostname -f)"
SMTP_HOST=""
SMTP_PORT=""
SMTP_USER=""
SMTP_PASS=""
;;
esac
echo ""
return 0
}
# ==================== НАСТРОЙКА SHOREWALL ====================
setup_shorewall() {
print_header "🔥 НАСТРОЙКА SHOREWALL"
local IPSET_NAME="ssh_ban"
# 1. Создаём initdone (Perl синтаксис!)
print_info "Создаю /etc/shorewall/initdone..."
cat > /etc/shorewall/initdone << 'EOF'
# ============================================================
# Shorewall initdone - выполняется при старте Shorewall
# Использует Perl синтаксис!
# ============================================================
# Загружаем модули ядра
system("modprobe xt_set");
system("modprobe ip_set");
system("modprobe ip_set_hash_ip");
# Создаём ipset для блокировки SSH (не удаляем если существует)
system("ipset create ssh_ban hash:ip timeout 86400 -exist");
1;
EOF
chmod 755 /etc/shorewall/initdone
print_success "Создан /etc/shorewall/initdone"
# 2. Добавляем правило в rules (если ещё нет)
if ! grep -q "net:+ssh_ban" /etc/shorewall/rules 2>/dev/null; then
print_info "Добавляю правило в /etc/shorewall/rules..."
# Бэкап
cp /etc/shorewall/rules "/etc/shorewall/rules.backup.$(date +%Y%m%d_%H%M%S)"
# Добавляем правило в правильном формате (net:+ssh_ban с плюсом!)
cat >> /etc/shorewall/rules << 'EOF'
# ============================================================
# SSH BAN через ipset - блокировка неразрешённых IP
# ВАЖНО: должно быть ПОСЛЕ всех ACCEPT для SSH!
# ============================================================
DROP net:+ssh_ban all
EOF
print_success "Правило добавлено в /etc/shorewall/rules"
else
print_success "Правило уже есть в /etc/shorewall/rules"
fi
# 3. Проверяем конфиг
print_info "Проверка конфига Shorewall..."
if shorewall check >/dev/null 2>&1; then
print_success "Конфиг Shorewall корректен"
else
print_error "Ошибка в конфиге Shorewall!"
shorewall check
exit 1
fi
# 4. Перезапускаем Shorewall
print_info "Перезапуск Shorewall..."
if shorewall restart >/dev/null 2>&1; then
print_success "Shorewall перезапущен"
else
print_error "Не удалось перезапустить Shorewall"
shorewall restart
exit 1
fi
# 5. Проверяем ipset
if ipset list "$IPSET_NAME" >/dev/null 2>&1; then
print_success "ipset $IPSET_NAME создан"
else
print_error "ipset $IPSET_NAME НЕ создан!"
print_info "Создаю вручную..."
modprobe xt_set 2>/dev/null
modprobe ip_set 2>/dev/null
modprobe ip_set_hash_ip 2>/dev/null
ipset create "$IPSET_NAME" hash:ip timeout 86400 -exist
fi
# 6. Проверяем правило
if iptables -n -L net-fw 2>/dev/null | grep -q "ssh_ban"; then
print_success "Правило iptables для ssh_ban активно"
else
print_error "Правило iptables для ssh_ban НЕ найдено!"
fi
echo ""
}
# ==================== ЗАГОЛОВОК ====================
clear
print_header "🔐 SSH MONITOR - ИНТЕРАКТИВНАЯ УСТАНОВКА v15.0 (SHOREWALL)"
echo -e "${YELLOW}Этот скрипт установит систему мониторинга SSH подключений.${NC}"
echo -e "${YELLOW}Работает совместно с Shorewall + ipset!${NC}"
echo -e "${YELLOW}Подозрительные IP блокируются и АВТОМАТИЧЕСКИ разблокируются!${NC}"
echo ""
# ==================== 0. ЗАВИСИМОСТИ ====================
check_dependencies
# ==================== 1. ПОЧТА ====================
setup_mail
# ==================== 2. ИМЯ СЕРВЕРА ====================
print_header "🏷️ ИМЯ СЕРВЕРА"
CURRENT_HOSTNAME=$(cat /etc/hostname 2>/dev/null || echo "unknown")
CURRENT_FQDN=$(hostname -f 2>/dev/null || echo "unknown")
echo -e "${CYAN}Текущее имя:${NC}"
echo -e " /etc/hostname: ${GREEN}$CURRENT_HOSTNAME${NC}"
echo -e " hostname -f: ${YELLOW}$CURRENT_FQDN${NC}"
echo ""
DEFAULT_NAME="$CURRENT_HOSTNAME"
if [[ "$CURRENT_FQDN" != "localhost" ]] && [[ "$CURRENT_FQDN" != "localhost.localdomain" ]]; then
DEFAULT_NAME="$CURRENT_FQDN"
fi
SERVER_NAME=$(get_input "🌐 Имя сервера для уведомлений" "$DEFAULT_NAME")
print_success "Имя сервера: $SERVER_NAME"
echo ""
# ==================== 3. EMAIL ====================
print_header "📧 EMAIL ДЛЯ УВЕДОМЛЕНИЙ"
echo -e "${YELLOW}Можно указать несколько email через запятую или пробел.${NC}"
echo -e "${YELLOW}Пример: admin@domain.ru, security@domain.ru${NC}"
echo ""
while true; do
EMAIL_INPUT=$(get_input "📧 Email для уведомлений" "admin@padonak.su")
EMAIL_INPUT_CLEAN=$(echo "$EMAIL_INPUT" | tr ',' ' ')
EMAILS_TO=()
ALL_VALID=true
for email in $EMAIL_INPUT_CLEAN; do
if validate_email "$email"; then
EMAILS_TO+=("$email")
else
print_error "Неверный формат email: $email"
ALL_VALID=false
fi
done
if [[ "$ALL_VALID" == true ]] && [[ ${#EMAILS_TO[@]} -gt 0 ]]; then
print_success "Принято email: ${#EMAILS_TO[@]}"
for email in "${EMAILS_TO[@]}"; do
echo -e " ${GREEN}•${NC} $email"
done
break
else
print_error "Попробуйте снова."
fi
done
echo ""
# ==================== 4. РАЗРЕШЕННЫЕ IP ====================
print_header "🛡️ РАЗРЕШЕННЫЕ IP АДРЕСА"
echo -e "${YELLOW}Укажите IP адреса одной строкой через пробел или запятую.${NC}"
echo -e "${YELLOW}Можно указывать отдельные IP и подсети.${NC}"
echo ""
echo -e "${YELLOW}📌 Пример:${NC}"
echo -e " ${GREEN}93.95.101.238 79.164.47.234 185.215.60.0/22${NC}"
echo ""
CURRENT_IP=$(hostname -I | awk '{print $1}')
if [[ -z "$CURRENT_IP" ]]; then
CURRENT_IP="127.0.0.1"
fi
echo -e "${YELLOW}💡 Текущий IP сервера: $CURRENT_IP${NC}"
echo ""
while true; do
read -p "Введите IP адреса: " IP_INPUT
if [[ -z "$IP_INPUT" ]]; then
print_info "Добавляю текущий IP: $CURRENT_IP"
ALLOWED_IPS=("$CURRENT_IP")
break
fi
IP_INPUT_CLEAN=$(echo "$IP_INPUT" | tr ',;\t' ' ')
ALLOWED_IPS=()
ALL_VALID=true
for ip in $IP_INPUT_CLEAN; do
if validate_ip "$ip"; then
ALLOWED_IPS+=("$ip")
else
print_error "Неверный формат IP: $ip"
ALL_VALID=false
fi
done
if [[ "$ALL_VALID" == true ]] && [[ ${#ALLOWED_IPS[@]} -gt 0 ]]; then
break
else
print_error "Попробуйте снова."
echo ""
fi
done
echo ""
print_success "📋 Добавлено разрешенных IP: ${#ALLOWED_IPS[@]}"
for ip in "${ALLOWED_IPS[@]}"; do
echo -e " ${GREEN}•${NC} $ip"
done
echo ""
# ==================== 5. НАСТРОЙКИ БАНА ====================
print_header "🔒 НАСТРОЙКИ АВТОБЛОКИРОВКИ"
echo -e "${CYAN}⏱️ Время блокировки (автоматический разбан):${NC}"
echo " 1) 1 час"
echo " 2) 24 часа (рекомендуется)"
echo " 3) 7 дней"
echo " 4) 30 дней"
read -p "Выберите [1-4]: " ban_time_choice
case "$ban_time_choice" in
1) BAN_TIME="3600"; BAN_TEXT="1 час" ;;
2) BAN_TIME="86400"; BAN_TEXT="24 часа" ;;
3) BAN_TIME="604800"; BAN_TEXT="7 дней" ;;
4) BAN_TIME="2592000"; BAN_TEXT="30 дней" ;;
*) BAN_TIME="86400"; BAN_TEXT="24 часа" ;;
esac
print_success "Время блокировки: $BAN_TEXT"
echo ""
echo -e "${CYAN}⚡ Действие при подозрительном подключении:${NC}"
echo " 1) Блокировать + уведомление (рекомендуется)"
echo " 2) Только блокировка (без уведомлений)"
echo " 3) Только уведомление (без блокировки)"
read -p "Выберите [1-3]: " action_choice
case "$action_choice" in
2) AUTO_BLOCK="yes"; NOTIFY_SUSPICIOUS="no"; ACTION_TEXT="Только блокировка" ;;
3) AUTO_BLOCK="no"; NOTIFY_SUSPICIOUS="yes"; ACTION_TEXT="Только уведомление" ;;
*) AUTO_BLOCK="yes"; NOTIFY_SUSPICIOUS="yes"; ACTION_TEXT="Блокировка + уведомление" ;;
esac
print_success "Действие: $ACTION_TEXT"
echo ""
# ==================== 6. ПОДТВЕРЖДЕНИЕ ====================
print_header "📋 ПРОВЕРЬТЕ НАСТРОЙКИ"
if [[ -n "$SMTP_HOST" ]]; then
echo -e "${CYAN}📧 SMTP:${NC} $SMTP_HOST:$SMTP_PORT ($SMTP_TLS_TEXT)"
echo -e "${CYAN}👤 SMTP логин:${NC} $SMTP_USER"
fi
echo -e "${CYAN}🔥 Shorewall:${NC} $(shorewall version)"
echo -e "${CYAN}🏷️ Имя сервера:${NC} $SERVER_NAME"
echo -e "${CYAN}📧 Email (${#EMAILS_TO[@]}):${NC}"
for email in "${EMAILS_TO[@]}"; do
echo -e " ${GREEN}•${NC} $email"
done
echo -e "${CYAN}🛡️ Разрешенные IP (${#ALLOWED_IPS[@]}):${NC}"
for ip in "${ALLOWED_IPS[@]}"; do
echo -e " ${GREEN}•${NC} $ip"
done
echo -e "${CYAN}🔒 Время блокировки:${NC} $BAN_TEXT"
echo -e "${CYAN}⏰ Авторазбан:${NC} ${GREEN}ДА${NC} (через $BAN_TEXT)"
echo -e "${CYAN}⚡ Действие:${NC} $ACTION_TEXT"
echo ""
read -p "Продолжить установку? (y/n): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_error "Установка отменена"
exit 1
fi
# ==================== 7. НАСТРОЙКА SHOREWALL ====================
setup_shorewall
# ==================== 8. ОСТАНОВКА СТАРОГО СЕРВИСА ====================
print_header "🛑 ОСТАНОВКА СТАРОГО СЕРВИСА"
systemctl stop ssh-monitor 2>/dev/null
systemctl stop ssh-monitor-final 2>/dev/null
systemctl disable ssh-monitor 2>/dev/null
systemctl disable ssh-monitor-final 2>/dev/null
rm -f /etc/systemd/system/ssh-monitor.service
rm -f /etc/systemd/system/ssh-monitor-final.service
rm -f /usr/local/bin/ssh-monitor.sh
rm -f /usr/local/bin/ssh-monitor-final.sh
systemctl daemon-reload
print_success "Старый сервис удален"
# ==================== 9. ОЧИСТКА IPSET ====================
print_header "🧹 ОЧИСТКА IPSET"
IPSET_NAME="ssh_ban"
if ipset list "$IPSET_NAME" >/dev/null 2>&1; then
print_info "Очистка ipset $IPSET_NAME..."
ipset flush "$IPSET_NAME" 2>/dev/null
print_success "ipset очищен"
else
print_info "Создаю ipset..."
modprobe xt_set 2>/dev/null
modprobe ip_set 2>/dev/null
modprobe ip_set_hash_ip 2>/dev/null
ipset create "$IPSET_NAME" hash:ip timeout $BAN_TIME 2>/dev/null
fi
if ipset list "$IPSET_NAME" >/dev/null 2>&1; then
print_success "ipset $IPSET_NAME готов"
else
print_error "ipset $IPSET_NAME не создан!"
exit 1
fi
echo ""
# ==================== 10. СОЗДАНИЕ СКРИПТА ====================
print_header "📝 СОЗДАНИЕ СКРИПТА"
ALLOWED_IPS_STR=""
for ip in "${ALLOWED_IPS[@]}"; do
ALLOWED_IPS_STR+=" \"$ip\"\n"
done
EMAILS_TO_STR_BUILD=""
for email in "${EMAILS_TO[@]}"; do
EMAILS_TO_STR_BUILD+=" \"$email\"\n"
done
cat > /usr/local/bin/ssh-monitor.sh << SCRIPT_EOF
#!/bin/bash
# ============================================================
# SSH MONITOR С АВТОБАНОМ (IPSet + Shorewall)
# Сервер: $SERVER_NAME
# Установлен: $(date '+%Y-%m-%d %H:%M:%S')
# ============================================================
# ==================== НАСТРОЙКИ ====================
EMAILS_TO=(
$(echo -e "$EMAILS_TO_STR_BUILD")
)
SERVER_NAME="$SERVER_NAME"
ALLOWED_IPS=(
$(echo -e "$ALLOWED_IPS_STR")
)
BAN_TIME="$BAN_TIME"
AUTO_BLOCK="$AUTO_BLOCK"
NOTIFY_SUSPICIOUS="$NOTIFY_SUSPICIOUS"
IPSET_NAME="$IPSET_NAME"
# ==================== СЛУЖЕБНЫЕ ПЕРЕМЕННЫЕ ====================
EMAIL_FROM="${SMTP_FROM:-ssh-alert@\$SERVER_NAME}"
LOG_FILE="/var/log/ssh-monitor.log"
BAN_LOG="/var/log/ssh-ban.log"
STATE_DIR="/var/lib/ssh-monitor"
STATE_FILE="\$STATE_DIR/last_state"
PID_FILE="/var/run/ssh-monitor.pid"
# ==================== ФУНКЦИИ ====================
log_message() {
echo "[\$(date '+%Y-%m-%d %H:%M:%S')] \$1" | tee -a "\$LOG_FILE"
}
log_ban() {
echo "[\$(date '+%Y-%m-%d %H:%M:%S')] \$1" | tee -a "\$BAN_LOG"
}
send_email() {
local subject="\$1"
local body="\$2"
local email_content="From: \$EMAIL_FROM
To: \${EMAILS_TO[*]}
Subject: \$subject
Content-Type: text/plain; charset=UTF-8
\$body
---
Server: \$SERVER_NAME
IP: \$(hostname -I | awk '{print \$1}')
Time: \$(date '+%Y-%m-%d %H:%M:%S')
"
log_message "📧 Отправка письма на: \${EMAILS_TO[*]}"
for recipient in "\${EMAILS_TO[@]}"; do
if command -v msmtp >/dev/null 2>&1; then
if echo "\$email_content" | msmtp -t "\$recipient" 2>/dev/null; then
log_message " ✅ Отправлено на \$recipient через msmtp"
continue
fi
fi
if command -v sendmail >/dev/null 2>&1; then
if echo "\$email_content" | sendmail -t "\$recipient" 2>/dev/null; then
log_message " ✅ Отправлено на \$recipient через sendmail"
continue
fi
fi
if command -v mail >/dev/null 2>&1; then
if echo "\$body" | mail -s "\$subject" -a "From: \$EMAIL_FROM" "\$recipient" 2>/dev/null; then
log_message " ✅ Отправлено на \$recipient через mail"
continue
fi
fi
log_message " ❌ Не удалось отправить на \$recipient"
done
}
is_ip_allowed() {
local ip="\$1"
if [[ -z "\$ip" ]] || [[ "\$ip" == "unknown" ]]; then
return 1
fi
for allowed in "\${ALLOWED_IPS[@]}"; do
if [[ "\$ip" == "\$allowed" ]]; then
return 0
fi
if [[ "\$allowed" == *"/"* ]]; then
local network=\$(echo "\$allowed" | cut -d'/' -f1)
local mask=\$(echo "\$allowed" | cut -d'/' -f2)
ip_to_int() {
local a b c d
IFS=. read -r a b c d <<< "\$1"
echo "\$((a * 256**3 + b * 256**2 + c * 256 + d))"
}
local ip_int=\$(ip_to_int "\$ip")
local net_int=\$(ip_to_int "\$network")
local mask_int=\$((0xffffffff << (32 - mask) & 0xffffffff))
if [[ \$((ip_int & mask_int)) -eq \$((net_int & mask_int)) ]]; then
return 0
fi
fi
done
return 1
}
get_ip_for_pid() {
local pid="\$1"
local ip=""
if command -v ss >/dev/null 2>&1; then
ip=\$(ss -tnp 2>/dev/null | grep "pid=\$pid" | head -1 | awk '{print \$5}' | cut -d':' -f1)
if [[ -n "\$ip" ]] && [[ "\$ip" != "0.0.0.0" ]] && [[ "\$ip" != "::" ]] && [[ "\$ip" != "*" ]]; then
echo "\$ip"
return 0
fi
fi
if command -v netstat >/dev/null 2>&1; then
ip=\$(netstat -tnp 2>/dev/null | grep "\$pid/sshd" | head -1 | awk '{print \$5}' | cut -d':' -f1)
if [[ -n "\$ip" ]] && [[ "\$ip" != "0.0.0.0" ]] && [[ "\$ip" != "::" ]] && [[ "\$ip" != "*" ]]; then
echo "\$ip"
return 0
fi
fi
local tty=\$(ps -o tty= -p "\$pid" 2>/dev/null | tr -d ' ')
if [[ -n "\$tty" ]] && [[ "\$tty" != "?" ]]; then
ip=\$(who -u 2>/dev/null | grep "\$tty" | awk '{print \$NF}' | sed 's/[()]//g')
if [[ -n "\$ip" ]] && [[ "\$ip" != "0.0.0.0" ]] && [[ "\$ip" != "::" ]] && [[ "\$ip" != "*" ]]; then
echo "\$ip"
return 0
fi
fi
echo "unknown"
}
get_ssh_sessions() {
ps aux | grep -E 'sshd-session:.*@|sshd:.*@' | grep -v grep | grep -v "listener" | grep -v "accepted" | awk '{print \$2}'
}
block_ip() {
local ip="\$1"
log_ban "🔒 БЛОКИРОВКА IP: \$ip"
if ! ipset list "\$IPSET_NAME" >/dev/null 2>&1; then
modprobe xt_set 2>/dev/null
modprobe ip_set 2>/dev/null
modprobe ip_set_hash_ip 2>/dev/null
if [[ "\$BAN_TIME" -gt 0 ]]; then
ipset create "\$IPSET_NAME" hash:ip timeout \$BAN_TIME 2>/dev/null
else
ipset create "\$IPSET_NAME" hash:ip 2>/dev/null
fi
fi
if ipset test "\$IPSET_NAME" "\$ip" 2>/dev/null; then
log_ban "ℹ️ IP \$ip уже заблокирован"
return 0
fi
if [[ "\$BAN_TIME" -gt 0 ]]; then
if ipset add "\$IPSET_NAME" "\$ip" timeout \$BAN_TIME 2>/dev/null; then
log_ban "✅ IP \$ip заблокирован на \$BAN_TIME секунд (\$((\$BAN_TIME / 3600)) часов) через Shorewall+ipset"
return 0
fi
else
if ipset add "\$IPSET_NAME" "\$ip" 2>/dev/null; then
log_ban "✅ IP \$ip заблокирован НАВСЕГДА через Shorewall+ipset"
return 0
fi
fi
log_ban "❌ НЕ УДАЛОСЬ ЗАБЛОКИРОВАТЬ IP \$ip"
return 1
}
unban_ip() {
local ip="\$1"
if ipset test "\$IPSET_NAME" "\$ip" 2>/dev/null; then
ipset del "\$IPSET_NAME" "\$ip" 2>/dev/null
log_ban "🔓 IP \$ip разблокирован вручную"
return 0
fi
log_ban "ℹ️ IP \$ip не найден в бане"
return 1
}
process_session() {
local pid="\$1"
local user=\$(ps -o user= -p "\$pid" 2>/dev/null | tr -d ' ')
local client_ip=\$(get_ip_for_pid "\$pid")
local start_time=\$(ps -o lstart= -p "\$pid" 2>/dev/null | tr -d ' ')
log_message "NEW SESSION: PID=\$pid, USER=\$user, IP=\$client_ip"
if [[ -z "\$client_ip" ]] || [[ "\$client_ip" == "unknown" ]]; then
log_message "FAILED to get IP for PID \$pid"
return 1
fi
if is_ip_allowed "\$client_ip"; then
log_message "✅ ALLOWED IP: \$client_ip"
return 0
fi
log_message "🚨 SUSPICIOUS IP: \$client_ip"
if [[ "\$AUTO_BLOCK" == "yes" ]]; then
block_ip "\$client_ip"
fi
if [[ "\$NOTIFY_SUSPICIOUS" == "yes" ]]; then
local ban_text=""
if [[ "\$BAN_TIME" -gt 0 ]]; then
ban_text="на \$((\$BAN_TIME / 3600)) часов"
else
ban_text="НАВСЕГДА"
fi
local subject="🚨 SSH БАН: IP \$client_ip заблокирован!"
local body="🚨 ПОДОЗРИТЕЛЬНОЕ SSH ПОДКЛЮЧЕНИЕ
========================================
СТАТУС: ❌ НЕ РАЗРЕШЕН!
Пользователь: \$user
IP адрес: \$client_ip
Время подключения: \$start_time
Сервер: \$SERVER_NAME
========================================
🔴 IP АДРЕС ЗАБЛОКИРОВАН \$ban_text!
Причина: Подключение с неразрешенного IP
Действие: Автоматическая блокировка через Shorewall + ipset"
if [[ "\$BAN_TIME" -gt 0 ]]; then
body+="
⏰ IP автоматически разблокируется через \$((\$BAN_TIME / 3600)) часов!"
fi
body+="
Текущие активные сессии:
\$(who -u 2>/dev/null || echo "Нет активных сессий")
Заблокированные IP (ipset):
\$(ipset list "\$IPSET_NAME" 2>/dev/null | grep -E "^[0-9]" | head -10 || echo "Нет блокировок")
========================================"
send_email "\$subject" "\$body"
fi
}
show_status() {
echo "========================================="
echo "SSH MONITOR WITH AUTO-BAN (Shorewall+IPSet)"
echo "========================================="
echo ""
echo "Server: \$SERVER_NAME"
echo "Emails (\${#EMAILS_TO[@]}):"
for email in "\${EMAILS_TO[@]}"; do
echo " - \$email"
done
echo ""
echo "Allowed IPs:"
for ip in "\${ALLOWED_IPS[@]}"; do
echo " - \$ip"
done
echo ""
echo "Ban time: \$BAN_TIME seconds (\$((\$BAN_TIME / 3600)) hours)"
echo "Auto block: \$AUTO_BLOCK"
echo "IPSet: \$IPSET_NAME"
echo "Shorewall: \$(shorewall version 2>/dev/null || echo 'не установлен')"
echo ""
echo "Blocked IPs (ipset):"
if ipset list "\$IPSET_NAME" >/dev/null 2>&1; then
local count=\$(ipset list "\$IPSET_NAME" | grep -cE "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
echo " Всего: \$count"
ipset list "\$IPSET_NAME" | grep -E "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | while read ip timeout; do
if [[ -n "\$timeout" ]]; then
echo " - \$ip (осталось: \$((timeout / 60)) мин)"
else
echo " - \$ip (навсегда)"
fi
done
else
echo " ipset \$IPSET_NAME не создан"
fi
echo ""
echo "Log: \$LOG_FILE"
echo "Ban log: \$BAN_LOG"
echo "========================================="
}
test_email() {
echo "Sending test email to: \${EMAILS_TO[*]}..."
local subject="🧪 Test from SSH Monitor with Auto-Ban"
local body="TEST EMAIL
========================================
This is a test email from SSH Monitor.
System is working with AUTO-BAN (Shorewall+ipset) enabled.
Server: \$SERVER_NAME
IP: \$(hostname -I | awk '{print \$1}')
Time: \$(date '+%Y-%m-%d %H:%M:%S')
========================================"
send_email "\$subject" "\$body"
echo "✅ Test email process finished!"
}
case "\$1" in
--status|status)
show_status
exit 0
;;
--test|test)
test_email
exit 0
;;
--unban|unban)
if [[ -z "\$2" ]]; then
echo "Usage: \$0 --unban IP"
exit 1
fi
unban_ip "\$2"
echo "✅ IP \$2 разблокирован"
exit 0
;;
--list|list)
if ipset list "\$IPSET_NAME" >/dev/null 2>&1; then
echo "Blocked IPs:"
ipset list "\$IPSET_NAME" | grep -E "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"
else
echo "ipset \$IPSET_NAME не создан"
fi
exit 0
;;
--help|help|-h)
echo "Usage: \$0 [OPTION]"
echo " --status - Show status"
echo " --test - Send test email"
echo " --unban IP - Unblock IP"
echo " --list - List blocked IPs"
echo " --help - Show this help"
exit 0
;;
esac
mkdir -p "\$(dirname "\$LOG_FILE")" "\$STATE_DIR"
touch "\$LOG_FILE" "\$BAN_LOG"
if [[ -f "\$PID_FILE" ]]; then
OLD_PID=\$(cat "\$PID_FILE" 2>/dev/null)
if kill -0 "\$OLD_PID" 2>/dev/null; then
echo "❌ Script already running (PID: \$OLD_PID)"
exit 1
fi
fi
echo \$\$ > "\$PID_FILE"
if ! ipset list "\$IPSET_NAME" >/dev/null 2>&1; then
modprobe xt_set 2>/dev/null
modprobe ip_set 2>/dev/null
modprobe ip_set_hash_ip 2>/dev/null
if [[ "\$BAN_TIME" -gt 0 ]]; then
ipset create "\$IPSET_NAME" hash:ip timeout \$BAN_TIME 2>/dev/null
else
ipset create "\$IPSET_NAME" hash:ip 2>/dev/null
fi
fi
log_message "========================================="
log_message "🚀 START SSH MONITOR WITH AUTO-BAN (Shorewall+IPSet)"
log_message "Server: \$SERVER_NAME"
log_message "Emails: \${EMAILS_TO[*]}"
log_message "Allowed IPs: \${ALLOWED_IPS[*]}"
log_message "Ban time: \$BAN_TIME seconds"
log_message "Auto block: \$AUTO_BLOCK"
log_message "IPSet: \$IPSET_NAME"
log_message "========================================="
EXISTING_SESSIONS=\$(get_ssh_sessions)
if [[ -n "\$EXISTING_SESSIONS" ]]; then
log_message "Found existing sessions: \$(echo "\$EXISTING_SESSIONS" | wc -w)"
fi
echo "\$EXISTING_SESSIONS" > "\$STATE_FILE"
log_message "Initialization complete"
while true; do
CURRENT_SESSIONS=\$(get_ssh_sessions)
if [[ -n "\$CURRENT_SESSIONS" ]]; then
PREVIOUS_SESSIONS=\$(cat "\$STATE_FILE" 2>/dev/null || echo "")
for pid in \$CURRENT_SESSIONS; do
if ! echo "\$PREVIOUS_SESSIONS" | grep -q "^\$pid\$"; then
process_session "\$pid"
fi
done
echo "\$CURRENT_SESSIONS" > "\$STATE_FILE"
else
echo "" > "\$STATE_FILE" 2>/dev/null
fi
sleep 5
done
SCRIPT_EOF
chmod +x /usr/local/bin/ssh-monitor.sh
print_success "Скрипт создан: /usr/local/bin/ssh-monitor.sh"
# ==================== 11. СОЗДАНИЕ СЕРВИСА ====================
print_header "📝 СОЗДАНИЕ СИСТЕМНОГО СЕРВИСА"
cat > /etc/systemd/system/ssh-monitor.service << 'EOF'
[Unit]
Description=SSH Monitor with Auto-Ban (Shorewall+IPSet)
After=network.target shorewall.service
Wants=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/ssh-monitor.sh
Restart=always
RestartSec=10
User=root
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable ssh-monitor
systemctl restart ssh-monitor
print_success "Сервис создан и запущен"
# ==================== 12. ТЕСТ ====================
print_header "🧪 ТЕСТИРОВАНИЕ"
sleep 2
if systemctl is-active --quiet ssh-monitor; then
print_success "Сервис работает!"
else
print_error "Сервис не запущен"
systemctl status ssh-monitor --no-pager
fi
echo ""
print_question "Отправить тестовое письмо на все адреса?"
echo -e "${YELLOW}Получатели: ${EMAILS_TO[*]}${NC}"
read -p "(y/n): " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
/usr/local/bin/ssh-monitor.sh --test
echo ""
fi
# ==================== 13. ИНФОРМАЦИЯ ====================
print_header "✅ УСТАНОВКА ЗАВЕРШЕНА!"
echo -e "${CYAN}📋 ВАШИ НАСТРОЙКИ:${NC}"
if [[ -n "$SMTP_HOST" ]]; then
echo -e " 📧 SMTP: ${GREEN}$SMTP_HOST:$SMTP_PORT${NC}"
echo -e " 👤 SMTP логин: ${GREEN}$SMTP_USER${NC}"
fi
echo -e " 🔥 Shorewall: ${GREEN}$(shorewall version)${NC}"
echo -e " 🏷️ Имя сервера: ${GREEN}$SERVER_NAME${NC}"
echo -e " 📧 Email (${#EMAILS_TO[@]}):"
for email in "${EMAILS_TO[@]}"; do
echo -e " • ${GREEN}$email${NC}"
done
echo -e " 🛡️ Разрешенные IP (${#ALLOWED_IPS[@]}):"
for ip in "${ALLOWED_IPS[@]}"; do
echo -e " • ${GREEN}$ip${NC}"
done
echo -e " 🔒 Время блокировки: ${GREEN}$BAN_TEXT${NC}"
echo -e " ⏰ Авторазбан: ${GREEN}ДА${NC} (через $BAN_TEXT)"
echo -e " ⚡ Действие: ${GREEN}$ACTION_TEXT${NC}"
echo -e " 📦 IPSet: ${GREEN}$IPSET_NAME${NC}"
echo ""
echo -e "${CYAN}📝 КОМАНДЫ УПРАВЛЕНИЯ:${NC}"
echo -e " ${BLUE}systemctl status ssh-monitor${NC} - Статус"
echo -e " ${BLUE}systemctl restart ssh-monitor${NC} - Перезапуск"
echo -e " ${BLUE}tail -f /var/log/ssh-monitor.log${NC} - Логи"
echo -e " ${BLUE}tail -f /var/log/ssh-ban.log${NC} - Лог блокировок"
echo -e " ${BLUE}tail -f /var/log/msmtp.log${NC} - Логи почты"
echo ""
echo -e " ${BLUE}/usr/local/bin/ssh-monitor.sh --test${NC} - Тест почты"
echo -e " ${BLUE}/usr/local/bin/ssh-monitor.sh --status${NC} - Статус"
echo -e " ${BLUE}/usr/local/bin/ssh-monitor.sh --list${NC} - Список банов"
echo -e " ${BLUE}/usr/local/bin/ssh-monitor.sh --unban IP${NC} - Разблокировать"
echo ""
echo -e "${CYAN}🔍 ПРОВЕРКА:${NC}"
echo -e " ${BLUE}ipset list $IPSET_NAME${NC} - Заблокированные IP"
echo -e " ${BLUE}iptables -n -L net-fw | grep $IPSET_NAME${NC} - Правило"
echo -e " ${BLUE}shorewall status${NC} - Статус Shorewall"
echo ""
print_success "SSH Monitor с автобаном успешно установлен!"
echo -e "${GREEN}Система готова к работе!${NC}"
echo ""
exit 0
# 1. Создайте файл
Код: Выделить всё
vim install-ssh-monitor.sh# 3. Сделайте исполняемым
Код: Выделить всё
chmod +x install-ssh-monitor.shКод: Выделить всё
./install-ssh-monitor.shПочта — настроить msmtp / использовать существующую / пропустить
SMTP настройки — сервер, порт, шифрование, логин, пароль
Имя сервера — для уведомлений
Email — можно несколько через запятую
Разрешенные IP — одной строкой через пробел
Время блокировки — 1ч / 24ч / 7д / 30д
Действие — блокировка + уведомление / только блокировка / только уведомление
ГОТОВЫЕ КОМАНДЫ ДЛЯ УПРАВЛЕНИЯ:
# === Управление сервисом ===
Код: Выделить всё
systemctl status ssh-monitor
systemctl restart ssh-monitor
systemctl stop ssh-monitor
systemctl start ssh-monitorКод: Выделить всё
/usr/local/bin/ssh-monitor.sh --status
/usr/local/bin/ssh-monitor.sh --list
/usr/local/bin/ssh-monitor.sh --test
Код: Выделить всё
/usr/local/bin/ssh-monitor.sh --unban 8.8.8.8Код: Выделить всё
tail -f /var/log/ssh-monitor.log
tail -f /var/log/ssh-ban.log
tail -f /var/log/msmtp.log
Код: Выделить всё
ipset list ssh_ban
iptables -n -L net-fw | grep ssh_ban
shorewall status