Package dns :: Module query |
[hide private]
[frames] | no frames]

# Source Code for Module dns.query

      1  # Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
      2  #
      3  # Permission to use, copy, modify, and distribute this software and its
      4  # documentation for any purpose with or without fee is hereby granted,
      5  # provided that the above copyright notice and this permission notice
      6  # appear in all copies.
      7  #
      8  # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
      9  # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
     11  # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     14  # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15
     16  """Talk to a DNS server."""
     17
     18  from __future__ import generators
     19
     20  import errno
     21  import select
     22  import socket
     23  import struct
     24  import sys
     25  import time
     26
     27  import dns.exception
     28  import dns.inet
     29  import dns.name
     30  import dns.message
     31  import dns.rdataclass
     32  import dns.rdatatype
     33  from ._compat import long, string_types
     34
     35  if sys.version_info > (3,):
     36      select_error = OSError
     37  else:
     38      select_error = select.error
     39
     40  # Function used to create a socket.  Can be overridden if needed in special
     41  # situations.
     42  socket_factory = socket.socket
     43
     44 -class UnexpectedSource(dns.exception.DNSException):
     45
     46      """A DNS query response came from an unexpected address or port."""
     47
     48
     49 -class BadResponse(dns.exception.FormError):
     50
     51      """A DNS query response does not respond to the question asked."""
     52
     53
     54 -def _compute_expiration(timeout):
     55      if timeout is None:
     56          return None
     57      else:
     58          return time.time() + timeout
     59
     60
     61 -def _poll_for(fd, readable, writable, error, timeout):
     62      """Poll polling backend.
     63      @param fd: File descriptor
     64      @type fd: int
     65      @param readable: Whether to wait for readability
     66      @type readable: bool
     67      @param writable: Whether to wait for writability
     68      @type writable: bool
     69      @param timeout: Deadline timeout (expiration time, in seconds)
     70      @type timeout: float
     71      @return True on success, False on timeout
     72      """
     73      event_mask = 0
     74      if readable:
     75          event_mask |= select.POLLIN
     76      if writable:
     77          event_mask |= select.POLLOUT
     78      if error:
     79          event_mask |= select.POLLERR
     80
     81      pollable = select.poll()
     82      pollable.register(fd, event_mask)
     83
     84      if timeout:
     85          event_list = pollable.poll(long(timeout * 1000))
     86      else:
     87          event_list = pollable.poll()
     88
     89      return bool(event_list)
     90
     91
     92 -def _select_for(fd, readable, writable, error, timeout):
     93      """Select polling backend.
     94      @param fd: File descriptor
     95      @type fd: int
     96      @param readable: Whether to wait for readability
     97      @type readable: bool
     98      @param writable: Whether to wait for writability
     99      @type writable: bool
    100      @param timeout: Deadline timeout (expiration time, in seconds)
    101      @type timeout: float
    102      @return True on success, False on timeout
    103      """
    104      rset, wset, xset = [], [], []
    105
    106      if readable:
    107          rset = [fd]
    108      if writable:
    109          wset = [fd]
    110      if error:
    111          xset = [fd]
    112
    113      if timeout is None:
    114          (rcount, wcount, xcount) = select.select(rset, wset, xset)
    115      else:
    116          (rcount, wcount, xcount) = select.select(rset, wset, xset, timeout)
    117
    118      return bool((rcount or wcount or xcount))
    119
    120
    121 -def _wait_for(fd, readable, writable, error, expiration):
    122      done = False
    123      while not done:
    124          if expiration is None:
    125              timeout = None
    126          else:
    127              timeout = expiration - time.time()
    128              if timeout <= 0.0:
    129                  raise dns.exception.Timeout
    130          try:
    131              if not _polling_backend(fd, readable, writable, error, timeout):
    132                  raise dns.exception.Timeout
    133          except select_error as e:
    134              if e.args[0] != errno.EINTR:
    135                  raise e
    136          done = True
    137
    138
    139 -def _set_polling_backend(fn):
    140      """
    141      Internal API. Do not use.
    142      """
    143      global _polling_backend
    144
    145      _polling_backend = fn
    146
    147  if hasattr(select, 'poll'):
    148      # Prefer poll() on platforms that support it because it has no
    149      # limits on the maximum value of a file descriptor (plus it will
    150      # be more efficient for high values).
    151      _polling_backend = _poll_for
    152  else:
    153      _polling_backend = _select_for
    154
    155
    156 -def _wait_for_readable(s, expiration):
    157      _wait_for(s, True, False, True, expiration)
    158
    159
    160 -def _wait_for_writable(s, expiration):
    161      _wait_for(s, False, True, True, expiration)
    162
    163
    164 -def _addresses_equal(af, a1, a2):
    165      # Convert the first value of the tuple, which is a textual format
    166      # address into binary form, so that we are not confused by different
    167      # textual representations of the same address
    168      n1 = dns.inet.inet_pton(af, a1[0])
    169      n2 = dns.inet.inet_pton(af, a2[0])
    170      return n1 == n2 and a1[1:] == a2[1:]
    171
    172
    173 -def _destination_and_source(af, where, port, source, source_port):
    174      # Apply defaults and compute destination and source tuples
    175      # suitable for use in connect(), sendto(), or bind().
    176      if af is None:
    177          try:
    178              af = dns.inet.af_for_address(where)
    179          except Exception:
    180              af = dns.inet.AF_INET
    181      if af == dns.inet.AF_INET:
    182          destination = (where, port)
    183          if source is not None or source_port != 0:
    184              if source is None:
    185                  source = '0.0.0.0'
    186              source = (source, source_port)
    187      elif af == dns.inet.AF_INET6:
    188          destination = (where, port, 0, 0)
    189          if source is not None or source_port != 0:
    190              if source is None:
    191                  source = '::'
    192              source = (source, source_port, 0, 0)
    193      return (af, destination, source)
    194
    195
    196 -def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0,
    197          ignore_unexpected=False, one_rr_per_rrset=False):
    198      """Return the response obtained after sending a query via UDP.
    199
    200      @param q: the query
    201      @type q: dns.message.Message
    202      @param where: where to send the message
    203      @type where: string containing an IPv4 or IPv6 address
    204      @param timeout: The number of seconds to wait before the query times out.
    205      If None, the default, wait forever.
    206      @type timeout: float
    207      @param port: The port to which to send the message.  The default is 53.
    208      @type port: int
    209      @param af: the address family to use.  The default is None, which
    210      causes the address family to use to be inferred from the form of where.
    211      If the inference attempt fails, AF_INET is used.
    212      @type af: int
    213      @rtype: dns.message.Message object
    214      @param source: source address.  The default is the wildcard address.
    215      @type source: string
    216      @param source_port: The port from which to send the message.
    217      The default is 0.
    218      @type source_port: int
    219      @param ignore_unexpected: If True, ignore responses from unexpected
    220      sources.  The default is False.
    221      @type ignore_unexpected: bool
    222      @param one_rr_per_rrset: Put each RR into its own RRset
    223      @type one_rr_per_rrset: bool
    224      """
    225
    226      wire = q.to_wire()
    227      (af, destination, source) = _destination_and_source(af, where, port,
    228                                                          source, source_port)
    229      s = socket_factory(af, socket.SOCK_DGRAM, 0)
    230      begin_time = None
    231      try:
    232          expiration = _compute_expiration(timeout)
    233          s.setblocking(0)
    234          if source is not None:
    235              s.bind(source)
    236          _wait_for_writable(s, expiration)
    237          begin_time = time.time()
    238          s.sendto(wire, destination)
    239          while 1:
    240              _wait_for_readable(s, expiration)
    241              (wire, from_address) = s.recvfrom(65535)
    242              if _addresses_equal(af, from_address, destination) or \
    243                      (dns.inet.is_multicast(where) and
    244                       from_address[1:] == destination[1:]):
    245                  break
    246              if not ignore_unexpected:
    247                  raise UnexpectedSource('got a response from '
    248                                         '%s instead of %s' % (from_address,
    249                                                               destination))
    250      finally:
    251          if begin_time is None:
    252              response_time = 0
    253          else:
    254              response_time = time.time() - begin_time
    255          s.close()
    256      r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac,
    257                                one_rr_per_rrset=one_rr_per_rrset)
    258      r.time = response_time
    259      if not q.is_response(r):
    260          raise BadResponse
    261      return r
    262
    263
    264 -def _net_read(sock, count, expiration):
    265      """Read the specified number of bytes from sock.  Keep trying until we
    266      either get the desired amount, or we hit EOF.
    267      A Timeout exception will be raised if the operation is not completed
    268      by the expiration time.
    269      """
    270      s = b''
    271      while count > 0:
    272          _wait_for_readable(sock, expiration)
    273          n = sock.recv(count)
    274          if n == b'':
    275              raise EOFError
    276          count = count - len(n)
    277          s = s + n
    278      return s
    279
    280
    281 -def _net_write(sock, data, expiration):
    282      """Write the specified data to the socket.
    283      A Timeout exception will be raised if the operation is not completed
    284      by the expiration time.
    285      """
    286      current = 0
    287      l = len(data)
    288      while current < l:
    289          _wait_for_writable(sock, expiration)
    290          current += sock.send(data[current:])
    291
    292
    293 -def _connect(s, address):
    294      try:
    295          s.connect(address)
    296      except socket.error:
    297          (ty, v) = sys.exc_info()[:2]
    298
    299          if hasattr(v, 'errno'):
    300              v_err = v.errno
    301          else:
    302              v_err = v[0]
    303          if v_err not in [errno.EINPROGRESS, errno.EWOULDBLOCK, errno.EALREADY]:
    304              raise v
    305
    306
    307 -def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0,
    308          one_rr_per_rrset=False):
    309      """Return the response obtained after sending a query via TCP.
    310
    311      @param q: the query
    312      @type q: dns.message.Message object
    313      @param where: where to send the message
    314      @type where: string containing an IPv4 or IPv6 address
    315      @param timeout: The number of seconds to wait before the query times out.
    316      If None, the default, wait forever.
    317      @type timeout: float
    318      @param port: The port to which to send the message.  The default is 53.
    319      @type port: int
    320      @param af: the address family to use.  The default is None, which
    321      causes the address family to use to be inferred from the form of where.
    322      If the inference attempt fails, AF_INET is used.
    323      @type af: int
    324      @rtype: dns.message.Message object
    325      @param source: source address.  The default is the wildcard address.
    326      @type source: string
    327      @param source_port: The port from which to send the message.
    328      The default is 0.
    329      @type source_port: int
    330      @param one_rr_per_rrset: Put each RR into its own RRset
    331      @type one_rr_per_rrset: bool
    332      """
    333
    334      wire = q.to_wire()
    335      (af, destination, source) = _destination_and_source(af, where, port,
    336                                                          source, source_port)
    337      s = socket_factory(af, socket.SOCK_STREAM, 0)
    338      begin_time = None
    339      try:
    340          expiration = _compute_expiration(timeout)
    341          s.setblocking(0)
    342          begin_time = time.time()
    343          if source is not None:
    344              s.bind(source)
    345          _connect(s, destination)
    346
    347          l = len(wire)
    348
    349          # copying the wire into tcpmsg is inefficient, but lets us
    350          # avoid writev() or doing a short write that would get pushed
    351          # onto the net
    352          tcpmsg = struct.pack("!H", l) + wire
    353          _net_write(s, tcpmsg, expiration)
    354          ldata = _net_read(s, 2, expiration)
    355          (l,) = struct.unpack("!H", ldata)
    356          wire = _net_read(s, l, expiration)
    357      finally:
    358          if begin_time is None:
    359              response_time = 0
    360          else:
    361              response_time = time.time() - begin_time
    362          s.close()
    363      r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac,
    364                                one_rr_per_rrset=one_rr_per_rrset)
    365      r.time = response_time
    366      if not q.is_response(r):
    367          raise BadResponse
    368      return r
    369
    370
    371 -def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN,
    372          timeout=None, port=53, keyring=None, keyname=None, relativize=True,
    373          af=None, lifetime=None, source=None, source_port=0, serial=0,
    374          use_udp=False, keyalgorithm=dns.tsig.default_algorithm):
    375      """Return a generator for the responses to a zone transfer.
    376
    377      @param where: where to send the message
    378      @type where: string containing an IPv4 or IPv6 address
    379      @param zone: The name of the zone to transfer
    380      @type zone: dns.name.Name object or string
    381      @param rdtype: The type of zone transfer.  The default is
    382      dns.rdatatype.AXFR.
    383      @type rdtype: int or string
    384      @param rdclass: The class of the zone transfer.  The default is
    385      dns.rdataclass.IN.
    386      @type rdclass: int or string
    387      @param timeout: The number of seconds to wait for each response message.
    388      If None, the default, wait forever.
    389      @type timeout: float
    390      @param port: The port to which to send the message.  The default is 53.
    391      @type port: int
    392      @param keyring: The TSIG keyring to use
    393      @type keyring: dict
    394      @param keyname: The name of the TSIG key to use
    395      @type keyname: dns.name.Name object or string
    396      @param relativize: If True, all names in the zone will be relativized to
    397      the zone origin.  It is essential that the relativize setting matches
    398      the one specified to dns.zone.from_xfr().
    399      @type relativize: bool
    400      @param af: the address family to use.  The default is None, which
    401      causes the address family to use to be inferred from the form of where.
    402      If the inference attempt fails, AF_INET is used.
    403      @type af: int
    404      @param lifetime: The total number of seconds to spend doing the transfer.
    405      If None, the default, then there is no limit on the time the transfer may
    406      take.
    407      @type lifetime: float
    408      @rtype: generator of dns.message.Message objects.
    409      @param source: source address.  The default is the wildcard address.
    410      @type source: string
    411      @param source_port: The port from which to send the message.
    412      The default is 0.
    413      @type source_port: int
    414      @param serial: The SOA serial number to use as the base for an IXFR diff
    415      sequence (only meaningful if rdtype == dns.rdatatype.IXFR).
    416      @type serial: int
    417      @param use_udp: Use UDP (only meaningful for IXFR)
    418      @type use_udp: bool
    419      @param keyalgorithm: The TSIG algorithm to use; defaults to
    420      dns.tsig.default_algorithm
    421      @type keyalgorithm: string
    422      """
    423
    424      if isinstance(zone, string_types):
    425          zone = dns.name.from_text(zone)
    426      if isinstance(rdtype, string_types):
    427          rdtype = dns.rdatatype.from_text(rdtype)
    428      q = dns.message.make_query(zone, rdtype, rdclass)
    429      if rdtype == dns.rdatatype.IXFR:
    430          rrset = dns.rrset.from_text(zone, 0, 'IN', 'SOA',
    431                                      '. . %u 0 0 0 0' % serial)
    432          q.authority.append(rrset)
    433      if keyring is not None:
    434          q.use_tsig(keyring, keyname, algorithm=keyalgorithm)
    435      wire = q.to_wire()
    436      (af, destination, source) = _destination_and_source(af, where, port,
    437                                                          source, source_port)
    438      if use_udp:
    439          if rdtype != dns.rdatatype.IXFR:
    440              raise ValueError('cannot do a UDP AXFR')
    441          s = socket_factory(af, socket.SOCK_DGRAM, 0)
    442      else:
    443          s = socket_factory(af, socket.SOCK_STREAM, 0)
    444      s.setblocking(0)
    445      if source is not None:
    446          s.bind(source)
    447      expiration = _compute_expiration(lifetime)
    448      _connect(s, destination)
    449      l = len(wire)
    450      if use_udp:
    451          _wait_for_writable(s, expiration)
    452          s.send(wire)
    453      else:
    454          tcpmsg = struct.pack("!H", l) + wire
    455          _net_write(s, tcpmsg, expiration)
    456      done = False
    457      delete_mode = True
    458      expecting_SOA = False
    459      soa_rrset = None
    460      if relativize:
    461          origin = zone
    462          oname = dns.name.empty
    463      else:
    464          origin = None
    465          oname = zone
    466      tsig_ctx = None
    467      first = True
    468      while not done:
    469          mexpiration = _compute_expiration(timeout)
    470          if mexpiration is None or mexpiration > expiration:
    471              mexpiration = expiration
    472          if use_udp:
    473              _wait_for_readable(s, expiration)
    474              (wire, from_address) = s.recvfrom(65535)
    475          else:
    476              ldata = _net_read(s, 2, mexpiration)
    477              (l,) = struct.unpack("!H", ldata)
    478              wire = _net_read(s, l, mexpiration)
    479          is_ixfr = (rdtype == dns.rdatatype.IXFR)
    480          r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac,
    481                                    xfr=True, origin=origin, tsig_ctx=tsig_ctx,
    482                                    multi=True, first=first,
    483                                    one_rr_per_rrset=is_ixfr)
    484          tsig_ctx = r.tsig_ctx
    485          first = False
    486          answer_index = 0
    487          if soa_rrset is None:
    488              if not r.answer or r.answer[0].name != oname:
    489                  raise dns.exception.FormError(
    490                      "No answer or RRset not for qname")
    491              rrset = r.answer[0]
    492              if rrset.rdtype != dns.rdatatype.SOA:
    493                  raise dns.exception.FormError("first RRset is not an SOA")
    494              answer_index = 1
    495              soa_rrset = rrset.copy()
    496              if rdtype == dns.rdatatype.IXFR:
    497                  if soa_rrset[0].serial <= serial:
    498                      #
    499                      # We're already up-to-date.
    500                      #
    501                      done = True
    502                  else:
    503                      expecting_SOA = True
    504          #
    505          # Process SOAs in the answer section (other than the initial
    506          # SOA in the first message).
    507          #
    508          for rrset in r.answer[answer_index:]:
    509              if done:
    510                  raise dns.exception.FormError("answers after final SOA")
    511              if rrset.rdtype == dns.rdatatype.SOA and rrset.name == oname:
    512                  if expecting_SOA:
    513                      if rrset[0].serial != serial:
    514                          raise dns.exception.FormError(
    515                              "IXFR base serial mismatch")
    516                      expecting_SOA = False
    517                  elif rdtype == dns.rdatatype.IXFR:
    518                      delete_mode = not delete_mode
    519                  #
    520                  # If this SOA RRset is equal to the first we saw then we're
    521                  # finished. If this is an IXFR we also check that we're seeing
    522                  # the record in the expected part of the response.
    523                  #
    524                  if rrset == soa_rrset and \
    525                          (rdtype == dns.rdatatype.AXFR or
    526                           (rdtype == dns.rdatatype.IXFR and delete_mode)):
    527                      done = True
    528              elif expecting_SOA:
    529                  #
    530                  # We made an IXFR request and are expecting another
    531                  # SOA RR, but saw something else, so this must be an
    532                  # AXFR response.
    533                  #
    534                  rdtype = dns.rdatatype.AXFR
    535                  expecting_SOA = False
    536          if done and q.keyring and not r.had_tsig:
    537              raise dns.exception.FormError("missing TSIG")
    538          yield r
    539      s.close()
    540