예제 #1
0
    def handle_confirm(self, bundle: TransactionBundle):
        """
        Handle a client requesting confirmation

        :param bundle: The request bundle
        """
        # Make sure we are responsible for this link
        link_address = bundle.get_link_address()
        if not address_in_prefixes(link_address, self.responsible_for_links):
            logger.debug("Not confirming to link {}: "
                         "doesn't match {}".format(link_address, ', '.join(map(str, self.responsible_for_links))))
            return

        # Get the assignment
        assignment = self.get_assignment(bundle)

        # Collect unanswered options
        unanswered_iana_options = bundle.get_unanswered_iana_options()

        # See if there are any addresses on a link that I am responsible for
        for option in unanswered_iana_options:
            for suboption in option.get_options_of_type(IAAddressOption):
                if suboption.address == assignment.address:
                    # This is the address from the assignment: it's ok
                    bundle.mark_handled(option)
                    continue

                if address_in_prefixes(suboption.address, self.responsible_for_links):
                    # Oops, an address on a link that I am responsible for, but it's the wrong one...
                    force_status(bundle.response.options,
                                 StatusCodeOption(STATUS_NOTONLINK,
                                                  "{} is not assigned to you".format(suboption.address)))
                    bundle.mark_handled(option)
                    return
예제 #2
0
    def handle(self, bundle: TransactionBundle):
        """
        Make sure that every :class:`.IANAOption` and :class:`.IATAOption` is answered.

        :param bundle: The transaction bundle
        """
        for option in bundle.get_unanswered_ia_options():
            ia_class = type(option)

            if isinstance(bundle.request, (SolicitMessage, RequestMessage)):
                # If the server will not assign any addresses to any IAs in a subsequent Request from the client, the
                # server MUST send an Advertise message to the client that includes only a Status Code option with code
                # NoAddrsAvail and a status message for the user
                #
                # We do the same for unanswered requests
                bundle.response.options.append(ia_class(option.iaid, options=[
                    StatusCodeOption(STATUS_NOADDRSAVAIL, "No addresses available")
                ]))

            elif isinstance(bundle.request, ConfirmMessage):
                # When the server receives a Confirm message, the server determines whether the addresses in the
                # Confirm message are appropriate for the link to which the client is attached.  If all of the
                # addresses in the Confirm message pass this test, the server returns a status of Success.  If any of
                # the addresses do not pass this test, the server returns a status of NotOnLink.  If the server is
                # unable to perform this test (for example, the server does not have information about prefixes on the
                # link to which the client is connected), or there were no addresses in any of the IAs sent by the
                # client, the server MUST NOT send a reply to the client.
                #
                # The "there were no addresses in any of the IAs sent by the client" check is done by the message
                # handler.
                if not self.authoritative:
                    raise CannotRespondError

                addresses = ', '.join([str(suboption.address)
                                       for suboption in option.get_options_of_type(IAAddressOption)])
                logger.warning("No handler confirmed {} for {}: "
                               "sending NotOnLink status".format(addresses, bundle.get_link_address()))

                force_status(bundle.response.options,
                             StatusCodeOption(STATUS_NOTONLINK, "Those addresses are not appropriate on this link"))

            elif isinstance(bundle.request, RenewMessage):
                # If the server cannot find a client entry for the IA the server returns the IA containing no addresses
                # with a Status Code option set to NoBinding in the Reply message.
                #
                # If the server finds that any of the addresses are not appropriate for the link to which the client is
                # attached, the server returns the address to the client with lifetimes of 0.
                addresses = ', '.join([str(suboption.address)
                                       for suboption in option.get_options_of_type(IAAddressOption)])

                if self.authoritative:
                    logger.warning("No handler renewed {} for {}: "
                                   "withdrawing addresses".format(addresses, bundle.get_link_address()))

                    reply_suboptions = []
                    for suboption in option.get_options_of_type(IAAddressOption):
                        reply_suboptions.append(IAAddressOption(suboption.address,
                                                                preferred_lifetime=0, valid_lifetime=0))

                    bundle.response.options.append(ia_class(option.iaid, options=reply_suboptions))
                else:
                    logger.warning("No handler renewed {} for {}: "
                                   "sending NoBinding status".format(addresses, bundle.get_link_address()))

                    bundle.response.options.append(ia_class(option.iaid, options=[
                        StatusCodeOption(STATUS_NOBINDING, "No addresses assigned to you")
                    ]))

            elif isinstance(bundle.request, RebindMessage):
                # If the server cannot find a client entry for the IA and the server determines that the addresses in
                # the IA are not appropriate for the link to which the client's interface is attached according to the
                # server's explicit configuration information, the server MAY send a Reply message to the client
                # containing the client's IA, with the lifetimes for the addresses in the IA set to zero.  This Reply
                # constitutes an explicit notification to the client that the addresses in the IA are no longer valid.
                # In this situation, if the server does not send a Reply message it silently discards the Rebind
                # message.
                #
                # If the server finds that any of the addresses are no longer appropriate for the link to which the
                # client is attached, the server returns the address to the client with lifetimes of 0.
                if not self.authoritative:
                    raise CannotRespondError

                addresses = ', '.join([str(suboption.address)
                                       for suboption in option.get_options_of_type(IAAddressOption)])
                logger.warning("No handler answered rebind of {} for {}: "
                               "withdrawing addresses".format(addresses, bundle.get_link_address()))

                reply_suboptions = []
                for suboption in option.get_options_of_type(IAAddressOption):
                    reply_suboptions.append(IAAddressOption(suboption.address, preferred_lifetime=0, valid_lifetime=0))

                bundle.response.options.append(ia_class(option.iaid, options=reply_suboptions))

            elif isinstance(bundle.request, DeclineMessage):
                # For each IA in the Decline message for which the server has no binding information, the server adds
                # an IA option using the IAID from the Release message and includes a Status Code option with the value
                # NoBinding in the IA option.  No other options are included in the IA option.
                bundle.response.options.append(ia_class(option.iaid, options=[
                    StatusCodeOption(STATUS_NOBINDING, "No addresses assigned to you")
                ]))

            elif isinstance(bundle.request, ReleaseMessage):
                # For each IA in the Release message for which the server has no binding information, the server adds an
                # IA option using the IAID from the Release message, and includes a Status Code option with the value
                # NoBinding in the IA option.  No other options are included in the IA option.
                bundle.response.options.append(ia_class(option.iaid, options=[
                    StatusCodeOption(STATUS_NOBINDING, "No addresses assigned to you")
                ]))