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.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( '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 handle_relay(self, bundle: TransactionBundle, relay_message_in: RelayForwardMessage, relay_message_out: RelayReplyMessage): """ Handle the options for each relay message pair. :param bundle: The transaction bundle :param relay_message_in: The incoming relay message :param relay_message_out: Thr outgoing relay message """ # See if the relay message contains an ERO ero = relay_message_in.get_option_of_type(EchoRequestOption) if not ero: # Nothing to do return for option_type in ero.requested_options: # Don't do anything if the outgoing relay message already has this one if any(option.option_type == option_type for option in relay_message_out.options): continue # Get the incoming options of the requested type incoming_options = [ option for option in relay_message_in.options if option.option_type == option_type ] for option in incoming_options: # Make sure this option can go into this type of response if not relay_message_out.may_contain(option): return # And append them to the outgoing message if possible relay_message_out.options.append(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.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 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 handle_relay(self, bundle: TransactionBundle, relay_message_in: RelayForwardMessage, relay_message_out: RelayReplyMessage): """ Copy the options for each relay message pair. :param bundle: The transaction bundle :param relay_message_in: The incoming relay message :param relay_message_out: Thr outgoing relay message """ # Make sure this option can go into this type of response if not relay_message_out.may_contain(self.option_class): return # Make sure this option isn't present and then copy those from the request relay_message_out.options = [existing_option for existing_option in relay_message_out.options if not isinstance(existing_option, self.option_class)] relay_message_out.options[:0] = relay_message_in.get_options_of_type(self.option_class)
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 handle_relay(self, bundle: TransactionBundle, relay_message_in: RelayForwardMessage, relay_message_out: RelayReplyMessage): """ Copy the options for each relay message pair. :param bundle: The transaction bundle :param relay_message_in: The incoming relay message :param relay_message_out: Thr outgoing relay message """ # Make sure this option can go into this type of response if not relay_message_out.may_contain(self.option_class): return # Make sure this option isn't present and then copy those from the request relay_message_out.options = [ existing_option for existing_option in relay_message_out.options if not isinstance(existing_option, self.option_class) ] relay_message_out.options[:0] = relay_message_in.get_options_of_type( self.option_class)
class RelayServerMessageTestCase(test_message.MessageTestCase): 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 parse_packet(self): super().parse_packet() self.assertIsInstance(self.message, RelayServerMessage) def test_validate_hop_count(self): self.message.hop_count = -1 with self.assertRaisesRegex(ValueError, 'unsigned 8 bit integer'): self.message.validate() self.message.hop_count = 255 self.message.validate() self.message.hop_count = 256 with self.assertRaisesRegex(ValueError, 'unsigned 8 bit integer'): self.message.validate() def test_validate_link_address(self): self.message.link_address = bytes.fromhex('20010db8000000000000000000000001') with self.assertRaisesRegex(ValueError, 'Link-address .* IPv6 address'): self.message.validate() self.message.link_address = IPv6Address('ff02::1') with self.assertRaisesRegex(ValueError, 'Link-address .* non-multicast IPv6 address'): self.message.validate() def test_validate_peer_address(self): self.message.peer_address = bytes.fromhex('20010db8000000000000000000000001') with self.assertRaisesRegex(ValueError, 'Peer-address .* IPv6 address'): self.message.validate() self.message.peer_address = IPv6Address('ff02::1') with self.assertRaisesRegex(ValueError, 'Peer-address .* non-multicast IPv6 address'): self.message.validate() def test_get_relayed_message(self): self.assertEqual(self.message.relayed_message, self.message_fixture.get_option_of_type(RelayMessageOption).relayed_message) def test_set_relayed_message(self): # Start with empty options self.message.options = [] self.assertEqual(len(self.message.get_options_of_type(RelayMessageOption)), 0) self.message.relayed_message = UnknownMessage(255, b'ThisIsAnUnknownMessage') self.assertEqual(len(self.message.get_options_of_type(RelayMessageOption)), 1) self.assertEqual(self.message.relayed_message.message_data, b'ThisIsAnUnknownMessage') self.message.relayed_message = UnknownMessage(255, b'ThisIsADifferentUnknownMessage') self.assertEqual(len(self.message.get_options_of_type(RelayMessageOption)), 1) self.assertEqual(self.message.relayed_message.message_data, b'ThisIsADifferentUnknownMessage') def test_inner_message(self): # Make sure the inner message is a message that is not a RelayServerMessage self.assertIsInstance(self.message.inner_message, Message) self.assertNotIsInstance(self.message.inner_message, RelayServerMessage) def test_inner_relay_message(self): # Make sure the inner relay message is a RelayServerMessage self.assertIsInstance(self.message.inner_relay_message, RelayServerMessage) # that contains a message that is not a RelayServerMessage self.assertIsInstance(self.message.inner_relay_message.relayed_message, Message) self.assertNotIsInstance(self.message.inner_relay_message.relayed_message, RelayServerMessage) def test_missing_inner_message(self): # Remove the final message and check that it's being handled correctly self.message.inner_relay_message.options = [] self.assertIsNone(self.message.inner_message) self.assertIsNone(self.message.inner_relay_message)
class RelayServerMessageTestCase(test_message.MessageTestCase): 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 parse_packet(self): super().parse_packet() self.assertIsInstance(self.message, RelayServerMessage) def test_validate_hop_count(self): self.check_unsigned_integer_property('hop_count', size=8) def test_validate_link_address(self): self.message.link_address = bytes.fromhex( '20010db8000000000000000000000001') with self.assertRaisesRegex(ValueError, 'Link-address .* IPv6 address'): self.message.validate() self.message.link_address = IPv6Address('ff02::1') with self.assertRaisesRegex( ValueError, 'Link-address .* non-multicast IPv6 address'): self.message.validate() def test_validate_peer_address(self): self.message.peer_address = bytes.fromhex( '20010db8000000000000000000000001') with self.assertRaisesRegex(ValueError, 'Peer-address .* IPv6 address'): self.message.validate() self.message.peer_address = IPv6Address('ff02::1') with self.assertRaisesRegex( ValueError, 'Peer-address .* non-multicast IPv6 address'): self.message.validate() def test_get_relayed_message(self): self.assertEqual( self.message.relayed_message, self.message_fixture.get_option_of_type( RelayMessageOption).relayed_message) def test_set_relayed_message(self): # Start with empty options self.message.options = [] self.assertEqual( len(self.message.get_options_of_type(RelayMessageOption)), 0) self.message.relayed_message = UnknownMessage( 255, b'ThisIsAnUnknownMessage') self.assertEqual( len(self.message.get_options_of_type(RelayMessageOption)), 1) self.assertEqual(self.message.relayed_message.message_data, b'ThisIsAnUnknownMessage') self.message.relayed_message = UnknownMessage( 255, b'ThisIsADifferentUnknownMessage') self.assertEqual( len(self.message.get_options_of_type(RelayMessageOption)), 1) self.assertEqual(self.message.relayed_message.message_data, b'ThisIsADifferentUnknownMessage') def test_inner_message(self): # Make sure the inner message is a message that is not a RelayServerMessage self.assertIsInstance(self.message.inner_message, Message) self.assertNotIsInstance(self.message.inner_message, RelayServerMessage) def test_inner_relay_message(self): # Make sure the inner relay message is a RelayServerMessage self.assertIsInstance(self.message.inner_relay_message, RelayServerMessage) # that contains a message that is not a RelayServerMessage self.assertIsInstance(self.message.inner_relay_message.relayed_message, Message) self.assertNotIsInstance( self.message.inner_relay_message.relayed_message, RelayServerMessage) def test_missing_inner_message(self): # Remove the final message and check that it's being handled correctly self.message.inner_relay_message.options = [] self.assertIsNone(self.message.inner_message) self.assertIsInstance(self.message.inner_relay_message, RelayServerMessage) def test_empty_relayed_message(self): # This uses a getter/setter, so test that code # Make sure we have a message to start with self.assertIsNotNone(self.message.relayed_message) # This sets the message in the RelayMessageOption self.message.relayed_message = None self.assertIsNone(self.message.relayed_message) with self.assertRaisesRegex(ValueError, 'must be an IPv6 DHCP message'): # Validation will complain about the missing message self.message.validate() # This removes the RelayMessageOption altogether option = self.message.get_option_of_type(RelayMessageOption) self.message.options.remove(option) # This still returns None self.assertIsNone(self.message.relayed_message)
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')), ], )
def load_from(self, buffer: bytes, offset: int = 0, length: int = None) -> int: """ Load the internal state of this object from the given buffer. The buffer may contain more data after the structured element is parsed. This data is ignored. :param buffer: The buffer to read data from :param offset: The offset in the buffer where to start reading :param length: The amount of data we are allowed to read from the buffer :return: The number of bytes used from the buffer """ my_offset, option_len = self.parse_option_header(buffer, offset, length) self.subscriber_id = buffer[offset + my_offset : offset + my_offset + option_len] my_offset += option_len return my_offset def save(self) -> bytes: """ Save the internal state of this object as a buffer. :return: The buffer with the data from this element """ return pack("!HH", self.option_type, len(self.subscriber_id)) + self.subscriber_id RelayForwardMessage.add_may_contain(SubscriberIdOption) # The RFC says there is no requirement for servers to include this option in replies, but it is not forbidden RelayReplyMessage.add_may_contain(SubscriberIdOption)
structured element is parsed. This data is ignored. :param buffer: The buffer to read data from :param offset: The offset in the buffer where to start reading :param length: The amount of data we are allowed to read from the buffer :return: The number of bytes used from the buffer """ my_offset, option_len = self.parse_option_header( buffer, offset, length) self.subscriber_id = buffer[offset + my_offset:offset + my_offset + option_len] my_offset += option_len return my_offset def save(self) -> Union[bytes, bytearray]: """ Save the internal state of this object as a buffer. :return: The buffer with the data from this element """ return pack('!HH', self.option_type, len( self.subscriber_id)) + self.subscriber_id RelayForwardMessage.add_may_contain(SubscriberIdOption) # The RFC says there is no requirement for servers to include this option in replies, but it is not forbidden RelayReplyMessage.add_may_contain(SubscriberIdOption)
my_offset, option_len = self.parse_option_header( buffer, offset, length) self.enterprise_number = unpack_from('!I', buffer, offset=offset + my_offset)[0] my_offset += 4 remote_id_length = option_len - 4 self.remote_id = buffer[offset + my_offset:offset + my_offset + remote_id_length] my_offset += remote_id_length return my_offset def save(self) -> Union[bytes, bytearray]: """ Save the internal state of this object as a buffer. :return: The buffer with the data from this element """ return pack('!HHI', self.option_type, len(self.remote_id) + 4, self.enterprise_number) + self.remote_id RelayForwardMessage.add_may_contain(RemoteIdOption) # The RFC says there is no requirement for servers to include this option in replies, but it is not forbidden RelayReplyMessage.add_may_contain(RemoteIdOption)
:param buffer: The buffer to read data from :param offset: The offset in the buffer where to start reading :param length: The amount of data we are allowed to read from the buffer :return: The number of bytes used from the buffer """ my_offset, option_len = self.parse_option_header(buffer, offset, length) self.enterprise_number = unpack_from('!I', buffer, offset=offset + my_offset)[0] my_offset += 4 remote_id_length = option_len - 4 self.remote_id = buffer[offset + my_offset:offset + my_offset + remote_id_length] my_offset += remote_id_length return my_offset def save(self) -> bytes: """ Save the internal state of this object as a buffer. :return: The buffer with the data from this element """ return pack('!HHI', self.option_type, len(self.remote_id) + 4, self.enterprise_number) + self.remote_id RelayForwardMessage.add_may_contain(RemoteIdOption) # The RFC says there is no requirement for servers to include this option in replies, but it is not forbidden RelayReplyMessage.add_may_contain(RemoteIdOption)