a1a17e81a1
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
634 lines
17 KiB
Bash
Executable File
634 lines
17 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# configure-miab-metrics.sh - Enable extended metrics logging on Mail-in-a-Box
|
|
#
|
|
# Enables SpamAssassin rules logging and/or TLS cipher logging for
|
|
# postfix-metrics.sh to collect detailed metrics.
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_NAME=$(basename "$0")
|
|
VERSION="1.0.0"
|
|
|
|
# Defaults
|
|
DRY_RUN=false
|
|
VERBOSE=false
|
|
ENABLE_SPAMASSASSIN=false
|
|
ENABLE_TLS=false
|
|
BACKUP=true
|
|
FORCE=false
|
|
STATUS_ONLY=false
|
|
|
|
# Colors (disabled if not a terminal)
|
|
if [[ -t 1 ]]; then
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
else
|
|
RED='' GREEN='' YELLOW='' BLUE='' NC=''
|
|
fi
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: $SCRIPT_NAME [OPTIONS]
|
|
|
|
Configure Mail-in-a-Box for extended metrics collection.
|
|
|
|
OPTIONS:
|
|
-s, --spamassassin Enable SpamAssassin rules logging (spampd debug mode)
|
|
-t, --tls Enable TLS cipher logging in Postfix
|
|
-a, --all Enable both (default if no -s or -t specified)
|
|
|
|
-n, --dry-run Show what would be done without making changes
|
|
-f, --force Skip confirmation prompts
|
|
-v, --verbose Show detailed output
|
|
--no-backup Don't create backups before modifying files
|
|
--status Show current configuration status and exit
|
|
|
|
-h, --help Show this help message
|
|
--version Show version
|
|
|
|
EXAMPLES:
|
|
$SCRIPT_NAME # Enable both (interactive)
|
|
$SCRIPT_NAME -a # Enable both (interactive)
|
|
$SCRIPT_NAME -s # SpamAssassin only
|
|
$SCRIPT_NAME -t # TLS cipher logging only
|
|
$SCRIPT_NAME -a -n # Dry run, show all changes
|
|
$SCRIPT_NAME -a -f # Enable both, no prompts
|
|
|
|
WHAT THIS SCRIPT DOES:
|
|
|
|
SpamAssassin (-s):
|
|
- Appends --debug to ADDOPTS in /etc/default/spampd
|
|
- Creates rsyslog config to log to /var/log/spamassassin.log
|
|
- Sets up log file with correct permissions
|
|
- Creates logrotate config
|
|
- Restarts spampd and rsyslog
|
|
|
|
TLS Cipher (-t):
|
|
- Adds smtpd_tls_loglevel=1 and smtp_tls_loglevel=1 to /etc/postfix/main.cf
|
|
- Restarts Postfix
|
|
|
|
REQUIREMENTS:
|
|
- Must be run as root (or with sudo)
|
|
- Mail-in-a-Box installation
|
|
- spampd service (for -s option)
|
|
- postfix service (for -t option)
|
|
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
version() {
|
|
echo "$SCRIPT_NAME version $VERSION"
|
|
exit 0
|
|
}
|
|
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $*"
|
|
}
|
|
|
|
log_ok() {
|
|
echo -e "${GREEN}[OK]${NC} $*"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $*"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $*" >&2
|
|
}
|
|
|
|
log_dry() {
|
|
echo -e "${YELLOW}[DRY-RUN]${NC} $*"
|
|
}
|
|
|
|
log_verbose() {
|
|
if $VERBOSE; then
|
|
echo -e "${BLUE}[VERBOSE]${NC} $*"
|
|
fi
|
|
}
|
|
|
|
run_cmd() {
|
|
local desc="$1"
|
|
shift
|
|
if $DRY_RUN; then
|
|
log_dry "$desc: $*"
|
|
return 0
|
|
fi
|
|
log_verbose "Running: $*"
|
|
if ! "$@"; then
|
|
log_error "Failed: $desc"
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
write_file() {
|
|
local file="$1"
|
|
local content="$2"
|
|
local desc="${3:-$file}"
|
|
|
|
if $DRY_RUN; then
|
|
log_dry "Would create $desc:"
|
|
echo "$content" | sed 's/^/ /'
|
|
return 0
|
|
fi
|
|
|
|
if [[ -f "$file" ]] && $BACKUP; then
|
|
local backup="${file}.bak.$(date +%Y%m%d%H%M%S)"
|
|
log_verbose "Backing up $file to $backup"
|
|
cp "$file" "$backup"
|
|
fi
|
|
|
|
echo "$content" > "$file"
|
|
log_ok "Created $desc"
|
|
}
|
|
|
|
check_root() {
|
|
if [[ $EUID -ne 0 ]]; then
|
|
log_error "This script must be run as root (use sudo)"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_miab() {
|
|
if [[ ! -d /home/user-data ]] && [[ ! -f /etc/mailinabox.conf ]]; then
|
|
log_warn "This doesn't appear to be a Mail-in-a-Box installation"
|
|
if ! $FORCE; then
|
|
read -rp "Continue anyway? [y/N] " response
|
|
if [[ ! "$response" =~ ^[Yy] ]]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
confirm_action() {
|
|
local msg="$1"
|
|
if $FORCE || $DRY_RUN; then
|
|
return 0
|
|
fi
|
|
read -rp "$msg [y/N] " response
|
|
[[ "$response" =~ ^[Yy] ]]
|
|
}
|
|
|
|
# ============================================================================
|
|
# SpamAssassin Configuration
|
|
# ============================================================================
|
|
|
|
SPAMPD_DEFAULTS="/etc/default/spampd"
|
|
|
|
check_spampd() {
|
|
if ! systemctl list-unit-files spampd.service &>/dev/null; then
|
|
log_error "spampd service not found"
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
is_spampd_debug_enabled() {
|
|
# Check /etc/default/spampd for --debug in ADDOPTS
|
|
if [[ -f "$SPAMPD_DEFAULTS" ]]; then
|
|
if grep -qE '^ADDOPTS\s*=.*--debug' "$SPAMPD_DEFAULTS" 2>/dev/null; then
|
|
return 0
|
|
fi
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
is_rsyslog_spamassassin_configured() {
|
|
[[ -f /etc/rsyslog.d/50-spamassassin.conf ]]
|
|
}
|
|
|
|
is_logrotate_configured() {
|
|
[[ -f /etc/logrotate.d/spamassassin ]]
|
|
}
|
|
|
|
configure_spamassassin() {
|
|
log_info "Configuring SpamAssassin rules logging..."
|
|
|
|
if ! check_spampd; then
|
|
return 1
|
|
fi
|
|
|
|
local changes_made=false
|
|
|
|
# 1. Enable debug mode via /etc/default/spampd
|
|
if is_spampd_debug_enabled; then
|
|
log_ok "spampd debug mode already enabled"
|
|
else
|
|
log_info "Enabling spampd debug mode..."
|
|
|
|
if [[ ! -f "$SPAMPD_DEFAULTS" ]]; then
|
|
log_error "$SPAMPD_DEFAULTS not found"
|
|
return 1
|
|
fi
|
|
|
|
# Get current ADDOPTS value
|
|
local current_addopts=""
|
|
if grep -qE '^ADDOPTS\s*=' "$SPAMPD_DEFAULTS" 2>/dev/null; then
|
|
current_addopts=$(grep -E '^ADDOPTS\s*=' "$SPAMPD_DEFAULTS" | tail -1 | sed 's/^ADDOPTS\s*=\s*//' | tr -d '"'"'")
|
|
fi
|
|
|
|
# Build new ADDOPTS with --debug appended
|
|
local new_addopts
|
|
if [[ -n "$current_addopts" ]]; then
|
|
new_addopts="${current_addopts} --debug"
|
|
else
|
|
new_addopts="--debug"
|
|
fi
|
|
|
|
if $DRY_RUN; then
|
|
log_dry "Would update ADDOPTS in $SPAMPD_DEFAULTS:"
|
|
if [[ -n "$current_addopts" ]]; then
|
|
echo " Current: ADDOPTS=\"$current_addopts\""
|
|
fi
|
|
echo " New: ADDOPTS=\"$new_addopts\""
|
|
else
|
|
if $BACKUP; then
|
|
local backup="${SPAMPD_DEFAULTS}.bak.$(date +%Y%m%d%H%M%S)"
|
|
cp "$SPAMPD_DEFAULTS" "$backup"
|
|
log_verbose "Backed up to $backup"
|
|
fi
|
|
|
|
if grep -qE '^ADDOPTS\s*=' "$SPAMPD_DEFAULTS"; then
|
|
# Update existing ADDOPTS line
|
|
sed -i "s|^ADDOPTS\s*=.*|ADDOPTS=\"$new_addopts\"|" "$SPAMPD_DEFAULTS"
|
|
log_ok "Updated ADDOPTS to include --debug"
|
|
else
|
|
# Add new ADDOPTS line
|
|
cat >> "$SPAMPD_DEFAULTS" <<EOF
|
|
|
|
# Enable debug logging for metrics collection (added by $SCRIPT_NAME)
|
|
ADDOPTS="--debug"
|
|
EOF
|
|
log_ok "Added ADDOPTS=\"--debug\" to $SPAMPD_DEFAULTS"
|
|
fi
|
|
fi
|
|
changes_made=true
|
|
fi
|
|
|
|
# 2. Create rsyslog config
|
|
if is_rsyslog_spamassassin_configured; then
|
|
log_ok "rsyslog spamassassin config already exists"
|
|
else
|
|
log_info "Creating rsyslog configuration..."
|
|
|
|
local rsyslog_content="# Log spampd/spamd to separate file for metrics collection
|
|
:programname, isequal, \"spampd\" /var/log/spamassassin.log
|
|
& stop
|
|
|
|
:programname, isequal, \"spamd\" /var/log/spamassassin.log
|
|
& stop"
|
|
|
|
write_file "/etc/rsyslog.d/50-spamassassin.conf" "$rsyslog_content" "rsyslog spamassassin config"
|
|
changes_made=true
|
|
fi
|
|
|
|
# 3. Create log file with correct permissions
|
|
if [[ -f /var/log/spamassassin.log ]]; then
|
|
log_ok "Log file /var/log/spamassassin.log already exists"
|
|
else
|
|
log_info "Creating log file..."
|
|
if ! $DRY_RUN; then
|
|
touch /var/log/spamassassin.log
|
|
chown syslog:adm /var/log/spamassassin.log
|
|
chmod 640 /var/log/spamassassin.log
|
|
log_ok "Created /var/log/spamassassin.log"
|
|
else
|
|
log_dry "Would create /var/log/spamassassin.log with syslog:adm ownership"
|
|
fi
|
|
changes_made=true
|
|
fi
|
|
|
|
# 4. Create logrotate config
|
|
if is_logrotate_configured; then
|
|
log_ok "Logrotate config already exists"
|
|
else
|
|
log_info "Creating logrotate configuration..."
|
|
|
|
local logrotate_content="/var/log/spamassassin.log {
|
|
daily
|
|
rotate 7
|
|
compress
|
|
delaycompress
|
|
missingok
|
|
notifempty
|
|
create 640 syslog adm
|
|
postrotate
|
|
systemctl reload rsyslog > /dev/null 2>&1 || true
|
|
endscript
|
|
}"
|
|
|
|
write_file "/etc/logrotate.d/spamassassin" "$logrotate_content" "logrotate spamassassin config"
|
|
changes_made=true
|
|
fi
|
|
|
|
# 5. Restart services if changes were made
|
|
if $changes_made; then
|
|
log_info "Restarting services..."
|
|
run_cmd "Restart rsyslog" systemctl restart rsyslog
|
|
run_cmd "Restart spampd" systemctl restart spampd
|
|
|
|
if ! $DRY_RUN; then
|
|
sleep 2
|
|
if systemctl is-active --quiet spampd; then
|
|
log_ok "spampd is running with debug mode"
|
|
else
|
|
log_error "spampd failed to start - check: journalctl -u spampd"
|
|
fi
|
|
fi
|
|
else
|
|
log_ok "SpamAssassin logging already fully configured"
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# ============================================================================
|
|
# TLS Cipher Configuration
|
|
# ============================================================================
|
|
|
|
POSTFIX_MAIN_CF="/etc/postfix/main.cf"
|
|
|
|
is_tls_logging_enabled() {
|
|
if [[ ! -f "$POSTFIX_MAIN_CF" ]]; then
|
|
return 1
|
|
fi
|
|
|
|
local smtpd_level smtp_level
|
|
smtpd_level=$(grep -E '^smtpd_tls_loglevel\s*=' "$POSTFIX_MAIN_CF" 2>/dev/null | tail -1 | awk -F= '{print $2}' | tr -d ' ')
|
|
smtp_level=$(grep -E '^smtp_tls_loglevel\s*=' "$POSTFIX_MAIN_CF" 2>/dev/null | tail -1 | awk -F= '{print $2}' | tr -d ' ')
|
|
|
|
[[ "$smtpd_level" -ge 1 ]] 2>/dev/null && [[ "$smtp_level" -ge 1 ]] 2>/dev/null
|
|
}
|
|
|
|
configure_tls() {
|
|
log_info "Configuring TLS cipher logging..."
|
|
|
|
if [[ ! -f "$POSTFIX_MAIN_CF" ]]; then
|
|
log_error "Postfix main.cf not found at $POSTFIX_MAIN_CF"
|
|
return 1
|
|
fi
|
|
|
|
if is_tls_logging_enabled; then
|
|
log_ok "TLS logging already enabled in Postfix"
|
|
return 0
|
|
fi
|
|
|
|
log_info "Adding TLS log level settings to $POSTFIX_MAIN_CF..."
|
|
|
|
if $DRY_RUN; then
|
|
log_dry "Would add to $POSTFIX_MAIN_CF:"
|
|
echo " smtpd_tls_loglevel = 1"
|
|
echo " smtp_tls_loglevel = 1"
|
|
else
|
|
if $BACKUP; then
|
|
local backup="${POSTFIX_MAIN_CF}.bak.$(date +%Y%m%d%H%M%S)"
|
|
cp "$POSTFIX_MAIN_CF" "$backup"
|
|
log_verbose "Backed up to $backup"
|
|
fi
|
|
|
|
# Remove any existing settings first (to avoid duplicates)
|
|
sed -i '/^smtpd_tls_loglevel\s*=/d' "$POSTFIX_MAIN_CF"
|
|
sed -i '/^smtp_tls_loglevel\s*=/d' "$POSTFIX_MAIN_CF"
|
|
|
|
# Add new settings
|
|
cat >> "$POSTFIX_MAIN_CF" <<EOF
|
|
|
|
# TLS cipher logging for metrics collection (added by $SCRIPT_NAME)
|
|
smtpd_tls_loglevel = 1
|
|
smtp_tls_loglevel = 1
|
|
EOF
|
|
log_ok "Added TLS log level settings"
|
|
fi
|
|
|
|
# Restart Postfix
|
|
log_info "Restarting Postfix..."
|
|
run_cmd "Restart Postfix" systemctl restart postfix
|
|
|
|
if ! $DRY_RUN; then
|
|
sleep 2
|
|
if systemctl is-active --quiet postfix; then
|
|
log_ok "Postfix is running with TLS logging enabled"
|
|
else
|
|
log_error "Postfix failed to start - check: journalctl -u postfix"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# ============================================================================
|
|
# Status Check
|
|
# ============================================================================
|
|
|
|
show_status() {
|
|
echo ""
|
|
echo "Current Configuration Status:"
|
|
echo "=============================="
|
|
|
|
# Find spampd service file
|
|
local service_file=""
|
|
for f in /var/lib/systemd/system/spampd.service /lib/systemd/system/spampd.service /etc/systemd/system/spampd.service; do
|
|
[[ -f "$f" ]] && service_file="$f" && break
|
|
done
|
|
|
|
echo -n "SpamAssassin debug mode: "
|
|
if is_spampd_debug_enabled; then
|
|
echo -e "${GREEN}ENABLED${NC}"
|
|
else
|
|
echo -e "${YELLOW}DISABLED${NC}"
|
|
fi
|
|
|
|
if $VERBOSE && [[ -n "$service_file" ]]; then
|
|
echo " Service file: $service_file"
|
|
echo " Defaults file: $SPAMPD_DEFAULTS"
|
|
fi
|
|
|
|
echo -n "SpamAssassin rsyslog: "
|
|
if is_rsyslog_spamassassin_configured; then
|
|
echo -e "${GREEN}CONFIGURED${NC}"
|
|
else
|
|
echo -e "${YELLOW}NOT CONFIGURED${NC}"
|
|
fi
|
|
|
|
echo -n "SpamAssassin log file: "
|
|
if [[ -f /var/log/spamassassin.log ]]; then
|
|
local size
|
|
size=$(du -h /var/log/spamassassin.log 2>/dev/null | cut -f1)
|
|
echo -e "${GREEN}EXISTS${NC} ($size)"
|
|
else
|
|
echo -e "${YELLOW}MISSING${NC}"
|
|
fi
|
|
|
|
echo -n "SpamAssassin logrotate: "
|
|
if is_logrotate_configured; then
|
|
echo -e "${GREEN}CONFIGURED${NC}"
|
|
else
|
|
echo -e "${YELLOW}NOT CONFIGURED${NC}"
|
|
fi
|
|
|
|
echo -n "Postfix TLS logging: "
|
|
if is_tls_logging_enabled; then
|
|
echo -e "${GREEN}ENABLED${NC}"
|
|
else
|
|
echo -e "${YELLOW}DISABLED${NC}"
|
|
fi
|
|
|
|
# Show service status
|
|
echo ""
|
|
echo -n "spampd service: "
|
|
if systemctl is-active --quiet spampd 2>/dev/null; then
|
|
echo -e "${GREEN}RUNNING${NC}"
|
|
else
|
|
echo -e "${YELLOW}STOPPED${NC}"
|
|
fi
|
|
|
|
echo -n "postfix service: "
|
|
if systemctl is-active --quiet postfix 2>/dev/null; then
|
|
echo -e "${GREEN}RUNNING${NC}"
|
|
else
|
|
echo -e "${YELLOW}STOPPED${NC}"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
# ============================================================================
|
|
# Main
|
|
# ============================================================================
|
|
|
|
main() {
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-s|--spamassassin)
|
|
ENABLE_SPAMASSASSIN=true
|
|
shift
|
|
;;
|
|
-t|--tls)
|
|
ENABLE_TLS=true
|
|
shift
|
|
;;
|
|
-a|--all)
|
|
ENABLE_SPAMASSASSIN=true
|
|
ENABLE_TLS=true
|
|
shift
|
|
;;
|
|
-n|--dry-run)
|
|
DRY_RUN=true
|
|
shift
|
|
;;
|
|
-f|--force)
|
|
FORCE=true
|
|
shift
|
|
;;
|
|
-v|--verbose)
|
|
VERBOSE=true
|
|
shift
|
|
;;
|
|
--no-backup)
|
|
BACKUP=false
|
|
shift
|
|
;;
|
|
--status)
|
|
STATUS_ONLY=true
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
;;
|
|
--version)
|
|
version
|
|
;;
|
|
*)
|
|
log_error "Unknown option: $1"
|
|
echo "Use --help for usage information"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Default to both if neither specified
|
|
if ! $ENABLE_SPAMASSASSIN && ! $ENABLE_TLS; then
|
|
ENABLE_SPAMASSASSIN=true
|
|
ENABLE_TLS=true
|
|
fi
|
|
|
|
# Check root (skip for dry-run or status-only)
|
|
if ! $DRY_RUN && ! $STATUS_ONLY; then
|
|
check_root
|
|
fi
|
|
|
|
check_miab
|
|
|
|
# Show current status
|
|
show_status
|
|
|
|
# Exit if status-only mode
|
|
if $STATUS_ONLY; then
|
|
exit 0
|
|
fi
|
|
|
|
# Build action summary
|
|
local actions=""
|
|
if $ENABLE_SPAMASSASSIN; then
|
|
actions+="SpamAssassin rules logging"
|
|
fi
|
|
if $ENABLE_TLS; then
|
|
[[ -n "$actions" ]] && actions+=", "
|
|
actions+="TLS cipher logging"
|
|
fi
|
|
|
|
if $DRY_RUN; then
|
|
log_info "DRY RUN - showing changes that would be made for: $actions"
|
|
echo ""
|
|
else
|
|
if ! confirm_action "Enable $actions?"; then
|
|
log_info "Aborted"
|
|
exit 0
|
|
fi
|
|
echo ""
|
|
fi
|
|
|
|
local exit_code=0
|
|
|
|
if $ENABLE_SPAMASSASSIN; then
|
|
if ! configure_spamassassin; then
|
|
exit_code=1
|
|
fi
|
|
echo ""
|
|
fi
|
|
|
|
if $ENABLE_TLS; then
|
|
if ! configure_tls; then
|
|
exit_code=1
|
|
fi
|
|
echo ""
|
|
fi
|
|
|
|
if [[ $exit_code -eq 0 ]]; then
|
|
if $DRY_RUN; then
|
|
log_info "Dry run complete - no changes made"
|
|
else
|
|
log_ok "Configuration complete!"
|
|
echo ""
|
|
echo "Metrics should now be available after some mail traffic."
|
|
echo "Run your postfix-metrics.sh script to verify."
|
|
fi
|
|
else
|
|
log_error "Some configurations failed"
|
|
fi
|
|
|
|
exit $exit_code
|
|
}
|
|
|
|
main "$@"
|