1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
42 socket_factory = socket.socket
43
45
46 """A DNS query response came from an unexpected address or port."""
47
48
50
51 """A DNS query response does not respond to the question asked."""
52
53
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
140 """
141 Internal API. Do not use.
142 """
143 global _polling_backend
144
145 _polling_backend = fn
146
147 if hasattr(select, 'poll'):
148
149
150
151 _polling_backend = _poll_for
152 else:
153 _polling_backend = _select_for
154
155
158
159
162
163
171
172
174
175
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
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
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
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
350
351
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
500
501 done = True
502 else:
503 expecting_SOA = True
504
505
506
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
521
522
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
531
532
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