1 /* srp-ioloop.c 2 * 3 * Copyright (c) 2019-2024 Apple Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 * srp host API implementation for Posix using ioloop primitives. 18 */ 19 20 #include <stdio.h> 21 #include <arpa/inet.h> 22 #include <string.h> 23 #include <stdlib.h> 24 #include <unistd.h> 25 #include <dns_sd.h> 26 #include <errno.h> 27 #include <fcntl.h> 28 29 #include "srp.h" 30 #include "srp-api.h" 31 #include "dns-msg.h" 32 #include "srp-crypto.h" 33 #include "ioloop.h" 34 #include "dso-utils.h" 35 #include "dso.h" 36 37 #include "cti-services.h" 38 39 static int lease_time = 0; 40 static bool random_leases = false; 41 static bool delete_registrations = false; 42 static bool use_thread_services = false; 43 static bool change_txt_record = false; 44 static bool new_ip_dup = false; 45 static bool dup_instance_name = false; 46 static bool random_txt_record = false; 47 static bool remove_added_service = false; 48 static bool let_added_service_expire = false; 49 static bool expecting_second_add = true; 50 static int num_clients = 1; 51 static int bogusify_signatures = false; 52 static int bogus_remove = false; 53 static int push_hardwired = false; 54 static int push_query = false; 55 static int push_unsubscribe = false; 56 static bool push_subscribe_sent = false; 57 static uint16_t dns_push_subscribe_xid; 58 static int push_send_bogus_keepalive = false; 59 static int push_exhaust = false; 60 static bool test_subtypes = false; 61 static bool test_renew_subtypes = false; 62 static bool test_diff_subtypes = false; 63 static uint8_t first_bogus_address[] = { 198, 51, 100, 1 }; // RFC 5737 documentation prefix TEST-NET-2 64 static uint8_t second_bogus_address[] = { 203, 0, 113, 1 }; // RFC 5737 documentation prefix TEST-NET-3 65 static bool host_only = false; 66 extern bool zero_addresses; 67 static bool expire_instance = false; 68 static bool test_bad_sig_time = false; 69 static bool do_srp = true; 70 71 const uint64_t thread_enterprise_number = 52627; 72 73 cti_connection_t thread_service_context; 74 75 static const char *interface_name = NULL; 76 static wakeup_t *wait_for_remote_disconnect = NULL; 77 static dso_state_t *disconnect_expected = NULL; 78 os_log_t global_os_log; 79 80 #define SRP_IO_CONTEXT_MAGIC 0xFEEDFACEFADEBEEFULL // BEES! Everybody gets BEES! 81 typedef struct io_context { 82 uint64_t magic_cookie1; 83 wakeup_t *wakeup; 84 void *NONNULL srp_context; 85 comm_t *NULLABLE connection; 86 srp_wakeup_callback_t wakeup_callback; 87 srp_datagram_callback_t datagram_callback; 88 bool deactivated, closed; 89 uint64_t magic_cookie2; 90 } io_context_t; 91 wakeup_t *remove_wakeup; 92 93 typedef struct srp_client { 94 DNSServiceRef sdref; 95 int index; 96 wakeup_t *wakeup; 97 char *name; 98 bool updated_txt_record; 99 } srp_client_t; 100 101 static void start_push_query(void); 102 static void send_push_unsubscribe(void); 103 static void send_push_subscribe(void); 104 105 static int 106 validate_io_context(io_context_t **dest, void *src) 107 { 108 io_context_t *context = src; 109 if (context->magic_cookie1 == SRP_IO_CONTEXT_MAGIC && 110 context->magic_cookie2 == SRP_IO_CONTEXT_MAGIC) 111 { 112 *dest = context; 113 return kDNSServiceErr_NoError; 114 } 115 return kDNSServiceErr_BadState; 116 } 117 118 static void 119 datagram_callback(comm_t *connection, message_t *message, void *context) 120 { 121 (void)connection; 122 io_context_t *io_context = context; 123 if (!io_context->deactivated) { 124 io_context->datagram_callback(io_context->srp_context, 125 &message->wire, message->length); 126 } 127 } 128 129 static void 130 wakeup_callback(void *context) 131 { 132 io_context_t *io_context; 133 if (validate_io_context(&io_context, context) == kDNSServiceErr_NoError) { 134 INFO("wakeup on context %p srp_context %p", io_context, io_context->srp_context); 135 if (!io_context->deactivated) { 136 io_context->wakeup_callback(io_context->srp_context); 137 } 138 } else { 139 INFO("wakeup with invalid context: %p", context); 140 } 141 } 142 143 int 144 srp_deactivate_udp_context(void *host_context, void *in_context) 145 { 146 io_context_t *io_context; 147 int err; 148 (void)host_context; 149 150 err = validate_io_context(&io_context, in_context); 151 if (err == kDNSServiceErr_NoError) { 152 if (io_context->wakeup != NULL) { 153 ioloop_cancel_wake_event(io_context->wakeup); 154 ioloop_wakeup_release(io_context->wakeup); 155 } 156 // Deactivate can be called with a connection still active; in this case, we need to wait for the 157 // cancel event before freeing the structure. Otherwise, we can free it immediately. 158 if (io_context->connection != NULL) { 159 ioloop_comm_cancel(io_context->connection); 160 io_context->deactivated = true; 161 io_context->closed = true; 162 } else { 163 free(io_context); 164 } 165 } 166 return err; 167 } 168 169 int 170 srp_disconnect_udp(void *context) 171 { 172 io_context_t *io_context; 173 int err; 174 175 err = validate_io_context(&io_context, context); 176 if (err == kDNSServiceErr_NoError) { 177 if (io_context->connection) { 178 ioloop_comm_cancel(io_context->connection); 179 } 180 io_context->closed = true; 181 } 182 return err; 183 } 184 185 static void 186 srp_udp_context_canceled(comm_t *UNUSED NONNULL comm, void *NULLABLE context, int UNUSED error) 187 { 188 io_context_t *io_context = context; 189 190 if (io_context->connection) { 191 ioloop_comm_release(io_context->connection); 192 io_context->connection = NULL; 193 } 194 if (io_context->deactivated) { 195 free(io_context); 196 } 197 } 198 199 int 200 srp_connect_udp(void *context, const uint8_t *port, uint16_t address_type, const uint8_t *address, uint16_t addrlen) 201 { 202 io_context_t *io_context; 203 addr_t remote; 204 int err; 205 206 err = validate_io_context(&io_context, context); 207 if (err == kDNSServiceErr_NoError) { 208 if (io_context->connection) { 209 ERROR("srp_connect_udp called with non-null I/O context."); 210 return kDNSServiceErr_Invalid; 211 } 212 213 if (address_type == dns_rrtype_a) { 214 if (addrlen != 4) { 215 return kDNSServiceErr_Invalid; 216 } 217 remote.sa.sa_family = AF_INET; 218 memcpy(&remote.sin.sin_addr, address, addrlen); 219 #ifndef NOT_HAVE_SA_LEN 220 remote.sa.sa_len = sizeof remote.sin; 221 #endif 222 memcpy(&remote.sin.sin_port, port, 2); 223 } else { 224 if (addrlen != 16) { 225 return kDNSServiceErr_Invalid; 226 } 227 remote.sa.sa_family = AF_INET6; 228 memcpy(&remote.sin6.sin6_addr, address, addrlen); 229 #ifndef NOT_HAVE_SA_LEN 230 remote.sa.sa_len = sizeof remote.sin; 231 #endif 232 memcpy(&remote.sin6.sin6_port, port, 2); 233 } 234 235 io_context->connection = ioloop_connection_create(&remote, false, false, false, true, datagram_callback, 236 NULL, srp_udp_context_canceled, NULL, io_context); 237 if (io_context->connection == NULL) { 238 return kDNSServiceErr_NoMemory; 239 } 240 } 241 return err; 242 } 243 244 int 245 srp_make_udp_context(void *host_context, void **p_context, srp_datagram_callback_t callback, void *context) 246 { 247 (void)host_context; 248 249 io_context_t *io_context = calloc(1, sizeof *io_context); 250 if (io_context == NULL) { 251 return kDNSServiceErr_NoMemory; 252 } 253 io_context->magic_cookie1 = io_context->magic_cookie2 = SRP_IO_CONTEXT_MAGIC; 254 io_context->datagram_callback = callback; 255 io_context->srp_context = context; 256 257 io_context->wakeup = ioloop_wakeup_create(); 258 if (io_context->wakeup == NULL) { 259 free(io_context); 260 return kDNSServiceErr_NoMemory; 261 } 262 263 *p_context = io_context; 264 return kDNSServiceErr_NoError; 265 } 266 267 int 268 srp_set_wakeup(void *host_context, void *context, int milliseconds, srp_wakeup_callback_t callback) 269 { 270 int err; 271 io_context_t *io_context; 272 (void)host_context; 273 274 err = validate_io_context(&io_context, context); 275 if (err == kDNSServiceErr_NoError) { 276 io_context->wakeup_callback = callback; 277 INFO("srp_set_wakeup on context %p, srp_context %p", io_context, io_context->srp_context); 278 ioloop_add_wake_event(io_context->wakeup, io_context, wakeup_callback, NULL, milliseconds); 279 } 280 return err; 281 } 282 283 int 284 srp_cancel_wakeup(void *host_context, void *context) 285 { 286 int err; 287 io_context_t *io_context; 288 (void)host_context; 289 290 err = validate_io_context(&io_context, context); 291 if (err == kDNSServiceErr_NoError) { 292 ioloop_cancel_wake_event(io_context->wakeup); 293 } 294 return err; 295 } 296 297 int 298 srp_send_datagram(void *host_context, void *context, void *message, size_t message_length) 299 { 300 int err; 301 struct iovec iov; 302 io_context_t *io_context; 303 (void)host_context; 304 305 memset(&iov, 0, sizeof iov); 306 iov.iov_base = message; 307 iov.iov_len = message_length; 308 309 if (bogusify_signatures) { 310 ((uint8_t *)message)[message_length - 10] = ~(((uint8_t *)message)[message_length - 10]); 311 } 312 313 err = validate_io_context(&io_context, context); 314 if (err == kDNSServiceErr_NoError) { 315 if (io_context->connection == NULL) { 316 return kDNSServiceErr_DefunctConnection; 317 } 318 if (!ioloop_send_message(io_context->connection, message, &iov, 1)) { 319 return kDNSServiceErr_Unknown; 320 } 321 } 322 return err; 323 } 324 325 uint32_t 326 srp_timenow(void) 327 { 328 time_t now = time(NULL); 329 if (test_bad_sig_time) { 330 return (uint32_t)(now - 10000); 331 } 332 return (uint32_t)now; 333 } 334 335 static void 336 interface_callback(srp_server_t *UNUSED NULLABLE server_state, void *context, const char *NONNULL name, 337 const addr_t *NONNULL address, const addr_t *NONNULL netmask, 338 uint32_t flags, enum interface_address_change event_type) 339 { 340 bool drop = false; 341 uint8_t *rdata; 342 uint16_t rdlen; 343 uint16_t rrtype; 344 cti_service_vec_t *cti_services = context; 345 346 (void)netmask; 347 (void)index; 348 (void)event_type; 349 350 if (address->sa.sa_family == AF_INET) { 351 rrtype = dns_rrtype_a; 352 rdata = (uint8_t *)&address->sin.sin_addr; 353 rdlen = 4; 354 355 // Should use IN_LINKLOCAL and IN_LOOPBACK macros here, but for some reason they are not present on 356 // OpenWRT. 357 if (rdata[0] == 127) { 358 drop = true; 359 } else if (rdata[0] == 169 && rdata[1] == 254) { 360 drop = true; 361 } 362 } else if (address->sa.sa_family == AF_INET6) { 363 rrtype = dns_rrtype_aaaa; 364 rdata = (uint8_t *)&address->sin6.sin6_addr; 365 rdlen = 16; 366 if (IN6_IS_ADDR_LOOPBACK(&address->sin6.sin6_addr)) { 367 drop = true; 368 } else if (IN6_IS_ADDR_LINKLOCAL(&address->sin6.sin6_addr)) { 369 drop = true; 370 } 371 } else { 372 return; 373 } 374 if (drop) { 375 if (address->sa.sa_family == AF_INET) { 376 IPv4_ADDR_GEN_SRP(rdata, ipv4_rdata_buf); 377 DEBUG("interface_callback: ignoring " PUB_S_SRP " " PRI_IPv4_ADDR_SRP, name, 378 IPv4_ADDR_PARAM_SRP(rdata, ipv4_rdata_buf)); 379 } else if (address->sa.sa_family == AF_INET6) { 380 SEGMENTED_IPv6_ADDR_GEN_SRP(rdata, ipv6_rdata_buf); 381 DEBUG("interface_callback: ignoring " PUB_S_SRP " " PRI_SEGMENTED_IPv6_ADDR_SRP, name, 382 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdata, ipv6_rdata_buf)); 383 } else { 384 INFO("ignoring with non-v4/v6 address" PUB_S_SRP, name); 385 } 386 return; 387 } 388 389 if (address->sa.sa_family == AF_INET) { 390 IPv4_ADDR_GEN_SRP(rdata, ipv4_rdata_buf); 391 DEBUG("interface_callback: " PUB_S_SRP " " PRI_IPv4_ADDR_SRP " %x", name, 392 IPv4_ADDR_PARAM_SRP(rdata, ipv4_rdata_buf), flags); 393 } else if (address->sa.sa_family == AF_INET6) { 394 SEGMENTED_IPv6_ADDR_GEN_SRP(rdata, ipv6_rdata_buf); 395 DEBUG("interface_callback: " PUB_S_SRP " " PRI_SEGMENTED_IPv6_ADDR_SRP " %x", name, 396 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdata, ipv6_rdata_buf), flags); 397 } else { 398 DEBUG("interface_callback: " PUB_S_SRP "<none IPv4/IPv6 address> %x", name, flags); 399 } 400 401 // This is a workaround for a bug in the utun0 code, where packets sent to the IP address of the local 402 // thread interface are dropped and do not reach the SRP server. To address this, if we find a service 403 // that is on a local IPv6 address, we replace the address with ::1. 404 if (cti_services != NULL && rrtype == dns_rrtype_aaaa) { 405 size_t i; 406 for (i = 0; i < cti_services->num; i++) { 407 cti_service_t *cti_service = cti_services->services[i]; 408 // Look for SRP service advertisements only. 409 if (IS_SRP_SERVICE(cti_service)) { 410 // Local IP address? 411 if (!memcmp(cti_service->server, rdata, 16)) { 412 // :: 413 memset(cti_service->server, 0, 15); 414 // 1 415 cti_service->server[15] = 1; 416 } 417 } 418 } 419 } 420 421 srp_add_interface_address(rrtype, rdata, rdlen); 422 } 423 424 static void 425 remove_callback(void *context) 426 { 427 srp_client_t *client = context; 428 if (bogus_remove) { 429 srp_set_hostname("bogus-api-test", NULL); 430 } 431 srp_deregister(client); 432 } 433 434 static void 435 second_register_callback(DNSServiceRef sdref, DNSServiceFlags flags, DNSServiceErrorType errorCode, 436 const char *name, const char *regtype, const char *domain, void *context) 437 { 438 srp_client_t *client = context; 439 440 (void)regtype; 441 (void)flags; 442 (void)name; 443 (void)regtype; 444 (void)domain; 445 INFO("Second Register Reply for %s: %d", client->name, errorCode); 446 447 if (errorCode == kDNSServiceErr_NoError) { 448 if (expecting_second_add) { 449 expecting_second_add = false; 450 if (remove_added_service) { 451 srp_deregister_instance(sdref); 452 srp_network_state_stable(NULL); 453 } else if (let_added_service_expire) { 454 DNSServiceRefDeallocate(sdref); 455 } 456 } else { 457 // Test succeeded 458 exit(0); 459 } 460 } else { 461 // Test failed 462 exit(1); 463 } 464 } 465 466 467 static void 468 register_callback(DNSServiceRef sdref, DNSServiceFlags flags, DNSServiceErrorType errorCode, 469 const char *name, const char *regtype, const char *domain, void *context) 470 { 471 srp_client_t *client = context; 472 473 (void)regtype; 474 (void)flags; 475 (void)name; 476 (void)regtype; 477 (void)domain; 478 INFO("Register Reply for %s: %d", client->name, errorCode); 479 480 if (errorCode == kDNSServiceErr_NoError) { 481 if ((change_txt_record && !client->updated_txt_record) || expire_instance) { 482 TXTRecordRef txt; 483 const void *txt_data = NULL; 484 uint16_t txt_len = 0; 485 char txt_buf[128]; 486 487 TXTRecordCreate(&txt, sizeof(txt_buf), txt_buf); 488 TXTRecordSetValue(&txt, "foo", 1, "1"); 489 TXTRecordSetValue(&txt, "bar", 3, "1.1"); 490 txt_data = TXTRecordGetBytesPtr(&txt); 491 txt_len = TXTRecordGetLength(&txt); 492 493 if (expire_instance) { 494 char hnbuf[128]; 495 ioloop_strcpy(hnbuf, name, sizeof(hnbuf)); 496 497 // silently let the first expire. This is just going to leak the data, but since this is a one-shot test 498 // that's not an actual problem. 499 DNSServiceRefDeallocate(sdref); 500 501 DNSServiceRef nsdref; 502 expecting_second_add = true; 503 // register a second instance 504 int err = DNSServiceRegister(&nsdref, 0, 0, hnbuf, "_second._tcp,foo", 0, 0, htons(1234), 505 txt_len, txt_data, second_register_callback, client); 506 if (err != kDNSServiceErr_NoError) { 507 ERROR("second DNSServiceRegister failed: %d", err); 508 exit(1); 509 } 510 } else { 511 (void)DNSServiceUpdateRecord(sdref, NULL, 0, txt_len, txt_data, 0); 512 client->updated_txt_record = true; 513 } 514 srp_network_state_stable(NULL); 515 return; 516 } 517 518 if (delete_registrations) { 519 client->wakeup = ioloop_wakeup_create(); 520 if (client->wakeup == NULL) { 521 ERROR("Unable to allocate a wakeup for %s.", client->name); 522 exit(1); 523 } 524 525 // Do a remove in five seconds. 526 ioloop_add_wake_event(client->wakeup, client, remove_callback, NULL, 5000); 527 return; 528 } 529 530 if (test_renew_subtypes) { 531 int err = srp_update_service_type(sdref, "_ipps._tcp,othersub", second_register_callback, client); 532 if (err != kDNSServiceErr_NoError) { 533 ERROR("srp_update_service_type failed: %d", err); 534 exit(1); 535 } 536 srp_network_state_stable(NULL); 537 return; 538 } 539 } 540 541 // We get this with the duplicate instance name. In this case, we change the host IP address. This validates 542 // the bit of code in srp-mdns-proxy that removes the added address when the update fails--when we look up the 543 // registered address, we should see only the second bogus address, not the first. 544 if (errorCode == kDNSServiceErr_NameConflict) { 545 char nnbuf[128]; 546 char rtbuf[128]; 547 srp_delete_interface_address(dns_rrtype_a, first_bogus_address, sizeof(first_bogus_address)); 548 srp_add_interface_address(dns_rrtype_a, second_bogus_address, sizeof(second_bogus_address)); 549 ioloop_strcpy(nnbuf, name, sizeof(nnbuf)); 550 ioloop_strcpy(rtbuf, regtype, sizeof(rtbuf)); 551 nnbuf[0] = 'a'; 552 INFO("changing service instance name from " PRI_S_SRP " to " PRI_S_SRP " type " PRI_S_SRP, name, nnbuf, rtbuf); 553 DNSServiceRefDeallocate(sdref); 554 int err = DNSServiceRegister(&sdref, kDNSServiceFlagsNoAutoRename, 0, nnbuf, rtbuf, 0, 0, htons(1234), 555 0, NULL, register_callback, client); 556 if (err != kDNSServiceErr_NoError) { 557 ERROR("DNSServiceRegister rename failed: %d", err); 558 exit(1); 559 } 560 srp_network_state_stable(NULL); 561 } 562 } 563 564 comm_t *dso_connection; 565 typedef struct connection_list connection_list_t; 566 struct connection_list { 567 connection_list_t *next; 568 comm_t *connection; 569 }; 570 connection_list_t *dso_connection_list; 571 uint16_t subscribe_xid; 572 uint16_t keepalive_xid; 573 574 static void 575 send_push_unsubscribe(void) 576 { 577 struct iovec iov; 578 INFO("unsubscribe"); 579 dns_wire_t dns_message; 580 uint8_t *buffer = (uint8_t *)&dns_message; 581 dns_towire_state_t towire; 582 dso_message_t message; 583 if (!push_send_bogus_keepalive) { 584 INFO("unsubscribe"); 585 dso_make_message(&message, buffer, sizeof(dns_message), dso_connection->dso, true, false, 0, 0, NULL); 586 memset(&towire, 0, sizeof(towire)); 587 towire.p = &buffer[DNS_HEADER_SIZE]; 588 towire.lim = towire.p + (sizeof(dns_message) - DNS_HEADER_SIZE); 589 towire.message = &dns_message; 590 dns_u16_to_wire(&towire, kDSOType_DNSPushUnsubscribe); 591 dns_rdlength_begin(&towire); 592 dns_u16_to_wire(&towire, dns_push_subscribe_xid); 593 dns_rdlength_end(&towire); 594 595 memset(&iov, 0, sizeof(iov)); 596 iov.iov_len = towire.p - buffer; 597 iov.iov_base = buffer; 598 ioloop_send_message(dso_connection, NULL, &iov, 1); 599 subscribe_xid = dns_message.id; // We need this to identify the response. 600 } 601 602 // Send a keepalive message so that we can get the response, since the unsubscribe is not a response-requiring request. 603 dso_make_message(&message, buffer, sizeof(dns_message), dso_connection->dso, false, false, 0, 0, NULL); 604 memset(&towire, 0, sizeof(towire)); 605 towire.p = &buffer[DNS_HEADER_SIZE]; 606 towire.lim = towire.p + (sizeof(dns_message) - DNS_HEADER_SIZE); 607 towire.message = &dns_message; 608 dns_u16_to_wire(&towire, kDSOType_Keepalive); 609 dns_rdlength_begin(&towire); 610 dns_u32_to_wire(&towire, 600); 611 dns_u32_to_wire(&towire, 600); 612 dns_rdlength_end(&towire); 613 if (push_send_bogus_keepalive) { 614 INFO("sending bogus keepalive"); 615 // Send a badly formatted message. 616 dns_u32_to_wire(&towire, 0x12345678); 617 } 618 keepalive_xid = dns_message.id; 619 memset(&iov, 0, sizeof(iov)); 620 iov.iov_len = towire.p - buffer; 621 iov.iov_base = buffer; 622 ioloop_send_message(dso_connection, NULL, &iov, 1); 623 } 624 625 static void 626 dso_remote_disconnect_didnt_happen(void *UNUSED context) 627 { 628 INFO("remote disconnect didn't happen"); 629 exit(1); 630 } 631 632 static void 633 handle_retry_delay(dso_state_t *dso, uint32_t delay) 634 { 635 INFO("Got our retry delay, %ums...", delay); 636 wait_for_remote_disconnect = ioloop_wakeup_create(); 637 if (!wait_for_remote_disconnect) { 638 INFO("can't wait for remote disconnect."); 639 exit(1); 640 } 641 // Wait six seconds for remote disconnect, which should happen in five. 642 ioloop_add_wake_event(wait_for_remote_disconnect, NULL, dso_remote_disconnect_didnt_happen, NULL, 6 * 1000); 643 disconnect_expected = dso; 644 } 645 646 static void 647 dso_message(message_t *message, dso_state_t *dso, bool response) 648 { 649 #if PRINT_TO_STDERR 650 char name[DNS_MAX_NAME_SIZE_ESCAPED + 1]; 651 char ptrname[DNS_MAX_NAME_SIZE_ESCAPED + 1]; 652 #endif 653 unsigned offset, max; 654 dns_rr_t rr; 655 uint8_t *message_bytes; 656 657 switch(dso->primary.opcode) { 658 case kDSOType_RetryDelay: 659 if (response) { 660 INFO("server sent a retry delay TLV as a response."); 661 exit(1); 662 } 663 dso_retry_delay(dso, &message->wire); 664 break; 665 666 case kDSOType_Keepalive: 667 if (response) { 668 INFO("Keepalive response from server, rcode = %d", dns_rcode_get(&message->wire)); 669 exit(0); 670 } else { 671 INFO("Keepalive from server"); 672 } 673 if (!push_subscribe_sent) { 674 send_push_subscribe(); 675 push_subscribe_sent = true; 676 } 677 break; 678 679 case kDSOType_DNSPushSubscribe: 680 if (response) { 681 // This is a protocol error--the response isn't supposed to contain a primary TLV. 682 INFO("DNS Push response from server, rcode = %d", dns_rcode_get(&message->wire)); 683 exit(1); 684 } else { 685 INFO("Unexpected DNS Push request from server, rcode = %d", dns_rcode_get(&message->wire)); 686 } 687 break; 688 689 case kDSOType_DNSPushUpdate: 690 // DNS Push Updates are never responses. 691 // DNS Push updates are compressed, so we can't just parse data out of the primary--we need to align 692 // our parse with the start of the message data. 693 message_bytes = (uint8_t *)message->wire.data; 694 offset = (unsigned)(dso->primary.payload - message_bytes); // difference can never be greater than sizeof(message->wire). 695 max = offset + dso->primary.length; 696 while (offset < max) { 697 if (!dns_rr_parse(&rr, message_bytes, max, &offset, true, true)) { 698 // Should have emitted an error earlier 699 break; 700 } 701 #if PRINT_TO_STDERR 702 dns_name_print(rr.name, name, sizeof(name)); 703 if (rr.type != dns_rrtype_ptr) { 704 fprintf(stderr, "%s: type %u class %u ttl %" PRIu32 "\n", name, rr.type, rr.qclass, rr.ttl); 705 } else { 706 dns_name_print(rr.data.ptr.name, ptrname, sizeof(ptrname)); 707 fprintf(stderr, "%s IN PTR %s\n", name, ptrname); 708 } 709 #endif 710 } 711 if (push_unsubscribe) { 712 send_push_unsubscribe(); 713 } else if (!push_exhaust) { 714 exit(0); 715 } 716 break; 717 718 case kDSOType_NoPrimaryTLV: // No Primary TLV 719 if (response) { 720 if (message->wire.id == subscribe_xid) { 721 int rcode = dns_rcode_get(&message->wire); 722 INFO("DNS Push Subscribe response from server, rcode = %d", rcode); 723 if (rcode != dns_rcode_noerror) { 724 exit(0); 725 } 726 if (push_exhaust) { 727 start_push_query(); 728 } 729 } else if (message->wire.id == keepalive_xid) { 730 int rcode = dns_rcode_get(&message->wire); 731 INFO("DNS Keepalive response from server, rcode = %d", rcode); 732 exit(0); 733 } else { 734 int rcode = dns_rcode_get(&message->wire); 735 INFO("Unexpected DSO response from server, rcode = %d", rcode); 736 } 737 } else { 738 INFO("DSO request with no primary TLV."); 739 exit(1); 740 } 741 break; 742 743 default: 744 INFO("dso_message: unexpected primary TLV %d", dso->primary.opcode); 745 dso_simple_response(dso_connection, NULL, &message->wire, dns_rcode_dsotypeni); 746 break; 747 } 748 } 749 750 static void 751 dso_event_callback(void *UNUSED context, void *event_context, dso_state_t *dso, dso_event_type_t eventType) 752 { 753 message_t *message; 754 dso_query_receive_context_t *response_context; 755 dso_disconnect_context_t *disconnect_context; 756 757 switch(eventType) 758 { 759 case kDSOEventType_DNSMessage: 760 // We shouldn't get here because we already handled any DNS messages 761 message = event_context; 762 INFO("DNS Message (opcode=%d) received from " PRI_S_SRP, dns_opcode_get(&message->wire), 763 dso->remote_name); 764 break; 765 case kDSOEventType_DNSResponse: 766 // We shouldn't get here because we already handled any DNS messages 767 message = event_context; 768 INFO("DNS Response (opcode=%d) received from " PRI_S_SRP, dns_opcode_get(&message->wire), 769 dso->remote_name); 770 break; 771 case kDSOEventType_DSOMessage: 772 INFO("DSO Message (Primary TLV=%d) received from " PRI_S_SRP, 773 dso->primary.opcode, dso->remote_name); 774 message = event_context; 775 dso_message(message, dso, false); 776 break; 777 case kDSOEventType_DSOResponse: 778 INFO("DSO Response (Primary TLV=%d) received from " PRI_S_SRP, 779 dso->primary.opcode, dso->remote_name); 780 response_context = event_context; 781 message = response_context->message_context; 782 dso_message(message, dso, true); 783 break; 784 785 case kDSOEventType_Finalize: 786 INFO("Finalize"); 787 break; 788 789 case kDSOEventType_Connected: 790 INFO("Connected to " PRI_S_SRP, dso->remote_name); 791 break; 792 793 case kDSOEventType_ConnectFailed: 794 INFO("Connection to " PRI_S_SRP " failed", dso->remote_name); 795 break; 796 797 case kDSOEventType_Disconnected: 798 INFO("Connection to " PRI_S_SRP " disconnected", dso->remote_name); 799 if (dso == disconnect_expected) { 800 INFO("remote end disconnected as expected."); 801 exit(0); 802 } 803 break; 804 case kDSOEventType_ShouldReconnect: 805 INFO("Connection to " PRI_S_SRP " should reconnect (not for a server)", dso->remote_name); 806 break; 807 case kDSOEventType_Inactive: 808 INFO("Inactivity timer went off, closing connection."); 809 break; 810 case kDSOEventType_Keepalive: 811 INFO("should send a keepalive now."); 812 break; 813 case kDSOEventType_KeepaliveRcvd: 814 if (!push_subscribe_sent) { 815 send_push_subscribe(); 816 push_subscribe_sent = true; 817 } 818 INFO("keepalive received."); 819 break; 820 case kDSOEventType_RetryDelay: 821 disconnect_context = event_context; 822 INFO("retry delay received, %d seconds", disconnect_context->reconnect_delay); 823 handle_retry_delay(dso, disconnect_context->reconnect_delay); 824 break; 825 } 826 } 827 828 static void 829 send_push_subscribe(void) 830 { 831 struct iovec iov; 832 INFO("have session"); 833 dns_wire_t dns_message; 834 uint8_t *buffer = (uint8_t *)&dns_message; 835 dns_towire_state_t towire; 836 dso_message_t message; 837 dso_make_message(&message, buffer, sizeof(dns_message), dso_connection->dso, false, false, 0, 0, NULL); 838 dns_push_subscribe_xid = ntohs(dns_message.id); 839 memset(&towire, 0, sizeof(towire)); 840 towire.p = &buffer[DNS_HEADER_SIZE]; 841 towire.lim = towire.p + (sizeof(dns_message) - DNS_HEADER_SIZE); 842 towire.message = &dns_message; 843 dns_u16_to_wire(&towire, kDSOType_DNSPushSubscribe); 844 dns_rdlength_begin(&towire); 845 if (push_hardwired) { 846 dns_full_name_to_wire(NULL, &towire, "default.service.arpa"); 847 dns_u16_to_wire(&towire, dns_rrtype_soa); 848 } else { 849 dns_full_name_to_wire(NULL, &towire, "_airplay._tcp.default.service.arpa"); 850 dns_u16_to_wire(&towire, dns_rrtype_ptr); 851 } 852 dns_u16_to_wire(&towire, dns_qclass_in); 853 dns_rdlength_end(&towire); 854 855 memset(&iov, 0, sizeof(iov)); 856 iov.iov_len = towire.p - buffer; 857 iov.iov_base = buffer; 858 ioloop_send_message(dso_connection, NULL, &iov, 1); 859 subscribe_xid = dns_message.id; // We need this to identify the response. 860 } 861 862 static void 863 dso_connected(comm_t *connection, void *UNUSED context) 864 { 865 struct iovec iov; 866 INFO("connected"); 867 connection->dso = dso_state_create(false, 1, connection->name, dso_event_callback, 868 dso_connection, NULL, dso_connection); 869 if (connection->dso == NULL) { 870 ERROR("can't create dso state object."); 871 exit(1); 872 } 873 dns_wire_t dns_message; 874 uint8_t *buffer = (uint8_t *)&dns_message; 875 dns_towire_state_t towire; 876 dso_message_t message; 877 dso_make_message(&message, buffer, sizeof(dns_message), connection->dso, false, false, 0, 0, NULL); 878 memset(&towire, 0, sizeof(towire)); 879 towire.p = &buffer[DNS_HEADER_SIZE]; 880 towire.lim = towire.p + (sizeof(dns_message) - DNS_HEADER_SIZE); 881 towire.message = &dns_message; 882 dns_u16_to_wire(&towire, kDSOType_Keepalive); 883 dns_rdlength_begin(&towire); 884 dns_u32_to_wire(&towire, 100); // Inactivity timeout 885 dns_u32_to_wire(&towire, 100); // Keepalive interval 886 dns_rdlength_end(&towire); 887 888 memset(&iov, 0, sizeof(iov)); 889 iov.iov_len = towire.p - buffer; 890 iov.iov_base = buffer; 891 ioloop_send_message(dso_connection, NULL, &iov, 1); 892 } 893 894 static void 895 dso_disconnected(comm_t *UNUSED connection, void *UNUSED context, int UNUSED error) 896 { 897 fprintf(stderr, "disconnected."); 898 exit(0); 899 } 900 901 static void 902 dso_datagram_callback(comm_t *connection, message_t *message, void *UNUSED context) 903 { 904 // If this is a DSO message, see if we have a session yet. 905 switch(dns_opcode_get(&message->wire)) { 906 case dns_opcode_dso: 907 if (connection->dso == NULL) { 908 INFO("dso message received with no DSO object on connection " PRI_S_SRP, connection->name); 909 exit(1); 910 } 911 dso_message_received(connection->dso, (uint8_t *)&message->wire, message->length, message); 912 return; 913 break; 914 } 915 INFO("datagram on connection " PRI_S_SRP " not handled, type = %d.", 916 connection->name, dns_opcode_get(&message->wire)); 917 } 918 919 static void 920 start_push_query(void) 921 { 922 // If we can (should always be able to) remember the list of connections we've created. 923 if (dso_connection != NULL) { 924 connection_list_t *connection = calloc(1, sizeof (*connection)); 925 if (connection != NULL) { 926 connection->connection = dso_connection; 927 connection->next = dso_connection_list; 928 dso_connection_list = connection; 929 } 930 } 931 932 addr_t address; 933 memset(&address, 0, sizeof(address)); 934 address.sa.sa_family = AF_INET; 935 address.sin.sin_port = htons(853); 936 address.sin.sin_addr.s_addr = htonl(0x7f000001); // localhost. 937 // tls, stream, stable, opportunistic 938 dso_connection = ioloop_connection_create(&address, true, true, true, true, 939 dso_datagram_callback, dso_connected, dso_disconnected, NULL, NULL); 940 if (dso_connection == NULL) { 941 ERROR("Unable to create dso connection."); 942 exit(1); 943 } 944 } 945 946 static void 947 usage(void) 948 { 949 fprintf(stderr, 950 "srp-client [--lease-time <seconds>] [--client-count <client count>] [--server <address>%%<port>]\n" 951 " [--push-query] [--push-unsubscribe]\n" 952 " [--bogus-server-test] [--change-txt-record] [--service-type] [--test-renew-subtypes]\n" 953 " [--random-leases] [--delete-registrations] [--use-thread-services] [--log-stderr]\n" 954 " [--interface <interface name>] [--bogusify-signatures] [--remove-added-service]\n" 955 " [--dup-instance-name] [--service-port <port number>] [--expire-added-service]\n" 956 " [--random-txt-record] [--bogus-remove] [--test-subtypes] [--test-diff-subtypes]\n" 957 " [--new-ip-dup] [--push-exhaust] [--test-bad-sig-time] [--zero-addresses]\n" 958 " [--host-only] [--expire-instance]"); 959 exit(1); 960 } 961 962 963 static void 964 cti_service_list_callback(void *UNUSED context, cti_service_vec_t *services, cti_status_t status) 965 { 966 size_t i; 967 968 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) { 969 INFO("disconnected"); 970 exit(1); 971 } 972 973 if (!new_ip_dup && !zero_addresses) { 974 srp_start_address_refresh(); 975 ioloop_map_interface_addresses(NULL, interface_name, services, interface_callback); 976 } 977 for (i = 0; i < services->num; i++) { 978 cti_service_t *cti_service = services->services[i]; 979 // Look for SRP service advertisements only. 980 if (IS_SRP_SERVICE(cti_service)) { 981 srp_add_server_address(&cti_service->server[16], dns_rrtype_aaaa, cti_service->server, 16); 982 } 983 } 984 if (!new_ip_dup && !zero_addresses) { 985 srp_finish_address_refresh(NULL); 986 } 987 srp_network_state_stable(NULL); 988 } 989 990 int 991 main(int argc, char **argv) 992 { 993 994 uint8_t server_address[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 }; 995 uint8_t bogus_address[16] = { 0xfc,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 }; 996 // { 0x26, 0x20, 0x01, 0x49, 0x00, 0x0f, 0x1a, 0x4d, 0x04, 0xff, 0x61, 0x5a, 0xa2, 0x2a, 0xab, 0xe8 }; 997 int err; 998 DNSServiceRef sdref; 999 int *nump; 1000 char *end; 1001 (void)argc; 1002 (void)argv; 1003 int i; 1004 bool have_server_address = false; 1005 bool log_stderr = false; 1006 char instance_name[128]; 1007 const char *service_type = "_ipps._tcp"; 1008 uint16_t service_port = 0; 1009 bool bogus_server = false; 1010 1011 ioloop_init(); 1012 1013 for (i = 1; i < argc; i++) { 1014 if (!strcmp(argv[i], "--lease-time")) { 1015 nump = &lease_time; 1016 number: 1017 if (i + 1 == argc) { 1018 usage(); 1019 } 1020 *nump = (uint32_t)strtoul(argv[i + 1], &end, 10); 1021 if (end == argv[i + 1] || end[0] != 0) { 1022 usage(); 1023 } 1024 i++; 1025 } else if (!strcmp(argv[i], "--client-count")) { 1026 nump = &num_clients; 1027 goto number; 1028 } else if (!strcmp(argv[i], "--interface")) { 1029 if (i + 1 == argc) { 1030 usage(); 1031 } 1032 interface_name = argv[i + 1]; 1033 i++; 1034 } else if (!strcmp(argv[i], "--server")) { 1035 char *percent; 1036 uint8_t addrbuf[16]; 1037 uint16_t addrtype = dns_rrtype_aaaa; 1038 int addrlen = 16; 1039 1040 if (i + 1 == argc) { 1041 usage(); 1042 } 1043 percent = strchr(argv[i + 1], '%'); 1044 if (percent == NULL || percent[1] == 0) { 1045 usage(); 1046 } 1047 *percent = 0; 1048 percent++; 1049 1050 const unsigned long in_server_port = strtoul(percent, &end, 10); 1051 if (in_server_port > UINT16_MAX || end == percent || end[0] != 0) { 1052 usage(); 1053 } 1054 uint8_t server_port[2]; 1055 server_port[0] = ((uint16_t)in_server_port) >> 8; 1056 server_port[1] = ((uint16_t)in_server_port) & 255; 1057 1058 if (inet_pton(AF_INET6, argv[i + 1], addrbuf) < 1) { 1059 if (inet_pton(AF_INET, argv[i + 1], addrbuf) < 1) { 1060 usage(); 1061 } else { 1062 addrtype = dns_rrtype_a; 1063 addrlen = 4; 1064 } 1065 } 1066 srp_add_server_address(server_port, addrtype, addrbuf, addrlen); 1067 have_server_address = true; 1068 i++; 1069 } else if (!strcmp(argv[i], "--random-leases")) { 1070 random_leases = true; 1071 } else if (!strcmp(argv[i], "--delete-registrations")) { 1072 delete_registrations = true; 1073 } else if (!strcmp(argv[i], "--use-thread-services")) { 1074 use_thread_services = true; 1075 } else if (!strcmp(argv[i], "--dup-instance-name")) { 1076 dup_instance_name = true; 1077 } else if (!strcmp(argv[i], "--new-ip-dup")) { 1078 new_ip_dup = true; 1079 } else if (!strcmp(argv[i], "--log-stderr")) { 1080 log_stderr = true; 1081 OPENLOG("srp-client", true); 1082 } else if (!strcmp(argv[i], "--change-txt-record")) { 1083 change_txt_record = true; 1084 } else if (!strcmp(argv[i], "--random-txt-record")) { 1085 random_txt_record = true; 1086 } else if (!strcmp(argv[i], "--remove-added-service")) { 1087 remove_added_service = true; 1088 } else if (!strcmp(argv[i], "--expire-added-service")) { 1089 let_added_service_expire = true; 1090 } else if (!strcmp(argv[1], "--bogus-server-test")) { 1091 bogus_server = true; 1092 } else if (!strcmp(argv[i], "--bogusify-signatures")) { 1093 bogusify_signatures = true; 1094 } else if (!strcmp(argv[i], "--bogus-remove")) { 1095 bogus_remove = true; 1096 } else if (!strcmp(argv[i], "--push-query")) { 1097 push_query = true; 1098 do_srp = false; 1099 } else if (!strcmp(argv[i], "--push-hardwired")) { 1100 push_query = true; 1101 push_hardwired = true; 1102 push_unsubscribe = true; 1103 do_srp = false; 1104 } else if (!strcmp(argv[i], "--push-unsubscribe")) { 1105 push_query = true; 1106 push_unsubscribe = true; 1107 do_srp = false; 1108 } else if (!strcmp(argv[i], "--push-send-bogus-keepalive")) { 1109 push_query = true; 1110 push_unsubscribe = true; 1111 push_send_bogus_keepalive = true; 1112 do_srp = false; 1113 } else if (!strcmp(argv[i], "--push-exhaust")) { 1114 push_exhaust = true; 1115 do_srp = false; 1116 } else if (!strcmp(argv[i], "--test-subtypes")) { 1117 test_subtypes = true; 1118 } else if (!strcmp(argv[i], "--test-diff-subtypes")) { 1119 test_diff_subtypes = true; 1120 } else if (!strcmp(argv[i], "--test-renew-subtypes")) { 1121 test_renew_subtypes = true; 1122 } else if (!strcmp(argv[i], "--host-only")) { 1123 host_only = true; 1124 } else if (!strcmp(argv[i], "--zero-addresses")) { 1125 zero_addresses = true; 1126 } else if (!strcmp(argv[i], "--expire-instance")) { 1127 expire_instance = true; 1128 } else if (!strcmp(argv[i], "--test-bad-sig-time")) { 1129 test_bad_sig_time = true; 1130 } else if (!strcmp(argv[i], "--service-type")) { 1131 if (i + 1 == argc) { 1132 usage(); 1133 } 1134 service_type = argv[i + 1]; 1135 i++; 1136 } else if (!strcmp(argv[i], "--service-port")) { 1137 if (i + 1 == argc) { 1138 usage(); 1139 } 1140 1141 const int in_service_port = atoi(argv[i + 1]); 1142 if (in_service_port == 0 || in_service_port > UINT16_MAX) { 1143 fprintf(stderr, "Service port number %d is out of range or invalid, should be in (0, 65535].\n", 1144 in_service_port); 1145 usage(); 1146 } 1147 1148 service_port = (uint16_t)in_service_port; 1149 i++; 1150 } else { 1151 usage(); 1152 } 1153 } 1154 1155 if (!log_stderr) { 1156 OPENLOG("srp-client", false); 1157 } 1158 1159 // If we're asked to do a push query, we're not actually going to act as an SRP client, just do the push query. 1160 if (push_query || push_exhaust) { 1161 start_push_query(); 1162 ioloop(); 1163 exit(1); 1164 } 1165 1166 if (!use_thread_services && !new_ip_dup && !zero_addresses) { 1167 ioloop_map_interface_addresses(NULL, interface_name, NULL, interface_callback); 1168 } 1169 1170 if (!have_server_address && !use_thread_services) { 1171 uint8_t port[] = { 0, 53 }; 1172 if (bogus_server) { 1173 srp_add_server_address(port, dns_rrtype_aaaa, bogus_address, 16); 1174 } 1175 srp_add_server_address(port, dns_rrtype_aaaa, server_address, 16); 1176 } 1177 1178 if (dup_instance_name) { 1179 num_clients = 2; 1180 ioloop_strcpy(instance_name, "dup-name-test", sizeof(instance_name)); 1181 } 1182 if (new_ip_dup || zero_addresses) { 1183 // Set up the test to validate the "failed update removes address" code in srp-mdns-proxy. 1184 srp_add_interface_address(dns_rrtype_a, first_bogus_address, sizeof(first_bogus_address)); 1185 if (zero_addresses) { 1186 srp_delete_interface_address(dns_rrtype_a, first_bogus_address, sizeof(first_bogus_address)); 1187 } 1188 } 1189 1190 for (i = 0; i < num_clients; i++) { 1191 srp_client_t *client; 1192 char hnbuf[128]; 1193 TXTRecordRef txt; 1194 const void *txt_data = NULL; 1195 uint16_t txt_len = 0; 1196 char txt_buf[128]; 1197 1198 client = calloc(1, sizeof(*client)); 1199 if (client == NULL) { 1200 ERROR("no memory for client %d", i); 1201 exit(1); 1202 } 1203 1204 if (num_clients == 1) { 1205 strcpy(hnbuf, "srp-api-test"); 1206 } else { 1207 snprintf(hnbuf, sizeof(hnbuf), "srp-api-test-%d", i); 1208 } 1209 client->name = strdup(hnbuf); 1210 if (client->name == NULL) { 1211 ERROR("No memory for client name %s", hnbuf); 1212 exit(1); 1213 } 1214 client->index = i; 1215 1216 srp_host_init(client); 1217 srp_set_hostname(hnbuf, NULL); 1218 1219 if (random_leases) { 1220 int random_lease_time = 30 + srp_random16() % 1800; // random 1221 INFO("Client %d, lease time = %d", i, random_lease_time); 1222 srp_set_lease_times(random_lease_time, 7 * 24 * 3600); // random host lease, 7 day key lease 1223 } else if (lease_time > 0) { 1224 srp_set_lease_times(lease_time, 7 * 24 * 3600); // specified host lease, 7 day key lease 1225 } else if (let_added_service_expire) { 1226 srp_set_lease_times(30, 30); // Use short lease times so the lease expires quickly. 1227 } 1228 1229 if (change_txt_record) { 1230 TXTRecordCreate(&txt, sizeof(txt_buf), txt_buf); 1231 TXTRecordSetValue(&txt, "foo", 1, "0"); 1232 TXTRecordSetValue(&txt, "bar", 3, "1.1"); 1233 txt_data = TXTRecordGetBytesPtr(&txt); 1234 txt_len = TXTRecordGetLength(&txt); 1235 } 1236 if (random_txt_record) { 1237 char rbuf[6]; 1238 snprintf(rbuf, sizeof(rbuf), "%u", srp_random16()); 1239 TXTRecordCreate(&txt, sizeof(txt_buf), txt_buf); 1240 TXTRecordSetValue(&txt, "foo", strlen(rbuf), rbuf); 1241 INFO("TXTRecordSetValue(..., \"foo\", %zd, %s)", strlen(rbuf), rbuf); 1242 txt_data = TXTRecordGetBytesPtr(&txt); 1243 txt_len = TXTRecordGetLength(&txt); 1244 } 1245 1246 if (service_port == 0) { 1247 // If no service port is specified (0 indicates that port is unspecified), the index i will be used to 1248 // generate the port number. 1249 service_port = (i % UINT16_MAX) == 0 ? 1 : (i % UINT16_MAX); 1250 } 1251 1252 if (!test_subtypes && !test_diff_subtypes && !test_renew_subtypes && !host_only) { 1253 err = DNSServiceRegister(&sdref, new_ip_dup ? kDNSServiceFlagsNoAutoRename : 0, 0, 1254 dup_instance_name ? instance_name : hnbuf, service_type, 0, 0, htons(service_port), 1255 txt_len, txt_data, register_callback, client); 1256 if (err != kDNSServiceErr_NoError) { 1257 ERROR("DNSServiceRegister failed: %d", err); 1258 exit(1); 1259 } 1260 } 1261 if (remove_added_service || let_added_service_expire) { 1262 expecting_second_add = true; 1263 err = DNSServiceRegister(&sdref, 0, 0, hnbuf, "_second._tcp,foo", 0, 0, htons(service_port), 1264 txt_len, txt_data, second_register_callback, client); 1265 if (err != kDNSServiceErr_NoError) { 1266 ERROR("second DNSServiceRegister failed: %d", err); 1267 exit(1); 1268 } 1269 } 1270 // Here we register two services with subtypes. The idea is to see that the srp parsing code does not 1271 // associate the second subtype with the first service instance and report an error. In order to 1272 // attempt to trigger the error, we need the service instance name of the second service instance 1273 // to be different. 1274 if (test_subtypes || test_diff_subtypes || test_renew_subtypes) { 1275 expecting_second_add = true; 1276 err = DNSServiceRegister(&sdref, 0, 0, hnbuf, "_ipps._tcp,subtype", 1277 0, 0, htons(service_port), txt_len, txt_data, register_callback, client); 1278 if (err != kDNSServiceErr_NoError) { 1279 ERROR("DNSServiceRegister failed: %d", err); 1280 exit(1); 1281 } 1282 if (test_diff_subtypes) { 1283 err = DNSServiceRegister(&sdref, 0, 0, hnbuf, "_second._tcp,othersub", 1284 0, 0, htons(service_port), txt_len, txt_data, second_register_callback, client); 1285 if (err != kDNSServiceErr_NoError) { 1286 ERROR("DNSServiceRegister failed: %d", err); 1287 exit(1); 1288 } 1289 } else if (!test_renew_subtypes) { 1290 char shnbuf[132]; 1291 snprintf(shnbuf, sizeof(shnbuf), "foo-%s", hnbuf); 1292 err = DNSServiceRegister(&sdref, 0, 0, shnbuf, "_ipps._tcp,othersub", 1293 0, 0, htons(service_port), txt_len, txt_data, second_register_callback, client); 1294 if (err != kDNSServiceErr_NoError) { 1295 ERROR("DNSServiceRegister failed: %d", err); 1296 exit(1); 1297 } 1298 } 1299 } 1300 } 1301 1302 if (do_srp) { 1303 if (use_thread_services) { 1304 cti_get_service_list(NULL, &thread_service_context, NULL, cti_service_list_callback, NULL); 1305 } else { 1306 srp_network_state_stable(NULL); 1307 } 1308 } 1309 ioloop(); 1310 } 1311 1312 // Local Variables: 1313 // mode: C 1314 // tab-width: 4 1315 // c-file-style: "bsd" 1316 // c-basic-offset: 4 1317 // fill-column: 108 1318 // indent-tabs-mode: nil 1319 // End: 1320