Пример #1
0
 def __init__(self, interface=None):
     """
     Init takes the local interface in order to retrieve the local MAC.
     This method also instantiate an ScapyIO class. We do not use the normal
     lower/upper layer system because in this case no any other lower layer
     is suitable other than ScapyIO.
     """
     Layer.__init__(self)
     self.io = ScapyIO(interface)
     self.io.register_handler(self)
     self.addr = ARP().hwsrc
     self.packet_pool = [
     ]  #Packet will be stored as a tuple (packet, timestamp)
Пример #2
0
 def __init__(self, interface=None):
     """
     Init takes the local interface in order to retrieve the local MAC.
     This method also instantiate an ScapyIO class. We do not use the normal
     lower/upper layer system because in this case no any other lower layer
     is suitable other than ScapyIO.
     """
     Layer.__init__(self)
     self.io = ScapyIO(interface)
     self.io.register_handler(self)
     self.addr = ARP().hwsrc
     self.packet_pool = [] #Packet will be stored as a tuple (packet, timestamp)
Пример #3
0
class EthernetProtocol(Layer):
    """
    This class provides all the functionalities to accomplish
    the layer 2 routing. When a packet is received from an upper layer
    this class basically look up in the host routing table to get the ip
    to send the packet to and if the mac address is not found trigger an 
    ARP request. It also maintain a pool of packet for which the destination
    MAC address is unknown until an ARP reply is received.
    """

    name = "Ether"

    def __init__(self, interface=None):
        """
        Init takes the local interface in order to retrieve the local MAC.
        This method also instantiate an ScapyIO class. We do not use the normal
        lower/upper layer system because in this case no any other lower layer
        is suitable other than ScapyIO.
        """
        Layer.__init__(self)
        #self.plugMpls = False
        #self.mplsLabel = 1
        self.io = ScapyIO(interface)
        self.io.register_handler(self)
        self.addr = ARP().hwsrc
        self.packet_pool = [
        ]  #Packet will be stored as a tuple (packet, timestamp)

    def packet_received(self, packet, **kwargs):
        """
        Decapsulate the packet as the Layer would have done except that if
        the packet is an IP packet this method update the ARP cache with ip and mac
        """
        name = packet.payload.name
        '''
        if packet.payload.name == 'MPLS':
            mpls_payload =  packet.payload

            print len(mpls_payload.fields), mpls_payload.fields
            name = mpls_payload.payload.name
            print mpls_payload.name, name
            target = self.upperLayers.get(name, self.upperLayers['default'])
            kwargs["Ether"] = packet.fields
            target.packet_received(mpls_payload.payload, **kwargs)

        else:
        '''
        target = self.upperLayers.get(name, self.upperLayers["default"])
        #print len(packet.fields)
        kwargs["Ether"] = packet.fields
        #print kwargs["Ether"]
        if name == "IP":
            if self.upperLayers.has_key("ARP"):
                self.upperLayers["ARP"].update_cache(packet.payload.src,
                                                     packet.src)
        target.packet_received(packet.payload, **kwargs)

    def transfer_packet(self, packet):
        """
        Rewrite transfer to use scapy_io because ethernet is the lowest layer.
        So in this case call the send method of Scapy
        """
        self.io.send(packet)

    def send_packet(self, packet, **kwargs):
        """
        When a packet is received from an upper layer try to route it. If
        the method return something call forge and transfert it (to scapyio)
        """
        args = self._route_packet(packet, **kwargs)
        if args:
            self.transfer_packet(self.forge_packet(packet, **args["Ether"]))

    def _route_packet(self, packet, **kwargs):
        """
        Basically change dst mac if needed in order to forge the ethernet packet.
        If destination MAC is not found an ARP request is triggered in the ARP layer
        and the packet put in a list while no ARP reply has been received.
        """
        if not kwargs.has_key("Ether"):
            kwargs["Ether"] = {}

        if isinstance(
                packet, ARP
        ):  #If the packet is an ARP use the address defined in ARP headers
            kwargs["Ether"]["dst"] = packet.hwdst

        elif isinstance(packet, IP):
            dstIP = packet.dst
            try:
                iff, _, gw = conf.route.route(dstIP)
                #Get the right routing row for the given IP automaticaly no need to parse the routing table..
            except AttributeError:
                return None

            if gw != "0.0.0.0":  #If the host to send is different from the ip itself
                ipaddr = gw  #Use the gateway ip to do the routing (so gateway MAC)
            else:
                ipaddr = dstIP  #Otherwise use directly the IP of dest

            #TODO: Deal better with interface and why not sending trame on this interface instead of always the same one ?
            if iff == "lo":
                mac = "ff:ff:ff:ff:ff:ff"
            else:
                if self.upperLayers.has_key(
                        "ARP"
                ):  #Check that ARP handler is registered in upper layer
                    mac = self.upperLayers["ARP"].get_mac(ipaddr)
                    #get_mac look up in the ARP table to return the MAC associated with the IP return None otherwise
                    if not mac:  #Nothing was returned
                        #print("Mac not found for "+ ipaddr)
                        self.packet_pool.append(
                            (packet, time.time()
                             ))  #Put the packet in the pool with a timestamp
                        self.upperLayers["ARP"].send_arp_request(
                            ipaddr
                        )  #Because nothing was found do an ARP request
                        return None
                else:
                    print("No ARP Layer registered to retrieve MAC")
                    return None

            kwargs["Ether"][
                "dst"] = mac  #Return args that will be sent to forge_packet
        return kwargs

    def forge_packet(self, packet, **kwargs):
        """ Forge the Ethernet packet using the given kwargs and the given packet"""
        return Ether(**kwargs) / packet

    def route_update(self, ip):
        """
        Method called by arp layer when receive an arp reply (is_at)
        Loop through all packets if the newly resolved MAC match dst of on of
        them complete the packet and send it.
        """
        updated_packet = []
        for p, _ in self.packet_pool:
            _, _, gw = conf.route.route(p.dst)  #Try to reroute each packets
            if gw == "0.0.0.0":
                gw = ip
            if gw == ip:
                mac = self.upperLayers["ARP"].get_mac(gw)
                #The ARP cache has been updated so a packet dst IP may be resolved into a MAC.
                if mac:  #If a mac was returned for the packet
                    #print("Packet match ARP reply: ",p)
                    completedpacket = self.forge_packet(p, dst=mac)
                    self.transfer_packet(completedpacket)
                    updated_packet.append(p)
        now = time.time()
        self.packet_pool = [
            x for x in self.packet_pool
            if now < x[1] + 5 and x[0] not in updated_packet
        ]  #Remove entries older than 5 seconds

    def start_listening(self, doreactor=True):
        """
        Because Ethernet have directly the ScapyIO as a class attribute it should
        interface ScapyIO methods. This method should be called to start listening
        on the socket using the appropriate method (twisted reactor or threads)
        """
        self.io.start_listening(doreactor)

    def stop(self):
        """Call the stop method of ScapyIO"""
        self.io.stop_listening()
Пример #4
0
class EthernetProtocol(Layer):
    """
    This class provides all the functionalities to accomplish
    the layer 2 routing. When a packet is received from an upper layer
    this class basically look up in the host routing table to get the ip
    to send the packet to and if the mac address is not found trigger an 
    ARP request. It also maintain a pool of packet for which the destination
    MAC address is unknown until an ARP reply is received.
    """
    
    name = "Ether"
    
    def __init__(self, interface=None):
        """
        Init takes the local interface in order to retrieve the local MAC.
        This method also instantiate an ScapyIO class. We do not use the normal
        lower/upper layer system because in this case no any other lower layer
        is suitable other than ScapyIO.
        """
        Layer.__init__(self)
        self.io = ScapyIO(interface)
        self.io.register_handler(self)
        self.addr = ARP().hwsrc
        self.packet_pool = [] #Packet will be stored as a tuple (packet, timestamp)
    
    def packet_received(self, packet, **kwargs):
        """
        Decapsulate the packet as the Layer would have done except that if
        the packet is an IP packet this method update the ARP cache with ip and mac
        """
        name = packet.payload.name
        target = self.upperLayers.get(name, self.upperLayers["default"])
        kwargs["Ether"] = packet.fields
        if name == "IP":
            if self.upperLayers.has_key("ARP"):
                self.upperLayers["ARP"].update_cache(packet.payload.src, packet.src)
        target.packet_received(packet.payload, **kwargs)
    
    def transfer_packet(self, packet):
        """
        Rewrite transfer to use scapy_io because ethernet is the lowest layer.
        So in this case call the send method of Scapy
        """
        self.io.send(packet)
        
    def send_packet(self, packet, **kwargs):
        """
        When a packet is received from an upper layer try to route it. If
        the method return something call forge and transfert it (to scapyio)
        """
        args = self._route_packet(packet, **kwargs)
        if args:
            self.transfer_packet(self.forge_packet(packet, **args["Ether"]))
    
    def _route_packet(self, packet, **kwargs):
        """
        Basically change dst mac if needed in order to forge the ethernet packet.
        If destination MAC is not found an ARP request is triggered in the ARP layer
        and the packet put in a list while no ARP reply has been received.
        """
        if not kwargs.has_key("Ether"):
            kwargs["Ether"] = {}
            
        if isinstance(packet, ARP):  #If the packet is an ARP use the address defined in ARP headers
            kwargs["Ether"]["dst"] = packet.hwdst
            
        elif isinstance(packet, IP):
            dstIP = packet.dst
            try:
                iff, _, gw = conf.route.route(dstIP)
                #Get the right routing row for the given IP automaticaly no need to parse the routing table..
            except AttributeError:
                return None
            
            if gw != "0.0.0.0":  #If the host to send is different from the ip itself
                ipaddr = gw  #Use the gateway ip to do the routing (so gateway MAC)
            else:
                ipaddr = dstIP  #Otherwise use directly the IP of dest
            
            #TODO: Deal better with interface and why not sending trame on this interface instead of always the same one ?
            if iff == "lo":
                mac = "ff:ff:ff:ff:ff:ff"
            else:
                if self.upperLayers.has_key("ARP"):  #Check that ARP handler is registered in upper layer
                    mac = self.upperLayers["ARP"].get_mac(ipaddr)
                    #get_mac look up in the ARP table to return the MAC associated with the IP return None otherwise
                    if not mac:  #Nothing was returned
                        #print("Mac not found for "+ ipaddr)
                        self.packet_pool.append((packet, time.time()))  #Put the packet in the pool with a timestamp
                        self.upperLayers["ARP"].send_arp_request(ipaddr)  #Because nothing was found do an ARP request
                        return None
                else:
                    print("No ARP Layer registered to retrieve MAC")
                    return None
    
            kwargs["Ether"]["dst"] = mac  #Return args that will be sent to forge_packet
        return kwargs
    
    def forge_packet(self, packet, **kwargs):
        """ Forge the Ethernet packet using the given kwargs and the given packet"""
        return Ether(**kwargs)/packet
    
    def route_update(self, ip):
        """
        Method called by arp layer when receive an arp reply (is_at)
        Loop through all packets if the newly resolved MAC match dst of on of
        them complete the packet and send it.
        """
        updated_packet = []
        for p, _ in self.packet_pool:
            _, _, gw = conf.route.route(p.dst)  #Try to reroute each packets
            if gw == "0.0.0.0":
                gw = ip
            if gw == ip:
                mac = self.upperLayers["ARP"].get_mac(gw)
                #The ARP cache has been updated so a packet dst IP may be resolved into a MAC.
                if mac:  #If a mac was returned for the packet
                    #print("Packet match ARP reply: ",p)
                    completedpacket = self.forge_packet(p, dst=mac)
                    self.transfer_packet(completedpacket)
                    updated_packet.append(p)
        now = time.time()
        self.packet_pool = [x for x in self.packet_pool if now < x[1] + 5 and x[0] not in updated_packet] #Remove entries older than 5 seconds
        
    def start_listening(self, doreactor=True):
        """
        Because Ethernet have directly the ScapyIO as a class attribute it should
        interface ScapyIO methods. This method should be called to start listening
        on the socket using the appropriate method (twisted reactor or threads)
        """
        self.io.start_listening(doreactor)
    
    def stop(self):
        """Call the stop method of ScapyIO"""
        self.io.stop_listening()