Nachdem ich meine ARM64-VM unter Proxmox zum Laufen gebracht hatte, konnte ich mich mit dem Thema NetFlows von OpenWRT in ntopng beschäftigen.
OpenWRT verwendet softflowd um NetFLows zu generieren, daher muss softflowd nur installiert und konfiguriert werden. Aus Performancegründen ist es jedoch nicht empfehlenswert, diese NetFlows direkt an ntopng zu senden. Die typische Konfiguration für ntopng verwendet nprobe als Zwischenschritt zwischen softflowd und ntopng. nprobe fungiert als NetFlow-Kollektor, der die Daten von softflowd empfängt und dann über das ZeroMQ-Protokoll an ntopng weiterleitet.
Ohne nprobe kann es zu Problemen bei der Darstellung und Aktualisierung der Flows in ntopng kommen. Durch Recherchen habe ich herausgefunden, dass Benutzer (von pfsense) berichteten, dass bei der direkten Verwendung von softflowd mit ntopng die Flows nicht korrekt aktualisiert wurden und nur für kurze Zeit sichtbar waren. nprobe bietet wichtige Funktionen zur Verarbeitung und Aufbereitung der NetFlow-Daten, bevor sie an ntopng weitergeleitet werden. Dies verbessert die Qualität und Nutzbarkeit der Daten in ntopng. Für den Einsatz von nprobe ist in der Regel eine Lizenz erforderlich, die nur für Universitäten und gemeinnützige Organisationen kostenlos ist. Diese kostet für Embedded Systeme wie Raspberry Pi knapp 100€, für X86 oder AMD64 CPUs das Dreifache – lebenslang (aber nur mit 1 Jahr Updateservice)! Deshalb habe ich mich entschlossen, die ARM-Architektur unter Intel-Proxmox zum Laufen zu bringen und die embedded nProbe dort zu installieren. Leider musste ich dann feststellen, das die nProbe-Paketquellen auf die Debian-Quellen für Raspberry Pi aufsetzen, also habe ich kurzer Hand eine neue ARM64-VM für Raspberry Pi OS aufgesetzt.
Vorbereitung
Öffne als erstes deine Proxmox-Shell, installiere die ARM64-Unterstützung und lade dir das Raspberry-Pi-OS herunter.
apt update
apt install pve-edk2-firmware-aarch64 qemu-utils
wget https://downloads.raspberrypi.com/raspios_lite_arm64/images/raspios_lite_arm64-2024-11-19/2024-11-19-raspios-bookworm-arm64-lite.img.xz
Leider gibt es das nicht direkt als ISO-Image, wie wir es für Proxmox benötigen, aber das wandeln wir uns einfach um:
xz -d 2024-11-19-raspios-bookworm-arm64-lite.img.xz
qemu-img convert -f raw 2024-11-19-raspios-bookworm-arm64-lite.img -O qcow2 2024-11-19-raspios-bookworm-arm64-lite.qcow2
qemu-img resize 2024-11-19-raspios-bookworm-arm64-lite.qcow2 30G
Da RaspberryOS UEFI voraussetzt, aber in dieser Form (noch) nicht lauffähig ist, müssen wir einen Workaround anwenden. Wir nutzen wie in meinem o.a. Tutorial für ARM-VM unter Proxmox das Debian-ARM64-ISO, um die VM initial zu booten und einige Dinge zu „verbiegen“. Dazu gehst du als erstes in deine Proxmox-ISO-Bibliothek und klickst auf „Download from URL“ (überspringe den Schritt, wenn du bereits ein DebianARM64-ISO heruntergeladen hast)

In das folgende Dialogfeld fügst du unter URL folgenden Link ein: https://cdimage.debian.org/debian-cd/current/arm64/iso-cd/debian-12.10.0-arm64-netinst.iso und klickst auf Query URL.

Und schon kann der Download beginnen:

Erstellen der ARM64-VM
Klicke auf „Create VM“ und vergib einen aussagekräftigen Namen:

Im OS-Tab wählst du „Do not use any media“

Im System-Tab wählst du OVMF (UEFI) als BIOS aus, entfernst den Haken bei „Add EFI Disk“ und änderst den SCSI Controller auf „VirtIO SCSI“ – also die Version ohne Single.

Lösche die vorgeschlagene Disk durch Klick auf den Papierkorb (ist hier schon passiert 🙂 ).

Im CPU-Tab klickst du auf das kleine Kreuz im Type-Feld und wechselst dadurch auf Default (kvm64). Ich empfehle dir ausreichend Cores auszuwählen, sonst wird die Wartezeit sehr lang.

Stelle sicher, das der Haken bei „Start after created“ nicht gesetzt ist, bevor du auf „Finish“ klickst.

Im Anschluss gehst du auf den Hardware-Tab und löscht das vorhandene CD/DVD-Drive. Als IDE wird das eh nicht funktionieren.

Jetzt wechselst du wieder auf die Proxmox-Shell und importierst das entpackte und umgewandelte RaspiI-mage von oben in deine neue VM. Ändere also ggf. die 102 in deine dreistellige VM-Nummer und passe ggf. das Ziel an (bei mir local-lvm, könnte bei dir auch nur local o.ä. sein (die TAB-Taste ist dein Freund)):
qm importdisk 102 /var/lib/vz/template/qcow/2024-11-19-raspios-bookworm-arm64-lite.qcow2 local-lvm
Das Ergebnis sollte dann so aussehen:
importing disk '/var/lib/vz/template/qcow/2024-11-19-raspios-bookworm-arm64-lite.qcow2' to VM 102 ...
Logical volume "vm-102-disk-1" created.
transferred 0.0 B of 30.0 GiB (0.00%)
...
transferred 30.0 GiB of 30.0 GiB (100.00%)
unused0: successfully imported disk 'local-lvm:vm-102-disk-1'
Im Hardware-Tab deiner VM sollte jetzt eine neue „Unused Disk“ vorhanden sein, mache einen Doppelklick darauf:

Stelle sicher, das SCSI 0 ausgewählt ist und klicke auf Add.

ALs nächstes fügen wir das CD/DVD-Laufwerk mit dem Debian-ARM64-ISO hinzu, dies wird dann als SCSI 1 eingebunden:


Ab diesem Moment haben wir ein System mit dem RaspiOS-Image als SCSI 0 (HDD) und der Debian-ARM64-ISO als DVD-Laufwerk unter SCSI 1.
Jetzt ändern wir die Bootreihenfolge und stellen sicher, dass das DVD-Laufwerk das erste Boot-Laufwerk ist, net0 kannst du deaktivieren und SCSI0 kannst du schon mal aktivieren. Wichtig ist dann aber die Reihenfolge – DVD als erstes!

Dann öffnest du in der Proxmox-Shell mit nano /etc/pve/qemu-server/102.conf
(ändere 102 in deine dreistellige VM-ID) den Editor, kommentiere die Zeile mit „vmgenid“ aus und füge die Zeile arch: aarch64
hinzu. Sollte da eine Zeile mit „cpu: “ beginndend sein, lösche diese.

Speichere und schließe die Datei (STRG-S, gefolgt von STRG-X) und starte die VM über den Start-Button in der Web-GUI oder qm start 102
. Klicke dann zeitnah auf „>- Console“, dann öffnet sich ein neues Fenster. Im ersten Dialog wählst du „Advanced options…“

…gefolgt von „Rescue mode“.

Dann wird der Bildschirm schwarz, aber keine Sorge – du musst nur warten.

Nach einiger Wartezeit (kann durchaus 1 Minute werden) öffnet sich der gewohnte Dialog zur Auswahl von Sprache, Tastatur-Layout, Rechnername, Domäne (.internal), etc.

Dann kommt irgendwann die Frage nach dem Root-Dateisystem. Wenn du meiner Anleitung bislang sauber gefolgt bist, kannst du jetzt „/dev/sda2“ auswählen.

Dann wählst du „Execute a shell in /dev/sda2″…

…und klickst auf „Continue“:

Sobald sich die Konsole öffnet, kannst du folgendes Kommando absetzen
raspi-config --expand-rootfs

Wichtg! Jetzt klickst du auf den Reset-Button deiner ARM64-VM und zwingst diese somit zum Reboot.
Dann musst du leider die letzten Schritte alle wiederholen (advanced options, rescue mode, Sprache, Layout, /dev/sda2, execute shell). Sobald du wieder im Rescue-System der VM bist geht es weiter mit:
resize2fs /dev/sda2
Als nächstes ändern wir die Datei /etc/fstab ab:
nano /etc/fstab
Füge hier am Ende der Datei folgende Zeile hinzu und speichere und schließe im Anschluss die Datei wieder mit (STRG-S, STRG-X)
none /sys/firmware/efi/efivars efivarfs defaults
Als nächstes installieren wir und den Bootloader für efi-64 und löschen im Anschluss nicht benötigte rpi-Images:
mount /boot/firmware
touch /boot/firmware/ssh
mount /sys/firmware/efi/efivars
Als vorletzten Schritt passt du den Bootloader an und aktivierst die neuen Einstellungen:
grub-install --efi-directory=/boot/firmware
update-grub2
Dann verlässt du die VM-Shell mit exit
und wählst im folgenden Dialog „System neu starten“ aus:

Wenn die VM dann neu startet drückst du direkt im Anschluss mehrfach die ESC-Taste, um in das BIOS zu gelangen. Wähle dort den Boot Maintenance Manager aus:

Und prüfe, ob „debian“ in der Boot-Reihenfolge ganz oben steht. Wenn nicht ändere das entsprechend ab:

Sollte gar kein Eintrag für debian vorhanden sein, kannst du ihn an dieser Stelle auch neu erstellen durch:
- Zurück zum Hauptmenü vom BIOS.
- Klick Boot Options
- Add Boot Option
- Klick bootfs.
- Klick EFI > Debian
- Klick grubbaa64.efi
- Gib „debian“ ein
- Klick Commit.
- Ändere die Reihenfolge und stelle sicher, das „debian“ ganz oben steht.
Dann geht du zurück in das Hauptmenü vom BIOS, wählst „Continue“ und jetzt brauchst du ganz viel Geduld (der Bildschirm ist wirklich für mehrere Minuten schwarz) …und dann

Es folgt der gewohnte Installationsdialog mit Sprache, Keyboard-Layout, User, Password, – ich erspare dir die ganzen Screenshots.
Sollte die VM in die Grub-CLI bootet, musst du erneut das Debian-netinst-ISO von der CD/DVD laden und in den Rettungsmodus wechseln. Sobald du in der Shell bist, aktualisiere Grub erneut, indem du update-grub2
ausführst. Verlassen dann die Shell und starten die VM erneut.
Wenn du durch bist mit der Installation begrüßt dich der Login-Bildschirm.

Logge dich mit deinen soeben erstellten Credentials ein und checke Betriebsystem und CPU mit uname -a && lscpu
Linux raspberrypi 6.1.0-32-arm64 #1 SMP Debian 6.1.129-1 (2025-03-06) aarch64 GNU/Linux
Architecture: aarch64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 2
On-line CPU(s) list: 0,1
Vendor ID: ARM
Model name: Cortex-A57
Model: 0
Thread(s) per core: 1
Core(s) per socket: 2
Socket(s): 1
Stepping: r1p0
BogoMIPS: 125.00
Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
NUMA:
NUMA node(s): 1
NUMA node0 CPU(s): 0,1
Vulnerabilities:
Gather data sampling: Not affected
Itlb multihit: Not affected
L1tf: Not affected
Mds: Not affected
Meltdown: Not affected
Mmio stale data: Not affected
Reg file data sampling: Not affected
Retbleed: Not affected
Spec rstack overflow: Not affected
Spec store bypass: Vulnerable
Spectre v1: Mitigation; __user pointer sanitization
Spectre v2: Vulnerable
Srbds: Not affected
Tsx async abort: Not affected
Wenn du magst, kannst du noch mit sudo apt autoremove
ein wenig aufräumen oder mit sudo apt update && sudo apt upgrade
das System auf den aktuellsten Stand bringen. Ich persönlich füge die neue VM zunächst der lokalen Wazuh-Überwachung hinzu, aber dazu evtl. in einem späteren Tutorial mehr.
Installation von nProbe
Die Installation von nProbe ist dagegen vergleichsweise einfach, um die Konfiguration kümmern wir uns dann später:
wget https://packages.ntop.org/RaspberryPI/apt-ntop.deb
sudo dpkg -i apt-ntop.deb
sudo apt-get update
sudo apt-get install nprobe
Installation softlowd unter OpenWRT
Auch die ist verhältnismäßig unspektakulär:
opkg update
opkg install softflowd
Konfiguration
Jetzt kommt der wirklich spaßige Teil. Ich fange bei solch komplexen Konfigurationen gerne an einem der beiden Enden an, nie in der Mitte – das kennt man sicher von der Fehlersuche 🙂
In diesem Fall fange ich mit dem OpenWRT-Router an, da dieser ja die NetFlows per softflowd an die nProbe senden soll, diese dann schon mal anfängt, die Daten passend für ntopng aufzubereiten, um sie dann selbst per ZeroMQ (ein mehr als geniales Protokoll dafür) an ntopng zu senden.
Und bevor wir da gleich anfangen die Deamons und Skripte zu konfigurieren und dann beim Start den Kopf einziehen, fangen wir ganz klein mit dem OpenWRT-Router an und erarbeiten uns (die Arbeit habe ich dir mit Masse schon abgenommen) auf der Kommandozeile unsere eigentliche Konfiguration.
Wenn du softflowd ganz stumpf auf der Kommandozeile eingibst, zeigt dir die App, was sie alles kann:
root@GL-MT3000:~# softflowd
-i, -r or -R option not specified.
Usage: softflowd [options] [bpf_program]
This is softflowd version 1.0.0. Valid commandline options:
-i [idx:]interface Specify interface to listen on
-r pcap_file Specify packet capture file to read
-t timeout=time Specify named timeout
-m max_flows Specify maximum number of flows to track (default 8192)
-n host:port Send Cisco NetFlow(tm)-compatible packets to host:port
-p pidfile Record pid in specified file
(default: /var/run/softflowd.pid)
-c socketfile Location of control socket
(default: /var/run/softflowd.ctl)
-v 1|5|9|10|psamp NetFlow export packet version
10 means IPFIX and psamp means PSAMP (packet sampling)
-L hoplimit Set TTL/hoplimit for export datagrams
-T full|port|proto|ip| Set flow tracking level (default: full)
vlan ("vlan" tracking means "full" tracking with vlanid)
ether ("ether" tracking means "vlan" tracking with ether header)
-6 Track IPv6 flows, regardless of whether selected
NetFlow export protocol supports it
-d Don't daemonise (run in foreground)
-D Debug mode: foreground + verbosity + track v6 flows
-P udp|tcp|sctp Specify transport layer protocol for exporting packets
-A sec|milli|micro|nano Specify absolute time format form exporting records
-s sampling_rate Specify periodical sampling rate (denominator)
-b Bidirectional mode in IPFIX (-b work with -v 10)
-a Adjusting time for reading pcap file (-a work with -r)
-C capture_length Specify length for packet capture (snaplen)
-l Load balancing mode for multiple destinations
-R receive_port Specify port number for PSAMP receive mode
-h Display this help
Valid timeout names and default values:
tcp (default 3600) tcp.rst (default 120) tcp.fin (default 300)
udp (default 300) icmp (default 300) general (default 3600)
maxlife (default 604800) expint (default 60)
Okay, was davon ist interessant für uns:
- -i spezifiziert das Interface, das kann bei einem OpenWRT-Router eth0 (das WAN-Interface) sein, aber besser ist noch br-lan, da durch diese Schnittstelle der gesamte interne Verkehr geht, egal ob LAN oder WLAN – und NAT hier noch nicht gewirkt hat.
- -n definiert den Zielhost und Port für die generierten NetFlows (auch wenn das hier mit CISCO etwas unglücklich formuliert ist). Die IP-Adresse meiner ARM64-VM mit nProbe ist die 192.168.178.175 und nProbe hört per default aus Port 2055/UDP.
- -v legt die Form der NetFlows fest, nProbe kann man v5, v9 und IPFIX umgehen, sagt der Entwickler auf seiner Webseite.
- -D startet softflowd im Ddebug-Modus. Oh ja – damit fangen wir an!
Das schaut dann so aus:
softflowd -i br-lan -n 192.168.178.175:2055 -v 9 -D
Und dann geht es auch schon los, softflowd generiert NetFlows:
softflowd v1.0.0 starting data collection
Exporting flows to [192.168.178.175]:2055
ADD FLOW seq:1 [139.7.117.169]:4500 <> [192.168.8.161]:4500 proto:17 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
ADD FLOW seq:2 [17.57.146.27]:5223 <> [192.168.8.161]:51969 proto:6 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
ADD FLOW seq:3 [192.168.8.161]:49391 <> [216.239.36.127]:5223 proto:6 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
ADD FLOW seq:4 [192.168.8.161]:0 <> [224.0.0.22]:0 proto:2 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
ADD FLOW seq:5 [192.168.8.161]:5353 <> [224.0.0.251]:5353 proto:17 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
ADD FLOW seq:6 [fe80::9a:8ec6:7420:989f]:5353 <> [ff02::fb]:5353 proto:17 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
ADD FLOW seq:7 [192.168.8.1]:53 <> [192.168.8.161]:51278 proto:17 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
ADD FLOW seq:8 [192.168.8.1]:53 <> [192.168.8.161]:61668 proto:17 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
ADD FLOW seq:9 [192.168.8.1]:53 <> [192.168.8.161]:63720 proto:17 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
ADD FLOW seq:10 [17.242.179.27]:443 <> [192.168.8.161]:52237 proto:6 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
Aber kommen die auch bei der nProbe an? Dazu wechseln wir zur nProbe-Shell und sniffen mal auf der Netzwerkkarte, ob irgendetwas vom OpenWRT-Router (192.168.8.1) ankommt.
user@nProbe:~ $ sudo tcpdump -n host 192.168.8.1
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
15:47:01.654731 IP 192.168.8.1.34709 > 192.168.178.175.2055: UDP, length 372
15:47:01.660007 IP 192.168.178.175 > 192.168.8.1: ICMP 192.168.178.175 udp port 2055 unreachable, length 408
Ah, okay – klare Ansage. Da kommt etwas auf Zielport 2055, aber nProbe sagt Port nicht erreichbar. Das ist logisch, da die nProbe noch nicht gestartet ist, hört auch niemand auf diesem Port 2055/UDP. Also kümmern wir uns jetzt darum.
Mit nprobe –help bekommst du alle Optionen aufgelistet, den Auszug erspare ich dir hier (er füllt mehrere Bildschirmseiten). Also ein anderer Ansatz, auch hier hilft uns der Entwickler mit einer hervorragenden Dokumentation. Es gibt einen eigenen Abschnitt „Using ntopng with nProbe„, der unserem Anwendungsfall sehr ähnlich ist. Hier wird auch erklärt, wie man mit nur einer nProbe die NetFlows aus mehreren Quellen sammeln kann, um sie dann an eine ntopng-Instanz weiterzugeben. Volltreffer! Ich habe mehrere OpenWRT-Router, eine ntopng-Instanz in der Community Edition (kostenlos) und kann mit der embedded nProbe-Lizenz für knapp 100€ bis zu 4 NetFlow-Exporter softflowd anzapfen.
Aber zurück zur Syntax, nProbe verhält sich wie ein intelligentes Relais, daher sind Angaben wie Quelle und Ziel obligatorisch.
- –collector-port ist der Port, auf dem nProbe NetFlows von einem Exporter wie softflowd empfängt
- –zmq weist nProbe an, die NetFlows als ZeroMQ an ein bestimmtes Ziel weiterzuleiten, das ist ntopng, das bei mir unter 192.168.178.162 erreichbar ist. In den Beispielen wird der Port 5556 nur für eine Probe verwendet, also nehmen wir diesen auch.
- –zmq-probe-mode verdeutlicht noch einmal, dass kein physikalisches Interface überwacht werden soll, sondern ausschließlich ZeroMQ zum Einsatz kommen soll
- -n scheint auf den ersten Blick unwichtig, gibt aber an, wohin die nProbe die NetFlows senden soll. Da wir die NetFlows aber nicht einfach weiterleiten, sondern durch die nProbe verarbeiten und per ZeroMQ weiterleiten, müssen wir hier explizit none angeben
- -T steht für das Template (kennt man sicher von Datenbanken), für unser Ziel ntopng ist die Variable %NTOPNG%
Zusammengefast sieht das dann so aus:
nprobe -i none --collector-port 2055 --zmq "tcp://192.168.178.162:5556" --zmq-probe-mode -n none -T @NTOPNG@
Und in der Bildschirmausgabe so:
user@nProbe:~ $ nprobe --collector-port 2055 --zmq "tcp://192.168.178.162:5556" --zmq-probe-mode -n none -T @NTOPNG@
27/Mar/2025 15:59:57 [plugin.c:176] No plugins found in ./plugins
27/Mar/2025 15:59:57 [plugin.c:184] Loading 22 plugins [.so] from /usr/lib/nprobe/plugins
27/Mar/2025 15:59:57 [nprobe.c:6396] Disabling flow cache during collection
...
27/Mar/2025 15:59:57 [nprobe.c:8423] -i is ignored as --collector-port|-3 has been used: using '-i none'
27/Mar/2025 15:59:57 [nprobe.c:8475] Flow cache is disabled in flow collection mode
27/Mar/2025 15:59:57 [nprobe.c:8478] Welcome to nProbe v.10.7.250326 for aarch64-unknown-linux-gnu
27/Mar/2025 15:59:57 [nprobe.c:8500] Pro Edition running on Debian GNU/Linux 12 (bookworm) [Raspberry]
27/Mar/2025 15:59:57 [nprobe.c:8508] Current limits [4 ZMQ exporters][4 collector devices]
27/Mar/2025 15:59:57 [nprobe.c:8523] SystemId: L237A19D85E6BA0A5--OL
27/Mar/2025 15:59:57 [nprobe.c:8616] Sample rate [packet: 1][flow collection/export: 1/1]
...
27/Mar/2025 15:59:58 [nprobe.c:12306] Flow export type (-T): bidirectional flows
27/Mar/2025 15:59:58 [nprobe.c:12512] Flows ASs will not be computed (no GeoDB files loaded with --as-list)
27/Mar/2025 15:59:58 [nprobe.c:12544] Flows will be exported in NetFlow 9 format
27/Mar/2025 15:59:58 [util.c:6840] Initializing ZMQ as client
27/Mar/2025 15:59:58 [util.c:6871] Exporting flows towards ZMQ endpoint tcp://192.168.178.162:5556
27/Mar/2025 15:59:58 [nprobe.c:12783] Not capturing packet from interface (collector mode)
27/Mar/2025 15:59:58 [util.c:5596] WARNING: Skept UDP socket buffer enlargement: lack of privileges or in a container
27/Mar/2025 15:59:58 [util.c:5597] WARNING: Flow collection drops are possible with bursty exporters!
27/Mar/2025 15:59:58 [util.c:5606] Privileges are not dropped as we're not superuser
27/Mar/2025 15:59:58 [collect.c:248] Flow collector listening on port 2055 (IPv4/v6)
27/Mar/2025 15:59:58 [export.c:533] Using TLV as serialization format
27/Mar/2025 15:59:58 [nprobe.c:13105] nProbe started successfully
27/Mar/2025 16:11:01 [collect.c:3677] Collecting flows from 192.168.8.1 [total: 1/4]
27/Mar/2025 16:11:01 [collect.c:2013] Added new flow template definition [id=1024][flow_version=9][netflow_device=192.168.8.1:34709][observation_domain_id=0][total=1]
27/Mar/2025 16:11:01 [collect.c:2013] Added new flow template definition [id=1025][flow_version=9][netflow_device=192.168.8.1:34709][observation_domain_id=0][total=2]
27/Mar/2025 16:11:01 [collect.c:2013] Added new flow template definition [id=2048][flow_version=9][netflow_device=192.168.8.1:34709][observation_domain_id=0][total=3]
27/Mar/2025 16:11:01 [collect.c:2013] Added new flow template definition [id=2049][flow_version=9][netflow_device=192.168.8.1:34709][observation_domain_id=0][total=4]
27/Mar/2025 16:11:01 [collect.c:2013] Added new flow template definition [id=256][flow_version=9][netflow_device=192.168.8.1:34709][observation_domain_id=0][total=5]
Die letzten 5 Zeilen sehen gut aus.
Also wechseln wir in die Shell von ntopng und beginnen auch hier auf der Kommandozeile. Beende gegebenenfalls das Skript fritzdump.sh, wenn du mein anderes Tutorial hier verfolgt hast. Dann kennst du ntopng aber schon ein wenig. ntopng benötigt mindestens eine Datenquelle, um Flows visualisieren zu können. Bisher (Tutorial) war das der Paketmitschnitt der Fritzbox, jetzt soll es die nProbe sein.
Zusätzlich können wir noch angeben, was das lokale Subnetz ist, das habe ich hier mit supernetting zusammengefasst.
ntopng -i tcp://*:5556c -m "192.168.0.0/16=local"
Wir lassen ntopng hier auf allen Interfaces auf Port 5556 lauschen, du kannst auch explizit nur eines angeben. Das kleine c bedeutet, dass ntopng hier im Collector-Modus arbeitet. Sonst würde ntopng aktiv bei der nProbe nach neuen Flows fragen, hier verhält es sich passiv und lässt die nProbe berichten.

Läuft!…würde ich sagen. NetFlows aus einem „völlig fremden“ Netzwerk (192.168.8.0/24)
Zusammenfassung
Okay, nachdem das alles so gut auf der Kommandozeile funktioniert, übergeben wir das Ganze an Daemons oder Skripte, die die Arbeit im Hintergrund erledigen.
Beginnen wir wieder mit dem OpenWRT-Router. Beende softflowd mit CTRL-X und du hast wieder die Kontrolle über die Kommandozeile.
OpenWRT bietet die Konfiguration über uci an, einen eigenen Konfigurationsmanager.
uci add softflowd softflowd
uci set softflowd.@softflowd[0].enabled='1'
uci set softflowd.@softflowd[0].interface='br-lan' # Zu überwachende Schnittstelle
uci set softflowd.@softflowd[0].host_port='COLLECTOR_IP:2055' # Ziel-IP/Port des NetFlow-Kollektors
uci set softflowd.@softflowd[0].export_version='9' # NetFlow v9 empfohlen
uci commit softflowd
#uci set softflowd.@softflowd[0].track_ipv6='1' #auskommentieren, wenn du auch IPv6 tracken möchtest
/etc/init.d/softflowd start
/etc/init.d/softflowd enable
Das war es schon, der Dienst läuft im Hintergrund. Du kannst mit softflowctl statistics
oder softflowctl dump-flows
das ganze auch verifizieren. Aufpassen! softflowctl und nicht nicht softflowd 🙂
root@GL-MT3000:~# softflowctl statistics
softflowd[12511]: Accumulated statistics since 2025-03-26T12:24:16 UTC:
Number of active flows: 2
Packets processed: 56
Packets non-sampled: 5453
Fragments: 0
Ignored packets: 798 (798 non-IP, 0 too short)
Flows expired: 42 (0 forced)
Flows exported: 42 (45 records) in 23 packets (0 failures)
Packets received by libpcap: 6315
Packets dropped by libpcap: 0
Packets dropped by interface: 0
Expired flow statistics: minimum average maximum
Flow bytes: 40 279 1500
Flow packets: 1 1 3
Duration: 0.00s 83.46s 1500.50s
Expired flow reasons:
tcp = 15 tcp.rst = 1 tcp.fin = 1
udp = 19 icmp = 5 general = 1
maxlife = 0
over 2 GiB = 0
maxflows = 0
flushed = 0
Per-protocol statistics: Octets Packets Avg Life Max Life
icmp (1): 2988 5 0.00s 0.00s
igmp (2): 40 1 0.00s 0.00s
tcp (6): 4616 25 206.19s 1500.50s
udp (17): 4070 19 0.00s 0.00s
root@GL-MT3000:~# softflowctl dump-flows
softflowd[12511]: Dumping flow data:
ACTIVE seq:38 [178.254.4.110]:993 <> [192.168.8.193]:50370 proto:6 octets>:117 packets>:1 octets<:0 packets<:0 start:2025-03-26T14:48:45.874 finish:2025-03-26T14:48:45.874 tcp>:18 tcp<:00 flowlabel>:00000000 flowlabel<:00000000 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
EXPIRY EVENT for flow 38 in 702 seconds
ACTIVE seq:21 [17.57.146.55]:5223 <> [192.168.8.193]:56339 proto:6 octets>:0 packets>:0 octets<:200 packets<:5 start:2025-03-26T13:50:58.289 finish:2025-03-26T15:31:15.272 tcp>:00 tcp<:10 flowlabel>:00000000 flowlabel<:00000000 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
EXPIRY EVENT for flow 21 in 3252 seconds
ACTIVE seq:45 [17.253.15.201]:443 <> [192.168.8.193]:57143 proto:6 octets>:1399 packets>:1 octets<:0 packets<:0 start:2025-03-26T15:32:28.054 finish:2025-03-26T15:32:28.054 tcp>:18 tcp<:00 flowlabel>:00000000 flowlabel<:00000000 vlan>:0 vlan<:0 ether:00:00:00:00:00:00 <> 00:00:00:00:00:00
EXPIRY EVENT for flow 45 in 3325 seconds
...
Die eigentliche Konfigurationsdatei kannst du auch manuell unter /etc/config/softflowd mit einem Editor bearbeiten und anschließend den Dienst mit /etc/init.d/softflowd restart
neu starten. Die ist recht selbsterklärend, da gehe ich jetzt nicht weiter drauf ein.
Die nProbe hat zwar ein Konfigurationstool, das du wie folgt starten kannst, aber… (das aber siehst du gleich):
sudo nprobe-config
Natürlich wollen wir zunächst eine neue Konfiguration erstellen:

Wir möchten Flows sammeln und dann an ntopng weiterleiten:

Dann vergibst du einen aussagekräftigen Namen, wählst als Port 2055 als eingehenden Port für softflowd und die IP-Adresse von ntopng sowie den Port 5556, auf dem ntopng auf die Pakete von der nProbe wartet.
Was auffällt ist, das du ZeroMQ als Protokoll gar nicht auswählen kannst. Also ist doch wieder Handarbeit nötig. Du findest die entsprechende Konfigurationsdatei unter /run/nprobe.conf für einen Flow, oder wenn du die mittels der GUI eine neue Konfig erstellt hast unter /run/nprobe-<NAME>.conf. Also wenn dein aussagekräftige Name „openwrt“ war unter /run/nprobe-openwrt.conf. Dort findest du alle einzelnen Parameter wie auf der Kommandozeile.
Den Dienst selbst kannst du dann wie folgt starten
systemctl start nprobe
systemctl enable nprobe
Bleibt noch ntopng selbst. Da wir zwingend eine Schnittstelle übergeben müssen, bleibst du entweder bei der Kommandozeile und hängst nur ein & an, bevor du Enter drückst. Dann läuft der Dienst im Hintergrund. Oder du änderst die letzte Zeile von fritzdump.sh (die, die mit wget beginnt) aus dem anderen Tutorial (oben verlinkt) wie folgt ab
wget --no-check-certificate -qO- $FRITZIP/cgi-bin/capture_notimeout?ifaceorminor=$IFACE\&snaplen=\&capture=Start\&sid=$SID | ntopng -m "192.168.0.0/16=local" -q -F syslog --community -i tcp://*:5556c -i -
Beachte, dass der Parameter -i zweimal enthalten ist, zuerst unser NetFlow von der nProbe und dann STDIN, der Paketmitschnitt der Fritzbox.
Jetzt kann das ntop-Team gerne 100€ für die nProbe-Lizenz von mir haben, dann erspare ich mir den 10-minütigen Neustart der nProbe zur Evaluierung. 🙂
An der Performance kann man sicher noch etwas schrauben, ich werde dieses Tutorial anpassen, wenn ich Verbesserungen am Workflow oder den Parametern finde.