1   
   2   
   3   
   4   
   5   
   6   
   7   
   8   
   9   
  10   
  11   
  12   
  13   
  14   
  15   
  16   
  17   
  18  """DNS Messages""" 
  19   
  20  from __future__ import absolute_import 
  21   
  22  from io import StringIO 
  23  import struct 
  24  import time 
  25   
  26  import dns.edns 
  27  import dns.exception 
  28  import dns.flags 
  29  import dns.name 
  30  import dns.opcode 
  31  import dns.entropy 
  32  import dns.rcode 
  33  import dns.rdata 
  34  import dns.rdataclass 
  35  import dns.rdatatype 
  36  import dns.rrset 
  37  import dns.renderer 
  38  import dns.tsig 
  39  import dns.wiredata 
  40   
  41  from ._compat import long, xrange, string_types 
  42   
  43   
  45      """The DNS packet passed to from_wire() is too short.""" 
   46   
  47   
  49      """The DNS packet passed to from_wire() has extra junk at the end of it.""" 
   50   
  51   
  53      """The header field name was not recognized when converting from text 
  54      into a message.""" 
   55   
  56   
  57 -class BadEDNS(dns.exception.FormError): 
   58      """An OPT record occurred somewhere other than the start of 
  59      the additional data section.""" 
   60   
  61   
  62 -class BadTSIG(dns.exception.FormError): 
   63      """A TSIG record occurred somewhere other than the end of 
  64      the additional data section.""" 
   65   
  66   
  68      """A TSIG with an unknown key was received.""" 
   69   
  70   
  71   
  72  QUESTION = 0 
  73   
  74   
  75  ANSWER = 1 
  76   
  77   
  78  AUTHORITY = 2 
  79   
  80   
  81  ADDITIONAL = 3 
  82   
  84      """A DNS message.""" 
  85   
  87          if id is None: 
  88              self.id = dns.entropy.random_16() 
  89          else: 
  90              self.id = id 
  91          self.flags = 0 
  92          self.question = [] 
  93          self.answer = [] 
  94          self.authority = [] 
  95          self.additional = [] 
  96          self.edns = -1 
  97          self.ednsflags = 0 
  98          self.payload = 0 
  99          self.options = [] 
 100          self.request_payload = 0 
 101          self.keyring = None 
 102          self.keyname = None 
 103          self.keyalgorithm = dns.tsig.default_algorithm 
 104          self.request_mac = b'' 
 105          self.other_data = b'' 
 106          self.tsig_error = 0 
 107          self.fudge = 300 
 108          self.original_id = self.id 
 109          self.mac = b'' 
 110          self.xfr = False 
 111          self.origin = None 
 112          self.tsig_ctx = None 
 113          self.had_tsig = False 
 114          self.multi = False 
 115          self.first = True 
 116          self.index = {} 
  117   
 119          return '<DNS message, ID ' + repr(self.id) + '>' 
  120   
 123   
 124 -    def to_text(self, origin=None, relativize=True, **kw): 
  125          """Convert the message to text. 
 126   
 127          The *origin*, *relativize*, and any other keyword 
 128          arguments are passed to the RRset ``to_wire()`` method. 
 129   
 130          Returns a ``text``. 
 131          """ 
 132   
 133          s = StringIO() 
 134          s.write(u'id %d\n' % self.id) 
 135          s.write(u'opcode %s\n' % 
 136                  dns.opcode.to_text(dns.opcode.from_flags(self.flags))) 
 137          rc = dns.rcode.from_flags(self.flags, self.ednsflags) 
 138          s.write(u'rcode %s\n' % dns.rcode.to_text(rc)) 
 139          s.write(u'flags %s\n' % dns.flags.to_text(self.flags)) 
 140          if self.edns >= 0: 
 141              s.write(u'edns %s\n' % self.edns) 
 142              if self.ednsflags != 0: 
 143                  s.write(u'eflags %s\n' % 
 144                          dns.flags.edns_to_text(self.ednsflags)) 
 145              s.write(u'payload %d\n' % self.payload) 
 146          for opt in self.options: 
 147              s.write(u'option %s\n' % opt.to_text()) 
 148          is_update = dns.opcode.is_update(self.flags) 
 149          if is_update: 
 150              s.write(u';ZONE\n') 
 151          else: 
 152              s.write(u';QUESTION\n') 
 153          for rrset in self.question: 
 154              s.write(rrset.to_text(origin, relativize, **kw)) 
 155              s.write(u'\n') 
 156          if is_update: 
 157              s.write(u';PREREQ\n') 
 158          else: 
 159              s.write(u';ANSWER\n') 
 160          for rrset in self.answer: 
 161              s.write(rrset.to_text(origin, relativize, **kw)) 
 162              s.write(u'\n') 
 163          if is_update: 
 164              s.write(u';UPDATE\n') 
 165          else: 
 166              s.write(u';AUTHORITY\n') 
 167          for rrset in self.authority: 
 168              s.write(rrset.to_text(origin, relativize, **kw)) 
 169              s.write(u'\n') 
 170          s.write(u';ADDITIONAL\n') 
 171          for rrset in self.additional: 
 172              s.write(rrset.to_text(origin, relativize, **kw)) 
 173              s.write(u'\n') 
 174           
 175           
 176           
 177           
 178           
 179          return s.getvalue()[:-1] 
  180   
 182          """Two messages are equal if they have the same content in the 
 183          header, question, answer, and authority sections. 
 184   
 185          Returns a ``bool``. 
 186          """ 
 187   
 188          if not isinstance(other, Message): 
 189              return False 
 190          if self.id != other.id: 
 191              return False 
 192          if self.flags != other.flags: 
 193              return False 
 194          for n in self.question: 
 195              if n not in other.question: 
 196                  return False 
 197          for n in other.question: 
 198              if n not in self.question: 
 199                  return False 
 200          for n in self.answer: 
 201              if n not in other.answer: 
 202                  return False 
 203          for n in other.answer: 
 204              if n not in self.answer: 
 205                  return False 
 206          for n in self.authority: 
 207              if n not in other.authority: 
 208                  return False 
 209          for n in other.authority: 
 210              if n not in self.authority: 
 211                  return False 
 212          return True 
  213   
 215          return not self.__eq__(other) 
  216   
 240   
 242          """Return the "section number" of the specified section for use 
 243          in indexing.  The question section is 0, the answer section is 1, 
 244          the authority section is 2, and the additional section is 3. 
 245   
 246          *section* is one of the section attributes of this message. 
 247   
 248          Raises ``ValueError`` if the section isn't known. 
 249   
 250          Returns an ``int``. 
 251          """ 
 252   
 253          if section is self.question: 
 254              return QUESTION 
 255          elif section is self.answer: 
 256              return ANSWER 
 257          elif section is self.authority: 
 258              return AUTHORITY 
 259          elif section is self.additional: 
 260              return ADDITIONAL 
 261          else: 
 262              raise ValueError('unknown section') 
  263   
 265          """Return the "section number" of the specified section for use 
 266          in indexing.  The question section is 0, the answer section is 1, 
 267          the authority section is 2, and the additional section is 3. 
 268   
 269          *section* is one of the section attributes of this message. 
 270   
 271          Raises ``ValueError`` if the section isn't known. 
 272   
 273          Returns an ``int``. 
 274          """ 
 275   
 276          if number == QUESTION: 
 277              return self.question 
 278          elif number == ANSWER: 
 279              return self.answer 
 280          elif number == AUTHORITY: 
 281              return self.authority 
 282          elif number == ADDITIONAL: 
 283              return self.additional 
 284          else: 
 285              raise ValueError('unknown section') 
  286   
 287 -    def find_rrset(self, section, name, rdclass, rdtype, 
 288                     covers=dns.rdatatype.NONE, deleting=None, create=False, 
 289                     force_unique=False): 
  290          """Find the RRset with the given attributes in the specified section. 
 291   
 292          *section*, an ``int`` section number, or one of the section 
 293          attributes of this message.  This specifies the 
 294          the section of the message to search.  For example:: 
 295   
 296              my_message.find_rrset(my_message.answer, name, rdclass, rdtype) 
 297              my_message.find_rrset(dns.message.ANSWER, name, rdclass, rdtype) 
 298   
 299          *name*, a ``dns.name.Name``, the name of the RRset. 
 300   
 301          *rdclass*, an ``int``, the class of the RRset. 
 302   
 303          *rdtype*, an ``int``, the type of the RRset. 
 304   
 305          *covers*, an ``int`` or ``None``, the covers value of the RRset. 
 306          The default is ``None``. 
 307   
 308          *deleting*, an ``int`` or ``None``, the deleting value of the RRset. 
 309          The default is ``None``. 
 310   
 311          *create*, a ``bool``.  If ``True``, create the RRset if it is not found. 
 312          The created RRset is appended to *section*. 
 313   
 314          *force_unique*, a ``bool``.  If ``True`` and *create* is also ``True``, 
 315          create a new RRset regardless of whether a matching RRset exists 
 316          already.  The default is ``False``.  This is useful when creating 
 317          DDNS Update messages, as order matters for them. 
 318   
 319          Raises ``KeyError`` if the RRset was not found and create was 
 320          ``False``. 
 321   
 322          Returns a ``dns.rrset.RRset object``. 
 323          """ 
 324   
 325          if isinstance(section, int): 
 326              section_number = section 
 327              section = self.section_from_number(section_number) 
 328          else: 
 329              section_number = self.section_number(section) 
 330          key = (section_number, name, rdclass, rdtype, covers, deleting) 
 331          if not force_unique: 
 332              if self.index is not None: 
 333                  rrset = self.index.get(key) 
 334                  if rrset is not None: 
 335                      return rrset 
 336              else: 
 337                  for rrset in section: 
 338                      if rrset.match(name, rdclass, rdtype, covers, deleting): 
 339                          return rrset 
 340          if not create: 
 341              raise KeyError 
 342          rrset = dns.rrset.RRset(name, rdclass, rdtype, covers, deleting) 
 343          section.append(rrset) 
 344          if self.index is not None: 
 345              self.index[key] = rrset 
 346          return rrset 
  347   
 348 -    def get_rrset(self, section, name, rdclass, rdtype, 
 349                    covers=dns.rdatatype.NONE, deleting=None, create=False, 
 350                    force_unique=False): 
  351          """Get the RRset with the given attributes in the specified section. 
 352   
 353          If the RRset is not found, None is returned. 
 354   
 355          *section*, an ``int`` section number, or one of the section 
 356          attributes of this message.  This specifies the 
 357          the section of the message to search.  For example:: 
 358   
 359              my_message.get_rrset(my_message.answer, name, rdclass, rdtype) 
 360              my_message.get_rrset(dns.message.ANSWER, name, rdclass, rdtype) 
 361   
 362          *name*, a ``dns.name.Name``, the name of the RRset. 
 363   
 364          *rdclass*, an ``int``, the class of the RRset. 
 365   
 366          *rdtype*, an ``int``, the type of the RRset. 
 367   
 368          *covers*, an ``int`` or ``None``, the covers value of the RRset. 
 369          The default is ``None``. 
 370   
 371          *deleting*, an ``int`` or ``None``, the deleting value of the RRset. 
 372          The default is ``None``. 
 373   
 374          *create*, a ``bool``.  If ``True``, create the RRset if it is not found. 
 375          The created RRset is appended to *section*. 
 376   
 377          *force_unique*, a ``bool``.  If ``True`` and *create* is also ``True``, 
 378          create a new RRset regardless of whether a matching RRset exists 
 379          already.  The default is ``False``.  This is useful when creating 
 380          DDNS Update messages, as order matters for them. 
 381   
 382          Returns a ``dns.rrset.RRset object`` or ``None``. 
 383          """ 
 384   
 385          try: 
 386              rrset = self.find_rrset(section, name, rdclass, rdtype, covers, 
 387                                      deleting, create, force_unique) 
 388          except KeyError: 
 389              rrset = None 
 390          return rrset 
  391   
 392 -    def to_wire(self, origin=None, max_size=0, **kw): 
  393          """Return a string containing the message in DNS compressed wire 
 394          format. 
 395   
 396          Additional keyword arguments are passed to the RRset ``to_wire()`` 
 397          method. 
 398   
 399          *origin*, a ``dns.name.Name`` or ``None``, the origin to be appended 
 400          to any relative names. 
 401   
 402          *max_size*, an ``int``, the maximum size of the wire format 
 403          output; default is 0, which means "the message's request 
 404          payload, if nonzero, or 65535". 
 405   
 406          Raises ``dns.exception.TooBig`` if *max_size* was exceeded. 
 407   
 408          Returns a ``binary``. 
 409          """ 
 410   
 411          if max_size == 0: 
 412              if self.request_payload != 0: 
 413                  max_size = self.request_payload 
 414              else: 
 415                  max_size = 65535 
 416          if max_size < 512: 
 417              max_size = 512 
 418          elif max_size > 65535: 
 419              max_size = 65535 
 420          r = dns.renderer.Renderer(self.id, self.flags, max_size, origin) 
 421          for rrset in self.question: 
 422              r.add_question(rrset.name, rrset.rdtype, rrset.rdclass) 
 423          for rrset in self.answer: 
 424              r.add_rrset(dns.renderer.ANSWER, rrset, **kw) 
 425          for rrset in self.authority: 
 426              r.add_rrset(dns.renderer.AUTHORITY, rrset, **kw) 
 427          if self.edns >= 0: 
 428              r.add_edns(self.edns, self.ednsflags, self.payload, self.options) 
 429          for rrset in self.additional: 
 430              r.add_rrset(dns.renderer.ADDITIONAL, rrset, **kw) 
 431          r.write_header() 
 432          if self.keyname is not None: 
 433              r.add_tsig(self.keyname, self.keyring[self.keyname], 
 434                         self.fudge, self.original_id, self.tsig_error, 
 435                         self.other_data, self.request_mac, 
 436                         self.keyalgorithm) 
 437              self.mac = r.mac 
 438          return r.get_wire() 
  439   
 443          """When sending, a TSIG signature using the specified keyring 
 444          and keyname should be added. 
 445   
 446          See the documentation of the Message class for a complete 
 447          description of the keyring dictionary. 
 448   
 449          *keyring*, a ``dict``, the TSIG keyring to use.  If a 
 450          *keyring* is specified but a *keyname* is not, then the key 
 451          used will be the first key in the *keyring*.  Note that the 
 452          order of keys in a dictionary is not defined, so applications 
 453          should supply a keyname when a keyring is used, unless they 
 454          know the keyring contains only one key. 
 455   
 456          *keyname*, a ``dns.name.Name`` or ``None``, the name of the TSIG key 
 457          to use; defaults to ``None``. The key must be defined in the keyring. 
 458   
 459          *fudge*, an ``int``, the TSIG time fudge. 
 460   
 461          *original_id*, an ``int``, the TSIG original id.  If ``None``, 
 462          the message's id is used. 
 463   
 464          *tsig_error*, an ``int``, the TSIG error code. 
 465   
 466          *other_data*, a ``binary``, the TSIG other data. 
 467   
 468          *algorithm*, a ``dns.name.Name``, the TSIG algorithm to use. 
 469          """ 
 470   
 471          self.keyring = keyring 
 472          if keyname is None: 
 473              self.keyname = list(self.keyring.keys())[0] 
 474          else: 
 475              if isinstance(keyname, string_types): 
 476                  keyname = dns.name.from_text(keyname) 
 477              self.keyname = keyname 
 478          self.keyalgorithm = algorithm 
 479          self.fudge = fudge 
 480          if original_id is None: 
 481              self.original_id = self.id 
 482          else: 
 483              self.original_id = original_id 
 484          self.tsig_error = tsig_error 
 485          self.other_data = other_data 
  486   
 487 -    def use_edns(self, edns=0, ednsflags=0, payload=1280, request_payload=None, 
 488                   options=None): 
  489          """Configure EDNS behavior. 
 490   
 491          *edns*, an ``int``, is the EDNS level to use.  Specifying 
 492          ``None``, ``False``, or ``-1`` means "do not use EDNS", and in this case 
 493          the other parameters are ignored.  Specifying ``True`` is 
 494          equivalent to specifying 0, i.e. "use EDNS0". 
 495   
 496          *ednsflags*, an ``int``, the EDNS flag values. 
 497   
 498          *payload*, an ``int``, is the EDNS sender's payload field, which is the 
 499          maximum size of UDP datagram the sender can handle.  I.e. how big 
 500          a response to this message can be. 
 501   
 502          *request_payload*, an ``int``, is the EDNS payload size to use when 
 503          sending this message.  If not specified, defaults to the value of 
 504          *payload*. 
 505   
 506          *options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS 
 507          options. 
 508          """ 
 509   
 510          if edns is None or edns is False: 
 511              edns = -1 
 512          if edns is True: 
 513              edns = 0 
 514          if request_payload is None: 
 515              request_payload = payload 
 516          if edns < 0: 
 517              ednsflags = 0 
 518              payload = 0 
 519              request_payload = 0 
 520              options = [] 
 521          else: 
 522               
 523              ednsflags &= long(0xFF00FFFF) 
 524              ednsflags |= (edns << 16) 
 525              if options is None: 
 526                  options = [] 
 527          self.edns = edns 
 528          self.ednsflags = ednsflags 
 529          self.payload = payload 
 530          self.options = options 
 531          self.request_payload = request_payload 
  532   
 534          """Enable or disable 'DNSSEC desired' flag in requests. 
 535   
 536          *wanted*, a ``bool``.  If ``True``, then DNSSEC data is 
 537          desired in the response, EDNS is enabled if required, and then 
 538          the DO bit is set.  If ``False``, the DO bit is cleared if 
 539          EDNS is enabled. 
 540          """ 
 541   
 542          if wanted: 
 543              if self.edns < 0: 
 544                  self.use_edns() 
 545              self.ednsflags |= dns.flags.DO 
 546          elif self.edns >= 0: 
 547              self.ednsflags &= ~dns.flags.DO 
  548   
 550          """Return the rcode. 
 551   
 552          Returns an ``int``. 
 553          """ 
 554          return dns.rcode.from_flags(self.flags, self.ednsflags) 
  555   
 557          """Set the rcode. 
 558   
 559          *rcode*, an ``int``, is the rcode to set. 
 560          """ 
 561          (value, evalue) = dns.rcode.to_flags(rcode) 
 562          self.flags &= 0xFFF0 
 563          self.flags |= value 
 564          self.ednsflags &= long(0x00FFFFFF) 
 565          self.ednsflags |= evalue 
 566          if self.ednsflags != 0 and self.edns < 0: 
 567              self.edns = 0 
  568   
 575   
  583   
 584   
 586   
 587      """Wire format reader. 
 588   
 589      wire: a binary, is the wire-format message. 
 590      message: The message object being built 
 591      current: When building a message object from wire format, this 
 592      variable contains the offset from the beginning of wire of the next octet 
 593      to be read. 
 594      updating: Is the message a dynamic update? 
 595      one_rr_per_rrset: Put each RR into its own RRset? 
 596      ignore_trailing: Ignore trailing junk at end of request? 
 597      zone_rdclass: The class of the zone in messages which are 
 598      DNS dynamic updates. 
 599      """ 
 600   
 601 -    def __init__(self, wire, message, question_only=False, 
 602                   one_rr_per_rrset=False, ignore_trailing=False): 
  603          self.wire = dns.wiredata.maybe_wrap(wire) 
 604          self.message = message 
 605          self.current = 0 
 606          self.updating = False 
 607          self.zone_rdclass = dns.rdataclass.IN 
 608          self.question_only = question_only 
 609          self.one_rr_per_rrset = one_rr_per_rrset 
 610          self.ignore_trailing = ignore_trailing 
  611   
 613          """Read the next *qcount* records from the wire data and add them to 
 614          the question section. 
 615          """ 
 616   
 617          if self.updating and qcount > 1: 
 618              raise dns.exception.FormError 
 619   
 620          for i in xrange(0, qcount): 
 621              (qname, used) = dns.name.from_wire(self.wire, self.current) 
 622              if self.message.origin is not None: 
 623                  qname = qname.relativize(self.message.origin) 
 624              self.current = self.current + used 
 625              (rdtype, rdclass) = \ 
 626                  struct.unpack('!HH', 
 627                                self.wire[self.current:self.current + 4]) 
 628              self.current = self.current + 4 
 629              self.message.find_rrset(self.message.question, qname, 
 630                                      rdclass, rdtype, create=True, 
 631                                      force_unique=True) 
 632              if self.updating: 
 633                  self.zone_rdclass = rdclass 
  634   
 636          """Read the next I{count} records from the wire data and add them to 
 637          the specified section. 
 638   
 639          section: the section of the message to which to add records 
 640          count: the number of records to read 
 641          """ 
 642   
 643          if self.updating or self.one_rr_per_rrset: 
 644              force_unique = True 
 645          else: 
 646              force_unique = False 
 647          seen_opt = False 
 648          for i in xrange(0, count): 
 649              rr_start = self.current 
 650              (name, used) = dns.name.from_wire(self.wire, self.current) 
 651              absolute_name = name 
 652              if self.message.origin is not None: 
 653                  name = name.relativize(self.message.origin) 
 654              self.current = self.current + used 
 655              (rdtype, rdclass, ttl, rdlen) = \ 
 656                  struct.unpack('!HHIH', 
 657                                self.wire[self.current:self.current + 10]) 
 658              self.current = self.current + 10 
 659              if rdtype == dns.rdatatype.OPT: 
 660                  if section is not self.message.additional or seen_opt: 
 661                      raise BadEDNS 
 662                  self.message.payload = rdclass 
 663                  self.message.ednsflags = ttl 
 664                  self.message.edns = (ttl & 0xff0000) >> 16 
 665                  self.message.options = [] 
 666                  current = self.current 
 667                  optslen = rdlen 
 668                  while optslen > 0: 
 669                      (otype, olen) = \ 
 670                          struct.unpack('!HH', 
 671                                        self.wire[current:current + 4]) 
 672                      current = current + 4 
 673                      opt = dns.edns.option_from_wire( 
 674                          otype, self.wire, current, olen) 
 675                      self.message.options.append(opt) 
 676                      current = current + olen 
 677                      optslen = optslen - 4 - olen 
 678                  seen_opt = True 
 679              elif rdtype == dns.rdatatype.TSIG: 
 680                  if not (section is self.message.additional and 
 681                          i == (count - 1)): 
 682                      raise BadTSIG 
 683                  if self.message.keyring is None: 
 684                      raise UnknownTSIGKey('got signed message without keyring') 
 685                  secret = self.message.keyring.get(absolute_name) 
 686                  if secret is None: 
 687                      raise UnknownTSIGKey("key '%s' unknown" % name) 
 688                  self.message.keyname = absolute_name 
 689                  (self.message.keyalgorithm, self.message.mac) = \ 
 690                      dns.tsig.get_algorithm_and_mac(self.wire, self.current, 
 691                                                     rdlen) 
 692                  self.message.tsig_ctx = \ 
 693                      dns.tsig.validate(self.wire, 
 694                                        absolute_name, 
 695                                        secret, 
 696                                        int(time.time()), 
 697                                        self.message.request_mac, 
 698                                        rr_start, 
 699                                        self.current, 
 700                                        rdlen, 
 701                                        self.message.tsig_ctx, 
 702                                        self.message.multi, 
 703                                        self.message.first) 
 704                  self.message.had_tsig = True 
 705              else: 
 706                  if ttl < 0: 
 707                      ttl = 0 
 708                  if self.updating and \ 
 709                     (rdclass == dns.rdataclass.ANY or 
 710                          rdclass == dns.rdataclass.NONE): 
 711                      deleting = rdclass 
 712                      rdclass = self.zone_rdclass 
 713                  else: 
 714                      deleting = None 
 715                  if deleting == dns.rdataclass.ANY or \ 
 716                     (deleting == dns.rdataclass.NONE and 
 717                          section is self.message.answer): 
 718                      covers = dns.rdatatype.NONE 
 719                      rd = None 
 720                  else: 
 721                      rd = dns.rdata.from_wire(rdclass, rdtype, self.wire, 
 722                                               self.current, rdlen, 
 723                                               self.message.origin) 
 724                      covers = rd.covers() 
 725                  if self.message.xfr and rdtype == dns.rdatatype.SOA: 
 726                      force_unique = True 
 727                  rrset = self.message.find_rrset(section, name, 
 728                                                  rdclass, rdtype, covers, 
 729                                                  deleting, True, force_unique) 
 730                  if rd is not None: 
 731                      rrset.add(rd, ttl) 
 732              self.current = self.current + rdlen 
  733   
  757   
 758   
 759 -def from_wire(wire, keyring=None, request_mac=b'', xfr=False, origin=None, 
 760                tsig_ctx=None, multi=False, first=True, 
 761                question_only=False, one_rr_per_rrset=False, 
 762                ignore_trailing=False): 
  763      """Convert a DNS wire format message into a message 
 764      object. 
 765   
 766      *keyring*, a ``dict``, the keyring to use if the message is signed. 
 767   
 768      *request_mac*, a ``binary``.  If the message is a response to a 
 769      TSIG-signed request, *request_mac* should be set to the MAC of 
 770      that request. 
 771   
 772      *xfr*, a ``bool``, should be set to ``True`` if this message is part of 
 773      a zone transfer. 
 774   
 775      *origin*, a ``dns.name.Name`` or ``None``.  If the message is part 
 776      of a zone transfer, *origin* should be the origin name of the 
 777      zone. 
 778   
 779      *tsig_ctx*, a ``hmac.HMAC`` objext, the ongoing TSIG context, used 
 780      when validating zone transfers. 
 781   
 782      *multi*, a ``bool``, should be set to ``True`` if this message 
 783      part of a multiple message sequence. 
 784   
 785      *first*, a ``bool``, should be set to ``True`` if this message is 
 786      stand-alone, or the first message in a multi-message sequence. 
 787   
 788      *question_only*, a ``bool``.  If ``True``, read only up to 
 789      the end of the question section. 
 790   
 791      *one_rr_per_rrset*, a ``bool``.  If ``True``, put each RR into its 
 792      own RRset. 
 793   
 794      *ignore_trailing*, a ``bool``.  If ``True``, ignore trailing 
 795      junk at end of the message. 
 796   
 797      Raises ``dns.message.ShortHeader`` if the message is less than 12 octets 
 798      long. 
 799   
 800      Raises ``dns.messaage.TrailingJunk`` if there were octets in the message 
 801      past the end of the proper DNS message, and *ignore_trailing* is ``False``. 
 802   
 803      Raises ``dns.message.BadEDNS`` if an OPT record was in the 
 804      wrong section, or occurred more than once. 
 805   
 806      Raises ``dns.message.BadTSIG`` if a TSIG record was not the last 
 807      record of the additional data section. 
 808   
 809      Returns a ``dns.message.Message``. 
 810      """ 
 811   
 812      m = Message(id=0) 
 813      m.keyring = keyring 
 814      m.request_mac = request_mac 
 815      m.xfr = xfr 
 816      m.origin = origin 
 817      m.tsig_ctx = tsig_ctx 
 818      m.multi = multi 
 819      m.first = first 
 820   
 821      reader = _WireReader(wire, m, question_only, one_rr_per_rrset, 
 822                           ignore_trailing) 
 823      reader.read() 
 824   
 825      return m 
  826   
 827   
 828 -class _TextReader(object): 
  829   
 830      """Text format reader. 
 831   
 832      tok: the tokenizer. 
 833      message: The message object being built. 
 834      updating: Is the message a dynamic update? 
 835      zone_rdclass: The class of the zone in messages which are 
 836      DNS dynamic updates. 
 837      last_name: The most recently read name when building a message object. 
 838      """ 
 839   
 840 -    def __init__(self, text, message): 
  841          self.message = message 
 842          self.tok = dns.tokenizer.Tokenizer(text) 
 843          self.last_name = None 
 844          self.zone_rdclass = dns.rdataclass.IN 
 845          self.updating = False 
  846   
 848          """Process one line from the text format header section.""" 
 849   
 850          token = self.tok.get() 
 851          what = token.value 
 852          if what == 'id': 
 853              self.message.id = self.tok.get_int() 
 854          elif what == 'flags': 
 855              while True: 
 856                  token = self.tok.get() 
 857                  if not token.is_identifier(): 
 858                      self.tok.unget(token) 
 859                      break 
 860                  self.message.flags = self.message.flags | \ 
 861                      dns.flags.from_text(token.value) 
 862              if dns.opcode.is_update(self.message.flags): 
 863                  self.updating = True 
 864          elif what == 'edns': 
 865              self.message.edns = self.tok.get_int() 
 866              self.message.ednsflags = self.message.ednsflags | \ 
 867                  (self.message.edns << 16) 
 868          elif what == 'eflags': 
 869              if self.message.edns < 0: 
 870                  self.message.edns = 0 
 871              while True: 
 872                  token = self.tok.get() 
 873                  if not token.is_identifier(): 
 874                      self.tok.unget(token) 
 875                      break 
 876                  self.message.ednsflags = self.message.ednsflags | \ 
 877                      dns.flags.edns_from_text(token.value) 
 878          elif what == 'payload': 
 879              self.message.payload = self.tok.get_int() 
 880              if self.message.edns < 0: 
 881                  self.message.edns = 0 
 882          elif what == 'opcode': 
 883              text = self.tok.get_string() 
 884              self.message.flags = self.message.flags | \ 
 885                  dns.opcode.to_flags(dns.opcode.from_text(text)) 
 886          elif what == 'rcode': 
 887              text = self.tok.get_string() 
 888              self.message.set_rcode(dns.rcode.from_text(text)) 
 889          else: 
 890              raise UnknownHeaderField 
 891          self.tok.get_eol() 
  892   
 893 -    def _question_line(self, section): 
  894          """Process one line from the text format question section.""" 
 895   
 896          token = self.tok.get(want_leading=True) 
 897          if not token.is_whitespace(): 
 898              self.last_name = dns.name.from_text(token.value, None) 
 899          name = self.last_name 
 900          token = self.tok.get() 
 901          if not token.is_identifier(): 
 902              raise dns.exception.SyntaxError 
 903           
 904          try: 
 905              rdclass = dns.rdataclass.from_text(token.value) 
 906              token = self.tok.get() 
 907              if not token.is_identifier(): 
 908                  raise dns.exception.SyntaxError 
 909          except dns.exception.SyntaxError: 
 910              raise dns.exception.SyntaxError 
 911          except Exception: 
 912              rdclass = dns.rdataclass.IN 
 913           
 914          rdtype = dns.rdatatype.from_text(token.value) 
 915          self.message.find_rrset(self.message.question, name, 
 916                                  rdclass, rdtype, create=True, 
 917                                  force_unique=True) 
 918          if self.updating: 
 919              self.zone_rdclass = rdclass 
 920          self.tok.get_eol() 
  921   
 922 -    def _rr_line(self, section): 
  923          """Process one line from the text format answer, authority, or 
 924          additional data sections. 
 925          """ 
 926   
 927          deleting = None 
 928           
 929          token = self.tok.get(want_leading=True) 
 930          if not token.is_whitespace(): 
 931              self.last_name = dns.name.from_text(token.value, None) 
 932          name = self.last_name 
 933          token = self.tok.get() 
 934          if not token.is_identifier(): 
 935              raise dns.exception.SyntaxError 
 936           
 937          try: 
 938              ttl = int(token.value, 0) 
 939              token = self.tok.get() 
 940              if not token.is_identifier(): 
 941                  raise dns.exception.SyntaxError 
 942          except dns.exception.SyntaxError: 
 943              raise dns.exception.SyntaxError 
 944          except Exception: 
 945              ttl = 0 
 946           
 947          try: 
 948              rdclass = dns.rdataclass.from_text(token.value) 
 949              token = self.tok.get() 
 950              if not token.is_identifier(): 
 951                  raise dns.exception.SyntaxError 
 952              if rdclass == dns.rdataclass.ANY or rdclass == dns.rdataclass.NONE: 
 953                  deleting = rdclass 
 954                  rdclass = self.zone_rdclass 
 955          except dns.exception.SyntaxError: 
 956              raise dns.exception.SyntaxError 
 957          except Exception: 
 958              rdclass = dns.rdataclass.IN 
 959           
 960          rdtype = dns.rdatatype.from_text(token.value) 
 961          token = self.tok.get() 
 962          if not token.is_eol_or_eof(): 
 963              self.tok.unget(token) 
 964              rd = dns.rdata.from_text(rdclass, rdtype, self.tok, None) 
 965              covers = rd.covers() 
 966          else: 
 967              rd = None 
 968              covers = dns.rdatatype.NONE 
 969          rrset = self.message.find_rrset(section, name, 
 970                                          rdclass, rdtype, covers, 
 971                                          deleting, True, self.updating) 
 972          if rd is not None: 
 973              rrset.add(rd, ttl) 
  974   
 976          """Read a text format DNS message and build a dns.message.Message 
 977          object.""" 
 978   
 979          line_method = self._header_line 
 980          section = None 
 981          while 1: 
 982              token = self.tok.get(True, True) 
 983              if token.is_eol_or_eof(): 
 984                  break 
 985              if token.is_comment(): 
 986                  u = token.value.upper() 
 987                  if u == 'HEADER': 
 988                      line_method = self._header_line 
 989                  elif u == 'QUESTION' or u == 'ZONE': 
 990                      line_method = self._question_line 
 991                      section = self.message.question 
 992                  elif u == 'ANSWER' or u == 'PREREQ': 
 993                      line_method = self._rr_line 
 994                      section = self.message.answer 
 995                  elif u == 'AUTHORITY' or u == 'UPDATE': 
 996                      line_method = self._rr_line 
 997                      section = self.message.authority 
 998                  elif u == 'ADDITIONAL': 
 999                      line_method = self._rr_line 
1000                      section = self.message.additional 
1001                  self.tok.get_eol() 
1002                  continue 
1003              self.tok.unget(token) 
1004              line_method(section) 
  1005   
1006   
1007 -def from_text(text): 
 1008      """Convert the text format message into a message object. 
1009   
1010      *text*, a ``text``, the text format message. 
1011   
1012      Raises ``dns.message.UnknownHeaderField`` if a header is unknown. 
1013   
1014      Raises ``dns.exception.SyntaxError`` if the text is badly formed. 
1015   
1016      Returns a ``dns.message.Message object`` 
1017      """ 
1018   
1019       
1020       
1021       
1022   
1023      m = Message() 
1024   
1025      reader = _TextReader(text, m) 
1026      reader.read() 
1027   
1028      return m 
 1029   
1030   
1032      """Read the next text format message from the specified file. 
1033   
1034      *f*, a ``file`` or ``text``.  If *f* is text, it is treated as the 
1035      pathname of a file to open. 
1036   
1037      Raises ``dns.message.UnknownHeaderField`` if a header is unknown. 
1038   
1039      Raises ``dns.exception.SyntaxError`` if the text is badly formed. 
1040   
1041      Returns a ``dns.message.Message object`` 
1042      """ 
1043   
1044      str_type = string_types 
1045      opts = 'rU' 
1046   
1047      if isinstance(f, str_type): 
1048          f = open(f, opts) 
1049          want_close = True 
1050      else: 
1051          want_close = False 
1052   
1053      try: 
1054          m = from_text(f) 
1055      finally: 
1056          if want_close: 
1057              f.close() 
1058      return m 
 1059   
1060   
1061 -def make_query(qname, rdtype, rdclass=dns.rdataclass.IN, use_edns=None, 
1062                 want_dnssec=False, ednsflags=None, payload=None, 
1063                 request_payload=None, options=None): 
 1064      """Make a query message. 
1065   
1066      The query name, type, and class may all be specified either 
1067      as objects of the appropriate type, or as strings. 
1068   
1069      The query will have a randomly chosen query id, and its DNS flags 
1070      will be set to dns.flags.RD. 
1071   
1072      qname, a ``dns.name.Name`` or ``text``, the query name. 
1073   
1074      *rdtype*, an ``int`` or ``text``, the desired rdata type. 
1075   
1076      *rdclass*, an ``int`` or ``text``,  the desired rdata class; the default 
1077      is class IN. 
1078   
1079      *use_edns*, an ``int``, ``bool`` or ``None``.  The EDNS level to use; the 
1080      default is None (no EDNS). 
1081      See the description of dns.message.Message.use_edns() for the possible 
1082      values for use_edns and their meanings. 
1083   
1084      *want_dnssec*, a ``bool``.  If ``True``, DNSSEC data is desired. 
1085   
1086      *ednsflags*, an ``int``, the EDNS flag values. 
1087   
1088      *payload*, an ``int``, is the EDNS sender's payload field, which is the 
1089      maximum size of UDP datagram the sender can handle.  I.e. how big 
1090      a response to this message can be. 
1091   
1092      *request_payload*, an ``int``, is the EDNS payload size to use when 
1093      sending this message.  If not specified, defaults to the value of 
1094      *payload*. 
1095   
1096      *options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS 
1097      options. 
1098   
1099      Returns a ``dns.message.Message`` 
1100      """ 
1101   
1102      if isinstance(qname, string_types): 
1103          qname = dns.name.from_text(qname) 
1104      if isinstance(rdtype, string_types): 
1105          rdtype = dns.rdatatype.from_text(rdtype) 
1106      if isinstance(rdclass, string_types): 
1107          rdclass = dns.rdataclass.from_text(rdclass) 
1108      m = Message() 
1109      m.flags |= dns.flags.RD 
1110      m.find_rrset(m.question, qname, rdclass, rdtype, create=True, 
1111                   force_unique=True) 
1112       
1113       
1114       
1115      kwargs = {} 
1116      if ednsflags is not None: 
1117          kwargs['ednsflags'] = ednsflags 
1118          if use_edns is None: 
1119              use_edns = 0 
1120      if payload is not None: 
1121          kwargs['payload'] = payload 
1122          if use_edns is None: 
1123              use_edns = 0 
1124      if request_payload is not None: 
1125          kwargs['request_payload'] = request_payload 
1126          if use_edns is None: 
1127              use_edns = 0 
1128      if options is not None: 
1129          kwargs['options'] = options 
1130          if use_edns is None: 
1131              use_edns = 0 
1132      kwargs['edns'] = use_edns 
1133      m.use_edns(**kwargs) 
1134      m.want_dnssec(want_dnssec) 
1135      return m 
 1136   
1137   
1138 -def make_response(query, recursion_available=False, our_payload=8192, 
1139                    fudge=300): 
 1140      """Make a message which is a response for the specified query. 
1141      The message returned is really a response skeleton; it has all 
1142      of the infrastructure required of a response, but none of the 
1143      content. 
1144   
1145      The response's question section is a shallow copy of the query's 
1146      question section, so the query's question RRsets should not be 
1147      changed. 
1148   
1149      *query*, a ``dns.message.Message``, the query to respond to. 
1150   
1151      *recursion_available*, a ``bool``, should RA be set in the response? 
1152   
1153      *our_payload*, an ``int``, the payload size to advertise in EDNS 
1154      responses. 
1155   
1156      *fudge*, an ``int``, the TSIG time fudge. 
1157   
1158      Returns a ``dns.message.Message`` object. 
1159      """ 
1160   
1161      if query.flags & dns.flags.QR: 
1162          raise dns.exception.FormError('specified query message is not a query') 
1163      response = dns.message.Message(query.id) 
1164      response.flags = dns.flags.QR | (query.flags & dns.flags.RD) 
1165      if recursion_available: 
1166          response.flags |= dns.flags.RA 
1167      response.set_opcode(query.opcode()) 
1168      response.question = list(query.question) 
1169      if query.edns >= 0: 
1170          response.use_edns(0, 0, our_payload, query.payload) 
1171      if query.had_tsig: 
1172          response.use_tsig(query.keyring, query.keyname, fudge, None, 0, b'', 
1173                            query.keyalgorithm) 
1174          response.request_mac = query.mac 
1175      return response 
 1176