Skip to content

Ephpotle/opnsense-iptv-helper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OPNsense IPTV Helper

A kernel-level multicast forwarding helper for IPTV on FreeBSD/OPNsense routers.

Problem

Some ISPs (like Bahnhof/Tele2 in Sweden) send IGMP packets with TOS 0xc0 (DSCP CS6). FreeBSD's raw sockets don't deliver these high-priority IGMP packets to userspace applications, making standard IGMP proxies unable to detect when TV boxes want to join/leave multicast groups.

This helper works around the issue by:

  1. Using tcpdump to capture IGMP traffic from the LAN interface
  2. Sending IGMP membership reports to the ISP on the WAN interface
  3. Using FreeBSD's kernel Multicast Routing Table (MRT) for efficient packet forwarding

Requirements

  • FreeBSD 14+ or OPNsense 24+
  • Python 3.9+
  • Root privileges (for MRT and raw sockets)
  • tcpdump installed

Installation

# Install dependencies
pkg install python3 py311-scapy py311-yaml

# Or via pip
pip install -r requirements.txt

# Copy to system location
cp iptv_helper.py /usr/local/bin/
chmod +x /usr/local/bin/iptv_helper.py

# Copy and edit configuration
cp config.yaml.example /usr/local/etc/iptv_helper.yaml
# Edit the configuration file for your setup

Configuration

Create a configuration file (YAML):

# Network interfaces
interfaces:
  wan: "igb0"     # WAN interface (connects to ISP)
  lan: "igb1"     # LAN interface (connects to TV box)

# Client configuration (TV boxes)
clients:
  - "192.168.1.100"
  - "192.168.1.101"  # Multiple clients supported

# Multicast settings
multicast:
  prefix: "234."    # Only forward groups matching this prefix

# Timing settings (in seconds)
timing:
  igmp_refresh: 30  # How often to refresh IGMP with ISP
  heartbeat: 300    # Status logging interval

# Logging settings
logging:
  level: "INFO"     # DEBUG, INFO, WARN, ERROR
  file: "/var/log/iptv_helper.log"  # Optional

Usage

Using configuration file

iptv_helper.py -c /usr/local/etc/iptv_helper.yaml

Using command-line arguments

iptv_helper.py --wan igb0 --lan igb1 --client 192.168.1.100

All options

Usage: iptv_helper.py [OPTIONS]

Options:
  -c, --config FILE     Path to YAML configuration file
  --wan IF              WAN interface name
  --lan IF              LAN interface name
  --client IP           Client IP address (can be repeated)
  --prefix PREFIX       Multicast prefix filter (default: 234.)
  --refresh SEC         IGMP refresh interval (default: 30)
  --heartbeat SEC       Heartbeat interval (default: 300)
  --log-level LEVEL     Log level: DEBUG, INFO, WARN, ERROR
  --log-file FILE       Log to file instead of stdout
  --version             Show version

Running as a Service

Using daemon (FreeBSD)

/usr/sbin/daemon -f /usr/local/bin/python3.11 /usr/local/bin/iptv_helper.py -c /usr/local/etc/iptv_helper.yaml

Watchdog cron job

Add to root's crontab:

*/5 * * * * pgrep -f 'python.*iptv_helper' || /usr/sbin/daemon -f /usr/local/bin/python3.11 /usr/local/bin/iptv_helper.py -c /usr/local/etc/iptv_helper.yaml

Important Notes

Stopping the Helper

Always use SIGTERM, never SIGKILL:

# Correct - allows cleanup
pkill -f 'python.*iptv_helper'

# WRONG - orphans MRT socket, requires reboot
pkill -9 -f 'python.*iptv_helper'

If you kill with -9, the kernel MRT socket becomes orphaned and the only fix is a router reboot.

Disabling igmpproxy

This helper is incompatible with igmpproxy. Only one process can hold the MRT socket. To disable:

  1. OPNsense Web UI: Services -> IGMP Proxy -> Disable
  2. Command line: sysrc igmpproxy_enable="NO"

Both steps are required for a complete disable.

How It Works

  1. IGMP Capture: Uses tcpdump to monitor IGMP traffic from configured clients on the LAN interface

  2. Group Tracking: When a client sends an IGMP Report (join), the helper:

    • Records the group as active
    • Sends an IGMP Report to the ISP on the WAN interface
    • Waits for the kernel to request routing via upcall
  3. Kernel MRT: When multicast packets arrive for an active group:

    • Kernel sends NOCACHE upcall
    • Helper adds MFC (Multicast Forwarding Cache) entry
    • Kernel forwards packets directly (no userspace copying)
  4. IGMP Refresh: Periodically resends IGMP Reports to the ISP to maintain stream

  5. Leave Handling: When a client sends IGMP Leave:

    • Removes MFC entries
    • Sends IGMP Leave to ISP
    • Stops tracking the group

Troubleshooting

Check if helper is running

pgrep -lf iptv_helper

View logs

tail -f /var/log/iptv_helper.log
# or if logging to stdout:
tail -f /tmp/iptv_helper.log

Check multicast routing

netstat -gn   # Show multicast groups
netstat -rn   # Show routes

Verify MFC entries

Look for "Out-Vifs:Ttls" showing "1:1" indicating LAN forwarding is active.

Common issues

"Address already in use": Another process holds the MRT socket. Check for:

  • igmpproxy running
  • Previous helper instance not cleaned up (reboot required)

No video: Check:

  • Helper is running
  • Correct interfaces configured
  • ISP is sending multicast (tcpdump on WAN)
  • Client is sending IGMP (tcpdump on LAN)

License

MIT License

About

Kernel MRT multicast forwarder for IPTV on FreeBSD/OPNsense

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages