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()
Esempio n. 2
0
 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()
Esempio n. 3
0
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
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
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
Esempio n. 7
0
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