#!/usr/bin/env python3 # SPDX-License-Identifier: ISC # # Copyright (C) 2021 by # Network Device Education Foundation, Inc. ("NetDEF") """ Subscribe to a multicast group so that the kernel sends an IGMP JOIN for the multicast group we subscribed to. """ import argparse import json import ipaddress import os import socket import struct import subprocess import sys import time # # Functions # def interface_name_to_index(name): "Gets the interface index using its name. Returns None on failure." interfaces = json.loads(subprocess.check_output("ip -j link show", shell=True)) for interface in interfaces: if interface["ifname"] == name: return interface["ifindex"] return None def interface_index_to_address(index, iptype="inet"): "Gets the interface main address using its name. Returns None on failure." interfaces = json.loads(subprocess.check_output("ip -j addr show", shell=True)) for interface in interfaces: if interface["ifindex"] == index: break for address in interface["addr_info"]: if address["family"] == iptype: break local_address = ipaddress.ip_address(address["local"]) return local_address.packed def group_source_req(ifindex, group, source): "Packs the information into 'struct group_source_req' format." mreq = struct.pack(" 0: # Prepare multicast bit in that interface. msock.setsockopt( socket.SOL_SOCKET, 25, struct.pack("%ds" % len(args.interface), args.interface.encode("utf-8")), ) # Set packets TTL/hops. ttlopt = socket.IP_MULTICAST_TTL if ip_version == 4 else socket.IPV6_MULTICAST_HOPS if ip_version == 4: msock.setsockopt(ip_proto, ttlopt, struct.pack("B", args.ttl)) else: msock.setsockopt(ip_proto, ttlopt, struct.pack("I", args.ttl)) # Block to ensure packet send. msock.setblocking(True) else: multicast_join(msock, ifindex, args.group, args.port, args.source) def should_exit(): if not toposock: # If we are sending then we have slept if not args.send: time.sleep(100) return False else: try: data = toposock.recv(1) if data == b"": print(" -> Connection closed") return True except BlockingIOError: return False counter = 0 while not should_exit(): if args.send > 0: msock.sendto(b"test %d" % counter, (str(args.group), args.port)) counter += 1 time.sleep(args.send) msock.close() sys.exit(0)