def __init__(self, incoming_message: Message, received_over_multicast: bool, received_over_tcp: bool = False, allow_rapid_commit: bool = False, marks: Iterable[str] = None): self.incoming_message = incoming_message """The incoming message including the relay chain""" self.received_over_multicast = received_over_multicast """A flag indicating whether the client used multicast to contact the server""" self.received_over_tcp = received_over_tcp """A flag indicating whether the client used TCP to contact the server""" self.allow_unicast = False """Allow the client use unicast to contact the server. Set to True by handlers""" self.allow_rapid_commit = allow_rapid_commit """Allow rapid commit? May be set to True on creation, may be set to False by handlers, not vice versa""" # Convenience properties for easy access to the request and chain without having to walk the chain every time self.request = None """The incoming request without the relay messages""" self.incoming_relay_messages = [] """The chain of relay messages starting with the one closest to the client""" self.request, self.incoming_relay_messages = split_relay_chain( incoming_message) # Check that TCP connections don't include any further relay messages if self.received_over_tcp and len(self.incoming_relay_messages) > 1: raise ValueError("Relayed message on TCP connection, ignoring") self.responses = MessagesList() """This is where we keep our responses, potentially more than one""" self.outgoing_relay_messages = None """This is where the user puts the reply relay chain by calling :meth:`create_outgoing_relay_messages`""" # Extra state to track handling of the message self.handled_options = [] """A list of options from the request that have been handled, only applies to IA type options""" self.marks = set(marks or []) """A set of marks that have been applied to this message""" self.handler_data = {} """A place for handlers to store data related to this transaction"""
def __init__(self, incoming_message: Message, received_over_multicast: bool, received_over_tcp: bool = False, allow_rapid_commit: bool = False, marks: Iterable[str] = None): self.incoming_message = incoming_message """The incoming message including the relay chain""" self.received_over_multicast = received_over_multicast """A flag indicating whether the client used multicast to contact the server""" self.received_over_tcp = received_over_tcp """A flag indicating whether the client used TCP to contact the server""" self.allow_unicast = False """Allow the client use unicast to contact the server. Set to True by handlers""" self.allow_rapid_commit = allow_rapid_commit """Allow rapid commit? May be set to True on creation, may be set to False by handlers, not vice versa""" # Convenience properties for easy access to the request and chain without having to walk the chain every time self.request = None """The incoming request without the relay messages""" self.incoming_relay_messages = [] """The chain of relay messages starting with the one closest to the client""" self.request, self.incoming_relay_messages = split_relay_chain(incoming_message) # Check that TCP connections don't include any further relay messages if self.received_over_tcp and len(self.incoming_relay_messages) > 1: raise ValueError("Relayed message on TCP connection, ignoring") self.responses = MessagesList() """This is where we keep our responses, potentially more than one""" self.outgoing_relay_messages = None """This is where the user puts the reply relay chain by calling :meth:`create_outgoing_relay_messages`""" # Extra state to track handling of the message self.handled_options = [] """A list of options from the request that have been handled, only applies to IA type options""" self.marks = set(marks or []) """A set of marks that have been applied to this message""" self.handler_data = {} """A place for handlers to store data related to this transaction"""
def __init__(self, incoming_message: Message, received_over_multicast: bool, allow_rapid_commit: bool = False, marks: Iterable[str] = None): self.incoming_message = incoming_message """The incoming message including the relay chain""" self.received_over_multicast = received_over_multicast """A flag indicating whether the client used multicast to contact the server""" self.allow_unicast = False """Allow the client use unicast to contact the server. Set to True by handlers""" self.allow_rapid_commit = allow_rapid_commit """Allow rapid commit? May be set to True on creation, may be set to False by handlers, not vice versa""" # Convenience properties for easy access to the request and chain without having to walk the chain every time self.request = None """The incoming request without the relay messages""" self.incoming_relay_messages = [] """The chain of relay messages starting with the one closest to the client""" self.request, self.incoming_relay_messages = split_relay_chain( incoming_message) self.response = None """This is where the user puts the response :class:`.ClientServerMessage`""" self.outgoing_relay_messages = None """This is where the user puts the reply relay chain by calling :meth:`create_outgoing_relay_messages`""" # Extra state to track handling of the message self.handled_options = [] """A list of options from the request that have been handled, only applies to IA type options""" self.marks = set(marks or []) """A set of marks that have been applied to this message""" self.handler_data = {} """A place for handlers to store data related to this transaction"""
def get_transaction_info(message: DHCPKafkaMessage) -> Dict[str, object]: """ Extract interesting data from the incoming message :param message: The Kafka DHCP message :return: A dictionary of stuff """ # Split the message into usable blocks request, incoming_relay_messages = split_relay_chain(message.message_in) # Get the DUID and create representations for in the database duid_obj = request.get_option_of_type(ClientIdOption).duid duid = '0x' + codecs.encode(duid_obj.save(), 'hex').decode('ascii') # Get the link-local address of the client link_local = str(incoming_relay_messages[0].peer_address) # Get the Interface ID and create representation for in the database interface_id_obj = incoming_relay_messages[0].get_option_of_type(InterfaceIdOption) if interface_id_obj: try: interface_id = interface_id_obj.interface_id.decode('ascii') except ValueError: interface_id = '0x' + codecs.encode(interface_id_obj.interface_id, 'hex').decode('ascii') else: interface_id = '' # Get the Remote ID and create representation for in the database remote_id_obj = incoming_relay_messages[0].get_option_of_type(RemoteIdOption) if remote_id_obj: try: remote_id = '{}:{}'.format(remote_id_obj.enterprise_number, remote_id_obj.remote_id.decode('ascii')) except ValueError: remote_id = '{}:0x{}'.format(remote_id_obj.enterprise_number, codecs.encode(remote_id_obj.remote_id, 'hex').decode('ascii')) else: remote_id = '' # Get the request type request_type = request.__class__.__name__ if request_type.endswith('Message'): request_type = request_type[:-7] # Get the response type response = message.message_out while isinstance(response, RelayReplyMessage): response = response.relayed_message if isinstance(response, ClientServerMessage): response_type = response.__class__.__name__ else: response_type = None return { 'duid': duid, 'interface_id': interface_id, 'remote_id': remote_id, 'link_local': link_local, 'request_type': request_type, 'response_type': response_type, }