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
42
43 """A DNS query response came from an unexpected address or port."""
44
45
47
48 """A DNS query response does not respond to the question asked."""
49
50
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
137 """
138 Internal API. Do not use.
139 """
140 global _polling_backend
141
142 _polling_backend = fn
143
144 if hasattr(select, 'poll'):
145
146
147
148 _polling_backend = _poll_for
149 else:
150 _polling_backend = _select_for
151
152
155
156
159
160
168
169
171
172
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
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
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
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
344
345
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
494
495 done = True
496 else:
497 expecting_SOA = True
498
499
500
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
515
516
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
525
526
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