示例#1
0
    def handle_client(self, client_socket, address):
        """Listens on the client_socket at address.
        This function is expected to be run in a thread dispatched by the
        LISTEN thread.
        @client_socket      socket_instance produced by accept()
        @address            tuple of (ip, port)
        """
        while True:
            try:
                data = client_socket.recv(PACKET_LEN)
                if not data:
                    raise Exception('Client disconnected')

                packet = BBBPacket.from_bytes(data)
                print(
                    'Received packet from {} destined to {} of type {}'.format(
                        packet.src, packet.dst, packet.type))
                if self.verify(packet):
                    print('Verified packet from {} destined to {} of type {}'.
                          format(packet.src, packet.dst, packet.type))
                    self.handle_packet(packet, address)

            except Exception as e:
                print(e)
                client_socket.close()
                return False
示例#2
0
    def update_neighbors(self):
        """Periodically sends out routing information to neighbors.
        Implements Split Horizon to avoid Count-to-Infinity problems.
        """
        while True:
            # Calculate a dictionary where each key is the ip of a neighbor
            # and the value is a list of all the destinations we should display
            # format: {neighbor_ip: [dst_ip]}
            route_updates = {
                n: [d for d in self.routes if self.routes[d] != n]
                for n in self.neighbors
            }

            # Iterate through calculated updates
            for neighbor, routes in route_updates.items():
                if routes:
                    # Get old socket for the neighbors_ip if it exists
                    try:
                        neighbor_socket = self.sockets[neighbor]
                    except KeyError:
                        # If it does not exist, make a new one, store it in
                        # the list of open sockets and dispatch a client thread
                        neighbor_endpoint = (neighbor, ROUTER_PORT)
                        neighbor_socket = socket.socket()
                        neighbor_socket.connect(neighbor_endpoint)
                        self.sockets[neighbor] = neighbor_socket
                        threading.Thread(target=self.handle_client,
                                         args=(neighbor_socket,
                                               neighbor_endpoint)).start()

                    # Create and send appropriate route packet for neighbor
                    self.sqn_lock.acquire()
                    route_packet = BBBPacket(
                        src=self.ip_address,
                        dst=neighbor,
                        type=BBBPacketType.ROUTEUPDATE,
                        payload=json.dumps(routes),
                        seq=self.sqn_counter,
                    )
                    self.sqn_counter += 1
                    self.sqn_lock.release()
                    self.sign(route_packet)
                    self.socket_lock.acquire()
                    neighbor_socket.sendall(route_packet.to_bytes())
                    self.socket_lock.release()
            time.sleep(30)
示例#3
0
    def test_handle_flood_flood(self):
        router1 = BasicRouter('1.1.1.1', test=True)
        router2 = BasicRouter('2.2.2.2', test=True)
        router1.neighbors.add('2.2.2.2')
        router1.neighbors.add('3.3.3.3')
        router1.sockets['2.2.2.2'] = Mock()
        router1.sockets['3.3.3.3'] = Mock()

        message = 'hello world'
        packet = BBBPacket('2.2.2.2', '3.3.3.3', BBBPacketType.FLOOD, message,
                           0)

        router2.sign(packet)
        router1.keys['2.2.2.2'] = router2.packet_key.publickey()
        router1.handle_flood(packet, ('2.2.2.2', 9999))
        # Packet should be sent to 3.3.3.3, but not 2.2.2.2
        router1.sockets['2.2.2.2'].sendall.assert_not_called()
        router1.sockets['3.3.3.3'].sendall.assert_called_with(
            packet.to_bytes())
示例#4
0
 def send_hello_flood(self, dst, count):
     """Function to simply send a packet with hello string as its payload.
     Invoked via CLI.
     """
     for i in range(int(count)):
         for address in self.neighbors:
             self.sqn_lock.acquire()
             packet = BBBPacket(
                 src=self.ip_address,
                 dst=dst,
                 type=BBBPacketType.FLOOD,
                 payload="hello-{0}".format(i),
                 seq=self.sqn_counter,
             )
             self.sqn_counter += 1
             self.sqn_lock.release()
             self.sign(packet)
             self.socket_lock.acquire()
             self.sockets[address].sendall(packet.to_bytes())
             self.socket_lock.release()
         time.sleep(10)
示例#5
0
    def test_verify_sequence_number(self):
        router = BasicRouter('1.1.1.1', test=True)
        message = 'hello world'

        packet = BBBPacket('1.1.1.1', '2.2.2.2', BBBPacketType.FLOOD, message,
                           0)

        router.sign(packet)

        router.keys['1.1.1.1'] = router.packet_key.publickey()
        assert router.verify(packet)

        # Sequence number is the same, so we should reject this packet.
        packet2 = BBBPacket('1.1.1.1', '2.2.2.2', BBBPacketType.FLOOD, message,
                            0)
        router.sign(packet2)
        assert not router.verify(packet2)
        # Sequence number is higher, so we should accept this packet.
        packet3 = BBBPacket('1.1.1.1', '2.2.2.2', BBBPacketType.FLOOD, message,
                            1)
        router.sign(packet3)
        assert router.verify(packet3)
示例#6
0
    def test_simple_sign_verify(self):
        router = BasicRouter('1.1.1.1', test=True)
        message = 'hello world'
        packet = BBBPacket('1.1.1.1', '2.2.2.2', BBBPacketType.FLOOD, message,
                           0)

        router.sign(packet)

        router.keys['1.1.1.1'] = router.packet_key.publickey()
        assert router.verify(packet)

        router.keys['1.1.1.1'] = RSA.generate(2048).publickey()
        assert not router.verify(packet)
示例#7
0
    def test_simple_sign_verify_encoding(self):
        router = BasicRouter('1.1.1.1', test=True)
        message = 'hello world'
        packet = BBBPacket('1.1.1.1', '2.2.2.2', BBBPacketType.FLOOD, message,
                           0)

        router.sign(packet)

        pem_key = router.packet_key.publickey().export_key().decode()
        print(pem_key)
        reread_key = RSA.import_key(pem_key.encode())

        router.keys['1.1.1.1'] = reread_key
        assert router.verify(packet)
示例#8
0
    def test_sqn_numbers(self):
        router1 = BasicRouter('1.1.1.1', test=True)
        router2 = BasicRouter('2.2.2.2', test=True)

        routes = ['3.3.3.3', '4.4.4.4', '5.5.5.5']

        route_packet = BBBPacket(
            '2.2.2.2',
            '1.1.1.1',
            BBBPacketType.ROUTEUPDATE,
            json.dumps(routes),
            0,
        )

        router2.sign(route_packet)

        router1.keys['2.2.2.2'] = router2.packet_key.publickey()
        assert router1.verify(route_packet)

        message = 'hello world'
        packet = BBBPacket('2.2.2.2', '1.1.1.1', BBBPacketType.FLOOD, message,
                           1)
        router2.sign(packet)
        assert router1.verify(packet)
示例#9
0
    def __init__(self, topo_path="simple.json"):
        """Constructor
        @topo_path      name of the topology file to parse
        """
        self.sockets = {}
        seq_num = 0

        # Load the network topology from the json file
        self.topology = {}
        with open(path_join(TOPO_DIRECTORY, topo_path), 'r') as topo_file:
            self.topology = json.loads(topo_file.read())

        while True:
            for host, config in self.topology.items():
                # get corresponding socket for host
                print("attempting to connect to: {0}".format(host))
                endpoint = (host, ROUTER_PORT)
                try:
                    host_socket = self.sockets[endpoint]
                except KeyError:
                    # create and store a new socket if necessary
                    host_socket = socket.socket()
                    self.sockets[endpoint] = host_socket
                    host_socket.connect(endpoint)

                # create configuration packet and send it to the host
                config_packet = BBBPacket(
                    src=host_socket.getsockname()[0],
                    dst=host,
                    type=BBBPacketType.MASTERCONFIG,
                    payload=json.dumps(config),
                    seq=seq_num,
                )
                host_socket.sendall(config_packet.to_bytes())
                seq_num += 1
            sleep(TOPO_UPDATE_PERIOD)
示例#10
0
    def test_handle_flood_receive(self):
        router1 = BasicRouter('1.1.1.1', test=True)
        router2 = BasicRouter('2.2.2.2', test=True)
        router1.neighbors.add('2.2.2.2')
        router1.neighbors.add('3.3.3.3')
        router1.sockets['2.2.2.2'] = Mock()
        router1.sockets['3.3.3.3'] = Mock()

        message = 'hello world'
        packet = BBBPacket('2.2.2.2', '1.1.1.1', BBBPacketType.FLOOD, message,
                           0)
        router2.sign(packet)
        router1.keys['2.2.2.2'] = router2.packet_key.publickey()
        router1.handle_flood(packet, ('2.2.2.2', 9999))
        # Packet destined for router1. Shouldn't be flooded
        router1.sockets['2.2.2.2'].sendall.assert_not_called()
        router1.sockets['3.3.3.3'].sendall.assert_not_called()
    def test_handle_flood_byzantine(self):
        router1 = FaultyFloodingRouter('1.1.1.1', test=True)
        router2 = BasicRouter('2.2.2.2', test=True)
        router1.neighbors.add('2.2.2.2')
        router1.neighbors.add('3.3.3.3')
        router1.sockets['2.2.2.2'] = Mock()
        router1.sockets['3.3.3.3'] = Mock()

        message = 'hello world'
        packet = BBBPacket('2.2.2.2', '3.3.3.3', BBBPacketType.FLOOD, message,
                           0)

        router2.sign(packet)
        router1.keys['2.2.2.2'] = router2.packet_key.publickey()
        router1.handle_flood(packet, ('2.2.2.2', 9999))
        # Packet should be dropped
        router1.sockets['2.2.2.2'].sendall.assert_not_called()
        router1.sockets['3.3.3.3'].sendall.assert_not_called()
示例#12
0
    def test_handle_route_update(self):
        router1 = BasicRouter('1.1.1.1', test=True)
        router2 = BasicRouter('2.2.2.2', test=True)

        routes = ['3.3.3.3', '4.4.4.4', '5.5.5.5']

        route_packet = BBBPacket(
            '2.2.2.2',
            '1.1.1.1',
            BBBPacketType.ROUTEUPDATE,
            json.dumps(routes),
            0,
        )

        router2.sign(route_packet)

        router1.keys['2.2.2.2'] = router2.packet_key.publickey()
        router1.handle_routeupdate(route_packet)

        assert '2.2.2.2' in router1.neighbors
        for route in routes:
            assert route in router1.routes
            assert router1.routes[route] == '2.2.2.2'
        assert router1.routes['2.2.2.2'] == '2.2.2.2'
示例#13
0
    def test_json_encoding(self):
        packet = BBBPacket('2.2.2.2', '3.3.3.3', BBBPacketType.FLOOD, 'memes',
                           0)
        packet_bytes = packet.to_bytes()
        packet_redux = BBBPacket.from_bytes(packet_bytes)

        assert packet.__dict__ == packet_redux.__dict__

        h = SHA256.new(packet_bytes)
        h_redux = SHA256.new(packet_redux.to_bytes())
        assert h.hexdigest() == h_redux.hexdigest()

        router1 = BasicRouter('1.1.1.1', test=True)
        router1.sign(packet)

        packet_bytes = packet.to_bytes()
        packet_redux = BBBPacket.from_bytes(packet_bytes)

        assert packet.__dict__ == packet_redux.__dict__
        router1.keys['2.2.2.2'] = router1.packet_key.publickey()
        assert router1.verify(packet_redux)
        router1.sqn_numbers['2.2.2.2'] = -1
        assert router1.verify(packet)