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