Skip to content
Merged

sync #1792

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e0b8abc
Merge pull request #1770 from netalertx/next_release
jokob-sk Sep 1, 2026
a686a01
Merge pull request #1771 from netalertx/next_release
jokob-sk Sep 1, 2026
6916b06
Translated using Weblate (Russian)
YoSafeguard Sep 3, 2026
dced246
fix(front): make notifications page span full width
HsukqiLee Sep 4, 2026
b934e01
Merge pull request #1777 from TsinbeiLabs/fix/notifications-full-width
jokob-sk Sep 4, 2026
aad6d24
Merge pull request #1776 from netalertx/next_release
jokob-sk Sep 6, 2026
4005147
Merge pull request #1778 from netalertx/next_release
jokob-sk Sep 7, 2026
dc83732
Merge pull request #1779 from netalertx/next_release
jokob-sk Sep 9, 2026
8022546
Merge pull request #1781 from netalertx/next_release
jokob-sk Sep 10, 2026
a23c650
Merge pull request #1782 from netalertx/next_release
jokob-sk Sep 10, 2026
f3620ab
Merge pull request #1783 from netalertx/next_release
jokob-sk Sep 11, 2026
d02e40c
Merge pull request #1785 from netalertx/next_release
jokob-sk Sep 14, 2026
9946519
Merge pull request #1786 from netalertx/next_release
jokob-sk Sep 14, 2026
1b52017
Merge pull request #1787 from netalertx/next_release
jokob-sk Sep 14, 2026
c86d02a
Translated using Weblate (Italian)
mapi68 Sep 14, 2026
d44e9d7
Merge branch 'origin/main' into Weblate.
weblate Sep 14, 2026
94a5cd4
Add DOCKERDISC plugin: enrich existing devices with their Docker cont…
mauricio-camayo Sep 14, 2026
6a26804
Address CodeRabbit review: request timeout budget, shape validation, …
mauricio-camayo Sep 14, 2026
0794bb8
Merge pull request #1790 from netalertx/next_release
jokob-sk Sep 14, 2026
fbc9fce
Refactor config import logic for legacy column references
agueybanapr Sep 15, 2026
3b83d24
Address jokob-sk review: DeviceInstance instead of raw SQL, drop HTML…
mauricio-camayo Sep 15, 2026
776b462
Merge remote-tracking branch 'upstream/main' into add-dockerdisc-plugin
mauricio-camayo Sep 15, 2026
b0d1776
Trim module docstring: drop design-history attribution and verificati…
mauricio-camayo Sep 15, 2026
d512e5d
Add regression test for lookup_device_mac() case handling
mauricio-camayo Sep 15, 2026
091e648
Fix DOCKERDISC_HOST_MAC docs and strengthen case-insensitivity test
mauricio-camayo Sep 15, 2026
726ca7b
Translated using Weblate (French)
GitSpoon Sep 14, 2026
fce1c00
Merge pull request #1788 from mauricio-camayo/add-dockerdisc-plugin
jokob-sk Sep 15, 2026
014b960
Merge pull request #1791 from agueybanapr/patch-1
jokob-sk Sep 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions front/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,14 @@ height: 50px;
display: flex;
}

/* The wrapper above is a flex container, so the content section shrinks to
its content width unless stretched; make it span the full page like the
other Monitoring pages (#1762). */
#notifications .content
{
width: 100%;
}

#notificationData
{
margin-bottom: 10px;
Expand Down
6 changes: 3 additions & 3 deletions front/php/templates/language/fr_fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -351,12 +351,12 @@
"Gen_LockedDB": "Erreur - La base de données est peut-être verrouillée - Vérifier avec les outils de dév via F12 -> Console ou essayer plus tard.",
"Gen_NetworkMask": "Masque réseau",
"Gen_New": "Nouveau",
"Gen_Next": "",
"Gen_Next": "Suivant",
"Gen_No_Data": "Aucune donnée",
"Gen_Offline": "Hors ligne",
"Gen_Okay": "OK",
"Gen_Online": "En ligne",
"Gen_Prev": "",
"Gen_Prev": "Précédent",
"Gen_Purge": "Purger",
"Gen_ReadDocs": "Plus d'infos dans la documentation.",
"Gen_Remove_All": "Enlever tous",
Expand Down Expand Up @@ -837,4 +837,4 @@
"settings_system_label": "Système",
"settings_update_item_warning": "Mettre à jour la valeur ci-dessous. Veillez à bien suivre le même format qu'auparavant. <b>Il n'y a pas de pas de contrôle.</b>",
"test_event_tooltip": "Enregistrer d'abord vos modifications avant de tester vôtre paramétrage."
}
}
6 changes: 4 additions & 2 deletions front/php/templates/language/it_it.json
Original file line number Diff line number Diff line change
Expand Up @@ -836,5 +836,7 @@
"settings_system_icon": "fa-solid fa-gear",
"settings_system_label": "Sistema",
"settings_update_item_warning": "Aggiorna il valore qui sotto. Fai attenzione a seguire il formato precedente. <b>La convalida non viene eseguita.</b>",
"test_event_tooltip": "Salva le modifiche prima di provare le nuove impostazioni."
}
"test_event_tooltip": "Salva le modifiche prima di provare le nuove impostazioni.",
"Gen_Next": "Successivo",
"Gen_Prev": "Precedente"
}
12 changes: 6 additions & 6 deletions front/php/templates/language/ru_ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@
"Device_Shortcut_OnlineChart": "Присутствие устройств",
"Device_Shortcut_Unstable": "Нестабильный",
"Device_TableHead_AlertDown": "Оповещение о сост. ВЫКЛ",
"Device_TableHead_Comments": "",
"Device_TableHead_Comments": "Комментарии",
"Device_TableHead_Connected_Devices": "Соединения",
"Device_TableHead_CustomProps": "Свойства / Действия",
"Device_TableHead_FQDN": "FQDN",
Expand Down Expand Up @@ -389,8 +389,8 @@
"HRS_TO_KEEP_NEWDEV_name": "Удалить новые устройства после",
"HRS_TO_KEEP_OFFDEV_description": "Это настройка обслуживания <b>УДАЛЕНИЕ устройств</b>. Если этот параметр включен (<code>0</code> отключен), устройства, которые находятся <b>в Offline</b> и их дата и время <b>последнего подключения</b> старше, чем часы, указанные в этом параметре. Используйте этот параметр, если вы хотите автоматически удалять <b>Offline устройства</b> после <code>X</code> часов отсутствия в сети.",
"HRS_TO_KEEP_OFFDEV_name": "Удалить устройства Offline после",
"Header_PauseScans_Tooltip": "",
"Header_ResumeScans_Tooltip": "",
"Header_PauseScans_Tooltip": "Приостанавить автоматическое сканирование",
"Header_ResumeScans_Tooltip": "Возобновить автоматическое сканирование",
"LOADED_PLUGINS_description": "Какие плагины загружать. Добавление плагинов может замедлить работу приложения. Подробнее о том, какие плагины необходимо включить, их типах или параметрах сканирования, читайте в <a target=\"_blank\" href=\"https://docs.netalertx.com/PLUGINS \">Документация по плагинам</a>. Выгруженные плагины потеряют ваши настройки. Можно выгрузить только <code>отключенные</code> плагины.",
"LOADED_PLUGINS_name": "Загруженные плагины",
"LOG_LEVEL_description": "Этот параметр включит более подробное ведение журнала. Полезно для отладки записи событий в базу данных.",
Expand Down Expand Up @@ -649,8 +649,8 @@
"SCAN_SUBNETS_description": "Большинство сетевых сканеров (ARP-SCAN, NMAP, NSLOOKUP, DIG) полагаются на сканирование определенных сетевых интерфейсов и подсетей. Дополнительную информацию по этому параметру можно найти в <a href=\"https://docs.netalertx.com/SUBNETS\" target=\"_blank\">документации по подсетям</a>, особенно VLAN, какие VLAN поддерживаются или как разобраться в маске сети и своем интерфейсе. <br/> <br/> Альтернативой сетевым сканерам является включение некоторых других сканеров/импортеров устройств, которые не полагаются на NetAlert<sup>X</sup>, имеющий доступ к сети (UNIFI, dhcp.leases , PiHole и др.). <br/> <br/> Примечание. Само время сканирования зависит от количества проверяемых IP-адресов, поэтому тщательно настройте его, указав соответствующую маску сети и интерфейс.",
"SCAN_SUBNETS_name": "Сети для сканирования",
"SYSTEM_TITLE": "Системная информация",
"Scans_Paused": "",
"Scans_Resumed": "",
"Scans_Paused": "Сканирование остановлено",
"Scans_Resumed": "Сканирование возобновило",
"Setting_Override": "Переопределить значение",
"Setting_Override_Description": "Включение этой опции приведет к переопределению значения по умолчанию, предоставленного приложением, на значение, указанное выше.",
"Settings_Metadata_Toggle": "Показать/скрыть метаданные для данного параметра.",
Expand Down Expand Up @@ -837,4 +837,4 @@
"settings_system_label": "Система",
"settings_update_item_warning": "Обновить значение ниже. Будьте осторожны, следуя предыдущему формату. <b>Проверка не выполняется.</b>",
"test_event_tooltip": "Сначала сохраните изменения, прежде чем проверять настройки."
}
}
10 changes: 5 additions & 5 deletions server/initialise.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,17 +230,14 @@ def importConfigs(pm, db, all_plugins):
# get config file name
config_file = Path(fullConfPath)

# Only import file if the file was modifed since last import.
# Only import file if the file was modified since last import.
# this avoids time zone issues as we just compare the previous timestamp to the current time stamp

# rename settings that have changed names due to code cleanup and migration to plugins
# renameSettings(config_file)

# rename legacy DB column references in user config values (e.g. templates, WATCH lists)
renameColumnReferences(config_file)

fileModifiedTime = os.path.getmtime(config_file)

mylog("debug", ["[Import Config] checking config file "])
mylog("debug", ["[Import Config] lastImportedConfFile :", conf.lastImportedConfFile],)
mylog("debug", ["[Import Config] fileModifiedTime :", fileModifiedTime])
Expand All @@ -249,6 +246,9 @@ def importConfigs(pm, db, all_plugins):
mylog("debug", ["[Import Config] skipping config file import"])
return pm, all_plugins, False

# rename legacy column references only when the config file actually changed
renameColumnReferences(config_file)

# Header
updateState("Import config", showSpinner=True)

Expand Down
189 changes: 189 additions & 0 deletions server/plugins/dockerdisc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
## Overview

`DOCKERDISC` enriches Docker **hosts** NetAlertX already knows about with
the list of containers running on them - image, Compose project/service,
network driver, and (for containers on a `macvlan`/`ipvlan` network) their
own MAC/IP.

It does **not** discover devices. NetAlertX's own ARP/Nmap scanners remain
the only source of device presence. `DOCKERDISC` never creates a device row
- not for a container, and not for the Docker host itself, which must
already exist in NetAlertX before this plugin can attach anything to it.

Maintainer's mental model for this plugin: **Device = Docker host → List of
containers.** Every container found on a host shows up under that **host's
own** Device Details → Plugins → DOCKERDISC tab, not as a device of its
own.

> [!TIP]
> Connects via a read-only [Docker Socket
> Proxy](https://github.com/Tecnativa/docker-socket-proxy) (e.g.
> `tecnativa/docker-socket-proxy`) - never mounts `/var/run/docker.sock`
> directly into the NetAlertX container.

### Why a Socket Proxy, and not `docker.sock` directly?

Mounting `/var/run/docker.sock` into a container gives that container the
same power as root on the host: anything that can reach the socket can,
for example, start a new `--privileged` container with the host
filesystem bind-mounted in - a standard, well-known way to escalate from
"container access" to "host root." It can't be scoped down to "read-only"
or "just these endpoints" - it's all or nothing.

That's a much bigger risk to accept for NetAlertX specifically than for a
small single-purpose tool: NetAlertX is a web UI, a GraphQL API, and
dozens of other plugins pulling in data from routers, DHCP leases, and
other external sources - a large attack surface. A vulnerability anywhere
in any of that would inherit full `docker.sock` access too, even though
this plugin itself only ever needs to read three things: the container
list, host info, and the network list.

The Socket Proxy sits between NetAlertX and the real socket and only
forwards the specific API paths this plugin actually needs
(`CONTAINERS=1`, `INFO=1`, `NETWORKS=1`) - everything else (exec, image
builds, volumes, secrets, any `POST` that creates/kills something) is
rejected by default. If NetAlertX is ever compromised, the blast radius
stops at "can list containers/networks," not "can root the host."

### Socket Proxy compose service

Add this as another service in the **same `docker-compose.yml` as
NetAlertX itself** - not a separate stack/file:

```yaml
services:
netalertx:
container_name: netalertx
image: "ghcr.io/jokob-sk/netalertx"
... # same as you already have
...

docker-socket-proxy:
image: tecnativa/docker-socket-proxy:latest
container_name: docker-socket-proxy
environment:
CONTAINERS: 1
INFO: 1
NETWORKS: 1
POST: 0
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
# Only if netalertx uses network_mode: host - see note below
# ports:
# - "127.0.0.1:2375:2375"
```

> [!NOTE]
> If your `netalertx` service uses `network_mode: host` (common, since ARP
> scanning needs a real host NIC), it won't resolve `docker-socket-proxy`
> by name - host networking means it isn't on the compose network at all.
> Fix: add `ports: ["127.0.0.1:2375:2375"]` to the proxy service above, and
> use `http://127.0.0.1:2375` as the Socket Proxy URL instead. Don't give
> the proxy `network_mode: host` too - that likely exposes it to the whole
> LAN instead of just the NAS.

Same file, on purpose:

- Compose puts every service in one file on the same default network
automatically, so NetAlertX can reach it at `http://docker-socket-proxy:2375`
for free - no extra `networks:` config, no port published to the LAN
(nothing else needs to reach it). (`http://127.0.0.1:2375` only applies
under the `network_mode: host` case above, not this default one - under
default bridge networking each container has its own loopback, so
`127.0.0.1` inside NetAlertX wouldn't reach the proxy container.)
- Its lifecycle naturally follows NetAlertX's - one `docker compose up`/
`down` brings both up or down together, instead of a second stack to
remember to manage separately.
- It's a dependency this plugin needs, not an unrelated service, so it
belongs with NetAlertX conceptually as well as operationally.

(The only real reason to split it into its own stack is sharing one proxy
across several unrelated projects - e.g. Watchtower and NetAlertX both
reading from the same proxy instead of each running their own. Not needed
here.)

`POST: 0` is already the image's default; it's listed explicitly since
it's the setting that keeps this read-only - nothing here can
create/start/stop/kill anything.

### Quick setup guide

1. Add the Socket Proxy service above to NetAlertX's `docker-compose.yml`
and bring it up (`docker compose up -d docker-socket-proxy`) - one per
Docker host you want tracked, if you're tracking more than one.
2. In NetAlertX, add one entry per Docker host under **Docker hosts**
(`DOCKERDISC_hosts`) with that proxy's URL (`http://127.0.0.1:2375`,
`http://docker-socket-proxy:2375`, or whatever you named the service).
3. Make sure the Docker host itself already exists as a device in
NetAlertX (it normally does, found via ARP/Nmap - Docker hosts have a
real NIC on the LAN). If host-MAC auto-detection doesn't find it (see
below), fill in its MAC manually in the same entry.

#### Required Settings

- When to run `DOCKERDISC_RUN`
- Docker hosts `DOCKERDISC_hosts` - at least one entry, each with:
- Docker Socket Proxy URL `DOCKERDISC_SOCKET_PROXY_URL`
- Docker Host MAC Address (Fallback) `DOCKERDISC_HOST_MAC` - optional if
auto-detection works for that host

### Host MAC auto-detection

If `DOCKERDISC_HOST_MAC` is filled in, it's used immediately - no Socket
Proxy call at all. Deliberate trade-off: a MAC is stable, so there's
nothing to gain by re-confirming it via `/info` on every scheduled run,
but it also means a future MAC change (e.g. a replaced NIC) won't be
auto-detected while the field stays set.

Otherwise, the plugin calls the Socket Proxy's `GET /info` (Docker Engine
API) to read the daemon's hostname, then looks for a NetAlertX device
whose `devName` matches it. If either step fails - `/info` isn't reachable
(check the `INFO=1` permission), or no device's name matches - that host's
entry is skipped for the run (logged, not fatal to other hosts).

### Container listing

Every container on a host is listed, including `bridge`/overlay ones - not
only `macvlan`/`ipvlan` containers. What changes per container is only
whether it has a real LAN-visible identity to show:

- **Network Driver** (`watchedValue3`) is always populated.
- **Container MAC** (`watchedValue4`) and **IP** (`extra`) are populated
only when the container has a `macvlan`/`ipvlan` network attached;
otherwise they show `null`. A `bridge`-only container's own IP/MAC isn't
LAN-visible, so there's nothing meaningful to show there - it still gets
a row (image, Compose project/service, driver).
- If a container is attached to **more than one** `macvlan`/`ipvlan`
network at the same time (uncommon, but possible - e.g. a dual-homed
network appliance), the network whose *name* sorts first alphabetically
is the one shown. This is a deliberate, deterministic tie-break, not an
attempt to pick the "right" one - Docker doesn't expose any ordering or
priority between a container's networks, so any rule here is arbitrary;
what matters is that it's stable (the same container always reports the
same MAC/IP) rather than depending on whatever order the Socket Proxy's
JSON happens to return them in.

### Usage

- Head to **Settings** → **Docker discovery** to configure Docker hosts.
- Container details appear under each host's own **Device Details** →
**Plugins** → **DOCKERDISC** tab.

### Notes

- This plugin never writes to `devMac`, `devLastIP`, `devFirstConnection`,
`devSourcePlugin`, or `devCustomProps` - ARP/Nmap remain authoritative
for device identity and discovery-source attribution on every device,
including the Docker host itself.
- Only Socket Proxy permissions required: `CONTAINERS=1` (list containers,
their networks and labels), `INFO=1` (host-MAC auto-detection), and
`NETWORKS=1` (network driver lookup - one batched `GET /networks` call
per run for every unique network id seen, not one call per container).
No write/exec permissions needed.
- Design history and open implementation questions in [issue #1721]
(https://github.com/netalertx/NetAlertX/issues/1721).

- Version: 0.1.0
- Author: [mauricio-camayo](https://github.com/mauricio-camayo/)
- Release Date: `2026-09-14`
Loading
Loading