Multicast(at)Work

Multicast(at)Work / Teknisk beskrivelse

Multicast(at)Work

Arkitektur, testverktøyene, sikkerhet, installasjon og drift for Multicast(at)Work – et web-GUI for iperf 2 og ping som tester unicast, multicast og MTU i lukkede nett

Versjon 3.0.0Revidert 2026-10-04Mottaker, sender og MTU-test

Multicast(at)Work er et web-grensesnitt for iperf 2 og ping. Det kontrollerer at et nettverk fører unicast og multicast riktig, og finner største pakkestørrelse (MTU) på en vei gjennom nettet. Programmet installeres offline på Rocky Linux 9, i VMware og i Proxmox VE, og kjører som én systemd-tjeneste uten Docker. Dokumentet beskriver arkitekturen, hvordan testene kjøres, sikkerhetsmekanismene, installasjonsmodellen og grensesnittene, og er skrevet for drift, sikkerhetsgjennomgang og videreutvikling.

1. Formål og omfang

Produkt

Multicast(at)Work 3.0.0

Komponenter

Web-GUI (app.py, i18n.py, maler, static/), iperf 2.2.1 (statisk bygget), installasjonsskript (install.sh, uninstall.sh, check-prereqs.sh), selvtest (selftest.py)

Bruksområde

Kontroll av multicast i og mellom VLAN (IGMP-join, snooping, querier, PIM og TTL), unicast-gjennomstrømning som grunnlinje, og MTU for en sti (jumborammer, tunneler, PPPoE)

Ikke formål

Kontinuerlig overvåking, lastgenerering i produksjonsnett eller måling over IPv6

Målplattformer

Rocky Linux 9 / RHEL 9 / AlmaLinux 9 / Oracle Linux 9 (primær) og VMware Photon OS, på fysisk maskin, som VM i VMware eller Proxmox VE, eller som LXC-container i Proxmox VE. x86_64 og aarch64.

Kjøremodell

Én Flask-applikasjon under waitress, styrt av systemd, som starter iperf og ping som egne prosesser. Ingen containere, ingen pip, ingen EPEL, ingen internettilgang.

Språk

Engelsk og norsk (bokmål) i web-grensesnitt, logglinjer, feilmeldinger, brukermanual og installasjonsskript

Lisens

MIT

2. Arkitektur

2.1. Oversikt

Komponenter og dataflyt
Nettleser (administrator)
   │ HTTP :5152, innloggingsside (signert sesjonskapsel) eller Basic Auth,
   │ X-Requested-With: mct på alle POST
   ▼
waitress 3.0 + Flask 3.1 (app.py, i18n.py)          bruker mct (ikke root)
   │                                                  CAP_NET_RAW, CAP_NET_ADMIN
   │  økter i minnet: id → prosesser, logg, status
   │  hver kommando i egen prosessgruppe, uten skall
   ├─ /opt/multicast-tester/bin/iperf -s …            mottaker (TCP og/eller UDP-gruppe)
   ├─ /opt/multicast-tester/bin/iperf -c …            sender (TCP / UDP-multicast)
   ├─ ping -M do|want -s N …                          ping og MTU-test
   └─ ip -4 -o addr                                   adresser til nettkortlista
   ▼
Nettkort ── IGMP join/leave, UDP-strøm, TCP, ICMP ──▶ testnettet ◀── andre installasjoner / iperf 2

2.2. Kodemoduler

Fil Innhold

app.py

Flask-applikasjonen: ruter, autentisering, CSRF-kontroll, sikkerhetshoder, validering, øktstyring, kjøring av iperf og ping, MTU-testen, språkvalg, lisens- og manualsider

i18n.py

Norske oversettelser (engelsk er nøkkelen) og tekstene som sendes til JavaScript

templates/

base.html (blå topplinje med status, EN | NO og Logg ut, bunnlinje), login.html, index.html (fem faner), manual.html, licenses.html

static/

Bootstrap 5.3.8 (bare CSS), app.css (samme utseende som SNMP Trap Sender), app.js (faner, hurtigvalg, økter, logg, historikk, nettkort), ikon, skjermbilder til manualen

manual/

Brukermanualen som HTML, bygget fra docs/*.md med tools/build-manuals.py

vendor/iperf/

iperf 2.2.1 for x86_64 og aarch64, lisenstekster og BUILD-INFO.txt

lib/common.sh

Felles skallfunksjoner: språk, utskrift, plattformgjenkjenning, valg av iperf for CPU-en

tools/selftest.py

Selvtest mot en installert server (bare standardbiblioteket)

2.3. Prosessmodell og rettigheter

Prosess Bruker Rettigheter

waitress (multicast-tester.service)

mct

AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN, samme CapabilityBoundingSet, NoNewPrivileges. 16 tråder.

iperf, ping

mct (arvet)

Arver de to rettighetene. CAP_NET_RAW trengs for SO_BINDTODEVICE (valg av nettkort) og ICMP, CAP_NET_ADMIN for innmelding i en gruppe på et bestemt nettkort.

Hver kommando startes med start_new_session=True, altså i sin egen prosessgruppe. Stopp sender SIGTERM til gruppa og SIGKILL etter to sekunder. Når tjenesten stoppes, gjør KillMode=control-group det samme for alle prosessene.

3. Testverktøyene

3.1. Mottaker

Modus Kommandoer (parallelt)

Begge

iperf -s -p P -i 1 og iperf -s -u -B G[%IF] -p P -i 1

Bare TCP

iperf -s -p P -i 1

UDP / multicast

iperf -s -u -B G[%IF] -p P -i 1

-B gruppe%nettkort får iperf til å melde seg inn i gruppa (IGMP join) på det valgte nettkortet. Uten nettkort brukes nettkortet til standardruta. Mottakeren kjører til den stoppes. -i 1 gir én linje per sekund med båndbredde, jitter og tapte/mottatte datagrammer.

3.2. Sender

Stegene kjøres etter hverandre. Et steg som feiler, stopper ikke de neste.

  1. ping -n -c 5 [-I IF] U

  2. iperf -c U -p P -t T -i 1

  3. iperf -u -c G[%IF] -p P -t T -T TTL -b B -i 1

TTL (1–255) bestemmer hvor mange rutere multicast kan passere. Båndbredden -b er tall med valgfri k, M eller G.

3.3. MTU-test

  1. En vanlig ping (-c 2 -W 2). Svarer ikke målet, stopper testen med en forklaring.

  2. For hver størrelse S (29–9216 byte, maks 1000 størrelser, sortert og uten duplikater): ping -n -c 1 -W 2 -M do|want -s S-28 [-I IF] mål. 28 byte er IP- og ICMP-hodet.

  3. Utdata tolkes: svar (✓ med rtt), message too long, mtu=N (større enn eget nettkort), frag needed (for stor for stien), ingen svar, tidsavbrudd, ukjent vert.

  4. Med DF på er den største størrelsen som fikk svar, MTU for stien. Med DF av står det tydelig at resultatet ikke er MTU-en. Feiler mindre størrelser enn den største som virket, varsles det om inkonsistente resultater.

3.4. Økter og logger

  • En økt er en mottaker, en sender eller en MTU-test. Den har en UUID, type, etikett, språk, prosessliste, logg og status.

  • Hver logglinje får tidsstempel. Loggen begrenses til MCT_MAX_LOG_LINES linjer; de eldste fjernes, og forskyvningen i API-et tar hensyn til det, så nettleseren aldri mister eller dobler linjer.

  • Ferdige økter slettes etter MCT_SESSION_TTL sekunder. Er det MCT_MAX_SESSIONS økter, slettes de eldste ferdige først. Er alle i gang, svarer API-et 429.

  • Nettleseren spør etter nye linjer hvert 0,8 sekund (/api/log/<id>?offset=N). Når forsiden åpnes, henter den /api/sessions og kobler seg til den nyeste kjørende økta av hver type. /api/sessions hentes deretter hvert 3. sekund for fanen Historikk og statusmerket i topplinjen.

4. Web-grensesnitt

4.1. Sider og HTTP-API

Sti Metode Innhold

/login

GET, POST

Innloggingssiden. Skjema: user, password, next

/logout

POST

Logger ut. Skjema: csrf (token i sesjonen)

/

GET

Forsiden med fanene Mottaker, Sender, MTU-test, Historikk og Nettkort

/manual

GET

Brukermanualen på valgt språk

/licenses

GET

LICENSE.txt (#license) og THIRD_PARTY_NOTICES.txt (#third-party)

/licenses/third_party_inventory.json

GET

Maskinlesbar liste over tredjepartskomponenter

/lang/<en|no>?next=<sti>

GET

Lagrer språkvalget i informasjonskapselen mct_lang og går tilbake til next (bare lokale stier)

/api/start_receiver

POST

Starter en mottaker. JSON: mode, multicast_addr, port, iface

/api/start_sender

POST

Starter en sender. JSON: mode, unicast_addr, multicast_addr, port, duration, ttl, bandwidth, iface

/api/start_mtu_probe

POST

Starter en MTU-test. JSON: target, iface, sizes, df

/api/log/<id>?offset=N

GET

Nye logglinjer, running, total

/api/stop/<id>

POST

Stopper økta og alle prosessene

/api/download/<id>

GET

Hele loggen som multicast_<type>_<tid>.log

/api/sessions

GET

Alle økter med id, type, etikett, running, stopped, antall linjer, start- og sluttid

/api/interfaces

GET

Nettkort med MTU, IPv4-adresser, standardrute og flaggene up, multicast og loopback (fra /sys/class/net/<navn>/flags)

/healthz

GET

{"ok":true,"version":"3.0.0","iperf":"2.2.1"}. Krever ikke innlogging.

4.2. Språk (i18n)

  • Engelsk tekst er nøkkelen, og i18n.NO har den norske oversettelsen. tests/test_i18n.py kontrollerer at alle tekster i maler, app.py og app.js er oversatt, og at plassholderne er like.

  • Språket velges med informasjonskapselen mct_lang, ellers MCT_LANG. Malene bruker _(), app.py bruker tr(), og JavaScript får sine tekster som JSON i <body data-i18n>.

  • Logglinjene programmet selv skriver (overskrifter, MTU-resultater, «avsluttet (kode N)»), oversettes til språket økta ble startet med. Utdata fra iperf og ping vises uendret.

  • Feilmeldinger fra API-et kommer på språket i informasjonskapselen.

4.3. Lisenser og manual

  • Bunnlinja på alle sider: Multicast(at)Work 3.0.0 · Lisenser · Tredjepartsmerknader · Brukermanual.

  • /licenses viser LICENSE.txt og THIRD_PARTY_NOTICES.txt fra MCT_DOC_DIR (/opt/multicast-tester).

  • Brukermanualen lages fra docs/Brukermanual.md og docs/en/User-Manual.md med pandoc når pakken bygges. Innholdslista legges i sidefeltet.

5. Sikkerhet

5.1. Tilgangskontroll

  • Innlogging kreves for alt unntatt /login, /lang, /licenses, /healthz og /static. Sider sendes videre til /login, og API-kall får 401 med JSON (uten WWW-Authenticate, så nettleseren ikke viser sin egen dialog).

  • Innloggingssiden setter en signert sesjonskapsel mct_session (Flask, HttpOnly, SameSite=Strict, gyldig i MCT_SESSION_HOURS, standard 12 timer). Nøkkelen er MCT_SECRET_KEY, som install.sh lager (secrets.token_hex(32)) og beholder ved ny installasjon. Sesjonen tømmes ved innlogging (ingen fiksering) og inneholder et merke avledet av passordet, så et nytt passord logger ut alle.

  • Etter 5 feil passord fra samme adresse må den vente 60 sekunder. Feil forsøk logges i journalen.

  • Skript kan bruke HTTP Basic Auth med samme brukernavn og passord. Brukernavn og passord sammenlignes med hmac.compare_digest. install.sh lager et tilfeldig passord (secrets.token_urlsafe(12)) hvis det ikke finnes.

  • Logg ut er et POST-skjema med et CSRF-token fra sesjonen.

  • CSRF: alle POST må ha X-Requested-With: mct. En annen nettside kan ikke sende det hodet uten en CORS-forespørsel, som programmet aldri godtar. Sec-Fetch-Site: cross-site avvises også.

  • Sikkerhetshoder på alle svar: Content-Security-Policy: default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:; frame-ancestors 'none'; form-action 'self'; base-uri 'none', X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy: same-origin, Cache-Control: no-store.

  • Språkbyttet og innloggingen godtar bare lokale stier i next (ingen åpen videresending).

5.2. Validering

Felt Kontroll

IP-adresser

ipaddress.IPv4Address (avviser ledende nuller og oktal skrivemåte). Unicast kan ikke være multicast, kringkasting eller 0.0.0.0. Gruppa må være 224.0.0.0/4.

Vertsnavn (MTU-mål)

Regulært uttrykk etter RFC 1123. Kan ikke begynne med -.

Port, varighet, TTL

Heltall: 1–65535, 1–300, 1–255

Båndbredde

^\d+(\.\d+)?[kKmMgG]?$

Nettkort

^[A-Za-z0-9][A-Za-z0-9._@:-]{0,14}$ og må finnes i /sys/class/net

MTU-størrelser

Liste med maks 1000 tall, avgrenset til 29–9216

JSON

Kroppen må være et JSON-objekt, ellers HTTP 400

Alle kommandoer er argumentlister (subprocess.Popen([…​])), aldri en skallstreng.

5.3. Kjente begrensninger

  • GUI-et går over HTTP, så passordet og sesjonskapselen sendes ukryptert. Bruk et administrasjonsnett, --admin-net eller en SSH-tunnel.

  • En innlogget bruker kan sende trafikk med valgfri hastighet til valgfrie adresser. Det er formålet med verktøyet.

  • Én felles innlogging, ingen roller.

  • Øktene holdes i minnet og forsvinner ved omstart.

  • click 8.1.8 har en kjent sårbarhet som ikke kan nås fra programmet (se Revisjonsrapport.md).

6. Installasjon og filstruktur

6.1. Installasjonsprogrammet

install.sh kjører disse trinnene: kontroll av pakken (SHA256SUMS) → plattform (OS, arkitektur, systemd-detect-virt) → krav (python3 ≥ 3.9, ping, ip; prøver dnf/tdnf bare hvis noe mangler) → valg og kontroll av iperf → bruker mct → filer → Python-pakker → innstillinger → rp_filter → tjeneste (med container-tillegg i LXC) → brannmur → plattformmerknader → selvtest → sammendrag. Avslutningskoden er 0 (OK), 1 (feil) eller 2 (installert, men selvtesten fant noe).

Alle skriptene finnes på engelsk og norsk (--lang, ellers $LANG).

6.2. Installert struktur

Sti Innhold

/opt/multicast-tester/app/

app.py, i18n.py, templates/, static/, manual/

/opt/multicast-tester/bin/iperf

iperf 2.2.1 for maskinens CPU (eller kopi av systemets iperf med --system-iperf)

/opt/multicast-tester/lib/python/

Python-pakkene (utpakkede hjul)

/opt/multicast-tester/lib/sh/common.sh

Til uninstall.sh

/opt/multicast-tester/docs/, licenses/

Dokumentene, og lisenstekster og byggeinformasjon for iperf

/opt/multicast-tester/{LICENSE.txt,THIRD_PARTY_NOTICES.txt,third_party_inventory.json,VERSION,README.txt}

Vises også i GUI-et

/opt/multicast-tester/{uninstall.sh,selftest.py}

Avinstallering og selvtest

/etc/multicast-tester/multicast-tester.env

Innstillinger og passord (0640 root:mct)

/etc/systemd/system/multicast-tester.service

Tjenesten

/etc/systemd/system/multicast-tester.service.d/10-container.conf

Bare i containere

/etc/sysctl.d/90-multicast-tester.conf

net.ipv4.conf.{all,default}.rp_filter = 2

Programmet byttes ut i sin helhet ved oppgradering (app.new → app), så filer som er fjernet i en ny versjon, forsvinner.

6.3. Python-pakker

Hjulene i vendor/wheels pakkes ut direkte med python3 -m zipfile til /opt/multicast-tester/lib/python, som tjenesten finner gjennom PYTHONPATH. pip og virtualenv brukes ikke. MarkupSafe velges etter Python-versjon og CPU (cp39, cp311 og cp312, x86_64 og aarch64). Finnes ikke riktig hjul, brukes et annet, og MarkupSafe faller da tilbake til sin rene Python-utgave. Til slutt kontrolleres det at flask, waitress, jinja2 og markupsafe kan importeres.

6.4. iperf

  • Bygget av tools/build-iperf.sh fra iperf 2.2.1 (iperf_2.2.1+dfsg.orig.tar.xz, SHA-256 kontrollert) med zig cc -target <arch>-linux-musl -static. Resultatet er en statisk fil uten avhengigheter, som virker på alle vanlige Linux-distribusjoner.

  • gnu_getopt (LGPL) er byttet ut med getopt_long fra musl, slik at fila ikke inneholder copyleft-kode (se Lisensrapport.md). Resten av kildekoden er uendret.

  • Byggingen er reproduserbar: samme kildekode og kompilator gir samme SHA-256, som står i vendor/iperf/BUILD-INFO.txt.

6.5. Oppgradering fra 2.x

Versjon 2 lå direkte i /opt/multicast-tester med .venv og hadde innstillingene i /etc/multicast-tester.env. install.sh gjenkjenner det, henter port, bruker og passord fra den gamle fila, flytter den til .v2-migrated, bytter eksempelpassordet change-me og fjerner de gamle filene.

7. Nettverk og eksterne ressurser

7.1. Porter

Port Protokoll Bruk

5152 (--port)

TCP

Web-GUI-et. Kan begrenses til --admin-net.

5001–5010 (--iperf-ports)

TCP og UDP

iperf-testene (standard i GUI-et: 5001)

–

IGMP (protokoll 2)

Innmelding i grupper og svar til querier

–

ICMP

Ping og MTU-test (utgående, med svar)

rp_filter = 2 (løs kontroll) hindrer at kjernen forkaster multicast som kommer inn på et annet nettkort enn ruta tilbake til avsenderen.

7.2. Eksterne ressurser

Ingen. Programmet laster ikke ned noe ved installasjon eller kjøring, og web-sidene henter bare filer fra serveren selv. Navneoppslag brukes bare hvis MTU-målet oppgis som vertsnavn.

8. Drift

Oppgave Kommando

Status

systemctl status multicast-tester

Logg fra tjenesten

journalctl -u multicast-tester -f

Selvtest

sudo python3 /opt/multicast-tester/selftest.py [--lang no] [--quick]

Endre passord, port eller språk

sudo ./install.sh --password … --port … --lang … fra pakkemappa

Start på nytt

sudo systemctl restart multicast-tester

Avinstaller

sudo /opt/multicast-tester/uninstall.sh [--keep-config]

Tjenesten bruker lite ressurser når ingen test kjører (omtrent 40 MB minne). Under en test bestemmer båndbredden CPU-bruken til iperf.

9. Kvalitetssikring

  • 42 enhetstester (pytest) for innlogging og utlogging, validering, sikkerhet, språk, økter, Stopp og MTU-tolkning. iperf og ping erstattes av små skript, så testene ikke trenger nettverk.

  • shellcheck på alle skall-skript, pyflakes og bandit på Python-koden, pip-audit på avhengighetene.

  • Copyleft-skanning av alle filene i pakken (tools/gen-third-party.py --scan).

  • Selvtesten (19 kontroller, også innlogging og utlogging med skjemaet) kjøres av hver installasjon, med en ekte multicast-strøm fra senderen til mottakeren på samme maskin.

  • Nettlesertester i Chromium på begge språk, i alle fem fanene, på innloggingssiden og på mobilbredde.

  • Detaljer og akseptansetest for målplattformene står i Revisjonsrapport.md.

Skjermbilder, installasjon og testscenarier: Tilbake til forsiden