def test_create_domain_name_query(self): """ Test case to create a DNS query to ask for a particular domain name from a dns server. """ encoded_dns_message: BytesIO = DNSMessageUtilities.create_domain_name_query( 'www.cs.ubc.ca', 12345, 15) encoded_dns_message.seek( 0 ) # need to start reading the dns message from the start of the BytesIO object dns_message = DNSMessage.decode_dns_message(encoded_dns_message) # Check that the query id is correct self.assertEqual(dns_message.query_id, 12345) # Check that flags are correct self.assertEqual(dns_message.is_response, False) self.assertEqual(dns_message.opcode, 0) self.assertEqual(dns_message.authoritative, False) self.assertEqual(dns_message.is_truncated, False) self.assertEqual(dns_message.recursion_desired, False) self.assertEqual(dns_message.recursion_available, False) self.assertEqual(dns_message.rcode, 0) # Check that record/question counts are correct self.assertEqual(dns_message.question_count, 1) self.assertEqual(dns_message.answer_count, 0) self.assertEqual(dns_message.nameserver_count, 0) self.assertEqual(dns_message.additional_count, 0) # Check that the question was properly decoded self.assertEqual(dns_message.dns_questions[0].name, 'www.cs.ubc.ca') self.assertEqual(dns_message.dns_questions[0].type, 15) self.assertEqual(dns_message.dns_questions[0].response_class, 1)
def _handle_tracing_for_dns_query(self, domain_name_query: BytesIO, next_dns_server_ip: str) -> None: """ If the resolver is set to verbose, then print tracing information for the dns query. :param domain_name_query: the domain name query that is sent to the next_dns_server_ip. :param next_dns_server_ip: the dns server we send the domain name query to. :return: None """ if self.verbose: print('') print('') domain_name_query.seek( 0) # need to ensure we are at the start of the writer # to be able to correctly decode into a DNS Question DNSMessage.decode_dns_message(domain_name_query).print_dns_query( next_dns_server_ip)
def test_decode_dns_message(self): """ Test case to decode an entire dns message. This dns message contains resource records with pointers. """ dns_message: DNSMessage = DNSMessage.decode_dns_message( BytesIO(self.dns_message_encoded)) # Check that the query id is correct self.assertEqual(dns_message.query_id, 1) # Check that flags are correct self.assertEqual(dns_message.is_response, True) self.assertEqual(dns_message.opcode, 0) self.assertEqual(dns_message.authoritative, False) self.assertEqual(dns_message.is_truncated, False) self.assertEqual(dns_message.recursion_desired, False) self.assertEqual(dns_message.recursion_available, True) self.assertEqual(dns_message.rcode, 0) # Check that record/question counts are correct self.assertEqual(dns_message.question_count, 1) self.assertEqual(dns_message.answer_count, 0) self.assertEqual(dns_message.nameserver_count, 4) self.assertEqual(dns_message.additional_count, 8) # Check that the question was properly decoded self.assertEqual(dns_message.dns_questions[0].name, 'www.cs.ubc.ca') self.assertEqual(dns_message.dns_questions[0].type, 1) self.assertEqual(dns_message.dns_questions[0].response_class, 1) # Check that the first name server record was correctly decoded self.assertEqual(dns_message.name_server_records[0].name, 'ca') self.assertEqual(dns_message.name_server_records[0].type, 2) self.assertEqual(dns_message.name_server_records[0].response_class, 1) self.assertEqual(dns_message.name_server_records[0].ttl, 150873) self.assertEqual(dns_message.name_server_records[0].rdlength, 15) self.assertEqual(dns_message.name_server_records[0].rdata, 'x.ca-servers.ca') # Check that the first additional record was correctly decoded self.assertEqual(dns_message.additional_records[0].name, 'x.ca-servers.ca') self.assertEqual(dns_message.additional_records[0].type, 1) self.assertEqual(dns_message.additional_records[0].response_class, 1) self.assertEqual(dns_message.additional_records[0].ttl, 150873) self.assertEqual(dns_message.additional_records[0].rdlength, 4) self.assertEqual(dns_message.additional_records[0].rdata, '199.253.250.68')
def _receive_dns_message(self, expected_query_id: int) -> DNSMessage: """ Receives and decodes a dns message from a dns server. If the received dns message does not have the expected query_id or is not a response, then simply wait for the next message received. :param expected_query_id: the query id we expect the incoming dns response to possess. :return: the dns response that has been received, successfully decoded, and has the correct query_id and is_ response value. """ received_data: bytes = self.udp_socket.recv(1024) received_dns_message: DNSMessage = DNSMessage.decode_dns_message( BytesIO(received_data)) if (received_dns_message.query_id != expected_query_id) or not received_dns_message.is_response: received_dns_message = self._receive_dns_message(expected_query_id) return received_dns_message