]> git.ipfire.org Git - thirdparty/pdns.git/blame - regression-tests.dnsdist/test_Protobuf.py
Merge pull request #8795 from omoerbeek/rec-lua-docs-policytag
[thirdparty/pdns.git] / regression-tests.dnsdist / test_Protobuf.py
CommitLineData
1d0bd88a 1#!/usr/bin/env python
1d0bd88a
RG
2import threading
3import socket
4import struct
5import sys
6import time
b4f23783 7from dnsdisttests import DNSDistTest, Queue
1d0bd88a
RG
8
9import dns
10import dnsmessage_pb2
11
f29fabd9 12class DNSDistProtobufTest(DNSDistTest):
1d0bd88a 13 _protobufServerPort = 4242
b4f23783 14 _protobufQueue = Queue()
312a09a6 15 _protobufServerID = 'dnsdist-server-1'
1d0bd88a 16 _protobufCounter = 0
1d0bd88a
RG
17
18 @classmethod
19 def ProtobufListener(cls, port):
20 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
21 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
22 try:
23 sock.bind(("127.0.0.1", port))
24 except socket.error as e:
25 print("Error binding in the protbuf listener: %s" % str(e))
26 sys.exit(1)
27
28 sock.listen(100)
29 while True:
30 (conn, _) = sock.accept()
31 data = None
32 while True:
33 data = conn.recv(2)
34 if not data:
35 break
36 (datalen,) = struct.unpack("!H", data)
37 data = conn.recv(datalen)
38 if not data:
39 break
40
41 cls._protobufQueue.put(data, True, timeout=2.0)
42
43 conn.close()
44 sock.close()
45
46 @classmethod
47 def startResponders(cls):
5df86a8a 48 cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
1d0bd88a
RG
49 cls._UDPResponder.setDaemon(True)
50 cls._UDPResponder.start()
741ebe08 51
5df86a8a 52 cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
1d0bd88a
RG
53 cls._TCPResponder.setDaemon(True)
54 cls._TCPResponder.start()
55
56 cls._protobufListener = threading.Thread(name='Protobuf Listener', target=cls.ProtobufListener, args=[cls._protobufServerPort])
57 cls._protobufListener.setDaemon(True)
58 cls._protobufListener.start()
59
60 def getFirstProtobufMessage(self):
61 self.assertFalse(self._protobufQueue.empty())
62 data = self._protobufQueue.get(False)
63 self.assertTrue(data)
64 msg = dnsmessage_pb2.PBDNSMessage()
65 msg.ParseFromString(data)
66 return msg
67
29cd61cc 68 def checkProtobufBase(self, msg, protocol, query, initiator, normalQueryResponse=True):
1d0bd88a
RG
69 self.assertTrue(msg)
70 self.assertTrue(msg.HasField('timeSec'))
71 self.assertTrue(msg.HasField('socketFamily'))
72 self.assertEquals(msg.socketFamily, dnsmessage_pb2.PBDNSMessage.INET)
73 self.assertTrue(msg.HasField('from'))
74 fromvalue = getattr(msg, 'from')
29cd61cc 75 self.assertEquals(socket.inet_ntop(socket.AF_INET, fromvalue), initiator)
1d0bd88a
RG
76 self.assertTrue(msg.HasField('socketProtocol'))
77 self.assertEquals(msg.socketProtocol, protocol)
78 self.assertTrue(msg.HasField('messageId'))
79 self.assertTrue(msg.HasField('id'))
29cd61cc 80 self.assertEquals(msg.id, query.id)
1d0bd88a 81 self.assertTrue(msg.HasField('inBytes'))
312a09a6 82 self.assertTrue(msg.HasField('serverIdentity'))
06b0e003 83 self.assertEquals(msg.serverIdentity, self._protobufServerID.encode('utf-8'))
312a09a6 84
0096ada6
RG
85 if normalQueryResponse:
86 # compare inBytes with length of query/response
87 self.assertEquals(msg.inBytes, len(query.to_wire()))
1d0bd88a
RG
88 # dnsdist doesn't set the existing EDNS Subnet for now,
89 # although it might be set from Lua
90 # self.assertTrue(msg.HasField('originalRequestorSubnet'))
91 # self.assertEquals(len(msg.originalRequestorSubnet), 4)
92 # self.assertEquals(socket.inet_ntop(socket.AF_INET, msg.originalRequestorSubnet), '127.0.0.1')
93
8667904b 94 def checkProtobufQuery(self, msg, protocol, query, qclass, qtype, qname, initiator='127.0.0.1'):
0096ada6 95 self.assertEquals(msg.type, dnsmessage_pb2.PBDNSMessage.DNSQueryType)
8667904b 96 self.checkProtobufBase(msg, protocol, query, initiator)
1d0bd88a
RG
97 # dnsdist doesn't fill the responder field for responses
98 # because it doesn't keep the information around.
99 self.assertTrue(msg.HasField('to'))
100 self.assertEquals(socket.inet_ntop(socket.AF_INET, msg.to), '127.0.0.1')
101 self.assertTrue(msg.HasField('question'))
102 self.assertTrue(msg.question.HasField('qClass'))
103 self.assertEquals(msg.question.qClass, qclass)
104 self.assertTrue(msg.question.HasField('qType'))
105 self.assertEquals(msg.question.qClass, qtype)
106 self.assertTrue(msg.question.HasField('qName'))
107 self.assertEquals(msg.question.qName, qname)
108
0096ada6
RG
109 def checkProtobufTags(self, tags, expectedTags):
110 # only differences will be in new list
111 listx = set(tags) ^ set(expectedTags)
112 # exclusive or of lists should be empty
113 self.assertEqual(len(listx), 0, "Protobuf tags don't match")
741ebe08 114
29cd61cc
SO
115 def checkProtobufQueryConvertedToResponse(self, msg, protocol, response, initiator='127.0.0.0'):
116 self.assertEquals(msg.type, dnsmessage_pb2.PBDNSMessage.DNSResponseType)
0096ada6
RG
117 # skip comparing inBytes (size of the query) with the length of the generated response
118 self.checkProtobufBase(msg, protocol, response, initiator, False)
29cd61cc
SO
119 self.assertTrue(msg.HasField('response'))
120 self.assertTrue(msg.response.HasField('queryTimeSec'))
121
8667904b 122 def checkProtobufResponse(self, msg, protocol, response, initiator='127.0.0.1'):
29cd61cc 123 self.assertEquals(msg.type, dnsmessage_pb2.PBDNSMessage.DNSResponseType)
8667904b 124 self.checkProtobufBase(msg, protocol, response, initiator)
29cd61cc
SO
125 self.assertTrue(msg.HasField('response'))
126 self.assertTrue(msg.response.HasField('queryTimeSec'))
741ebe08 127
8667904b
RG
128 def checkProtobufResponseRecord(self, record, rclass, rtype, rname, rttl):
129 self.assertTrue(record.HasField('class'))
130 self.assertEquals(getattr(record, 'class'), rclass)
131 self.assertTrue(record.HasField('type'))
132 self.assertEquals(record.type, rtype)
133 self.assertTrue(record.HasField('name'))
134 self.assertEquals(record.name, rname)
135 self.assertTrue(record.HasField('ttl'))
136 self.assertEquals(record.ttl, rttl)
137 self.assertTrue(record.HasField('rdata'))
138
f29fabd9
RG
139class TestProtobuf(DNSDistProtobufTest):
140 _config_params = ['_testServerPort', '_protobufServerPort', '_protobufServerID', '_protobufServerID']
141 _config_template = """
142 luasmn = newSuffixMatchNode()
143 luasmn:add(newDNSName('lua.protobuf.tests.powerdns.com.'))
144
145 function alterProtobufResponse(dq, protobuf)
146 if luasmn:check(dq.qname) then
147 requestor = newCA(dq.remoteaddr:toString()) -- called by testLuaProtobuf()
148 if requestor:isIPv4() then
149 requestor:truncate(24)
150 else
151 requestor:truncate(56)
152 end
153 protobuf:setRequestor(requestor)
154
155 local tableTags = {}
156 table.insert(tableTags, "TestLabel1,TestData1")
157 table.insert(tableTags, "TestLabel2,TestData2")
158
159 protobuf:setTagArray(tableTags)
160
161 protobuf:setTag('TestLabel3,TestData3')
162
163 protobuf:setTag("Response,456")
164
165 else
166
167 local tableTags = {} -- called by testProtobuf()
168 table.insert(tableTags, "TestLabel1,TestData1")
169 table.insert(tableTags, "TestLabel2,TestData2")
170 protobuf:setTagArray(tableTags)
171
172 protobuf:setTag('TestLabel3,TestData3')
173
174 protobuf:setTag("Response,456")
175
176 end
177 end
178
179 function alterProtobufQuery(dq, protobuf)
180
181 if luasmn:check(dq.qname) then
182 requestor = newCA(dq.remoteaddr:toString()) -- called by testLuaProtobuf()
183 if requestor:isIPv4() then
184 requestor:truncate(24)
185 else
186 requestor:truncate(56)
187 end
188 protobuf:setRequestor(requestor)
189
190 local tableTags = {}
191 tableTags = dq:getTagArray() -- get table from DNSQuery
192
193 local tablePB = {}
194 for k, v in pairs( tableTags) do
195 table.insert(tablePB, k .. "," .. v)
196 end
197
198 protobuf:setTagArray(tablePB) -- store table in protobuf
199 protobuf:setTag("Query,123") -- add another tag entry in protobuf
200
d3ec24f9 201 protobuf:setResponseCode(DNSRCode.NXDOMAIN) -- set protobuf response code to be NXDOMAIN
f29fabd9
RG
202
203 local strReqName = dq.qname:toString() -- get request dns name
204
205 protobuf:setProtobufResponseType() -- set protobuf to look like a response and not a query, with 0 default time
206
207 blobData = '\127' .. '\000' .. '\000' .. '\001' -- 127.0.0.1, note: lua 5.1 can only embed decimal not hex
208
209 protobuf:addResponseRR(strReqName, 1, 1, 123, blobData) -- add a RR to the protobuf
210
211 protobuf:setBytes(65) -- set the size of the query to confirm in checkProtobufBase
212
213 else
214
215 local tableTags = {} -- called by testProtobuf()
216 table.insert(tableTags, "TestLabel1,TestData1")
217 table.insert(tableTags, "TestLabel2,TestData2")
218
219 protobuf:setTagArray(tableTags)
220 protobuf:setTag('TestLabel3,TestData3')
221 protobuf:setTag("Query,123")
222
223 end
224 end
225
226 function alterLuaFirst(dq) -- called when dnsdist receives new request
227 local tt = {}
228 tt["TestLabel1"] = "TestData1"
229 tt["TestLabel2"] = "TestData2"
230
231 dq:setTagArray(tt)
232
233 dq:setTag("TestLabel3","TestData3")
234 return DNSAction.None, "" -- continue to the next rule
235 end
236
237 newServer{address="127.0.0.1:%s", useClientSubnet=true}
238 rl = newRemoteLogger('127.0.0.1:%s')
239
240 addAction(AllRule(), LuaAction(alterLuaFirst)) -- Add tags to DNSQuery first
241
242 addAction(AllRule(), RemoteLogAction(rl, alterProtobufQuery, {serverID='%s'})) -- Send protobuf message before lookup
243
244 addResponseAction(AllRule(), RemoteLogResponseAction(rl, alterProtobufResponse, true, {serverID='%s'})) -- Send protobuf message after lookup
245
246 """
247
1d0bd88a
RG
248 def testProtobuf(self):
249 """
250 Protobuf: Send data to a protobuf server
251 """
29cd61cc 252 name = 'query.protobuf.tests.powerdns.com.'
741ebe08 253
165c9030 254 target = 'target.protobuf.tests.powerdns.com.'
1d0bd88a
RG
255 query = dns.message.make_query(name, 'A', 'IN')
256 response = dns.message.make_response(query)
741ebe08 257
1d0bd88a 258 rrset = dns.rrset.from_text(name,
165c9030
RG
259 3600,
260 dns.rdataclass.IN,
261 dns.rdatatype.CNAME,
262 target)
263 response.answer.append(rrset)
741ebe08 264
165c9030 265 rrset = dns.rrset.from_text(target,
1d0bd88a
RG
266 3600,
267 dns.rdataclass.IN,
268 dns.rdatatype.A,
269 '127.0.0.1')
270 response.answer.append(rrset)
271
272 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
273 self.assertTrue(receivedQuery)
274 self.assertTrue(receivedResponse)
275 receivedQuery.id = query.id
276 self.assertEquals(query, receivedQuery)
277 self.assertEquals(response, receivedResponse)
278
279 # let the protobuf messages the time to get there
280 time.sleep(1)
281
282 # check the protobuf message corresponding to the UDP query
283 msg = self.getFirstProtobufMessage()
741ebe08 284
29cd61cc 285 self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
0096ada6 286 self.checkProtobufTags(msg.response.tags, [u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Query,123"])
1d0bd88a
RG
287
288 # check the protobuf message corresponding to the UDP response
289 msg = self.getFirstProtobufMessage()
0096ada6
RG
290 self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response)
291 self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Response,456"])
29cd61cc 292 self.assertEquals(len(msg.response.rrs), 2)
165c9030
RG
293 rr = msg.response.rrs[0]
294 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 3600)
06b0e003 295 self.assertEquals(rr.rdata.decode('utf-8'), target)
165c9030
RG
296 rr = msg.response.rrs[1]
297 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, target, 3600)
298 self.assertEquals(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
1d0bd88a
RG
299
300 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
301 self.assertTrue(receivedQuery)
302 self.assertTrue(receivedResponse)
303 receivedQuery.id = query.id
304 self.assertEquals(query, receivedQuery)
305 self.assertEquals(response, receivedResponse)
306
307 # let the protobuf messages the time to get there
308 time.sleep(1)
309
310 # check the protobuf message corresponding to the TCP query
311 msg = self.getFirstProtobufMessage()
29cd61cc 312
1d0bd88a 313 self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.TCP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
0096ada6 314 self.checkProtobufTags(msg.response.tags, [u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Query,123"])
1d0bd88a
RG
315
316 # check the protobuf message corresponding to the TCP response
317 msg = self.getFirstProtobufMessage()
0096ada6
RG
318 self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response)
319 self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Response,456"])
165c9030
RG
320 self.assertEquals(len(msg.response.rrs), 2)
321 rr = msg.response.rrs[0]
322 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 3600)
06b0e003 323 self.assertEquals(rr.rdata.decode('utf-8'), target)
165c9030
RG
324 rr = msg.response.rrs[1]
325 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, target, 3600)
326 self.assertEquals(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
8667904b
RG
327
328 def testLuaProtobuf(self):
741ebe08 329
8667904b
RG
330 """
331 Protobuf: Check that the Lua callback rewrote the initiator
332 """
333 name = 'lua.protobuf.tests.powerdns.com.'
334 query = dns.message.make_query(name, 'A', 'IN')
335 response = dns.message.make_response(query)
336 rrset = dns.rrset.from_text(name,
337 3600,
338 dns.rdataclass.IN,
339 dns.rdatatype.A,
340 '127.0.0.1')
341 response.answer.append(rrset)
342
741ebe08 343
8667904b 344 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
741ebe08 345
29cd61cc
SO
346 self.assertTrue(receivedQuery)
347 self.assertTrue(receivedResponse)
8667904b
RG
348 receivedQuery.id = query.id
349 self.assertEquals(query, receivedQuery)
350 self.assertEquals(response, receivedResponse)
351
741ebe08 352
8667904b
RG
353 # let the protobuf messages the time to get there
354 time.sleep(1)
355
356 # check the protobuf message corresponding to the UDP query
357 msg = self.getFirstProtobufMessage()
29cd61cc 358
0096ada6
RG
359 self.checkProtobufQueryConvertedToResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response, '127.0.0.0')
360 self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Query,123"])
8667904b
RG
361
362 # check the protobuf message corresponding to the UDP response
363 msg = self.getFirstProtobufMessage()
0096ada6
RG
364 self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response, '127.0.0.0')
365 self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Response,456"])
8667904b
RG
366 self.assertEquals(len(msg.response.rrs), 1)
367 for rr in msg.response.rrs:
368 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 3600)
369 self.assertEquals(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
370
371 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
372 self.assertTrue(receivedQuery)
373 self.assertTrue(receivedResponse)
374 receivedQuery.id = query.id
375 self.assertEquals(query, receivedQuery)
376 self.assertEquals(response, receivedResponse)
377
378 # let the protobuf messages the time to get there
379 time.sleep(1)
380
381 # check the protobuf message corresponding to the TCP query
382 msg = self.getFirstProtobufMessage()
0096ada6
RG
383 self.checkProtobufQueryConvertedToResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response, '127.0.0.0')
384 self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Query,123"])
8667904b
RG
385
386 # check the protobuf message corresponding to the TCP response
387 msg = self.getFirstProtobufMessage()
0096ada6
RG
388 self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response, '127.0.0.0')
389 self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Response,456"])
8667904b
RG
390 self.assertEquals(len(msg.response.rrs), 1)
391 for rr in msg.response.rrs:
392 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 3600)
1d0bd88a 393 self.assertEquals(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
f29fabd9
RG
394
395class TestProtobufIPCipher(DNSDistProtobufTest):
396 _config_params = ['_testServerPort', '_protobufServerPort', '_protobufServerID', '_protobufServerID']
397 _config_template = """
398 newServer{address="127.0.0.1:%s", useClientSubnet=true}
399 key = makeIPCipherKey("some 16-byte key")
400 rl = newRemoteLogger('127.0.0.1:%s')
401 addAction(AllRule(), RemoteLogAction(rl, nil, {serverID='%s', ipEncryptKey=key})) -- Send protobuf message before lookup
402 addResponseAction(AllRule(), RemoteLogResponseAction(rl, nil, true, {serverID='%s', ipEncryptKey=key})) -- Send protobuf message after lookup
403
404 """
405
406 def testProtobuf(self):
407 """
408 Protobuf: Send data to a protobuf server
409 """
410 name = 'query.protobuf-ipcipher.tests.powerdns.com.'
411
78603024 412 target = 'target.protobuf-ipcipher.tests.powerdns.com.'
f29fabd9
RG
413 query = dns.message.make_query(name, 'A', 'IN')
414 response = dns.message.make_response(query)
415
416 rrset = dns.rrset.from_text(name,
417 3600,
418 dns.rdataclass.IN,
419 dns.rdatatype.CNAME,
420 target)
421 response.answer.append(rrset)
422
423 rrset = dns.rrset.from_text(target,
424 3600,
425 dns.rdataclass.IN,
426 dns.rdatatype.A,
427 '127.0.0.1')
428 response.answer.append(rrset)
429
430 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
431 self.assertTrue(receivedQuery)
432 self.assertTrue(receivedResponse)
433 receivedQuery.id = query.id
434 self.assertEquals(query, receivedQuery)
435 self.assertEquals(response, receivedResponse)
436
437 # let the protobuf messages the time to get there
438 time.sleep(1)
439
440 # check the protobuf message corresponding to the UDP query
441 msg = self.getFirstProtobufMessage()
442
443 # 108.41.239.98 is 127.0.0.1 pseudonymized with ipcipher and the current key
444 self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, '108.41.239.98')
445
446 # check the protobuf message corresponding to the UDP response
447 msg = self.getFirstProtobufMessage()
448 self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response, '108.41.239.98')
449
450 self.assertEquals(len(msg.response.rrs), 2)
451 rr = msg.response.rrs[0]
452 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 3600)
78603024 453 self.assertEquals(rr.rdata.decode('ascii'), target)
f29fabd9
RG
454 rr = msg.response.rrs[1]
455 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, target, 3600)
456 self.assertEquals(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
457
458 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
459 self.assertTrue(receivedQuery)
460 self.assertTrue(receivedResponse)
461 receivedQuery.id = query.id
462 self.assertEquals(query, receivedQuery)
463 self.assertEquals(response, receivedResponse)
464
465 # let the protobuf messages the time to get there
466 time.sleep(1)
467
468 # check the protobuf message corresponding to the TCP query
469 msg = self.getFirstProtobufMessage()
470 # 108.41.239.98 is 127.0.0.1 pseudonymized with ipcipher and the current key
471 self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.TCP, query, dns.rdataclass.IN, dns.rdatatype.A, name, '108.41.239.98')
472
473 # check the protobuf message corresponding to the TCP response
474 msg = self.getFirstProtobufMessage()
475 self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response, '108.41.239.98')
476 self.assertEquals(len(msg.response.rrs), 2)
477 rr = msg.response.rrs[0]
478 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 3600)
78603024 479 self.assertEquals(rr.rdata.decode('ascii'), target)
f29fabd9
RG
480 rr = msg.response.rrs[1]
481 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, target, 3600)
482 self.assertEquals(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')