checkms.sh first commit
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
#!/usr/bin/env bash
|
||||
# checkms - Analyse von MS-Fehlercodes im Exim-Log + Code-Management
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# --- Defaults ---
|
||||
DATE="$(date +%Y-%m-%d)"
|
||||
MINUTES=0
|
||||
HOURS=0
|
||||
CONF_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/checkms"
|
||||
ADD_CODES=()
|
||||
DEL_INDEXES=()
|
||||
SET_USER=""
|
||||
SHOW_CONF=0
|
||||
|
||||
# --- Funktionen ---
|
||||
usage() {
|
||||
cat <<USAGE
|
||||
Usage: $0 [OPTIONS] [YYYY-MM-DD]
|
||||
|
||||
Analyse von MS-Fehlercodes im Exim-Log und Pflege der Codes.
|
||||
|
||||
Analyse-Optionen:
|
||||
--minutes N Analysiert nur die letzten N Minuten
|
||||
--hours N Analysiert nur die letzten N Stunden
|
||||
--confdir PATH Pfad zum Konfigurationsordner (Default: ~/.config/checkms)
|
||||
|
||||
Konfig-Optionen:
|
||||
--add-code REGEX Fügt einen Code/Regex zur Config hinzu (mehrfach möglich)
|
||||
--del-code ID Löscht Code mit ID (siehe --show-config)
|
||||
--set-user USER Setzt den SSH-User in der Config
|
||||
--show-config Zeigt die aktuelle Config (JSON + tabellarisch) und beendet
|
||||
--help Diese Hilfe
|
||||
USAGE
|
||||
}
|
||||
|
||||
init_conf() {
|
||||
mkdir -p "$CONF_DIR"
|
||||
read -rp "Bitte SSH-User für den Logger angeben: " SSHUSER
|
||||
cat >"$CONF_FILE" <<JSON
|
||||
{
|
||||
"ssh_user": "$SSHUSER",
|
||||
"codes": [
|
||||
"S3150",
|
||||
"S775",
|
||||
"S7771[0-9]*"
|
||||
]
|
||||
}
|
||||
JSON
|
||||
echo "Konfigurationsdatei erstellt: $CONF_FILE"
|
||||
}
|
||||
|
||||
require_jq_write() {
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "Fehler: Für --add-code/--del-code/--set-user wird 'jq' benötigt." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
show_config() {
|
||||
if [[ ! -f "$CONF_FILE" ]]; then
|
||||
echo "Keine Config vorhanden. Sie wird beim nächsten Run erstellt."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Roh-JSON
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
echo "RAW ($CONF_FILE):"
|
||||
jq . "$CONF_FILE"
|
||||
else
|
||||
echo "RAW ($CONF_FILE):"
|
||||
cat "$CONF_FILE"
|
||||
fi
|
||||
echo
|
||||
|
||||
# Tabellarisch
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
SSH_USER_SHOW="$(jq -r '.ssh_user' "$CONF_FILE")"
|
||||
mapfile -t CODES_SHOW < <(jq -r '.codes[]' "$CONF_FILE")
|
||||
else
|
||||
SSH_USER_SHOW="$(grep -o '"ssh_user":[^,}]*' "$CONF_FILE" | cut -d'"' -f4)"
|
||||
CODES_LINE="$(sed -n 's/.*"codes":[[]\(.*\)[]].*/\1/p' "$CONF_FILE")"
|
||||
IFS=',' read -r -a CODES_SHOW <<<"$(echo "$CODES_LINE" | tr -d ' \t"')"
|
||||
fi
|
||||
|
||||
echo "TABELLARISCHE ANSICHT:"
|
||||
printf "%-12s %s\n" "SSH_USER" "${SSH_USER_SHOW:-<unset>}"
|
||||
echo
|
||||
printf "%-6s %s\n" "ID" "CODE"
|
||||
printf "%-6s %s\n" "----" "-----------------------"
|
||||
id=0
|
||||
for code in "${CODES_SHOW[@]}"; do
|
||||
printf "%-6s %s\n" "$id" "$code"
|
||||
id=$((id+1))
|
||||
done
|
||||
exit 0
|
||||
}
|
||||
|
||||
apply_add_codes() {
|
||||
[[ ${#ADD_CODES[@]} -eq 0 ]] && return 0
|
||||
require_jq_write
|
||||
local tmp; tmp="$(mktemp)"
|
||||
cp "$CONF_FILE" "$tmp"
|
||||
for code in "${ADD_CODES[@]}"; do
|
||||
jq --arg code "$code" '
|
||||
(.codes | any(. == $code)) as $exists
|
||||
| if $exists then . else (.codes += [$code]) end
|
||||
' "$tmp" > "${tmp}.new"
|
||||
mv "${tmp}.new" "$tmp"
|
||||
done
|
||||
mv "$tmp" "$CONF_FILE"
|
||||
}
|
||||
|
||||
apply_del_indexes() {
|
||||
[[ ${#DEL_INDEXES[@]} -eq 0 ]] && return 0
|
||||
require_jq_write
|
||||
local tmp; tmp="$(mktemp)"
|
||||
cp "$CONF_FILE" "$tmp"
|
||||
IFS=$'\n' read -r -d '' -a sorted <<<"$(printf "%s\n" "${DEL_INDEXES[@]}" | sort -rn; printf '\0')"
|
||||
for idx in "${sorted[@]}"; do
|
||||
[[ "$idx" =~ ^[0-9]+$ ]] || { echo "Warnung: ungültige ID '$idx'"; continue; }
|
||||
jq --argjson i "$idx" '
|
||||
if ($i >= 0 and $i < (.codes|length))
|
||||
then .codes |= del(.[$i])
|
||||
else .
|
||||
end
|
||||
' "$tmp" > "${tmp}.new"
|
||||
mv "${tmp}.new" "$tmp"
|
||||
done
|
||||
mv "$tmp" "$CONF_FILE"
|
||||
}
|
||||
|
||||
apply_set_user() {
|
||||
[[ -z "$SET_USER" ]] && return 0
|
||||
require_jq_write
|
||||
local tmp; tmp="$(mktemp)"
|
||||
jq --arg u "$SET_USER" '.ssh_user = $u' "$CONF_FILE" > "$tmp"
|
||||
mv "$tmp" "$CONF_FILE"
|
||||
}
|
||||
|
||||
# --- Argumente parsen ---
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--minutes) MINUTES="$2"; shift 2 ;;
|
||||
--hours) HOURS="$2"; shift 2 ;;
|
||||
--confdir) CONF_DIR="$2"; shift 2 ;;
|
||||
--show-config) SHOW_CONF=1; shift ;;
|
||||
--add-code) ADD_CODES+=("$2"); shift 2 ;;
|
||||
--del-code) DEL_INDEXES+=("$2"); shift 2 ;;
|
||||
--set-user) SET_USER="$2"; shift 2 ;;
|
||||
--help) usage; exit 0 ;;
|
||||
[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]) DATE="$1"; shift ;;
|
||||
*) echo "Unbekannte Option: $1" >&2; usage; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# --- Configpfade ---
|
||||
CONF_FILE="${CONF_DIR}/checkms.conf"
|
||||
[[ -f "$CONF_FILE" ]] || init_conf
|
||||
|
||||
# --- Reine Konfig-Operationen (frühzeitiger Exit!) ---
|
||||
if [[ $SHOW_CONF -eq 1 && ${#ADD_CODES[@]} -eq 0 && ${#DEL_INDEXES[@]} -eq 0 && -z "$SET_USER" ]]; then
|
||||
show_config
|
||||
fi
|
||||
|
||||
# Wenn Codes/User geändert werden sollen, erst anwenden …
|
||||
if [[ ${#ADD_CODES[@]} -gt 0 || ${#DEL_INDEXES[@]} -gt 0 || -n "$SET_USER" ]]; then
|
||||
apply_add_codes
|
||||
apply_del_indexes
|
||||
apply_set_user
|
||||
# Wenn nur Konfig bearbeitet wurde (keine Analyse-Flags/Datum), hier enden
|
||||
if [[ $MINUTES -eq 0 && $HOURS -eq 0 && "$DATE" == "$(date +%Y-%m-%d)" ]]; then
|
||||
# Optional: danach anzeigen
|
||||
[[ $SHOW_CONF -eq 1 ]] && show_config
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Config laden für Analyse ---
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
SSH_USER="$(jq -r '.ssh_user' "$CONF_FILE")"
|
||||
CODES_REGEX="$(jq -r '.codes[]' "$CONF_FILE" | paste -sd'|' -)"
|
||||
else
|
||||
SSH_USER="$(grep -o '"ssh_user":[^,}]*' "$CONF_FILE" | cut -d'"' -f4)"
|
||||
CODES_REGEX="$(
|
||||
sed -n 's/.*"codes":[[]\(.*\)[]].*/\1/p' "$CONF_FILE" \
|
||||
| tr -d ' \t"' | tr ',' '|'
|
||||
)"
|
||||
fi
|
||||
[[ -n "${CODES_REGEX// }" ]] || CODES_REGEX="S3150|S775|S7771[0-9]*"
|
||||
|
||||
LOGFILE="${DATE}.log"
|
||||
|
||||
# --- Remote-Kommando ---
|
||||
if type go >/dev/null 2>&1; then
|
||||
REMOTE="go logger"
|
||||
else
|
||||
REMOTE="ssh ${SSH_USER}@logger.in.nessus.at"
|
||||
fi
|
||||
|
||||
# --- Analyse (remote) ---
|
||||
$REMOTE bash -s <<EOF
|
||||
set -euo pipefail
|
||||
cd /var/log/easyname/\$(date +%Y/%m)
|
||||
|
||||
if [ -f "$LOGFILE" ]; then SRC="cat \"$LOGFILE\""
|
||||
elif [ -f "$LOGFILE.gz" ]; then SRC="zcat \"$LOGFILE.gz\""
|
||||
else
|
||||
echo "Logfile $LOGFILE(.gz) nicht gefunden." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Analysiere $LOGFILE"
|
||||
echo
|
||||
printf "%-8s %-16s %-8s\n" "COUNT" "IP" "CODE"
|
||||
printf "%-8s %-16s %-8s\n" "-----" "----------------" "------"
|
||||
|
||||
TF_CMD=""
|
||||
if [ $MINUTES -gt 0 ]; then
|
||||
START_TS=\$(date -d "-$MINUTES minutes" +"%b %_d %H:%M")
|
||||
echo "Zeitraum: letzte $MINUTES Minuten (ab \$START_TS)"
|
||||
TF_CMD="awk -v ts=\"\$START_TS\" '\$0 ~ ts,0'"
|
||||
elif [ $HOURS -gt 0 ]; then
|
||||
START_TS=\$(date -d "-$HOURS hours" +"%b %_d %H")
|
||||
echo "Zeitraum: letzte $HOURS Stunden (ab \$START_TS)"
|
||||
TF_CMD="awk -v ts=\"\$START_TS\" '\$0 ~ ts,0'"
|
||||
fi
|
||||
|
||||
eval \$SRC \${TF_CMD:+| \$TF_CMD} \
|
||||
| grep -E 'outlook|hotmail' \
|
||||
| grep -E "$CODES_REGEX" \
|
||||
| awk '
|
||||
{
|
||||
code="NA"; ip="NA";
|
||||
for (i=1;i<=NF;i++) {
|
||||
if (\$i ~ /\(S[0-9]+\)/) { t=\$i; gsub(/[()]/,"",t); code=t }
|
||||
else if (\$i ~ /^S[0-9]+/) { code=\$i }
|
||||
if (\$i ~ /^\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\]$/) {
|
||||
ip=\$i; gsub(/[\[\]]/,"",ip)
|
||||
}
|
||||
}
|
||||
print code, ip
|
||||
}
|
||||
' \
|
||||
| sort | uniq -c | sort -nr \
|
||||
| while read count code ip; do
|
||||
printf "%-8s %-16s %-8s\n" "\$count" "\$ip" "\$code"
|
||||
done
|
||||
EOF
|
||||
Reference in New Issue
Block a user