auspex/main.go
2026-08-26 12:58:09 +03:00

290 lines
No EOL
12 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"bufio"
"fmt"
"os"
"strings"
)
const appVersion = "1.5.0"
// Цвета терминала (общие для всех модулей)
const (
cReset = "\033[0m"
cRed = "\033[0;31m"
cGreen = "\033[0;32m"
cYellow = "\033[1;33m"
cBlue = "\033[0;34m"
cCyan = "\033[0;36m"
)
func main() {
// Загружаем конфигурацию из /etc/auspex/auspex.env
if err := loadConfig(); err != nil {
// Файл не найден - выводим предупреждение
fmt.Printf("⚠️ %v\n", err)
fmt.Println("⚠️ Используются значения по умолчанию")
fmt.Printf("💡 Создайте файл конфигурации: sudo mkdir -p /etc/auspex && sudo nano /etc/auspex/auspex.env\n\n")
}
// Если переданы аргументы — быстрый вызов
if len(os.Args) > 1 {
runByFlag(os.Args[1], os.Args[2:])
return
}
// Интерактивное меню
showMenu()
}
func runByFlag(flag string, extraArgs []string) {
switch flag {
case "-ss":
fmt.Printf("%s⚡ Auspex — Просмотр занятых портов (TUI)%s\n\n", cCyan, cReset)
if err := runPortsView(); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-c":
fmt.Printf("%s🔐 Auspex — Проверка SSL сертификатов%s\n\n", cCyan, cReset)
if err := runCertCheck(); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-p":
fmt.Printf("%s🌐 Auspex — Проверка доступности портов%s\n\n", cCyan, cReset)
if err := runPortCheck(); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-m":
fmt.Printf("%s🔄 Auspex — Проверка совпадений Angie ↔ Docker%s\n\n", cCyan, cReset)
clientFilter := ""
if len(extraArgs) > 0 {
clientFilter = extraArgs[0]
}
if err := runMatchCheck(clientFilter); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-l":
fmt.Printf("%s📝 Auspex — Проверка активности логов%s\n\n", cCyan, cReset)
if err := runLogCheck(); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-sv":
fmt.Printf("%s🔧 Auspex — Проверка состояния служб%s\n\n", cCyan, cReset)
if err := runServiceCheck(); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-dc", "-d":
fmt.Printf("%s🐳 Auspex — Проверка контейнеров Docker%s\n\n", cCyan, cReset)
if err := runDockerCheck(); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-w":
fmt.Printf("%s🌍 Auspex — Проверка доступности сайтов (lynx)%s\n\n", cCyan, cReset)
sid := ""
if len(extraArgs) > 0 {
sid = extraArgs[0]
}
if err := runWebCheck(sid); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-fd":
fmt.Printf("%s🗑 Auspex — Удалённые-но-открытые файловые дескрипторы%s\n\n", cCyan, cReset)
if err := runFDCheck(); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-dt":
if err := runDockerTUI(); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-fw":
if err := runFirewallTUI(); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-au":
category := ""
if len(extraArgs) > 0 {
category = extraArgs[0]
}
if err := runAudit(category); err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
case "-v", "--version":
fmt.Printf("auspex v%s (%s)\n", appVersion, buildVariant)
case "-h", "--help":
printUsage()
default:
fmt.Fprintf(os.Stderr, "%sНеизвестный флаг: %s%s\n\n", cRed, flag, cReset)
printUsage()
os.Exit(1)
}
}
func showMenu() {
printBanner()
reader := bufio.NewReader(os.Stdin)
for {
printMenuOptions()
fmt.Printf("%s>>> %s", cGreen, cReset)
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(input)
switch input {
case "1", "-ss", "ss":
if err := runPortsView(); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "2", "-c", "c":
if err := runCertCheck(); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "3", "-p", "p":
if err := runPortCheck(); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "4", "-m", "m":
fmt.Printf(" Имя клиента (Enter = все): ")
clientInput, _ := reader.ReadString('\n')
clientInput = strings.TrimSpace(clientInput)
if err := runMatchCheck(clientInput); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "5", "-l", "l":
if err := runLogCheck(); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "6", "-sv", "sv":
if err := runServiceCheck(); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "7", "-dc", "-d", "dc", "d":
if err := runDockerCheck(); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "8", "-w", "w":
fmt.Printf(" SID: ")
sidInput, _ := reader.ReadString('\n')
sidInput = strings.TrimSpace(sidInput)
if err := runWebCheck(sidInput); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "9", "-fd", "fd":
if err := runFDCheck(); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "10", "-dt", "dt":
if err := runDockerTUI(); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "11", "-fw", "fw":
if err := runFirewallTUI(); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "12", "-au", "au":
fmt.Printf(" Категория (Enter = все: systemd/nginx/docker/cert/disk/network/firewall): ")
catInput, _ := reader.ReadString('\n')
catInput = strings.TrimSpace(catInput)
if err := runAudit(catInput); err != nil {
fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset)
}
case "0", "q", "quit", "exit":
fmt.Println("Выход.")
return
default:
fmt.Printf("%sНеизвестная команда. Введите 1-11 или 0 для выхода.%s\n", cRed, cReset)
}
fmt.Println() // разделитель перед повторным показом меню
}
}
// printMenuOptions выводит нумерованный список утилит и подсказку по флагам.
// Вызывается заново после каждого действия — успешного или с ошибкой,
// программа не завершается, а возвращается к выбору.
func printMenuOptions() {
fmt.Printf("%sВыберите утилиту:%s\n\n", cBlue, cReset)
fmt.Printf(" %s1%s) %s-ss%s Просмотр занятых портов (TUI интерфейс)\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s2%s) %s-c %s Проверка SSL сертификатов\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s3%s) %s-p %s Проверка доступности портов (nginx upstream) [WAF]\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s4%s) %s-m %s Проверка совпадений портов Angie ↔ Docker [WAF]\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s5%s) %s-l %s Проверка активности логов (PostgreSQL) [WAF]\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s6%s) %s-sv%s Проверка состояния служб (systemd)\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s7%s) %s-dc%s Проверка контейнеров Docker\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s8%s) %s-w %s Проверка доступности сайтов (lynx) [sid] [WAF]\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s9%s) %s-fd%s Удалённые-но-открытые файловые дескрипторы\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s10%s) %s-dt%s Docker Live — TUI (аналог lazydocker)\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s11%s) %s-fw%s Firewall — TUI (ufw/nftables/iptables)\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s12%s) %s-au%s Audit — комплексная диагностика [категория]\n", cGreen, cReset, cCyan, cReset)
fmt.Printf(" %s0%s) Выход\n\n", cGreen, cReset)
fmt.Printf("%sДля быстрого вызова: auspex <ключ>%s\n", cYellow, cReset)
fmt.Printf("%sПример: auspex -ss | auspex -c | auspex -p | auspex -m [клиент] | auspex -l | auspex -sv | auspex -dc | auspex -w <sid>%s\n\n", cYellow, cReset)
}
func printBanner() {
fmt.Printf(`%s
█████╗ ██╗ ██╗███████╗██████╗ ███████╗██╗ ██╗
██╔══██╗██║ ██║██╔════╝██╔══██╗██╔════╝╚██╗██╔╝
███████║██║ ██║███████╗██████╔╝█████╗ ╚███╔╝
██╔══██║██║ ██║╚════██║██╔═══╝ ██╔══╝ ██╔██╗
██║ ██║╚██████╔╝███████║██║ ███████╗██╔╝ ██╗
╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚══════╝╚═╝ ╚═╝
%s`, cCyan, cReset)
fmt.Printf(" %sv%s%s — набор утилит мониторинга инфраструктуры\n", cBlue, appVersion, cReset)
if buildHasWAF {
fmt.Printf(" %sСборка: full (включает WAF-модули -p, -l, -m, -w)%s\n\n", cYellow, cReset)
} else {
fmt.Printf(" %sСборка: generic (без WAF-модулей -p, -l, -m, -w — см. -h)%s\n\n", cYellow, cReset)
}
}
func printUsage() {
fmt.Printf("Использование: auspex [флаг] [аргументы]\n\n")
fmt.Printf("Флаги:\n")
fmt.Printf(" %-12s Просмотр занятых портов (интерактивный TUI)\n", "-ss")
fmt.Printf(" %-12s Проверка SSL сертификатов в %s\n", "-c", cfgSSLDir)
fmt.Printf(" %-12s Проверка доступности портов (nginx upstream) [WAF]\n", "-p")
fmt.Printf(" %-12s Проверка совпадений портов Angie ↔ Docker [имя_клиента] [WAF]\n", "-m")
fmt.Printf(" %-12s Проверка активности логов (PostgreSQL) [WAF]\n", "-l")
fmt.Printf(" %-12s Проверка состояния служб systemd\n", "-sv")
fmt.Printf(" %-12s Проверка контейнеров Docker\n", "-dc")
fmt.Printf(" %-12s Проверка доступности сайтов через lynx [sid] [WAF]\n", "-w")
fmt.Printf(" %-12s Удалённые-но-открытые файловые дескрипторы (recover/reopen/restart/kill)\n", "-fd")
fmt.Printf(" %-12s Docker Live — интерактивный TUI (аналог lazydocker)\n", "-dt")
fmt.Printf(" %-12s Firewall — интерактивный TUI (ufw/nftables/iptables, dry-run 'D')\n", "-fw")
fmt.Printf(" %-12s Комплексный аудит-скан по категориям [категория] (read-only)\n", "-au")
fmt.Printf(" %-12s Показать версию\n", "-v")
fmt.Printf(" %-12s Показать эту справку\n\n", "-h")
fmt.Printf("Без аргументов запускается интерактивное меню.\n")
if !buildHasWAF {
fmt.Printf("\n%s⚠ Эта сборка (generic) не включает модули [WAF] (-p, -m, -l, -w) —\n"+
" они требуют БД waf_info / структуры PT AF. Соберите с 'go build -tags waf .',\n"+
" чтобы получить полную (full) сборку.%s\n", cYellow, cReset)
}
}