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