Cross-platform tool (macOS, Windows, Linux) for subscribing to multicast streams — ASM and SSM — with live receive statistics and IGMP querier analysis. Python standard library only, no dependencies. Two variants with identical functionality:
| Variant | File | GUI |
|---|---|---|
| Native app | igmp_join_gui.py |
Tkinter (available as prebuilt executable) |
| Web GUI | igmp_join_tool.py |
Browser at http://127.0.0.1:8688 |
Prebuilt binaries under Releases (built automatically by GitHub Actions):
- macOS (Intel + Apple Silicon, universal):
IGMP-Test-Tool-macOS-universal.zip— unzip and run. If the build is not notarized, on first launch right-click → Open, orxattr -cr "IGMP Test Tool.app". (Maintainers: add the signing secrets from SIGNING.md to ship notarized builds that open with a normal double-click.) - Windows:
IGMP-Test-Tool-Windows.exe— a single self-contained file, no Python required (confirm the SmartScreen warning once). If your antivirus blocks the single exe, useIGMP-Test-Tool-Windows-folder.zipinstead: extract the whole folder first, then runIGMP Test Tool.exefrom it. Running the exe straight out of the zip fails with "failed to load python3xx.dll" because the_internalfolder next to it is required. Local build still possible viabuild_windows.bat. - Without build:
python3 igmp_join_gui.py.
python3 igmp_join_tool.pyWindows: py igmp_join_tool.py — or double-click Start IGMP Test Tool.bat
(Mac: Start IGMP Test Tool.command; may need chmod +x or right-click →
Open once because of Gatekeeper).
The browser opens automatically at http://127.0.0.1:8688.
Options: --port <n> (GUI port), --no-browser.
| Field | Meaning |
|---|---|
| Multicast group | Required, e.g. 239.1.1.1 |
| Source | Optional — with a source an SSM join (IGMPv3, INCLUDE mode) is sent, without one an ASM join |
| Interface | Interface the IGMP report is sent on. The list refreshes automatically (e.g. when a USB adapter is plugged in); ⟳ forces an immediate refresh |
| UDP port | Needed for packet statistics: with a port the tool counts received packets and shows the bitrate (e.g. 5004 for ST 2110/AES67, 2467 for Q-SYS discovery). Leave it empty to auto-detect the port (see below) |
The green dot pulses while packets are arriving. If the interface goes down under an active join, the row turns red ("interrupted") and the tool re-joins automatically once the interface is back. Joins stay active until ended via Leave / Leave all or the tool is closed (IGMP Leave is sent cleanly).
If you join without a port, the tool finds it for you in two stages:
- Well-known ports, no privileges: for ~20 s it listens on a list of
common multicast ports (RTP 5004/5005, PTP 319/320, Q-SYS 2467, Dante 4321,
SAP 9875, VLC 1234, ...). Traffic on one of them adopts that port
automatically; the row then shows e.g.
2467 (auto). - Any port, exact: Detect port captures the UDP traffic to the group and takes the destination port it sees. This needs elevated rights and uses the same helper/system dialog as the querier analysis (once per session). Once the helper is authorized, further port-less joins are sniffed automatically.
Joining the same group again with a port simply sets that port on the existing join. Detected ports are written back to the library entry.
Every successful join (group, source, port) is remembered automatically and listed in the Library panel: click a row to fill the form, double-click (or Join) to join it again on the currently selected interface, give entries a label (e.g. "Cam 1 video"), or remove them. Sorted by last use, up to 200 entries.
The library is a plain JSON file shared by the native app and the web GUI (edit or copy it freely):
| Platform | Path |
|---|---|
| macOS | ~/Library/Application Support/IGMP Test Tool/library.json |
| Windows | %APPDATA%\IGMP Test Tool\library.json |
| Linux | ~/.config/igmp-test-tool/library.json |
Both variants can analyse the IGMP querier on the network ("Start analysis" button): querier IP, IGMP version (v1/v2/v3), query interval (from the QQIC field for v3, additionally measured between two general queries), max response time, the querier's MAC address including vendor (OUI lookup online via macvendors.com) and — if several queriers are visible — which one wins the election (lowest IP).
Capturing IGMP needs a raw socket, i.e. elevated rights. You don't have to start the app as root/admin — on "Start analysis" the tool asks through the system's own dialog and runs only a small capture helper elevated:
| Platform | What you see |
|---|---|
| macOS | the standard password prompt ("osascript wants to make changes") |
| Windows | a UAC prompt (Yes/No) |
| Linux | the polkit dialog (pkexec); without polkit fall back to sudo |
The helper is this same script/executable started with --querier-helper; it
streams the parsed queries back to the (unprivileged) app over a loopback TCP
connection secured with a one-time token, and it exits when the app closes.
You are asked once per session — stop/start of the analysis re-uses the
helper. If the app already runs elevated (e.g. sudo), no dialog appears.
macOS note: a root process started this way may not read files inside
~/Documents, ~/Desktop, ~/Downloads (privacy protection, TCC). If the
app/script lives there, the tool copies itself to a temp folder for the
helper automatically; from /Applications it runs directly.
General queries typically arrive only every 60–125 s — wait a moment after starting the analysis. Joins/statistics never need elevated privileges.
Unsigned PyInstaller executables are sometimes flagged by heuristics. The
release build minimises this (bootloader compiled from source, version
metadata), and ships two layouts: the single-file .exe and the
-folder.zip. If your scanner flags the single exe, try the folder zip (or
vice versa). If it still complains: the build is fully transparent in the
public GitHub Actions log, or build it yourself with build_windows.bat;
report the false positive to your AV vendor (Microsoft:
https://www.microsoft.com/wdsi/filesubmission); or run the Python file
directly, py igmp_join_gui.py, which needs no build at all.
Note: if the antivirus quarantines _internal\python3xx.dll from the folder
build, the exe fails with "failed to load python3xx.dll" — restore the file
or use the single-file exe instead.
- Whether IGMPv2 or v3 is sent is decided by the OS stack (or the querier on the network). SSM joins require IGMPv3 on the path to the router.
- Verify memberships: macOS
netstat -gn, Linuxip maddr/cat /proc/net/igmp, Windowsnetsh interface ipv4 show joins. - A firewall exception for Python may be needed when using receive statistics (port).
- Unhandled errors are written to
igmp-test-tool-crash.login the temp directory (Windows:%TEMP%, macOS/Linux:$TMPDIR//tmp).