diff --git a/README.fr.md b/README.fr.md index b3d6473..58df5d1 100644 --- a/README.fr.md +++ b/README.fr.md @@ -231,7 +231,10 @@ couleur, est mémorisé par navigateur. Le menu *+ Préréglage…* ajoute des tags tout faits pour les logs d'accès HTTP/HTTPS (nginx et Apache common/combined, Traefik CLF et JSON, Caddy JSON, HAProxy httplog) : codes de statut (2xx vert, 3xx bleu, 4xx orange, 5xx rouge), méthodes, sondes et attaques (`wp-login.php`, - `/.env`, `../`…), robots et scripts, erreurs TLS et proxy. Les tags déjà présents ne sont pas + `/.env`, `../`…), robots et scripts, erreurs TLS et proxy. D'autres préréglages couvrent les + logs système (échecs et succès de connexion SSH, commandes sudo, OOM et erreurs du noyau, + services systemd, UFW/iptables et fail2ban), les applications (conteneurs Docker, erreurs + PostgreSQL et MySQL/MariaDB) et des motifs généraux (niveaux de log, adresses IPv4). Les tags déjà présents ne sont pas ajoutés en double, et les tags ajoutés se modifient comme les autres. Dans une expression régulière, un groupe nommé `hl` (`(?…)`) ne colore que cette partie de la correspondance : les préréglages s'en servent pour colorer le code de statut ou la méthode, pas le texte autour. diff --git a/README.md b/README.md index dcde535..c301b03 100644 --- a/README.md +++ b/README.md @@ -210,7 +210,10 @@ remembered per browser. The *+ Preset…* menu adds ready-made tags for HTTP/HTTPS access logs (nginx and Apache common/combined, Traefik CLF and JSON, Caddy JSON, HAProxy httplog): status codes (2xx green, 3xx blue, 4xx orange, 5xx red), methods, probes and attacks (`wp-login.php`, `/.env`, - `../`…), bots and scripts, TLS and proxy errors. Tags already in the list are skipped, and the + `../`…), bots and scripts, TLS and proxy errors. Other presets cover system logs (SSH and + login failures/successes, sudo commands, kernel OOM and errors, systemd services, UFW/iptables + and fail2ban), applications (Docker containers, PostgreSQL and MySQL/MariaDB errors) and + general patterns (log levels, IPv4 addresses). Tags already in the list are skipped, and the added tags can be edited like any other. In a regular expression, a group named `hl` (`(?…)`) colors only that part of the match: the presets use it to color the status code or the method, not the text around it. diff --git a/web/app.js b/web/app.js index d19762f..08484ca 100644 --- a/web/app.js +++ b/web/app.js @@ -53,6 +53,15 @@ const I18N = { preset_http_probes: 'Probes and attacks', preset_http_bots: 'Bots and scripts', preset_http_errors: 'TLS/HTTPS and proxy errors', pl_probes: 'probes / attacks', pl_bots: 'bots / scripts', pl_tls: 'TLS errors', pl_proxy: 'proxy errors', + presetGroupSys: 'System', presetGroupApps: 'Applications', presetGroupGen: 'General', + preset_sys_auth: 'SSH and logins', preset_sys_sudo: 'sudo commands', preset_sys_kernel: 'Kernel: OOM, crashes, disks', + preset_sys_systemd: 'systemd services', preset_sys_firewall: 'Firewall and fail2ban', + preset_app_docker: 'Docker and containers', preset_app_db: 'Databases', + preset_gen_levels: 'Log levels', preset_gen_ip: 'IPv4 addresses', + pl_authFail: 'login failures', pl_authOk: 'logins', pl_sudo: 'sudo commands', pl_oom: 'out of memory', + pl_kernel: 'kernel errors', pl_unitFail: 'failed services', pl_unitOk: 'service start/stop', + pl_firewall: 'firewall', pl_docker: 'container problems', pl_db: 'database errors', + pl_fatal: 'fatal / critical', pl_info: 'info / notice', pl_debug: 'debug / trace', pl_ip: 'IPv4 addresses', presetAdded: (n) => (n ? `${n} tag(s) added` : 'These tags are already in the list'), tagsLoadErr: 'Tags: ', err_pattern_required: 'The keyword is required', @@ -207,6 +216,15 @@ const I18N = { preset_http_probes: 'Sondes et attaques', preset_http_bots: 'Robots et scripts', preset_http_errors: 'Erreurs TLS/HTTPS et proxy', pl_probes: 'sondes / attaques', pl_bots: 'robots / scripts', pl_tls: 'erreurs TLS', pl_proxy: 'erreurs proxy', + presetGroupSys: 'Système', presetGroupApps: 'Applications', presetGroupGen: 'Général', + preset_sys_auth: 'SSH et connexions', preset_sys_sudo: 'Commandes sudo', preset_sys_kernel: 'Noyau : OOM, plantages, disques', + preset_sys_systemd: 'Services systemd', preset_sys_firewall: 'Pare-feu et fail2ban', + preset_app_docker: 'Docker et conteneurs', preset_app_db: 'Bases de données', + preset_gen_levels: 'Niveaux de log', preset_gen_ip: 'Adresses IPv4', + pl_authFail: 'échecs de connexion', pl_authOk: 'connexions', pl_sudo: 'commandes sudo', pl_oom: 'mémoire épuisée', + pl_kernel: 'erreurs noyau', pl_unitFail: 'services en échec', pl_unitOk: 'démarrage/arrêt de service', + pl_firewall: 'pare-feu', pl_docker: 'problèmes de conteneur', pl_db: 'erreurs base de données', + pl_fatal: 'fatal / critique', pl_info: 'info / notice', pl_debug: 'debug / trace', pl_ip: 'adresses IPv4', presetAdded: (n) => (n ? `${n} tag(s) ajouté(s)` : 'Ces tags sont déjà dans la liste'), tagsLoadErr: 'Tags : ', err_pattern_required: 'Le mot-clé est obligatoire', @@ -479,6 +497,7 @@ function applyLang() { for (const el of document.querySelectorAll('[data-i18n-title]')) el.title = t(el.dataset.i18nTitle) + (el.dataset.user ? ` (${el.dataset.user})` : ''); for (const el of document.querySelectorAll('[data-i18n-aria]')) el.setAttribute('aria-label', t(el.dataset.i18nAria)); for (const el of document.querySelectorAll('[data-i18n-ph]')) el.placeholder = t(el.dataset.i18nPh); + for (const el of document.querySelectorAll('[data-i18n-label]')) el.label = t(el.dataset.i18nLabel); for (const b of document.querySelectorAll('#langSwitch [data-lang]')) b.setAttribute('aria-checked', String(b.dataset.lang === lang)); } @@ -2055,10 +2074,12 @@ $('#purgeBtn').addEventListener('click', async () => { const PALETTE = ['#6366f1', '#0ea5e9', '#14b8a6', '#a855f7', '#ec4899', '#eab308', '#64748b', '#f97316']; -// Ready-made tags for HTTP/HTTPS access logs. The patterns are valid in both -// JavaScript and Go (RE2) and cover nginx/Apache (common, combined), Traefik -// (CLF, JSON), Caddy (JSON) and HAProxy (httplog). For status codes and -// methods only the "hl" group is colored, not the context around it. +// Ready-made tags. The patterns are valid in both JavaScript and Go (RE2). +// The HTTP ones cover nginx/Apache (common, combined), Traefik (CLF, JSON), +// Caddy (JSON) and HAProxy (httplog); for status codes and methods only the +// "hl" group is colored, not the context around it. The others target the +// usual messages of sshd/PAM, sudo, the kernel, systemd, UFW/iptables, +// fail2ban, Docker, PostgreSQL and MySQL/MariaDB. const HTTP_STATUS_CTX = '(?:" |"(?:status|DownstreamStatus|OriginStatus|status_code)": ?|(?:-1|\\d+)/(?:-1|\\d+)/(?:-1|\\d+)/(?:-1|\\d+)/\\+?\\d+ )'; const httpStatus = (d, color) => ({ label: `HTTP ${d}xx`, pattern: `${HTTP_STATUS_CTX}(?${d}\\d\\d)\\b`, color }); const httpMethod = (m, color) => ({ label: m.replace(/\|/g, '/'), pattern: `"(?${m})[ "]`, color, caseSensitive: true }); @@ -2075,6 +2096,38 @@ const PRESETS = { { label: t('pl_proxy'), color: '#fdba74', pattern: '(?:upstream timed out|upstream prematurely closed|no live upstreams|connect\\(\\) failed|connection refused|bad gateway|gateway time-?out|service unavailable)' }, ], + sys_auth: () => [ + { label: t('pl_authFail'), color: '#fca5a5', + pattern: '(?:Failed (?:password|publickey|none)|Invalid user|authentication failures?|Connection closed by (?:invalid|authenticating) user|maximum authentication attempts exceeded|FAILED (?:LOGIN|SU)|incorrect password attempts?|NOT in sudoers)' }, + { label: t('pl_authOk'), color: '#86efac', + pattern: '(?:Accepted (?:password|publickey|keyboard-interactive(?:/pam)?)|session opened for user|New session \\S+ of user)' }, + ], + sys_sudo: () => [{ label: t('pl_sudo'), color: '#fde68a', pattern: '\\bCOMMAND=\\S+', caseSensitive: true }], + sys_kernel: () => [ + { label: t('pl_oom'), color: '#f87171', + pattern: '(?:Out of memory|oom-kill(?:er)?|oom_reaper|Killed process \\d+|invoked oom-killer)' }, + { label: t('pl_kernel'), color: '#fda4af', + pattern: '(?:Kernel panic|\\bBUG: |\\bOops\\b|Call Trace|segfault at|general protection fault|I/O error|EXT4-fs error|Buffer I/O error|blocked for more than \\d+ seconds|Hardware Error|soft lockup|hard LOCKUP)' }, + ], + sys_systemd: () => [ + { label: t('pl_unitFail'), color: '#fca5a5', + pattern: '(?:Failed to start|failed with result|Main process exited, code=(?:exited|killed|dumped)|entered failed state|Start request repeated too quickly|Dependency failed)' }, + { label: t('pl_unitOk'), color: '#bbf7d0', caseSensitive: true, + pattern: '\\b(?:Started|Starting|Stopped|Stopping|Reloaded|Reloading|Reached target)\\b' }, + ], + sys_firewall: () => [{ label: t('pl_firewall'), color: '#fdba74', caseSensitive: true, + pattern: '(?:\\[UFW (?:BLOCK|ALLOW|AUDIT|LIMIT BLOCK)\\]|\\b(?:DROP|REJECT)\\b|\\b(?:Ban|Unban|Found) \\d{1,3}(?:\\.\\d{1,3}){3}\\b)' }], + app_docker: () => [{ label: t('pl_docker'), color: '#fcd34d', + pattern: '(?:\\bOOMKilled\\b|exited with code [1-9]\\d*|exit code: [1-9]\\d*|health_status: unhealthy|\\bunhealthy\\b|Back-off restarting|CrashLoopBackOff|container (?:die|kill|oom)\\b|restarting \\(\\d+\\))' }], + app_db: () => [{ label: t('pl_db'), color: '#c4b5fd', + pattern: '(?:\\bdeadlock(?: detected| found)?\\b|duplicate key|too many (?:connections|clients)|lock wait timeout|slow query|could not connect to server|server has gone away|out of shared memory|terminating connection|Access denied for user|password authentication failed)' }], + gen_levels: () => [ + { label: t('pl_fatal'), color: '#ef4444', pattern: '\\b(?:fatal|crit(?:ical)?|panic|emerg(?:ency)?)\\b' }, + { label: t('pl_info'), color: '#bfdbfe', pattern: '\\b(?:info|notice)\\b' }, + { label: t('pl_debug'), color: '#e5e7eb', pattern: '\\b(?:debug|trace)\\b' }, + ], + gen_ip: () => [{ label: t('pl_ip'), color: '#a5f3fc', + pattern: '\\b(?:(?:25[0-5]|2[0-4]\\d|1?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1?\\d?\\d)\\b' }], }; async function loadTags() { diff --git a/web/index.html b/web/index.html index f4b0ed4..6e542ea 100644 --- a/web/index.html +++ b/web/index.html @@ -193,11 +193,28 @@