1# -*- coding: utf-8
2# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
3
4# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
5#
6# Permission to use, copy, modify, and distribute this software and its
7# documentation for any purpose with or without fee is hereby granted,
8# provided that the above copyright notice and this permission notice
9# appear in all copies.
10#
11# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
12# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
14# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19import unittest
20import binascii
21
22import dns.exception
23import dns.flags
24import dns.message
25import dns.name
26import dns.rdataclass
27import dns.rdatatype
28import dns.rrset
29import dns.tsig
30import dns.update
31import dns.rdtypes.ANY.OPT
32import dns.rdtypes.ANY.TSIG
33
34from tests.util import here
35
36query_text = """id 1234
37opcode QUERY
38rcode NOERROR
39flags RD
40edns 0
41eflags DO
42payload 4096
43;QUESTION
44wwww.dnspython.org. IN A
45;ANSWER
46;AUTHORITY
47;ADDITIONAL"""
48
49goodhex = b'04d201000001000000000001047777777709646e73707974686f6e' \
50          b'036f726700000100010000291000000080000000'
51
52goodwire = binascii.unhexlify(goodhex)
53
54answer_text = """id 1234
55opcode QUERY
56rcode NOERROR
57flags QR AA RD
58;QUESTION
59dnspython.org. IN SOA
60;ANSWER
61dnspython.org. 3600 IN SOA woof.dnspython.org. hostmaster.dnspython.org. 2003052700 3600 1800 604800 3600
62;AUTHORITY
63dnspython.org. 3600 IN NS ns1.staff.nominum.org.
64dnspython.org. 3600 IN NS ns2.staff.nominum.org.
65dnspython.org. 3600 IN NS woof.play-bow.org.
66;ADDITIONAL
67woof.play-bow.org. 3600 IN A 204.152.186.150
68"""
69
70goodhex2 = '04d2 8500 0001 0001 0003 0001' \
71           '09646e73707974686f6e036f726700 0006 0001' \
72           'c00c 0006 0001 00000e10 0028 ' \
73               '04776f6f66c00c 0a686f73746d6173746572c00c' \
74               '7764289c 00000e10 00000708 00093a80 00000e10' \
75           'c00c 0002 0001 00000e10 0014' \
76               '036e7331057374616666076e6f6d696e756dc016' \
77           'c00c 0002 0001 00000e10 0006 036e7332c063' \
78           'c00c 0002 0001 00000e10 0010 04776f6f6608706c61792d626f77c016' \
79           'c091 0001 0001 00000e10 0004 cc98ba96'
80
81
82goodwire2 = binascii.unhexlify(goodhex2.replace(' ', '').encode())
83
84query_text_2 = """id 1234
85opcode QUERY
86rcode 4095
87flags RD
88edns 0
89eflags DO
90payload 4096
91;QUESTION
92wwww.dnspython.org. IN A
93;ANSWER
94;AUTHORITY
95;ADDITIONAL"""
96
97goodhex3 = b'04d2010f0001000000000001047777777709646e73707974686f6e' \
98           b'036f726700000100010000291000ff0080000000'
99
100goodwire3 = binascii.unhexlify(goodhex3)
101
102idna_text = """id 1234
103opcode QUERY
104rcode NOERROR
105flags QR AA RD
106;QUESTION
107Königsgäßchen. IN NS
108;ANSWER
109Königsgäßchen. 3600 IN NS Königsgäßchen.
110"""
111
112class MessageTestCase(unittest.TestCase):
113
114    def test_class(self):
115        m = dns.message.from_text(query_text)
116        self.assertTrue(isinstance(m, dns.message.QueryMessage))
117
118    def test_comparison_eq1(self):
119        q1 = dns.message.from_text(query_text)
120        q2 = dns.message.from_text(query_text)
121        self.assertEqual(q1, q2)
122
123    def test_comparison_ne1(self):
124        q1 = dns.message.from_text(query_text)
125        q2 = dns.message.from_text(query_text)
126        q2.id = 10
127        self.assertNotEqual(q1, q2)
128
129    def test_comparison_ne2(self):
130        q1 = dns.message.from_text(query_text)
131        q2 = dns.message.from_text(query_text)
132        q2.question = []
133        self.assertNotEqual(q1, q2)
134
135    def test_comparison_ne3(self):
136        q1 = dns.message.from_text(query_text)
137        self.assertNotEqual(q1, 1)
138
139    def test_EDNS_to_wire1(self):
140        q = dns.message.from_text(query_text)
141        w = q.to_wire()
142        self.assertEqual(w, goodwire)
143
144    def test_EDNS_from_wire1(self):
145        m = dns.message.from_wire(goodwire)
146        self.assertEqual(str(m), query_text)
147
148    def test_EDNS_to_wire2(self):
149        q = dns.message.from_text(query_text_2)
150        w = q.to_wire()
151        self.assertEqual(w, goodwire3)
152
153    def test_EDNS_from_wire2(self):
154        m = dns.message.from_wire(goodwire3)
155        self.assertEqual(str(m), query_text_2)
156
157    def test_EDNS_options_wire(self):
158        m = dns.message.make_query('foo', 'A')
159        opt = dns.edns.GenericOption(3, b'data')
160        m.use_edns(options=[opt])
161        m2 = dns.message.from_wire(m.to_wire())
162        self.assertEqual(m2.edns, 0)
163        self.assertEqual(len(m2.options), 1)
164        self.assertEqual(m2.options[0], opt)
165
166    def test_TooBig(self):
167        def bad():
168            q = dns.message.from_text(query_text)
169            for i in range(0, 25):
170                rrset = dns.rrset.from_text('foo%d.' % i, 3600,
171                                            dns.rdataclass.IN,
172                                            dns.rdatatype.A,
173                                            '10.0.0.%d' % i)
174                q.additional.append(rrset)
175            q.to_wire(max_size=512)
176        self.assertRaises(dns.exception.TooBig, bad)
177
178    def test_answer1(self):
179        a = dns.message.from_text(answer_text)
180        wire = a.to_wire(want_shuffle=False)
181        self.assertEqual(wire, goodwire2)
182
183    def test_TrailingJunk(self):
184        def bad():
185            badwire = goodwire + b'\x00'
186            dns.message.from_wire(badwire)
187        self.assertRaises(dns.message.TrailingJunk, bad)
188
189    def test_ShortHeader(self):
190        def bad():
191            badwire = b'\x00' * 11
192            dns.message.from_wire(badwire)
193        self.assertRaises(dns.message.ShortHeader, bad)
194
195    def test_RespondingToResponse(self):
196        def bad():
197            q = dns.message.make_query('foo', 'A')
198            r1 = dns.message.make_response(q)
199            dns.message.make_response(r1)
200        self.assertRaises(dns.exception.FormError, bad)
201
202    def test_RespondingToEDNSRequestAndSettingRA(self):
203        q = dns.message.make_query('foo', 'A', use_edns=0)
204        r = dns.message.make_response(q, True)
205        self.assertTrue(r.flags & dns.flags.RA != 0)
206        self.assertEqual(r.edns, 0)
207
208    def test_ExtendedRcodeSetting(self):
209        m = dns.message.make_query('foo', 'A')
210        m.set_rcode(4095)
211        self.assertEqual(m.rcode(), 4095)
212        self.assertEqual(m.edns, 0)
213        m.set_rcode(2)
214        self.assertEqual(m.rcode(), 2)
215
216    def test_EDNSVersionCoherence(self):
217        m = dns.message.make_query('foo', 'A')
218        m.use_edns(1)
219        self.assertEqual((m.ednsflags >> 16) & 0xFF, 1)
220
221    def test_SettingNoEDNSOptionsImpliesNoEDNS(self):
222        m = dns.message.make_query('foo', 'A')
223        self.assertEqual(m.edns, -1)
224
225    def test_SettingEDNSFlagsImpliesEDNS(self):
226        m = dns.message.make_query('foo', 'A', ednsflags=dns.flags.DO)
227        self.assertEqual(m.edns, 0)
228
229    def test_SettingEDNSPayloadImpliesEDNS(self):
230        m = dns.message.make_query('foo', 'A', payload=4096)
231        self.assertEqual(m.edns, 0)
232
233    def test_SettingEDNSRequestPayloadImpliesEDNS(self):
234        m = dns.message.make_query('foo', 'A', request_payload=4096)
235        self.assertEqual(m.edns, 0)
236
237    def test_SettingOptionsImpliesEDNS(self):
238        m = dns.message.make_query('foo', 'A', options=[])
239        self.assertEqual(m.edns, 0)
240
241    def test_FindRRset(self):
242        a = dns.message.from_text(answer_text)
243        n = dns.name.from_text('dnspython.org.')
244        rrs1 = a.find_rrset(a.answer, n, dns.rdataclass.IN, dns.rdatatype.SOA)
245        rrs2 = a.find_rrset(dns.message.ANSWER, n, dns.rdataclass.IN,
246                            dns.rdatatype.SOA)
247        self.assertEqual(rrs1, rrs2)
248
249    def test_FindRRsetUnindexed(self):
250        a = dns.message.from_text(answer_text)
251        a.index = None
252        n = dns.name.from_text('dnspython.org.')
253        rrs1 = a.find_rrset(a.answer, n, dns.rdataclass.IN, dns.rdatatype.SOA)
254        rrs2 = a.find_rrset(dns.message.ANSWER, n, dns.rdataclass.IN,
255                            dns.rdatatype.SOA)
256        self.assertEqual(rrs1, rrs2)
257
258    def test_GetRRset(self):
259        a = dns.message.from_text(answer_text)
260        a.index = None
261        n = dns.name.from_text('dnspython.org.')
262        rrs1 = a.get_rrset(a.answer, n, dns.rdataclass.IN, dns.rdatatype.SOA)
263        rrs2 = a.get_rrset(dns.message.ANSWER, n, dns.rdataclass.IN,
264                           dns.rdatatype.SOA)
265        self.assertEqual(rrs1, rrs2)
266
267    def test_GetNonexistentRRset(self):
268        a = dns.message.from_text(answer_text)
269        a.index = None
270        n = dns.name.from_text('dnspython.org.')
271        rrs1 = a.get_rrset(a.answer, n, dns.rdataclass.IN, dns.rdatatype.TXT)
272        rrs2 = a.get_rrset(dns.message.ANSWER, n, dns.rdataclass.IN,
273                           dns.rdatatype.TXT)
274        self.assertTrue(rrs1 is None)
275        self.assertEqual(rrs1, rrs2)
276
277    def test_CleanTruncated(self):
278        def bad():
279            a = dns.message.from_text(answer_text)
280            a.flags |= dns.flags.TC
281            wire = a.to_wire(want_shuffle=False)
282            dns.message.from_wire(wire, raise_on_truncation=True)
283        self.assertRaises(dns.message.Truncated, bad)
284
285    def test_MessyTruncated(self):
286        def bad():
287            a = dns.message.from_text(answer_text)
288            a.flags |= dns.flags.TC
289            wire = a.to_wire(want_shuffle=False)
290            dns.message.from_wire(wire[:-3], raise_on_truncation=True)
291        self.assertRaises(dns.message.Truncated, bad)
292
293    def test_IDNA_2003(self):
294        a = dns.message.from_text(idna_text, idna_codec=dns.name.IDNA_2003)
295        rrs = dns.rrset.from_text_list('xn--knigsgsschen-lcb0w.', 30,
296                                       'in', 'ns',
297                                       ['xn--knigsgsschen-lcb0w.'],
298                                       idna_codec=dns.name.IDNA_2003)
299        self.assertEqual(a.answer[0], rrs)
300
301    @unittest.skipUnless(dns.name.have_idna_2008,
302                         'Python idna cannot be imported; no IDNA2008')
303    def test_IDNA_2008(self):
304        a = dns.message.from_text(idna_text, idna_codec=dns.name.IDNA_2008)
305        rrs = dns.rrset.from_text_list('xn--knigsgchen-b4a3dun.', 30,
306                                       'in', 'ns',
307                                       ['xn--knigsgchen-b4a3dun.'],
308                                       idna_codec=dns.name.IDNA_2008)
309        self.assertEqual(a.answer[0], rrs)
310
311    def test_bad_section_number(self):
312        m = dns.message.make_query('foo', 'A')
313        self.assertRaises(ValueError,
314                          lambda: m.section_number(123))
315
316    def test_section_from_number(self):
317        m = dns.message.make_query('foo', 'A')
318        self.assertEqual(m.section_from_number(dns.message.QUESTION),
319                         m.question)
320        self.assertEqual(m.section_from_number(dns.message.ANSWER),
321                         m.answer)
322        self.assertEqual(m.section_from_number(dns.message.AUTHORITY),
323                         m.authority)
324        self.assertEqual(m.section_from_number(dns.message.ADDITIONAL),
325                         m.additional)
326        self.assertRaises(ValueError,
327                          lambda: m.section_from_number(999))
328
329    def test_wanting_EDNS_true_is_EDNS0(self):
330        m = dns.message.make_query('foo', 'A')
331        self.assertEqual(m.edns, -1)
332        m.use_edns(True)
333        self.assertEqual(m.edns, 0)
334
335    def test_wanting_DNSSEC_turns_on_EDNS(self):
336        m = dns.message.make_query('foo', 'A')
337        self.assertEqual(m.edns, -1)
338        m.want_dnssec()
339        self.assertEqual(m.edns, 0)
340        self.assertTrue(m.ednsflags & dns.flags.DO)
341
342    def test_EDNS_default_payload_is_1232(self):
343        m = dns.message.make_query('foo', 'A')
344        m.use_edns()
345        self.assertEqual(m.payload, dns.message.DEFAULT_EDNS_PAYLOAD)
346
347    def test_from_file(self):
348        m = dns.message.from_file(here('query'))
349        expected = dns.message.from_text(query_text)
350        self.assertEqual(m, expected)
351
352    def test_explicit_header_comment(self):
353        m = dns.message.from_text(';HEADER\n' + query_text)
354        expected = dns.message.from_text(query_text)
355        self.assertEqual(m, expected)
356
357    def test_repr(self):
358        q = dns.message.from_text(query_text)
359        self.assertEqual(repr(q), '<DNS message, ID 1234>')
360
361    def test_non_question_setters(self):
362        rrset = dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1')
363        q = dns.message.QueryMessage(id=1)
364        q.answer = [rrset]
365        self.assertEqual(q.sections[1], [rrset])
366        self.assertEqual(q.sections[2], [])
367        self.assertEqual(q.sections[3], [])
368        q.authority = [rrset]
369        self.assertEqual(q.sections[2], [rrset])
370        self.assertEqual(q.sections[3], [])
371        q.additional = [rrset]
372        self.assertEqual(q.sections[3], [rrset])
373
374    def test_is_a_response_empty_question(self):
375        q = dns.message.make_query('www.dnspython.org.', 'a')
376        r = dns.message.make_response(q)
377        r.question = []
378        r.set_rcode(dns.rcode.FORMERR)
379        self.assertTrue(q.is_response(r))
380
381    def test_not_a_response(self):
382        q = dns.message.QueryMessage(id=1)
383        self.assertFalse(q.is_response(q))
384        r = dns.message.QueryMessage(id=2)
385        r.flags = dns.flags.QR
386        self.assertFalse(q.is_response(r))
387        r = dns.update.UpdateMessage(id=1)
388        self.assertFalse(q.is_response(r))
389        q1 = dns.message.make_query('www.dnspython.org.', 'a')
390        q2 = dns.message.make_query('www.google.com.', 'a')
391        # Give them the same id, as we want to test if responses for
392        # differing questions are rejected.
393        q1.id = 1
394        q2.id = 1
395        r = dns.message.make_response(q2)
396        self.assertFalse(q1.is_response(r))
397        # Now set rcode to FORMERR and check again.  It should still
398        # not be a response as we check the question section for FORMERR
399        # if it is present.
400        r.set_rcode(dns.rcode.FORMERR)
401        self.assertFalse(q1.is_response(r))
402        # Test the other case of differing questions, where there is
403        # something in the response's question section that is not in
404        # the question's.  We have to do multiple questions to test
405        # this :)
406        r = dns.message.make_query('www.dnspython.org.', 'a')
407        r.flags |= dns.flags.QR
408        r.id = 1
409        r.find_rrset(r.question, dns.name.from_text('example'),
410                     dns.rdataclass.IN, dns.rdatatype.A, create=True,
411                     force_unique=True)
412        self.assertFalse(q1.is_response(r))
413
414    def test_more_not_equal_cases(self):
415        q1 = dns.message.make_query('www.dnspython.org.', 'a')
416        q2 = dns.message.make_query('www.dnspython.org.', 'a')
417        # ensure ids are same
418        q1.id = 1
419        q2.id = 1
420        # and flags are different
421        q2.flags |= dns.flags.QR
422        self.assertFalse(q1 == q2)
423        q2.flags = q1.flags
424        q2.find_rrset(q2.question, dns.name.from_text('example'),
425                      dns.rdataclass.IN, dns.rdatatype.A, create=True,
426                      force_unique=True)
427        self.assertFalse(q1 == q2)
428
429    def test_edns_properties(self):
430        q = dns.message.make_query('www.dnspython.org.', 'a')
431        self.assertEqual(q.edns, -1)
432        self.assertEqual(q.payload, 0)
433        self.assertEqual(q.options, ())
434        q = dns.message.make_query('www.dnspython.org.', 'a', use_edns=0,
435                                   payload=4096)
436        self.assertEqual(q.edns, 0)
437        self.assertEqual(q.payload, 4096)
438        self.assertEqual(q.options, ())
439
440    def test_generic_message_class(self):
441        q1 = dns.message.Message(id=1)
442        q1.set_opcode(dns.opcode.NOTIFY)
443        q1.flags |= dns.flags.AA
444        q1.find_rrset(q1.question, dns.name.from_text('example'),
445                      dns.rdataclass.IN, dns.rdatatype.SOA, create=True,
446                      force_unique=True)
447        w = q1.to_wire()
448        q2 = dns.message.from_wire(w)
449        self.assertTrue(isinstance(q2, dns.message.Message))
450        self.assertFalse(isinstance(q2, dns.message.QueryMessage))
451        self.assertFalse(isinstance(q2, dns.update.UpdateMessage))
452        self.assertEqual(q1, q2)
453
454    def test_truncated_exception_message(self):
455        q = dns.message.Message(id=1)
456        q.flags |= dns.flags.TC
457        te = dns.message.Truncated(message=q)
458        self.assertEqual(te.message(), q)
459
460    def test_bad_opt(self):
461        # Not in addtional
462        q = dns.message.Message(id=1)
463        opt = dns.rdtypes.ANY.OPT.OPT(1200, dns.rdatatype.OPT, ())
464        rrs = dns.rrset.from_rdata(dns.name.root, 0, opt)
465        q.answer.append(rrs)
466        wire = q.to_wire()
467        with self.assertRaises(dns.message.BadEDNS):
468            dns.message.from_wire(wire)
469        # Owner name not root name
470        q = dns.message.Message(id=1)
471        rrs = dns.rrset.from_rdata('foo.', 0, opt)
472        q.additional.append(rrs)
473        wire = q.to_wire()
474        with self.assertRaises(dns.message.BadEDNS):
475            dns.message.from_wire(wire)
476        # Multiple opts
477        q = dns.message.Message(id=1)
478        rrs = dns.rrset.from_rdata(dns.name.root, 0, opt)
479        q.additional.append(rrs)
480        q.additional.append(rrs)
481        wire = q.to_wire()
482        with self.assertRaises(dns.message.BadEDNS):
483            dns.message.from_wire(wire)
484
485    def test_bad_tsig(self):
486        keyname = dns.name.from_text('key.')
487        # Not in addtional
488        q = dns.message.Message(id=1)
489        tsig = dns.rdtypes.ANY.TSIG.TSIG(dns.rdataclass.ANY, dns.rdatatype.TSIG,
490                                         dns.tsig.HMAC_SHA256, 0, 300, b'1234',
491                                         0, 0, b'')
492        rrs = dns.rrset.from_rdata(keyname, 0, tsig)
493        q.answer.append(rrs)
494        wire = q.to_wire()
495        with self.assertRaises(dns.message.BadTSIG):
496            dns.message.from_wire(wire)
497        # Multiple tsigs
498        q = dns.message.Message(id=1)
499        q.additional.append(rrs)
500        q.additional.append(rrs)
501        wire = q.to_wire()
502        with self.assertRaises(dns.message.BadTSIG):
503            dns.message.from_wire(wire)
504        # Class not ANY
505        tsig = dns.rdtypes.ANY.TSIG.TSIG(dns.rdataclass.IN, dns.rdatatype.TSIG,
506                                         dns.tsig.HMAC_SHA256, 0, 300, b'1234',
507                                         0, 0, b'')
508        rrs = dns.rrset.from_rdata(keyname, 0, tsig)
509        wire = q.to_wire()
510        with self.assertRaises(dns.message.BadTSIG):
511            dns.message.from_wire(wire)
512
513    def test_read_no_content_message(self):
514        m = dns.message.from_text(';comment')
515        self.assertIsInstance(m, dns.message.QueryMessage)
516
517    def test_eflags_turns_on_edns(self):
518        m = dns.message.from_text('eflags DO')
519        self.assertIsInstance(m, dns.message.QueryMessage)
520        self.assertEqual(m.edns, 0)
521
522    def test_payload_turns_on_edns(self):
523        m = dns.message.from_text('payload 1200')
524        self.assertIsInstance(m, dns.message.QueryMessage)
525        self.assertEqual(m.payload, 1200)
526
527    def test_bogus_header(self):
528        with self.assertRaises(dns.message.UnknownHeaderField):
529            dns.message.from_text('bogus foo')
530
531    def test_question_only(self):
532        m = dns.message.from_text(answer_text)
533        w = m.to_wire()
534        r = dns.message.from_wire(w, question_only=True)
535        self.assertEqual(r.id, m.id)
536        self.assertEqual(r.question[0], m.question[0])
537        self.assertEqual(len(r.answer), 0)
538        self.assertEqual(len(r.authority), 0)
539        self.assertEqual(len(r.additional), 0)
540
541    def test_bad_resolve_chaining(self):
542        r = dns.message.make_query('www.dnspython.org.', 'a')
543        with self.assertRaises(dns.message.NotQueryResponse):
544            r.resolve_chaining()
545        r.flags |= dns.flags.QR
546        r.id = 1
547        r.find_rrset(r.question, dns.name.from_text('example'),
548                     dns.rdataclass.IN, dns.rdatatype.A, create=True,
549                     force_unique=True)
550        with self.assertRaises(dns.exception.FormError):
551            r.resolve_chaining()
552
553    def test_resolve_chaining_no_infinite_loop(self):
554        r = dns.message.from_text('''id 1
555flags QR
556;QUESTION
557www.example. IN CNAME
558;AUTHORITY
559example. 300 IN SOA . . 1 2 3 4 5
560''')
561        # passing is actuall not going into an infinite loop in this call
562        result = r.resolve_chaining()
563        self.assertEqual(result.canonical_name,
564                         dns.name.from_text('www.example.'))
565        self.assertEqual(result.minimum_ttl, 5)
566        self.assertIsNone(result.answer)
567
568    def test_bad_text_questions(self):
569        with self.assertRaises(dns.exception.SyntaxError):
570            dns.message.from_text('''id 1
571;QUESTION
572example.
573''')
574        with self.assertRaises(dns.exception.SyntaxError):
575            dns.message.from_text('''id 1
576;QUESTION
577example. IN
578''')
579        with self.assertRaises(dns.rdatatype.UnknownRdatatype):
580            dns.message.from_text('''id 1
581;QUESTION
582example. INA
583''')
584        with self.assertRaises(dns.rdatatype.UnknownRdatatype):
585            dns.message.from_text('''id 1
586;QUESTION
587example. IN BOGUS
588''')
589
590    def test_bad_text_rrs(self):
591        with self.assertRaises(dns.exception.SyntaxError):
592            dns.message.from_text('''id 1
593flags QR
594;QUESTION
595example. IN A
596;ANSWER
597example.
598''')
599        with self.assertRaises(dns.exception.SyntaxError):
600            dns.message.from_text('''id 1
601flags QR
602;QUESTION
603example. IN A
604;ANSWER
605example. IN
606''')
607        with self.assertRaises(dns.exception.SyntaxError):
608            dns.message.from_text('''id 1
609flags QR
610;QUESTION
611example. IN A
612;ANSWER
613example. 300
614''')
615        with self.assertRaises(dns.rdatatype.UnknownRdatatype):
616            dns.message.from_text('''id 1
617flags QR
618;QUESTION
619example. IN A
620;ANSWER
621example. 30a IN A
622''')
623        with self.assertRaises(dns.rdatatype.UnknownRdatatype):
624            dns.message.from_text('''id 1
625flags QR
626;QUESTION
627example. IN A
628;ANSWER
629example. 300 INA A
630''')
631        with self.assertRaises(dns.exception.UnexpectedEnd):
632            dns.message.from_text('''id 1
633flags QR
634;QUESTION
635example. IN A
636;ANSWER
637example. 300 IN A
638''')
639        with self.assertRaises(dns.exception.SyntaxError):
640            dns.message.from_text('''id 1
641flags QR
642opcode UPDATE
643;ZONE
644example. IN SOA
645;UPDATE
646example. 300 IN A
647''')
648        with self.assertRaises(dns.exception.SyntaxError):
649            dns.message.from_text('''id 1
650flags QR
651opcode UPDATE
652;ZONE
653example. IN SOA
654;UPDATE
655example. 300 NONE A
656''')
657        with self.assertRaises(dns.exception.SyntaxError):
658            dns.message.from_text('''id 1
659flags QR
660opcode UPDATE
661;ZONE
662example. IN SOA
663;PREREQ
664example. 300 NONE A 10.0.0.1
665''')
666        with self.assertRaises(dns.exception.SyntaxError):
667            dns.message.from_text('''id 1
668flags QR
669;ANSWER
670            300 IN A 10.0.0.1
671''')
672        with self.assertRaises(dns.exception.SyntaxError):
673            dns.message.from_text('''id 1
674flags QR
675;QUESTION
676            IN SOA
677''')
678
679    def test_from_wire_makes_Flag(self):
680        m = dns.message.from_wire(goodwire)
681        self.assertIsInstance(m.flags, dns.flags.Flag)
682        self.assertEqual(m.flags, dns.flags.Flag.RD)
683
684
685if __name__ == '__main__':
686    unittest.main()
687