1 # Unix SMB/CIFS implementation.
2 # Copyright (C) Kai Blin <kai@samba.org> 2011
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 import samba.ndr as ndr
23 import samba.dcerpc.dns as dns
24 from samba.tests import TestCase
26 FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
29 class DNSTest(TestCase):
31 def errstr(self, errcode):
32 "Return a readable error code"
47 return string_codes[errcode]
50 def assert_dns_rcode_equals(self, packet, rcode):
51 "Helper function to check return code"
52 p_errcode = packet.operation & 0x000F
53 self.assertEquals(p_errcode, rcode, "Expected RCODE %s, got %s" %
54 (self.errstr(rcode), self.errstr(p_errcode)))
56 def assert_dns_opcode_equals(self, packet, opcode):
57 "Helper function to check opcode"
58 p_opcode = packet.operation & 0x7800
59 self.assertEquals(p_opcode, opcode, "Expected OPCODE %s, got %s" %
62 def make_name_packet(self, opcode, qid=None):
63 "Helper creating a dns.name_packet"
66 p.id = random.randint(0x0, 0xffff)
71 def finish_name_packet(self, packet, questions):
72 "Helper to finalize a dns.name_packet"
73 packet.qdcount = len(questions)
74 packet.questions = questions
76 def make_name_question(self, name, qtype, qclass):
77 "Helper creating a dns.name_question"
78 q = dns.name_question()
80 q.question_type = qtype
81 q.question_class = qclass
84 def get_dns_domain(self):
85 "Helper to get dns domain"
86 return os.getenv('REALM', 'example.com').lower()
88 def dns_transaction_udp(self, packet, host=os.getenv('SERVER_IP'), dump=False):
89 "send a DNS query and read the reply"
92 send_packet = ndr.ndr_pack(packet)
94 print self.hexdump(send_packet)
95 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
97 s.send(send_packet, 0)
98 recv_packet = s.recv(2048, 0)
100 print self.hexdump(recv_packet)
101 return ndr.ndr_unpack(dns.name_packet, recv_packet)
106 def dns_transaction_tcp(self, packet, host=os.getenv('SERVER_IP'), dump=False):
107 "send a DNS query and read the reply"
110 send_packet = ndr.ndr_pack(packet)
112 print self.hexdump(send_packet)
113 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
114 s.connect((host, 53))
115 tcp_packet = struct.pack('!H', len(send_packet))
116 tcp_packet += send_packet
117 s.send(tcp_packet, 0)
118 recv_packet = s.recv(0xffff + 2, 0)
120 print self.hexdump(recv_packet)
121 return ndr.ndr_unpack(dns.name_packet, recv_packet[2:])
126 def hexdump(self, src, length=8):
130 s, src = src[:length], src[length:]
131 hexa = ' '.join(["%02X" % ord(x) for x in s])
132 s = s.translate(FILTER)
133 result += "%04X %-*s %s\n" % (N, length*3, hexa, s)
138 class TestSimpleQueries(DNSTest):
140 def test_one_a_query(self):
141 "create a query packet containing one query record"
142 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
145 name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
146 q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN)
147 print "asking for ", q.name
150 self.finish_name_packet(p, questions)
151 response = self.dns_transaction_udp(p)
152 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
153 self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
154 self.assertEquals(response.ancount, 1)
155 self.assertEquals(response.answers[0].rdata,
156 os.getenv('SERVER_IP'))
158 def test_one_a_query_tcp(self):
159 "create a query packet containing one query record via TCP"
160 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
163 name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
164 q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN)
165 print "asking for ", q.name
168 self.finish_name_packet(p, questions)
169 response = self.dns_transaction_tcp(p)
170 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
171 self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
172 self.assertEquals(response.ancount, 1)
173 self.assertEquals(response.answers[0].rdata,
174 os.getenv('SERVER_IP'))
176 def test_one_mx_query(self):
177 "create a query packet causing an empty RCODE_OK answer"
178 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
181 name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
182 q = self.make_name_question(name, dns.DNS_QTYPE_MX, dns.DNS_QCLASS_IN)
183 print "asking for ", q.name
186 self.finish_name_packet(p, questions)
187 response = self.dns_transaction_udp(p)
188 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
189 self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
190 self.assertEquals(response.ancount, 0)
192 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
195 name = "invalid-%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
196 q = self.make_name_question(name, dns.DNS_QTYPE_MX, dns.DNS_QCLASS_IN)
197 print "asking for ", q.name
200 self.finish_name_packet(p, questions)
201 response = self.dns_transaction_udp(p)
202 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NXDOMAIN)
203 self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
204 self.assertEquals(response.ancount, 0)
206 def test_two_queries(self):
207 "create a query packet containing two query records"
208 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
211 name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
212 q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN)
215 name = "%s.%s" % ('bogusname', self.get_dns_domain())
216 q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN)
219 self.finish_name_packet(p, questions)
220 response = self.dns_transaction_udp(p)
221 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_FORMERR)
223 def test_qtype_all_query(self):
224 "create a QTYPE_ALL query"
225 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
228 name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
229 q = self.make_name_question(name, dns.DNS_QTYPE_ALL, dns.DNS_QCLASS_IN)
230 print "asking for ", q.name
233 self.finish_name_packet(p, questions)
234 response = self.dns_transaction_udp(p)
237 dc_ipv6 = os.getenv('SERVER_IPV6')
238 if dc_ipv6 is not None:
241 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
242 self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
243 self.assertEquals(response.ancount, num_answers)
244 self.assertEquals(response.answers[0].rdata,
245 os.getenv('SERVER_IP'))
246 if dc_ipv6 is not None:
247 self.assertEquals(response.answers[1].rdata, dc_ipv6)
249 def test_qclass_none_query(self):
250 "create a QCLASS_NONE query"
251 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
254 name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
255 q = self.make_name_question(name, dns.DNS_QTYPE_ALL, dns.DNS_QCLASS_NONE)
258 self.finish_name_packet(p, questions)
259 response = self.dns_transaction_udp(p)
260 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NOTIMP)
262 # Only returns an authority section entry in BIND and Win DNS
263 # FIXME: Enable one Samba implements this feature
264 # def test_soa_hostname_query(self):
265 # "create a SOA query for a hostname"
266 # p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
269 # name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
270 # q = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
271 # questions.append(q)
273 # self.finish_name_packet(p, questions)
274 # response = self.dns_transaction_udp(p)
275 # self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
276 # self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
277 # # We don't get SOA records for single hosts
278 # self.assertEquals(response.ancount, 0)
280 def test_soa_domain_query(self):
281 "create a SOA query for a domain"
282 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
285 name = self.get_dns_domain()
286 q = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
289 self.finish_name_packet(p, questions)
290 response = self.dns_transaction_udp(p)
291 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
292 self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
293 self.assertEquals(response.ancount, 1)
294 self.assertEquals(response.answers[0].rdata.minimum, 3600)
297 class TestDNSUpdates(DNSTest):
299 def test_two_updates(self):
300 "create two update requests"
301 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
304 name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
305 u = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN)
308 name = self.get_dns_domain()
309 u = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN)
312 self.finish_name_packet(p, updates)
313 response = self.dns_transaction_udp(p)
314 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_FORMERR)
316 def test_update_wrong_qclass(self):
317 "create update with DNS_QCLASS_NONE"
318 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
321 name = self.get_dns_domain()
322 u = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_NONE)
325 self.finish_name_packet(p, updates)
326 response = self.dns_transaction_udp(p)
327 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NOTIMP)
329 def test_update_prereq_with_non_null_ttl(self):
330 "test update with a non-null TTL"
331 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
334 name = self.get_dns_domain()
336 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
338 self.finish_name_packet(p, updates)
342 r.name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
343 r.rr_type = dns.DNS_QTYPE_TXT
344 r.rr_class = dns.DNS_QCLASS_NONE
349 p.ancount = len(prereqs)
352 response = self.dns_transaction_udp(p)
353 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_FORMERR)
355 # I'd love to test this one, but it segfaults. :)
356 # def test_update_prereq_with_non_null_length(self):
357 # "test update with a non-null length"
358 # p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
361 # name = self.get_dns_domain()
363 # u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
365 # self.finish_name_packet(p, updates)
369 # r.name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
370 # r.rr_type = dns.DNS_QTYPE_TXT
371 # r.rr_class = dns.DNS_QCLASS_ANY
376 # p.ancount = len(prereqs)
377 # p.answers = prereqs
379 # response = self.dns_transaction_udp(p)
380 # self.assert_dns_rcode_equals(response, dns.DNS_RCODE_FORMERR)
382 def test_update_prereq_nonexisting_name(self):
383 "test update with a nonexisting name"
384 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
387 name = self.get_dns_domain()
389 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
391 self.finish_name_packet(p, updates)
395 r.name = "idontexist.%s" % self.get_dns_domain()
396 r.rr_type = dns.DNS_QTYPE_TXT
397 r.rr_class = dns.DNS_QCLASS_ANY
402 p.ancount = len(prereqs)
405 response = self.dns_transaction_udp(p)
406 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NXRRSET)
408 def test_update_add_txt_record(self):
409 "test adding records works"
410 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
413 name = self.get_dns_domain()
415 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
417 self.finish_name_packet(p, updates)
421 r.name = "textrec.%s" % self.get_dns_domain()
422 r.rr_type = dns.DNS_QTYPE_TXT
423 r.rr_class = dns.DNS_QCLASS_IN
426 rdata = dns.txt_record()
427 rdata.txt = '"This is a test"'
430 p.nscount = len(updates)
433 response = self.dns_transaction_udp(p)
434 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
436 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
439 name = "textrec.%s" % self.get_dns_domain()
440 q = self.make_name_question(name, dns.DNS_QTYPE_TXT, dns.DNS_QCLASS_IN)
443 self.finish_name_packet(p, questions)
444 response = self.dns_transaction_udp(p)
445 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
446 self.assertEquals(response.ancount, 1)
447 self.assertEquals(response.answers[0].rdata.txt, '"This is a test"')
449 def test_update_add_two_txt_records(self):
450 "test adding two txt records works"
451 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
454 name = self.get_dns_domain()
456 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
458 self.finish_name_packet(p, updates)
462 r.name = "textrec2.%s" % self.get_dns_domain()
463 r.rr_type = dns.DNS_QTYPE_TXT
464 r.rr_class = dns.DNS_QCLASS_IN
467 rdata = dns.txt_record()
468 rdata.txt = '"This is a test" "and this is a test, too"'
471 p.nscount = len(updates)
474 response = self.dns_transaction_udp(p)
475 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
477 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
480 name = "textrec2.%s" % self.get_dns_domain()
481 q = self.make_name_question(name, dns.DNS_QTYPE_TXT, dns.DNS_QCLASS_IN)
484 self.finish_name_packet(p, questions)
485 response = self.dns_transaction_udp(p)
486 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
487 self.assertEquals(response.ancount, 1)
488 self.assertEquals(response.answers[0].rdata.txt, '"This is a test" "and this is a test, too"')
490 def test_delete_record(self):
491 "Test if deleting records works"
493 NAME = "deleterec.%s" % self.get_dns_domain()
495 # First, create a record to make sure we have a record to delete.
496 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
499 name = self.get_dns_domain()
501 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
503 self.finish_name_packet(p, updates)
508 r.rr_type = dns.DNS_QTYPE_TXT
509 r.rr_class = dns.DNS_QCLASS_IN
512 rdata = dns.txt_record()
513 rdata.txt = '"This is a test"'
516 p.nscount = len(updates)
519 response = self.dns_transaction_udp(p)
520 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
522 # Now check the record is around
523 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
525 q = self.make_name_question(NAME, dns.DNS_QTYPE_TXT, dns.DNS_QCLASS_IN)
528 self.finish_name_packet(p, questions)
529 response = self.dns_transaction_udp(p)
530 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
532 # Now delete the record
533 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
536 name = self.get_dns_domain()
538 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
540 self.finish_name_packet(p, updates)
545 r.rr_type = dns.DNS_QTYPE_TXT
546 r.rr_class = dns.DNS_QCLASS_NONE
549 rdata = dns.txt_record()
550 rdata.txt = '"This is a test"'
553 p.nscount = len(updates)
556 response = self.dns_transaction_udp(p)
557 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
559 # And finally check it's gone
560 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
563 q = self.make_name_question(NAME, dns.DNS_QTYPE_TXT, dns.DNS_QCLASS_IN)
566 self.finish_name_packet(p, questions)
567 response = self.dns_transaction_udp(p)
568 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NXDOMAIN)
570 def test_readd_record(self):
571 "Test if adding, deleting and then readding a records works"
573 NAME = "readdrec.%s" % self.get_dns_domain()
576 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
579 name = self.get_dns_domain()
581 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
583 self.finish_name_packet(p, updates)
588 r.rr_type = dns.DNS_QTYPE_TXT
589 r.rr_class = dns.DNS_QCLASS_IN
592 rdata = dns.txt_record()
593 rdata.txt = '"This is a test"'
596 p.nscount = len(updates)
599 response = self.dns_transaction_udp(p)
600 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
602 # Now check the record is around
603 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
605 q = self.make_name_question(NAME, dns.DNS_QTYPE_TXT, dns.DNS_QCLASS_IN)
608 self.finish_name_packet(p, questions)
609 response = self.dns_transaction_udp(p)
610 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
612 # Now delete the record
613 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
616 name = self.get_dns_domain()
618 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
620 self.finish_name_packet(p, updates)
625 r.rr_type = dns.DNS_QTYPE_TXT
626 r.rr_class = dns.DNS_QCLASS_NONE
629 rdata = dns.txt_record()
630 rdata.txt = '"This is a test"'
633 p.nscount = len(updates)
636 response = self.dns_transaction_udp(p)
637 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
640 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
643 q = self.make_name_question(NAME, dns.DNS_QTYPE_TXT, dns.DNS_QCLASS_IN)
646 self.finish_name_packet(p, questions)
647 response = self.dns_transaction_udp(p)
648 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NXDOMAIN)
650 # recreate the record
651 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
654 name = self.get_dns_domain()
656 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
658 self.finish_name_packet(p, updates)
663 r.rr_type = dns.DNS_QTYPE_TXT
664 r.rr_class = dns.DNS_QCLASS_IN
667 rdata = dns.txt_record()
668 rdata.txt = '"This is a test"'
671 p.nscount = len(updates)
674 response = self.dns_transaction_udp(p)
675 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
677 # Now check the record is around
678 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
680 q = self.make_name_question(NAME, dns.DNS_QTYPE_TXT, dns.DNS_QCLASS_IN)
683 self.finish_name_packet(p, questions)
684 response = self.dns_transaction_udp(p)
685 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
687 def test_update_add_mx_record(self):
688 "test adding MX records works"
689 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
692 name = self.get_dns_domain()
694 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
696 self.finish_name_packet(p, updates)
700 r.name = "%s" % self.get_dns_domain()
701 r.rr_type = dns.DNS_QTYPE_MX
702 r.rr_class = dns.DNS_QCLASS_IN
705 rdata = dns.mx_record()
706 rdata.preference = 10
707 rdata.exchange = 'mail.%s' % self.get_dns_domain()
710 p.nscount = len(updates)
713 response = self.dns_transaction_udp(p)
714 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
716 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
719 name = "%s" % self.get_dns_domain()
720 q = self.make_name_question(name, dns.DNS_QTYPE_MX, dns.DNS_QCLASS_IN)
723 self.finish_name_packet(p, questions)
724 response = self.dns_transaction_udp(p)
725 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
726 self.assertEqual(response.ancount, 1)
727 ans = response.answers[0]
728 self.assertEqual(ans.rr_type, dns.DNS_QTYPE_MX)
729 self.assertEqual(ans.rdata.preference, 10)
730 self.assertEqual(ans.rdata.exchange, 'mail.%s' % self.get_dns_domain())
733 class TestComplexQueries(DNSTest):
736 super(TestComplexQueries, self).setUp()
737 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
740 name = self.get_dns_domain()
742 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
744 self.finish_name_packet(p, updates)
748 r.name = "cname_test.%s" % self.get_dns_domain()
749 r.rr_type = dns.DNS_QTYPE_CNAME
750 r.rr_class = dns.DNS_QCLASS_IN
753 r.rdata = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
755 p.nscount = len(updates)
758 response = self.dns_transaction_udp(p)
759 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
762 super(TestComplexQueries, self).tearDown()
763 p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
766 name = self.get_dns_domain()
768 u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
770 self.finish_name_packet(p, updates)
774 r.name = "cname_test.%s" % self.get_dns_domain()
775 r.rr_type = dns.DNS_QTYPE_CNAME
776 r.rr_class = dns.DNS_QCLASS_NONE
779 r.rdata = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
781 p.nscount = len(updates)
784 response = self.dns_transaction_udp(p)
785 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
787 def test_one_a_query(self):
788 "create a query packet containing one query record"
789 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
792 name = "cname_test.%s" % self.get_dns_domain()
793 q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN)
794 print "asking for ", q.name
797 self.finish_name_packet(p, questions)
798 response = self.dns_transaction_udp(p)
799 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
800 self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
801 self.assertEquals(response.ancount, 2)
802 self.assertEquals(response.answers[0].rr_type, dns.DNS_QTYPE_CNAME)
803 self.assertEquals(response.answers[0].rdata, "%s.%s" %
804 (os.getenv('SERVER'), self.get_dns_domain()))
805 self.assertEquals(response.answers[1].rr_type, dns.DNS_QTYPE_A)
806 self.assertEquals(response.answers[1].rdata,
807 os.getenv('SERVER_IP'))
809 class TestInvalidQueries(DNSTest):
811 def test_one_a_query(self):
812 "send 0 bytes follows by create a query packet containing one query record"
816 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
817 s.connect((os.getenv('SERVER_IP'), 53))
823 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
826 name = "%s.%s" % (os.getenv('SERVER'), self.get_dns_domain())
827 q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN)
828 print "asking for ", q.name
831 self.finish_name_packet(p, questions)
832 response = self.dns_transaction_udp(p)
833 self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
834 self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
835 self.assertEquals(response.ancount, 1)
836 self.assertEquals(response.answers[0].rdata,
837 os.getenv('SERVER_IP'))
839 def test_one_a_reply(self):
840 "send a reply instead of a query"
842 p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
845 name = "%s.%s" % ('fakefakefake', self.get_dns_domain())
846 q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN)
847 print "asking for ", q.name
850 self.finish_name_packet(p, questions)
851 p.operation |= dns.DNS_FLAG_REPLY
854 send_packet = ndr.ndr_pack(p)
855 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
856 host=os.getenv('SERVER_IP')
857 s.connect((host, 53))
858 tcp_packet = struct.pack('!H', len(send_packet))
859 tcp_packet += send_packet
860 s.send(tcp_packet, 0)
861 recv_packet = s.recv(0xffff + 2, 0)
862 self.assertEquals(0, len(recv_packet))
868 if __name__ == "__main__":