1 #include "LocalOnlyTimeoutTests.h"
2 #include "unittest_common.h"
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();
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
];
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,
27 UNITTEST_HEADER(LocalOnlyTimeoutTests
)
28 UNITTEST_TEST(InitUnitTest
)
29 UNITTEST_TEST(StartLocalOnlyClientQueryRequest
)
30 UNITTEST_TEST(PopulateCacheWithClientLOResponseRecords
)
31 UNITTEST_TEST(RestartLocalOnlyClientQueryRequest
)
32 UNITTEST_TEST(FinalizeUnitTest
)
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
)
42 mStatus result
= init_mdns_storage();
43 if (result
!= mStatus_NoError
)
46 // Allocate a client request
47 local_socket
= calloc(1, sizeof(request_state
));
49 // Allocate memory for a request that is used to make client requests.
50 client_request_message
= calloc(1, sizeof(request_state
));
52 // Init domainname that is used by unit tests
53 strlcpy(domainname_cstr
, "cardinal2.apple.com.", sizeof(domainname_cstr
));
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
)
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
);
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
;
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
);
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
);
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>
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
));
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
);
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>
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
);
139 UNITTEST_ASSERT(m
->NewLocalOnlyQuestions
== NULL
);
140 UNITTEST_ASSERT(q
->LOAddressAnswers
== 0);
142 len
= get_reply_len(qname_cstr
, 0);
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
);
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>
156 // Simulate what udsserver_idle normally does for clean up
157 freeL("StartLocalOnlyClientQueryRequest:reply", reply
);
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;
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);
173 len
= get_reply_len(qname_cstr
, 0);
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>
186 // Free request and reallocate to use when query is restarted
188 client_request_message
= calloc(1, sizeof(request_state
));
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
)
196 mDNS
*const m
= &mDNSStorage
;
198 // Verify cache is empty
199 int count
= LogEtcHosts_ut(m
);
200 UNITTEST_ASSERT(count
== 0);
202 // Populate /etc/hosts
203 mStatus result
= InitEtcHostsRecords();
204 UNITTEST_ASSERT(result
== mStatus_NoError
);
206 // mDNS_Execute is called to populate the /etc/hosts cache.
207 m
->NextScheduledEvent
= mDNS_TimeNow_NoLock(m
);
210 count
= LogEtcHosts_ut(m
);
211 UNITTEST_ASSERT(count
== 4);
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
)
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
;
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
);
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
);
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
));
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
);
290 reply
= req
->replies
;
291 len
= get_reply_len(qname_cstr
, 4);
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
);
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;
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);
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>
331 // This function does memory cleanup and no verification.
332 UNITTEST_HEADER(FinalizeUnitTest
)
333 mDNSPlatformMemFree(local_socket
);
336 mDNSlocal mStatus
InitEtcHostsRecords(void)
338 mDNS
*m
= &mDNSStorage
;
339 struct sockaddr_storage hostaddr
;
342 mDNSPlatformMemZero(&newhosts
, sizeof(AuthHash
));
344 memset(&hostaddr
, 0, sizeof(hostaddr
));
345 get_ip("127.0.0.1", &hostaddr
);
348 MakeDomainNameFromDNSNameString(&domain
, "localhost");
350 mDNSMacOSXCreateEtcHostsEntry_ut(&domain
, (struct sockaddr
*) &hostaddr
, mDNSNULL
, mDNSNULL
, &newhosts
);
352 memset(&hostaddr
, 0, sizeof(hostaddr
));
353 get_ip("0000:0000:0000:0000:0000:0000:0000:0001", &hostaddr
);
355 MakeDomainNameFromDNSNameString(&domain
, "localhost");
357 mDNSMacOSXCreateEtcHostsEntry_ut(&domain
, (struct sockaddr
*) &hostaddr
, mDNSNULL
, mDNSNULL
, &newhosts
);
359 memset(&hostaddr
, 0, sizeof(hostaddr
));
360 get_ip("255.255.255.255", &hostaddr
);
362 MakeDomainNameFromDNSNameString(&domain
, "broadcasthost");
364 mDNSMacOSXCreateEtcHostsEntry_ut(&domain
, (struct sockaddr
*) &hostaddr
, mDNSNULL
, mDNSNULL
, &newhosts
);
366 memset(&hostaddr
, 0, sizeof(hostaddr
));
367 get_ip("17.226.40.200", &hostaddr
);
369 MakeDomainNameFromDNSNameString(&domain
, "cardinal2.apple.com");
371 mDNSMacOSXCreateEtcHostsEntry_ut(&domain
, (struct sockaddr
*) &hostaddr
, mDNSNULL
, mDNSNULL
, &newhosts
);
372 UpdateEtcHosts_ut(&newhosts
);
374 m
->NextScheduledEvent
= mDNS_TimeNow_NoLock(m
);
377 return mStatus_NoError
;