diff --git a/pimdm/Config.py b/pimdm/Config.py index 0e96947..8e8ede3 100644 --- a/pimdm/Config.py +++ b/pimdm/Config.py @@ -1,7 +1,7 @@ import yaml from pimdm.tree import pim_globals -from pimdm.igmp import igmp_globals -from pimdm.mld import mld_globals +from igmp.igmp2 import igmp_globals +from mld.mld1 import mld_globals from pimdm import Main diff --git a/pimdm/InterfaceIGMP.py b/pimdm/InterfaceIGMP.py deleted file mode 100644 index 887706b..0000000 --- a/pimdm/InterfaceIGMP.py +++ /dev/null @@ -1,114 +0,0 @@ -import socket -import struct -from ipaddress import IPv4Address -from ctypes import create_string_buffer, addressof -import netifaces -from pimdm.Interface import Interface -from pimdm.packet.ReceivedPacket import ReceivedPacket -from pimdm.igmp.igmp_globals import VERSION_1_MEMBERSHIP_REPORT, VERSION_2_MEMBERSHIP_REPORT, LEAVE_GROUP, \ - MEMBERSHIP_QUERY -if not hasattr(socket, 'SO_BINDTODEVICE'): - socket.SO_BINDTODEVICE = 25 - - -class InterfaceIGMP(Interface): - ETH_P_IP = 0x0800 # Internet Protocol packet - SO_ATTACH_FILTER = 26 - - FILTER_IGMP = [ - struct.pack('HBBI', 0x28, 0, 0, 0x0000000c), - struct.pack('HBBI', 0x15, 0, 3, 0x00000800), - struct.pack('HBBI', 0x30, 0, 0, 0x00000017), - struct.pack('HBBI', 0x15, 0, 1, 0x00000002), - struct.pack('HBBI', 0x6, 0, 0, 0x00040000), - struct.pack('HBBI', 0x6, 0, 0, 0x00000000), - ] - - def __init__(self, interface_name: str, vif_index: int): - # SEND SOCKET - snd_s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IGMP) - - # bind to interface - snd_s.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, str(interface_name + "\0").encode('utf-8')) - - # RECEIVE SOCKET - rcv_s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(InterfaceIGMP.ETH_P_IP)) - - # receive only IGMP packets by setting a BPF filter - bpf_filter = b''.join(InterfaceIGMP.FILTER_IGMP) - b = create_string_buffer(bpf_filter) - mem_addr_of_filters = addressof(b) - fprog = struct.pack('HL', len(InterfaceIGMP.FILTER_IGMP), mem_addr_of_filters) - rcv_s.setsockopt(socket.SOL_SOCKET, InterfaceIGMP.SO_ATTACH_FILTER, fprog) - - # bind to interface - rcv_s.bind((interface_name, 0x0800)) - super().__init__(interface_name=interface_name, recv_socket=rcv_s, send_socket=snd_s, vif_index=vif_index) - self.interface_enabled = True - from pimdm.igmp.RouterState import RouterState - self.interface_state = RouterState(self) - super()._enable() - - def get_ip(self): - return netifaces.ifaddresses(self.interface_name)[netifaces.AF_INET][0]['addr'] - - @property - def ip_interface(self): - """ - Get IP of this interface - """ - return self.get_ip() - - def send(self, data: bytes, address: str="224.0.0.1"): - super().send(data, address) - - def _receive(self, raw_bytes, ancdata, src_addr): - if raw_bytes: - raw_bytes = raw_bytes[14:] - packet = ReceivedPacket(raw_bytes, self) - ip_src = packet.ip_header.ip_src - if not (ip_src == "0.0.0.0" or IPv4Address(ip_src).is_multicast): - self.PKT_FUNCTIONS.get(packet.payload.get_igmp_type(), InterfaceIGMP.receive_unknown_type)(self, packet) - - ########################################### - # Recv packets - ########################################### - def receive_version_1_membership_report(self, packet): - ip_dst = packet.ip_header.ip_dst - igmp_group = packet.payload.group_address - if ip_dst == igmp_group and IPv4Address(igmp_group).is_multicast: - self.interface_state.receive_v1_membership_report(packet) - - def receive_version_2_membership_report(self, packet): - ip_dst = packet.ip_header.ip_dst - igmp_group = packet.payload.group_address - if ip_dst == igmp_group and IPv4Address(igmp_group).is_multicast: - self.interface_state.receive_v2_membership_report(packet) - - def receive_leave_group(self, packet): - ip_dst = packet.ip_header.ip_dst - igmp_group = packet.payload.group_address - if ip_dst == "224.0.0.2" and IPv4Address(igmp_group).is_multicast: - self.interface_state.receive_leave_group(packet) - - def receive_membership_query(self, packet): - ip_dst = packet.ip_header.ip_dst - igmp_group = packet.payload.group_address - if (IPv4Address(igmp_group).is_multicast and ip_dst == igmp_group) or \ - (ip_dst == "224.0.0.1" and igmp_group == "0.0.0.0"): - self.interface_state.receive_query(packet) - - def receive_unknown_type(self, packet): - return - - PKT_FUNCTIONS = { - VERSION_1_MEMBERSHIP_REPORT: receive_version_1_membership_report, - VERSION_2_MEMBERSHIP_REPORT: receive_version_2_membership_report, - LEAVE_GROUP: receive_leave_group, - MEMBERSHIP_QUERY: receive_membership_query, - } - - ################## - def remove(self): - super().remove() - self.interface_state.remove() diff --git a/pimdm/InterfaceMLD.py b/pimdm/InterfaceMLD.py deleted file mode 100644 index 37fadaf..0000000 --- a/pimdm/InterfaceMLD.py +++ /dev/null @@ -1,199 +0,0 @@ -import socket -import struct -import netifaces -import ipaddress -from socket import if_nametoindex -from ipaddress import IPv6Address -from .Interface import Interface -from .packet.ReceivedPacket import ReceivedPacket_v6 -from .mld.mld_globals import MULTICAST_LISTENER_QUERY_TYPE, MULTICAST_LISTENER_DONE_TYPE, MULTICAST_LISTENER_REPORT_TYPE -from ctypes import create_string_buffer, addressof - -ETH_P_IPV6 = 0x86DD # IPv6 over bluebook -SO_ATTACH_FILTER = 26 -ICMP6_FILTER = 1 -IPV6_ROUTER_ALERT = 22 - - -def ICMP6_FILTER_SETBLOCKALL(): - return struct.pack("I"*8, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) - - -def ICMP6_FILTER_SETPASS(type, filterp): - return filterp[:type >> 5] + (bytes([(filterp[type >> 5] & ~(1 << ((type) & 31)))])) + filterp[(type >> 5) + 1:] - - -class InterfaceMLD(Interface): - IPv6_LINK_SCOPE_ALL_NODES = IPv6Address("ff02::1") - IPv6_LINK_SCOPE_ALL_ROUTERS = IPv6Address("ff02::2") - IPv6_ALL_ZEROS = IPv6Address("::") - - FILTER_MLD = [ - struct.pack('HBBI', 0x28, 0, 0, 0x0000000c), - struct.pack('HBBI', 0x15, 0, 9, 0x000086dd), - struct.pack('HBBI', 0x30, 0, 0, 0x00000014), - struct.pack('HBBI', 0x15, 0, 7, 0x00000000), - struct.pack('HBBI', 0x30, 0, 0, 0x00000036), - struct.pack('HBBI', 0x15, 0, 5, 0x0000003a), - struct.pack('HBBI', 0x30, 0, 0, 0x0000003e), - struct.pack('HBBI', 0x15, 2, 0, 0x00000082), - struct.pack('HBBI', 0x15, 1, 0, 0x00000083), - struct.pack('HBBI', 0x15, 0, 1, 0x00000084), - struct.pack('HBBI', 0x6, 0, 0, 0x00040000), - struct.pack('HBBI', 0x6, 0, 0, 0x00000000), - ] - - def __init__(self, interface_name: str, vif_index: int): - # SEND SOCKET - s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6) - - # set socket output interface - if_index = if_nametoindex(interface_name) - s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, struct.pack('@I', if_index)) - - """ - # set ICMP6 filter to only receive MLD packets - icmp6_filter = ICMP6_FILTER_SETBLOCKALL() - icmp6_filter = ICMP6_FILTER_SETPASS(MULTICAST_LISTENER_QUERY_TYPE, icmp6_filter) - icmp6_filter = ICMP6_FILTER_SETPASS(MULTICAST_LISTENER_REPORT_TYPE, icmp6_filter) - icmp6_filter = ICMP6_FILTER_SETPASS(MULTICAST_LISTENER_DONE_TYPE, icmp6_filter) - s.setsockopt(socket.IPPROTO_ICMPV6, ICMP6_FILTER, icmp6_filter) - s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_RECVPKTINFO, True) - s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, False) - s.setsockopt(socket.IPPROTO_IPV6, self.IPV6_ROUTER_ALERT, 0) - rcv_s = s - """ - - ip_interface = "::" - for if_addr in netifaces.ifaddresses(interface_name)[netifaces.AF_INET6]: - ip_interface = if_addr["addr"] - if ipaddress.IPv6Address(ip_interface.split("%")[0]).is_link_local: - # bind to interface - s.bind(socket.getaddrinfo(ip_interface, None, 0, socket.SOCK_RAW, 0, socket.AI_PASSIVE)[0][4]) - ip_interface = ip_interface.split("%")[0] - break - self.ip_interface = ip_interface - - # RECEIVE SOCKET - rcv_s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_IPV6)) - - # receive only MLD packets by setting a BPF filter - bpf_filter = b''.join(InterfaceMLD.FILTER_MLD) - b = create_string_buffer(bpf_filter) - mem_addr_of_filters = addressof(b) - fprog = struct.pack('HL', len(InterfaceMLD.FILTER_MLD), mem_addr_of_filters) - rcv_s.setsockopt(socket.SOL_SOCKET, SO_ATTACH_FILTER, fprog) - - # bind to interface - rcv_s.bind((interface_name, ETH_P_IPV6)) - - super().__init__(interface_name=interface_name, recv_socket=rcv_s, send_socket=s, vif_index=vif_index) - self.interface_enabled = True - from .mld.RouterState import RouterState - self.interface_state = RouterState(self) - super()._enable() - - @staticmethod - def _get_address_family(): - return socket.AF_INET6 - - def get_ip(self): - return self.ip_interface - - def send(self, data: bytes, address: str = "FF02::1"): - # send router alert option - cmsg_level = socket.IPPROTO_IPV6 - cmsg_type = socket.IPV6_HOPOPTS - cmsg_data = b'\x3a\x00\x05\x02\x00\x00\x01\x00' - self._send_socket.sendmsg([data], [(cmsg_level, cmsg_type, cmsg_data)], 0, (address, 0)) - - """ - def receive(self): - while self.interface_enabled: - try: - (raw_bytes, ancdata, _, src_addr) = self._recv_socket.recvmsg(256 * 1024, 500) - if raw_bytes: - self._receive(raw_bytes, ancdata, src_addr) - except Exception: - import traceback - traceback.print_exc() - continue - """ - - def _receive(self, raw_bytes, ancdata, src_addr): - if raw_bytes: - raw_bytes = raw_bytes[14:] - src_addr = (socket.inet_ntop(socket.AF_INET6, raw_bytes[8:24]),) - print("MLD IP_SRC bf= ", src_addr) - dst_addr = raw_bytes[24:40] - (next_header,) = struct.unpack("B", raw_bytes[6:7]) - print("NEXT HEADER:", next_header) - payload_starts_at_len = 40 - if next_header == 0: - # Hop by Hop options - (next_header,) = struct.unpack("B", raw_bytes[40:41]) - if next_header != 58: - return - (hdr_ext_len,) = struct.unpack("B", raw_bytes[payload_starts_at_len +1:payload_starts_at_len + 2]) - if hdr_ext_len > 0: - payload_starts_at_len = payload_starts_at_len + 1 + hdr_ext_len*8 - else: - payload_starts_at_len = payload_starts_at_len + 8 - - raw_bytes = raw_bytes[payload_starts_at_len:] - ancdata = [(socket.IPPROTO_IPV6, socket.IPV6_PKTINFO, dst_addr)] - print("RECEIVE MLD") - print("ANCDATA: ", ancdata, "; SRC_ADDR: ", src_addr) - packet = ReceivedPacket_v6(raw_bytes, ancdata, src_addr, 58, self) - ip_src = packet.ip_header.ip_src - print("MLD IP_SRC = ", ip_src) - if not (ip_src == "::" or IPv6Address(ip_src).is_multicast): - self.PKT_FUNCTIONS.get(packet.payload.get_mld_type(), InterfaceMLD.receive_unknown_type)(self, packet) - """ - def _receive(self, raw_bytes, ancdata, src_addr): - if raw_bytes: - packet = ReceivedPacket_v6(raw_bytes, ancdata, src_addr, 58, self) - self.PKT_FUNCTIONS[packet.payload.get_mld_type(), InterfaceMLD.receive_unknown_type](self, packet) - """ - ########################################### - # Recv packets - ########################################### - def receive_multicast_listener_report(self, packet): - print("RECEIVE MULTICAST LISTENER REPORT") - ip_dst = packet.ip_header.ip_dst - mld_group = packet.payload.group_address - ipv6_group = IPv6Address(mld_group) - ipv6_dst = IPv6Address(ip_dst) - if ipv6_dst == ipv6_group and ipv6_group.is_multicast: - self.interface_state.receive_report(packet) - - def receive_multicast_listener_done(self, packet): - print("RECEIVE MULTICAST LISTENER DONE") - ip_dst = packet.ip_header.ip_dst - mld_group = packet.payload.group_address - if IPv6Address(ip_dst) == self.IPv6_LINK_SCOPE_ALL_ROUTERS and IPv6Address(mld_group).is_multicast: - self.interface_state.receive_done(packet) - - def receive_multicast_listener_query(self, packet): - print("RECEIVE MULTICAST LISTENER QUERY") - ip_dst = packet.ip_header.ip_dst - mld_group = packet.payload.group_address - ipv6_group = IPv6Address(mld_group) - ipv6_dst = IPv6Address(ip_dst) - if (ipv6_group.is_multicast and ipv6_dst == ipv6_group) or\ - (ipv6_dst == self.IPv6_LINK_SCOPE_ALL_NODES and ipv6_group == self.IPv6_ALL_ZEROS): - self.interface_state.receive_query(packet) - - def receive_unknown_type(self, packet): - raise Exception("UNKNOWN MLD TYPE: " + str(packet.payload.get_mld_type())) - - PKT_FUNCTIONS = { - MULTICAST_LISTENER_REPORT_TYPE: receive_multicast_listener_report, - MULTICAST_LISTENER_DONE_TYPE: receive_multicast_listener_done, - MULTICAST_LISTENER_QUERY_TYPE: receive_multicast_listener_query, - } - - ################## - def remove(self): - super().remove() - self.interface_state.remove() diff --git a/pimdm/InterfacePIM.py b/pimdm/InterfacePIM.py index 7c5472a..8e786ec 100644 --- a/pimdm/InterfacePIM.py +++ b/pimdm/InterfacePIM.py @@ -78,7 +78,7 @@ def __init__(self, interface_name: str, vif_index:int, state_refresh_capable:boo # don't receive outgoing packets s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 0) - #self.drop_packet_type = None + self.drop_packet_type = None super().__init__(interface_name, s, s, vif_index) super()._enable() @@ -109,9 +109,11 @@ def send(self, data: bytes, group_ip: str=MCAST_GRP): """ Send a new packet destined to group_ip IP """ - #if self.drop_packet_type is not None and data.payload.get_pim_type() == self.drop_packet_type: - # self.drop_packet_type = None - # return + packet = PacketPimHeader.parse_bytes(data) + if self.drop_packet_type is not None: + if packet.get_pim_type() == self.drop_packet_type: + self.drop_packet_type = None + return super().send(data=data, group_ip=group_ip) @@ -199,15 +201,13 @@ def get_neighbors(self): """ Get list of known neighbors """ - with self.neighbors_lock.genRlock(): - return self.neighbors.values() + return list(self.neighbors.values()) def get_neighbor(self, ip): """ Get specific neighbor by its IP """ - with self.neighbors_lock.genRlock(): - return self.neighbors.get(ip) + return self.neighbors.get(ip) def remove_neighbor(self, ip): """ diff --git a/pimdm/Kernel.py b/pimdm/Kernel.py index 00a45c1..d91faeb 100644 --- a/pimdm/Kernel.py +++ b/pimdm/Kernel.py @@ -11,8 +11,8 @@ from pimdm.rwlock.RWLock import RWLockWrite from pimdm.tree import pim_globals -from pimdm.InterfaceMLD import InterfaceMLD -from pimdm.InterfaceIGMP import InterfaceIGMP +from mld.InterfaceMLD import InterfaceMLD +from igmp.InterfaceIGMP import InterfaceIGMP from pimdm.InterfacePIM import InterfacePim from pimdm.InterfacePIM6 import InterfacePim6 from pimdm.tree.KernelEntry import KernelEntry @@ -113,14 +113,14 @@ def create_membership_interface(self, interface_name: str): else: index = list(range(0, self.MAXVIFS) - self.vif_index_to_name_dic.keys())[0] - ip_interface = None if interface_name not in self.membership_interface: - igmp_interface = self._create_membership_interface_object(interface_name, index) - self.membership_interface[interface_name] = igmp_interface - ip_interface = igmp_interface.ip_interface + membership_interface = self._create_membership_interface_object(interface_name, index) + self.membership_interface[interface_name] = membership_interface + ip_interface = membership_interface.ip_interface - if not vif_already_exists: - self.create_virtual_interface(ip_interface=ip_interface, interface_name=interface_name, index=index) + if not vif_already_exists: + self.create_virtual_interface(ip_interface=ip_interface, interface_name=interface_name, index=index) + membership_interface.enable() @abstractmethod def _create_membership_interface_object(self, interface_name, index): diff --git a/pimdm/Main.py b/pimdm/Main.py index 42d0e89..f09ff72 100644 --- a/pimdm/Main.py +++ b/pimdm/Main.py @@ -226,6 +226,8 @@ def get_config(): return Config.get_yaml_file() except ModuleNotFoundError: return "PYYAML needs to be installed. Execute \"pip3 install pyyaml\"" + except ImportError: + return "PYYAML needs to be installed. Execute \"pip3 install pyyaml\"" def set_config(file_path): @@ -264,8 +266,19 @@ def main(): # logging global logger logger = logging.getLogger('pim') + mld_logger = logging.getLogger('mld') + igmp_logger = logging.getLogger('igmp') logger.setLevel(logging.DEBUG) - logger.addHandler(logging.StreamHandler(sys.stdout)) + igmp_logger.setLevel(logging.DEBUG) + mld_logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler(sys.stdout) + handler.addFilter(RootFilter("")) + handler.setLevel(logging.DEBUG) + handler.setFormatter(logging.Formatter('%(asctime)-20s %(name)-50s %(tree)-35s %(vif)-2s %(interfacename)-5s ' + '%(routername)-2s %(message)s')) + logger.addHandler(handler) + igmp_logger.addHandler(handler) + mld_logger.addHandler(handler) global kernel from pimdm.Kernel import Kernel4 diff --git a/pimdm/Run.py b/pimdm/Run.py index 1889de2..fd3ec48 100644 --- a/pimdm/Run.py +++ b/pimdm/Run.py @@ -15,7 +15,7 @@ from pimdm.tree import pim_globals from pimdm.daemon.Daemon import Daemon -VERSION = "1.2" +VERSION = "1.3" def client_socket(data_to_send, print_output=True): @@ -156,7 +156,7 @@ def main(): group.add_argument("-v", "--verbose", action="store_true", default=False, help="Verbose (print all debug messages)") group.add_argument("-t", "--test", nargs=2, metavar=('ROUTER_NAME', 'SERVER_LOG_IP'), help="Tester... send log information to SERVER_LOG_IP. Set the router name to ROUTER_NAME") group.add_argument("-config", "--config", nargs=1, metavar='CONFIG_FILE_PATH', type=str, - help="File path for configuration file. This command should only be used with -start") + help="File path for configuration file.") group.add_argument("-get_config", "--get_config", action="store_true", default=False, help="Get configuration file of live daemon.") #group.add_argument("-drop", "--drop", nargs=2, metavar=('INTERFACE_NAME', 'PACKET_TYPE'), type=str) @@ -229,6 +229,9 @@ def main(): except ModuleNotFoundError: print("PYYAML needs to be installed. Execute \"pip3 install pyyaml\"") sys.exit(0) + except ImportError: + print("PYYAML needs to be installed. Execute \"pip3 install pyyaml\"") + sys.exit(0) elif args.verbose: os.system("tail -f {}".format(pim_globals.DAEMON_LOG_STDOUT_FILE.format(pim_globals.MULTICAST_TABLE_ID))) sys.exit(0) diff --git a/pimdm/igmp/GroupState.py b/pimdm/igmp/GroupState.py deleted file mode 100644 index 5fb30b1..0000000 --- a/pimdm/igmp/GroupState.py +++ /dev/null @@ -1,225 +0,0 @@ -import logging -from threading import Lock -from threading import Timer - -from pimdm.utils import TYPE_CHECKING -from .wrapper import NoMembersPresent -from .igmp_globals import GROUP_MEMBERSHIP_INTERVAL, LAST_MEMBER_QUERY_INTERVAL - -if TYPE_CHECKING: - from .RouterState import RouterState - - -class GroupState(object): - LOGGER = logging.getLogger('pim.igmp.RouterState.GroupState') - - def __init__(self, router_state: 'RouterState', group_ip: str): - #logger - extra_dict_logger = router_state.router_state_logger.extra.copy() - extra_dict_logger['tree'] = '(*,' + group_ip + ')' - self.group_state_logger = logging.LoggerAdapter(GroupState.LOGGER, extra_dict_logger) - - #timers and state - self.router_state = router_state - self.group_ip = group_ip - self.state = NoMembersPresent - self.timer = None - self.v1_host_timer = None - self.retransmit_timer = None - # lock - self.lock = Lock() - - # KernelEntry's instances to notify change of igmp state - self.multicast_interface_state = [] - self.multicast_interface_state_lock = Lock() - - def print_state(self): - return self.state.print_state() - - ########################################### - # Set state - ########################################### - def set_state(self, state): - """ - Set membership state regarding this Group - """ - self.state = state - self.group_state_logger.debug("change membership state to: " + state.print_state()) - - ########################################### - # Set timers - ########################################### - def set_timer(self, alternative: bool = False, max_response_time: int = None): - """ - Set timer - """ - self.clear_timer() - if not alternative: - time = GROUP_MEMBERSHIP_INTERVAL - else: - time = self.router_state.interface_state.get_group_membership_time(max_response_time) - - timer = Timer(time, self.group_membership_timeout) - timer.start() - self.timer = timer - - def clear_timer(self): - """ - Stop timer - """ - if self.timer is not None: - self.timer.cancel() - - def set_v1_host_timer(self): - """ - Set v1 host timer - """ - self.clear_v1_host_timer() - v1_host_timer = Timer(GROUP_MEMBERSHIP_INTERVAL, self.group_membership_v1_timeout) - v1_host_timer.start() - self.v1_host_timer = v1_host_timer - - def clear_v1_host_timer(self): - """ - Stop v1 host timer - """ - if self.v1_host_timer is not None: - self.v1_host_timer.cancel() - - def set_retransmit_timer(self): - """ - Set retransmit timer - """ - self.clear_retransmit_timer() - retransmit_timer = Timer(LAST_MEMBER_QUERY_INTERVAL, self.retransmit_timeout) - retransmit_timer.start() - self.retransmit_timer = retransmit_timer - - def clear_retransmit_timer(self): - """ - Stop retransmit timer - """ - if self.retransmit_timer is not None: - self.retransmit_timer.cancel() - - ########################################### - # Get group state from specific interface state - ########################################### - def get_interface_group_state(self): - """ - Get specific implementation of the membership state machine (depending on the querier state machine) - """ - return self.state.get_state(self.router_state) - - ########################################### - # Timer timeout - ########################################### - def group_membership_timeout(self): - """ - Timer has expired - """ - with self.lock: - self.get_interface_group_state().group_membership_timeout(self) - - def group_membership_v1_timeout(self): - """ - v1 host timer has expired - """ - with self.lock: - self.get_interface_group_state().group_membership_v1_timeout(self) - - def retransmit_timeout(self): - """ - Retransmit timer has expired - """ - with self.lock: - self.get_interface_group_state().retransmit_timeout(self) - - ########################################### - # Receive Packets - ########################################### - def receive_v1_membership_report(self): - """ - Received IGMP Version 1 Membership Report packet regarding this group - """ - with self.lock: - self.get_interface_group_state().receive_v1_membership_report(self) - - def receive_v2_membership_report(self): - """ - Received IGMP Membership Report packet regarding this group - """ - with self.lock: - self.get_interface_group_state().receive_v2_membership_report(self) - - def receive_leave_group(self): - """ - Received IGMP Leave packet regarding this group - """ - with self.lock: - self.get_interface_group_state().receive_leave_group(self) - - def receive_group_specific_query(self, max_response_time: int): - """ - Received IGMP Group Specific Query packet regarding this group - """ - with self.lock: - self.get_interface_group_state().receive_group_specific_query(self, max_response_time) - - ########################################### - # Notify Routing - ########################################### - def notify_routing_add(self): - """ - Notify all tree entries that IGMP considers to have hosts interested in this group - """ - with self.multicast_interface_state_lock: - print("notify+", self.multicast_interface_state) - for interface_state in self.multicast_interface_state: - interface_state.notify_membership(has_members=True) - - def notify_routing_remove(self): - """ - Notify all tree entries that IGMP considers to have not hosts interested in this group - """ - with self.multicast_interface_state_lock: - print("notify-", self.multicast_interface_state) - for interface_state in self.multicast_interface_state: - interface_state.notify_membership(has_members=False) - - def add_multicast_routing_entry(self, kernel_entry): - """ - A new tree is being monitored by the multicast routing protocol that has the same group - IGMP will store these entries in order to accelerate the notification process regarding changes in IGMP state - """ - with self.multicast_interface_state_lock: - self.multicast_interface_state.append(kernel_entry) - return self.has_members() - - def remove_multicast_routing_entry(self, kernel_entry): - """ - A tree is no longer being monitored by the multicast routing protocol - Remove this tree from this object - """ - with self.multicast_interface_state_lock: - self.multicast_interface_state.remove(kernel_entry) - - def has_members(self): - """ - Determine if IGMP considers to have hosts interested in receiving data packets - """ - return self.state is not NoMembersPresent - - def remove(self): - """ - Remove this group from the IGMP process - Notify all trees that this group no longer considers to be connected to hosts - This method will be invoked whenever an IGMP interface is removed - """ - with self.multicast_interface_state_lock: - self.clear_retransmit_timer() - self.clear_timer() - self.clear_v1_host_timer() - for interface_state in self.multicast_interface_state: - interface_state.notify_membership(has_members=False) - del self.multicast_interface_state[:] diff --git a/pimdm/igmp/RouterState.py b/pimdm/igmp/RouterState.py deleted file mode 100644 index bff57b5..0000000 --- a/pimdm/igmp/RouterState.py +++ /dev/null @@ -1,173 +0,0 @@ -from threading import Timer -import logging - -from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader -from pimdm.packet.ReceivedPacket import ReceivedPacket -from pimdm.utils import TYPE_CHECKING -from pimdm.rwlock.RWLock import RWLockWrite -from .querier.Querier import Querier -from .nonquerier.NonQuerier import NonQuerier -from .GroupState import GroupState -from .igmp_globals import MEMBERSHIP_QUERY, QUERY_RESPONSE_INTERVAL, QUERY_INTERVAL, OTHER_QUERIER_PRESENT_INTERVAL - -if TYPE_CHECKING: - from pimdm.InterfaceIGMP import InterfaceIGMP - - -class RouterState(object): - ROUTER_STATE_LOGGER = logging.getLogger('pim.igmp.RouterState') - - def __init__(self, interface: 'InterfaceIGMP'): - #logger - logger_extra = dict() - logger_extra['vif'] = interface.vif_index - logger_extra['interfacename'] = interface.interface_name - self.router_state_logger = logging.LoggerAdapter(RouterState.ROUTER_STATE_LOGGER, logger_extra) - - # interface of the router connected to the network - self.interface = interface - - # state of the router (Querier/NonQuerier) - self.interface_state = Querier - - # state of each group - # Key: GroupIPAddress, Value: GroupState object - self.group_state = {} - self.group_state_lock = RWLockWrite() - - # send general query - packet = PacketIGMPHeader(type=MEMBERSHIP_QUERY, max_resp_time=QUERY_RESPONSE_INTERVAL * 10) - self.interface.send(packet.bytes()) - - # set initial general query timer - timer = Timer(QUERY_INTERVAL, self.general_query_timeout) - timer.start() - self.general_query_timer = timer - - # present timer - self.other_querier_present_timer = None - - # Send packet via interface - def send(self, data: bytes, address: str): - self.interface.send(data, address) - - ############################################ - # interface_state methods - ############################################ - def print_state(self): - return self.interface_state.state_name() - - def set_general_query_timer(self): - """ - Set general query timer - """ - self.clear_general_query_timer() - general_query_timer = Timer(QUERY_INTERVAL, self.general_query_timeout) - general_query_timer.start() - self.general_query_timer = general_query_timer - - def clear_general_query_timer(self): - """ - Stop general query timer - """ - if self.general_query_timer is not None: - self.general_query_timer.cancel() - - def set_other_querier_present_timer(self): - """ - Set other querier present timer - """ - self.clear_other_querier_present_timer() - other_querier_present_timer = Timer(OTHER_QUERIER_PRESENT_INTERVAL, self.other_querier_present_timeout) - other_querier_present_timer.start() - self.other_querier_present_timer = other_querier_present_timer - - def clear_other_querier_present_timer(self): - """ - Stop other querier present timer - """ - if self.other_querier_present_timer is not None: - self.other_querier_present_timer.cancel() - - def general_query_timeout(self): - """ - General Query timer has expired - """ - self.interface_state.general_query_timeout(self) - - def other_querier_present_timeout(self): - """ - Other Querier Present timer has expired - """ - self.interface_state.other_querier_present_timeout(self) - - def change_interface_state(self, querier: bool): - """ - Change state regarding querier state machine (Querier/NonQuerier) - """ - if querier: - self.interface_state = Querier - self.router_state_logger.debug('change querier state to -> Querier') - else: - self.interface_state = NonQuerier - self.router_state_logger.debug('change querier state to -> NonQuerier') - - ############################################ - # group state methods - ############################################ - def get_group_state(self, group_ip): - """ - Get object that monitors a given group (with group_ip IP address) - """ - with self.group_state_lock.genRlock(): - if group_ip in self.group_state: - return self.group_state[group_ip] - - with self.group_state_lock.genWlock(): - if group_ip in self.group_state: - group_state = self.group_state[group_ip] - else: - group_state = GroupState(self, group_ip) - self.group_state[group_ip] = group_state - return group_state - - def receive_v1_membership_report(self, packet: ReceivedPacket): - """ - Received IGMP Version 1 Membership Report packet - """ - igmp_group = packet.payload.group_address - self.get_group_state(igmp_group).receive_v1_membership_report() - - def receive_v2_membership_report(self, packet: ReceivedPacket): - """ - Received IGMP Membership Report packet - """ - igmp_group = packet.payload.group_address - self.get_group_state(igmp_group).receive_v2_membership_report() - - def receive_leave_group(self, packet: ReceivedPacket): - """ - Received IGMP Leave packet - """ - igmp_group = packet.payload.group_address - self.get_group_state(igmp_group).receive_leave_group() - - def receive_query(self, packet: ReceivedPacket): - """ - Received IGMP Query packet - """ - self.interface_state.receive_query(self, packet) - igmp_group = packet.payload.group_address - - # process group specific query - if igmp_group != "0.0.0.0" and igmp_group in self.group_state: - max_response_time = packet.payload.max_resp_time - self.get_group_state(igmp_group).receive_group_specific_query(max_response_time) - - def remove(self): - """ - Remove this IGMP interface - Clear all state - """ - for group in self.group_state.values(): - group.remove() diff --git a/pimdm/igmp/__init__.py b/pimdm/igmp/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pimdm/igmp/igmp_globals.py b/pimdm/igmp/igmp_globals.py deleted file mode 100644 index 18c5f66..0000000 --- a/pimdm/igmp/igmp_globals.py +++ /dev/null @@ -1,20 +0,0 @@ -# IGMP timers (in seconds) -ROBUSTNESS_VARIABLE = 2 -QUERY_INTERVAL = 125 -QUERY_RESPONSE_INTERVAL = 10 -MAX_RESPONSE_TIME_QUERY_RESPONSE_INTERVAL = QUERY_RESPONSE_INTERVAL * 10 -GROUP_MEMBERSHIP_INTERVAL = ROBUSTNESS_VARIABLE * QUERY_INTERVAL + QUERY_RESPONSE_INTERVAL -OTHER_QUERIER_PRESENT_INTERVAL = ROBUSTNESS_VARIABLE * QUERY_INTERVAL + QUERY_RESPONSE_INTERVAL / 2 -STARTUP_QUERY_INTERVAL = QUERY_INTERVAL / 4 -STARTUP_QUERY_COUNT = ROBUSTNESS_VARIABLE -LAST_MEMBER_QUERY_INTERVAL = 1 -MAX_RESPONSE_TIME_LAST_MEMBER_QUERY_INTERVAL = LAST_MEMBER_QUERY_INTERVAL * 10 -LAST_MEMBER_QUERY_COUNT = ROBUSTNESS_VARIABLE -UNSOLICITED_REPORT_INTERVAL = 10 -VERSION_1_ROUTER_PRESENT_TIMEOUT = 400 - -# IGMP msg type -MEMBERSHIP_QUERY = 0x11 -VERSION_1_MEMBERSHIP_REPORT = 0x12 -VERSION_2_MEMBERSHIP_REPORT = 0x16 -LEAVE_GROUP = 0x17 diff --git a/pimdm/igmp/nonquerier/CheckingMembership.py b/pimdm/igmp/nonquerier/CheckingMembership.py deleted file mode 100644 index fb24322..0000000 --- a/pimdm/igmp/nonquerier/CheckingMembership.py +++ /dev/null @@ -1,70 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -from ..wrapper import NoMembersPresent -from ..wrapper import MembersPresent - -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier CheckingMembership: group_membership_timeout') - group_state.set_state(NoMembersPresent) - - # NOTIFY ROUTING - !!!! - group_state.notify_routing_remove() - - -def group_membership_v1_timeout(group_state: 'GroupState'): - """ - v1 host timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier CheckingMembership: group_membership_v1_timeout') - # do nothing - return - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier CheckingMembership: retransmit_timeout') - # do nothing - return - - -def receive_v1_membership_report(group_state: 'GroupState'): - """ - Received IGMP Version 1 Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_v1_membership_report') - receive_v2_membership_report(group_state) - - -def receive_v2_membership_report(group_state: 'GroupState'): - """ - Received IGMP Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_v2_membership_report') - group_state.set_timer() - group_state.set_state(MembersPresent) - - -def receive_leave_group(group_state: 'GroupState'): - """ - Received IGMP Leave packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_leave_group') - # do nothing - return - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): - """ - Received IGMP Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier CheckingMembership: receive_group_specific_query') - # do nothing - return diff --git a/pimdm/igmp/nonquerier/MembersPresent.py b/pimdm/igmp/nonquerier/MembersPresent.py deleted file mode 100644 index 619cb2f..0000000 --- a/pimdm/igmp/nonquerier/MembersPresent.py +++ /dev/null @@ -1,69 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -from ..wrapper import NoMembersPresent -from ..wrapper import CheckingMembership - -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier MembersPresent: group_membership_timeout') - group_state.set_state(NoMembersPresent) - - # NOTIFY ROUTING - !!!! - group_state.notify_routing_remove() - - -def group_membership_v1_timeout(group_state: 'GroupState'): - """ - v1 host timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier MembersPresent: group_membership_v1_timeout') - # do nothing - return - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier MembersPresent: retransmit_timeout') - # do nothing - return - - -def receive_v1_membership_report(group_state: 'GroupState'): - """ - Received IGMP Version 1 Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_v1_membership_report') - receive_v2_membership_report(group_state) - - -def receive_v2_membership_report(group_state: 'GroupState'): - """ - Received IGMP Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_v2_membership_report') - group_state.set_timer() - - -def receive_leave_group(group_state: 'GroupState'): - """ - Received IGMP Leave packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_leave_group') - # do nothing - return - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): - """ - Received IGMP Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier MembersPresent: receive_group_specific_query') - group_state.set_timer(alternative=True, max_response_time=max_response_time) - group_state.set_state(CheckingMembership) diff --git a/pimdm/igmp/nonquerier/NoMembersPresent.py b/pimdm/igmp/nonquerier/NoMembersPresent.py deleted file mode 100644 index 40f01fa..0000000 --- a/pimdm/igmp/nonquerier/NoMembersPresent.py +++ /dev/null @@ -1,70 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -from ..wrapper import MembersPresent - -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier NoMembersPresent: group_membership_timeout') - # do nothing - return - - -def group_membership_v1_timeout(group_state: 'GroupState'): - """ - v1 host timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier NoMembersPresent: group_membership_v1_timeout') - # do nothing - return - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier NoMembersPresent: retransmit_timeout') - # do nothing - return - - -def receive_v1_membership_report(group_state: 'GroupState'): - """ - Received IGMP Version 1 Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_v1_membership_report') - receive_v2_membership_report(group_state) - - -def receive_v2_membership_report(group_state: 'GroupState'): - """ - Received IGMP Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_v2_membership_report') - group_state.set_timer() - group_state.set_state(MembersPresent) - - # NOTIFY ROUTING + !!!! - group_state.notify_routing_add() - - -def receive_leave_group(group_state: 'GroupState'): - """ - Received IGMP Leave packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_leave_group') - # do nothing - return - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): - """ - Received IGMP Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier NoMembersPresent: receive_group_specific_query') - # do nothing - return diff --git a/pimdm/igmp/nonquerier/NonQuerier.py b/pimdm/igmp/nonquerier/NonQuerier.py deleted file mode 100644 index 0fa4bd1..0000000 --- a/pimdm/igmp/nonquerier/NonQuerier.py +++ /dev/null @@ -1,94 +0,0 @@ -from ipaddress import IPv4Address -from pimdm.utils import TYPE_CHECKING -from pimdm.igmp.igmp_globals import MEMBERSHIP_QUERY, QUERY_RESPONSE_INTERVAL, LAST_MEMBER_QUERY_COUNT -from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader -from pimdm.packet.ReceivedPacket import ReceivedPacket -from . import NoMembersPresent, MembersPresent, CheckingMembership - -if TYPE_CHECKING: - from ..RouterState import RouterState - - -class NonQuerier: - - @staticmethod - def general_query_timeout(router_state: 'RouterState'): - """ - General Query timer has expired - """ - router_state.router_state_logger.debug('NonQuerier state: general_query_timeout') - # do nothing - return - - @staticmethod - def other_querier_present_timeout(router_state: 'RouterState'): - """ - Other Query Present timer has expired - """ - router_state.router_state_logger.debug('NonQuerier state: other_querier_present_timeout') - #change state to Querier - router_state.change_interface_state(querier=True) - - # send general query - packet = PacketIGMPHeader(type=MEMBERSHIP_QUERY, max_resp_time=QUERY_RESPONSE_INTERVAL * 10) - router_state.interface.send(packet.bytes()) - - # set general query timer - router_state.set_general_query_timer() - - @staticmethod - def receive_query(router_state: 'RouterState', packet: ReceivedPacket): - """ - Interface associated with RouterState is NonQuerier and received a Query packet - """ - router_state.router_state_logger.debug('NonQuerier state: receive_query') - source_ip = packet.ip_header.ip_src - - # if source ip of membership query not lower than the ip of the received interface => ignore - if IPv4Address(source_ip) >= IPv4Address(router_state.interface.get_ip()): - return - - # reset other present querier timer - router_state.set_other_querier_present_timer() - - # TODO ver se existe uma melhor maneira de fazer isto - @staticmethod - def state_name(): - return "Non Querier" - - @staticmethod - def get_group_membership_time(max_response_time: int): - """ - Get time to set timer* - """ - return (max_response_time/10.0) * LAST_MEMBER_QUERY_COUNT - - # State - @staticmethod - def get_checking_membership_state(): - """ - Get implementation of CheckingMembership state machine of interface in NonQuerier state - """ - return CheckingMembership - - @staticmethod - def get_members_present_state(): - """ - Get implementation of MembersPresent state machine of interface in NonQuerier state - """ - return MembersPresent - - @staticmethod - def get_no_members_present_state(): - """ - Get implementation of NoMembersPresent state machine of interface in NonQuerier state - """ - return NoMembersPresent - - @staticmethod - def get_version_1_members_present_state(): - """ - Get implementation of Version1MembersPresent state machine of interface in NonQuerier state - This will return implementation of MembersPresent state machine - """ - return NonQuerier.get_members_present_state() diff --git a/pimdm/igmp/nonquerier/__init__.py b/pimdm/igmp/nonquerier/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pimdm/igmp/querier/CheckingMembership.py b/pimdm/igmp/querier/CheckingMembership.py deleted file mode 100644 index ee0141a..0000000 --- a/pimdm/igmp/querier/CheckingMembership.py +++ /dev/null @@ -1,77 +0,0 @@ -from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader -from pimdm.utils import TYPE_CHECKING -from pimdm.igmp.igmp_globals import MEMBERSHIP_QUERY, LAST_MEMBER_QUERY_INTERVAL -from ..wrapper import NoMembersPresent, MembersPresent, Version1MembersPresent -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier CheckingMembership: group_membership_timeout') - group_state.clear_retransmit_timer() - group_state.set_state(NoMembersPresent) - - # NOTIFY ROUTING - !!!! - group_state.notify_routing_remove() - - -def group_membership_v1_timeout(group_state: 'GroupState'): - """ - v1 host timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier CheckingMembership: group_membership_v1_timeout') - # do nothing - return - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier CheckingMembership: retransmit_timeout') - group_addr = group_state.group_ip - packet = PacketIGMPHeader(type=MEMBERSHIP_QUERY, max_resp_time=LAST_MEMBER_QUERY_INTERVAL * 10, - group_address=group_addr) - group_state.router_state.send(data=packet.bytes(), address=group_addr) - - group_state.set_retransmit_timer() - - -def receive_v1_membership_report(group_state: 'GroupState'): - """ - Received IGMP Version 1 Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier CheckingMembership: receive_v1_membership_report') - group_state.set_timer() - group_state.set_v1_host_timer() - group_state.set_state(Version1MembersPresent) - - -def receive_v2_membership_report(group_state: 'GroupState'): - """ - Received IGMP Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier CheckingMembership: receive_v2_membership_report') - group_state.set_timer() - group_state.set_state(MembersPresent) - - -def receive_leave_group(group_state: 'GroupState'): - """ - Received IGMP Leave packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier CheckingMembership: receive_leave_group') - # do nothing - return - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): - """ - Received IGMP Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier CheckingMembership: receive_group_specific_query') - # do nothing - return diff --git a/pimdm/igmp/querier/MembersPresent.py b/pimdm/igmp/querier/MembersPresent.py deleted file mode 100644 index 3b0e9cb..0000000 --- a/pimdm/igmp/querier/MembersPresent.py +++ /dev/null @@ -1,79 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader -from pimdm.igmp.igmp_globals import MEMBERSHIP_QUERY, LAST_MEMBER_QUERY_INTERVAL -from ..wrapper import Version1MembersPresent, CheckingMembership, NoMembersPresent -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier MembersPresent: group_membership_timeout') - group_state.set_state(NoMembersPresent) - - # NOTIFY ROUTING - !!!! - group_state.notify_routing_remove() - - -def group_membership_v1_timeout(group_state: 'GroupState'): - """ - v1 host timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier MembersPresent: group_membership_v1_timeout') - # do nothing - return - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier MembersPresent: retransmit_timeout') - # do nothing - return - - -def receive_v1_membership_report(group_state: 'GroupState'): - """ - Received IGMP Version 1 Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier MembersPresent: receive_v1_membership_report') - group_state.set_timer() - group_state.set_v1_host_timer() - group_state.set_state(Version1MembersPresent) - - -def receive_v2_membership_report(group_state: 'GroupState'): - """ - Received IGMP Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier MembersPresent: receive_v2_membership_report') - group_state.set_timer() - - -def receive_leave_group(group_state: 'GroupState'): - """ - Received IGMP Leave packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier MembersPresent: receive_leave_group') - group_ip = group_state.group_ip - - group_state.set_timer(alternative=True) - group_state.set_retransmit_timer() - - packet = PacketIGMPHeader(type=MEMBERSHIP_QUERY, max_resp_time=LAST_MEMBER_QUERY_INTERVAL * 10, - group_address=group_ip) - group_state.router_state.send(data=packet.bytes(), address=group_ip) - - group_state.set_state(CheckingMembership) - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time): - """ - Received IGMP Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier MembersPresent: receive_group_specific_query') - # do nothing - return diff --git a/pimdm/igmp/querier/NoMembersPresent.py b/pimdm/igmp/querier/NoMembersPresent.py deleted file mode 100644 index d453776..0000000 --- a/pimdm/igmp/querier/NoMembersPresent.py +++ /dev/null @@ -1,75 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -from ..wrapper import MembersPresent -from ..wrapper import Version1MembersPresent -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier NoMembersPresent: group_membership_timeout') - # do nothing - return - - -def group_membership_v1_timeout(group_state: 'GroupState'): - """ - v1 host timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier NoMembersPresent: group_membership_v1_timeout') - # do nothing - return - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier NoMembersPresent: retransmit_timeout') - # do nothing - return - - -def receive_v1_membership_report(group_state: 'GroupState'): - """ - Received IGMP Version 1 Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier NoMembersPresent: receive_v1_membership_report') - group_state.set_timer() - group_state.set_v1_host_timer() - group_state.set_state(Version1MembersPresent) - - # NOTIFY ROUTING + !!!! - group_state.notify_routing_add() - - -def receive_v2_membership_report(group_state: 'GroupState'): - """ - Received IGMP Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier NoMembersPresent: receive_v2_membership_report') - group_state.set_timer() - group_state.set_state(MembersPresent) - - # NOTIFY ROUTING + !!!! - group_state.notify_routing_add() - - -def receive_leave_group(group_state: 'GroupState'): - """ - Received IGMP Leave packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier NoMembersPresent: receive_leave_group') - # do nothing - return - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): - """ - Received IGMP Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier NoMembersPresent: receive_group_specific_query') - # do nothing - return diff --git a/pimdm/igmp/querier/Querier.py b/pimdm/igmp/querier/Querier.py deleted file mode 100644 index b22b285..0000000 --- a/pimdm/igmp/querier/Querier.py +++ /dev/null @@ -1,100 +0,0 @@ -from ipaddress import IPv4Address - -from pimdm.utils import TYPE_CHECKING -from ..igmp_globals import MEMBERSHIP_QUERY, QUERY_RESPONSE_INTERVAL, LAST_MEMBER_QUERY_COUNT, \ - LAST_MEMBER_QUERY_INTERVAL - -from pimdm.packet.PacketIGMPHeader import PacketIGMPHeader -from pimdm.packet.ReceivedPacket import ReceivedPacket -from . import CheckingMembership, MembersPresent, Version1MembersPresent, NoMembersPresent - -if TYPE_CHECKING: - from ..RouterState import RouterState - - -class Querier: - @staticmethod - def general_query_timeout(router_state: 'RouterState'): - """ - General Query timer has expired - """ - router_state.router_state_logger.debug('Querier state: general_query_timeout') - # send general query - packet = PacketIGMPHeader(type=MEMBERSHIP_QUERY, max_resp_time=QUERY_RESPONSE_INTERVAL * 10) - router_state.interface.send(packet.bytes()) - - # set general query timer - router_state.set_general_query_timer() - - @staticmethod - def other_querier_present_timeout(router_state: 'RouterState'): - """ - Other Querier Present timer has expired - """ - router_state.router_state_logger.debug('Querier state: other_querier_present_timeout') - # do nothing - return - - @staticmethod - def receive_query(router_state: 'RouterState', packet: ReceivedPacket): - """ - Interface associated with RouterState is Querier and received a Query packet - """ - router_state.router_state_logger.debug('Querier state: receive_query') - source_ip = packet.ip_header.ip_src - - # if source ip of membership query not lower than the ip of the received interface => ignore - if IPv4Address(source_ip) >= IPv4Address(router_state.interface.get_ip()): - return - - # if source ip of membership query lower than the ip of the received interface => change state - # change state of interface - # Querier -> Non Querier - router_state.change_interface_state(querier=False) - - # set other present querier timer - router_state.clear_general_query_timer() - router_state.set_other_querier_present_timer() - - - # TODO ver se existe uma melhor maneira de fazer isto - @staticmethod - def state_name(): - return "Querier" - - @staticmethod - def get_group_membership_time(max_response_time: int): - """ - Get time to set timer* - """ - return LAST_MEMBER_QUERY_INTERVAL * LAST_MEMBER_QUERY_COUNT - - - # State - @staticmethod - def get_checking_membership_state(): - """ - Get implementation of CheckingMembership state machine of interface in Querier state - """ - return CheckingMembership - - @staticmethod - def get_members_present_state(): - """ - Get implementation of MembersPresent state machine of interface in Querier state - """ - return MembersPresent - - @staticmethod - def get_no_members_present_state(): - """ - Get implementation of NoMembersPresent state machine of interface in Querier state - """ - return NoMembersPresent - - @staticmethod - def get_version_1_members_present_state(): - """ - Get implementation of Version1MembersPresent state machine of interface in Querier state - """ - return Version1MembersPresent diff --git a/pimdm/igmp/querier/Version1MembersPresent.py b/pimdm/igmp/querier/Version1MembersPresent.py deleted file mode 100644 index 253df05..0000000 --- a/pimdm/igmp/querier/Version1MembersPresent.py +++ /dev/null @@ -1,67 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -from ..wrapper import NoMembersPresent -from ..wrapper import MembersPresent -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier Version1MembersPresent: group_membership_timeout') - group_state.set_state(NoMembersPresent) - - # NOTIFY ROUTING - !!!! - group_state.notify_routing_remove() - - -def group_membership_v1_timeout(group_state: 'GroupState'): - """ - v1 host timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier Version1MembersPresent: group_membership_v1_timeout') - group_state.set_state(MembersPresent) - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier Version1MembersPresent: retransmit_timeout') - # do nothing - return - - -def receive_v1_membership_report(group_state: 'GroupState'): - """ - Received IGMP Version 1 Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_v1_membership_report') - group_state.set_timer() - group_state.set_v1_host_timer() - - -def receive_v2_membership_report(group_state: 'GroupState'): - """ - Received IGMP Membership Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_v2_membership_report') - group_state.set_timer() - - -def receive_leave_group(group_state: 'GroupState'): - """ - Received IGMP Leave packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_leave_group') - # do nothing - return - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): - """ - Received IGMP Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier Version1MembersPresent: receive_group_specific_query') - # do nothing - return diff --git a/pimdm/igmp/querier/__init__.py b/pimdm/igmp/querier/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pimdm/igmp/wrapper/CheckingMembership.py b/pimdm/igmp/wrapper/CheckingMembership.py deleted file mode 100644 index 01bf2fb..0000000 --- a/pimdm/igmp/wrapper/CheckingMembership.py +++ /dev/null @@ -1,40 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -if TYPE_CHECKING: - from ..RouterState import RouterState - - -def get_state(router_state: 'RouterState'): - return router_state.interface_state.get_checking_membership_state() - - -def print_state(): - return "CheckingMembership" -''' -def group_membership_timeout(group_state): - get_state(group_state).group_membership_timeout(group_state) - - -def group_membership_v1_timeout(group_state): - get_state(group_state).group_membership_v1_timeout(group_state) - - -def retransmit_timeout(group_state): - get_state(group_state).retransmit_timeout(group_state) - - -def receive_v1_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v1_membership_report(group_state, packet) - - -def receive_v2_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v2_membership_report(group_state, packet) - - -def receive_leave_group(group_state, packet: ReceivedPacket): - get_state(group_state).receive_leave_group(group_state, packet) - - -def receive_group_specific_query(group_state, packet: ReceivedPacket): - get_state(group_state).receive_group_specific_query(group_state, packet) - -''' \ No newline at end of file diff --git a/pimdm/igmp/wrapper/MembersPresent.py b/pimdm/igmp/wrapper/MembersPresent.py deleted file mode 100644 index f09d6a5..0000000 --- a/pimdm/igmp/wrapper/MembersPresent.py +++ /dev/null @@ -1,41 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -if TYPE_CHECKING: - from ..RouterState import RouterState - - -def get_state(router_state: 'RouterState'): - return router_state.interface_state.get_members_present_state() - - -def print_state(): - return "MembersPresent" - -''' -def group_membership_timeout(group_state): - get_state(group_state).group_membership_timeout(group_state) - - -def group_membership_v1_timeout(group_state): - get_state(group_state).group_membership_v1_timeout(group_state) - - -def retransmit_timeout(group_state): - get_state(group_state).retransmit_timeout(group_state) - - -def receive_v1_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v1_membership_report(group_state, packet) - - -def receive_v2_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v2_membership_report(group_state, packet) - - -def receive_leave_group(group_state, packet: ReceivedPacket): - get_state(group_state).receive_leave_group(group_state, packet) - - -def receive_group_specific_query(group_state, packet: ReceivedPacket): - get_state(group_state).receive_group_specific_query(group_state, packet) - -''' \ No newline at end of file diff --git a/pimdm/igmp/wrapper/NoMembersPresent.py b/pimdm/igmp/wrapper/NoMembersPresent.py deleted file mode 100644 index f6a7109..0000000 --- a/pimdm/igmp/wrapper/NoMembersPresent.py +++ /dev/null @@ -1,39 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -if TYPE_CHECKING: - from ..RouterState import RouterState - - -def get_state(router_state: 'RouterState'): - return router_state.interface_state.get_no_members_present_state() - - -def print_state(): - return "NoMembersPresent" -''' -def group_membership_timeout(group_state): - get_state(group_state).group_membership_timeout(group_state) - - -def group_membership_v1_timeout(group_state): - get_state(group_state).group_membership_v1_timeout(group_state) - - -def retransmit_timeout(group_state): - get_state(group_state).retransmit_timeout(group_state) - - -def receive_v1_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v1_membership_report(group_state, packet) - - -def receive_v2_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v2_membership_report(group_state, packet) - - -def receive_leave_group(group_state, packet: ReceivedPacket): - get_state(group_state).receive_leave_group(group_state, packet) - - -def receive_group_specific_query(group_state, packet: ReceivedPacket): - get_state(group_state).receive_group_specific_query(group_state, packet) -''' diff --git a/pimdm/igmp/wrapper/Version1MembersPresent.py b/pimdm/igmp/wrapper/Version1MembersPresent.py deleted file mode 100644 index d188c14..0000000 --- a/pimdm/igmp/wrapper/Version1MembersPresent.py +++ /dev/null @@ -1,40 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -if TYPE_CHECKING: - from ..RouterState import RouterState - - -def get_state(router_state: 'RouterState'): - return router_state.interface_state.get_version_1_members_present_state() - - -def print_state(): - return "Version1MembersPresent" - -''' -def group_membership_timeout(group_state): - get_state(group_state).group_membership_timeout(group_state) - - -def group_membership_v1_timeout(group_state): - get_state(group_state).group_membership_v1_timeout(group_state) - - -def retransmit_timeout(group_state): - get_state(group_state).retransmit_timeout(group_state) - - -def receive_v1_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v1_membership_report(group_state, packet) - - -def receive_v2_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v2_membership_report(group_state, packet) - - -def receive_leave_group(group_state, packet: ReceivedPacket): - get_state(group_state).receive_leave_group(group_state, packet) - - -def receive_group_specific_query(group_state, packet: ReceivedPacket): - get_state(group_state).receive_group_specific_query(group_state, packet) -''' diff --git a/pimdm/igmp/wrapper/__init__.py b/pimdm/igmp/wrapper/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pimdm/mld/GroupState.py b/pimdm/mld/GroupState.py deleted file mode 100644 index 280cb27..0000000 --- a/pimdm/mld/GroupState.py +++ /dev/null @@ -1,193 +0,0 @@ -import logging -from threading import Lock -from threading import Timer - -from pimdm.utils import TYPE_CHECKING -from .wrapper import NoListenersPresent -from .mld_globals import MULTICAST_LISTENER_INTERVAL, LAST_LISTENER_QUERY_INTERVAL - -if TYPE_CHECKING: - from .RouterState import RouterState - - -class GroupState(object): - LOGGER = logging.getLogger('pim.mld.RouterState.GroupState') - - def __init__(self, router_state: 'RouterState', group_ip: str): - #logger - extra_dict_logger = router_state.router_state_logger.extra.copy() - extra_dict_logger['tree'] = '(*,' + group_ip + ')' - self.group_state_logger = logging.LoggerAdapter(GroupState.LOGGER, extra_dict_logger) - - #timers and state - self.router_state = router_state - self.group_ip = group_ip - self.state = NoListenersPresent - self.timer = None - self.retransmit_timer = None - # lock - self.lock = Lock() - - # KernelEntry's instances to notify change of igmp state - self.multicast_interface_state = [] - self.multicast_interface_state_lock = Lock() - - def print_state(self): - return self.state.print_state() - - ########################################### - # Set state - ########################################### - def set_state(self, state): - """ - Set membership state regarding this Group - """ - self.state = state - self.group_state_logger.debug("change membership state to: " + state.print_state()) - - ########################################### - # Set timers - ########################################### - def set_timer(self, alternative: bool = False, max_response_time: int = None): - """ - Set timer - """ - self.clear_timer() - if not alternative: - time = MULTICAST_LISTENER_INTERVAL - else: - time = self.router_state.interface_state.get_group_membership_time(max_response_time) - - timer = Timer(time, self.group_membership_timeout) - timer.start() - self.timer = timer - - def clear_timer(self): - """ - Stop timer - """ - if self.timer is not None: - self.timer.cancel() - - def set_retransmit_timer(self): - """ - Set retransmit timer - """ - self.clear_retransmit_timer() - retransmit_timer = Timer(LAST_LISTENER_QUERY_INTERVAL, self.retransmit_timeout) - retransmit_timer.start() - self.retransmit_timer = retransmit_timer - - def clear_retransmit_timer(self): - """ - Stop retransmit timer - """ - if self.retransmit_timer is not None: - self.retransmit_timer.cancel() - - ########################################### - # Get group state from specific interface state - ########################################### - def get_interface_group_state(self): - """ - Get specific implementation of the membership state machine (depending on the querier state machine) - """ - return self.state.get_state(self.router_state) - - ########################################### - # Timer timeout - ########################################### - def group_membership_timeout(self): - """ - Timer has expired - """ - with self.lock: - self.get_interface_group_state().group_membership_timeout(self) - - def retransmit_timeout(self): - """ - Retransmit timer has expired - """ - with self.lock: - self.get_interface_group_state().retransmit_timeout(self) - - ########################################### - # Receive Packets - ########################################### - def receive_report(self): - """ - Received MLD Report packet regarding this group - """ - with self.lock: - self.get_interface_group_state().receive_report(self) - - def receive_done(self): - """ - Received MLD Done packet regarding this group - """ - with self.lock: - self.get_interface_group_state().receive_done(self) - - def receive_group_specific_query(self, max_response_time: int): - """ - Received MLD Group Specific Query packet regarding this group - """ - with self.lock: - self.get_interface_group_state().receive_group_specific_query(self, max_response_time) - - ########################################### - # Notify Routing - ########################################### - def notify_routing_add(self): - """ - Notify all tree entries that MLD considers to have hosts interested in this group - """ - with self.multicast_interface_state_lock: - print("notify+", self.multicast_interface_state) - for interface_state in self.multicast_interface_state: - interface_state.notify_membership(has_members=True) - - def notify_routing_remove(self): - """ - Notify all tree entries that MLD considers to have not hosts interested in this group - """ - with self.multicast_interface_state_lock: - print("notify-", self.multicast_interface_state) - for interface_state in self.multicast_interface_state: - interface_state.notify_membership(has_members=False) - - def add_multicast_routing_entry(self, kernel_entry): - """ - A new tree is being monitored by the multicast routing protocol that has the same group - MLD will store these entries in order to accelerate the notification process regarding changes in MLD state - """ - with self.multicast_interface_state_lock: - self.multicast_interface_state.append(kernel_entry) - return self.has_members() - - def remove_multicast_routing_entry(self, kernel_entry): - """ - A tree is no longer being monitored by the multicast routing protocol - Remove this tree from this object - """ - with self.multicast_interface_state_lock: - self.multicast_interface_state.remove(kernel_entry) - - def has_members(self): - """ - Determine if MLD considers to have hosts interested in receiving data packets - """ - return self.state is not NoListenersPresent - - def remove(self): - """ - Remove this group from the MLD process - Notify all trees that this group no longer considers to be connected to hosts - This method will be invoked whenever an MLD interface is removed - """ - with self.multicast_interface_state_lock: - self.clear_retransmit_timer() - self.clear_timer() - for interface_state in self.multicast_interface_state: - interface_state.notify_membership(has_members=False) - del self.multicast_interface_state[:] diff --git a/pimdm/mld/RouterState.py b/pimdm/mld/RouterState.py deleted file mode 100644 index 900039a..0000000 --- a/pimdm/mld/RouterState.py +++ /dev/null @@ -1,167 +0,0 @@ -import logging -from threading import Timer - -from pimdm.packet.PacketMLDHeader import PacketMLDHeader -from pimdm.packet.ReceivedPacket import ReceivedPacket -from pimdm.utils import TYPE_CHECKING -from pimdm.rwlock.RWLock import RWLockWrite -from .querier.Querier import Querier -from .nonquerier.NonQuerier import NonQuerier -from .GroupState import GroupState -from .mld_globals import QUERY_RESPONSE_INTERVAL, QUERY_INTERVAL, OTHER_QUERIER_PRESENT_INTERVAL, \ - MULTICAST_LISTENER_QUERY_TYPE - -if TYPE_CHECKING: - from pimdm.InterfaceMLD import InterfaceMLD - - -class RouterState(object): - ROUTER_STATE_LOGGER = logging.getLogger('pim.mld.RouterState') - - def __init__(self, interface: 'InterfaceMLD'): - #logger - logger_extra = dict() - logger_extra['vif'] = interface.vif_index - logger_extra['interfacename'] = interface.interface_name - self.router_state_logger = logging.LoggerAdapter(RouterState.ROUTER_STATE_LOGGER, logger_extra) - - # interface of the router connected to the network - self.interface = interface - - # state of the router (Querier/NonQuerier) - self.interface_state = Querier - - # state of each group - # Key: GroupIPAddress, Value: GroupState object - self.group_state = {} - self.group_state_lock = RWLockWrite() - - # send general query - packet = PacketMLDHeader(type=MULTICAST_LISTENER_QUERY_TYPE, max_resp_delay=QUERY_RESPONSE_INTERVAL * 1000) - self.interface.send(packet.bytes()) - - # set initial general query timer - timer = Timer(QUERY_INTERVAL, self.general_query_timeout) - timer.start() - self.general_query_timer = timer - - # present timer - self.other_querier_present_timer = None - - # Send packet via interface - def send(self, data: bytes, address: str): - self.interface.send(data, address) - - ############################################ - # interface_state methods - ############################################ - def print_state(self): - return self.interface_state.state_name() - - def set_general_query_timer(self): - """ - Set general query timer - """ - self.clear_general_query_timer() - general_query_timer = Timer(QUERY_INTERVAL, self.general_query_timeout) - general_query_timer.start() - self.general_query_timer = general_query_timer - - def clear_general_query_timer(self): - """ - Stop general query timer - """ - if self.general_query_timer is not None: - self.general_query_timer.cancel() - - def set_other_querier_present_timer(self): - """ - Set other querier present timer - """ - self.clear_other_querier_present_timer() - other_querier_present_timer = Timer(OTHER_QUERIER_PRESENT_INTERVAL, self.other_querier_present_timeout) - other_querier_present_timer.start() - self.other_querier_present_timer = other_querier_present_timer - - def clear_other_querier_present_timer(self): - """ - Stop other querier present timer - """ - if self.other_querier_present_timer is not None: - self.other_querier_present_timer.cancel() - - def general_query_timeout(self): - """ - General Query timer has expired - """ - self.interface_state.general_query_timeout(self) - - def other_querier_present_timeout(self): - """ - Other Querier Present timer has expired - """ - self.interface_state.other_querier_present_timeout(self) - - def change_interface_state(self, querier: bool): - """ - Change state regarding querier state machine (Querier/NonQuerier) - """ - if querier: - self.interface_state = Querier - self.router_state_logger.debug('change querier state to -> Querier') - else: - self.interface_state = NonQuerier - self.router_state_logger.debug('change querier state to -> NonQuerier') - - ############################################ - # group state methods - ############################################ - def get_group_state(self, group_ip): - """ - Get object that monitors a given group (with group_ip IP address) - """ - with self.group_state_lock.genRlock(): - if group_ip in self.group_state: - return self.group_state[group_ip] - - with self.group_state_lock.genWlock(): - if group_ip in self.group_state: - group_state = self.group_state[group_ip] - else: - group_state = GroupState(self, group_ip) - self.group_state[group_ip] = group_state - return group_state - - def receive_report(self, packet: ReceivedPacket): - """ - Received MLD Report packet - """ - mld_group = packet.payload.group_address - self.get_group_state(mld_group).receive_report() - - def receive_done(self, packet: ReceivedPacket): - """ - Received MLD Done packet - """ - mld_group = packet.payload.group_address - self.get_group_state(mld_group).receive_done() - - def receive_query(self, packet: ReceivedPacket): - """ - Received MLD Query packet - """ - self.interface_state.receive_query(self, packet) - mld_group = packet.payload.group_address - - # process group specific query - if mld_group != "::" and mld_group in self.group_state: - max_response_time = packet.payload.max_resp_delay - self.get_group_state(mld_group).receive_group_specific_query(max_response_time) - - def remove(self): - """ - Remove this MLD interface - Clear all state - """ - for group in self.group_state.values(): - group.remove() diff --git a/pimdm/mld/__init__.py b/pimdm/mld/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pimdm/mld/mld_globals.py b/pimdm/mld/mld_globals.py deleted file mode 100644 index 028d6b2..0000000 --- a/pimdm/mld/mld_globals.py +++ /dev/null @@ -1,17 +0,0 @@ -# MLD timers (in seconds) -ROBUSTNESS_VARIABLE = 2 -QUERY_INTERVAL = 125 -QUERY_RESPONSE_INTERVAL = 10 -MULTICAST_LISTENER_INTERVAL = (ROBUSTNESS_VARIABLE * QUERY_INTERVAL) + (QUERY_RESPONSE_INTERVAL) -OTHER_QUERIER_PRESENT_INTERVAL = (ROBUSTNESS_VARIABLE * QUERY_INTERVAL) + 0.5 * QUERY_RESPONSE_INTERVAL -STARTUP_QUERY_INTERVAL = (1 / 4) * QUERY_INTERVAL -STARTUP_QUERY_COUNT = ROBUSTNESS_VARIABLE -LAST_LISTENER_QUERY_INTERVAL = 1 -LAST_LISTENER_QUERY_COUNT = ROBUSTNESS_VARIABLE -UNSOLICITED_REPORT_INTERVAL = 10 - - -# MLD msg type -MULTICAST_LISTENER_QUERY_TYPE = 130 -MULTICAST_LISTENER_REPORT_TYPE = 131 -MULTICAST_LISTENER_DONE_TYPE = 132 \ No newline at end of file diff --git a/pimdm/mld/nonquerier/CheckingListeners.py b/pimdm/mld/nonquerier/CheckingListeners.py deleted file mode 100644 index 3b6fb08..0000000 --- a/pimdm/mld/nonquerier/CheckingListeners.py +++ /dev/null @@ -1,53 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -from ..wrapper import NoListenersPresent -from ..wrapper import ListenersPresent - -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def receive_report(group_state: 'GroupState'): - """ - Received MLD Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier CheckingListeners: receive_report') - group_state.set_timer() - group_state.set_state(ListenersPresent) - - -def receive_done(group_state: 'GroupState'): - """ - Received MLD Done packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier CheckingListeners: receive_done') - # do nothing - return - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): - """ - Received MLD Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier CheckingListeners: receive_group_specific_query') - # do nothing - return - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier CheckingListeners: group_membership_timeout') - group_state.set_state(NoListenersPresent) - - # NOTIFY ROUTING - !!!! - group_state.notify_routing_remove() - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier CheckingListeners: retransmit_timeout') - # do nothing - return diff --git a/pimdm/mld/nonquerier/ListenersPresent.py b/pimdm/mld/nonquerier/ListenersPresent.py deleted file mode 100644 index 0995688..0000000 --- a/pimdm/mld/nonquerier/ListenersPresent.py +++ /dev/null @@ -1,52 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -from ..wrapper import NoListenersPresent -from ..wrapper import CheckingListeners - -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def receive_report(group_state: 'GroupState'): - """ - Received MLD Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier ListenersPresent: receive_report') - group_state.set_timer() - - -def receive_done(group_state: 'GroupState'): - """ - Received MLD Done packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier ListenersPresent: receive_done') - # do nothing - return - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): - """ - Received MLD Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier ListenersPresent: receive_group_specific_query') - group_state.set_timer(alternative=True, max_response_time=max_response_time) - group_state.set_state(CheckingListeners) - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier ListenersPresent: group_membership_timeout') - group_state.set_state(NoListenersPresent) - - # NOTIFY ROUTING - !!!! - group_state.notify_routing_remove() - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier ListenersPresent: retransmit_timeout') - # do nothing - return diff --git a/pimdm/mld/nonquerier/NoListenersPresent.py b/pimdm/mld/nonquerier/NoListenersPresent.py deleted file mode 100644 index 4c3e650..0000000 --- a/pimdm/mld/nonquerier/NoListenersPresent.py +++ /dev/null @@ -1,53 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -from ..wrapper import ListenersPresent - -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def receive_report(group_state: 'GroupState'): - """ - Received MLD Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier NoListenersPresent: receive_report') - group_state.set_timer() - group_state.set_state(ListenersPresent) - - # NOTIFY ROUTING + !!!! - group_state.notify_routing_add() - - -def receive_done(group_state: 'GroupState'): - """ - Received MLD Done packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier NoListenersPresent: receive_done') - # do nothing - return - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): - """ - Received MLD Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('NonQuerier NoListenersPresent: receive_group_specific_query') - # do nothing - return - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier NoListenersPresent: group_membership_timeout') - # do nothing - return - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('NonQuerier NoListenersPresent: retransmit_timeout') - # do nothing - return diff --git a/pimdm/mld/nonquerier/NonQuerier.py b/pimdm/mld/nonquerier/NonQuerier.py deleted file mode 100644 index c0cc4ad..0000000 --- a/pimdm/mld/nonquerier/NonQuerier.py +++ /dev/null @@ -1,86 +0,0 @@ -from ipaddress import IPv6Address -from pimdm.utils import TYPE_CHECKING -from ..mld_globals import QUERY_RESPONSE_INTERVAL, LAST_LISTENER_QUERY_COUNT -from pimdm.packet.PacketMLDHeader import PacketMLDHeader -from pimdm.packet.ReceivedPacket import ReceivedPacket -from . import NoListenersPresent, ListenersPresent, CheckingListeners - -if TYPE_CHECKING: - from ..RouterState import RouterState - - -class NonQuerier: - @staticmethod - def general_query_timeout(router_state: 'RouterState'): - """ - General Query timer has expired - """ - router_state.router_state_logger.debug('NonQuerier state: general_query_timeout') - # do nothing - return - - @staticmethod - def other_querier_present_timeout(router_state: 'RouterState'): - """ - Other Query Present timer has expired - """ - router_state.router_state_logger.debug('NonQuerier state: other_querier_present_timeout') - #change state to Querier - router_state.change_interface_state(querier=True) - - # send general query - packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE, - max_resp_delay=QUERY_RESPONSE_INTERVAL * 1000) - router_state.interface.send(packet.bytes()) - - # set general query timer - router_state.set_general_query_timer() - - @staticmethod - def receive_query(router_state: 'RouterState', packet: ReceivedPacket): - """ - Interface associated with RouterState is NonQuerier and received a Query packet - """ - router_state.router_state_logger.debug('NonQuerier state: receive_query') - source_ip = packet.ip_header.ip_src - - # if source ip of membership query not lower than the ip of the received interface => ignore - if IPv6Address(source_ip) >= IPv6Address(router_state.interface.get_ip()): - return - - # reset other present querier timer - router_state.set_other_querier_present_timer() - - # TODO ver se existe uma melhor maneira de fazer isto - @staticmethod - def state_name(): - return "Non Querier" - - @staticmethod - def get_group_membership_time(max_response_time: int): - """ - Get time to set timer* - """ - return (max_response_time/1000.0) * LAST_LISTENER_QUERY_COUNT - - # State - @staticmethod - def get_checking_listeners_state(): - """ - Get implementation of CheckingListeners state machine of interface in NonQuerier state - """ - return CheckingListeners - - @staticmethod - def get_listeners_present_state(): - """ - Get implementation of ListenersPresent state machine of interface in NonQuerier state - """ - return ListenersPresent - - @staticmethod - def get_no_listeners_present_state(): - """ - Get implementation of NoListenersPresent state machine of interface in NonQuerier state - """ - return NoListenersPresent diff --git a/pimdm/mld/nonquerier/__init__.py b/pimdm/mld/nonquerier/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pimdm/mld/querier/CheckingListeners.py b/pimdm/mld/querier/CheckingListeners.py deleted file mode 100644 index 886dc00..0000000 --- a/pimdm/mld/querier/CheckingListeners.py +++ /dev/null @@ -1,59 +0,0 @@ -from pimdm.packet.PacketMLDHeader import PacketMLDHeader -from pimdm.utils import TYPE_CHECKING -from ..mld_globals import LAST_LISTENER_QUERY_INTERVAL -from ..wrapper import ListenersPresent, NoListenersPresent -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def receive_report(group_state: 'GroupState'): - """ - Received MLD Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier CheckingListeners: receive_report') - group_state.set_timer() - group_state.clear_retransmit_timer() - group_state.set_state(ListenersPresent) - - -def receive_done(group_state: 'GroupState'): - """ - Received MLD Done packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier CheckingListeners: receive_done') - # do nothing - return - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): - """ - Received MLD Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier CheckingListeners: receive_group_specific_query') - # do nothing - return - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier CheckingListeners: group_membership_timeout') - group_state.clear_retransmit_timer() - group_state.set_state(NoListenersPresent) - - # NOTIFY ROUTING - !!!! - group_state.notify_routing_remove() - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier CheckingListeners: retransmit_timeout') - group_addr = group_state.group_ip - packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE, - max_resp_delay=LAST_LISTENER_QUERY_INTERVAL * 1000, group_address=group_addr) - group_state.router_state.send(data=packet.bytes(), address=group_addr) - - group_state.set_retransmit_timer() diff --git a/pimdm/mld/querier/ListenersPresent.py b/pimdm/mld/querier/ListenersPresent.py deleted file mode 100644 index da18b73..0000000 --- a/pimdm/mld/querier/ListenersPresent.py +++ /dev/null @@ -1,60 +0,0 @@ -from pimdm.packet.PacketMLDHeader import PacketMLDHeader -from pimdm.utils import TYPE_CHECKING -from ..mld_globals import LAST_LISTENER_QUERY_INTERVAL -from ..wrapper import CheckingListeners, NoListenersPresent -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def receive_report(group_state: 'GroupState'): - """ - Received MLD Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier ListenersPresent: receive_report') - group_state.set_timer() - - -def receive_done(group_state: 'GroupState'): - """ - Received MLD Done packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier ListenersPresent: receive_done') - group_ip = group_state.group_ip - - group_state.set_timer(alternative=True) - group_state.set_retransmit_timer() - - packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE, - max_resp_delay=LAST_LISTENER_QUERY_INTERVAL * 1000, group_address=group_ip) - group_state.router_state.send(data=packet.bytes(), address=group_ip) - - group_state.set_state(CheckingListeners) - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time): - """ - Received MLD Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier ListenersPresent: receive_group_specific_query') - # do nothing - return - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier ListenersPresent: group_membership_timeout') - group_state.set_state(NoListenersPresent) - - # NOTIFY ROUTING - !!!! - group_state.notify_routing_remove() - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier ListenersPresent: retransmit_timeout') - # do nothing - return diff --git a/pimdm/mld/querier/NoListenersPresent.py b/pimdm/mld/querier/NoListenersPresent.py deleted file mode 100644 index 8f1f6e7..0000000 --- a/pimdm/mld/querier/NoListenersPresent.py +++ /dev/null @@ -1,52 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -from ..wrapper import ListenersPresent -if TYPE_CHECKING: - from ..GroupState import GroupState - - -def receive_report(group_state: 'GroupState'): - """ - Received MLD Report packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier NoListenersPresent: receive_report') - group_state.set_timer() - group_state.set_state(ListenersPresent) - - # NOTIFY ROUTING + !!!! - group_state.notify_routing_add() - - -def receive_done(group_state: 'GroupState'): - """ - Received MLD Done packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier NoListenersPresent: receive_done') - # do nothing - return - - -def receive_group_specific_query(group_state: 'GroupState', max_response_time: int): - """ - Received MLD Group Specific Query packet regarding group GroupState - """ - group_state.group_state_logger.debug('Querier NoListenersPresent: receive_group_specific_query') - # do nothing - return - - -def group_membership_timeout(group_state: 'GroupState'): - """ - timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier NoListenersPresent: group_membership_timeout') - # do nothing - return - - -def retransmit_timeout(group_state: 'GroupState'): - """ - retransmit timer associated with group GroupState object has expired - """ - group_state.group_state_logger.debug('Querier NoListenersPresent: retransmit_timeout') - # do nothing - return diff --git a/pimdm/mld/querier/Querier.py b/pimdm/mld/querier/Querier.py deleted file mode 100644 index fda0eb8..0000000 --- a/pimdm/mld/querier/Querier.py +++ /dev/null @@ -1,91 +0,0 @@ -from ipaddress import IPv6Address - -from pimdm.utils import TYPE_CHECKING -from ..mld_globals import LAST_LISTENER_QUERY_INTERVAL, LAST_LISTENER_QUERY_COUNT, QUERY_RESPONSE_INTERVAL - -from pimdm.packet.PacketMLDHeader import PacketMLDHeader -from pimdm.packet.ReceivedPacket import ReceivedPacket -from . import CheckingListeners, ListenersPresent, NoListenersPresent - -if TYPE_CHECKING: - from ..RouterState import RouterState - - -class Querier: - @staticmethod - def receive_query(router_state: 'RouterState', packet: ReceivedPacket): - """ - Interface associated with RouterState is Querier and received a Query packet - """ - router_state.router_state_logger.debug('Querier state: receive_query') - source_ip = packet.ip_header.ip_src - - # if source ip of membership query not lower than the ip of the received interface => ignore - if IPv6Address(source_ip) >= IPv6Address(router_state.interface.get_ip()): - return - - # if source ip of membership query lower than the ip of the received interface => change state - # change state of interface - # Querier -> Non Querier - router_state.change_interface_state(querier=False) - - # set other present querier timer - router_state.clear_general_query_timer() - router_state.set_other_querier_present_timer() - - @staticmethod - def general_query_timeout(router_state: 'RouterState'): - """ - General Query timer has expired - """ - router_state.router_state_logger.debug('Querier state: general_query_timeout') - # send general query - packet = PacketMLDHeader(type=PacketMLDHeader.MULTICAST_LISTENER_QUERY_TYPE, - max_resp_delay=QUERY_RESPONSE_INTERVAL * 1000) - router_state.interface.send(packet.bytes()) - - # set general query timer - router_state.set_general_query_timer() - - @staticmethod - def other_querier_present_timeout(router_state: 'RouterState'): - """ - Other Querier Present timer has expired - """ - router_state.router_state_logger.debug('Querier state: other_querier_present_timeout') - # do nothing - return - - # TODO ver se existe uma melhor maneira de fazer isto - @staticmethod - def state_name(): - return "Querier" - - @staticmethod - def get_group_membership_time(max_response_time: int): - """ - Get time to set timer* - """ - return LAST_LISTENER_QUERY_INTERVAL * LAST_LISTENER_QUERY_COUNT - - # State - @staticmethod - def get_checking_listeners_state(): - """ - Get implementation of CheckingListeners state machine of interface in Querier state - """ - return CheckingListeners - - @staticmethod - def get_listeners_present_state(): - """ - Get implementation of ListenersPresent state machine of interface in Querier state - """ - return ListenersPresent - - @staticmethod - def get_no_listeners_present_state(): - """ - Get implementation of NoListenersPresent state machine of interface in Querier state - """ - return NoListenersPresent diff --git a/pimdm/mld/querier/__init__.py b/pimdm/mld/querier/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pimdm/mld/wrapper/CheckingListeners.py b/pimdm/mld/wrapper/CheckingListeners.py deleted file mode 100644 index eca9ea4..0000000 --- a/pimdm/mld/wrapper/CheckingListeners.py +++ /dev/null @@ -1,40 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -if TYPE_CHECKING: - from ..RouterState import RouterState - - -def get_state(router_state: 'RouterState'): - return router_state.interface_state.get_checking_listeners_state() - - -def print_state(): - return "CheckingListeners" -''' -def group_membership_timeout(group_state): - get_state(group_state).group_membership_timeout(group_state) - - -def group_membership_v1_timeout(group_state): - get_state(group_state).group_membership_v1_timeout(group_state) - - -def retransmit_timeout(group_state): - get_state(group_state).retransmit_timeout(group_state) - - -def receive_v1_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v1_membership_report(group_state, packet) - - -def receive_v2_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v2_membership_report(group_state, packet) - - -def receive_leave_group(group_state, packet: ReceivedPacket): - get_state(group_state).receive_leave_group(group_state, packet) - - -def receive_group_specific_query(group_state, packet: ReceivedPacket): - get_state(group_state).receive_group_specific_query(group_state, packet) - -''' \ No newline at end of file diff --git a/pimdm/mld/wrapper/ListenersPresent.py b/pimdm/mld/wrapper/ListenersPresent.py deleted file mode 100644 index 81e4605..0000000 --- a/pimdm/mld/wrapper/ListenersPresent.py +++ /dev/null @@ -1,41 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -if TYPE_CHECKING: - from ..RouterState import RouterState - - -def get_state(router_state: 'RouterState'): - return router_state.interface_state.get_listeners_present_state() - - -def print_state(): - return "ListenersPresent" - -''' -def group_membership_timeout(group_state): - get_state(group_state).group_membership_timeout(group_state) - - -def group_membership_v1_timeout(group_state): - get_state(group_state).group_membership_v1_timeout(group_state) - - -def retransmit_timeout(group_state): - get_state(group_state).retransmit_timeout(group_state) - - -def receive_v1_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v1_membership_report(group_state, packet) - - -def receive_v2_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v2_membership_report(group_state, packet) - - -def receive_leave_group(group_state, packet: ReceivedPacket): - get_state(group_state).receive_leave_group(group_state, packet) - - -def receive_group_specific_query(group_state, packet: ReceivedPacket): - get_state(group_state).receive_group_specific_query(group_state, packet) - -''' \ No newline at end of file diff --git a/pimdm/mld/wrapper/NoListenersPresent.py b/pimdm/mld/wrapper/NoListenersPresent.py deleted file mode 100644 index 063c81c..0000000 --- a/pimdm/mld/wrapper/NoListenersPresent.py +++ /dev/null @@ -1,39 +0,0 @@ -from pimdm.utils import TYPE_CHECKING -if TYPE_CHECKING: - from ..RouterState import RouterState - - -def get_state(router_state: 'RouterState'): - return router_state.interface_state.get_no_listeners_present_state() - - -def print_state(): - return "NoListenersPresent" -''' -def group_membership_timeout(group_state): - get_state(group_state).group_membership_timeout(group_state) - - -def group_membership_v1_timeout(group_state): - get_state(group_state).group_membership_v1_timeout(group_state) - - -def retransmit_timeout(group_state): - get_state(group_state).retransmit_timeout(group_state) - - -def receive_v1_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v1_membership_report(group_state, packet) - - -def receive_v2_membership_report(group_state, packet: ReceivedPacket): - get_state(group_state).receive_v2_membership_report(group_state, packet) - - -def receive_leave_group(group_state, packet: ReceivedPacket): - get_state(group_state).receive_leave_group(group_state, packet) - - -def receive_group_specific_query(group_state, packet: ReceivedPacket): - get_state(group_state).receive_group_specific_query(group_state, packet) -''' diff --git a/pimdm/mld/wrapper/__init__.py b/pimdm/mld/wrapper/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pimdm/packet/PacketIGMPHeader.py b/pimdm/packet/PacketIGMPHeader.py deleted file mode 100644 index 6b8f171..0000000 --- a/pimdm/packet/PacketIGMPHeader.py +++ /dev/null @@ -1,83 +0,0 @@ -import struct -from pimdm.utils import checksum -import socket -from .PacketPayload import PacketPayload -''' - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Type | Max Resp Time | Checksum | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Group Address | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Resv |S| QRV | QQIC | Number of Sources (N) | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Source Address [1] | -+- -+ -| Source Address [2] | -+- . -+ -. . . -. . . -+- -+ -| Source Address [N] | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -''' -class PacketIGMPHeader(PacketPayload): - IGMP_TYPE = 2 - - IGMP_HDR = "! BB H 4s" - IGMP_HDR_LEN = struct.calcsize(IGMP_HDR) - - IGMP3_SRC_ADDR_HDR = "! BB H " - IGMP3_SRC_ADDR_HDR_LEN = struct.calcsize(IGMP3_SRC_ADDR_HDR) - - IPv4_HDR = "! 4s" - IPv4_HDR_LEN = struct.calcsize(IPv4_HDR) - - Membership_Query = 0x11 - Version_2_Membership_Report = 0x16 - Leave_Group = 0x17 - Version_1_Membership_Report = 0x12 - - def __init__(self, type: int, max_resp_time: int, group_address: str="0.0.0.0"): - # todo check type - self.type = type - self.max_resp_time = max_resp_time - self.group_address = group_address - - def get_igmp_type(self): - return self.type - - def bytes(self) -> bytes: - # obter mensagem e criar checksum - msg_without_chcksum = struct.pack(PacketIGMPHeader.IGMP_HDR, self.type, self.max_resp_time, 0, - socket.inet_aton(self.group_address)) - igmp_checksum = checksum(msg_without_chcksum) - msg = msg_without_chcksum[0:2] + struct.pack("! H", igmp_checksum) + msg_without_chcksum[4:] - return msg - - def __len__(self): - return len(self.bytes()) - - @staticmethod - def parse_bytes(data: bytes): - #print("parseIGMPHdr: ", data) - - igmp_hdr = data[0:PacketIGMPHeader.IGMP_HDR_LEN] - (type, max_resp_time, rcv_checksum, group_address) = struct.unpack(PacketIGMPHeader.IGMP_HDR, igmp_hdr) - - #print(type, max_resp_time, rcv_checksum, group_address) - - - msg_to_checksum = data[0:2] + b'\x00\x00' + data[4:] - #print("checksum calculated: " + str(checksum(msg_to_checksum))) - if checksum(msg_to_checksum) != rcv_checksum: - #print("wrong checksum") - raise Exception("wrong checksum") - - igmp_hdr = igmp_hdr[PacketIGMPHeader.IGMP_HDR_LEN:] - group_address = socket.inet_ntoa(group_address) - pkt = PacketIGMPHeader(type, max_resp_time, group_address) - return pkt \ No newline at end of file diff --git a/pimdm/packet/PacketMLDHeader.py b/pimdm/packet/PacketMLDHeader.py deleted file mode 100644 index 1f79190..0000000 --- a/pimdm/packet/PacketMLDHeader.py +++ /dev/null @@ -1,64 +0,0 @@ -import struct -import socket -from .PacketPayload import PacketPayload - -""" - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Type | Code | Checksum | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Maximum Response Delay | Reserved | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| | -+ + -| | -+ Multicast Address + -| | -+ + -| | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -""" -class PacketMLDHeader(PacketPayload): - MLD_TYPE = 58 - - MLD_HDR = "! BB H H H 16s" - MLD_HDR_LEN = struct.calcsize(MLD_HDR) - - MULTICAST_LISTENER_QUERY_TYPE = 130 - MULTICAST_LISTENER_REPORT_TYPE = 131 - MULTICAST_LISTENER_DONE_TYPE = 132 - - def __init__(self, type: int, max_resp_delay: int, group_address: str = "::"): - # todo check type - self.type = type - self.max_resp_delay = max_resp_delay - self.group_address = group_address - - def get_mld_type(self): - return self.type - - def bytes(self) -> bytes: - # obter mensagem e criar checksum - msg_without_chcksum = struct.pack(PacketMLDHeader.MLD_HDR, self.type, 0, 0, self.max_resp_delay, 0, - socket.inet_pton(socket.AF_INET6, self.group_address)) - #mld_checksum = checksum(msg_without_chcksum) - #msg = msg_without_chcksum[0:2] + struct.pack("! H", mld_checksum) + msg_without_chcksum[4:] - # checksum handled by linux kernel - return msg_without_chcksum - - def __len__(self): - return len(self.bytes()) - - - @staticmethod - def parse_bytes(data: bytes): - mld_hdr = data[0:PacketMLDHeader.MLD_HDR_LEN] - if len(mld_hdr) < PacketMLDHeader.MLD_HDR_LEN: - raise Exception("MLD packet length is lower than expected") - (mld_type, _, _, max_resp_delay, _, group_address) = struct.unpack(PacketMLDHeader.MLD_HDR, mld_hdr) - # checksum is handled by linux kernel - mld_hdr = mld_hdr[PacketMLDHeader.MLD_HDR_LEN:] - group_address = socket.inet_ntop(socket.AF_INET6, group_address) - pkt = PacketMLDHeader(mld_type, max_resp_delay, group_address) - return pkt diff --git a/pimdm/packet/ReceivedPacket.py b/pimdm/packet/ReceivedPacket.py index 5922302..105e20a 100644 --- a/pimdm/packet/ReceivedPacket.py +++ b/pimdm/packet/ReceivedPacket.py @@ -1,8 +1,6 @@ import socket from .Packet import Packet from .PacketPimHeader import PacketPimHeader -from .PacketMLDHeader import PacketMLDHeader -from .PacketIGMPHeader import PacketIGMPHeader from .PacketIpHeader import PacketIpv4Header, PacketIpv6Header from pimdm.utils import TYPE_CHECKING if TYPE_CHECKING: @@ -11,7 +9,7 @@ class ReceivedPacket(Packet): # choose payload protocol class based on ip protocol number - payload_protocol = {2: PacketIGMPHeader, 103: PacketPimHeader} + payload_protocol = {103: PacketPimHeader} def __init__(self, raw_packet: bytes, interface: 'Interface'): self.interface = interface @@ -28,7 +26,7 @@ def __init__(self, raw_packet: bytes, interface: 'Interface'): class ReceivedPacket_v6(Packet): # choose payload protocol class based on ip protocol number - payload_protocol_v6 = {58: PacketMLDHeader, 103: PacketPimHeader} + payload_protocol_v6 = {103: PacketPimHeader} def __init__(self, raw_packet: bytes, ancdata: list, src_addr: str, next_header: int, interface: 'Interface'): self.interface = interface diff --git a/requirements.txt b/requirements.txt index 451280d..5c69f95 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,5 @@ PrettyTable netifaces ipaddress pyroute2 +py-mld==1.0 +igmp==1.0.2 \ No newline at end of file diff --git a/setup.py b/setup.py index 05e2b96..94b90c3 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ long_description=open("README.md", "r").read(), long_description_content_type="text/markdown", keywords="PIM-DM Multicast Routing Protocol PIM Dense-Mode Router RFC3973 IPv4 IPv6", - version="1.2", + version="1.3", url="http://github.com/pedrofran12/pim_dm", author="Pedro Oliveira", author_email="pedro.francisco.oliveira@tecnico.ulisboa.pt",