def decode_request(message): # decode the query message = dns.message.from_wire(message) myprint(type(message)) myprint("---query----") myprint(message) myprint("------------") # section eg: message.question or message.answer # section=message.question # name="A" # rdclass= 1 # IN the internet # rdtype= 1 # A 1 a host address # rrs = message.find_rrset(section, name, rdclass, rdtype) # rrs = message.get_rrset(section, name, rdclass, rdtype) myprint("id %s" % message.id) myprint("rcode %s" % message.rcode()) myprint(" rcode %s" % dns.rcode.to_text(message.rcode())) # print dir(message.rcode) myprint("opcode %s" % message.opcode()) myprint(" opcode %s" % dns.opcode.to_text(message.opcode())) myprint("flags %s" % message.flags) myprint(" flags %s" % dns.flags.to_text(message.flags)) myprint("index %s" % message.index) for rrset in message.question: # list of dns.rrset.RRset objects myprint("----> rrset: %s" % rrset) myprint(" covers %i" % rrset.covers) myprint(" rdclass %i" % rrset.rdclass) myprint(" rdtype %i" % rrset.rdtype) myprint(" ttl %i" % rrset.ttl) myprint(" name %s" % rrset.name) return message
def main(): # Parse the arguments parser = argparse.ArgumentParser(description='A basic DoH client') parser.add_argument('label', metavar='label', type=str, help='The label to make the query for') parser.add_argument('uri', metavar='uri', type=str, help='The URI template to make the query to') parser.add_argument('type', metavar='type', type=str, default='A', help='The type to query for') parser.add_argument('--get', dest='req', action='store_const', const=get, default=post, help='Make a GET request instead of POST') parser.add_argument('--insecure', action='store_true', help='Ignore TLS/SSL issues') args = parser.parse_args() # Build the response, using the values determined from the arguments resp = args.req(args.label, args.uri, args.type) message = dns.message.from_wire(resp) # If NoError, print message info if message.rcode() == 0: print('Question:') for result in message.question: print('\t' + str(result)) print('\nAnswer:') for result in message.answer: print('\t' + str(result)) print('\nAuthority:') for result in message.authority: print('\t' + str(result)) print('\nAdditional:') for result in message.additional: print('\t' + str(result)) elif message.rcode() == 3: print('Got NXDOMAIN, label does not exist\n') print('Question:') for result in message.question: print('\t' + str(result)) print('\nAuthority:') for result in message.authority: print('\t' + str(result)) print('\nAdditional:') for result in message.additional: print('\t' + str(result)) else: print('Error, got rcode ' + str(message.rcode()))
def main(): global testdomain if len(sys.argv) < 2: sys.stderr.write("Usage error") return 2 # create resolver object resolver = dns.resolver.Resolver() # create common query for all nameservers query = dns.message.make_query(testdomain, "A") # list of faulty nameservers renegades = [] # process nameserver records for nsarg in sys.argv[1:]: # get ip addresses of nameserver (ns, addrs) = get_ns_addrs(nsarg) message = None for addr in addrs: try: dbg_print("Query nameserver %s (%s) for A rr %s" % (ns, addr, testdomain)) message = dns.query.udp(query, addr, 3) break except dns.exception.Timeout, e: # timeout means that it is good - some nameservers do not # send answers for domain which are not delegated on them break # if there is any answer it means that recursive query was done if message and message.rcode() == dns.rcode.NXDOMAIN: dbg_print("Answer with result received") renegades.append(ns)
def to_doh_simple(message): simple = {"Status": message.rcode()} for f in dns.flags.Flag: if f != dns.flags.Flag.AA and f != dns.flags.Flag.QR: # DoH JSON doesn't need AA and omits it. DoH JSON is only # used in replies so the QR flag is implied. simple[f.name] = (message.flags & f) != 0 for i, s in enumerate(message.sections): k = dns.message.MessageSection.to_text(i).title() simple[k] = [] for rrs in s: simple[k].extend(flatten_rrset(rrs)) # we don't encode the ecs_client_subnet field return simple
def process_message(self, message): """Process one message in the transfer. The message should have the same relativization as was specified when the `dns.xfr.Inbound` was created. The message should also have been created with `one_rr_per_rrset=True` because order matters. Returns `True` if the transfer is complete, and `False` otherwise. """ if self.txn is None: replacement = self.rdtype == dns.rdatatype.AXFR self.txn = self.txn_manager.writer(replacement) rcode = message.rcode() if rcode != dns.rcode.NOERROR: raise TransferError(rcode) # # We don't require a question section, but if it is present is # should be correct. # if len(message.question) > 0: if message.question[0].name != self.origin: raise dns.exception.FormError("wrong question name") if message.question[0].rdtype != self.rdtype: raise dns.exception.FormError("wrong question rdatatype") answer_index = 0 if self.soa_rdataset is None: # # This is the first message. We're expecting an SOA at # the origin. # if not message.answer or message.answer[0].name != self.origin: raise dns.exception.FormError("No answer or RRset not " "for zone origin") rrset = message.answer[0] name = rrset.name rdataset = rrset if rdataset.rdtype != dns.rdatatype.SOA: raise dns.exception.FormError("first RRset is not an SOA") answer_index = 1 self.soa_rdataset = rdataset.copy() if self.rdtype == dns.rdatatype.IXFR: if self.soa_rdataset[0].serial == self.serial: # # We're already up-to-date. # self.done = True elif dns.serial.Serial(self.soa_rdataset[0].serial) < \ self.serial: # It went backwards! raise SerialWentBackwards else: if self.is_udp and len(message.answer[answer_index:]) == 0: # # There are no more records, so this is the # "truncated" response. Say to use TCP # raise UseTCP # # Note we're expecting another SOA so we can detect # if this IXFR response is an AXFR-style response. # self.expecting_SOA = True # # Process the answer section (other than the initial SOA in # the first message). # for rrset in message.answer[answer_index:]: name = rrset.name rdataset = rrset if self.done: raise dns.exception.FormError("answers after final SOA") if rdataset.rdtype == dns.rdatatype.SOA and \ name == self.origin: # # Every time we see an origin SOA delete_mode inverts # if self.rdtype == dns.rdatatype.IXFR: self.delete_mode = not self.delete_mode # # If this SOA Rdataset is equal to the first we saw # then we're finished. If this is an IXFR we also # check that we're seeing the record in the expected # part of the response. # if rdataset == self.soa_rdataset and \ (self.rdtype == dns.rdatatype.AXFR or (self.rdtype == dns.rdatatype.IXFR and self.delete_mode)): # # This is the final SOA # if self.expecting_SOA: # We got an empty IXFR sequence! raise dns.exception.FormError('empty IXFR sequence') if self.rdtype == dns.rdatatype.IXFR \ and self.serial != rdataset[0].serial: raise dns.exception.FormError('unexpected end of IXFR ' 'sequence') self.txn.replace(name, rdataset) self.txn.commit() self.txn = None self.done = True else: # # This is not the final SOA # self.expecting_SOA = False if self.rdtype == dns.rdatatype.IXFR: if self.delete_mode: # This is the start of an IXFR deletion set if rdataset[0].serial != self.serial: raise dns.exception.FormError( "IXFR base serial mismatch") else: # This is the start of an IXFR addition set self.serial = rdataset[0].serial self.txn.replace(name, rdataset) else: # We saw a non-final SOA for the origin in an AXFR. raise dns.exception.FormError('unexpected origin SOA ' 'in AXFR') continue if self.expecting_SOA: # # We made an IXFR request and are expecting another # SOA RR, but saw something else, so this must be an # AXFR response. # self.rdtype = dns.rdatatype.AXFR self.expecting_SOA = False self.delete_mode = False self.txn.rollback() self.txn = self.txn_manager.writer(True) # # Note we are falling through into the code below # so whatever rdataset this was gets written. # # Add or remove the data if self.delete_mode: self.txn.delete_exact(name, rdataset) else: self.txn.add(name, rdataset) if self.is_udp and not self.done: # # This is a UDP IXFR and we didn't get to done, and we didn't # get the proper "truncated" response # raise dns.exception.FormError('unexpected end of UDP IXFR') return self.done
# decode the query message = dns.message.from_wire(message) print type(message) print "---query----" print message print "------------" # section eg: message.question or message.answer # section=message.question # name="A" # rdclass= 1 # IN the internet # rdtype= 1 # A 1 a host address # rrs = message.find_rrset(section, name, rdclass, rdtype) # rrs = message.get_rrset(section, name, rdclass, rdtype) print "id %s" % message.id print "rcode %s" % message.rcode() print " rcode %s" % dns.rcode.to_text(message.rcode()) # print dir(message.rcode) print "opcode %s" % message.opcode() print " opcode %s" % dns.opcode.to_text(message.opcode()) print "flags %s" % message.flags print " flags %s" % dns.flags.to_text(message.flags) print "index %s" % message.index for rrset in message.question: # list of dns.rrset.RRset objects print "----> rrset: %s" % rrset print " covers %i" % rrset.covers print " rdclass %i" % rrset.rdclass print " rdtype %i" % rrset.rdtype print " ttl %i" % rrset.ttl print " name %s" % rrset.name
# decode the query message = dns.message.from_wire(message) myprint(type(message)) myprint("---query----") myprint(message) myprint("------------") # section eg: message.question or message.answer # section=message.question # name="A" # rdclass= 1 # IN the internet # rdtype= 1 # A 1 a host address # rrs = message.find_rrset(section, name, rdclass, rdtype) # rrs = message.get_rrset(section, name, rdclass, rdtype) myprint("id %s" % message.id) myprint("rcode %s" % message.rcode()) myprint(" rcode %s" % dns.rcode.to_text(message.rcode())) # print dir(message.rcode) myprint("opcode %s" % message.opcode()) myprint(" opcode %s" % dns.opcode.to_text(message.opcode())) myprint("flags %s" % message.flags) myprint(" flags %s" % dns.flags.to_text(message.flags)) myprint("index %s" % message.index) for rrset in message.question: # list of dns.rrset.RRset objects myprint("----> rrset: %s" % rrset) myprint(" covers %i" % rrset.covers) myprint(" rdclass %i" % rrset.rdclass) myprint(" rdtype %i" % rrset.rdtype) myprint(" ttl %i" % rrset.ttl) myprint(" name %s" % rrset.name)
def _parse(self): try: message = dns.message.from_wire(self.data) except dns.exception.ShortHeader: print("The message is less than 12 octets long.", file=sys.stderr) raise except dns.exception.TrailingJunk: print("There were octets in the message past the end of the proper DNS message.", file=sys.stderr) raise except dns.exception.BadEDNS: print("An OPT record was in the wrong section, or occurred more than once.", file=sys.stderr) raise except dns.exception.BadTSIG: print("A TSIG record was not the last record of the additional data section.", file=sys.stderr) raise message_id = message.id flags = [] for flag in dns.flags.to_text(message.flags).split(): flags.append(flag) flags.append(dns.opcode.to_text(message.opcode())) flags.append(dns.rcode.to_text(message.rcode())) total_questions = len(message.question) total_answer_rrs = len(message.answer) total_authority_rrs = len(message.authority) total_additional_rrs = len(message.additional) questions = [] for question in message.question: questions.append({"name": question.name.to_text(), "type": dns.rdatatype.to_text(question.rdtype), "class": dns.rdataclass.to_text(question.rdclass)}) answer_rrs = [] for answer in message.answer: rdata_items = [] for item in answer.items: rdata_items.append(item.to_text()) answer_rrs.append({"name": answer.name.to_text(), "type": dns.rdatatype.to_text(answer.rdtype), "class": dns.rdataclass.to_text(answer.rdclass), "ttl": answer.ttl, "rdata_length": len(answer.items), "rdata": rdata_items}) authority_rrs = [] for authority in message.authority: rdata_items = [] for item in authority.items: rdata_items.append(item.to_text()) authority_rrs.append({"name": authority.name.to_text(), "type": dns.rdatatype.to_text(dnsauthority.rdtype), "class": dns.rdataclass.to_text(authority.rdclass), "ttl": authority.ttl, "rdata_length": len(authority.items), "rdata": rdata_items}) additional_rrs = [] for additional in message.additional: rdata_items = [] for item in additional.items: rdata_items.append(item.to_text()) additional_rrs.append({"name": additional.name.to_text(), "type": dns.rdatatype.to_text(additional.rdtype), "class": dns.rdataclass.to_text(additional.rdclass), "ttl": additional.ttl, "rdata_length": len(additional.items), "rdata": rdata_items}) return (message_id, flags, total_questions, total_answer_rrs, total_authority_rrs, total_additional_rrs, questions, answer_rrs, authority_rrs, additional_rrs)