Exemplo n.º 1
0
    def init_response(bundle: TransactionBundle):
        """
        Create the message object in bundle.response

        :param bundle: The transaction bundle
        """
        # Start building the response
        if isinstance(bundle.request, SolicitMessage):
            bundle.response = AdvertiseMessage(bundle.request.transaction_id)

        elif isinstance(bundle.request, (RequestMessage, RenewMessage, RebindMessage,
                                         ReleaseMessage, DeclineMessage, InformationRequestMessage)):
            bundle.response = ReplyMessage(bundle.request.transaction_id)

        elif isinstance(bundle.request, ConfirmMessage):
            # Receipt of Confirm Messages: If [...] there were no addresses in any of the IAs sent by the client, the
            # server MUST NOT send a reply to the client.
            for option in bundle.request.get_options_of_type((IANAOption, IATAOption, IAPDOption)):
                if option.get_options_of_type((IAAddressOption, IAPrefixOption)):
                    # Found an address or prefix option
                    break
            else:
                # Not found: ignore request
                raise CannotRespondError("No IAs present in confirm reply")

            bundle.response = ReplyMessage(bundle.request.transaction_id)

        else:
            raise CannotRespondError("Do not know how to reply to {}".format(type(bundle.request).__name__))

        # Build the plain chain of relay reply messages
        bundle.create_outgoing_relay_messages()
Exemplo n.º 2
0
    def post(self, bundle: TransactionBundle):
        """
        Upgrade the response from a AdvertiseMessage to a ReplyMessage if appropriate
        :param bundle: The transaction bundle
        """
        # Does this transaction even allow rapid commit?
        if not bundle.allow_rapid_commit:
            return

        # We only look for SolicitMessages that have a RapidCommitOption
        if not isinstance(
                bundle.request, SolicitMessage
        ) or not bundle.request.get_option_of_type(RapidCommitOption):
            return

        # And only if the current response is an AdvertiseMessage
        if not isinstance(bundle.response, AdvertiseMessage):
            return

        # Ok, this looks promising, do extra checks if requested
        if not self.rapid_commit_rejections:
            # Ok, we don't want to rapid-commit rejections. Check for them.
            if bundle.get_unhandled_options(
                (IANAOption, IATAOption, IAPDOption)):
                # Unhandled options. We are post-processing, so they are not going to be answered anymore
                return

            # Did we already refuse anything?
            ia_options = [
                option for option in bundle.response.options
                if isinstance(option, (IANAOption, IATAOption))
            ]
            for option in ia_options:
                status = option.get_option_of_type(StatusCodeOption)
                if status and status.status_code == STATUS_NO_ADDRS_AVAIL:
                    # Refusal: don't do anything
                    return

            iapd_options = [
                option for option in bundle.response.options
                if isinstance(option, IAPDOption)
            ]
            for option in iapd_options:
                status = option.get_option_of_type(StatusCodeOption)
                if status and status.status_code == STATUS_NO_PREFIX_AVAIL:
                    # Refusal: don't do anything
                    return

        # It seems the request and response qualify: upgrade to ReplyMessage
        bundle.response = ReplyMessage(bundle.response.transaction_id,
                                       [RapidCommitOption()] +
                                       bundle.response.options)
Exemplo n.º 3
0
    def construct_plain_status_reply(self, bundle: TransactionBundle,
                                     option: StatusCodeOption) -> ReplyMessage:
        """
        Construct a reply message signalling a status code to the client.

        :param bundle: The transaction bundle containing the incoming request
        :param option: The status code option to include in the reply
        :return: A reply with only the bare necessities and a status code
        """
        return ReplyMessage(
            bundle.request.transaction_id,
            options=[
                bundle.request.get_option_of_type(ClientIdOption),
                ServerIdOption(duid=self.server_id), option
            ])
Exemplo n.º 4
0
    def construct_use_multicast_reply(self, bundle: TransactionBundle) -> ReplyMessage:
        """
        Construct a message signalling to the client that they should have used multicast.

        :param bundle: The transaction bundle containing the incoming request
        :return: The proper answer to tell a client to use multicast
        """
        # Make sure we only tell this to requests that came in over unicast
        if bundle.received_over_multicast:
            logger.error("Not telling client to use multicast, they already did...")
            return None

        return ReplyMessage(bundle.request.transaction_id, options=[
            bundle.request.get_option_of_type(ClientIdOption),
            ServerIdOption(duid=self.server_id),
            StatusCodeOption(STATUS_USE_MULTICAST, "You cannot send requests directly to this server, "
                                                   "please use the proper multicast addresses")
        ])
Exemplo n.º 5
0
reply_message = ReplyMessage(
    transaction_id=bytes.fromhex('f350d6'),
    options=[
        IANAOption(iaid=bytes.fromhex('c43cb2f1'),
                   options=[
                       IAAddressOption(
                           address=IPv6Address('2001:db8:ffff:1:c::e09c'),
                           preferred_lifetime=375,
                           valid_lifetime=600),
                   ]),
        IAPDOption(iaid=bytes.fromhex('c43cb2f1'),
                   options=[
                       IAPrefixOption(
                           prefix=IPv6Network('2001:db8:ffcc:fe00::/56'),
                           preferred_lifetime=375,
                           valid_lifetime=600),
                   ]),
        ClientIdOption(duid=LinkLayerDUID(hardware_type=1,
                                          link_layer_address=bytes.fromhex(
                                              '3431c43cb2f1'))),
        ServerIdOption(duid=LinkLayerTimeDUID(hardware_type=1,
                                              time=488458703,
                                              link_layer_address=bytes.fromhex(
                                                  '00137265ca42'))),
        ReconfigureAcceptOption(),
        RecursiveNameServersOption(
            dns_servers=[IPv6Address('2001:4860:4860::8888')]),
    ],
)
Exemplo n.º 6
0
 def test_wrong_way(self):
     with self.assertLogs() as cm:
         TransactionBundle(ReplyMessage(), False)
     self.assertEqual(len(cm.output), 1)
     self.assertRegex(cm.output[0], 'server should not receive')