def wrap_response(self, response: ClientServerMessage) -> RelayReplyMessage: """ The incoming message was wrapped in this RelayForwardMessage. Let this RelayForwardMessage then create a RelayReplyMessage with the correct options and wrap the reply . :param response: The response that is going to be sent to the client :return: The RelayReplyMessage wrapping the response :rtype: RelayReplyMessage """ from dhcpkit.ipv6.options import RelayMessageOption my_response = RelayReplyMessage(self.hop_count, self.link_address, self.peer_address) my_relayed_message = self.relayed_message if isinstance(my_relayed_message, RelayForwardMessage): # Our relayed message is another relay message: let it create its own reply my_response.options.append( RelayMessageOption(relayed_message=my_relayed_message. wrap_response(response))) elif isinstance(my_relayed_message, ClientServerMessage): # Our relayed message is a ClientServerMessage, so place the response here in the RelayReplyMessage my_response.options.append( RelayMessageOption(relayed_message=response)) return my_response
def setUp(self): self.relayed_solicit_message = RelayForwardMessage( hop_count=1, link_address=IPv6Address('2001:db8:ffff:1::1'), peer_address=IPv6Address('fe80::3631:c4ff:fe3c:b2f1'), options=[ RelayMessageOption(relayed_message=RelayForwardMessage( hop_count=0, link_address=IPv6Address('::'), peer_address=IPv6Address('fe80::3631:c4ff:fe3c:b2f1'), options=[ RelayMessageOption(relayed_message=SolicitMessage( transaction_id=bytes.fromhex('f350d6'), options=[ ElapsedTimeOption(elapsed_time=0), ClientIdOption(duid=LinkLayerDUID(hardware_type=1, link_layer_address=bytes.fromhex('3431c43cb2f1'))), IANAOption(iaid=bytes.fromhex('c43cb2f1')), IAPDOption(iaid=bytes.fromhex('c43cb2f1')), OptionRequestOption(requested_options=[ OPTION_DNS_SERVERS, ]), ], )), InterfaceIdOption(interface_id=b'Fa2/3'), RemoteIdOption(enterprise_number=9, remote_id=bytes.fromhex('020023000001000a0003000100211c7d486e')), ]) ), InterfaceIdOption(interface_id=b'Gi0/0/0'), RemoteIdOption(enterprise_number=9, remote_id=bytes.fromhex('020000000000000a0003000124e9b36e8100')), RelayIdOption(duid=LinkLayerDUID(hardware_type=1, link_layer_address=bytes.fromhex('121212121212'))), ], )
def test_bad_message_length(self): # Add a fake message type to the registry message_registry[254] = WeirdLengthMessage with self.assertRaisesRegex(ValueError, 'different length'): RelayMessageOption.parse(bytes.fromhex('00090006fe1234567890')) # And clean it up again del message_registry[254]
def setUp(self): # The following attributes must be overruled by child classes # The basics are tested with nested RelayForwardMessages self.packet_fixture = bytes.fromhex( '0c' # message_type: MSG_RELAY_FORW '02' # hop_count '20010db8000000000000000000020001' # link_address '20010db8000000000000000000020002' # peer_address '0009' # option_type: OPTION_RELAY_MSG '0051' # option_length '0c' # message_type: MSG_RELAY_FORW '01' # hop_count '20010db8000000000000000000010001' # link_address '20010db8000000000000000000010002' # peer_address '0009' # option_type: OPTION_RELAY_MSG '002b' # option_length '0c' # message_type: MSG_RELAY_FORW '00' # hop_count '20010db8000000000000000000000001' # link_address '20010db8000000000000000000000002' # peer_address '0009' # option_type: OPTION_RELAY_MSG '0005' # option_length 'ff' # some unknown message_type: 255 '41424344') # some random message_data: 'ABCD' self.message_fixture = RelayForwardMessage( hop_count=2, link_address=IPv6Address('2001:db8::2:1'), peer_address=IPv6Address('2001:db8::2:2'), options=[ RelayMessageOption(relayed_message=RelayForwardMessage( hop_count=1, link_address=IPv6Address('2001:db8::1:1'), peer_address=IPv6Address('2001:db8::1:2'), options=[ RelayMessageOption(relayed_message=RelayForwardMessage( hop_count=0, link_address=IPv6Address('2001:db8::1'), peer_address=IPv6Address('2001:db8::2'), options=[ RelayMessageOption( relayed_message=UnknownMessage( 255, b'ABCD')) ])) ])) ]) self.parse_packet()
def test_absent_option_echo_request(self): relayed_solicit_message = RelayForwardMessage( hop_count=1, link_address=IPv6Address('2001:db8:ffff:1::1'), peer_address=IPv6Address('fe80::3631:c4ff:fe3c:b2f1'), options=[ RelayMessageOption(relayed_message=SolicitMessage( transaction_id=bytes.fromhex('f350d6'), options=[ ElapsedTimeOption(elapsed_time=0), ClientIdOption(duid=LinkLayerDUID(hardware_type=1, link_layer_address=bytes.fromhex('3431c43cb2f1'))), IANAOption(iaid=bytes.fromhex('c43cb2f1')), ], )), EchoRequestOption(requested_options=[OPTION_SUBSCRIBER_ID]), UnknownOption(option_type=65535), InterfaceIdOption(interface_id=b'Fa2/3'), RemoteIdOption(enterprise_number=9, remote_id=bytes.fromhex('020023000001000a0003000100211c7d486e')), ] ) bundle = TransactionBundle(incoming_message=relayed_solicit_message, received_over_multicast=True) self.message_handler.handle(bundle, StatisticsSet()) self.assertIsInstance(bundle.outgoing_message, RelayReplyMessage) self.assertEqual(len(bundle.outgoing_message.options), 2) self.assertIsInstance(bundle.outgoing_message.options[0], InterfaceIdOption) self.assertIsInstance(bundle.outgoing_message.options[1], RelayMessageOption)
def setUp(self): self.bundle = TransactionBundle(relayed_solicit_message, received_over_multicast=False) self.shallow_bundle = TransactionBundle(solicit_message, received_over_multicast=True) self.deep_bundle = TransactionBundle(RelayForwardMessage( hop_count=0, link_address=IPv6Address('2001:db8:ffff:2::1'), peer_address=IPv6Address('fe80::3631:c4ff:fe3c:b2f1'), options=[ RelayMessageOption(relayed_message=relayed_solicit_message), ]), received_over_multicast=False, marks=['some', 'marks']) self.ia_bundle = TransactionBundle(SolicitMessage(options=[ IANAOption(b'0001'), IANAOption(b'0002'), IATAOption(b'0003'), IATAOption(b'0004'), IAPDOption(b'0005'), IAPDOption(b'0006'), ]), received_over_multicast=False) self.option_handlers = [ InterfaceIdOptionHandler(), ]
def relayed_message(self, message): """ Utility method to easily set the relayed message inside this RelayServerMessage. :param message: The new message """ from dhcpkit.ipv6.options import RelayMessageOption relay_message_option = self.get_option_of_type(RelayMessageOption) if relay_message_option: # Overwrite the existing message relay_message_option.relayed_message = message else: # Add a new one relay_message_option = RelayMessageOption(relayed_message=message) self.options.append(relay_message_option)
def parse_incoming_request( incoming_packet: IncomingPacketBundle) -> TransactionBundle: """ Parse the incoming packet and add a RelayServerMessage around it containing the meta-data received from the listener. :param incoming_packet: The received packet :return: The parsed message in a transaction bundle """ # Parse message and validate length, incoming_message = Message.parse(incoming_packet.data) incoming_message.validate() # Determine the next hop count and construct useful log messages if isinstance(incoming_message, RelayForwardMessage): next_hop_count = incoming_message.hop_count + 1 else: next_hop_count = 0 # Collect the relay options relay_options = [] """:type: List[Option]""" relay_options.append( InterfaceIdOption( interface_id=incoming_packet.interface_name.encode('utf-8'))) relay_options.extend(incoming_packet.extra_options) relay_options.append(RelayMessageOption(relayed_message=incoming_message)) # Pretend to be an internal relay and wrap the message like a relay would wrapped_message = RelayForwardMessage( hop_count=next_hop_count, link_address=incoming_packet.link_address, peer_address=incoming_packet.sender, options=relay_options) # Create the transaction bundle return TransactionBundle( incoming_message=wrapped_message, received_over_multicast=incoming_packet.received_over_multicast, marks=incoming_packet.marks)
def setUp(self): self.option_bytes = bytes.fromhex( '00090017ff') + b'ThisIsAnUnknownMessage' self.option_object = RelayMessageOption( relayed_message=UnknownMessage(255, b'ThisIsAnUnknownMessage')) self.parse_option()
""" import unittest from dhcpkit.ipv6.message_registry import message_registry from dhcpkit.ipv6.messages import ClientServerMessage, UnknownMessage from dhcpkit.ipv6.options import RelayMessageOption from dhcpkit.tests.ipv6.options import test_option # A dummy option that may not be in a RelayMessageOption class NonRelayableMessage(UnknownMessage): pass # Add the constraint to disallow putting it in a RelayMessageOption RelayMessageOption.add_may_contain(NonRelayableMessage, max_occurrence=0) # A dummy message that has the wrong length class WeirdLengthMessage(ClientServerMessage): message_type = 254 def load_from(self, buffer: bytes, offset: int = 0, length: int = None): return 4 class RelayMessageOptionTestCase(test_option.OptionTestCase): def setUp(self): self.option_bytes = bytes.fromhex( '00090017ff') + b'ThisIsAnUnknownMessage' self.option_object = RelayMessageOption(
""" import unittest from dhcpkit.ipv6.message_registry import message_registry from dhcpkit.ipv6.messages import UnknownMessage, ClientServerMessage from dhcpkit.ipv6.options import RelayMessageOption from tests.ipv6.options import test_option # A dummy option that may not be in a RelayMessageOption class NonRelayableMessage(UnknownMessage): pass # Add the constraint to disallow putting it in a RelayMessageOption RelayMessageOption.add_may_contain(NonRelayableMessage, max_occurrence=0) # A dummy message that has the wrong length class WeirdLengthMessage(ClientServerMessage): message_type = 254 def load_from(self, buffer: bytes, offset: int = 0, length: int = None): return 4 class RelayMessageOptionTestCase(test_option.OptionTestCase): def setUp(self): self.option_bytes = bytes.fromhex('00090017ff') + b'ThisIsAnUnknownMessage' self.option_object = RelayMessageOption(relayed_message=UnknownMessage(255, b'ThisIsAnUnknownMessage')) self.parse_option()
RelayMessageOption(relayed_message=RelayForwardMessage( hop_count=0, link_address=IPv6Address('::'), peer_address=IPv6Address('fe80::3631:c4ff:fe3c:b2f1'), options=[ RelayMessageOption(relayed_message=SolicitMessage( transaction_id=bytes.fromhex('f350d6'), options=[ ElapsedTimeOption(elapsed_time=0), ClientIdOption(duid=LinkLayerDUID( hardware_type=1, link_layer_address=bytes.fromhex('3431c43cb2f1'))), RapidCommitOption(), IANAOption(iaid=bytes.fromhex('c43cb2f1')), IAPDOption(iaid=bytes.fromhex('c43cb2f1'), options=[ IAPrefixOption( prefix=IPv6Network('::/0')), ]), ReconfigureAcceptOption(), OptionRequestOption(requested_options=[ OPTION_DNS_SERVERS, OPTION_NTP_SERVER, OPTION_SNTP_SERVERS, OPTION_IA_PD, OPTION_IA_NA, OPTION_VENDOR_OPTS, OPTION_SOL_MAX_RT, OPTION_INF_MAX_RT, ]), VendorClassOption(enterprise_number=872), ], )), InterfaceIdOption(interface_id=b'Fa2/3'), RemoteIdOption(enterprise_number=9, remote_id=bytes.fromhex( '020023000001000a0003000100211c7d486e')), ])),
RelayMessageOption(relayed_message=RelayReplyMessage( hop_count=0, link_address=IPv6Address('::'), peer_address=IPv6Address('fe80::3631:c4ff:fe3c:b2f1'), options=[ InterfaceIdOption(interface_id=b'Fa2/3'), RelayMessageOption(relayed_message=AdvertiseMessage( 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')]), ], )) ], ))