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 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 setUp(self): self.option_bytes = bytes.fromhex( '002f' # Option type: OPTION_LQ_RELAY_DATA '003b' # Option length: 59 '20010db8000000000000000000000002' # Peer address: 2001:db8::2 '0c' # Message type: MSG_RELAY_FORW '00' # Hop count: 0 '20010db8000000000000000000000002' # Link address: 2001:db8::2 'fe800000000000000000000000000022' # Peer address: fe80::22 '0012' # Option type: OPTION_INTERFACE_ID '0005' # Option length: 5 '4661322f33' # Interface ID: 'Fa2/3' ) self.option_object = LQRelayDataOption( peer_address=IPv6Address('2001:db8::2'), relay_message=RelayForwardMessage( hop_count=0, link_address=IPv6Address('2001:db8::2'), peer_address=IPv6Address('fe80::22'), options=[ InterfaceIdOption(interface_id=b'Fa2/3'), ] ) ) self.parse_option()
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 encode_relay_messages( self, relay_chain: Optional[RelayForwardMessage]) -> bytes: """ Encode a chain of relay messages as bytes. :param relay_chain: The incoming relay messages :return: The bytes """ if not relay_chain: return b'' current_in = relay_chain current_out = None out = None while isinstance(current_in, RelayForwardMessage): new_relay_message = RelayForwardMessage( hop_count=current_in.hop_count, link_address=current_in.link_address, peer_address=current_in.peer_address, options=self.filter_storable_options(current_in.options)) if not current_out: out = new_relay_message else: current_out.relayed_message = new_relay_message current_in = current_in.relayed_message current_out = new_relay_message # Save the resulting chain if not out: return b'' return out.save()
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 setUp(self): self.option_bytes = bytes.fromhex( '002d' # Option type 45: OPTION_CLIENT_DATA '0099' # Option length: 153 '0001' # Option type 1: OPTION_CLIENT_ID '0015' # Option length: 21 '0002' # DUID type: DUID_EN '00009d10' # Enterprise ID: 40208 '303132333435363738396162636465' # Identifier: '0123456789abcde' '0005' # Option type: OPTION_IAADDR '0018' # Option length: 24 '20010db800000000000000000000cafe' # IPv6 address: 2001:db8::cafe '00000708' # Preferred lifetime: 1800 '00000e10' # Valid lifetime: 3600 '001a' # Option type: OPTION_IAPREFIX '0019' # Option length: 25 '00000708' # Preferred lifetime: 1800 '00000e10' # Valid lifetime: 3600 '30' # Prefix length: 48 '20010db8000100000000000000000000' '002e' # Option type: OPTION_CLT_TIME '0004' # Option length: 4 '00000384' # Client-Last-Transaction time: 900 '002f' # Option type: OPTION_LQ_RELAY_DATA '003b' # Option length: 59 '20010db8000000000000000000000002' # Peer address: 2001:db8::2 '0c' # Message type: MSG_RELAY_FORW '00' # Hop count: 0 '20010db8000000000000000000000002' # Link address: 2001:db8::2 'fe800000000000000000000000000022' # Peer address: fe80::22 '0012' # Option type: OPTION_INTERFACE_ID '0005' # Option length: 5 '4661322f33' # Interface ID: 'Fa2/3' ) self.option_object = ClientDataOption(options=[ ClientIdOption(EnterpriseDUID(40208, b'0123456789abcde')), IAAddressOption(address=IPv6Address('2001:db8::cafe'), preferred_lifetime=1800, valid_lifetime=3600), IAPrefixOption(prefix=IPv6Network('2001:db8:1::/48'), preferred_lifetime=1800, valid_lifetime=3600), CLTTimeOption(clt_time=900), LQRelayDataOption(peer_address=IPv6Address('2001:db8::2'), relay_message=RelayForwardMessage( hop_count=0, link_address=IPv6Address('2001:db8::2'), peer_address=IPv6Address('fe80::22'), options=[ InterfaceIdOption(interface_id=b'Fa2/3'), ] )) ]) self.parse_option()
def test_empty_message(self): with self.assertLogs(level=logging.WARNING) as cm: bundle = TransactionBundle(incoming_message=RelayForwardMessage(), received_over_multicast=True) result = self.message_handler.handle(bundle, StatisticsSet()) self.assertIsNone(result) self.assertEqual(len(cm.output), 1) self.assertRegex(cm.output[0], '^WARNING:.*:A server should not receive')
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)
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'))), 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')), ])), InterfaceIdOption(interface_id=b'Gi0/0/0'), RemoteIdOption( enterprise_number=9, remote_id=bytes.fromhex('020000000000000a0003000124e9b36e8100')), ], )