繼上編:< 自用文 主機 USC 記錄:> 發現正在被攻擊 后的自救-CSDN博客
環境:
改進:
以下是把代碼,懶得寫,扔給了 AI ,讓它出的:
Fail2ban + IPset + UFW 工作流程詳解
工具概述
1. UFW (Uncomplicated Firewall)
- 作用: iptables 的簡化前端
- 功能: 基礎防火墻規則管理
- 特點: 用戶友好的規則語法
2. IPset
- 作用: IP地址集合管理工具
- 功能: 高效存儲和匹配大量IP地址
- 特點: 比傳統iptables規則更高效
3. Fail2ban
- 作用: 入侵檢測和自動封禁系統
- 功能: 分析日志、檢測攻擊、觸發封禁動作
- 特點: 智能攻擊模式識別
完整工作流程
階段1: 初始化和基礎防護
[系統啟動] → [UFW啟動] → [建立基礎防火墻規則]↓
[IPset工具初始化] → [創建IP集合]↓
[Fail2ban啟動] → [讀取配置] → [開始監控日志]
階段2: 攻擊檢測流程
[攻擊者連接] → [服務日志記錄] → [Fail2ban監控]↓
[模式匹配] → [計數器增加] → [達到閾值?]↓ ↓ ↓[繼續監控] [重置計數器] [觸發封禁]
階段3: 封禁執行流程
[Fail2ban檢測到攻擊] ↓
[調用Action腳本]↓
[IPset添加惡意IP] → [ipset add fail2ban-ssh 192.168.1.100]↓
[UFW規則生效] → [DROP來自IPset集合的流量]↓
[攻擊者被阻斷]
技術架構圖
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 網絡流量 │────│ UFW/iptables │────│ 目標服務 │
│ │ │ │ │ (SSH/HTTP) │
└─────────────────┘ └─────────────────┘ └─────────────────┘│ ││ │┌─────────────┐ ┌─────────────┐│ IPset │ │ 日志文件 ││ (IP集合) │ │ │└─────────────┘ └─────────────┘│ │└──────┬──────────────────┘│┌─────────────┐│ Fail2ban ││ (監控分析) │└─────────────┘
詳細配置示例
1. UFW基礎配置
# 啟用UFW
sudo ufw enable# 默認策略
sudo ufw default deny incoming
sudo ufw default allow outgoing# 允許SSH (在配置fail2ban之前)
sudo ufw allow ssh# 創建IPset規則 (UFW會自動處理)
# 實際在iptables中創建規則引用IPset
2. IPset配置
# 創建IP集合
sudo ipset create fail2ban-ssh hash:ip timeout 86400# 手動添加IP到集合 (通常由fail2ban自動執行)
sudo ipset add fail2ban-ssh 192.168.1.100# 查看集合內容
sudo ipset list fail2ban-ssh
3. Fail2ban配置 (/etc/fail2ban/jail.local)
[DEFAULT]
# 使用ipset作為封禁后端
banaction = iptables-ipset-proto6[name=fail2ban-ssh][sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400
findtime = 600# 使用ipset action
action = iptables-ipset-proto6[name=fail2ban-ssh, port=ssh, protocol=tcp]
數據流詳解
1. 正常流量處理
外部請求 → UFW檢查 → 基礎規則匹配 → 允許通過 → 到達服務↓檢查IPset集合↓IP不在黑名單 → 繼續處理
2. 惡意流量處理
攻擊流量 → UFW檢查 → IPset集合匹配 → 發現惡意IP → 直接丟棄↓記錄封禁日志
3. 新攻擊檢測
新攻擊 → 到達服務 → 認證失敗 → 寫入日志↓Fail2ban監控 → 模式匹配 → 計數增加↓達到閾值 → 調用action → 添加IP到IPset↓下次請求 → UFW/IPset阻斷
性能優勢分析
傳統iptables方式
# 每個被封IP都要一條規則
iptables -I INPUT -s 192.168.1.100 -j DROP
iptables -I INPUT -s 192.168.1.101 -j DROP
iptables -I INPUT -s 192.168.1.102 -j DROP
# ... 可能有數千條規則
問題: 規則數量多時,匹配效率低下
IPset優化方式
# 只需一條規則引用整個集合
iptables -I INPUT -m set --match-set fail2ban-ssh src -j DROP# 所有IP存儲在高效的哈希表中
ipset add fail2ban-ssh 192.168.1.100
ipset add fail2ban-ssh 192.168.1.101
ipset add fail2ban-ssh 192.168.1.102
優勢: O(1) 時間復雜度查找,支持數萬IP
實際工作示例
場景:SSH暴力破解攻擊
-
攻擊開始
攻擊者IP: 203.0.113.100 連續嘗試SSH登錄,密碼錯誤
-
日志記錄
/var/log/auth.log: Failed password for root from 203.0.113.100 port 22 ssh2 Failed password for admin from 203.0.113.100 port 22 ssh2 Failed password for user from 203.0.113.100 port 22 ssh2
-
Fail2ban檢測
fail2ban監控到3次失敗 達到maxretry=3的閾值 觸發封禁action
-
IPset執行
# Fail2ban執行命令 ipset add fail2ban-ssh 203.0.113.100
-
UFW/iptables生效
# 現有規則開始匹配IPset iptables -I INPUT -m set --match-set fail2ban-ssh src -j DROP
-
結果
攻擊者IP被立即阻斷 后續請求直接在內核層面丟棄 不再到達SSH服務
監控和管理
查看當前狀態
# 查看fail2ban狀態
sudo fail2ban-client status sshd# 查看IPset內容
sudo ipset list fail2ban-ssh# 查看UFW狀態
sudo ufw status verbose# 查看iptables規則
sudo iptables -L INPUT -n -v
手動管理
# 手動解封IP
sudo fail2ban-client set sshd unbanip 203.0.113.100# 直接從IPset移除
sudo ipset del fail2ban-ssh 203.0.113.100# 查看封禁歷史
sudo tail -f /var/log/fail2ban.log
優勢總結
- 高效性: IPset提供O(1)查找效率,支持大規模IP封禁
- 自動化: Fail2ban自動檢測和響應,減少人工干預
- 靈活性: UFW提供簡單的規則管理界面
- 可擴展: 支持多種服務和攻擊模式檢測
- 持久化: IPset支持超時和持久化存儲
- 資源節約: 比傳統方法消耗更少系統資源
這種組合為Linux系統提供了一套完整、高效的自動化安全防護解決方案。
代碼:僅 fail2ban+ipset?
這是我自用的裝機 bash script, 之前有分享過,因為有兩個 V 沒過審核,留著自已來。
主要功能:
現在這個腳本?15千行:
這里包含幾個 filter,測試腳本 ,還有硬寫的日志文件名(這需要替換),參考時要記得修改。
# 13. Install Fail2Ban
install_fail2ban() {log_function_start "Installing Fail2Ban with IPSet integration"log_info "Installing Fail2Ban with IPSet and UFW integration for enhanced security..."# Verify nobody user exists for service isolationverify_nobody_user || log_warning "Nobody user not available for service isolation"# Safe to stop and disable Fail2Ban if already runningsafe_stop_and_disable_service "fail2ban" "Fail2Ban service"# Remove any existing Fail2Ban packageslog_info "Removing any existing Fail2Ban packages..."apt remove --purge -y fail2ban || truelog_success "Existing Fail2Ban packages removed"# Clean up orphaned dependencieslog_info "Cleaning up orphaned dependencies..."apt autoremove -y || trueapt autoclean -y || truelog_success "Orphaned dependencies cleaned up"# Remove any existing Fail2Ban configuration fileslog_info "Removing any existing Fail2Ban configuration files..."rm -rf /etc/fail2ban/* 2>/dev/null || truelog_info "Removed existing Fail2Ban configuration files"rm -rf /var/lib/fail2ban/* 2>/dev/null || truelog_info "Removed existing Fail2Ban data files"rm -rf /var/log/fail2ban.log 2>/dev/null || truelog_info "Removed existing Fail2Ban log file"log_success "Existing Fail2Ban configuration files removed"# Check system requirements for Fail2Banlog_info "Checking system requirements for Fail2Ban..."# Check log filesif [ ! -f /var/log/auth.log ]; thenlog_warning "Auth log file not found at /var/log/auth.log"touch /var/log/auth.logchmod 640 /var/log/auth.logchown root:adm /var/log/auth.logsleep 1log_info "Created missing auth log file at /var/log/auth.log with correct permissions"log_success "Auth log file created successfully"elselog_success "Auth log file found at /var/log/auth.log"fi# Check UFW statusif ! command -v ufw >/dev/null; thenlog_error "UFW is not installed. Installing it now..."if configure_ufw; thenlog_success "UFW installed and configured successfully"elselog_error "Failed to install UFW. Fail2Ban installation cannot proceed."log_function_end "Installing Fail2Ban" 1return 1fielselog_success "UFW is installed and available"fi# Install and configure IPSetlog_info "Installing IPSet package..."if apt install -y ipset; thenlog_success "IPSet installed successfully"elselog_error "Failed to install IPSet"log_function_end "Installing Fail2Ban with IPSet" 1return 1fi# Clean up any existing ipsetslog_info "Cleaning up any existing fail2ban ipsets..."ipset destroy fail2ban-banned 2>/dev/null || trueipset destroy fail2ban-recidive 2>/dev/null || truelog_info "Existing fail2ban ipsets cleaned up"# Create IPSet for fail2banlog_info "Creating IPSet for fail2ban..."if ipset create fail2ban-banned hash:ip timeout 0 2>/dev/null; thenlog_success "Created IPSet 'fail2ban-banned'"elselog_error "Failed to create IPSet 'fail2ban-banned'"log_function_end "Creating IPSet for fail2ban" 1return 1fi# Create additional IPSet for recidive (repeat offenders)log_info "Creating IPSet for repeat offenders..."if ipset create fail2ban-recidive hash:ip timeout 0 2>/dev/null; thenlog_success "Created IPSet 'fail2ban-recidive'"elselog_warning "Failed to create IPSet 'fail2ban-recidive' (may already exist)"fi# Create the initial persistent file for IPSet ruleslog_info "Creating the initial persistent file for IPSet rules..."if ipset save > /etc/ipset.rules; thenlog_success "Created the initial persistent file for IPSet rules"elselog_error "Failed to create the initial persistent file for IPSet rules"log_function_end "Creating the initial persistent file for IPSet rules" 1return 1fi# Create IPSet persistence servicelog_info "Creating IPSet persistence service..."cat > /etc/systemd/system/ipset-persistent.service << 'EOF'
[Unit]
Description=IPSet persistent rule service
Before=netfilter-persistent.service network-pre.target ufw.service fail2ban.service
ConditionFileNotEmpty=/etc/ipset.rules[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/ipset restore -exist -file /etc/ipset.rules
ExecStop=/sbin/ipset save -file /etc/ipset.rules
ExecReload=/sbin/ipset save -file /etc/ipset.rules[Install]
WantedBy=multi-user.target
EOFlog_success "Created IPSet persistence service"# Enable IPSet persistencesystemctl daemon-reloadsystemctl enable ipset-persistent.servicelog_success "Enabled IPSet persistence via systemd"# Create IPSet save script for graceful shutdownlog_info "Creating IPSet save script..."cat > /etc/systemd/system/ipset-save.service << 'EOF'
[Unit]
Description=Save IPSet rules on shutdown
DefaultDependencies=false
Before=shutdown.target reboot.target halt.target[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/true
ExecStop=/sbin/ipset save -file /etc/ipset.rules
TimeoutStopSec=30[Install]
WantedBy=multi-user.target
EOFsystemctl enable ipset-save.servicelog_success "Created IPSet save script for graceful shutdown"# Replace /etc/ufw/before.rules to integrate with IPSetlog_info "Updating /etc/ufw/before.rules to integrate with IPSet..."cp /etc/ufw/before.rules /etc/ufw/before.rules.backup.$(date +%s)log_info "Backed up existing /etc/ufw/before.rules"cat > /etc/ufw/before.rules << 'EOF'
#
# rules.before
#
# Rules that should be run before the ufw command line added rules. Custom
# rules should be added to one of these chains:
# ufw-before-input
# ufw-before-output
# ufw-before-forward
## Don't delete these required lines, otherwise there will be errors
*filter
:ufw-before-input - [0:0]
:ufw-before-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-not-local - [0:0]# Fail2Ban IPSet integration
# Block all traffic from fail2ban banned IPs
-A ufw-before-input -m set --match-set fail2ban-banned src -j DROP
-A ufw-before-input -m set --match-set fail2ban-recidive src -j DROP# End required lines# allow all on loopback
-A ufw-before-input -i lo -j ACCEPT
-A ufw-before-output -o lo -j ACCEPT# quickly process packets for which we already have a connection
-A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-output -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT# drop INVALID packets (logs these in loglevel medium and higher)
-A ufw-before-input -m conntrack --ctstate INVALID -j ufw-logging-deny
-A ufw-before-input -m conntrack --ctstate INVALID -j DROP# ok icmp codes for INPUT
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT
-A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT
-A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT
-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT# ok icmp code for FORWARD
-A ufw-before-forward -p icmp --icmp-type destination-unreachable -j ACCEPT
-A ufw-before-forward -p icmp --icmp-type time-exceeded -j ACCEPT
-A ufw-before-forward -p icmp --icmp-type parameter-problem -j ACCEPT
-A ufw-before-forward -p icmp --icmp-type echo-request -j ACCEPT# allow dhcp client to work
-A ufw-before-input -p udp --sport 67 --dport 68 -j ACCEPT#
# ufw-not-local
#
-A ufw-before-input -j ufw-not-local# if LOCAL, RETURN
-A ufw-not-local -m addrtype --dst-type LOCAL -j RETURN# if MULTICAST, RETURN
-A ufw-not-local -m addrtype --dst-type MULTICAST -j RETURN# if BROADCAST, RETURN
-A ufw-not-local -m addrtype --dst-type BROADCAST -j RETURN# all other non-local packets are dropped
-A ufw-not-local -m limit --limit 3/min --limit-burst 10 -j ufw-logging-deny
-A ufw-not-local -j DROP# allow MULTICAST mDNS for service discovery (be sure the MULTICAST line above
# is uncommented)
-A ufw-before-input -p udp -d 224.0.0.251 --dport 5353 -j ACCEPT# allow MULTICAST UPnP for service discovery (be sure the MULTICAST line above
# is uncommented)
-A ufw-before-input -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT
EOFlog_success "Updated /etc/ufw/before.rules with IPSet integration"# Install Fail2Banlog_info "Installing Fail2Ban package..."if apt install -y fail2ban; thenlog_success "Fail2Ban installed successfully"elselog_error "Failed to install Fail2Ban"log_function_end "Installing Fail2Ban" 1return 1fi# Create /etc/fail2ban/action.d/ipset-block.conflog_info "Creating Persistent /etc/fail2ban/action.d/ipset-block.conf"cat > /etc/fail2ban/action.d/ipset-block.conf << 'EOF'
# Fail2Ban action file for ipset
#
# This action blocks/unblocks an IP address using ipset.
#
[INCLUDES]before =[Definition]# The name of the ipset set to use.
setname = fail2ban-banned# Action startup (creates the set if it doesn't exist)
actionstart = /usr/sbin/ipset create <setname> hash:ip timeout 0 exist# Action shutdown (flushes the set when Fail2Ban stops)
#actionstop = ipset flush <setname>
actionstop = # Action to ban an IP
actionban = /usr/sbin/ipset add <setname> <ip> timeout 0 exist# Action to unban an IP
actionunban = /usr/sbin/ipset del <setname> <ip> exist[Init]
EOFlog_success "Created /etc/fail2ban/action.d/ipset-block.conf"# Create IPSet action for fail2banlog_info "Creating Fail2Ban IPSet action configuration..."mkdir -p /etc/fail2ban/action.dcat > /etc/fail2ban/action.d/ipset-ban.conf << 'EOF'
[INCLUDES]
before = iptables-common.conf[Definition]
# Option: actionstart
# Notes.: command executed once at the start of Fail2Ban.
actionstart = ipset create <ipmset> hash:ip timeout <default-timeout> <family># Option: actionstop
# Notes.: command executed once at the end of Fail2Ban
actionstop = ipset destroy <ipmset># Option: actionban
# Notes.: command executed when banning an IP.
actionban = ipset add <ipmset> <ip> timeout <timeout> -exist# Option: actionunban
# Notes.: command executed when unbanning an IP.
actionunban = ipset del <ipmset> <ip> -exist[Init]
# Default name of the ipset
ipmset = fail2ban-<name># Option: timeout
# Notes.: timeout for the ban, in seconds
timeout = 0# Option: default-timeout
# Notes.: default timeout for ipset creation
default-timeout = 0# Option: family
# Notes.: IP family, can be inet or inet6
family = inet
EOF# Create enhanced IPSet action for permanent banscat > /etc/fail2ban/action.d/ipset-persistent.conf << 'EOF'
[INCLUDES]
before = iptables-common.conf[Definition]
actionstart = ipset create <ipmset> hash:ip timeout 0 -existipset restore -file /etc/ipset.rules -existactionstop = ipset save -file /etc/ipset.rulesipset destroy <ipmset>actionban = ipset add <ipmset> <ip> timeout 0 -existipset save -file /etc/ipset.rulesactionunban = ipset del <ipmset> <ip> -existipset save -file /etc/ipset.rules[Init]
ipmset = fail2ban-banned
EOF# Create recidive action for repeat offenderscat > /etc/fail2ban/action.d/ipset-recidive.conf << 'EOF'
[INCLUDES]
before = iptables-common.conf[Definition]
actionstart = ipset create <ipmset> hash:ip timeout 0 -existactionstop = ipset save -file /etc/ipset.rulesactionban = ipset add <ipmset> <ip> timeout 0 -existipset save -file /etc/ipset.rulesactionunban = ipset del <ipmset> <ip> -existipset save -file /etc/ipset.rules[Init]
ipmset = fail2ban-recidive
EOFlog_success "Created Fail2Ban IPSet action configurations"# Create jail configurationlog_info "Configuring Fail2Ban jails with IPSet integration..."cat > /etc/fail2ban/jail.local << EOF
[DEFAULT]
# Ban settings
bantime = -1
findtime = 1800
maxretry = 3
backend = auto# IPSet integration
banaction = ipset-persistent
banaction_allports = ipset-persistent# Network settings
allowipv6 = auto
ignoreip = 127.0.0.1/8 ::1usw.daven.us jpt.daven.us bjn.daven.us bjt.daven.us usc.daven.us# Email settings (optional)
# destemail = admin@yourdomain.com
# sendername = Fail2Ban
# mta = sendmail[recidive]
enabled = true
logpath = /var/log/fail2ban.log
banaction = ipset-recidive
bantime = -1
findtime = 86400
maxretry = 3
filter = recidive[sshd]
enabled = true
port = $SSH_PORT
filter = sshd
logpath = /var/log/auth.log
backend = auto
bantime = 72000
findtime = 600
maxretry = 5[ssh-scanner]
enabled = true
port = $SSH_PORT
filter = ssh-scanner
logpath = /var/log/auth.log
maxretry = 5
bantime = 72000
findtime = 600[nginx-scan]
enabled = true
port = http,https,6033
logpath = /var/log/nginx/access.log/var/log/nginx/*.access.log
filter = nginx-scan
maxretry = 5
bantime = -1
findtime = 600[nginx-404-scan]
enabled = true
port = http,https,6033
logpath = /var/log/nginx/access.log/var/log/nginx/*.access.log
filter = nginx-404-scan
maxretry = 20
bantime = -1
findtime = 600[nginx-login-bruteforce]
enabled = true
port = http,https,6033
logpath = /var/log/nginx/access.log
filter = nginx-login-bruteforce
maxretry = 5
bantime = -1
findtime = 600[nginx-bad-useragent]
enabled = true
port = http,https,6033
logpath = /var/log/nginx/access.log
filter = nginx-bad-useragent
maxretry = 5
bantime = -1
findtime = 600[nginx-ray-abuse]
enabled = true
port = http,https,6033
logpath = /var/log/nginx/access.log
filter = nginx-ray-abuse
maxretry = 12
bantime = -1
findtime = 60[nginx-status-abuse]
enabled = true
port = http,https,6033
logpath = /var/log/nginx/access.log/var/log/nginx/*.access.log
filter = nginx-status-abuse
maxretry = 30
bantime = -1
findtime = 600[nginx-attacks]
enabled = true
port = http,https
filter = nginx-attack
logpath = /var/log/nginx/access.log
maxretry = 3
bantime = -1
findtime = 60[nginx-web-attacks]
enabled = true
port = http,https
filter = nginx-web-attacks
logpath = /var/log/nginx/*.daven.us.access.log
maxretry = 12
bantime = -1
findtime = 600
EOFlog_success "Created /etc/fail2ban/jail.local configuration file"# fail2ban for sshd and ssh-scanner local filterlog_success "Fail2Ban jails configured successfully"mkdir -p /etc/fail2ban/filter.dlog_info "Creating Fail2Ban filter for sshd and ssh-scanner..."# Create sshd local filter configurationlog_info "Creating sshd.local filter configuration..."cat > /etc/fail2ban/filter.d/sshd.local << 'EOF'
[Definition]
allowipv6 = auto
failregex = ^<HOST> .* "[^"]*" .*" "(?:Go-http-client|wget|curl|python-requests|masscan|zgrab|sqlmap|nikto|dirb|gobuster)" .*$^<HOST> .* "[^"]*" .*" ".*(?:Mozi\.m|scamanje|stresserit)" .*$^<HOST> .* "[^"]*" .*" "xfa1" .*$
ignoreregex = ^<HOST> .* "[^"]*" .*" ".*(?:Googlebot|Bingbot|YandexBot|DuckDuckBot)" .*$
EOFlog_success "sshd.local filter configuration created"# Create ssh-scanner filterlog_info "Creating Fail2Ban filter for SSH scanner..."cat > /etc/fail2ban/filter.d/ssh-scanner.conf << 'EOF'
[INCLUDES]
before = common.conf
[Definition]
_daemon = sshd
allowipv6 = auto
failregex = ^%(__prefix_line)sConnection from <HOST> port \d+ on \S+ port \d+$^%(__prefix_line)sConnection closed by <HOST> port \d+ \[preauth\]$^%(__prefix_line)sConnection closed by authenticating user .* <HOST> port \d+ \[preauth\]$^%(__prefix_line)sDisconnected from .* <HOST> port \d+ \[preauth\]$^%(__prefix_line)sReceived disconnect from <HOST> port \d+:\d+: .* \[preauth\]$^%(__prefix_line)sbanner exchange: Connection from <HOST> port \d+: invalid format$
ignoreregex =
EOFlog_success "ssh-scanner filter created"# Create Fail2Ban jail for nginx scanners# Create nginx-scan filterlog_info "Creating Fail2Ban filter for Nginx scanner..."cat > /etc/fail2ban/filter.d/nginx-scan.conf << 'EOF'
[Definition]
allowipv6 = auto
failregex = ^<HOST> .* "(GET|POST|PUT) [^"]*(?:\.env|\.git|phpinfo|eval-stdin\.php|shell\?|admin/login\.asp|boaform/admin|login\.cgi)" .*$^<HOST> .* "(GET|POST) [^"]*(?:wget\+|chmod\+|/tmp/|Mozi\.m|scamanje\.stresserit\.pro)" .*$^<HOST> .* "(GET|POST) [^"]*(?:/SDK/webLanguage|/actuator|/console|/geoserver|/solr/admin)" .*$^<HOST> .* "(GET|POST) [^"]*(?:phpunit|vendor/phpunit|_ignition)" .*$^<HOST> .* "[^"]*(?:27;wget|mstshash=)" .*$
ignoreregex = ^<HOST> .* "GET /(?:favicon\.ico|robots\.txt|sitemap\.xml) .*$
EOFlog_success "nginx-scan filter created"# Create nginx-404-scan filterlog_info "Creating Fail2Ban filter for Nginx 404 scanner..."cat > /etc/fail2ban/filter.d/nginx-404-scan.conf << 'EOF'
[Definition]
allowipv6 = auto
failregex = ^<HOST> - - \[.*\] "(?:GET|POST) /(?:admin|wp-admin|\.php|\.asp|phpinfo|\.env|config|backup|uploads|test|debug|system_info|diagnostics)" .*" 404 .*$^<HOST> - - \[.*\] "(?:GET|POST) [^"]*/(?:partymgr|jasperserver|solr|owncloud|geoserver|WebInterface)" .*" 404 .*$^<HOST> - - \[.*\] "(?:GET|POST|HEAD|OPTIONS|PUT|DELETE|CONNECT|TRACE|PATCH) /[a-zA-Z0-9]{4,8}(?:\s|/|$)" .*" 404 .*$
ignoreregex = ^<HOST> - - \[.*\] "GET /(?:favicon\.ico|robots\.txt|sitemap\.xml|apple-touch-icon|\.well-known/)" .*" 404 .*$
EOFlog_success "nginx-404-scan filter created"# Create login scanner filterlog_info "Creating Fail2Ban filter for nginx login bruteforce scanner..."cat > /etc/fail2ban/filter.d/nginx-login-bruteforce.conf << 'EOF'
[Definition]
allowipv6 = auto
failregex = ^<HOST> .* "(?:GET|POST) /login\.cgi\?username=.*&psd=" .*$^<HOST> .* "POST /boaform/admin/formLogin" .*$^<HOST> .* "GET /boaform/admin/formLogin\?username=.*&psd=" .*$^<HOST> .* "POST /admin/login\." .*$
ignoreregex =
EOFlog_success "nginx-login-bruteforce filter created"# Create nginx bad User-Agent filterlog_info "Creating Fail2Ban filter for Nginx bad User-Agent..."cat > /etc/fail2ban/filter.d/nginx-bad-useragent.conf << 'EOF'
[Definition]
allowipv6 = auto
failregex = ^<HOST> .* "[^"]*" .*" "(?:Go-http-client|wget|curl|python-requests|masscan|zgrab|sqlmap|nikto|dirb|gobuster)" .*$^<HOST> .* "[^"]*" .*" ".*(?:Mozi\.m|scamanje|stresserit)" .*$^<HOST> .* "[^"]*" .*" "xfa1" .*$
ignoreregex = ^<HOST> .* "[^"]*" .*" ".*(?:Googlebot|Bingbot|YandexBot|DuckDuckBot)" .*$
EOFlog_success "nginx-bad-useragent filter created"# Create nginx ray abuse filterlog_info "Creating Fail2Ban filter for Nginx Ray abuse..."cat > /etc/fail2ban/filter.d/nginx-ray-abuse.conf << 'EOF'
[Definition]
allowipv6 = auto
failregex = ^<HOST> .* "GET /api HTTP/1\.1" 101 .*$
ignoreregex =
EOFlog_success "nginx-ray-abuse filter created"# Create nginx status abuse filterlog_info "Creating Fail2Ban filter for Nginx status abuse..."cat > /etc/fail2ban/filter.d/nginx-status-abuse.conf << 'EOF'
[Definition]
allowipv6 = auto
failregex = ^<HOST> - - \[.*\] "(?:GET|POST|HEAD) .* HTTP/1\.[01]" 40[0-3] \d+ ".*" ".*"$
ignoreregex = ^<HOST> .* "GET /(?:favicon\.ico|robots\.txt)" 40[0-3] .*$
EOFlog_success "nginx-status-abuse filter created"# Create nginx status abuse filterlog_info "Creating Fail2Ban filter for Nginx attack abuse..."cat > /etc/fail2ban/filter.d/nginx-attack.conf << 'EOF'
[Definition]
allowipv6 = auto
failregex = ^<HOST> -.*"GET .*(.env|.git|.well-known/security\.txt|\/phpmyadmin|\/wp-login\.php|\/wp-admin|\/cgi-bin|\/phpinfo|\.sql|\.log|\.ini|\.conf|\.bak).* HTTP.*" (40[0-4]|444|499|500)^<HOST> -.*"GET .*(?:\x09hink|\x09pp).*shell_exec.*wget.*" 400.*
ignoreregex =
EOFlog_success "nginx-attack filter created"# Create nginx status abuse filterlog_info "Creating Fail2Ban filter for Nginx web attacks abuse..."cat > /etc/fail2ban/filter.d/nginx-web-attacks.conf << 'EOF'
[Definition]
allowipv6 = auto
failregex = ^<HOST> -.*"GET .*(?:\.env|\.git|\.well-known/security\.txt|\/phpmyadmin|\/wp-admin|\/cgi-bin|\/webui|\/geoserver|\/remote/login|onvif|PSIA|boaform|owa/auth/logon\.aspx|PROPFIND|\+CSCOE\+).*HTTP.*" (40[0-4]|444|499|500)^<HOST> -.*"GET .*(?:\x09hink|\x07pp).*shell_exec.*wget.*" 400.*^<HOST> -.*"POST .*cgi-bin/(\.\./).*bin/sh HTTP.*" (400|404|301|302)^<HOST> -.*"GET .*HTTP.*" (40[0-4]|444|499).*"(?:zgrab|CMS-Checker|libredtail-http|WanScannerBot|Odin|GenomeCrawlerd)"
ignoreregex =
EOFlog_success "nginx-web-attacks filter created"# Disable conflicting default configuration fileslog_info "Disabling conflicting default configuration files..."if [ -f /etc/fail2ban/jail.d/defaults-debian.conf ]; thenif mv /etc/fail2ban/jail.d/defaults-debian.conf /etc/fail2ban/jail.d/defaults-debian.disabled; thenlog_success "Conflicting default configuration files disabled"elselog_warning "Failed to disable conflicting default configuration files"fifi# Restart services in proper orderlog_info "Starting services in proper order..."# Start IPSet persistence firstsystemctl start ipset-persistent.service# Reload UFW to pick up the new before.ruleslog_info "Reloading UFW to apply IPSet integration..."ufw --force reloadlog_success "UFW reloaded with IPSet integration"# Enable and start Fail2Bansystemctl enable fail2bansystemctl start fail2banlog_info "Fail2Ban service started"# Wait for fail2ban to initializesleep 3# Verify IPSet integrationlog_info "Verifying IPSet integration..."if ipset list fail2ban-banned >/dev/null 2>&1; thenlog_success "IPSet 'fail2ban-banned' is active"elselog_error "IPSet 'fail2ban-banned' is not active"fi# Verify UFW integrationif iptables -L ufw-before-input -n | grep -q fail2ban-banned; thenlog_success "UFW is integrated with IPSet"elselog_warning "UFW integration with IPSet may not be working"fi# Create management toolscreate_ipset_management_tools# Create fail2ban-tester.shlog_info "Creating /usr/bin/fail2ban-tester.sh..."cat > /usr/bin/fail2ban-tester.sh << 'EOF'
#!/bin/bash
# A script to automatically test all enabled Fail2ban jails using fail2ban-regex.
# It fetches the filter and logpath for each active jail and runs the test.
# By Dave Nian on 25Aug25# --- Configuration ---
# Colors for better readability
C_RESET='\033[0m'
C_RED='\033[0;31m'
C_GREEN='\033[0;32m'
C_YELLOW='\033[0;33m'
C_BLUE='\033[0;34m'
C_CYAN='\033[0;36m'
C_BOLD='\033[1m'# --- Pre-flight Checks ---
# Check if running as root
if [[ $EUID -ne 0 ]]; thenecho -e "${C_RED}This script must be run as root.${C_RESET}"exit 1
fi# Check if fail2ban-client is available
if ! command -v fail2ban-client &> /dev/null; thenecho -e "${C_RED}Error: 'fail2ban-client' command not found.${C_RESET}"echo "Please ensure Fail2ban is installed and you are running this on the correct server."exit 1
fi# --- Main Logic ---
echo -e "${C_BOLD}${C_BLUE}--- Starting Fail2ban Filter Test ---${C_RESET}"# Get the list of enabled jails from fail2ban-client
# The sed command cleans up the output to get just the jail names
ENABLED_JAILS=$(fail2ban-client status | grep "Jail list:" | sed -e 's/.*Jail list:\s*//' -e 's/,//g')if [ -z "$ENABLED_JAILS" ]; thenecho -e "${C_RED}Could not find any enabled jails. Exiting.${C_RESET}"exit 1
fiecho -e "Found enabled jails: ${C_YELLOW}${ENABLED_JAILS}${C_RESET}\n"# Loop through each enabled jail
for jail in $ENABLED_JAILS; doecho -e "${C_BOLD}${C_CYAN}========================================${C_RESET}"echo -e "${C_BOLD}${C_CYAN} Testing Jail: [${jail}] ${C_RESET}"echo -e "${C_BOLD}${C_CYAN}========================================${C_RESET}"# Get the filter name for the current jail.# Redirect stderr to /dev/null to keep the output clean.filter_name=$(fail2ban-client get "$jail" filter 2>/dev/null)# ** FIX **: Check if the command failed or returned a known error message.# Some versions of fail2ban-client output this error to stdout.# If it fails, we assume the filter name is the same as the jail name.if [ $? -ne 0 ] || [[ "$filter_name" == *"Invalid command"* ]] || [ -z "$filter_name" ]; thenecho -e " ${C_YELLOW}Warning: Could not dynamically get filter for [${jail}].${C_RESET}"echo -e " ${C_YELLOW}Assuming filter name matches jail name.${C_RESET}"filter_name=$jailfifilter_file="/etc/fail2ban/filter.d/${filter_name}.conf"# ** FIX **: Get the log path(s) and parse the multi-line output correctly.# This command now specifically extracts lines that are file paths.log_paths_output=$(fail2ban-client get "$jail" logpath)log_paths=$(echo "$log_paths_output" | grep -E '^[|`]-' | sed -E 's/^[|`]- //')# If the above fails (for single-line outputs), use the raw output but clean it.if [ -z "$log_paths" ]; thenlog_paths=$(echo "$log_paths_output" | sed 's/Current monitored log file(s)://g' | tr -d '`-' | tr -d '|')fi# Check if the filter file actually existsif [ ! -f "$filter_file" ]; thenecho -e " ${C_RED}Filter file not found:${C_RESET} ${filter_file}"# Try to find it with a .local extension as a fallbackfilter_file_local="/etc/fail2ban/filter.d/${filter_name}.local"if [ -f "$filter_file_local" ]; thenecho -e " ${C_YELLOW}Found fallback filter:${C_RESET} ${filter_file_local}"filter_file=$filter_file_localelseecho -e " ${C_RED}Skipping jail [${jail}] as no valid filter was found.${C_RESET}\n"continuefifiecho -e " ${C_BOLD}Filter:${C_RESET} ${filter_file}"echo -e " ${C_BOLD}Log(s):${C_RESET}\n${log_paths}" # Print the cleaned listecho ""# Loop through each log path (a jail can have multiple)for log_path in $log_paths; do# Expand wildcards in log pathsexpanded_logs=$(eval echo $log_path)for expanded_log_path in $expanded_logs; do# Check if the log file exists and is readableif [ ! -r "$expanded_log_path" ]; thenecho -e " -> Testing log: ${C_YELLOW}${expanded_log_path}${C_RESET}"echo -e " ${C_RED}Result: Log file not found or not readable. Skipping.${C_RESET}\n"continuefiecho -e " -> Testing log: ${C_GREEN}${expanded_log_path}${C_RESET}"# Run the fail2ban-regex command and capture the outputtest_output=$(fail2ban-regex "$expanded_log_path" "$filter_file")# ** FIX **: More robustly extract the number of matched lines.# This specifically finds the number preceding "matched".matches=0 # Default to 0matches_line=$(echo "$test_output" | grep "Lines:")if [[ -n "$matches_line" ]]; then# Use grep with Perl-compatible regex to extract the numbermatches=$(echo "$matches_line" | grep -oP '\d+(?=\s+matched)')fi# Print the summaryif [ "$matches" -gt 0 ]; thenecho -e " ${C_GREEN}${C_BOLD}Result: Found ${matches} matching lines!${C_RESET}"elseecho -e " ${C_YELLOW}Result: Found 0 matching lines.${C_RESET}"fiecho ""donedone
doneecho -e "${C_BOLD}${C_BLUE}--- Test Complete ---${C_RESET}"EOFif [ -f "/usr/bin/fail2ban-tester.sh" ];then log_info "fail2ban-tester.sh created in /usr/bin/"elselog_warning "fail2ban-tester.sh didn't exist in /usr/bin/"return 1fiif chmod 777 /usr/bin/fail2ban-tester.sh;thenlog_info "/usr/bin/fail2ban-tester.sh has been given execute permission"elselog_warning "Ran chmode on /usr/bin/fail2ban-tester.sh failed"return 1fiif ln -s /usr/bin/fail2ban-tester.sh /usr/bin/fail2ban-tester;thenlog_info "Linked /usr/bin/fail2ban-tester.sh to /usr/bin/fail2ban-tester"elselog_warning "Failed to link /usr/bin/fail2ban-tester"return 1fi# Fixing the WARNING 'allowipv6' not defined in 'Definition'if fail2ban_sshd_local_allowipv6; thenlog_success "'allowipv6' configuration fixed in sshd.local"elselog_warning "'allowipv6' configuration not fixed in sshd.local"fi# Final restart to apply all changeslog_info "Performing final restart of services..."systemctl daemon-reloadsystemctl restart fail2banif systemctl is-active --quiet fail2ban; thenlog_success "Fail2Ban restarted successfully with IPSet integration"elselog_error "Failed to restart Fail2Ban"systemctl status fail2ban --no-pager -l || truelog_function_end "Installing Fail2Ban with IPSet" 1return 1fi# Create Fail2Ban management toolslog_info "Creating Fail2Ban management tools..." create_fail2ban_tools# Verify installationif verify_fail2ban_installation; thenlog_success "🎉 Fail2Ban with IPSet integration completed successfully!"show_fail2ban_summarylog_function_end "Installing Fail2Ban with IPSet" 0return 0elselog_warning "?? Fail2Ban with IPSet installed but some issues detected"show_fail2ban_troubleshootinglog_function_end "Installing Fail2Ban with IPSet" 1return 1fi
}# Function to create IPSet management tools
create_ipset_management_tools() {log_info "Creating IPSet management tools..."# Create IPSet status scriptcat > /usr/local/bin/ipset-status << 'EOF'
#!/bin/bash
# IPSet Status Display Scriptecho "=== IPSet Status ==="
echo "Active IPSets:"
ipset list -nameecho ""
echo "=== Fail2Ban IPSets ==="
for set in $(ipset list -name | grep fail2ban); doecho "--- $set ---"echo "Members: $(ipset list $set | grep -c '^[0-9]')"ipset list $set | head -20echo ""
doneecho "=== IPSet Rules in iptables ==="
iptables -L ufw-before-input -n | grep set
EOFchmod +x /usr/local/bin/ipset-statuslog_success "Created IPSet status script"# Create IPSet backup scriptcat > /usr/local/bin/ipset-backup << 'EOF'
#!/bin/bash
# IPSet Backup ScriptBACKUP_DIR="/etc/ipset-backups"
mkdir -p "$BACKUP_DIR"BACKUP_FILE="$BACKUP_DIR/ipset-backup-$(date +%Y%m%d-%H%M%S).rules"
ipset save > "$BACKUP_FILE"echo "IPSet rules backed up to: $BACKUP_FILE"# Keep only last 10 backups
ls -t "$BACKUP_DIR"/ipset-backup-*.rules | tail -n +11 | xargs rm -f 2>/dev/null
EOFchmod +x /usr/local/bin/ipset-backuplog_success "Created IPSet backup script"
}fail2ban_sshd_local_allowipv6() {local source_file="/etc/fail2ban/filter.d/sshd.conf"local local_file="/etc/fail2ban/filter.d/sshd.local"if [ -f "$source_file" ]; thenlog_info "Setting up sshd.local filter configuration..."# Backup existing sshd.local if it existsif [ -f "$local_file" ]; thenlog_info "Backing up existing sshd.local..."cp "$local_file" "${local_file}.backup.$(date +%s)"fi# Copy and set permissionsif cp -f "$source_file" "$local_file"; thenchmod 644 "$local_file"# Verify copy resultif [ -s "$local_file" ]; thenlog_success "sshd.conf copied to sshd.local successfully"elselog_error "Copied file is empty"return 1fielselog_error "Failed to copy sshd.conf to sshd.local"return 1fi# Fix 'allowipv6' configurationlog_info "Fixing 'allowipv6' warning in sshd.local..."if sed -n '/^\[Definition\]/,/^\[/p' "$local_file" | grep -q "^[[:space:]]*allowipv6[[:space:]]*=[[:space:]]*\(auto\|yes\)"; thenlog_success "'allowipv6' already correctly configured in sshd.local"elseif sed -n '/^\[Definition\]/,/^\[/p' "$local_file" | grep -q "^[[:space:]]*allowipv6[[:space:]]*="; thenlog_info "Updating existing 'allowipv6' configuration to 'auto'"sed -i '/^\[Definition\]/,/^\[/{ s/^[[:space:]]*allowipv6[[:space:]]*=.*/allowipv6 = auto/; }' "$local_file"elselog_info "Adding 'allowipv6 = auto' to sshd.local"sed -i '/^\[Definition\]/a allowipv6 = auto' "$local_file"fi# Verify modification resultif grep -A 5 "^\[Definition\]" "$local_file" | grep -q "^allowipv6[[:space:]]*=[[:space:]]*auto"; thenlog_success "? allowipv6 successfully configured in sshd.local"elselog_warning "?? allowipv6 configuration may not be correct"fifielselog_error "Source file does not exist: $source_file"return 1fi
}# Unified verification function that handles both standard and IPSet installations
verify_fail2ban_installation() {log_info "Verifying Fail2Ban installation and configuration..."local verification_passed=truelocal tools_dir="/usr/local/bin/fail2ban-tools"local has_ipset=false# Detect if IPSet integration is being usedif command -v ipset >/dev/null 2>&1 && ipset list fail2ban-banned >/dev/null 2>&1; thenhas_ipset=truelog_info "IPSet integration detected, performing enhanced verification..."elselog_info "Standard Fail2Ban installation detected..."fi# 1. Check Fail2Ban service statusif systemctl is-active --quiet fail2ban; thenlog_success "? Fail2Ban service is running"elselog_error "? Fail2Ban service is not running"verification_passed=falsefi# 2. IPSet-specific checks (only if IPSet integration detected)if [ "$has_ipset" = true ]; then# Check IPSet persistence serviceif systemctl is-active --quiet ipset-persistent; thenlog_success "? IPSet persistence service is active"elselog_warning "?? IPSet persistence service may not be active"fi# Check IPSets existif ipset list fail2ban-banned >/dev/null 2>&1; thenlog_success "? IPSet 'fail2ban-banned' exists"elselog_error "? IPSet 'fail2ban-banned' does not exist"verification_passed=falsefi# Check for recidive IPSet (optional)if ipset list fail2ban-recidive >/dev/null 2>&1; thenlog_success "? IPSet 'fail2ban-recidive' exists"elselog_info "?? IPSet 'fail2ban-recidive' not found (optional)"fi# Check UFW integration with IPSetif iptables -L ufw-before-input -n | grep -q fail2ban-banned; thenlog_success "? UFW is integrated with IPSet"elselog_error "? UFW is not integrated with IPSet"verification_passed=falsefi# Check IPSet action fileslocal ipset_actions=("/etc/fail2ban/action.d/ipset-ban.conf""/etc/fail2ban/action.d/ipset-persistent.conf""/etc/fail2ban/action.d/ipset-recidive.conf")for action_file in "${ipset_actions[@]}"; doif [ -f "$action_file" ]; thenlog_success "? IPSet action file exists: $(basename "$action_file")"elselog_warning "?? IPSet action file missing: $action_file"fidone# Check IPSet rules fileif [ -f "/etc/ipset.rules" ]; thenlog_success "? IPSet rules file exists: /etc/ipset.rules"elselog_warning "?? IPSet rules file missing: /etc/ipset.rules"fifi# 3. Check jail statuslocal active_jails=$(fail2ban-client status 2>/dev/null | grep "Jail list:" | cut -d: -f2 | tr ',' '\n' | wc -w)if [ "$active_jails" -gt 0 ]; thenlog_success "? $active_jails jail(s) active"# Check specific jailsfor jail in sshd ssh-scanner; doif fail2ban-client status "$jail" >/dev/null 2>&1; thenlog_success "? $jail jail is active"elselog_warning "?? $jail jail is not active"fidoneelselog_error "? No active jails found"verification_passed=falsefi# 4. Check configuration fileslocal config_files=("/etc/fail2ban/jail.local""/etc/fail2ban/filter.d/sshd.local""/etc/fail2ban/filter.d/ssh-scanner.conf""/etc/fail2ban/filter.d/nginx-scan.conf""/etc/fail2ban/filter.d/nginx-404-scan.conf""/etc/fail2ban/filter.d/nginx-login-bruteforce.conf""/etc/fail2ban/filter.d/nginx-bad-useragent.conf""/etc/fail2ban/filter.d/nginx-ray-abuse.conf""/etc/fail2ban/filter.d/nginx-status-abuse.conf""/etc/fail2ban/filter.d/nginx-attack.conf""/etc/fail2ban/filter.d/nginx-web-attacks.conf")local missing_configs=0for config_file in "${config_files[@]}"; doif [ -f "$config_file" ]; thenlog_success "? Configuration file exists: $(basename "$config_file")"elselog_error "? Configuration file missing: $config_file"verification_passed=false((missing_configs++))fidoneif [ "$missing_configs" -eq 0 ]; thenlog_success "? All configuration files are present"elselog_error "? $missing_configs configuration file(s) missing"fi# 5. Check log fileif [ -f "/var/log/fail2ban.log" ]; thenlocal recent_errors=$(tail -50 /var/log/fail2ban.log 2>/dev/null | grep -c "ERROR" || echo "0")if [ "$recent_errors" -eq 0 ]; thenlog_success "? No recent errors in Fail2Ban log"elselog_warning "?? Found $recent_errors recent errors in Fail2Ban log"fielselog_warning "?? Fail2Ban log file not found at /var/log/fail2ban.log"fi# 6. Check tool filesif [ -d "$tools_dir" ]; thenlog_success "? Fail2Ban tools directory exists ($tools_dir)"if [ -f "$tools_dir/fail2ban-checking.sh" ]; thenlog_success "? Fail2Ban check script exists"if [ -f "$tools_dir/fail2ban-status.sh" ]; thenlog_success "? Fail2Ban status script exists"elselog_error "? Fail2Ban status script missing"verification_passed=falsefielselog_error "? Fail2Ban check script missing"verification_passed=falsefielselog_error "? Fail2Ban tools directory missing"verification_passed=falsefi# 7. Check tool symlinksif [ -f "/usr/local/bin/fail2ban-checking" ]; thenlog_success "? Fail2Ban checking symlink exists"if [ -f "/usr/local/bin/fail2ban-status" ]; thenlog_success "? Fail2Ban status symlink exists"elselog_error "? Fail2Ban status symlink missing"verification_passed=falsefielselog_error "? Fail2Ban checking symlink missing"verification_passed=falsefi# 8. Check fail2ban-tester scriptif [ -f "/usr/bin/fail2ban-tester.sh" ] && [ -f "/usr/bin/fail2ban-tester" ]; thenlog_success "? Fail2Ban tester script exists"elselog_warning "?? Fail2Ban tester script missing"fi# 9. Additional IPSet management tools check (if IPSet detected)if [ "$has_ipset" = true ]; thenif [ -f "/usr/local/bin/ipset-status" ]; thenlog_success "? IPSet status script exists"elselog_warning "?? IPSet status script missing"fiif [ -f "/usr/local/bin/ipset-backup" ]; thenlog_success "? IPSet backup script exists"elselog_warning "?? IPSet backup script missing"fifi# Summaryif [ "$has_ipset" = true ]; thenlog_info "Verification completed for Fail2Ban with IPSet integration"elselog_info "Verification completed for standard Fail2Ban installation"fireturn $([ "$verification_passed" = true ] && echo 0 || echo 1)
}show_fail2ban_summary() {local has_ipset=false# Detect if IPSet integration is being usedif command -v ipset >/dev/null 2>&1 && ipset list fail2ban-banned >/dev/null 2>&1; thenhas_ipset=truefiechoif [ "$has_ipset" = true ]; thenlog_info "📋 Fail2Ban with IPSet Integration Summary"echo "============================================="echo "🔐 SSH Port: $SSH_PORT"echo "🚫 Ban Policy: Permanent bans via IPSet"echo "🕒 SSH Attempts: 3 failures in 30 minutes"echo "🕒 Scanner Detection: 2 connections in 5 minutes"echo "🔧 Firewall Integration: UFW + IPSet"echo "💾 IPSet Persistence: Enabled"echoecho "📁 Key Configuration Files:"echo " ? Main config: /etc/fail2ban/jail.local"echo " ? IPSet actions: /etc/fail2ban/action.d/ipset-*.conf"echo " ? IPSet rules: /etc/ipset.rules"echo " ? UFW before rules: /etc/ufw/before.rules"echo " ? SSH filter: /etc/fail2ban/filter.d/sshd.local"echo " ? Scanner filter: /etc/fail2ban/filter.d/ssh-scanner.conf"echo " ? Nginx filters: /etc/fail2ban/filter.d/nginx-*.conf"echoecho "🔧 Management Commands:"echo " ? Fail2Ban status: fail2ban-client status"echo " ? IPSet status: ipset-status"echo " ? IPSet backup: ipset-backup"echo " ? View banned IPs: ipset list fail2ban-banned"echo " ? Unban IP: fail2ban-client set <jail> unbanip <IP>"echo " ? Manual IPSet ban: ipset add fail2ban-banned <IP>"echo " ? Manual IPSet unban: ipset del fail2ban-banned <IP>"echoecho "🔧 Service Management:"echo " ? Restart Fail2Ban: systemctl restart fail2ban"echo " ? Reload UFW: ufw reload"echo " ? Save IPSet: ipset save > /etc/ipset.rules"echo "============================================="elselog_info "📋 Fail2Ban Configuration Summary"echo "=================================="echo "🔐 SSH Port: $SSH_PORT"echo "🚫 Ban Policy: Permanent bans"echo "🕒 SSH Attempts: 3 failures in 30 minutes"echo "🕒 Scanner Detection: 2 connections in 5 minutes" echo "🔧 Firewall Integration: UFW"echoecho "📁 Configuration Files:"echo " ? Main config: /etc/fail2ban/jail.local"echo " ? SSH filter: /etc/fail2ban/filter.d/sshd.local"echo " ? Scanner filter: /etc/fail2ban/filter.d/ssh-scanner.conf"echo " ? Nginx filters: /etc/fail2ban/filter.d/nginx-*.conf"echoecho "🔧 Management Commands:"echo " ? Check status: fail2ban-client status"echo " ? Check SSH jail: fail2ban-client status sshd"echo " ? View logs: tail -f /var/log/fail2ban.log"echo " ? Unban IP: fail2ban-client set sshd unbanip <IP>"echo " ? Restart service: systemctl restart fail2ban"echo "=================================="fiechoecho "🔧 Additional Tools:"echo " ? Security check: fail2ban-checking"echo " ? Status display: fail2ban-status" echo " ? Filter tester: fail2ban-tester"echoecho "🔧 Troubleshooting:"echo " ? Check service status: systemctl status fail2ban"echo " ? View logs: journalctl -u fail2ban -f"echo " ? Test configuration: fail2ban-client -d"echo " ? Check log files: tail -f /var/log/fail2ban.log"echo " ? Manual restart: systemctl restart fail2ban"echo " ? Check UFW integration: ufw status"if [ "$has_ipset" = true ]; thenecho " ? Check IPSet rules: ipset list"echo " ? Check firewall rules: iptables -L ufw-before-input -n"elseecho " ? Check firewall rules: iptables -L -n"fiecho "=================================="
}
總結:
因為我使用的 -1 永久封,造成內存中有幾百條 iptables 記錄,嚴重影響性能。 現在使用 IPset 做為一個池來集中管理。 也在修改之前的策略改為封20小時,這個腳本中可改。
這三個工具構成了一套層次化的網絡安全防護體系,它們的協同工作過程如下:
角色分工
UFW (Uncomplicated Firewall):作為 iptables 的簡化前端,負責基礎防火墻規則管理和流量過濾的最終執行。
IPset:高效的 IP 地址集合管理工具,使用哈希表存儲大量 IP 地址,提供 O(1) 時間復雜度的查找效率。
Fail2ban:智能入侵檢測系統,監控日志文件、分析攻擊模式、觸發自動封禁動作。
核心工作流程
檢測階段:
- 攻擊者嘗試連接服務(如SSH)
- 服務記錄認證失敗日志到
/var/log/auth.log
- Fail2ban 實時監控日志文件,使用正則表達式匹配攻擊模式
- 計數器跟蹤每個IP的失敗次數
封禁階段:
- 當失敗次數達到閾值(如 maxretry=3),Fail2ban 觸發封禁動作
- 執行 IPset 命令:
ipset add fail2ban-ssh 攻擊者IP
- IP被添加到預先創建的IPset集合中
- UFW/iptables 規則立即生效:
iptables -I INPUT -m set --match-set fail2ban-ssh src -j DROP
防護階段:
- 后續來自該IP的所有請求在內核層面被直接丟棄
- 不再消耗應用服務資源
- 根據配置的 bantime 自動解封或永久封禁
關鍵性能優勢
傳統方式的問題是每個被封IP需要單獨的 iptables 規則,當封禁IP數量達到數千個時,規則匹配效率急劇下降。
IPset 優化方式只需要一條 iptables 規則引用整個IP集合,無論集合中有多少IP,查找效率都保持恒定。這種方式可以高效處理數萬個封禁IP而不影響網絡性能。
實際數據流
正常流量:外部請求 → UFW檢查 → IPset查詢(未命中) → 通過基礎規則 → 到達服務
惡意流量:攻擊請求 → UFW檢查 → IPset查詢(命中) → 直接丟棄數據包
這種架構的核心優勢是將被動防護(UFW/iptables)與主動檢測(Fail2ban)相結合,同時通過IPset解決了大規模IP封禁的性能瓶頸問題。整個系統實現了從攻擊檢測到自動響應的完全自動化,大大降低了管理員的工作負擔。
收到 CSDN 消息: