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
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") ]))