def check_decode(f, debug=False): errors = [] # Parse the q/a records with open(f) as x: q, r = DigParser(x) # Grab the hex data with open(f, 'rb') as x: for l in x.readlines(): if l.startswith(b';; QUERY:'): qdata = binascii.unhexlify(l.split()[-1]) elif l.startswith(b';; RESPONSE:'): rdata = binascii.unhexlify(l.split()[-1]) # Parse the hex data qparse = DNSRecord.parse(qdata) rparse = DNSRecord.parse(rdata) # Check records generated from DiG input matches # records parsed from packet data if q != qparse: errors.append(('Question', q.diff(qparse))) if r != rparse: errors.append(('Reply', r.diff(rparse))) # Repack the data qpack = qparse.pack() rpack = rparse.pack() # Check if repacked question data matches original # We occasionally get issues where original packet did not # compress all labels - in this case we reparse packed # record, repack this and compare with the packed data if qpack != qdata: if len(qpack) < len(qdata): # Shorter - possibly compression difference if DNSRecord.parse(qpack).pack() != qpack: errors.append(('Question Pack', (qdata, qpack))) else: errors.append(('Question Pack', (qdata, qpack))) if rpack != rdata: if len(rpack) < len(rdata): if DNSRecord.parse(rpack).pack() != rpack: errors.append(('Reply Pack', (rdata, rpack))) else: errors.append(('Reply Pack', (rdata, rpack))) if debug: if errors: print("ERROR\n") print_errors(errors) print() if input(">>> Inspect [y/n]? ").lower().startswith('y'): code.interact(local=locals()) print() else: print("OK") return errors
def check_decode(f,debug=False): errors = [] # Parse the q/a records with open(f) as x: q,r = DigParser(x) # Grab the hex data with open(f,'rb') as x: for l in x.readlines(): if l.startswith(b';; QUERY:'): qdata = binascii.unhexlify(l.split()[-1]) elif l.startswith(b';; RESPONSE:'): rdata = binascii.unhexlify(l.split()[-1]) # Parse the hex data qparse = DNSRecord.parse(qdata) rparse = DNSRecord.parse(rdata) # Check records generated from DiG input matches # records parsed from packet data if q != qparse: errors.append(('Question',q.diff(qparse))) if r != rparse: errors.append(('Reply',r.diff(rparse))) # Repack the data qpack = qparse.pack() rpack = rparse.pack() # Check if repacked question data matches original # We occasionally get issues where original packet did not # compress all labels - in this case we reparse packed # record, repack this and compare with the packed data if qpack != qdata: if len(qpack) < len(qdata): # Shorter - possibly compression difference if DNSRecord.parse(qpack).pack() != qpack: errors.append(('Question Pack',(qdata,qpack))) else: errors.append(('Question Pack',(qdata,qpack))) if rpack != rdata: if len(rpack) < len(rdata): if DNSRecord.parse(rpack).pack() != rpack: errors.append(('Reply Pack',(rdata,rpack))) else: errors.append(('Reply Pack',(rdata,rpack))) if debug: if errors: print("ERROR\n") print_errors(errors) print() if input(">>> Inspect [y/n]? ").lower().startswith('y'): code.interact(local=locals()) print() else: print("OK") return errors
def new_test(domain,qtype,address="8.8.8.8",port=53,nodig=False,dnssec=False): tcp = False q = DNSRecord.question(domain,qtype) if dnssec: q.add_ar(EDNS0(flags="do",udp_len=4096)) q.header.ad = 1 a_pkt = q.send(address,port) a = DNSRecord.parse(a_pkt) if a.header.tc: tcp = True a_pkt = q.send(address,port,tcp) a = DNSRecord.parse(a_pkt) if not nodig: if dnssec: dig = getoutput("dig +qr +dnssec -p %d %s %s @%s" % ( port, domain, qtype, address)) else: dig = getoutput("dig +qr +noedns +noadflag -p %d %s %s @%s" % ( port, domain, qtype, address)) dig_reply = list(iter(DigParser(dig))) # DiG might have retried in TCP mode so get last q/a q_dig = dig_reply[-2] a_dig = dig_reply[-1] if q != q_dig or a != a_dig: if q != q_dig: print(";;; ERROR: Diff Question differs") for (d1,d2) in q.diff(q_dig): if d1: print(";; - %s" % d1) if d2: print(";; + %s" % d2) if a != a_dig: print(";;; ERROR: Diff Response differs") for (d1,d2) in a.diff(a_dig): if d1: print(";; - %s" % d1) if d2: print(";; + %s" % d2) return if dnssec: fname = "%s-%s-dnssec" % (domain,qtype) else: fname = "%s-%s" % (domain,qtype) print("Writing test file: %s" % (fname)) with open(fname,"w") as f: print(";; Sending:",file=f) print(";; QUERY:",binascii.hexlify(q.pack()).decode(),file=f) print(q,file=f) print(file=f) print(";; Got answer:",file=f) print(";; RESPONSE:",binascii.hexlify(a_pkt).decode(),file=f) print(a,file=f) print(file=f)
def pan_dig(domain): import argparse, sys, time p = argparse.ArgumentParser(description="DNS Client") p.add_argument( "--server", "-s", default="8.8.8.8", metavar="<address:port>", help="Server address:port (default:8.8.8.8:53) (port is optional)") p.add_argument("--query", action='store_true', default=False, help="Show query (default: False)") p.add_argument("--hex", action='store_true', default=False, help="Dump packet in hex (default: False)") p.add_argument("--tcp", action='store_true', default=True, help="Use TCP (default: UDP)") p.add_argument( "--noretry", action='store_true', default=False, help="Don't retry query using TCP if truncated (default: false)") p.add_argument( "--diff", default="", help= "Compare response from alternate nameserver (format: address:port / default: false)" ) p.add_argument( "--dig", action='store_true', default=False, help= "Compare result with DiG - if ---diff also specified use alternative nameserver for DiG request (default: false)" ) p.add_argument("--short", action='store_true', default=True, help="Short output - rdata only (default: false)") p.add_argument("--debug", action='store_true', default=False, help="Drop into CLI after request (default: false)") p.add_argument("domain", metavar="<domain>", help="Query domain") p.add_argument("qtype", metavar="<type>", default="A", nargs="?", help="Query type (default: A)") args = p.parse_args(['--tcp', '--short', domain]) # Construct request q = DNSRecord(q=DNSQuestion(args.domain, getattr(QTYPE, args.qtype))) address, _, port = args.server.partition(':') port = int(port or 53) if args.query: print(";; Sending%s:" % (" (TCP)" if args.tcp else "")) if args.hex: print(";; QUERY:", binascii.hexlify(q.pack()).decode()) print(q) print() a_pkt = q.send(address, port, tcp=args.tcp) a = DNSRecord.parse(a_pkt) if a.header.tc and args.noretry == False: # Truncated - retry in TCP mode a_pkt = q.send(address, port, tcp=True) a = DNSRecord.parse(a_pkt) if args.dig or args.diff: if args.diff: address, _, port = args.diff.partition(':') port = int(port or 53) if args.dig: dig = getoutput("dig +qr -p %d %s %s @%s" % (port, args.domain, args.qtype, address)) dig_reply = list(iter(DigParser(dig))) # DiG might have retried in TCP mode so get last q/a q_diff = dig_reply[-2] a_diff = dig_reply[-1] else: q_diff = DNSRecord(header=DNSHeader(id=q.header.id), q=DNSQuestion(args.domain, getattr(QTYPE, args.qtype))) q_diff = q diff = q_diff.send(address, port, tcp=args.tcp) a_diff = DNSRecord.parse(diff) if a_diff.header.tc and args.noretry == False: diff = q_diff.send(address, port, tcp=True) a_diff = DNSRecord.parse(diff) if args.short: return a.short() else: print(";; Got answer:") if args.hex: print(";; RESPONSE:", binascii.hexlify(a_pkt).decode()) if args.diff and not args.dig: print(";; DIFF :", binascii.hexlify(diff).decode()) print(a) print() if args.dig or args.diff: if q != q_diff: print(";;; ERROR: Diff Question differs") for (d1, d2) in q.diff(q_diff): if d1: print(";; - %s" % d1) if d2: print(";; + %s" % d2) if a != a_diff: print(";;; ERROR: Diff Response differs") for (d1, d2) in a.diff(a_diff): if d1: print(";; - %s" % d1) if d2: print(";; + %s" % d2) if args.debug: code.interact(local=locals()) return None
a = DNSRecord.parse(a_pkt) if a.header.tc and args.noretry == False: # Truncated - retry in TCP mode a_pkt = q.send(address, port, tcp=True) a = DNSRecord.parse(a_pkt) if args.dig or args.diff: if args.diff: address, _, port = args.diff.partition(':') port = int(port or 53) if args.dig: dig = getoutput("dig +qr -p %d %s %s @%s" % (port, args.domain, args.qtype, address)) dig_reply = list(iter(DigParser(dig))) # DiG might have retried in TCP mode so get last q/a q_diff = dig_reply[-2] a_diff = dig_reply[-1] else: q_diff = DNSRecord(header=DNSHeader(id=q.header.id), q=DNSQuestion(args.domain, getattr(QTYPE, args.qtype))) q_diff = q diff = q_diff.send(address, port, tcp=args.tcp) a_diff = DNSRecord.parse(diff) if a_diff.header.tc and args.noretry == False: diff = q_diff.send(address, port, tcp=True) a_diff = DNSRecord.parse(diff) if args.short: