dns-push.c revision 1.1 1 1.1 christos /* dns-push.c
2 1.1 christos *
3 1.1 christos * Copyright (c) 2024 Apple Inc. All rights reserved.
4 1.1 christos *
5 1.1 christos * Licensed under the Apache License, Version 2.0 (the "License");
6 1.1 christos * you may not use this file except in compliance with the License.
7 1.1 christos * You may obtain a copy of the License at
8 1.1 christos *
9 1.1 christos * https://www.apache.org/licenses/LICENSE-2.0
10 1.1 christos *
11 1.1 christos * Unless required by applicable law or agreed to in writing, software
12 1.1 christos * distributed under the License is distributed on an "AS IS" BASIS,
13 1.1 christos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 1.1 christos * See the License for the specific language governing permissions and
15 1.1 christos * limitations under the License.
16 1.1 christos *
17 1.1 christos * This file contains the SRP server test runner.
18 1.1 christos */
19 1.1 christos
20 1.1 christos #include "srp.h"
21 1.1 christos #include <dns_sd.h>
22 1.1 christos #include <arpa/inet.h>
23 1.1 christos #include "srp-test-runner.h"
24 1.1 christos #include "srp-api.h"
25 1.1 christos #include "dns-msg.h"
26 1.1 christos #include "ioloop.h"
27 1.1 christos #include "srp-mdns-proxy.h"
28 1.1 christos #include "test-api.h"
29 1.1 christos #include "srp-proxy.h"
30 1.1 christos #include "srp-mdns-proxy.h"
31 1.1 christos #include "test-dnssd.h"
32 1.1 christos #include "test.h"
33 1.1 christos #include "dnssd-proxy.h"
34 1.1 christos #define DNSMessageHeader dns_wire_t
35 1.1 christos #include "dso.h"
36 1.1 christos #include "dso-utils.h"
37 1.1 christos
38 1.1 christos #define SUBSCRIBE_LIMIT 16 // SOA + SRV + A + AAAA || PTR + SRV + A + AAAA
39 1.1 christos #define TXN_LIMIT SUBSCRIBE_LIMIT * 4
40 1.1 christos typedef struct push_test_state push_test_state_t;
41 1.1 christos struct push_test_state {
42 1.1 christos test_state_t *test_state;
43 1.1 christos comm_t *dso_connection;
44 1.1 christos wakeup_t *wait_for_remote_disconnect;
45 1.1 christos dso_state_t *disconnect_expected;
46 1.1 christos DNSServiceRef register_ref, ptr_sdref;
47 1.1 christos DNSServiceRef txns[TXN_LIMIT];
48 1.1 christos int num_txns;
49 1.1 christos uint16_t subscribe_xids[SUBSCRIBE_LIMIT];
50 1.1 christos int num_subscribe_xids, soa_index, ds_index[2];
51 1.1 christos char *hostname;
52 1.1 christos char *srv_name;
53 1.1 christos int num_service_adds_pre, num_service_removes, num_service_adds_post;
54 1.1 christos int num_address_adds_pre, num_address_removes, num_address_adds_post;
55 1.1 christos uint16_t keepalive_xid;
56 1.1 christos int variant, num_a_records, num_aaaa_records;
57 1.1 christos int num_txt_records, num_srv_records;
58 1.1 christos bool push_send_bogus_keepalive, push_unsubscribe;
59 1.1 christos bool push_subscribe_sent, have_address_records;
60 1.1 christos bool server_was_crashed, server_is_being_crashed;
61 1.1 christos bool test_dns_push, have_keepalive_response, need_service;
62 1.1 christos };
63 1.1 christos
64 1.1 christos static void test_dns_push_send_push_subscribe(push_test_state_t *push_state, const char *name, int rrtype);
65 1.1 christos
66 1.1 christos static void
67 1.1 christos test_dns_push_dso_message_finished(void *context, message_t *UNUSED message, dso_state_t *dso)
68 1.1 christos {
69 1.1 christos push_test_state_t *push_state = context;
70 1.1 christos
71 1.1 christos if (dso->primary.opcode == kDSOType_DNSPushUnsubscribe) {
72 1.1 christos if (dso->activities == NULL) {
73 1.1 christos dispatch_async(dispatch_get_main_queue(), ^{
74 1.1 christos TEST_PASSED(push_state->test_state);
75 1.1 christos });
76 1.1 christos }
77 1.1 christos }
78 1.1 christos }
79 1.1 christos
80 1.1 christos static void
81 1.1 christos test_dns_push_send_push_unsubscribe(push_test_state_t *push_state, int index)
82 1.1 christos {
83 1.1 christos if (push_state->subscribe_xids[index] != 0) {
84 1.1 christos struct iovec iov;
85 1.1 christos dns_wire_t dns_message;
86 1.1 christos uint8_t *buffer = (uint8_t *)&dns_message;
87 1.1 christos dns_towire_state_t towire;
88 1.1 christos dso_message_t message;
89 1.1 christos
90 1.1 christos INFO("unsubscribe %x %d", push_state->subscribe_xids[index], index);
91 1.1 christos dso_make_message(&message, buffer, sizeof(dns_message), push_state->dso_connection->dso, true, false, 0, 0, NULL);
92 1.1 christos memset(&towire, 0, sizeof(towire));
93 1.1 christos towire.p = &buffer[DNS_HEADER_SIZE];
94 1.1 christos towire.lim = towire.p + (sizeof(dns_message) - DNS_HEADER_SIZE);
95 1.1 christos towire.message = &dns_message;
96 1.1 christos dns_u16_to_wire(&towire, kDSOType_DNSPushUnsubscribe);
97 1.1 christos dns_rdlength_begin(&towire);
98 1.1 christos dns_u16_to_wire(&towire, push_state->subscribe_xids[index]);
99 1.1 christos dns_rdlength_end(&towire);
100 1.1 christos
101 1.1 christos memset(&iov, 0, sizeof(iov));
102 1.1 christos iov.iov_len = towire.p - buffer;
103 1.1 christos iov.iov_base = buffer;
104 1.1 christos ioloop_send_message(push_state->dso_connection, NULL, &iov, 1);
105 1.1 christos push_state->subscribe_xids[index] = 0; // Don't unsubscribe again.
106 1.1 christos }
107 1.1 christos }
108 1.1 christos
109 1.1 christos static void
110 1.1 christos test_dns_push_unsubscribe_all(push_test_state_t *push_state)
111 1.1 christos {
112 1.1 christos struct iovec iov;
113 1.1 christos INFO("unsubscribe");
114 1.1 christos dns_wire_t dns_message;
115 1.1 christos uint8_t *buffer = (uint8_t *)&dns_message;
116 1.1 christos dns_towire_state_t towire;
117 1.1 christos dso_message_t message;
118 1.1 christos if (!push_state->push_send_bogus_keepalive) {
119 1.1 christos for (int i = 0; i < push_state->num_subscribe_xids; i++) {
120 1.1 christos test_dns_push_send_push_unsubscribe(push_state, i);
121 1.1 christos }
122 1.1 christos }
123 1.1 christos
124 1.1 christos // Send a keepalive message so that we can get the response, since the unsubscribe is not a response-requiring request.
125 1.1 christos dso_make_message(&message, buffer, sizeof(dns_message), push_state->dso_connection->dso, false, false, 0, 0, NULL);
126 1.1 christos memset(&towire, 0, sizeof(towire));
127 1.1 christos towire.p = &buffer[DNS_HEADER_SIZE];
128 1.1 christos towire.lim = towire.p + (sizeof(dns_message) - DNS_HEADER_SIZE);
129 1.1 christos towire.message = &dns_message;
130 1.1 christos dns_u16_to_wire(&towire, kDSOType_Keepalive);
131 1.1 christos dns_rdlength_begin(&towire);
132 1.1 christos dns_u32_to_wire(&towire, 600);
133 1.1 christos dns_u32_to_wire(&towire, 600);
134 1.1 christos dns_rdlength_end(&towire);
135 1.1 christos if (push_state->push_send_bogus_keepalive) {
136 1.1 christos INFO("sending bogus keepalive");
137 1.1 christos // Send a badly formatted message.
138 1.1 christos dns_u32_to_wire(&towire, 0x12345678);
139 1.1 christos }
140 1.1 christos push_state->keepalive_xid = dns_message.id;
141 1.1 christos memset(&iov, 0, sizeof(iov));
142 1.1 christos iov.iov_len = towire.p - buffer;
143 1.1 christos iov.iov_base = buffer;
144 1.1 christos ioloop_send_message(push_state->dso_connection, NULL, &iov, 1);
145 1.1 christos }
146 1.1 christos
147 1.1 christos static void
148 1.1 christos test_dns_push_remote_disconnect_didnt_happen(void *context)
149 1.1 christos {
150 1.1 christos push_test_state_t *push_state = context;
151 1.1 christos TEST_FAIL(push_state->test_state, "remote disconnect didn't happen");
152 1.1 christos }
153 1.1 christos
154 1.1 christos static void
155 1.1 christos test_dns_push_handle_retry_delay(push_test_state_t *push_state, dso_state_t *dso, uint32_t delay)
156 1.1 christos {
157 1.1 christos INFO("Got our retry delay, %ums...", delay);
158 1.1 christos push_state->wait_for_remote_disconnect = ioloop_wakeup_create();
159 1.1 christos
160 1.1 christos TEST_FAIL_CHECK(push_state->test_state, push_state->wait_for_remote_disconnect != NULL, "can't wait for remote disconnect.");
161 1.1 christos
162 1.1 christos // Wait six seconds for remote disconnect, which should happen in five.
163 1.1 christos ioloop_add_wake_event(push_state->wait_for_remote_disconnect, push_state, test_dns_push_remote_disconnect_didnt_happen, NULL, 6 * 1000);
164 1.1 christos push_state->disconnect_expected = dso;
165 1.1 christos }
166 1.1 christos
167 1.1 christos static void
168 1.1 christos test_dns_push_address_update(push_test_state_t *push_state, dns_rr_t *rr, const char *name)
169 1.1 christos {
170 1.1 christos const char *record_name = "AAAA";
171 1.1 christos char ntop[INET6_ADDRSTRLEN];
172 1.1 christos int num;
173 1.1 christos
174 1.1 christos if (rr->type == dns_rrtype_a) {
175 1.1 christos num = push_state->num_a_records;
176 1.1 christos if (rr->ttl != 0xffffffff) {
177 1.1 christos ++push_state->num_a_records;
178 1.1 christos }
179 1.1 christos inet_ntop(AF_INET, &rr->data.a, ntop, sizeof(ntop));
180 1.1 christos record_name = "A";
181 1.1 christos } else {
182 1.1 christos num = push_state->num_aaaa_records;
183 1.1 christos if (rr->ttl != 0xffffffff) {
184 1.1 christos ++push_state->num_aaaa_records;
185 1.1 christos }
186 1.1 christos inet_ntop(AF_INET6, &rr->data.aaaa, ntop, sizeof(ntop));
187 1.1 christos }
188 1.1 christos INFO("%s: %s %s record #%d: %s", name, rr->ttl == 0xffffffff ? "removed" : "added", record_name, num, ntop);
189 1.1 christos }
190 1.1 christos
191 1.1 christos static void
192 1.1 christos test_dns_push_update(push_test_state_t *push_state, dns_rr_t *rr)
193 1.1 christos {
194 1.1 christos char name[DNS_MAX_NAME_SIZE_ESCAPED + 1];
195 1.1 christos dns_name_print(rr->name, name, sizeof(name));
196 1.1 christos
197 1.1 christos if (rr->type == dns_rrtype_soa) {
198 1.1 christos TEST_FAIL_CHECK_STATUS(push_state->test_state, push_state->variant == PUSH_TEST_VARIANT_HARDWIRED,
199 1.1 christos "SOA received in wrong variant: %s", name);
200 1.1 christos char soaname[DNS_MAX_NAME_SIZE_ESCAPED + 1];
201 1.1 christos TEST_FAIL_CHECK_STATUS(push_state->test_state, !strcmp(name, "default.service.arpa."), "bad name for SOA: %s", name);
202 1.1 christos dns_name_print(rr->data.soa.mname, soaname, sizeof(soaname));
203 1.1 christos INFO("%s in SOA %s ...", name, soaname);
204 1.1 christos // Look up the SRV record for _dns-push-tls._tcp.default.service.arpa, so that we can get the hostname but also
205 1.1 christos // validate that the SRV record is being advertised.
206 1.1 christos push_state->srv_name = strdup("_dns-push-tls._tcp.default.service.arpa.");
207 1.1 christos test_dns_push_send_push_subscribe(push_state, push_state->srv_name, dns_rrtype_srv);
208 1.1 christos test_dns_push_send_push_unsubscribe(push_state, push_state->soa_index);
209 1.1 christos } else if (rr->type == dns_rrtype_a || rr->type == dns_rrtype_aaaa) {
210 1.1 christos test_dns_push_address_update(push_state, rr, name);
211 1.1 christos if (push_state->server_was_crashed) {
212 1.1 christos if (rr->ttl == 0xffffffff) {
213 1.1 christos push_state->num_address_removes++;
214 1.1 christos } else {
215 1.1 christos push_state->num_address_adds_post++;
216 1.1 christos }
217 1.1 christos } else {
218 1.1 christos push_state->num_address_adds_pre++;
219 1.1 christos }
220 1.1 christos } else if (rr->type == dns_rrtype_ptr) {
221 1.1 christos TEST_FAIL_CHECK_STATUS(push_state->test_state, push_state->variant != PUSH_TEST_VARIANT_HARDWIRED,
222 1.1 christos "PTR received in wrong variant: %s", name);
223 1.1 christos TEST_FAIL_CHECK_STATUS(push_state->test_state, !strcmp(name, "_example._tcp.default.service.arpa."),
224 1.1 christos "bad name for PTR: %s", name);
225 1.1 christos char ptrname[DNS_MAX_NAME_SIZE_ESCAPED + 1];
226 1.1 christos dns_name_print(rr->data.ptr.name, ptrname, sizeof(ptrname));
227 1.1 christos INFO("%s %s IN PTR %s", rr->ttl == 0xffffffff ? "removed" : "added", name, ptrname);
228 1.1 christos if (push_state->srv_name == NULL) {
229 1.1 christos push_state->srv_name = strdup(ptrname);
230 1.1 christos test_dns_push_send_push_subscribe(push_state, push_state->srv_name, dns_rrtype_srv);
231 1.1 christos }
232 1.1 christos if (push_state->server_was_crashed) {
233 1.1 christos if (rr->ttl == 0xffffffff) {
234 1.1 christos push_state->num_service_removes++;
235 1.1 christos } else {
236 1.1 christos push_state->num_service_adds_post++;
237 1.1 christos }
238 1.1 christos } else {
239 1.1 christos push_state->num_service_adds_pre++;
240 1.1 christos }
241 1.1 christos } else if (rr->type == dns_rrtype_srv) {
242 1.1 christos char hnbuf[DNS_MAX_NAME_SIZE_ESCAPED + 1];
243 1.1 christos dns_name_print(rr->data.ptr.name, hnbuf, sizeof(hnbuf));
244 1.1 christos INFO("%s IN SRV %s ...", name, hnbuf);
245 1.1 christos TEST_FAIL_CHECK_STATUS(push_state->test_state, !strcmp(name, push_state->srv_name), "bad name for SRV: %s", name);
246 1.1 christos // Look up address records for SOA name server name.
247 1.1 christos if (push_state->hostname == NULL) {
248 1.1 christos push_state->hostname = strdup(hnbuf);
249 1.1 christos TEST_FAIL_CHECK_STATUS(push_state->test_state, push_state->hostname != NULL, "no memory for %s", hnbuf);
250 1.1 christos dispatch_async(dispatch_get_main_queue(), ^{
251 1.1 christos test_dns_push_send_push_subscribe(push_state, push_state->hostname, dns_rrtype_a);
252 1.1 christos });
253 1.1 christos dispatch_async(dispatch_get_main_queue(), ^{
254 1.1 christos test_dns_push_send_push_subscribe(push_state, push_state->hostname, dns_rrtype_aaaa);
255 1.1 christos });
256 1.1 christos // At this point the DS queries should have been started, so we can remove them and make sure that works.
257 1.1 christos if (push_state->variant == PUSH_TEST_VARIANT_HARDWIRED) {
258 1.1 christos test_dns_push_send_push_unsubscribe(push_state, push_state->ds_index[0]);
259 1.1 christos test_dns_push_send_push_unsubscribe(push_state, push_state->ds_index[1]);
260 1.1 christos }
261 1.1 christos }
262 1.1 christos push_state->num_srv_records++;
263 1.1 christos } else if (rr->type == dns_rrtype_txt) {
264 1.1 christos char txt_buf[DNS_DATA_SIZE];
265 1.1 christos dns_txt_data_print(txt_buf, DNS_DATA_SIZE, rr->data.txt.len, rr->data.txt.data);
266 1.1 christos INFO("%s IN TXT %s ...", name, txt_buf);
267 1.1 christos push_state->num_txt_records++;
268 1.1 christos } else {
269 1.1 christos INFO("unexpected rrtype for %s in push update: %d", name, rr->type);
270 1.1 christos }
271 1.1 christos }
272 1.1 christos
273 1.1 christos static void
274 1.1 christos test_dns_push_send_appropriate_subscribe(push_test_state_t *push_state)
275 1.1 christos {
276 1.1 christos if (push_state->variant == PUSH_TEST_VARIANT_HARDWIRED) {
277 1.1 christos push_state->soa_index = push_state->num_subscribe_xids;
278 1.1 christos test_dns_push_send_push_subscribe(push_state, "default.service.arpa", dns_rrtype_soa);
279 1.1 christos push_state->ds_index[0] = push_state->num_subscribe_xids;
280 1.1 christos test_dns_push_send_push_subscribe(push_state, "default.service.arpa", dns_rrtype_ds);
281 1.1 christos push_state->ds_index[1] = push_state->num_subscribe_xids;
282 1.1 christos test_dns_push_send_push_subscribe(push_state, "default.service.arpa", dns_rrtype_ds);
283 1.1 christos } else {
284 1.1 christos test_dns_push_send_push_subscribe(push_state, "_example._tcp.default.service.arpa", dns_rrtype_ptr);
285 1.1 christos }
286 1.1 christos push_state->push_subscribe_sent = true;
287 1.1 christos }
288 1.1 christos
289 1.1 christos static void
290 1.1 christos test_dns_push_satisfied_check(push_test_state_t *push_state)
291 1.1 christos {
292 1.1 christos // Check to see if we have all the address records we wanted.
293 1.1 christos if (!push_state->have_address_records) {
294 1.1 christos bool satisfied;
295 1.1 christos switch(push_state->variant) {
296 1.1 christos case PUSH_TEST_VARIANT_HARDWIRED:
297 1.1 christos satisfied = push_state->num_a_records != 0 && push_state->num_aaaa_records != 0;
298 1.1 christos break;
299 1.1 christos case PUSH_TEST_VARIANT_DAEMON_CRASH:
300 1.1 christos case PUSH_TEST_VARIANT_MDNS:
301 1.1 christos satisfied = push_state->num_a_records != 0 || push_state->num_aaaa_records != 0;
302 1.1 christos break;
303 1.1 christos case PUSH_TEST_VARIANT_TWO_QUESTIONS:
304 1.1 christos satisfied = push_state->num_srv_records > 0 && push_state->num_txt_records > 0;
305 1.1 christos break;
306 1.1 christos default:
307 1.1 christos satisfied = false;
308 1.1 christos }
309 1.1 christos if (satisfied && push_state->variant == PUSH_TEST_VARIANT_DAEMON_CRASH) {
310 1.1 christos if (!push_state->server_was_crashed) {
311 1.1 christos // If the server hasn't been crashed yet
312 1.1 christos // And we haven't already queued up a crash event
313 1.1 christos if (!push_state->server_is_being_crashed) {
314 1.1 christos push_state->server_is_being_crashed = true;
315 1.1 christos // Queue up a crash event
316 1.1 christos dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 2),
317 1.1 christos dispatch_get_main_queue(), ^{
318 1.1 christos push_state->server_was_crashed = true;
319 1.1 christos push_state->num_a_records = push_state->num_aaaa_records = 0;
320 1.1 christos dns_service_ref_t *ref = push_state->ptr_sdref;
321 1.1 christos TEST_FAIL_CHECK(push_state->test_state, ref != NULL, "ptr sdref is gone!");
322 1.1 christos for (int i = 0; i < push_state->num_txns; i++) {
323 1.1 christos DNSServiceRefDeallocate(push_state->txns[i]);
324 1.1 christos }
325 1.1 christos DNSServiceQueryRecordReply callback = ref->callback.query_record_reply;
326 1.1 christos callback(ref, 0, 0, kDNSServiceErr_ServiceNotRunning,
327 1.1 christos NULL, dns_rrtype_ptr, dns_qclass_in, 0, 0, 0, ref->context);
328 1.1 christos });
329 1.1 christos }
330 1.1 christos satisfied = false;
331 1.1 christos } else {
332 1.1 christos if (push_state->num_address_removes != push_state->num_address_adds_pre) {
333 1.1 christos satisfied = false;
334 1.1 christos }
335 1.1 christos if (push_state->num_address_adds_pre != push_state->num_address_adds_post) {
336 1.1 christos satisfied = false;
337 1.1 christos }
338 1.1 christos INFO("address removes: %d address adds pre: %d address adds post: %d",
339 1.1 christos push_state->num_address_removes, push_state->num_address_adds_pre,
340 1.1 christos push_state->num_address_adds_post);
341 1.1 christos if (push_state->num_service_removes != push_state->num_service_adds_pre) {
342 1.1 christos satisfied = false;
343 1.1 christos }
344 1.1 christos INFO("service removes: %d service adds pre: %d service adds post: %d",
345 1.1 christos push_state->num_service_removes, push_state->num_service_adds_pre,
346 1.1 christos push_state->num_service_adds_post);
347 1.1 christos }
348 1.1 christos }
349 1.1 christos if (satisfied) {
350 1.1 christos push_state->have_address_records = true;
351 1.1 christos // If we've been asked to unsubscribe, do that.
352 1.1 christos if (push_state->push_unsubscribe) {
353 1.1 christos test_dns_push_unsubscribe_all(push_state);
354 1.1 christos } else {
355 1.1 christos // Finish any ongoing activities first...
356 1.1 christos dispatch_async(dispatch_get_main_queue(), ^{
357 1.1 christos TEST_PASSED(push_state->test_state);
358 1.1 christos });
359 1.1 christos }
360 1.1 christos }
361 1.1 christos }
362 1.1 christos }
363 1.1 christos
364 1.1 christos static void
365 1.1 christos test_dns_push_dns_response(push_test_state_t *push_state, message_t *message)
366 1.1 christos {
367 1.1 christos unsigned offset, max;
368 1.1 christos dns_rr_t rr;
369 1.1 christos uint8_t *message_bytes;
370 1.1 christos bool question = true;
371 1.1 christos int rdata_num = 0;
372 1.1 christos int num_answers = ntohs(message->wire.ancount);
373 1.1 christos
374 1.1 christos message_bytes = (uint8_t *)message->wire.data;
375 1.1 christos offset = 0;
376 1.1 christos max = message->length - DNS_HEADER_SIZE;
377 1.1 christos int rr_index = 0;
378 1.1 christos int qdcount = ntohs(message->wire.qdcount);
379 1.1 christos while (offset < max) {
380 1.1 christos INFO("%d %d", offset, max);
381 1.1 christos if (rr_index >= qdcount) {
382 1.1 christos question = false;
383 1.1 christos }
384 1.1 christos if (!dns_rr_parse(&rr, message_bytes, max, &offset, !question, true)) {
385 1.1 christos TEST_FAIL_STATUS(push_state->test_state, "dns RR parse failed on rr %d", rr_index);
386 1.1 christos break;
387 1.1 christos }
388 1.1 christos if (!question) {
389 1.1 christos if (rdata_num < num_answers) {
390 1.1 christos test_dns_push_update(push_state, &rr);
391 1.1 christos rdata_num++;
392 1.1 christos }
393 1.1 christos }
394 1.1 christos dns_name_free(rr.name);
395 1.1 christos rr.name = NULL;
396 1.1 christos dns_rrdata_free(&rr);
397 1.1 christos rr_index++;
398 1.1 christos }
399 1.1 christos test_dns_push_satisfied_check(push_state);
400 1.1 christos }
401 1.1 christos
402 1.1 christos static void
403 1.1 christos test_dns_push_dso_message(push_test_state_t *push_state, message_t *message, dso_state_t *dso, bool response)
404 1.1 christos {
405 1.1 christos unsigned offset, max;
406 1.1 christos dns_rr_t rr;
407 1.1 christos uint8_t *message_bytes;
408 1.1 christos
409 1.1 christos switch(dso->primary.opcode) {
410 1.1 christos case kDSOType_RetryDelay:
411 1.1 christos if (response) {
412 1.1 christos TEST_FAIL(push_state->test_state, "server sent a retry delay TLV as a response.");
413 1.1 christos }
414 1.1 christos dso_retry_delay(dso, &message->wire);
415 1.1 christos break;
416 1.1 christos
417 1.1 christos case kDSOType_Keepalive:
418 1.1 christos if (response) {
419 1.1 christos TEST_FAIL_STATUS(push_state->test_state, "keepalive response from server, rcode = %d", dns_rcode_get(&message->wire));
420 1.1 christos } else {
421 1.1 christos INFO("Keepalive from server");
422 1.1 christos }
423 1.1 christos
424 1.1 christos // We need to wait for the first keepalive response before sending a DNS push subscribe, since until we get
425 1.1 christos // it we don't have a session. So this actually kicks off the first (possibly only) DNS Push subscribe in the
426 1.1 christos // test.
427 1.1 christos if (!push_state->push_subscribe_sent) {
428 1.1 christos push_state->have_keepalive_response = true;
429 1.1 christos if (!push_state->need_service) {
430 1.1 christos test_dns_push_send_appropriate_subscribe(push_state);
431 1.1 christos }
432 1.1 christos }
433 1.1 christos break;
434 1.1 christos
435 1.1 christos case kDSOType_DNSPushSubscribe:
436 1.1 christos if (response) {
437 1.1 christos // This is a protocol error--the response isn't supposed to contain a primary TLV.
438 1.1 christos TEST_FAIL_STATUS(push_state->test_state,
439 1.1 christos "DNS Push response from server, rcode = %d", dns_rcode_get(&message->wire));
440 1.1 christos } else {
441 1.1 christos INFO("Unexpected DNS Push request from server, rcode = %d", dns_rcode_get(&message->wire));
442 1.1 christos }
443 1.1 christos break;
444 1.1 christos
445 1.1 christos case kDSOType_DNSPushUpdate:
446 1.1 christos // DNS Push Updates are never responses.
447 1.1 christos // DNS Push updates are compressed, so we can't just parse data out of the primary--we need to align
448 1.1 christos // our parse with the start of the message data.
449 1.1 christos message_bytes = (uint8_t *)message->wire.data;
450 1.1 christos offset = (unsigned)(dso->primary.payload - message_bytes); // difference can never be greater than sizeof(message->wire).
451 1.1 christos max = offset + dso->primary.length;
452 1.1 christos while (offset < max) {
453 1.1 christos if (!dns_rr_parse(&rr, message_bytes, max, &offset, true, true)) {
454 1.1 christos // Should have emitted an error earlier
455 1.1 christos break;
456 1.1 christos }
457 1.1 christos test_dns_push_update(push_state, &rr);
458 1.1 christos dns_name_free(rr.name);
459 1.1 christos rr.name = NULL;
460 1.1 christos dns_rrdata_free(&rr);
461 1.1 christos }
462 1.1 christos
463 1.1 christos test_dns_push_satisfied_check(push_state);
464 1.1 christos break;
465 1.1 christos
466 1.1 christos case kDSOType_NoPrimaryTLV: // No Primary TLV
467 1.1 christos if (response) {
468 1.1 christos bool subscribe_acked = false;
469 1.1 christos for (int i = 0; i < push_state->num_subscribe_xids; i++) {
470 1.1 christos if (message->wire.id == htons(push_state->subscribe_xids[i])) {
471 1.1 christos int rcode = dns_rcode_get(&message->wire);
472 1.1 christos INFO("DNS Push Subscribe response from server, rcode = %d", rcode);
473 1.1 christos if (rcode != dns_rcode_noerror) {
474 1.1 christos TEST_FAIL_STATUS(push_state->test_state, "subscribe for %x failed",
475 1.1 christos push_state->subscribe_xids[i]);
476 1.1 christos }
477 1.1 christos subscribe_acked = true;
478 1.1 christos }
479 1.1 christos }
480 1.1 christos if (subscribe_acked) {
481 1.1 christos } else if (message->wire.id == push_state->keepalive_xid) {
482 1.1 christos int rcode = dns_rcode_get(&message->wire);
483 1.1 christos INFO("DNS Keepalive response from server, rcode = %d", rcode);
484 1.1 christos exit(0);
485 1.1 christos } else {
486 1.1 christos int rcode = dns_rcode_get(&message->wire);
487 1.1 christos INFO("Unexpected DSO response from server, rcode = %d", rcode);
488 1.1 christos }
489 1.1 christos } else {
490 1.1 christos INFO("DSO request with no primary TLV.");
491 1.1 christos exit(1);
492 1.1 christos }
493 1.1 christos break;
494 1.1 christos
495 1.1 christos default:
496 1.1 christos INFO("dso_message: unexpected primary TLV %d", dso->primary.opcode);
497 1.1 christos dso_simple_response(push_state->dso_connection, NULL, &message->wire, dns_rcode_dsotypeni);
498 1.1 christos break;
499 1.1 christos }
500 1.1 christos }
501 1.1 christos
502 1.1 christos static void
503 1.1 christos test_dns_push_dso_event_callback(void *context, void *event_context, dso_state_t *dso, dso_event_type_t eventType)
504 1.1 christos {
505 1.1 christos push_test_state_t *push_state = context;
506 1.1 christos
507 1.1 christos message_t *message;
508 1.1 christos dso_query_receive_context_t *response_context;
509 1.1 christos dso_disconnect_context_t *disconnect_context;
510 1.1 christos
511 1.1 christos switch(eventType)
512 1.1 christos {
513 1.1 christos case kDSOEventType_DNSMessage:
514 1.1 christos // We shouldn't get here because we already handled any DNS messages
515 1.1 christos message = event_context;
516 1.1 christos INFO("DNS Message (opcode=%d) received from " PRI_S_SRP, dns_opcode_get(&message->wire),
517 1.1 christos dso->remote_name);
518 1.1 christos break;
519 1.1 christos case kDSOEventType_DNSResponse:
520 1.1 christos // We shouldn't get here because we already handled any DNS messages
521 1.1 christos message = event_context;
522 1.1 christos INFO("DNS Response (opcode=%d) received from " PRI_S_SRP, dns_opcode_get(&message->wire),
523 1.1 christos dso->remote_name);
524 1.1 christos break;
525 1.1 christos case kDSOEventType_DSOMessage:
526 1.1 christos INFO("DSO Message (Primary TLV=%d) received from " PRI_S_SRP,
527 1.1 christos dso->primary.opcode, dso->remote_name);
528 1.1 christos message = event_context;
529 1.1 christos test_dns_push_dso_message(push_state, message, dso, false);
530 1.1 christos break;
531 1.1 christos case kDSOEventType_DSOResponse:
532 1.1 christos INFO("DSO Response (Primary TLV=%d) received from " PRI_S_SRP,
533 1.1 christos dso->primary.opcode, dso->remote_name);
534 1.1 christos response_context = event_context;
535 1.1 christos message = response_context->message_context;
536 1.1 christos test_dns_push_dso_message(push_state, message, dso, true);
537 1.1 christos break;
538 1.1 christos
539 1.1 christos case kDSOEventType_Finalize:
540 1.1 christos INFO("Finalize");
541 1.1 christos break;
542 1.1 christos
543 1.1 christos case kDSOEventType_Connected:
544 1.1 christos INFO("Connected to " PRI_S_SRP, dso->remote_name);
545 1.1 christos break;
546 1.1 christos
547 1.1 christos case kDSOEventType_ConnectFailed:
548 1.1 christos INFO("Connection to " PRI_S_SRP " failed", dso->remote_name);
549 1.1 christos break;
550 1.1 christos
551 1.1 christos case kDSOEventType_Disconnected:
552 1.1 christos INFO("Connection to " PRI_S_SRP " disconnected", dso->remote_name);
553 1.1 christos if (dso == push_state->disconnect_expected) {
554 1.1 christos INFO("remote end disconnected as expected.");
555 1.1 christos exit(0);
556 1.1 christos }
557 1.1 christos break;
558 1.1 christos case kDSOEventType_ShouldReconnect:
559 1.1 christos INFO("Connection to " PRI_S_SRP " should reconnect (not for a server)", dso->remote_name);
560 1.1 christos break;
561 1.1 christos case kDSOEventType_Inactive:
562 1.1 christos INFO("Inactivity timer went off, closing connection.");
563 1.1 christos break;
564 1.1 christos case kDSOEventType_Keepalive:
565 1.1 christos INFO("should send a keepalive now.");
566 1.1 christos break;
567 1.1 christos case kDSOEventType_KeepaliveRcvd:
568 1.1 christos if (!push_state->push_subscribe_sent && !push_state->need_service) {
569 1.1 christos test_dns_push_send_appropriate_subscribe(push_state);
570 1.1 christos } else {
571 1.1 christos push_state->have_keepalive_response = true;
572 1.1 christos }
573 1.1 christos INFO("keepalive received.");
574 1.1 christos break;
575 1.1 christos case kDSOEventType_RetryDelay:
576 1.1 christos disconnect_context = event_context;
577 1.1 christos INFO("retry delay received, %d seconds", disconnect_context->reconnect_delay);
578 1.1 christos test_dns_push_handle_retry_delay(push_state, dso, disconnect_context->reconnect_delay);
579 1.1 christos break;
580 1.1 christos }
581 1.1 christos }
582 1.1 christos
583 1.1 christos static void
584 1.1 christos test_dns_push_send_push_subscribe(push_test_state_t *push_state, const char *name, int rrtype)
585 1.1 christos {
586 1.1 christos struct iovec iov;
587 1.1 christos
588 1.1 christos dns_wire_t dns_message;
589 1.1 christos uint8_t *buffer = (uint8_t *)&dns_message;
590 1.1 christos dns_towire_state_t towire;
591 1.1 christos dso_message_t message;
592 1.1 christos int i = push_state->num_subscribe_xids;
593 1.1 christos if (i >= SUBSCRIBE_LIMIT) {
594 1.1 christos TEST_FAIL_STATUS(push_state->test_state, "subscribe xid limit reached: %d", i);
595 1.1 christos }
596 1.1 christos push_state->num_subscribe_xids++;
597 1.1 christos
598 1.1 christos if (push_state->test_dns_push) {
599 1.1 christos // DNS Push subscription
600 1.1 christos dso_make_message(&message, buffer, sizeof(dns_message), push_state->dso_connection->dso, false, false, 0, 0, NULL);
601 1.1 christos
602 1.1 christos push_state->subscribe_xids[i] = ntohs(dns_message.id);
603 1.1 christos INFO("push subscribe for %s, rrtype %d, xid %x, num %d", name, rrtype, push_state->subscribe_xids[i], i);
604 1.1 christos memset(&towire, 0, sizeof(towire));
605 1.1 christos towire.p = &buffer[DNS_HEADER_SIZE];
606 1.1 christos towire.lim = towire.p + (sizeof(dns_message) - DNS_HEADER_SIZE);
607 1.1 christos towire.message = &dns_message;
608 1.1 christos dns_u16_to_wire(&towire, kDSOType_DNSPushSubscribe);
609 1.1 christos dns_rdlength_begin(&towire);
610 1.1 christos dns_full_name_to_wire(NULL, &towire, name);
611 1.1 christos dns_u16_to_wire(&towire, rrtype);
612 1.1 christos dns_u16_to_wire(&towire, dns_qclass_in);
613 1.1 christos dns_rdlength_end(&towire);
614 1.1 christos } else {
615 1.1 christos // Regular DNS query
616 1.1 christos memset(&dns_message, 0, sizeof(dns_message));
617 1.1 christos dns_message.id = htons((uint16_t)srp_random16());
618 1.1 christos dns_qr_set(&dns_message, 0); // query
619 1.1 christos dns_opcode_set(&dns_message, dns_opcode_query);
620 1.1 christos int num_questions;
621 1.1 christos if (rrtype == dns_rrtype_srv && push_state->variant == PUSH_TEST_VARIANT_TWO_QUESTIONS) {
622 1.1 christos num_questions = 2;
623 1.1 christos } else {
624 1.1 christos num_questions = 1;
625 1.1 christos }
626 1.1 christos dns_message.qdcount = htons(num_questions);
627 1.1 christos memset(&towire, 0, sizeof(towire));
628 1.1 christos towire.p = &buffer[DNS_HEADER_SIZE];
629 1.1 christos towire.lim = towire.p + (sizeof(dns_message) - DNS_HEADER_SIZE);
630 1.1 christos towire.message = &dns_message;
631 1.1 christos dns_name_pointer_t np;
632 1.1 christos dns_full_name_to_wire(&np, &towire, name);
633 1.1 christos dns_u16_to_wire(&towire, rrtype);
634 1.1 christos dns_u16_to_wire(&towire, dns_qclass_in);
635 1.1 christos if (num_questions == 2) {
636 1.1 christos dns_pointer_to_wire(NULL, &towire, &np);
637 1.1 christos dns_u16_to_wire(&towire, dns_rrtype_txt);
638 1.1 christos dns_u16_to_wire(&towire, dns_qclass_in);
639 1.1 christos }
640 1.1 christos push_state->subscribe_xids[i] = ntohs(dns_message.id);
641 1.1 christos INFO("DNS query for %s, rrtype %d, xid %x, num %d", name, rrtype, push_state->subscribe_xids[i], i);
642 1.1 christos }
643 1.1 christos
644 1.1 christos memset(&iov, 0, sizeof(iov));
645 1.1 christos iov.iov_len = towire.p - buffer;
646 1.1 christos iov.iov_base = buffer;
647 1.1 christos ioloop_send_message(push_state->dso_connection, NULL, &iov, 1);
648 1.1 christos }
649 1.1 christos
650 1.1 christos static void
651 1.1 christos test_dns_push_connected(comm_t *connection, void *context)
652 1.1 christos {
653 1.1 christos push_test_state_t *push_state = context;
654 1.1 christos struct iovec iov;
655 1.1 christos INFO("connected");
656 1.1 christos connection->dso = dso_state_create(false, 3, connection->name, test_dns_push_dso_event_callback,
657 1.1 christos push_state, NULL, push_state->dso_connection);
658 1.1 christos if (connection->dso == NULL) {
659 1.1 christos ERROR("can't create dso state object.");
660 1.1 christos exit(1);
661 1.1 christos }
662 1.1 christos dns_wire_t dns_message;
663 1.1 christos uint8_t *buffer = (uint8_t *)&dns_message;
664 1.1 christos dns_towire_state_t towire;
665 1.1 christos dso_message_t message;
666 1.1 christos dso_make_message(&message, buffer, sizeof(dns_message), connection->dso, false, false, 0, 0, NULL);
667 1.1 christos memset(&towire, 0, sizeof(towire));
668 1.1 christos towire.p = &buffer[DNS_HEADER_SIZE];
669 1.1 christos towire.lim = towire.p + (sizeof(dns_message) - DNS_HEADER_SIZE);
670 1.1 christos towire.message = &dns_message;
671 1.1 christos dns_u16_to_wire(&towire, kDSOType_Keepalive);
672 1.1 christos dns_rdlength_begin(&towire);
673 1.1 christos dns_u32_to_wire(&towire, 100); // Inactivity timeout
674 1.1 christos dns_u32_to_wire(&towire, 100); // Keepalive interval
675 1.1 christos dns_rdlength_end(&towire);
676 1.1 christos
677 1.1 christos memset(&iov, 0, sizeof(iov));
678 1.1 christos iov.iov_len = towire.p - buffer;
679 1.1 christos iov.iov_base = buffer;
680 1.1 christos ioloop_send_message(push_state->dso_connection, NULL, &iov, 1);
681 1.1 christos }
682 1.1 christos
683 1.1 christos static void
684 1.1 christos test_dns_push_disconnected(comm_t *UNUSED connection, void *context, int UNUSED error)
685 1.1 christos {
686 1.1 christos push_test_state_t *push_state = context;
687 1.1 christos TEST_FAIL(push_state->test_state, "push server disconnect.");
688 1.1 christos }
689 1.1 christos
690 1.1 christos static void
691 1.1 christos test_dns_push_datagram_callback(comm_t *connection, message_t *message, void *context)
692 1.1 christos {
693 1.1 christos push_test_state_t *push_state = context;
694 1.1 christos
695 1.1 christos // If this is a DSO message, see if we have a session yet.
696 1.1 christos switch(dns_opcode_get(&message->wire)) {
697 1.1 christos case dns_opcode_query:
698 1.1 christos test_dns_push_dns_response(push_state, message);
699 1.1 christos return;
700 1.1 christos case dns_opcode_dso:
701 1.1 christos if (connection->dso == NULL) {
702 1.1 christos INFO("dso message received with no DSO object on connection " PRI_S_SRP, connection->name);
703 1.1 christos exit(1);
704 1.1 christos }
705 1.1 christos dso_message_received(connection->dso, (uint8_t *)&message->wire, message->length, message);
706 1.1 christos return;
707 1.1 christos }
708 1.1 christos INFO("datagram on connection " PRI_S_SRP " not handled, type = %d.",
709 1.1 christos connection->name, dns_opcode_get(&message->wire));
710 1.1 christos }
711 1.1 christos
712 1.1 christos static void
713 1.1 christos test_dns_push_ready(void *context, uint16_t UNUSED port)
714 1.1 christos {
715 1.1 christos push_test_state_t *push_state = context;
716 1.1 christos test_state_t *state = push_state->test_state;
717 1.1 christos
718 1.1 christos addr_t address;
719 1.1 christos memset(&address, 0, sizeof(address));
720 1.1 christos address.sa.sa_family = AF_INET;
721 1.1 christos address.sin.sin_port = htons(8530);
722 1.1 christos address.sin.sin_addr.s_addr = htonl(0x7f000001); // localhost.
723 1.1 christos // tls, stream, stable, opportunistic
724 1.1 christos push_state->dso_connection = ioloop_connection_create(&address, true, true, true, true,
725 1.1 christos test_dns_push_datagram_callback, test_dns_push_connected,
726 1.1 christos test_dns_push_disconnected, NULL, push_state);
727 1.1 christos TEST_FAIL_CHECK(state, push_state->dso_connection != NULL, "Unable to create dso connection.");
728 1.1 christos }
729 1.1 christos
730 1.1 christos static bool
731 1.1 christos test_listen_longevity_dnssd_proxy_configure(void)
732 1.1 christos {
733 1.1 christos dnssd_proxy_udp_port= 53000;
734 1.1 christos dnssd_proxy_tcp_port = 53000;
735 1.1 christos dnssd_proxy_tls_port = 8530;
736 1.1 christos return true;
737 1.1 christos }
738 1.1 christos
739 1.1 christos static bool
740 1.1 christos test_dns_push_query_callback_intercept(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
741 1.1 christos DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype,
742 1.1 christos uint16_t rrclass, uint16_t rdlen, const void *vrdata, uint32_t ttl, void *context)
743 1.1 christos {
744 1.1 christos dns_service_ref_t *ref = sdRef;
745 1.1 christos const uint8_t *rdata = vrdata;
746 1.1 christos const uint8_t *new_rdata = rdata;
747 1.1 christos uint8_t rdbuf[16];
748 1.1 christos
749 1.1 christos if (rrtype == dns_rrtype_a) {
750 1.1 christos if (rdata[0] == 169 && rdata[1] == 254) {
751 1.1 christos new_rdata = rdbuf;
752 1.1 christos rdbuf[0] = 10;
753 1.1 christos rdbuf[1] = 255;
754 1.1 christos rdbuf[2] = rdata[2];
755 1.1 christos rdbuf[3] = rdata[3];
756 1.1 christos }
757 1.1 christos } else if (rrtype == dns_rrtype_aaaa) {
758 1.1 christos if (rdata[0] == 0xfe && rdata[1] == 0x80) {
759 1.1 christos new_rdata = rdbuf;
760 1.1 christos rdbuf[0] = 0xfc; // Change to unused 0xFC address space
761 1.1 christos memcpy(&rdbuf[1], rdata + 1, 15); // Keep the rest.
762 1.1 christos }
763 1.1 christos }
764 1.1 christos DNSServiceQueryRecordReply callback = ref->callback.query_record_reply;
765 1.1 christos callback(ref, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdlen, new_rdata, ttl, context);
766 1.1 christos return false;
767 1.1 christos }
768 1.1 christos
769 1.1 christos static void test_dns_push_register_example_service(push_test_state_t *push_state);
770 1.1 christos
771 1.1 christos static void
772 1.1 christos test_dns_push_register_callback(const DNSServiceRef UNUSED sd_ref, const DNSServiceFlags UNUSED flags,
773 1.1 christos const DNSServiceErrorType error, const char *const name, const char *const reg_type,
774 1.1 christos const char *const domain, void *const context)
775 1.1 christos {
776 1.1 christos push_test_state_t *push_state = context;
777 1.1 christos test_state_t *state = push_state->test_state;
778 1.1 christos
779 1.1 christos if (error == kDNSServiceErr_ServiceNotRunning) {
780 1.1 christos INFO("example service deregistered due to server exit");
781 1.1 christos dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 10), // 100ms
782 1.1 christos dispatch_get_main_queue(), ^{
783 1.1 christos test_dns_push_register_example_service(push_state);
784 1.1 christos });
785 1.1 christos } else {
786 1.1 christos TEST_FAIL_CHECK_STATUS(state, error == kDNSServiceErr_NoError, "example service registration failed: %d", error);
787 1.1 christos INFO("example service registered successfully -- %s.%s%s", name, reg_type, domain);
788 1.1 christos if (push_state->need_service) {
789 1.1 christos push_state->need_service = false;
790 1.1 christos if (push_state->have_keepalive_response) {
791 1.1 christos test_dns_push_send_appropriate_subscribe(push_state);
792 1.1 christos }
793 1.1 christos }
794 1.1 christos }
795 1.1 christos }
796 1.1 christos
797 1.1 christos static void
798 1.1 christos test_dns_push_register_example_service(push_test_state_t *push_state)
799 1.1 christos {
800 1.1 christos uint8_t txt_data[] = {
801 1.1 christos 0x08, 0x53, 0x49, 0x49, 0x3D, 0x35, 0x30, 0x30, 0x30, 0x07,
802 1.1 christos 0x53, 0x41, 0x49, 0x3D, 0x33, 0x30, 0x30, 0x03, 0x54, 0x3D, 0x30 };
803 1.1 christos
804 1.1 christos int ret = DNSServiceRegister(&push_state->register_ref, 0, kDNSServiceInterfaceIndexAny, NULL,
805 1.1 christos "_example._tcp", NULL, NULL, 12345, sizeof(txt_data), txt_data,
806 1.1 christos test_dns_push_register_callback, push_state);
807 1.1 christos TEST_FAIL_CHECK(push_state->test_state, ret == kDNSServiceErr_NoError, "failed to register example service.");
808 1.1 christos DNSServiceSetDispatchQueue(push_state->register_ref, dispatch_get_main_queue());
809 1.1 christos }
810 1.1 christos
811 1.1 christos static DNSServiceErrorType
812 1.1 christos test_dns_push_crash_intercept(test_state_t *state, DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
813 1.1 christos const char *fullname, uint16_t rrtype, uint16_t rrclass, DNSServiceAttribute const *attr,
814 1.1 christos DNSServiceQueryRecordReply callBack, void UNUSED *context)
815 1.1 christos {
816 1.1 christos dns_service_ref_t *ref = context;
817 1.1 christos DNSServiceErrorType status = DNSServiceQueryRecordWithAttribute(sdRef, flags, interfaceIndex, fullname,
818 1.1 christos rrtype, rrclass, attr, callBack, ref);
819 1.1 christos // We're going to signal the daemon crash on the PTR query.
820 1.1 christos push_test_state_t *push_state = state->context;
821 1.1 christos if (status == kDNSServiceErr_NoError && rrtype == dns_rrtype_ptr) {
822 1.1 christos push_state->ptr_sdref = ref;
823 1.1 christos } else {
824 1.1 christos if (push_state->num_txns < TXN_LIMIT) {
825 1.1 christos push_state->txns[push_state->num_txns++] = ref;
826 1.1 christos }
827 1.1 christos }
828 1.1 christos return status;
829 1.1 christos }
830 1.1 christos
831 1.1 christos void
832 1.1 christos test_dns_push(test_state_t *next_test, int variant)
833 1.1 christos {
834 1.1 christos extern srp_server_t *srp_servers;
835 1.1 christos test_state_t *state = NULL;
836 1.1 christos bool register_example_service = false;
837 1.1 christos bool push = true;
838 1.1 christos if (variant == PUSH_TEST_VARIANT_HARDWIRED) {
839 1.1 christos const char *hardwired =
840 1.1 christos " The goal of this test is to create DNS Push connection to the test server and attempt to\n"
841 1.1 christos " look up a name that goes through the hardwired query path. If we get a response, the test\n"
842 1.1 christos " succeeded.";
843 1.1 christos state = test_state_create(srp_servers, "DNS Push Hardwired test", NULL, hardwired, NULL);
844 1.1 christos } else if (variant == PUSH_TEST_VARIANT_MDNS) {
845 1.1 christos const char *mdns =
846 1.1 christos " The goal of this test is to create DNS Push connection to the test server and attempt to\n"
847 1.1 christos " look up a name that goes through the local (mDNS) query path. If we get a response, the test\n"
848 1.1 christos " succeeded.";
849 1.1 christos state = test_state_create(srp_servers, "DNS Push Local test", NULL, mdns, NULL);
850 1.1 christos register_example_service = true;
851 1.1 christos } else if (variant == PUSH_TEST_VARIANT_DNS_MDNS) {
852 1.1 christos const char *mdns =
853 1.1 christos " The goal of this test is to create DSO connection to the test server and send a DNS query to\n"
854 1.1 christos " look up a name that goes through the local (mDNS) query path. If we get a response, the test\n"
855 1.1 christos " succeeded.";
856 1.1 christos state = test_state_create(srp_servers, "DNS Local test", NULL, mdns, NULL);
857 1.1 christos register_example_service = true;
858 1.1 christos push = false;
859 1.1 christos variant = PUSH_TEST_VARIANT_MDNS;
860 1.1 christos } else if (variant == PUSH_TEST_VARIANT_TWO_QUESTIONS) {
861 1.1 christos const char *two =
862 1.1 christos " The goal of this test is to create DSO connection to the test server and send a DNS query with\n"
863 1.1 christos " two questions on the same name, for a TXT and an SRV record. We will register a matter service to\n"
864 1.1 christos " discover. If we get a well-formed response with answers for both service types, the test\n"
865 1.1 christos " succeeded.";
866 1.1 christos state = test_state_create(srp_servers, "DNS Local two-question test", NULL, two, NULL);
867 1.1 christos register_example_service = true;
868 1.1 christos push = false;
869 1.1 christos variant = PUSH_TEST_VARIANT_TWO_QUESTIONS;
870 1.1 christos } else if (variant == PUSH_TEST_VARIANT_DNS_HARDWIRED) {
871 1.1 christos const char *hardwired =
872 1.1 christos " The goal of this test is to create DSO connection to the test server and send a DNS query that\n"
873 1.1 christos " looks up a name that goes through the hardwired query path. If we get a response, the test\n"
874 1.1 christos " succeeded.";
875 1.1 christos state = test_state_create(srp_servers, "DNS query Hardwired test", NULL, hardwired, NULL);
876 1.1 christos push = false;
877 1.1 christos variant = PUSH_TEST_VARIANT_HARDWIRED;
878 1.1 christos } else if (variant == PUSH_TEST_VARIANT_DNS_CRASH) {
879 1.1 christos const char *crash =
880 1.1 christos " The goal of this test is to create DSO connection to the test server and attempt to\n"
881 1.1 christos " look up a name that goes through the local (mDNS) query path. Once we have a result, we fake\n"
882 1.1 christos " an mDNSResponder crash and make sure the query is successfully restarted.";
883 1.1 christos state = test_state_create(srp_servers, "DNS query daemon crash test", NULL, crash, NULL);
884 1.1 christos state->query_record_intercept = test_dns_push_crash_intercept;
885 1.1 christos register_example_service = true;
886 1.1 christos variant = PUSH_TEST_VARIANT_DAEMON_CRASH;
887 1.1 christos push = false;
888 1.1 christos } else if (variant == PUSH_TEST_VARIANT_DAEMON_CRASH) {
889 1.1 christos const char *crash =
890 1.1 christos " The goal of this test is to create DNS Push connection to the test server and attempt to\n"
891 1.1 christos " look up a name that goes through the local (mDNS) query path. Once we have a result, we fake\n"
892 1.1 christos " an mDNSResponder crash and make sure the query is successfully restarted.";
893 1.1 christos state = test_state_create(srp_servers, "DNS Push daemon crash test", NULL, crash, NULL);
894 1.1 christos state->query_record_intercept = test_dns_push_crash_intercept;
895 1.1 christos register_example_service = true;
896 1.1 christos }
897 1.1 christos state->next = next_test;
898 1.1 christos push_test_state_t *push_state = calloc(1, sizeof (*push_state));
899 1.1 christos TEST_FAIL_CHECK(state, push_state != NULL, "no memory for test-specific state.");
900 1.1 christos state->context = push_state;
901 1.1 christos push_state->test_state = state;
902 1.1 christos push_state->variant = variant;
903 1.1 christos push_state->test_dns_push = push;
904 1.1 christos
905 1.1 christos // Might as well always test
906 1.1 christos push_state->push_unsubscribe = true;
907 1.1 christos
908 1.1 christos srp_test_dnssd_tls_listener_ready = test_dns_push_ready;
909 1.1 christos srp_test_tls_listener_context = push_state;
910 1.1 christos srp_test_dso_message_finished = test_dns_push_dso_message_finished;
911 1.1 christos
912 1.1 christos srp_proxy_init("local");
913 1.1 christos srp_test_enable_stub_router(state, srp_servers);
914 1.1 christos state->dns_service_query_callback_intercept = test_dns_push_query_callback_intercept;
915 1.1 christos state->dnssd_proxy_configurer = test_listen_longevity_dnssd_proxy_configure;
916 1.1 christos TEST_FAIL_CHECK(state, init_dnssd_proxy(srp_servers), "failed to setup dnssd-proxy");
917 1.1 christos
918 1.1 christos if (register_example_service) {
919 1.1 christos push_state->need_service = true;
920 1.1 christos test_dns_push_register_example_service(push_state);
921 1.1 christos }
922 1.1 christos
923 1.1 christos // Test should not take longer than ten seconds.
924 1.1 christos srp_test_state_add_timeout(state, 20);
925 1.1 christos }
926 1.1 christos
927 1.1 christos // Local Variables:
928 1.1 christos // mode: C
929 1.1 christos // tab-width: 4
930 1.1 christos // c-file-style: "bsd"
931 1.1 christos // c-basic-offset: 4
932 1.1 christos // fill-column: 108
933 1.1 christos // indent-tabs-mode: nil
934 1.1 christos // End:
935