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