def test_bad_option_length(self): with self.assertRaisesRegex(ValueError, 'must have length 4'): CLTTimeOption.parse( bytes.fromhex('002e' # Option type: OPTION_CLT_TIME '0003' # Option length: 3 (must be 4) '00000384' # Client-Last-Transaction time: 900 )) with self.assertRaisesRegex(ValueError, 'must have length 4'): CLTTimeOption.parse( bytes.fromhex('002e' # Option type: OPTION_CLT_TIME '0005' # Option length: 5 (must be 4) '00000384' # Client-Last-Transaction time: 900 ))
def test_bad_option_length(self): with self.assertRaisesRegex(ValueError, 'must have length 4'): CLTTimeOption.parse(bytes.fromhex( '002e' # Option type: OPTION_CLT_TIME '0003' # Option length: 3 (must be 4) '00000384' # Client-Last-Transaction time: 900 )) with self.assertRaisesRegex(ValueError, 'must have length 4'): CLTTimeOption.parse(bytes.fromhex( '002e' # Option type: OPTION_CLT_TIME '0005' # Option length: 5 (must be 4) '00000384' # Client-Last-Transaction time: 900 ))
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 setUp(self): self.option_bytes = bytes.fromhex( '002e' # Option type: OPTION_CLT_TIME '0004' # Option length: 4 '00000384' # Client-Last-Transaction time: 900 ) self.option_object = CLTTimeOption(clt_time=900) self.parse_option()
def test_parse_wrong_type(self): with self.assertRaisesRegex(ValueError, 'does not contain CLTTimeOption data'): option = CLTTimeOption() option.load_from(b'00020010ff12000000000000000000000000abcd')
def generate_client_data_options(self, client_row_ids: Iterable[int], requested_options: Iterable[int]) \ -> Iterable[Tuple[IPv6Address, ClientDataOption]]: """ Create a generator for the data of the specified client rows/ :param client_row_ids: The list of client rows what we are interested in :param requested_options: Option types explicitly requested by the leasequery client :return: The client data options for those rows """ # Some helper variables relay_data_requested = OPTION_LQ_RELAY_DATA in requested_options extra_data_requested = any([ requested_option for requested_option in requested_options if requested_option != OPTION_LQ_RELAY_DATA ]) # Determine which columns we are interested in, no point in dragging in large chunks of data for nothing selected_columns = [ "id", "client_id", "link_address", "last_interaction" ] if extra_data_requested: selected_columns.append("options") if relay_data_requested: selected_columns.append("relay_data") now = int(time.time()) client_cur = self.db.execute( "SELECT {} FROM clients WHERE id IN ({})".format( ', '.join(selected_columns), ', '.join(map(str, client_row_ids)))) for client_row in client_cur: # This is the first part of the tuple we yield link_address = IPv6Address(client_row['link_address']) # Reconstruct the DUID of the client duid = self.decode_duid(client_row['client_id']) client_id_option = ClientIdOption(duid) # How long ago did we speak to this client? clt_option = CLTTimeOption(now - client_row['last_interaction']) # Get the requested options if extra_data_requested: stored_options = self.decode_options(client_row['options']) stored_options = self.filter_requested_options( stored_options, requested_options) else: stored_options = [] # Get the relay data if relay_data_requested: relay_data_option = self.build_relay_data_option_from_relay_data( client_row['relay_data']) else: relay_data_option = None # Build all the options for this client options = [client_id_option, clt_option ] + stored_options # type: List[Option] if relay_data_option: options.append(relay_data_option) # Add all addresses address_cur = self.db.execute( "SELECT address, preferred_lifetime_end, valid_lifetime_end, options " "FROM addresses WHERE client_fk=? AND valid_lifetime_end>?", (client_row['id'], now)) for address_row in address_cur: options.append( IAAddressOption( address=IPv6Address(address_row['address']), preferred_lifetime=max( 0, address_row['preferred_lifetime_end'] - now), valid_lifetime=max( 0, address_row['valid_lifetime_end'] - now), options=self.decode_options(address_row['options']))) # Add all prefixes prefix_cur = self.db.execute( "SELECT first_address, last_address, " "preferred_lifetime_end, valid_lifetime_end, options " "FROM prefixes WHERE client_fk=? AND valid_lifetime_end>?", (client_row['id'], now)) for prefix_row in prefix_cur: prefixes = list( summarize_address_range( IPv6Address(prefix_row['first_address']), IPv6Address(prefix_row['last_address']))) if len(prefixes) != 1: logger.error( "Ignoring invalid prefix range in leasequery db: {} - {}" .format(prefix_row['first_address'], prefix_row['last_address'])) continue options.append( IAPrefixOption( prefix=prefixes[0], preferred_lifetime=max( 0, prefix_row['preferred_lifetime_end'] - now), valid_lifetime=max( 0, prefix_row['valid_lifetime_end'] - now), options=self.decode_options(prefix_row['options']))) # We got everything, yield it yield link_address, ClientDataOption(options)