def __init__(self): self.printing_options = PrintingOptions() self.sanitizer = Sanitizer() self.oft = None self.stats = None self.cap = None self.packet_number = None self.load_apps = [] self.packet_count = 1 self.topo_reader = TopoReader() self.ofp_proxy = None self.load_config()
def __init__(self): self.printing_options = PrintingOptions() self.sanitizer = Sanitizer() self.oft = None self.stats = None self.influx = None self.notifications = None self.trigger_event = threading.Event() self.cap = None self.packet_number = None self.load_apps = dict() self.packet_count = 1 self.topo_reader = TopoReader() self.save_to_file = None self.ofp_proxy = None self.load_config()
def filter_of_type(msg): """ Filter per OF Message Type Args: msg: OFMessage class Returns: False: Don't filter packet True: Filter it (don't print) """ name_version = get_ofp_version(msg.ofp.header.version.value) # OF Types to be ignored through json file (-F) try: rejected_types = Sanitizer().allowed_of_versions[name_version] if msg.ofp.header.message_type in rejected_types['rejected_of_types']: return True except KeyError: pass return False
def filter_of_version(msg): """ Check if the OpenFlow version is allowed Args: msg: OFMessage class Returns: False: Don't filter packet True: Filter it (don't print) """ name_version = get_ofp_version(msg.ofp.header.version.value) supported_versions = [] try: for version in Sanitizer().allowed_of_versions: supported_versions.append(version) if name_version not in supported_versions: return True except KeyError: pass return False
def ethertype_filters(msg): """ Filter PacketIn and PacketOut messages based on Ethertype Sanitizer filter (-F), entry "filters", "ethertype" Args: msg: class OFMessage Returns: False: Don't filter packet True: Filter it (don't print) """ if msg.ofp.header.message_type in [10, 13]: try: filters = Sanitizer().filters['ethertypes'] except KeyError: return False if not len(filters): # No filters return False # Go to payload try: if is_protocol(msg.ofp.data, lldp=True) and filters['lldp']: return True if is_protocol(msg.ofp.data, oess=True) and filters['fvd']: return True if is_protocol(msg.ofp.data, arp=True) and filters['arp']: return True except KeyError: pass # Other Ethertypes listed as hex for protocol in filters['others']: try: if is_protocol(msg.ofp.data) == int(protocol, 16): return True except ValueError: pass return False
class RunSniffer(object): """ The RunSniffer class is the main class for the OpenFlow Sniffer. This class instantiate all auxiliary classes, captures the packets, instantiate new OpenFlow messages and triggers all applications. """ def __init__(self): self.printing_options = PrintingOptions() self.sanitizer = Sanitizer() self.oft = None self.stats = None self.influx = None self.notifications = None self.trigger_event = threading.Event() self.cap = None self.packet_number = None self.load_apps = dict() self.packet_count = 1 self.topo_reader = TopoReader() self.save_to_file = None self.ofp_proxy = None self.load_config() def load_config(self): """ Parses the parameters received and instantiates the apps requested. """ # Get CLI params and call the pcapy loop self.cap, self.packet_number, \ self.load_apps, sanitizer, \ topo_file, is_to_save = get_params(sys.argv) self.sanitizer.process_filters(sanitizer) # Load TopologyReader self.topo_reader.readfile(topo_file) # Save to File self.save_to_file = save_to_file(is_to_save) # Start Apps self.ofp_proxy = OFProxy() if 'oess_fvd' in self.load_apps: self.oft = OessFvdTracer(self.load_apps['oess_fvd']) if 'statistics' in self.load_apps: self.stats = OFStats() if 'influx' in self.load_apps: self.influx = InfluxClient(trigger_event=self.trigger_event) if 'notifications' in self.load_apps: self.notifications = Notifications(self.load_apps['notifications']) def run(self): """ cap.loop continuously capture packets w/ pcapy. For every captured packet, self.process_packet method is called. Exits: 0 - Normal, reached end of file 1 - Normal, user requested with CRTL + C 2 - Error 3 - Interface or file not found """ exit_code = 0 # DEBUG: # self.cap.loop(-1, self.process_packet) try: self.cap.loop(-1, self.process_packet) except EndOfPcapFile: exit_code = 3 except KeyboardInterrupt: exit_code = 1 except Exception as exception: print('Error on packet %s: %s ' % (self.packet_count, exception)) exit_code = 2 finally: if 'statistics' in self.load_apps: # If OFP_Stats is running, set a timer # before closing the app. Useful in cases # where the ofp_sniffer is reading from a # pcap file instead of a NIC. time.sleep(200) # pass print('Exiting with code: %s' % exit_code) # gracefully shut down if 'influx' in self.load_apps: self.influx.stop_event.set() sys.exit(exit_code) def process_packet(self, header, packet): """ Every packet captured by cap.loop is then processed here. If packets are bigger than 62 Bytes, we process them. If it is 0, means there are no more packets. If it is something in between, it is a fragment, we ignore for now. Args: header: header of the captured packet packet: packet captured from file or interface """ if len(packet) >= 54: # Verify if user asked for just one specific packet if self.was_packet_number_defined(): if not self.is_the_packet_number_specified(): self.packet_count += 1 return # DEBUG: # print("Packet Number: %s" % self.packet_count) pkt = Packet(packet, self.packet_count, header) if pkt.reconnect_error: if isinstance(self.stats, OFStats): # OFStats counts reconnects self.stats.process_packet(pkt) if isinstance(self.notifications, Notifications): # Send notifications via Slack self.notifications.send_msg(pkt) elif pkt.is_openflow_packet: valid_result = pkt.process_openflow_messages() if valid_result: # Apps go here: if isinstance(self.oft, OessFvdTracer): # FVD_Tracer does not print the packets self.oft.process_packet(pkt) if isinstance(self.ofp_proxy, OFProxy): # OFP_PROXY associates IP:PORT to DPID self.ofp_proxy.process_packet(pkt) if isinstance(self.stats, OFStats): # OFStats print the packets self.stats.process_packet(pkt) if isinstance(self.notifications, Notifications): # Send notifications via Slack self.notifications.send_msg(pkt) if not isinstance(self.oft, OessFvdTracer): # Print Packets pkt.print_packet() if self.influx: # tell influx to wake up and update immediately self.trigger_event.set() del pkt if self.is_the_packet_number_specified(): # If a specific packet was selected, end here. raise EndOfPcapFile elif len(packet) is 0: return 3 self.packet_count += 1 def was_packet_number_defined(self): """ In case user wants to see a specific packet inside a specific pcap file, provide file name with the specific packet number after ":" -r file.pcap:packet_number Returns: True if a packet number was specified False: if a packet number was not specified """ if self.packet_number != 0: return True return False def is_the_packet_number_specified(self): """ If user wants to see a specific packet inside a specific pcap file and the packet_count is that number, return True. Otherwise, return false Returns: True if packet_count matches False: if packet_count does not match """ return True if self.packet_count == self.packet_number else False
def dpid_filters(msg): """ Filter PacketIn and PacketOut messages based on DPID and ports Sanitizer filter (-F), entry "filters", "packetIn_filter" or "packetOut_filter" If switch_dpid AND in_port are Any, don't filter (print it) If switch_dpid OR in_port are NOT Any, print only what matches the most specific (filter everything else) Args: msg: class OFMessage Returns: False: Don' filter packet (print it) True: Filter it (don't print) """ # It has to be a PacketOut or PacketIn if msg.ofp.header.message_type not in [10, 13]: return False # It has to be a LLDP packet if not is_protocol(msg.ofp.data, lldp=True): return False try: # If it is a PacketIn ... if msg.ofp.header.message_type in [10]: # It has to have a packetIn_filter filter filters = Sanitizer().filters['packetIn_filter'] filter_port = filters['in_port'] # If it a PacketOut... else: # It has to have a packetOut_filter filter filters = Sanitizer().filters['packetOut_filter'] filter_port = filters['out_port'] filter_dpid = filters['switch_dpid'] except KeyError: return False if not len(filters): return False # Was switch_dpid or in_port specified by user? if filter_dpid in ['any', 'Any', 'ANY']: if filter_port in ['any', 'Any', 'ANY']: return False # If we got here, it means we have content to avoid printing print_it = False lldp_msg = get_protocol(msg.ofp.data, lldp=True) switch_dpid = clear_dpid(filter_dpid) if print_switch_dpid(switch_dpid, lldp_msg.c_id): if msg.ofp.header.message_type in [10]: if print_port(filter_port, str(msg.ofp.in_port)): print_it = True else: if print_port(filter_port, str(lldp_msg.p_id)): print_it = True if print_it: return False return True
class RunSniffer(object): """ The RunSniffer class is the main class for the OpenFlow Sniffer. This class instantiate all auxiliary classes, captures the packets, instantiate new OpenFlow messages and triggers all applications. """ def __init__(self): self.printing_options = PrintingOptions() self.sanitizer = Sanitizer() self.oft = None self.stats = None self.cap = None self.packet_number = None self.load_apps = [] self.packet_count = 1 self.topo_reader = TopoReader() self.ofp_proxy = None self.load_config() def load_config(self): """ Parses the parameters received and instantiates the apps requested. """ # Get CLI params and call the pcapy loop self.cap, self.packet_number, \ self.load_apps, sanitizer, topo_file = get_params(sys.argv) self.sanitizer.process_filters(sanitizer) # Load TopologyReader self.topo_reader.readfile(topo_file) # Start Apps if 'oess_fvd' in self.load_apps: self.oft = OessFvdTracer() if 'statistics' in self.load_apps: self.stats = OFStats() # Load Proxy self.ofp_proxy = OFProxy() def run(self): """ cap.loop continuously capture packets w/ pcapy. For every captured packet, self.process_packet method is called. Exits: 0 - Normal, reached end of file 1 - Normal, user requested with CRTL + C 2 - Error 3 - Interface or file not found """ exit_code = 0 # Debug: # self.cap.loop(-1, self.process_packet) try: self.cap.loop(-1, self.process_packet) if 'statistics' in self.load_apps: # If OFP_Stats is running, set a timer # before closing the app. Useful in cases # where the ofp_sniffer is reading from a # pcap file instead of real time. time.sleep(200) except KeyboardInterrupt: exit_code = 1 except Exception as exception: print('Error on packet %s: %s ' % (self.packet_count, exception)) exit_code = 2 finally: print('Exiting...') sys.exit(exit_code) def process_packet(self, header, packet): """ Every packet captured by cap.loop is then processed here. If packets are bigger than 62 Bytes, we process them. If it is 0, means there are no more packets. If it is something in between, it is a fragment, we ignore for now. Args: header: header of the captured packet packet: packet captured from file or interface """ if len(packet) >= 62 and self.packet_number_defined(): # DEBUG: # print("Packet Number: %s" % self.packet_count) pkt = Packet(packet, self.packet_count, header) if pkt.is_openflow_packet: valid_result = pkt.process_openflow_messages() if valid_result: # Apps go here: if isinstance(self.oft, OessFvdTracer): # FVD_Tracer does not print the packets self.oft.process_packet(pkt) if isinstance(self.ofp_proxy, OFProxy): # OFP_PROXY associates IP:PORT to DPID self.ofp_proxy.process_packet(pkt) if isinstance(self.stats, OFStats): # OFStats print the packets self.stats.process_packet(pkt) if not isinstance(self.oft, OessFvdTracer): # Print Packets pkt.print_packet() del pkt elif len(packet) is 0: sys.exit(0) self.packet_count += 1 def packet_number_defined(self): """ In case user wants to see a specific packet inside a specific pcap file, provide file name with the specific packet number -r file.pcap:packet_number Returns: True if packet_count matches False: if packet_count does not match """ if self.packet_number > 0: return True if self.packet_count == self.packet_number else False return True