]> git.saurik.com Git - apple/mdnsresponder.git/blob - unittests/LocalOnlyTimeoutTests.c
mDNSResponder-878.250.4.tar.gz
[apple/mdnsresponder.git] / unittests / LocalOnlyTimeoutTests.c
1 #include "LocalOnlyTimeoutTests.h"
2 #include "unittest_common.h"
3
4 mDNSlocal int InitUnitTest(void);
5 mDNSlocal int StartLocalOnlyClientQueryRequest(void);
6 mDNSlocal int PopulateCacheWithClientLOResponseRecords(void);
7 mDNSlocal int RestartLocalOnlyClientQueryRequest(void);
8 mDNSlocal int FinalizeUnitTest(void);
9 mDNSlocal mStatus InitEtcHostsRecords();
10
11 // This unit test's variables
12 static request_state* client_request_message;
13 static UDPSocket* local_socket;
14 static char domainname_cstr[MAX_ESCAPED_DOMAIN_NAME];
15
16 // This query request message was generated from the following command: "dns-sd -lo -timeout -Q cardinal2.apple.com. A"
17 char query_req_msgbuf[33]= {
18 0x00, 0x01, 0x90, 0x00,
19 // DNSServiceFlags.L = (kDNSServiceFlagsReturnIntermediates |kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsTimeout)
20 0xff, 0xff, 0xff, 0xff,
21 // interfaceIndex = mDNSInterface_LocalOnly
22 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c,
23 0x32, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x00, 0x00, 0x01, 0x00,
24 0x01
25 };
26
27 UNITTEST_HEADER(LocalOnlyTimeoutTests)
28 UNITTEST_TEST(InitUnitTest)
29 UNITTEST_TEST(StartLocalOnlyClientQueryRequest)
30 UNITTEST_TEST(PopulateCacheWithClientLOResponseRecords)
31 UNITTEST_TEST(RestartLocalOnlyClientQueryRequest)
32 UNITTEST_TEST(FinalizeUnitTest)
33 UNITTEST_FOOTER
34
35 // The InitUnitTest() initializes a minimal mDNSResponder environment as
36 // well as allocates memory for a local_socket and client request.
37 // It also sets the domainname_cstr specified in the client's query request.
38 // Note: This unit test does not send packets on the wire and it does not open sockets.
39 UNITTEST_HEADER(InitUnitTest)
40
41 // Init mDNSStorage
42 mStatus result = init_mdns_storage();
43 if (result != mStatus_NoError)
44 return result;
45
46 // Allocate a client request
47 local_socket = calloc(1, sizeof(request_state));
48
49 // Allocate memory for a request that is used to make client requests.
50 client_request_message = calloc(1, sizeof(request_state));
51
52 // Init domainname that is used by unit tests
53 strlcpy(domainname_cstr, "cardinal2.apple.com.", sizeof(domainname_cstr));
54
55 UNITTEST_FOOTER
56
57 // This unit test starts a local only request for "cardinal2.apple.com.". It first
58 // calls start_client_request to start a query, it then verifies the
59 // req and query data structures are set as expected. Next, the cache is verified to
60 // be empty by AnswerNewLocalOnlyQuestion() and so results in GenerateNegativeResponse()
61 // getting called which sets up a reply with a negative answer in it for the client.
62 // On return from mDNS_Execute, the client's reply structure is verified to be set as
63 // expected. Lastly the timeout is simulated and mDNS_Execute is called. This results
64 // in a call to TimeoutQuestions(). And again, the GenerateNegativeResponse() is called
65 // which returns a negative response to the client. This time the client reply is verified
66 // to be setup with a timeout result.
67 UNITTEST_HEADER(StartLocalOnlyClientQueryRequest)
68
69 mDNS *const m = &mDNSStorage;
70 request_state* req = client_request_message;
71 char *msgptr = (char *)query_req_msgbuf;
72 size_t msgsz = sizeof(query_req_msgbuf);
73 DNSQuestion *q;
74 mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
75 mStatus err = mStatus_NoError;
76 char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
77 struct reply_state *reply;
78 size_t len;
79
80 // Process the unit test's client request
81 start_client_request(req, msgptr, msgsz, query_request, local_socket);
82 UNITTEST_ASSERT(err == mStatus_NoError);
83
84 // Verify the query initialized and request fields were set as expected
85 UNITTEST_ASSERT(err == mStatus_NoError);
86 UNITTEST_ASSERT(req->hdr.version == VERSION);
87 UNITTEST_ASSERT((mDNSs32)req->data_bytes > min_size);
88 UNITTEST_ASSERT(req->flags == (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
89 UNITTEST_ASSERT(req->interfaceIndex == kDNSServiceInterfaceIndexLocalOnly);
90 UNITTEST_ASSERT(req->terminate != mDNSNULL);
91
92 q = &req->u.queryrecord.q;
93 UNITTEST_ASSERT(q == m->NewLocalOnlyQuestions);
94 UNITTEST_ASSERT(m->Questions == NULL);
95 UNITTEST_ASSERT(m->NewQuestions == NULL);
96 UNITTEST_ASSERT(q->SuppressUnusable == 1);
97 UNITTEST_ASSERT(q->ReturnIntermed == 1);
98 UNITTEST_ASSERT(q->SuppressQuery == 0); // Regress <rdar://problem/27571734>
99
100 UNITTEST_ASSERT(q->qnameOrig == mDNSNULL);
101 ConvertDomainNameToCString(&q->qname, qname_cstr);
102 UNITTEST_ASSERT(!strcmp(qname_cstr, domainname_cstr));
103 UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
104
105 UNITTEST_ASSERT(q->InterfaceID == mDNSInterface_LocalOnly);
106 UNITTEST_ASSERT(q->flags == req->flags);
107 UNITTEST_ASSERT(q->qtype == 1);
108 UNITTEST_ASSERT(q->qclass == 1);
109 UNITTEST_ASSERT(q->LongLived == 0);
110 UNITTEST_ASSERT(q->ExpectUnique == mDNSfalse);
111 UNITTEST_ASSERT(q->ForceMCast == 0);
112 UNITTEST_ASSERT(q->TimeoutQuestion == 1);
113 UNITTEST_ASSERT(q->WakeOnResolve == 0);
114 UNITTEST_ASSERT(q->UseBackgroundTrafficClass == 0);
115 UNITTEST_ASSERT(q->ValidationRequired == 0);
116 UNITTEST_ASSERT(q->ValidatingResponse == 0);
117 UNITTEST_ASSERT(q->ProxyQuestion == 0);
118 UNITTEST_ASSERT(q->AnonInfo == mDNSNULL);
119 UNITTEST_ASSERT(q->QuestionCallback != mDNSNULL);
120 UNITTEST_ASSERT(q->QuestionContext == req);
121 UNITTEST_ASSERT(q->SearchListIndex == 0);
122 UNITTEST_ASSERT(q->DNSSECAuthInfo == mDNSNULL);
123 UNITTEST_ASSERT(q->DAIFreeCallback == mDNSNULL);
124 UNITTEST_ASSERT(q->RetryWithSearchDomains == 0);
125 UNITTEST_ASSERT(q->StopTime != 0);
126 UNITTEST_ASSERT(q->AppendSearchDomains == 0);
127 UNITTEST_ASSERT(q->AppendLocalSearchDomains == 0);
128 UNITTEST_ASSERT(q->DuplicateOf == mDNSNULL);
129
130 // At this point the the cache is empty. Calling mDNS_Execute will answer the local-only
131 // question with a negative response.
132 m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
133 mDNS_Execute(m); // Regress <rdar://problem/28721294>
134
135 // Verify reply is a negative response and error code is set to kDNSServiceErr_NoSuchRecord error.
136 reply = req->replies;
137 UNITTEST_ASSERT(reply != mDNSNULL);
138
139 UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
140 UNITTEST_ASSERT(q->LOAddressAnswers == 0);
141
142 len = get_reply_len(qname_cstr, 0);
143
144 UNITTEST_ASSERT(reply->next == mDNSNULL);
145 UNITTEST_ASSERT(reply->totallen == reply->mhdr->datalen + sizeof(ipc_msg_hdr));
146 UNITTEST_ASSERT(reply->mhdr->version == VERSION);
147 UNITTEST_ASSERT(reply->mhdr->datalen == len);
148 UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
149 UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
150
151 UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
152 UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
153 UNITTEST_ASSERT(reply->rhdr->error ==
154 (DNSServiceErrorType)htonl(kDNSServiceErr_NoSuchRecord)); // Regress <rdar://problem/24827555>
155
156 // Simulate what udsserver_idle normally does for clean up
157 freeL("StartLocalOnlyClientQueryRequest:reply", reply);
158 req->replies = NULL;
159
160 // Simulate the query time out of the local-only question.
161 // The expected behavior is a negative answer with time out error
162 m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
163 q->StopTime = mDNS_TimeNow_NoLock(m);
164 m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
165 mDNS_Execute(m);
166
167 // Verify the reply is a negative response with timeout error.
168 reply = req->replies;
169 UNITTEST_ASSERT(reply != NULL);
170 UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
171 UNITTEST_ASSERT(q->LOAddressAnswers == 0);
172
173 len = get_reply_len(qname_cstr, 0);
174
175 UNITTEST_ASSERT(reply->next == mDNSNULL);
176 UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
177 UNITTEST_ASSERT(reply->mhdr->version == VERSION);
178 UNITTEST_ASSERT(reply->mhdr->datalen == len);
179 UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
180 UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
181 UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
182 UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
183 UNITTEST_ASSERT(reply->rhdr->error ==
184 (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout)); // Regress <rdar://problem/27562965>
185
186 // Free request and reallocate to use when query is restarted
187 free_req(req);
188 client_request_message = calloc(1, sizeof(request_state));
189
190 UNITTEST_FOOTER
191
192 // This unit test populates the cache with four /etc/hosts records and then
193 // verifies there are four entries in the cache.
194 UNITTEST_HEADER(PopulateCacheWithClientLOResponseRecords)
195
196 mDNS *const m = &mDNSStorage;
197
198 // Verify cache is empty
199 int count = LogEtcHosts_ut(m);
200 UNITTEST_ASSERT(count == 0);
201
202 // Populate /etc/hosts
203 mStatus result = InitEtcHostsRecords();
204 UNITTEST_ASSERT(result == mStatus_NoError);
205
206 // mDNS_Execute is called to populate the /etc/hosts cache.
207 m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
208 mDNS_Execute(m);
209
210 count = LogEtcHosts_ut(m);
211 UNITTEST_ASSERT(count == 4);
212
213 UNITTEST_FOOTER
214
215 // This unit test starts a local only request for "cardinal2.apple.com.". It first
216 // calls start_client_request to start a query, it then verifies the
217 // req and query data structures are set as expected. Next, the cache is verified to
218 // contain the answer by AnswerNewLocalOnlyQuestion() and so results in setting up an
219 // answer reply to the client. On return from mDNS_Execute, the client's reply structure
220 // is verified to be set as expected. Lastly the timeout is simulated and mDNS_Execute is
221 // called. This results in a call to TimeoutQuestions(). And this time, the
222 // GenerateNegativeResponse() is called which returns a negative response to the client
223 // which specifies the timeout occurred. Again, the answer reply is verified to
224 // to specify a timeout.
225 UNITTEST_HEADER(RestartLocalOnlyClientQueryRequest)
226
227 mDNS *const m = &mDNSStorage;
228 request_state* req = client_request_message;
229 char *msgptr = (char *)query_req_msgbuf;
230 size_t msgsz = sizeof(query_req_msgbuf); DNSQuestion *q;
231 mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
232 mStatus err = mStatus_NoError;
233 char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
234 struct reply_state *reply;
235 size_t len;
236
237 // Process the unit test's client request
238 start_client_request(req, msgptr, msgsz, query_request, local_socket);
239 UNITTEST_ASSERT(err == mStatus_NoError);
240
241 UNITTEST_ASSERT(err == mStatus_NoError);
242 UNITTEST_ASSERT(req->hdr.version == VERSION);
243 UNITTEST_ASSERT((mDNSs32)req->data_bytes > min_size);
244 UNITTEST_ASSERT(req->flags == (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
245 UNITTEST_ASSERT(req->interfaceIndex == kDNSServiceInterfaceIndexLocalOnly);
246 UNITTEST_ASSERT(req->terminate != mDNSNULL);
247 UNITTEST_ASSERT(m->Questions == NULL);
248
249 q = &req->u.queryrecord.q;
250 UNITTEST_ASSERT(q == m->NewLocalOnlyQuestions);
251 UNITTEST_ASSERT(q->SuppressUnusable == 1);
252 UNITTEST_ASSERT(q->ReturnIntermed == 1);
253 UNITTEST_ASSERT(q->SuppressQuery == 0); // Regress <rdar://problem/27571734>
254 UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
255 UNITTEST_ASSERT(q->InterfaceID == mDNSInterface_LocalOnly);
256 UNITTEST_ASSERT(q->flags == req->flags);
257 UNITTEST_ASSERT(q->qtype == 1);
258 UNITTEST_ASSERT(q->qclass == 1);
259 UNITTEST_ASSERT(q->LongLived == 0);
260 UNITTEST_ASSERT(q->ExpectUnique == mDNSfalse);
261 UNITTEST_ASSERT(q->ForceMCast == 0);
262 UNITTEST_ASSERT(q->TimeoutQuestion == 1);
263 UNITTEST_ASSERT(q->WakeOnResolve == 0);
264 UNITTEST_ASSERT(q->UseBackgroundTrafficClass == 0);
265 UNITTEST_ASSERT(q->ValidationRequired == 0);
266 UNITTEST_ASSERT(q->ValidatingResponse == 0);
267 UNITTEST_ASSERT(q->ProxyQuestion == 0);
268 UNITTEST_ASSERT(q->AnonInfo == mDNSNULL);
269 UNITTEST_ASSERT(q->QuestionCallback != mDNSNULL);
270 UNITTEST_ASSERT(q->QuestionContext == req);
271 UNITTEST_ASSERT(q->SearchListIndex == 0);
272 UNITTEST_ASSERT(q->DNSSECAuthInfo == mDNSNULL);
273 UNITTEST_ASSERT(q->DAIFreeCallback == mDNSNULL);
274 UNITTEST_ASSERT(q->RetryWithSearchDomains == 0);
275 UNITTEST_ASSERT(q->StopTime != 0);
276 UNITTEST_ASSERT(q->AppendSearchDomains == 0);
277 UNITTEST_ASSERT(q->AppendLocalSearchDomains == 0);
278 UNITTEST_ASSERT(q->DuplicateOf == mDNSNULL);
279 ConvertDomainNameToCString(&q->qname, qname_cstr);
280 UNITTEST_ASSERT(!strcmp(qname_cstr, domainname_cstr));
281
282 // Answer local-only question with found cache entry
283 m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
284 mDNS_Execute(m); // Regress <rdar://problem/28721294>
285 UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
286 UNITTEST_ASSERT(req->u.queryrecord.ans == 1);
287 UNITTEST_ASSERT(q->LOAddressAnswers == 1);
288 UNITTEST_ASSERT(q == m->LocalOnlyQuestions);
289
290 reply = req->replies;
291 len = get_reply_len(qname_cstr, 4);
292
293 UNITTEST_ASSERT(reply->next == mDNSNULL);
294 UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
295 UNITTEST_ASSERT(reply->mhdr->version == VERSION);
296 UNITTEST_ASSERT(reply->mhdr->datalen == len);
297 UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
298 UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
299 UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
300 UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
301 UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
302
303 // Simulate the query time out of the local-only question.
304 // The expected behavior is a negative answer with time out error
305 m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
306 q->StopTime = mDNS_TimeNow_NoLock(m);
307 m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
308 mDNS_Execute(m);
309
310 reply = req->replies->next;
311 UNITTEST_ASSERT(reply != NULL);
312 UNITTEST_ASSERT(reply->next == NULL);
313 UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
314 UNITTEST_ASSERT(q->LOAddressAnswers == 0);
315 len = get_reply_len(qname_cstr, 0);
316
317 UNITTEST_ASSERT(reply->next == mDNSNULL);
318 UNITTEST_ASSERT(reply->totallen == len + + sizeof(ipc_msg_hdr));
319 UNITTEST_ASSERT(reply->mhdr->version == VERSION);
320 UNITTEST_ASSERT(reply->mhdr->datalen == len);
321 UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
322 UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
323 UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
324 UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
325 UNITTEST_ASSERT(reply->rhdr->error ==
326 (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout)); // Regress <rdar://problem/27562965>
327
328 free_req(req);
329 UNITTEST_FOOTER
330
331 // This function does memory cleanup and no verification.
332 UNITTEST_HEADER(FinalizeUnitTest)
333 mDNSPlatformMemFree(local_socket);
334 UNITTEST_FOOTER
335
336 mDNSlocal mStatus InitEtcHostsRecords(void)
337 {
338 mDNS *m = &mDNSStorage;
339 struct sockaddr_storage hostaddr;
340
341 AuthHash newhosts;
342 mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
343
344 memset(&hostaddr, 0, sizeof(hostaddr));
345 get_ip("127.0.0.1", &hostaddr);
346
347 domainname domain;
348 MakeDomainNameFromDNSNameString(&domain, "localhost");
349
350 mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
351
352 memset(&hostaddr, 0, sizeof(hostaddr));
353 get_ip("0000:0000:0000:0000:0000:0000:0000:0001", &hostaddr);
354
355 MakeDomainNameFromDNSNameString(&domain, "localhost");
356
357 mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
358
359 memset(&hostaddr, 0, sizeof(hostaddr));
360 get_ip("255.255.255.255", &hostaddr);
361
362 MakeDomainNameFromDNSNameString(&domain, "broadcasthost");
363
364 mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
365
366 memset(&hostaddr, 0, sizeof(hostaddr));
367 get_ip("17.226.40.200", &hostaddr);
368
369 MakeDomainNameFromDNSNameString(&domain, "cardinal2.apple.com");
370
371 mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
372 UpdateEtcHosts_ut(&newhosts);
373
374 m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
375 mDNS_Execute(m);
376
377 return mStatus_NoError;
378 }