def main_helper(resolver: Resolver, domain_name: str, dns_server_ip: str, ipv6: bool, verbose: bool): try: answers: List[ResourceRecord] = resolver.ask(domain_name, dns_server_ip, ipv6, verbose) except (DNSFormatError, DNSNameError, DNSNotImplementedError, DNSServerFailureError, DNSRefusedError, DNSNoMatchingResourceRecordError, DNSZeroCounterError) as e: print("") print(e) else: ResolverCore.print_answers(domain_name, answers)
def ask(domain_name: str, dns_server: str, ipv6: bool = False, verbose: bool = False) -> List[ResourceRecord]: """ Resolves a domain name by starting the name resolution at the specified dns server ip. Can optionally specify whether an ipv6 address or verbose output is desired. :param domain_name: the domain name that will be resolved :param dns_server: the dns server ipv4 address that the name resolution process will begin with :param ipv6: a boolean flag indicating whether you want to find an ipv6 address for the domain name :param verbose: a boolean flag indicating whether you want verbose output for the name resolution process :raises: DNSFormatError, DNSServerFailureError, DNSNameError, DNSNotImplementedError, DNSRefusedError, DNSZeroCounterError, DNSNoMatchingResourceRecordError :return: a list of the resource records the domain name resolved to """ with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as udp_socket: resolver: ResolverCore = ResolverCore(udp_socket, verbose, dns_server, Random()) type = 28 if ipv6 else 1 answers: List[ResourceRecord] = resolver.resolve_domain_name( domain_name, dns_server, type) return answers
def test_refused_error(self): """ Test case for when the first response given by the queried dns name server gives a refused error. """ resolver: ResolverCore = ResolverCore(self.mock_socket, False, "1.2.3.4", self.mock_random) self.assertRaises(DNSRefusedError, resolver.resolve_domain_name, "www.cs.ubc.ca", "1.2.3.4", 1)
def test_zero_counter_error_counter_two(self): """ Test case for when the counter is set to two and exhausted. """ resolver: ResolverCore = ResolverCore(self.mock_socket, False, "1.2.3.4", self.mock_random, 2) self.assertRaises(DNSZeroCounterError, resolver.resolve_domain_name, "www.google.ca", "1.2.3.4", 1)
def test_no_matching_resource_record_error(self): """ Test case for when the first response given by the queried dns name server finds records for the searched for domain name. However, none of these records match the desired record types. """ resolver: ResolverCore = ResolverCore(self.mock_socket, False, "1.2.3.4", self.mock_random) self.assertRaises(DNSNoMatchingResourceRecordError, resolver.resolve_domain_name, "www.cs.ubc.ca", "1.2.3.4", 28)
def test_cname_resolution(self): """ Test case for when name resolution requires performing a cname resolution. """ resolver: ResolverCore = ResolverCore(self.mock_socket, False, "1.2.3.4", self.mock_random) answers: List[ResourceRecord] = resolver.resolve_domain_name("prep.ai.mit.edu", "1.2.3.4", 1) expected_answer: List[ResourceRecord] = [ResourceRecord('ftp.gnu.org', 1, 1, 300, 4, '208.118.235.20')] self.assertEqual(answers, expected_answer)
def test_matching_authoritative_response(self): """ Test case for when the first response given by the queried dns name server is an authoritative response with a matching resource record type. """ resolver: ResolverCore = ResolverCore(self.mock_socket, False, "1.2.3.4", self.mock_random) answers: List[ResourceRecord] = resolver.resolve_domain_name("www.cs.ubc.ca", "1.2.3.4", 1) expected_answer: List[ResourceRecord] = [ResourceRecord('www.cs.ubc.ca', 1, 1, 3600, 4, '142.103.6.5')] self.assertEqual(answers, expected_answer)
def test_incorrect_query_id(self): """ Test case for when a response is received that does not match the query id of the previously sent message. Thus, the resolver discards the packet and waits for another packet with the correct query id. """ resolver: ResolverCore = ResolverCore(self.mock_socket, False, "1.2.3.4", self.mock_random) answers: List[ResourceRecord] = resolver.resolve_domain_name("www.cs.ubc.ca", "1.2.3.4", 1) expected_answer: List[ResourceRecord] = [ResourceRecord('www.cs.ubc.ca', 1, 1, 3600, 4, '142.103.6.5')] self.assertEqual(answers, expected_answer)
def test_name_server_response_then_authoritative_ipv6(self): """ Test case for when the first two responses non-authoritative responses and the final one is authoritative and contains a matching resource record. The first two responses both contain the ip address a name server, so we do not need to do a separate lookup for the ip address of the name server. """ resolver: ResolverCore = ResolverCore(self.mock_socket, False, "1.2.3.4", self.mock_random) answers: List[ResourceRecord] = resolver.resolve_domain_name("www.google.com", "1.2.3.4", 28) expected_answer: List[ResourceRecord] = [ResourceRecord('www.google.com', 28, 1, 300, 16, '2607:f8b0:400a:803::2004')] self.assertEqual(answers, expected_answer)
def test_cname_resolution(self): """ Test case for when two different cname resolutions and one name server resolution needs to be performed before finding an authoritative response. """ resolver: ResolverCore = ResolverCore(self.mock_socket, False, "1.2.3.4", self.mock_random) answers: List[ResourceRecord] = resolver.resolve_domain_name( "finance.google.ca", "1.2.3.4", 1) expected_answer: List[ResourceRecord] = [ ResourceRecord('www3.l.google.com', 1, 1, 300, 4, '216.58.193.78') ] self.assertEqual(answers, expected_answer)
def test_cname_and_name_resolution_ipv6(self): """ Test case for when two different cname resolutions and one name server resolution needs to be performed before finding an authoritative response. Searching for an ipv6 address. """ resolver: ResolverCore = ResolverCore(self.mock_socket, False, "1.2.3.4", self.mock_random) answers: List[ResourceRecord] = resolver.resolve_domain_name( "finance.google.ca", "1.2.3.4", 28) expected_answer: List[ResourceRecord] = [ ResourceRecord('www3.l.google.com', 28, 1, 300, 16, '2607:f8b0:400a:800::200e') ] self.assertEqual(answers, expected_answer)
def test_matching_authoritative_response_ipv6(self): """ Test case for when the first response given by the queried dns name server is an authoritative response with an ipv6 resource record type, which is what was asked for. """ resolver: ResolverCore = ResolverCore(self.mock_socket, False, "1.2.3.4", self.mock_random) answers: List[ResourceRecord] = resolver.resolve_domain_name( "www.google.com", "1.2.3.4", 28) expected_answer: List[ResourceRecord] = [ ResourceRecord('www.google.com', 28, 1, 300, 16, '2607:f8b0:400a:800::2004') ] self.assertEqual(answers, expected_answer)
def test_name_resolution(self): """ Test case for when name resolution requires performing a name resolution. This is also a case where the name resolution returns multiple answers. """ resolver: ResolverCore = ResolverCore(self.mock_socket, False, "1.2.3.4", self.mock_random) answers: List[ResourceRecord] = resolver.resolve_domain_name( "www.stanford.edu", "1.2.3.4", 1) expected_answer: List[ResourceRecord] = [ ResourceRecord('www.stanford.edu', 1, 1, 60, 4, '54.218.91.228'), ResourceRecord('www.stanford.edu', 1, 1, 60, 4, '52.27.175.139'), ResourceRecord('www.stanford.edu', 1, 1, 60, 4, '52.10.247.217') ] self.assertEqual(answers, expected_answer)