#!/usr/bin/env python3 # # Copyright (c) 2020, The OpenThread Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of the copyright holder nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # import ctypes import ctypes.util import socket import struct import sys import time MYPORT = 8123 MYTTL = 1 # Increase to reach other networks libc = ctypes.CDLL(ctypes.util.find_library('c')) def if_nametoindex(name): if not isinstance(name, str): raise TypeError('name must be a string.') ret = libc.if_nametoindex(name.encode('ascii')) if not ret: raise RuntimeError("Invalid Name") return ret def if_indextoname(index): if not isinstance(index, int): raise TypeError('index must be an int.') libc.if_indextoname.argtypes = [ctypes.c_uint32, ctypes.c_char_p] libc.if_indextoname.restype = ctypes.c_char_p ifname = ctypes.create_string_buffer(32) ifname = libc.if_indextoname(index, ifname) if not ifname: raise RuntimeError("Invalid Index") return ifname def main(): args = sys.argv[1:] is_sender = False if args[0] == '-s': is_sender = True args.pop(0) elif args[0] == '-u': is_multicast_receiver = False args.pop(0) else: is_multicast_receiver = True ifname, group = args if is_sender: sender(ifname, group) else: receiver(ifname, group, is_multicast_receiver=is_multicast_receiver) def sender(ifname, group): addrinfo = socket.getaddrinfo(group, None)[0] s = socket.socket(addrinfo[0], socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, (ifname + '\0').encode('ascii')) # Set Time-to-live (optional) ttl_bin = struct.pack('@i', MYTTL) assert addrinfo[0] == socket.AF_INET6 s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl_bin) while True: data = repr(time.time()) s.sendto((data + '\0').encode('ascii'), (addrinfo[4][0], MYPORT)) time.sleep(1) def receiver(ifname, group, is_multicast_receiver=True): # Look up multicast group address in name server and find out IP version addrinfo = socket.getaddrinfo(group, None)[0] assert addrinfo[0] == socket.AF_INET6 # Create a socket s = socket.socket(addrinfo[0], socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, (ifname + '\0').encode('ascii')) # Allow multiple copies of this program on one machine # (not strictly needed) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Bind it to the port s.bind(('', MYPORT)) if is_multicast_receiver: group_bin = socket.inet_pton(addrinfo[0], addrinfo[4][0]) # Join group interface_index = if_nametoindex(ifname) mreq = group_bin + struct.pack('@I', interface_index) s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq) # Loop, printing any data we receive while True: data, sender = s.recvfrom(1500) while data[-1:] == '\0': data = data[:-1] # Strip trailing \0's print(str(sender) + ' ' + repr(data)) if __name__ == '__main__': main()