top | item 30171758

(no title)

_paulc | 4 years ago

Simple python version which does a bit more validation (checks response matches query) and also supports CNAMEs and different record types (37 lines - using dnslib library) - though there is still a lot of logic missing (handling failed NSs, IPv6 only NSs, cycles etc)

    from dnslib import DNSRecord,DNSError,QTYPE
    
    ROOT_NS='198.41.0.4'
    
    def find_cname(a,qtype,cname):
        for r in a.rr:
            if QTYPE[r.rtype] == qtype and r.rname == cname:
                return str(r.rdata)
            elif QTYPE[r.rtype] == 'CNAME' and r.rname == cname:
                return find_cname(a,qtype,str(r.rdata))
        return resolve(str(r.rdata),qtype,ROOT_NS)
    
    def resolve(name,qtype='A',ns=ROOT_NS):
        print(f"dig -r @{ns} {name} {qtype}")
        q = DNSRecord.question(name,qtype)
        a = DNSRecord.parse(q.send(ns))
        if q.header.id != a.header.id:
            raise DNSError('Response transaction id does not match query transaction id')
        for r in a.rr:
            if QTYPE[r.rtype] == qtype and r.rname == name:
                return str(r.rdata)
            elif QTYPE[r.rtype] == 'CNAME' and r.rname == name:
                return find_cname(a,qtype,str(r.rdata))
        for r in a.ar:
            if QTYPE[r.rtype] == 'A':
                return resolve(name,qtype,str(r.rdata))
        for r in a.auth:
            if QTYPE[r.rtype] == 'NS':
                return resolve(name,qtype,resolve(str(r.rdata),'A',ROOT_NS))
        raise ValueError("Cant resolve domain")
    
    if __name__ == '__main__':
        import sys
        def get_arg(i,d):
            try: return sys.argv[i]
            except IndexError: return d
        print(resolve(get_arg(1,"google.com"), get_arg(2,"A"), get_arg(3,ROOT_NS)))
Disclaimer: I am author of dnslib [https://github.com/paulc/dnslib]

Edit: Better CNAME support

discuss

order