1 #include "CNameRecordTests.h"
2 #include "unittest_common.h"
4 mDNSlocal
int InitThisUnitTest(void);
5 mDNSlocal
int StartClientQueryRequest(void);
6 mDNSlocal
int PopulateCacheWithClientResponseRecords(void);
7 mDNSlocal
int SimulateNetworkChangeAndVerifyTest(void);
8 mDNSlocal
int FinalizeUnitTest(void);
9 mDNSlocal mStatus
AddDNSServer(void);
11 // This unit test's variables
12 static UDPSocket
* local_socket
;
13 static request_state
* client_request_message
;
15 struct UDPSocket_struct
17 mDNSIPPort port
; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
19 typedef struct UDPSocket_struct UDPSocket
;
21 // This client request was generated using the following command: "dns-sd -Q 123server.dotbennu.com. A".
22 uint8_t query_client_msgbuf
[35] = {
23 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65,
24 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,
28 // This uDNS message is a canned response that was originally captured by wireshark.
29 uint8_t query_response_msgbuf
[108] = {
30 0x69, 0x41, // transaction id
32 0x00, 0x01, // 1 question for 123server.dotbennu.com. Addr
33 0x00, 0x02, // 2 anwsers: 123server.dotbennu.com. CNAME test212.dotbennu.com., test212.dotbennu.com. Addr 10.100.0.1,
34 0x00, 0x01, // 1 authorities anwser: dotbennu.com. NS cardinal2.apple.com.
35 0x00, 0x00, 0x09, 0x31, 0x32, 0x33,
36 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x08, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x03,
37 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
38 0x02, 0x56, 0x00, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x32, 0x31, 0x32, 0xc0, 0x16, 0xc0, 0x34,
39 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x04, 0x0a, 0x64, 0x00, 0x01, 0xc0, 0x16,
40 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x12, 0x09, 0x63, 0x61, 0x72, 0x64, 0x69,
41 0x6e, 0x61, 0x6c, 0x32, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x65, 0xc0, 0x1f
44 // Variables associated with contents of the above uDNS message
45 #define uDNS_TargetQID 16745
46 char udns_original_domainname_cstr
[] = "123server.dotbennu.com.";
47 char udns_cname_domainname_cstr
[] = "test212.dotbennu.com.";
48 static const mDNSv4Addr dns_response_ipv4
= {{ 10, 100, 0, 1 }};
50 UNITTEST_HEADER(CNameRecordTests
)
51 UNITTEST_TEST(InitThisUnitTest
)
52 UNITTEST_TEST(StartClientQueryRequest
)
53 UNITTEST_TEST(PopulateCacheWithClientResponseRecords
)
54 UNITTEST_TEST(SimulateNetworkChangeAndVerifyTest
)
55 UNITTEST_TEST(FinalizeUnitTest
)
58 // The InitThisUnitTest() initializes the mDNSResponder environment as well as
59 // a DNSServer. It also allocates memory for a local_socket and client request.
60 // Note: This unit test does not send packets on the wire and it does not open sockets.
61 UNITTEST_HEADER(InitThisUnitTest
)
62 // Init unit test environment and verify no error occurred.
63 mStatus result
= init_mdns_environment(mDNStrue
);
64 UNITTEST_ASSERT(result
== mStatus_NoError
);
66 // Add one DNS server and verify it was added.
68 UNITTEST_ASSERT(NumUnicastDNSServers
== 1);
70 // Create memory for a socket that is never used or opened.
71 local_socket
= mDNSPlatformMemAllocate(sizeof(UDPSocket
));
72 mDNSPlatformMemZero(local_socket
, sizeof(UDPSocket
));
74 // Create memory for a request that is used to make this unit test's client request.
75 client_request_message
= calloc(1, sizeof(request_state
));
78 // This test simulates a uds client request by setting up a client request and then
79 // calling mDNSResponder's handle_client_request. The handle_client_request function
80 // processes the request and starts a query. This unit test verifies
81 // the client request and query were setup as expected. This unit test also calls
82 // mDNS_execute which determines the cache does not contain the new question's
84 UNITTEST_HEADER(StartClientQueryRequest
)
85 mDNS
*const m
= &mDNSStorage
;
86 request_state
* req
= client_request_message
;
87 char *msgptr
= (char *)query_client_msgbuf
;
88 size_t msgsz
= sizeof(query_client_msgbuf
);
89 mDNSs32 min_size
= sizeof(DNSServiceFlags
) + sizeof(mDNSu32
) + 4;
91 mStatus err
= mStatus_NoError
;
92 char qname_cstr
[MAX_ESCAPED_DOMAIN_NAME
];
94 // Process the unit test's client request
95 start_client_request(req
, msgptr
, msgsz
, query_request
, local_socket
);
96 UNITTEST_ASSERT(err
== mStatus_NoError
);
98 // Verify the request fields were set as expected
99 UNITTEST_ASSERT(req
->next
== mDNSNULL
);
100 UNITTEST_ASSERT(req
->primary
== mDNSNULL
);
101 UNITTEST_ASSERT(req
->sd
== client_req_sd
);
102 UNITTEST_ASSERT(req
->process_id
== client_req_process_id
);
103 UNITTEST_ASSERT(!strcmp(req
->pid_name
, client_req_pid_name
));
104 UNITTEST_ASSERT(req
->validUUID
== mDNSfalse
);
105 UNITTEST_ASSERT(req
->errsd
== 0);
106 UNITTEST_ASSERT(req
->uid
== client_req_uid
);
107 UNITTEST_ASSERT(req
->ts
== t_complete
);
108 UNITTEST_ASSERT((mDNSs32
)req
->data_bytes
> min_size
);
109 UNITTEST_ASSERT(req
->msgend
== msgptr
+msgsz
);
110 UNITTEST_ASSERT(req
->msgbuf
== mDNSNULL
);
111 UNITTEST_ASSERT(req
->hdr
.version
== VERSION
);
112 UNITTEST_ASSERT(req
->replies
== mDNSNULL
);
113 UNITTEST_ASSERT(req
->terminate
!= mDNSNULL
);
114 UNITTEST_ASSERT(req
->flags
== kDNSServiceFlagsReturnIntermediates
);
115 UNITTEST_ASSERT(req
->interfaceIndex
== kDNSServiceInterfaceIndexAny
);
117 // Verify the query fields were set as expected
118 q
= &req
->u
.queryrecord
.q
;
119 UNITTEST_ASSERT(q
!= mDNSNULL
);
120 UNITTEST_ASSERT(q
== m
->Questions
);
121 UNITTEST_ASSERT(q
== m
->NewQuestions
);
122 UNITTEST_ASSERT(q
->SuppressUnusable
== mDNSfalse
);
123 UNITTEST_ASSERT(q
->ReturnIntermed
== mDNStrue
);
124 UNITTEST_ASSERT(q
->SuppressQuery
== mDNSfalse
);
126 UNITTEST_ASSERT(q
->qnameOrig
== mDNSNULL
);
127 ConvertDomainNameToCString(&q
->qname
, qname_cstr
);
128 UNITTEST_ASSERT(!strcmp(qname_cstr
, udns_original_domainname_cstr
));
129 UNITTEST_ASSERT(q
->qnamehash
== DomainNameHashValue(&q
->qname
));
131 UNITTEST_ASSERT(q
->InterfaceID
== mDNSInterface_Any
);
132 UNITTEST_ASSERT(q
->flags
== req
->flags
);
133 UNITTEST_ASSERT(q
->qtype
== 1);
134 UNITTEST_ASSERT(q
->qclass
== 1);
135 UNITTEST_ASSERT(q
->LongLived
== 0);
136 UNITTEST_ASSERT(q
->ExpectUnique
== mDNSfalse
);
137 UNITTEST_ASSERT(q
->ForceMCast
== 0);
138 UNITTEST_ASSERT(q
->TimeoutQuestion
== 0);
139 UNITTEST_ASSERT(q
->WakeOnResolve
== 0);
140 UNITTEST_ASSERT(q
->UseBackgroundTrafficClass
== 0);
141 UNITTEST_ASSERT(q
->ValidationRequired
== 0);
142 UNITTEST_ASSERT(q
->ValidatingResponse
== 0);
143 UNITTEST_ASSERT(q
->ProxyQuestion
== 0);
144 UNITTEST_ASSERT(q
->AnonInfo
== mDNSNULL
);
145 UNITTEST_ASSERT(q
->QuestionCallback
!= mDNSNULL
);
146 UNITTEST_ASSERT(q
->QuestionContext
== req
);
147 UNITTEST_ASSERT(q
->SearchListIndex
== 0);
148 UNITTEST_ASSERT(q
->DNSSECAuthInfo
== mDNSNULL
);
149 UNITTEST_ASSERT(q
->DAIFreeCallback
== mDNSNULL
);
150 UNITTEST_ASSERT(q
->RetryWithSearchDomains
== 0);
151 UNITTEST_ASSERT(q
->AppendSearchDomains
== 0);
152 UNITTEST_ASSERT(q
->AppendLocalSearchDomains
== 0);
153 UNITTEST_ASSERT(q
->DuplicateOf
== mDNSNULL
);
155 // Call mDNS_Execute to see if the new question, q, has an answer in the cache.
156 // It won't be yet because the cache is empty.
157 m
->NextScheduledEvent
= mDNS_TimeNow_NoLock(m
);
160 // Verify mDNS_Execute processed the new question.
161 UNITTEST_ASSERT(m
->NewQuestions
== mDNSNULL
);
163 // Verify the cache is empty and the request got no reply.
164 UNITTEST_ASSERT(m
->rrcache_totalused
== 0);
165 UNITTEST_ASSERT(req
->replies
== mDNSNULL
);
169 // This unit test receives a canned uDNS response message by calling the mDNSCoreReceive() function.
170 // It then verifies cache entries were added for the CNAME and A records that were contained in the
171 // answers of the canned response, query_response_msgbuf. This unit test also verifies that
172 // 2 add events were generated for the client.
173 UNITTEST_HEADER(PopulateCacheWithClientResponseRecords
)
174 mDNS
*const m
= &mDNSStorage
;
175 DNSMessage
*msgptr
= (DNSMessage
*)query_response_msgbuf
;
176 size_t msgsz
= sizeof(query_response_msgbuf
);
177 struct reply_state
*reply
;
178 request_state
* req
= client_request_message
;
179 DNSQuestion
*q
= &req
->u
.queryrecord
.q
;
182 char name
[kDNSServiceMaxDomainName
];
183 uint16_t rrtype
, rrclass
, rdlen
;
186 char domainname_cstr
[MAX_ESCAPED_DOMAIN_NAME
];
188 // Receive and populate the cache with canned response
189 receive_response(req
, msgptr
, msgsz
);
191 // Verify 2 cache entries for CName and A record are present
192 mDNSu32 CacheUsed
=0, notUsed
=0;
193 LogCacheRecords_ut(mDNS_TimeNow(m
), &CacheUsed
, ¬Used
);
194 UNITTEST_ASSERT(CacheUsed
== m
->rrcache_totalused
);
195 UNITTEST_ASSERT(CacheUsed
== 4); // 2 for the CacheGroup object plus 2 for the A and CNAME records
196 UNITTEST_ASSERT(m
->PktNum
== 1); // one packet was received
198 // Verify question's qname is now set with the A record's domainname
199 UNITTEST_ASSERT(q
->qnameOrig
== mDNSNULL
);
200 ConvertDomainNameToCString(&q
->qname
, domainname_cstr
);
201 UNITTEST_ASSERT(q
->qnamehash
== DomainNameHashValue(&q
->qname
));
202 UNITTEST_ASSERT(!strcmp(domainname_cstr
, udns_cname_domainname_cstr
));
204 // Verify client's add event for CNAME is properly formed
205 reply
= req
->replies
;
206 UNITTEST_ASSERT(reply
!= mDNSNULL
);
207 UNITTEST_ASSERT(reply
->next
== mDNSNULL
);
209 data
= (char *)&reply
->rhdr
[1];
210 end
= data
+reply
->totallen
;
211 get_string(&data
, data
+reply
->totallen
, name
, kDNSServiceMaxDomainName
);
212 rrtype
= get_uint16(&data
, end
);
213 rrclass
= get_uint16(&data
, end
);
214 rdlen
= get_uint16(&data
, end
);
215 rdata
= get_rdata(&data
, end
, rdlen
);
216 len
= get_reply_len(name
, rdlen
);
218 UNITTEST_ASSERT(reply
->totallen
== len
+ sizeof(ipc_msg_hdr
));
219 UNITTEST_ASSERT(reply
->mhdr
->version
== VERSION
);
220 UNITTEST_ASSERT(reply
->mhdr
->datalen
== len
);
221 UNITTEST_ASSERT(reply
->mhdr
->ipc_flags
== 0);
222 UNITTEST_ASSERT(reply
->mhdr
->op
== query_reply_op
);
224 UNITTEST_ASSERT(reply
->rhdr
->flags
== htonl(kDNSServiceFlagsAdd
));
225 UNITTEST_ASSERT(reply
->rhdr
->ifi
== kDNSServiceInterfaceIndexAny
);
226 UNITTEST_ASSERT(reply
->rhdr
->error
== kDNSServiceErr_NoError
);
228 UNITTEST_ASSERT(rrtype
== kDNSType_CNAME
);
229 UNITTEST_ASSERT(rrclass
== kDNSClass_IN
);
230 ConvertDomainNameToCString((const domainname
*const)rdata
, domainname_cstr
);
231 UNITTEST_ASSERT(!strcmp(domainname_cstr
, "test212.dotbennu.com."));
233 // The mDNS_Execute call generates an add event for the A record
234 m
->NextScheduledEvent
= mDNS_TimeNow_NoLock(m
);
237 // Verify the client's reply contains a properly formed add event for the A record.
238 reply
= req
->replies
;
239 UNITTEST_ASSERT(reply
!= mDNSNULL
);
240 UNITTEST_ASSERT(reply
->next
!= mDNSNULL
);
243 data
= (char *)&reply
->rhdr
[1];
244 end
= data
+reply
->totallen
;
245 get_string(&data
, data
+reply
->totallen
, name
, kDNSServiceMaxDomainName
);
246 rrtype
= get_uint16(&data
, end
);
247 rrclass
= get_uint16(&data
, end
);
248 rdlen
= get_uint16(&data
, end
);
249 rdata
= get_rdata(&data
, end
, rdlen
);
250 len
= get_reply_len(name
, rdlen
);
252 UNITTEST_ASSERT(reply
->totallen
== len
+ sizeof(ipc_msg_hdr
));
253 UNITTEST_ASSERT(reply
->mhdr
->version
== VERSION
);
254 UNITTEST_ASSERT(reply
->mhdr
->datalen
== len
);
256 UNITTEST_ASSERT(reply
->mhdr
->ipc_flags
== 0);
257 UNITTEST_ASSERT(reply
->mhdr
->op
== query_reply_op
);
259 UNITTEST_ASSERT(reply
->rhdr
->flags
== htonl(kDNSServiceFlagsAdd
));
260 UNITTEST_ASSERT(reply
->rhdr
->ifi
== kDNSServiceInterfaceIndexAny
);
261 UNITTEST_ASSERT(reply
->rhdr
->error
== kDNSServiceErr_NoError
);
263 UNITTEST_ASSERT(rrtype
== kDNSType_A
);
264 UNITTEST_ASSERT(rrclass
== kDNSClass_IN
);
265 UNITTEST_ASSERT(rdata
[0] == dns_response_ipv4
.b
[0]);
266 UNITTEST_ASSERT(rdata
[1] == dns_response_ipv4
.b
[1]);
267 UNITTEST_ASSERT(rdata
[2] == dns_response_ipv4
.b
[2]);
268 UNITTEST_ASSERT(rdata
[3] == dns_response_ipv4
.b
[3]);
272 // This function verifies the cache and event handling occurred as expected when a network change happened.
273 // The uDNS_SetupDNSConfig is called to simulate a network change and two outcomes occur. First the A record
274 // query is restarted and sent to a new DNS server. Second the cache records are purged. Then mDNS_Execute
275 // is called and it removes the purged cache records and generates a remove event for the A record.
276 // The following are verified:
277 // 1.) The restart of query for A record.
278 // 2.) The cache is empty after mDNS_Execute removes the cache entres.
279 // 3.) The remove event is verified by examining the request's reply data.
280 UNITTEST_HEADER(SimulateNetworkChangeAndVerifyTest
)
281 mDNS
*const m
= &mDNSStorage
;
282 request_state
* req
= client_request_message
;
283 DNSQuestion
* q
= &req
->u
.queryrecord
.q
;
284 mDNSu32 CacheUsed
=0, notUsed
=0;
285 const char *data
; const char *end
;
286 char name
[kDNSServiceMaxDomainName
];
287 uint16_t rrtype
, rrclass
, rdlen
;
291 // The uDNS_SetupDNSConfig reconfigures the resolvers so the A record query is restarted and
292 // both the CNAME and A record are purged.
293 uDNS_SetupDNSConfig(m
);
295 // Verify the A record query was restarted. This is done indirectly by noticing the transaction id and interval have changed.
296 UNITTEST_ASSERT(q
->ThisQInterval
== InitialQuestionInterval
);
297 UNITTEST_ASSERT(q
->TargetQID
.NotAnInteger
!= uDNS_TargetQID
);
299 // Then mDNS_Execute removes both records from the cache and calls the client back with a remove event for A record.
300 m
->NextScheduledEvent
= mDNS_TimeNow_NoLock(m
);
303 // Verify the cache entries are removed
304 LogCacheRecords_ut(mDNS_TimeNow(m
), &CacheUsed
, ¬Used
);
305 UNITTEST_ASSERT(CacheUsed
== m
->rrcache_totalused
);
306 UNITTEST_ASSERT(CacheUsed
== 0);
308 // Verify the A record's remove event is setup as expected in the reply data
309 struct reply_state
*reply
;
310 reply
= req
->replies
;
311 UNITTEST_ASSERT(reply
!= mDNSNULL
);
313 UNITTEST_ASSERT(reply
!= mDNSNULL
);
314 UNITTEST_ASSERT(reply
->next
!= mDNSNULL
);
315 UNITTEST_ASSERT(reply
->next
->next
!= mDNSNULL
);
317 reply
= reply
->next
->next
; // Get to last event to verify remove event
318 data
= (char *)&reply
->rhdr
[1];
319 end
= data
+reply
->totallen
;
320 get_string(&data
, data
+reply
->totallen
, name
, kDNSServiceMaxDomainName
);
321 rrtype
= get_uint16(&data
, end
);
322 rrclass
= get_uint16(&data
, end
);
323 rdlen
= get_uint16(&data
, end
);
324 rdata
= get_rdata(&data
, end
, rdlen
);
325 len
= get_reply_len(name
, rdlen
);
327 UNITTEST_ASSERT(reply
->totallen
== reply
->mhdr
->datalen
+ sizeof(ipc_msg_hdr
));
328 UNITTEST_ASSERT(reply
->mhdr
->version
== VERSION
);
329 UNITTEST_ASSERT(reply
->mhdr
->datalen
== len
);
330 UNITTEST_ASSERT(reply
->mhdr
->ipc_flags
== 0);
331 UNITTEST_ASSERT(reply
->mhdr
->op
== query_reply_op
);
333 UNITTEST_ASSERT(reply
->rhdr
->flags
!= htonl(kDNSServiceFlagsAdd
));
334 UNITTEST_ASSERT(reply
->rhdr
->ifi
== kDNSServiceInterfaceIndexAny
);
335 UNITTEST_ASSERT(reply
->rhdr
->error
== kDNSServiceErr_NoError
);
337 UNITTEST_ASSERT(rrtype
== kDNSType_A
);
338 UNITTEST_ASSERT(rrclass
== kDNSClass_IN
);
339 UNITTEST_ASSERT(rdata
[0] == dns_response_ipv4
.b
[0]);
340 UNITTEST_ASSERT(rdata
[1] == dns_response_ipv4
.b
[1]);
341 UNITTEST_ASSERT(rdata
[2] == dns_response_ipv4
.b
[2]);
342 UNITTEST_ASSERT(rdata
[3] == dns_response_ipv4
.b
[3]);
346 // This function does memory cleanup and no verification.
347 UNITTEST_HEADER(FinalizeUnitTest
)
348 mDNS
*m
= &mDNSStorage
;
349 request_state
* req
= client_request_message
;
350 DNSServer
*ptr
, **p
= &m
->DNSServers
;
354 reply_state
*reply
= req
->replies
;
355 req
->replies
= req
->replies
->next
;
356 mDNSPlatformMemFree(reply
);
358 mDNSPlatformMemFree(req
);
360 mDNSPlatformMemFree(local_socket
);
366 LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr
, &ptr
->addr
, mDNSVal16(ptr
->port
), ptr
->domain
.c
);
367 mDNSPlatformMemFree(ptr
);
371 // The mDNS_AddDNSServer function adds a dns server to mDNSResponder's list.
372 mDNSlocal mStatus
AddDNSServer(void)
374 mDNS
*m
= &mDNSStorage
;
380 mDNSs32 serviceID
= 0;
382 mDNSu32 timeout
= dns_server_timeout
;
383 mDNSBool cellIntf
= 0;
384 mDNSBool isExpensive
= 0;
385 mDNSBool isCLAT46
= mDNSfalse
;
386 mDNSu16 resGroupID
= dns_server_resGroupID
;
387 mDNSBool reqA
= mDNStrue
;
388 mDNSBool reqAAAA
= mDNStrue
;
389 mDNSBool reqDO
= mDNSfalse
;
391 addr
.type
= mDNSAddrType_IPv4
;
392 addr
.ip
.v4
.NotAnInteger
= dns_server_ipv4
.NotAnInteger
;
393 port
.NotAnInteger
= client_resp_src_port
;
394 mDNS_AddDNSServer(m
, &d
, primary_interfaceID
, serviceID
, &addr
, port
, scoped
, timeout
,
395 cellIntf
, isExpensive
, isCLAT46
, resGroupID
,
396 reqA
, reqAAAA
, reqDO
);
398 return mStatus_NoError
;