def test_no_cache_entry(self):
     cache = RecordCache(0)
     resolver = Resolver(5, cache)
     self.assertEqual(
         resolver.gethostbyname("google-public-dns-a.google.com"),
         ("google-public-dns-a.google.com", [], ["8.8.8.8"]),
     )
     self.assertEqual(
         resolver.gethostbyname("google-public-dns-b.google.com"),
         ("google-public-dns-b.google.com", [], ["8.8.4.4"]),
     )
 def test_gethostbyname_non_existent(self):
     resolver = Resolver(5, None)
     self.assertEqual(resolver.gethostbyname("bonobo.putin"),
                      ("bonobo.putin", [], []))
     self.assertEqual(resolver.gethostbyname("gumpenfisch.net"),
                      ("gumpenfisch.net", [], []))
     self.assertEqual(
         resolver.gethostbyname("ThisDomainDoesNotExist.false"),
         ("ThisDomainDoesNotExist.false", [], []))
     self.assertEqual(
         resolver.gethostbyname("JustSoWeHaveMoreThanThree.domains"),
         ("JustSoWeHaveMoreThanThree.domains", [], []))
예제 #3
0
class TestResolver(TestCase):
    """Resolver tests"""
    def setUp(self):
        self.resolver = Resolver(5, True, 0)

    def test_testOne(self):
        RR = ResourceRecord(Name("invalid_address.asdas"), Type.A, Class.IN, 2, ARecordData("1.4.1"))
        self.resolver.cache.add_record(RR)
        hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname("invalid_address.asdas")
        self.assertEqual(ipaddrlist[0], "1.4.1")

    def test_testTwo(self):
        time.sleep(4)
        hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname("invalid_address.asdas")
        self.assertEqual(ipaddrlist, [])
예제 #4
0
class TestServer(TestCase):
    def setUp(self):
        self.resolver = Resolver(5, False, 0, "127.0.0.1")

    def test_testOne(self):
        hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname("kaas.lol")
        self.assertEqual("1.1.1.1", ipaddrlist[0])

    def test_testTwo(self):
        hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname("ru.nl")
        self.assertEqual("131.174.78.60", ipaddrlist[0])

    def test_testThree(self):
        hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname("google.com")
        self.assertEqual([], ipaddrlist)
예제 #5
0
def resolve():
    """Resolve a hostname using the resolver """
    parser = ArgumentParser(description="DNS Client")
    parser.add_argument("hostname", help="hostname to resolve")
    parser.add_argument("--timeout",
                        metavar="time",
                        type=int,
                        default=5,
                        help="resolver timeout")
    parser.add_argument("-c",
                        "--caching",
                        action="store_true",
                        help="Enable caching")
    parser.add_argument("-t",
                        "--ttl",
                        metavar="time",
                        type=int,
                        default=0,
                        help="TTL value of cached entries (if > 0)")
    args = parser.parse_args()

    s = SocketWrapper(53)
    s.start()
    rc = RecordCache(3600)
    resolver = Resolver(args.timeout, args.caching, args.ttl, s, rc)
    hostname, aliaslist, ipaddrlist = resolver.gethostbyname(args.hostname)
    s.shutdown()
    rc.write_cache_file()

    print(hostname)
    print([rr.rdata.address for rr in aliaslist])
    print([rr.rdata.address for rr in ipaddrlist])
예제 #6
0
 def test_check_query(self):
     res = Resolver(5, False, 3600)
     hostname, alias, ips = res.gethostbyname("nickstracke.xyz")
     ip1 = ips[0].rdata.address
     ip2 = socket.gethostbyname("nickstracke.xyz")
     self.assertEqual(ip1, ip2)
     res.shutdown()
def resolve():
    """Resolve a hostname using the resolver """
    parser = ArgumentParser(description="DNS Client")
    parser.add_argument("hostname", help="hostname to resolve")
    parser.add_argument("--timeout", metavar="time", type=int, default=5,
                        help="resolver timeout")
    parser.add_argument("-c", "--caching", action="store_true",
                        help="Enable caching")
    parser.add_argument("-t", "--ttl", metavar="time", type=int, default=0,
                        help="TTL value of cached entries (if > 0)")
    args = parser.parse_args()

    cache = RecordCache(args.ttl)
    if args.caching:
        cache.read_cache_file()
        resolver = Resolver(args.timeout, cache)
    else:
        resolver = Resolver(args.timeout)
    hostname, aliaslist, ipaddrlist = resolver.gethostbyname(args.hostname)
    if args.caching:
        cache.write_cache_file()

    print(hostname)
    print(aliaslist)
    print(ipaddrlist)
예제 #8
0
def resolve():
    """Resolve a hostname using the resolver """
    parser = ArgumentParser(description="DNS Client")
    parser.add_argument("hostname", help="hostname to resolve")
    parser.add_argument("--timeout",
                        metavar="time",
                        type=int,
                        default=5,
                        help="resolver timeout")
    parser.add_argument("-c",
                        "--caching",
                        action="store_true",
                        help="Enable caching")
    parser.add_argument("-t",
                        "--ttl",
                        metavar="time",
                        type=int,
                        default=0,
                        help="TTL value of cached entries (if > 0)")
    parser.add_argument("-n",
                        "--nameserver",
                        type=str,
                        default="198.41.0.4",
                        help="set nameserver")
    args = parser.parse_args()

    resolver = Resolver(args.timeout, args.caching, args.ttl, args.nameserver)
    resolver.doLogging = True
    hostname, aliaslist, ipaddrlist = resolver.gethostbyname(args.hostname)

    print(hostname)
    print(aliaslist)
    print(ipaddrlist)
예제 #9
0
 def run(self):
     """ Run the handler thread """
     print "*Ping* We've got a message!"
     # Handle DNS request
     resolver = Resolver(self.caching, self.ttl)
     aliasRecords = []
     addressRecords = []
     # Read and resolve the questions one-by-one
     questions = self.request.questions
     for question in questions:
         hostname = question.qname
         (hostname, aliases, addresses) = resolver.gethostbyname(hostname)
         
         for alias in aliases:
             aliasData = dns.resource.RecordData.create(Type.CNAME, alias)
             aliasRecord = dns.resource.ResourceRecord(hostname, Type.CNAME, Class.IN, 9001, aliasData) # TODO fix ttl
             aliasRecords.append(aliasRecord)
         for address in addresses:
             addressData = dns.resource.RecordData.create(Type.A, address)
             addressRecord = dns.resource.ResourceRecord(hostname, Type.A, Class.IN, 9001, addressData)
             addressRecords.append(addressRecord)
         
     # Crafting of the response
     respHeader = self.request.header
     respHeader.qr = 1
     respHeader.qd_count = 0
     respHeader.an_count = 1
     
     respMessage = dns.message.Message(respHeader, [], addressRecords + aliasRecords, [], [])
     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     respMessageByte = respMessage.to_bytes()
     sock.sendto(respMessageByte, self.clientAddr)
     print "Ended request: " + hostname
     sock.close()
 def test_gethostbyname(self):
     resolver = Resolver(5, None)
     self.assertEqual(
         resolver.gethostbyname("google-public-dns-a.google.com"),
         ("google-public-dns-a.google.com", [], ["8.8.8.8"]),
     )
     self.assertEqual(
         resolver.gethostbyname("google-public-dns-b.google.com"),
         ("google-public-dns-b.google.com", [], ["8.8.4.4"]),
     )
     self.assertEqual(
         resolver.gethostbyname("con1.nipr.mil"),
         ("con1.nipr.mil", [], ["199.252.157.234"]),
     )
     self.assertEqual(
         # recommended domain to test
         resolver.gethostbyname("gaia.cs.umass.edu"),
         ("gaia.cs.umass.edu", [], ["128.119.245.12"]),
     )
예제 #11
0
class TestResolverCache(TestCase):
    """Resolver tests with cache enabled"""
    def setUp(self):
        self.RC = RecordCache(100,
                              "dns/ResolverTestCache.cache")  #never written to
        self.res = Resolver(5, True, -1)

    def test_resolver_caching(self):
        hostname = "google.com"
        t = time.time()
        self.res.gethostbyname(hostname)
        d1 = time.time() - t
        t = time.time()
        self.res.gethostbyname(hostname)
        d2 = time.time() - t
        self.assertTrue(d2 < d1)

    def tearDown(self):
        self.res.shutdown()
예제 #12
0
    def serve(self):
        """Start serving requests"""
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.bind(("", self.port))

        while not self.done:
            data, address = sock.recvfrom(65565)
            message = Message.from_bytes(data)

            rd = message.header.rd
            rcode = 0
            aa = 1

            self.log("REQUEST RECIEVED:", address)
            answers, authorities, additionals = self.zone_resolution(message.questions)

            if answers == []:
                if authorities == [] and additionals == []:
                    self.log("\tZONE RESOLUTION FAILED")
                    answers = self.consult_cache(message.questions)

                    if answers == []:
                        self.log("\tCACHE LOOKUP FAILED")
                        rcode = 3
                    else:
                        aa = 0

                if rcode == 3 and rd == 1:
                    rcode = 0
                    self.log("\tCALLING RESOLVER")
                    resolver = Resolver(5, True, 0)
                    resolver.rd = 0
                    resolver.rootip = "198.41.0.4"
                    for q in message.questions:
                        self.log("\t\tRESOLVING:", q.qname)

                        hostname, namelist, iplist = resolver.gethostbyname(str(q.qname))
                        if hostname == str(q.qname):
                            for ip in iplist:
                                answers.append(ResourceRecord(q.qname, Type.A, Class.IN, self.ttl, ARecordData(ip)))
                            for n in namelist:
                                answers.append(ResourceRecord(q.qname, Type.CNAME, Class.IN, self.ttl, CNAMERecordData(n)))

            self.log("SENDING RESPONSE:", rcode, "\n")
            mess = self.build_message(message.header.ident, rd, aa, rcode, message.questions, answers, authorities, additionals)
            sock.sendto(mess.to_bytes(), address)
 def test_invalid_domain_from_cache(self):
     cache = RecordCache(0)
     resolver = Resolver(5, cache)
     cache.add_record(
         ResourceRecord(
             name=Name("bonobo.putin"),
             type_=Type.A,
             class_=Class.IN,
             ttl=60,
             rdata=ARecordData("1.0.0.1"),
         ))
     cache.add_record(
         ResourceRecord(
             name=Name("bonobo.putin"),
             type_=Type.CNAME,
             class_=Class.IN,
             ttl=60,
             rdata=CNAMERecordData(Name("putin.bonobo")),
         ))
     self.assertEqual(resolver.gethostbyname("bonobo.putin"),
                      ("bonobo.putin", ["putin.bonobo."], ["1.0.0.1"]))
 def test_expired_cache_entry(self):
     cache = RecordCache(0)
     resolver = Resolver(5, cache)
     cache.add_record(
         ResourceRecord(
             name=Name("hw.gumpe"),
             type_=Type.A,
             class_=Class.IN,
             ttl=0,
             rdata=ARecordData("1.0.0.2"),
         ))
     cache.add_record(
         ResourceRecord(
             name=Name("hw.gumpe"),
             type_=Type.CNAME,
             class_=Class.IN,
             ttl=0,
             rdata=CNAMERecordData(Name("gumpe.hw")),
         ))
     self.assertEqual(resolver.gethostbyname("hw.gumpe"),
                      ("hw.gumpe", [], []))
예제 #15
0
                        metavar="time",
                        type=int,
                        default=Consts.DEFAULT_TIMEOUT,
                        help="resolver timeout")
    parser.add_argument("-c",
                        "--caching",
                        action="store_true",
                        help="Enable caching")
    parser.add_argument("-t",
                        "--ttl",
                        metavar="time",
                        type=int,
                        default=0,
                        help="TTL value of cached entries")
    args = parser.parse_args()

    if not args.hostname:
        parser.print_help()
        exit()

    # Resolve hostname
    resolver = Resolver(args.timeout, args.caching, args.ttl)
    hostname, aliaslist, ipaddrlist = resolver.gethostbyname(args.hostname)
    if args.caching:
        resolver.cache.write_cache_file()

    # Print output
    print(hostname)
    print(aliaslist)
    print(ipaddrlist)
예제 #16
0
    def run(self):
        """ Run the handler thread"""
        msg = Message.from_bytes(self.data)
        header = msg.header
        recursion = header.rd != 0
        questions = msg.questions

        answers = []
        authorative = []
        additional = []
        for question in questions:
            qname = question.qname
            qtype = question.qtype
            if question.qclass != Class.IN:
                pass
            domains = self.getdomains(str(qname))
            for domain in domains:
                if not self.zone.records.get(domain, False):
                    continue
                for rr in self.zone.records[domain]:
                    if (rr.type_ == Type.A or rr.type_
                            == Type.CNAME) and domain == str(qname):
                        answers.append(rr)
                    if rr.type_ == Type.NS:
                        authorative.append(rr)
                        for rec in self.zone.records[str(rr.rdata.nsdname)]:
                            if rec not in additional:
                                if rec.qtype == Type.A:
                                    additional.append(rec)
            if authorative or answers:
                header_response = Header(9001, 0, 1, len(answers),
                                         len(authorative), len(additionals))
                header_response.qr = True
                header_response.opcode(1)
                header_response.aa(False)
                header_respones.tc(False)
                header_response.rd(False)
                header_response.ra(True)
                header_response.z(False)
                header_respones.rcode(False)

                respons = Message(header_response, [question], answers,
                                  authorities, additionals)

                self.sock.sendto(respons.to_bytes(), self.addr)
                break

            if recursion and (qtype == Type.A or qtype == Type.CNAME):
                answers = []
                resolver = Resolver(100, False, 0, True)
                (hostname, aliaslist,
                 ipaddrlist) = resolver.gethostbyname(question.qname)
                header_response = Header(9001, 0, 1,
                                         len(aliaslist) + len(ipaddrlist), 0,
                                         0)
                header_response.qr = 1
                header_response.opcode = 1
                header_response.aa = 0
                header_response.tc = 0
                header_response.rd = 0
                header_response.ra = 1
                header_response.rcode = 0

                for addr in ipaddrlist:
                    answers.append(
                        ResourceRecord.from_dict({
                            "name": str(hostname),
                            "type": str(Type.A),
                            "class": str(Class.IN),
                            "ttl": 0,
                            "rdata": {
                                "address": str(addr)
                            }
                        }))
                for alias in aliaslist:
                    answers.append(
                        ResourceRecord.from_dict({
                            "name": str(hostname),
                            "type": str(Type.CNAME),
                            "class": str(Class.IN),
                            "ttl": 0,
                            "rdata": {
                                "cname": str(alias)
                            }
                        }))
                response = Message(header_response, questions, answers)
                self.sock.sendto(response.to_bytes(), self.addr)
                break
예제 #17
0
class RequestHandler(Thread):
    """A handler for requests to the DNS server"""
    def __init__(self, data, addr, catalog, sock, caching, cache, ttl=0):
        """Initialize the handler thread"""
        super().__init__()
        self.daemon = True
        self.data = data
        self.addr = addr
        self.catalog = catalog
        self.cache = cache
        self.resolver = Resolver(5, caching, ttl, sock, self.cache)
        self.sock = sock

    def run(self):
        """ Run the handler thread"""
        mess = self.data
        rd = mess.header.rd
        questions = mess.questions

        for q in questions:
            name = q.qname
            class_ = q.qclass
            type_ = q.qtype

            zone_resolution = self.resolveZone(str(name), type_, class_)
            if zone_resolution:
                mess.additionals += zone_resolution["additionals"]
                mess.authorities += zone_resolution["authorities"]
                mess.answers += zone_resolution["answers"]

                if type_ != Type.CNAME:
                    cnames = [
                        rr for rr in zone_resolution["answers"]
                        if rr.type_ == Type.CNAME
                    ]
                    for cn in cnames:
                        questions.append(
                            Question(cn.rdata.cname, Type.A, cn.class_))

                mess.header.aa = 1
                continue

            cached_rrs = self.cache.lookup(str(name), type_, class_)
            cached_cname = self.cache.lookup(str(name), Type.CNAME, class_)
            if cached_rrs:
                mess.answers += cached_rrs
                continue
            elif cached_cname and type_ != Type.CNAME:
                for rr in cached_cname:
                    mess.answer.append(rr)
                    questions.append(Question(rr.rdata.cname, type_, class_))
                continue
            elif not rd:
                matched = self.cache.matchByLabel(str(name), Type.NS, class_)
                mess.authorities += matched
                for m in matched:
                    glue = self.cache.lookup(str(m.rdata.nsdname), Type.A,
                                             class_)
                    mess.additionals += glue
                continue

            if rd:
                hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname(
                    str(name))
                mess.answers += aliaslist
                mess.answers += ipaddrlist
                mess.header.ra = 1
                continue

        # adjust header
        mess.header.qr = 1
        mess.header.qd_count = len(mess.questions)
        mess.header.an_count = len(mess.answers)
        mess.header.ns_count = len(mess.authorities)
        mess.header.ar_count = len(mess.additionals)

        msg = (mess, self.addr[0], self.addr[1])
        self.sock.send(msg)
        self.cache.write_cache_file(
        )  #write the cached records so they dont get lost

    def resolveZone(self, name, type_, class_):
        name = Name(name)
        root_domain = name.labels[-2:]
        root_domain = root_domain[0] + "." + root_domain[1]

        if root_domain not in self.catalog.zones:
            return {}

        zone = self.catalog.zones[root_domain]

        current_domain = name

        if str(current_domain) in zone.records:
            records = zone.records[str(current_domain)]
            rrs_a = [
                rr for rr in records
                if (rr.type_ == Type.A or rr.type_ == Type.CNAME)
                and rr.class_ == Class.IN
            ]
            if rrs_a:
                return {"answers": rrs_a, "additionals": [], "authorities": []}

        while True:
            if str(current_domain) in zone.records:
                records = zone.records[str(current_domain)]

                rrs_ns = [
                    rr for rr in records
                    if rr.type_ == Type.NS and rr.class_ == Class.IN
                ]
                if rrs_ns:
                    ret = {
                        "answers": [],
                        "authorities": rrs_ns,
                        "additionals": []
                    }

                    for rr_ns in rrs_ns:
                        ns_name = str(rr_ns.rdata.nsdname)
                        if ns_name in zone.records:
                            ns_records = zone.records[ns_name]
                            glue = [
                                rr for rr in ns_records
                                if rr.type_ == Type.A and rr.class_ == Class.IN
                            ]
                            ret["additionals"] += glue

                    return ret

            current_domain.labels = current_domain.labels[1:]
            if not current_domain.labels:
                break

        return {}
예제 #18
0
 def testResolver(self):
     res = Resolver(0, False, 0)
     self.assertEqual(res.gethostbyname("google.com")[0], "google.com")
     self.assertEqual(
         res.gethostbyname("symposium.thalia.nu")[2],
         res.gethostbyname("reis.thalia.nu")[2])