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] $ cat hello.nim
stdout.write("hello, world!\n")
Static (musl): $ nim --gcc.exe:musl-gcc --gcc.linkerexe:musl-gcc --passL:-static c -d:release hello.nim
$ ldd ./hello
not a dynamic executable
Execution Time: 0m0.002s (real)
Total Syscalls: 16
Unique Syscalls: 8
Size (KiB): 95K (78K stripped)
Dynamic (glibc): $ nim c -d:release hello.nim
$ ldd ./hello
linux-vdso.so.1 => (0x00007ffc994b6000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f7c88785000)
libc.so.6 => /lib64/libc.so.6 (0x00007f7c883b8000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7c88989000)
Execution Time: 0m0.002s (real)
Total Syscalls: 42
Unique Syscalls: 13
Size (KiB): 91K (79K stripped)
Which I think is actually pretty reasonable for a high-level GC'd language.
https://passtheaardvark-img.pgs.sh/screen.png