3 * Copyright (c) 2019-2020 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * This file contains the SRP Advertising Proxy, which is an SRP Server
18 * that offers registered addresses using mDNS.
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
34 #include <sys/resource.h>
38 #include "srp-crypto.h"
40 #include "dnssd-proxy.h"
42 #include "srp-proxy.h"
43 #include "srp-mdns-proxy.h"
44 #include "config-parse.h"
48 #include "xpc_client_advertising_proxy.h"
49 #include "advertising_proxy_services.h"
50 #include <os/transaction_private.h>
53 // Server internal state
59 typedef struct srp_xpc_client srp_xpc_client_t
;
60 struct srp_xpc_client
{
61 srp_xpc_client_t
*next
;
62 xpc_connection_t connection
;
63 bool connection_canceled
; // If true, we've initiated an xpc_connection_cancel on this client.
64 bool enabler
; // If true, this client has asked to enable the proxy.
67 typedef struct srp_wanted_state srp_wanted_state_t
;
68 struct srp_wanted_state
{
70 os_transaction_t transaction
;
74 int advertise_interface
= kDNSServiceInterfaceIndexAny
;
76 const char local_suffix_ld
[] = ".local";
77 const char *local_suffix
= &local_suffix_ld
[1];
78 uint32_t max_lease_time
= 3600 * 27; // One day plus 20%
80 static xpc_connection_t xpc_listener
;
82 srp_wanted_state_t
*srp_wanted
;
83 srp_xpc_client_t
*srp_xpc_clients
;
85 // Forward references...
86 static void try_new_hostname(adv_host_t
*host
);
87 static void register_host_completion(DNSServiceRef sdref
, DNSRecordRef rref
,
88 DNSServiceFlags flags
, DNSServiceErrorType error_code
, void *context
);
89 static void register_instance_completion(DNSServiceRef sdref
, DNSServiceFlags flags
, DNSServiceErrorType error_code
,
90 const char *name
, const char *regtype
, const char *domain
, void *context
);
91 static void update_from_host(adv_host_t
*host
);
92 static void start_host_update(adv_host_t
*host
);
93 static void prepare_update(adv_host_t
*host
);
94 static void lease_callback(void *context
);
98 adv_address_finalize(adv_address_t
*address
)
104 adv_instance_finalize(adv_instance_t
*instance
)
106 if (instance
->txn
!= NULL
) {
107 ioloop_dnssd_txn_release(instance
->txn
);
109 if (instance
->txt_data
!= NULL
) {
110 free(instance
->txt_data
);
112 if (instance
->instance_name
!= NULL
) {
113 free(instance
->instance_name
);
115 if (instance
->service_type
!= NULL
) {
116 free(instance
->service_type
);
121 static adv_instance_vec_t
*
122 adv_instance_vec_create(int size
)
124 adv_instance_vec_t
*vec
;
126 vec
= calloc(1, sizeof(*vec
));
131 vec
->vec
= calloc(size
, sizeof (*(vec
->vec
)));
132 if (vec
->vec
== NULL
) {
142 static adv_instance_vec_t
*
143 adv_instance_vec_copy(adv_instance_vec_t
*vec
)
145 adv_instance_vec_t
*new_vec
;
148 new_vec
= adv_instance_vec_create(vec
->num
);
149 if (new_vec
!= NULL
) {
150 RETAIN_HERE(new_vec
);
151 for (i
= 0; i
< vec
->num
; i
++) {
152 if (vec
->vec
[i
] != NULL
) {
153 new_vec
->vec
[i
] = vec
->vec
[i
];
154 RETAIN_HERE(new_vec
->vec
[i
]);
157 new_vec
->num
= vec
->num
;
163 adv_instance_vec_finalize(adv_instance_vec_t
*vec
)
167 for (i
= 0; i
< vec
->num
; i
++) {
168 if (vec
->vec
[i
] != NULL
) {
169 RELEASE_HERE(vec
->vec
[i
], adv_instance_finalize
);
178 same_prefix(void *ai
, void *bi
, int width
)
181 uint8_t *a
= ai
, *b
= bi
;
182 static int masks
[] = {0xff, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
184 for (bite
= 0; bite
* 8 < width
; bite
++) {
185 if (a
[bite
] != b
[bite
]) {
189 if ((width
% 8) == 0) {
192 mask
= masks
[width
% 8];
193 if ((a
[bite
] & mask
) == (b
[bite
] & mask
)) {
199 // We call advertise_finished when a client request has finished, successfully or otherwise.
201 advertise_finished(comm_t
*connection
, message_t
*message
, int rcode
, client_update_t
*client
)
205 INFO("advertise_finished: rcode = " PUB_S_SRP
, dns_rcode_name(rcode
));
207 memset(&response
, 0, DNS_HEADER_SIZE
);
208 response
.id
= message
->wire
.id
;
209 response
.bitfield
= message
->wire
.bitfield
;
210 dns_rcode_set(&response
, rcode
);
211 dns_qr_set(&response
, dns_qr_response
);
213 iov
.iov_base
= &response
;
214 // If this was a successful update, send back the lease time, which will either
215 // be what the client asked for, or a shorter lease, depending on what limit has
217 if (client
!= NULL
) {
218 dns_towire_state_t towire
;
219 memset(&towire
, 0, sizeof towire
);
220 towire
.p
= &response
.data
[0]; // We start storing RR data here.
221 towire
.lim
= &response
.data
[DNS_DATA_SIZE
]; // This is the limit to how much we can store.
222 towire
.message
= &response
;
223 response
.qdcount
= 0;
224 response
.ancount
= 0;
225 response
.nscount
= 0;
226 response
.arcount
= htons(1);
227 dns_edns0_header_to_wire(&towire
, DNS_MAX_UDP_PAYLOAD
, 0, 0, 1);
228 dns_rdlength_begin(&towire
);
229 dns_u16_to_wire(&towire
, dns_opt_update_lease
); // OPTION-CODE
230 dns_edns0_option_begin(&towire
); // OPTION-LENGTH
231 dns_u32_to_wire(&towire
, client
->host_lease
); // LEASE (e.g. 1 hour)
232 dns_u32_to_wire(&towire
, client
->key_lease
); // KEY-LEASE (7 days)
233 dns_edns0_option_end(&towire
); // Now we know OPTION-LENGTH
234 dns_rdlength_end(&towire
);
235 // It should not be possible for this to happen; if it does, the client
236 // might not renew its lease in a timely manner.
238 ERROR("advertise_finished: unexpectedly failed to send EDNS0 lease option.");
239 iov
.iov_len
= DNS_HEADER_SIZE
;
241 iov
.iov_len
= towire
.p
- (uint8_t *)&response
;
244 iov
.iov_len
= DNS_HEADER_SIZE
;
246 ioloop_send_message(connection
, message
, &iov
, 1);
250 host_txn_finalize_callback(void *context
)
252 adv_host_t
*host
= context
;
258 instance_txn_finalize_callback(void *context
)
260 adv_instance_t
*instance
= context
;
261 instance
->txn
= NULL
;
265 retry_callback(void *context
)
267 adv_host_t
*host
= (adv_host_t
*)context
;
268 if (host
->updates
== NULL
&& host
->clients
== NULL
) {
269 update_from_host(host
);
271 start_host_update(host
);
276 wait_retry(adv_host_t
*host
)
278 #define MIN_HOST_RETRY_INTERVAL 15
279 #define MAX_HOST_RETRY_INTERVAL 120
280 // If we've been retrying long enough for the lease to expire, give up.
281 if (!host
->lease_expiry
|| host
->lease_expiry
>= ioloop_timenow()) {
282 lease_callback(host
);
284 if (host
->retry_interval
== 0) {
285 host
->retry_interval
= MIN_HOST_RETRY_INTERVAL
;
286 } else if (host
->retry_interval
< MAX_HOST_RETRY_INTERVAL
) {
287 host
->retry_interval
*= 2;
289 INFO("wait_retry: waiting %d seconds...", host
->retry_interval
);
290 ioloop_add_wake_event(host
->retry_wakeup
, host
, retry_callback
, NULL
, host
->retry_interval
* 1000);
293 // When the connection to mDNSResponder has died, the registration dies with it.
294 // In order to get back to where we were, we use the contents of the host to create an
295 // update. We push that update in front of any update that was pending, and restart
296 // the registration. There is no guarantee that this will succeed. If it fails, then
297 // the registration is abandoned.
300 service_disconnected(adv_host_t
*host
)
302 // If we don't have any updates we can do, this host is dead.
303 if (host
->updates
== NULL
) {
304 // lease_callback will get rid of this host.
305 lease_callback(host
);
312 client_finalize(client_update_t
*client
)
314 srp_update_free_parts(client
->instances
, NULL
, client
->services
, client
->host
);
315 if (client
->parsed_message
!= NULL
) {
316 dns_message_free(client
->parsed_message
);
318 if (client
->message
!= NULL
) {
319 ioloop_message_release(client
->message
);
321 if (client
->connection
!= NULL
) {
322 ioloop_comm_release(client
->connection
);
328 update_finalize(adv_update_t
*NONNULL update
)
330 adv_host_t
*host
= update
->host
;
333 adv_update_t
**p_updates
= &host
->updates
;
335 // Once the update is done, we want to make sure that any results that come in on the host registration do not
336 // reference the update, which will we are about to free. So get rid of the update pointer that's in the
337 // host address transaction aux data.
338 if (update
->host
->txn
!= NULL
) {
339 adv_update_t
*host_txn_update
= ioloop_dnssd_txn_get_aux_pointer(host
->txn
);
340 // If we are retrying an update, the update on the host DNSServiceRegisterRecord transaction might not be
341 // the transaction we are finalizing, but if it is, we definitely want to make it go away.
342 if (host_txn_update
== update
) {
343 ioloop_dnssd_txn_set_aux_pointer(host
->txn
, NULL
);
346 INFO("finalizing update %p for host " PRI_S_SRP
, update
, host
->registered_name
);
348 // Take this update off the host's update list (it might already be gone)
349 while (*p_updates
!= NULL
) {
350 if (*p_updates
== update
) {
351 *p_updates
= update
->next
;
354 p_updates
= &((*p_updates
)->next
);
358 INFO("finalizing update with no host.");
361 // Release instances and instance vectors.
362 if (update
->add_instances
!= NULL
) {
363 RELEASE_HERE(update
->add_instances
, adv_instance_vec_finalize
);
366 if (update
->update_instances
!= NULL
) {
367 RELEASE_HERE(update
->update_instances
, adv_instance_vec_finalize
);
370 if (update
->remove_instances
!= NULL
) {
371 RELEASE_HERE(update
->remove_instances
, adv_instance_vec_finalize
);
374 if (update
->add_addresses
!= NULL
) {
375 for (i
= 0; i
< update
->num_add_addresses
; i
++) {
376 if (update
->add_addresses
[i
] != NULL
) {
377 RELEASE_HERE(update
->add_addresses
[i
], adv_address_finalize
);
380 free(update
->add_addresses
);
383 if (update
->remove_addresses
!= NULL
) {
384 for (i
= 0; i
< update
->num_remove_addresses
; i
++) {
385 if (update
->remove_addresses
[i
] != NULL
) {
386 RELEASE_HERE(update
->remove_addresses
[i
], adv_address_finalize
);
389 free(update
->remove_addresses
);
392 if (update
->selected_addr
!= NULL
) {
393 RELEASE_HERE(update
->selected_addr
, adv_address_finalize
);
400 update_failed(adv_update_t
*update
, int rcode
, bool expire
)
402 // If we still have a client waiting for the result of this update, tell it we failed.
403 // Updates that have never worked are abandoned when the client is notified.
404 if (update
->client
!= NULL
) {
405 adv_host_t
*host
= update
->host
;
406 client_update_t
*client
= update
->client
;
407 advertise_finished(client
->connection
, client
->message
, rcode
, NULL
);
408 update_finalize(update
);
409 client_finalize(client
);
410 // If we don't have a lease yet, or the old lease has expired, remove the host.
411 // However, if the expire flag is false, it's because we're already finalizing the
412 // host, so doing an expiry here would double free the host. In this case, we leave
413 // it to the caller to do the expiry (really, to finalize the host).
414 if (expire
&& (host
->lease_expiry
== 0 || host
->lease_expiry
<= ioloop_timenow())) {
415 lease_callback(host
);
420 // The only time that we will not have a client waiting for a result from an update is if
421 // we are trying to recover from an mDNSResponder crash. mDNSResponder doesn't crash much,
422 // so the likelihood of us even finding out if this behavior is correct is pretty low.
423 // That said, we do take this possibility into account; if it happens, we try to restore
424 // all the registrations that were present prior to the crash.
426 // In the case of an update that previously succeeded, but that now has failed because of a naming
427 // conflict (yxdomain), we have to abandon it, even though we have no way to notify the owner.
428 if (rcode
== dns_rcode_yxdomain
) {
429 update_finalize(update
);
435 host_addr_free(adv_host_t
*host
)
439 if (host
->addresses
!= NULL
) {
440 for (i
= 0; i
< host
->num_addresses
; i
++) {
441 if (host
->addresses
[i
] != NULL
) {
442 RELEASE_HERE(host
->addresses
[i
], adv_address_finalize
);
445 free(host
->addresses
);
447 host
->addresses
= NULL
;
448 host
->num_addresses
= 0;
452 host_finalize(adv_host_t
*host
)
456 // Get rid of the host wake events.
457 if (host
->lease_wakeup
!= NULL
) {
458 ioloop_cancel_wake_event(host
->lease_wakeup
);
459 ioloop_wakeup_release(host
->lease_wakeup
);
461 if (host
->retry_wakeup
!= NULL
) {
462 ioloop_cancel_wake_event(host
->retry_wakeup
);
463 ioloop_wakeup_release(host
->retry_wakeup
);
467 // Remove all the advertised address records (currently only one).
468 if (host
->txn
!= NULL
) {
469 if (host
->txn
->sdref
== NULL
) {
470 INFO("host_finalize: releasing DNSSD transaction for " PRI_S_SRP
", but there's no sdref.", host
->name
);
472 INFO("host_finalize: removing AAAA record(s) for " PRI_S_SRP
, host
->registered_name
);
474 ioloop_dnssd_txn_release(host
->txn
);
476 INFO("host_finalize: no host address transaction for " PRI_S_SRP
, host
->registered_name
);
479 // Remove the address records.
480 host_addr_free(host
);
482 // Remove the services.
484 if (host
->instances
!= NULL
) {
485 for (i
= 0; i
< host
->instances
->num
; i
++) {
486 if (host
->instances
->vec
[i
] != NULL
) {
487 if (host
->instances
->vec
[i
]->txn
) {
488 ioloop_dnssd_txn_release(host
->instances
->vec
[i
]->txn
);
492 RELEASE_HERE(host
->instances
, adv_instance_vec_finalize
);
495 // At this point we could claim the key, but for now just get rid of the host.
496 if (host
->key_rdata
!= NULL
) {
497 free(host
->key_rdata
);
499 INFO("host_finalize: removed " PRI_S_SRP
", key_id %x", host
->name
? host
->name
: "<null>", host
->key_id
);
501 // In the default case, host->name and host->registered_name point to the same memory: we don't want a double free.
502 if (host
->registered_name
== host
->name
) {
503 host
->registered_name
= NULL
;
505 if (host
->name
!= NULL
) {
508 if (host
->registered_name
!= NULL
) {
509 free(host
->registered_name
);
515 lease_callback(void *context
)
517 adv_host_t
**p_hosts
, *host
= context
;
519 // Find the host on the list of hosts.
520 for (p_hosts
= &hosts
; *p_hosts
!= NULL
; p_hosts
= &(*p_hosts
)->next
) {
521 if (*p_hosts
== host
) {
525 if (*p_hosts
== NULL
) {
526 ERROR("lease-callback: called with nonexistent host.");
530 // It's possible that we got an update to this host, but haven't processed it yet. In this
531 // case, we don't want to get rid of the host, but we do want to get rid of it later if the
532 // update fails. So postpone the removal for another lease interval.
533 if (host
->updates
!= NULL
|| host
->clients
!= NULL
) {
534 INFO("lease_callback: reached with pending updates on host " PRI_S_SRP
".", host
->registered_name
);
535 ioloop_add_wake_event(host
->lease_wakeup
, host
, lease_callback
, NULL
, host
->lease_interval
* 1000);
536 host
->lease_expiry
= ioloop_timenow() + host
->lease_interval
* 1000;
541 *p_hosts
= host
->next
;
543 // Get rid of any transactions attached to the host, any timer events, and any other associated data.
548 update_finished(adv_update_t
*update
)
550 adv_host_t
*host
= update
->host
;
551 client_update_t
*client
= update
->client
;
552 int num_addresses
= 0;
553 adv_address_t
**addresses
= NULL
;
554 int num_instances
= 0;
555 adv_instance_vec_t
*instances
= NULL
;
557 int num_host_addresses
= 0;
558 int num_add_addresses
= 0;
559 int num_host_instances
= 0;
560 int num_add_instances
= 0;
562 adv_update_t
**p_update
;
564 // Reset the retry interval, since we succeeded in updating.
565 host
->retry_interval
= 0;
567 // Once an update has finished, we need to apply all of the proposed changes to the host object.
568 if (host
->addresses
!= NULL
) {
569 for (i
= 0; i
< host
->num_addresses
; i
++) {
570 if (host
->addresses
[i
] != NULL
&&
571 (update
->remove_addresses
== NULL
|| update
->remove_addresses
[i
] == NULL
))
573 num_host_addresses
++;
578 if (update
->add_addresses
!= NULL
) {
579 for (i
= 0; i
< update
->num_add_addresses
; i
++) {
580 if (update
->add_addresses
[i
] != NULL
) {
586 num_addresses
= num_host_addresses
+ num_add_addresses
;
587 if (num_addresses
> 0) {
588 addresses
= calloc(num_addresses
, sizeof *addresses
);
589 if (addresses
== NULL
) {
590 update_failed(update
, dns_rcode_servfail
, true);
595 addresses
[j
] = update
->selected_addr
;
596 RETAIN_HERE(addresses
[j
]);
599 rdata
= update
->selected_addr
->rdata
;
600 SEGMENTED_IPv6_ADDR_GEN_SRP(rdata
, rdata_buf
);
601 INFO("update_finished: selected " PRI_SEGMENTED_IPv6_ADDR_SRP
" on host " PRI_S_SRP
,
602 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdata
, rdata_buf
), host
->registered_name
);
604 if (host
->addresses
!= NULL
) {
605 for (i
= 0; i
< host
->num_addresses
; i
++) {
606 if (host
->addresses
[i
] != NULL
&& host
->addresses
[i
] != update
->selected_addr
&&
607 (update
->remove_addresses
== NULL
|| update
->remove_addresses
[i
] == NULL
))
610 uint8_t *rdp
= host
->addresses
[i
]->rdata
;
611 SEGMENTED_IPv6_ADDR_GEN_SRP(rdp
, rdp_buf
);
612 INFO("update_finished: retaining " PRI_SEGMENTED_IPv6_ADDR_SRP
"on host " PRI_S_SRP
,
613 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdp
, rdp_buf
), host
->registered_name
);
615 addresses
[j
] = host
->addresses
[i
];
616 RETAIN_HERE(addresses
[j
]);
621 if (update
->add_addresses
!= NULL
) {
622 for (i
= 0; i
< update
->num_add_addresses
; i
++) {
623 if (update
->add_addresses
[i
] != NULL
) {
624 if (update
->add_addresses
[i
] != update
->selected_addr
) {
626 uint8_t *rdp
= update
->add_addresses
[i
]->rdata
;
627 SEGMENTED_IPv6_ADDR_GEN_SRP(rdp
, rdp_buf
);
628 INFO("update_finished: adding " PRI_SEGMENTED_IPv6_ADDR_SRP
"to host " PRI_S_SRP
,
629 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdp
, rdp_buf
), host
->registered_name
);
631 addresses
[j
] = update
->add_addresses
[i
];
632 RETAIN_HERE(addresses
[j
]);
635 RELEASE_HERE(update
->add_addresses
[i
], adv_address_finalize
);
636 update
->add_addresses
[i
] = NULL
;
640 if (update
->selected_addr
!= NULL
) {
641 RELEASE_HERE(update
->selected_addr
, adv_address_finalize
);
642 update
->selected_addr
= NULL
;
646 // Do the same for instances.
647 for (i
= 0; i
< host
->instances
->num
; i
++) {
648 if (host
->instances
->vec
[i
] != NULL
&&
649 (update
->remove_instances
== NULL
|| update
->remove_instances
->vec
[i
] == NULL
))
651 num_host_instances
++;
655 if (update
->add_instances
!= NULL
) {
656 for (i
= 0; i
< update
->add_instances
->num
; i
++) {
657 if (update
->add_instances
->vec
[i
] != NULL
) {
663 num_instances
= num_add_instances
+ num_host_instances
;
664 instances
= adv_instance_vec_create(num_instances
);
665 if (instances
== NULL
) {
666 if (addresses
!= NULL
) {
667 for (i
= 0; i
< num_addresses
; i
++) {
668 if (addresses
[i
] != NULL
) {
669 RELEASE_HERE(addresses
[i
], adv_address_finalize
);
674 update_failed(update
, dns_rcode_servfail
, true);
677 instances
->num
= num_instances
;
680 for (i
= 0; i
< host
->instances
->num
; i
++) {
681 if (update
->remove_instances
!= NULL
&& update
->remove_instances
->vec
[i
] == NULL
) {
682 if (update
->update_instances
->vec
[i
] != NULL
) {
683 adv_instance_t
*instance
= update
->update_instances
->vec
[i
];
684 INFO("update_finished: updated instance " PRI_S_SRP
" " PRI_S_SRP
" %d",
685 instance
->instance_name
, instance
->service_type
, instance
->port
);
686 // Implicit RETAIN/RELEASE
687 instances
->vec
[j
] = instance
;
688 update
->update_instances
->vec
[i
] = NULL
;
690 if (host
->instances
->vec
[i
] != NULL
) {
691 adv_instance_t
*instance
= host
->instances
->vec
[i
];
692 INFO("update_finished: retained instance " PRI_S_SRP
" " PRI_S_SRP
" %d",
693 instance
->instance_name
, instance
->service_type
, instance
->port
);
694 instances
->vec
[j
++] = instance
;
695 RETAIN_HERE(instance
);
700 if (update
->add_instances
!= NULL
) {
701 for (i
= 0; i
< update
->add_instances
->num
; i
++) {
702 adv_instance_t
*instance
= update
->add_instances
->vec
[i
];
703 if (instance
!= NULL
) {
704 INFO("update_finished: added instance " PRI_S_SRP
" " PRI_S_SRP
" %d",
705 instance
->instance_name
, instance
->service_type
, instance
->port
);
706 // Implicit RETAIN/RELEASE
707 instances
->vec
[j
++] = instance
;
708 update
->add_instances
->vec
[i
] = NULL
;
713 // At this point we can safely modify the host object because we aren't doing any more
715 host_addr_free(host
);
716 RELEASE_HERE(host
->instances
, adv_instance_vec_finalize
);
718 host
->addresses
= addresses
;
719 host
->num_addresses
= num_addresses
;
720 host
->instances
= instances
;
723 advertise_finished(client
->connection
, client
->message
, dns_rcode_noerror
, client
);
724 client_finalize(client
);
725 update
->client
= NULL
;
728 // The update should still be on the host.
729 for (p_update
= &host
->updates
; *p_update
!= NULL
; p_update
= &(*p_update
)->next
) {
730 if (*p_update
== update
) {
735 if (*p_update
== NULL
) {
736 ERROR("update_finished: p_update is null.");
738 *p_update
= update
->next
;
741 // If we have another prepared update to do, apply it first.
743 start_host_update(host
);
747 // If we have an update that hasn't yet been prepared, prepare it and apply it.
749 prepare_update(host
);
753 // If we got a late name conflict while processing the previous update, try to get a new hostname.
754 // We won't get here if the update caused the host to be reregistered--in that case we will either
755 // return a failure to the client and delete the host, or else we'll have resolved the conflict.
756 if (host
->hostname_update_pending
) {
757 try_new_hostname(host
);
760 // Otherwise, there's no work left to do, so just wait until the lease expires.
761 host
->lease_interval
= update
->host_lease
;
762 host
->key_lease
= update
->key_lease
;
764 if (update
->lease_expiry
!= 0) {
765 uint64_t now
= ioloop_timenow();
766 if (update
->lease_expiry
< now
) {
767 ERROR("update_finished: lease expiry for host %s happened %" PRIu64
" milliseconds ago.",
768 host
->registered_name
, now
- update
->lease_expiry
);
769 // Expire the lease in 1000 ms.
770 ioloop_add_wake_event(host
->lease_wakeup
, host
, lease_callback
, NULL
, 1000);
772 uint64_t when
= update
->lease_expiry
- now
;
773 if (when
> INT32_MAX
) {
776 ioloop_add_wake_event(host
->lease_wakeup
, host
, lease_callback
, NULL
, (uint32_t)when
);
777 host
->lease_expiry
= update
->lease_expiry
;
780 ioloop_add_wake_event(host
->lease_wakeup
, host
, lease_callback
, NULL
, host
->lease_interval
* 1000);
781 host
->lease_expiry
= ioloop_timenow() + host
->lease_interval
* 1000;
784 update_finalize(update
);
787 // When the host registration has completed, we get this callback. Completion either means that we succeeded in
788 // registering the record, or that something went wrong and the registration has failed.
790 register_instance_completion(DNSServiceRef sdref
, DNSServiceFlags flags
, DNSServiceErrorType error_code
,
791 const char *name
, const char *regtype
, const char *domain
, void *context
)
797 adv_instance_t
*instance
= context
;
798 adv_update_t
*update
= instance
->update
;
799 adv_host_t
*host
= instance
->host
;
801 // It's possible that we could restart a host update due to an error while a callback is still pending on a stale
802 // update. In this case, we just cancel all of the work that's been done on the stale update (it's probably already
804 if (update
!= NULL
&& host
->updates
!= update
) {
805 INFO("register_instance_completion: registration for service " PRI_S_SRP
"." PRI_S_SRP
806 " completed with invalid state.", name
, regtype
);
807 update_finalize(update
);
811 // We will generally get a callback on success or failure of the initial registration; this is what causes
812 // the update to complete or fail. We may get subsequent callbacks because of name conflicts. So the first
813 // time we get a callback, instance->update will always be valid; thereafter, it will not, so null it out.
814 instance
->update
= NULL
;
816 if (error_code
== kDNSServiceErr_NoError
) {
817 INFO("register_instance_completion: registration for service " PRI_S_SRP
"." PRI_S_SRP
"." PRI_S_SRP
" -> "
818 PRI_S_SRP
" has completed.", instance
->instance_name
, instance
->service_type
, domain
,
819 host
->registered_name
);
820 INFO("register_instance_completion: registration is under " PRI_S_SRP
"." PRI_S_SRP PRI_S_SRP
, name
, regtype
,
823 // In principle update->instance should always be non-NULL here because a no-error response should
824 // only happen once or not at all. But just to be safe...
825 if (update
!= NULL
) {
826 update
->num_instances_completed
++;
827 if (update
->num_instances_completed
== update
->num_instances_started
) {
828 // We have successfully advertised the service.
829 update_finished(update
);
832 ERROR("register_instance_completion: no error, but update is NULL for instance " PRI_S_SRP
" (" PRI_S_SRP
833 " " PRI_S_SRP
" " PRI_S_SRP
")", instance
->instance_name
, name
, regtype
, domain
);
836 INFO("register_instance_completion: registration for service " PRI_S_SRP
"." PRI_S_SRP
"." PRI_S_SRP
" -> "
837 PRI_S_SRP
" failed with code %d", instance
->instance_name
, instance
->service_type
, domain
,
838 host
->registered_name
, error_code
);
840 // If this is the immediate result of a registration, we can inform the SRP client that it failed.
841 if (update
!= NULL
) {
842 // At present we will never get this error because mDNSResponder will just choose a new name.
843 if (error_code
== kDNSServiceErr_NameConflict
) {
844 update_failed(update
, dns_rcode_yxdomain
, true);
846 update_failed(update
, dns_rcode_servfail
, true);
849 ERROR("Late failure for instance " PRI_S_SRP
"--can't update client.", instance
->instance_name
);
852 if (error_code
== kDNSServiceErr_ServiceNotRunning
|| error_code
== kDNSServiceErr_DefunctConnection
) {
853 service_disconnected(host
);
859 extract_instance_name(char *instance_name
, int instance_name_max
,
860 char *service_name
, int service_name_max
, service_instance_t
*instance
)
862 dns_name_t
*end_of_service_name
= instance
->service
->rr
->name
->next
;
863 if (end_of_service_name
!= NULL
) {
864 if (end_of_service_name
->next
!= NULL
) {
865 end_of_service_name
= end_of_service_name
->next
;
868 dns_name_print_to_limit(instance
->service
->rr
->name
, end_of_service_name
, service_name
, service_name_max
);
870 // Make a presentation-format version of the service instance name.
871 dns_name_print_to_limit(instance
->name
, instance
->name
!= NULL
? instance
->name
->next
: NULL
,
872 instance_name
, instance_name_max
);
876 register_instance(adv_instance_t
*instance
)
881 INFO("DNSServiceRegister(" PRI_S_SRP
", " PRI_S_SRP
", " PRI_S_SRP
", %d)",
882 instance
->instance_name
, instance
->service_type
, instance
->host
->registered_name
, instance
->port
);
883 err
= DNSServiceRegister(&sdref
, kDNSServiceFlagsUnique
, advertise_interface
,
884 instance
->instance_name
, instance
->service_type
, local_suffix
,
885 instance
->host
->registered_name
, htons(instance
->port
), instance
->txt_length
,
886 instance
->txt_data
, register_instance_completion
, instance
);
887 // This would happen if we pass NULL for regtype, which we don't, or if we run out of memory, or if
888 // the server isn't running; in the second two cases, we can always try again later.
889 if (err
!= kDNSServiceErr_NoError
) {
890 // If we can, always send status to the client.
891 if (instance
->update
!= NULL
) {
892 if (instance
->update
->client
== NULL
&&
893 (err
== kDNSServiceErr_ServiceNotRunning
|| err
== kDNSServiceErr_DefunctConnection
))
895 INFO("DNSServiceRegister failed: " PUB_S_SRP
,
896 err
== kDNSServiceErr_ServiceNotRunning
? "not running" : "defunct");
897 service_disconnected(instance
->host
);
899 INFO("DNSServiceRegister failed: %d", err
);
900 update_failed(instance
->update
, dns_rcode_servfail
, true);
905 instance
->txn
= ioloop_dnssd_txn_add(sdref
, instance
, instance_txn_finalize_callback
);
906 if (instance
->txn
== NULL
) {
907 ERROR("register_instance: no memory.");
908 DNSServiceRefDeallocate(sdref
);
911 if (instance
->update
!= NULL
) {
912 instance
->update
->num_instances_started
++;
918 // When an update fails on some record, abandon_update is called to stop advertising the other records
919 // that were proposed in the update. The state associated with the update is then freed. The caller is
920 // responsible for sending the result back to the SRP client. If anything was deleted by the update, it's
921 // also abandoned, which is somewhat problematic.
923 abandon_update(adv_host_t
*host
)
928 // When a registration that's been successfully added in the past is attempted, and fails in a way
929 // that indicates a conflict or unrecoverable error, we have to abandon it. abandon_registration
930 // takes care of that.
932 abandon_registration(adv_host_t
*host
)
939 start_service_updates(adv_host_t
*host
)
942 adv_update_t
*update
= host
->updates
;
944 if (update
== NULL
) {
945 ERROR("start_service_updates: no work to do.");
949 // For each service instance that's being added, register it.
950 for (i
= 0; i
< update
->add_instances
->num
; i
++) {
951 if (update
->add_instances
->vec
[i
] != NULL
) {
952 if (!register_instance(update
->add_instances
->vec
[i
])) {
957 // For each service instance that's being updated or deleted, delete it.
958 if (update
->update_instances
->num
!= host
->instances
->num
) {
959 ERROR("start_service_updates: update instance count %d differs from host instance count %d",
960 update
->update_instances
->num
, host
->instances
->num
);
961 update_failed(update
, dns_rcode_servfail
, true);
964 if (update
->remove_instances
->num
!= host
->instances
->num
) {
965 ERROR("start_service_updates: delete instance count %d differs from host instance count %d",
966 update
->remove_instances
->num
, host
->instances
->num
);
967 update_failed(update
, dns_rcode_servfail
, true);
970 for (i
= 0; i
< host
->instances
->num
; i
++) {
971 if (update
->update_instances
->vec
[i
] != NULL
|| update
->remove_instances
->vec
[i
] != NULL
) {
972 if (host
->instances
->vec
[i
]->txn
!= NULL
) {
973 ioloop_dnssd_txn_release(host
->instances
->vec
[i
]->txn
);
974 host
->instances
->vec
[i
]->txn
= NULL
;
977 if (update
->update_instances
->vec
[i
] != NULL
) {
978 if (!register_instance(update
->update_instances
->vec
[i
])) {
979 INFO("start_service_update: register instance failed.");
984 if (update
->num_instances_started
== 0) {
985 INFO("start_service_update: no service updates, so we're finished.");
986 update_finished(update
);
990 // When we get a late name conflict on the hostname, we need to update the host registration and all of the
991 // service registrations. To do this, we construct an update and then apply it. If there is already an update
992 // in progress, we put this update at the end of the list.
994 update_from_host(adv_host_t
*host
)
996 adv_update_t
*update
= NULL
;
999 // Allocate the update structure.
1000 update
= calloc(1, sizeof *update
);
1001 if (update
== NULL
) {
1002 ERROR("update_from_host: no memory for update.");
1006 update
->add_addresses
= calloc(host
->num_addresses
, sizeof (*update
->add_addresses
));
1007 if (update
->add_addresses
== NULL
) {
1008 ERROR("update_from_host: no memory for addresses");
1011 update
->num_add_addresses
= 0;
1013 // Copy all of the addresses in the host into add_addresses
1014 for (i
= 0; i
< host
->num_addresses
; i
++) {
1015 if (host
->addresses
[i
] != NULL
) {
1016 update
->add_addresses
[update
->num_add_addresses
] = host
->addresses
[i
];
1017 RETAIN_HERE(update
->add_addresses
[update
->num_add_addresses
]);
1018 update
->num_add_addresses
++;
1022 // We can never update more instances than currently exist for this host.
1023 update
->update_instances
= adv_instance_vec_copy(host
->instances
);
1024 for (i
= 0; i
< update
->update_instances
->num
; i
++) {
1025 if (update
->update_instances
->vec
[i
] != NULL
) {
1026 update
->update_instances
->vec
[i
]->update
= update
;
1030 // We aren't actually adding or deleting any instances, but...
1031 update
->remove_instances
= adv_instance_vec_create(host
->instances
->num
);
1032 if (update
->remove_instances
== NULL
) {
1033 ERROR("update_from_host: no memory for remove_instances");
1036 update
->remove_instances
->num
= host
->instances
->num
;
1038 update
->add_instances
= adv_instance_vec_create(host
->instances
->num
);
1039 if (update
->add_instances
== NULL
) {
1040 ERROR("update_from_host: no memory for add_instances");
1043 update
->add_instances
->num
= host
->instances
->num
;
1045 // At this point we have figured out all the work we need to do, so hang it off an update structure.
1046 update
->host
= host
;
1047 update
->num_remove_addresses
= 0;
1048 update
->num_add_addresses
= host
->num_addresses
;
1049 update
->host_lease
= host
->lease_interval
;
1050 update
->key_lease
= host
->key_lease
;
1051 update
->lease_expiry
= host
->lease_expiry
;
1053 // The only time we can expect this to happen is as a result of a retry, in which case we want to
1054 // get the host back to its correct state before continuing.
1055 update
->next
= host
->updates
;
1056 host
->updates
= update
;
1057 start_host_update(host
);
1061 update_finalize(update
);
1066 // If we get a name conflict, we need to choose a new name for the host.
1068 try_new_hostname(adv_host_t
*host
)
1071 char separator
= '-';
1072 char namebuf
[DNS_MAX_LABEL_SIZE_ESCAPED
];
1075 for (s
= host
->name
; *s
; s
++) {
1080 if (t
- namebuf
>= DNS_MAX_LABEL_SIZE_ESCAPED
- 13) { // 13: "-12345.local\0"
1082 ERROR("try_new_hostname: truncating " PRI_S_SRP
" to " PRI_S_SRP
, host
->name
, namebuf
);
1086 if (s
[1] == 0 || s
[2] == 0 || s
[3] == 0) {
1087 ERROR("try_new_hostname: escaped hostname " PRI_S_SRP
" is invalid", host
->name
);
1097 if (*s
== ' ' || *s
== '-' || *s
== '_') {
1102 INFO("try_new_hostname: using base name %s", namebuf
);
1103 // Append a random number to the end of the name.
1104 host
->name_serial
= srp_random16();
1105 snprintf(t
, 13, "-%d.local", host
->name_serial
);
1106 INFO("try_new_hostname: using full name %s", namebuf
);
1108 if (host
->registered_name
!= host
->name
) {
1109 free(host
->registered_name
);
1111 host
->registered_name
= strdup(namebuf
);
1112 if (host
->registered_name
== NULL
) {
1113 ERROR("try_new_hostname: No memory for alternative name for " PRI_S_SRP
": " PRI_S_SRP
, host
->name
, namebuf
);
1114 // We pretty much can't do anything at this point.
1115 lease_callback(host
);
1119 // Generate an update from the host entry and do it.
1120 update_from_host(host
);
1123 // When the host registration has completed, we get this callback. Completion either means that we succeeded in
1124 // registering the record, or that something went wrong and the registration has failed.
1126 register_host_completion(DNSServiceRef sdref
, DNSRecordRef rref
,
1127 DNSServiceFlags flags
, DNSServiceErrorType error_code
, void *context
)
1129 dnssd_txn_t
*txn
= context
;
1130 adv_update_t
*update
= ioloop_dnssd_txn_get_aux_pointer(txn
);
1131 adv_host_t
*host
= ioloop_dnssd_txn_get_context(txn
);
1137 // It's possible that we could restart a host update due to an error while a callback is still pending on a stale
1138 // update. In this case, we just cancel all of the work that's been done on the stale update (it's probably already
1140 if (update
!= NULL
&& (host
== NULL
|| host
->updates
!= update
)) {
1141 INFO("register_host_completion: registration for host completed with invalid state.");
1142 update_finalize(update
);
1147 ERROR("register_host_completion called on null host.");
1151 if (error_code
== kDNSServiceErr_NoError
) {
1152 // If we get here while a hostname update is pending, it means that the conflict was resolved when
1153 // we re-registered the host as a side effect of the update, so we no longer need to update the
1155 host
->hostname_update_pending
= false;
1157 // Now that the hostname has been registered, we can register services that point at it.
1158 INFO("register_host_completion: registration for host " PRI_S_SRP
" has completed.", host
->registered_name
);
1159 start_service_updates(host
);
1161 INFO("register_host_completion: registration for host " PRI_S_SRP
" failed, status = %d", host
->registered_name
,
1163 if (update
== NULL
) {
1164 // We shouldn't get any error here other than a name conflict or daemon not running.
1165 // If we get a name conflict, that means that some other BR or host on the network has
1166 // started advertising the hostname we chose, so we need to choose a new name and fix
1167 // all of the service registrations.
1168 if (error_code
== kDNSServiceErr_NameConflict
) {
1169 if (host
->updates
!= NULL
|| host
->clients
!= NULL
) {
1170 host
->hostname_update_pending
= true;
1172 try_new_hostname(host
);
1176 if (error_code
== kDNSServiceErr_NameConflict
) {
1177 update_failed(update
, dns_rcode_yxdomain
, true);
1179 update_failed(update
, dns_rcode_servfail
, true);
1185 static adv_instance_t
*
1186 adv_instance_create(service_instance_t
*raw
, adv_host_t
*host
, adv_update_t
*update
)
1188 char service_type
[DNS_MAX_LABEL_SIZE_ESCAPED
* 2 + 2]; // sizeof '.' + sizeof '\0'.
1189 char instance_name
[DNS_MAX_NAME_SIZE_ESCAPED
+ 1];
1192 // Allocate the raw registration
1193 adv_instance_t
*instance
= calloc(1, sizeof *instance
);
1194 if (instance
== NULL
) {
1195 ERROR("adv_instance:create: unable to allocate raw registration struct.");
1198 RETAIN_HERE(instance
);
1199 instance
->host
= host
;
1200 instance
->update
= update
;
1201 // SRV records have priority, weight and port, but DNSServiceRegister only uses port.
1202 instance
->port
= (raw
->srv
== NULL
) ? 0 : raw
->srv
->data
.srv
.port
;
1204 // Make a presentation-format version of the service name.
1205 extract_instance_name(instance_name
, sizeof instance_name
, service_type
, sizeof service_type
, raw
);
1206 instance
->instance_name
= strdup(instance_name
);
1207 if (instance
->instance_name
== NULL
) {
1208 ERROR("adv_instance:create: unable to allocate instance name.");
1209 RELEASE_HERE(instance
, adv_instance_finalize
);
1212 instance
->service_type
= strdup(service_type
);
1213 if (instance
->service_type
== NULL
) {
1214 ERROR("adv_instance:create: unable to allocate instance type.");
1215 RELEASE_HERE(instance
, adv_instance_finalize
);
1219 // Allocate the text record buffer
1220 if (raw
->txt
!= NULL
) {
1221 txt_data
= malloc(raw
->txt
->data
.txt
.len
);
1222 if (txt_data
== NULL
) {
1223 RELEASE_HERE(instance
, adv_instance_finalize
);
1224 ERROR("adv_instance:create: unable to allocate txt_data buffer");
1227 // Format the txt buffer as required by DNSServiceRegister().
1228 memcpy(txt_data
, raw
->txt
->data
.txt
.data
, raw
->txt
->data
.txt
.len
);
1229 instance
->txt_data
= txt_data
;
1230 instance
->txt_length
= raw
->txt
->data
.txt
.len
;
1232 instance
->txt_data
= NULL
;
1233 instance
->txt_length
= 0;
1238 #define adv_address_create(addr, host) \
1239 adv_address_create_(addr, host, __FILE__, __LINE__)
1240 static adv_address_t
*
1241 adv_address_create_(host_addr_t
*addr
, adv_host_t
*host
, const char *file
, int line
)
1244 adv_address_t
*new_addr
= calloc(1, sizeof *new_addr
);
1245 if (new_addr
== NULL
) {
1246 ERROR("adv_address_create: no memory for new_addr");
1249 new_addr
->host
= host
;
1250 new_addr
->rrtype
= addr
->rr
.type
;
1251 new_addr
->rdlen
= addr
->rr
.type
== dns_rrtype_a
? 4 : 16;
1252 memcpy(new_addr
->rdata
, &addr
->rr
.data
, new_addr
->rdlen
);
1257 // When we need to register a host with mDNSResponder, start_host_update is called. This can be either because
1258 // we just got a new registration for a host, or if the daemon dies and we need to re-do the host registration.
1259 // This just registers the host; if that succeeds, then we register the service instances.
1261 start_host_update(adv_host_t
*host
)
1263 adv_update_t
*update
= host
->updates
;
1265 bool remove_preexisting
;
1267 uint16_t add_rrtype
;
1269 adv_address_t
*selected_addr
= NULL
, *preferred_addr
= NULL
;
1271 adv_address_t
*addr
;
1274 if (host
->updates
== NULL
) {
1275 ERROR("start_host_update: no work to do for host " PRI_S_SRP
, host
->registered_name
);
1279 // If we haven't published an address yet, or if we are going to remove the currently published address,
1280 // or if we have new addresses to add, then choose the address that is best suited, preferring recently
1281 // added addresses over existing addresses.
1282 remove_preexisting
= false;
1287 // If the host address isn't about to be removed, and is an IPv6 address on the preferred prefix,
1288 // store it in preferred_addr for comparison and possible retention.
1289 if (preferred_prefix
!= NULL
&&
1290 host
->num_addresses
> 0 && host
->addresses
[0] != NULL
&&
1291 update
->remove_addresses
!= NULL
&& update
->remove_addresses
[0] == NULL
&&
1292 host
->addresses
[0]->rrtype
== dns_rrtype_aaaa
&&
1293 same_prefix(host
->addresses
[0]->rdata
, &preferred_prefix
->addr
, preferred_prefix
->width
))
1295 preferred_addr
= host
->addresses
[0];
1298 if ((host
->num_addresses
!= 0 && update
->remove_addresses
!= NULL
&& update
->remove_addresses
[0] != NULL
) ||
1299 update
->num_add_addresses
!= 0)
1301 if (preferred_prefix
!= NULL
) {
1302 for (i
= 0; i
< update
->num_add_addresses
; i
++) {
1303 addr
= update
->add_addresses
[i
];
1304 if (// there is an address
1305 addr
!= NULL
&& addr
->rrtype
== dns_rrtype_aaaa
&&
1306 // it's on the preferred prefix
1307 same_prefix(addr
->rdata
, &preferred_prefix
->addr
, preferred_prefix
->width
))
1309 // If this address is the same as the currently selected address, we don't need
1310 // to add it. Preferred_addr is always a AAAA.
1311 if (preferred_addr
!= NULL
&& preferred_addr
->rrtype
== dns_rrtype_aaaa
&&
1312 !memcmp(addr
->rdata
, preferred_addr
->rdata
, 16))
1314 selected_addr
= preferred_addr
;
1316 // But if the current address is not preferred, or there isn't one, then choose this
1317 // address. If there's more than one address in the preferred prefix, we choose the first
1318 // one we come to. SRP client should not be sending temporary addresses or deprecated addresses.
1320 selected_addr
= addr
;
1321 remove_preexisting
= true;
1329 // If none of the new addresses were different than the current address and in the preferred prefix,
1330 // keep the current address.
1331 if (selected_addr
== NULL
&&
1332 host
->num_addresses
> 0 && host
->addresses
[0] != NULL
&&
1333 update
->remove_addresses
!= NULL
&& update
->remove_addresses
[0] == NULL
)
1335 selected_addr
= host
->addresses
[0];
1336 remove_preexisting
= false;
1337 update
->registering_key
= false;
1340 // If the current address is being removed, and we don't have a new address in the preferred
1341 // prefix, just use the first address in the add list.
1342 if (selected_addr
== NULL
) {
1343 for (i
= 0; i
< update
->num_add_addresses
; i
++) {
1344 if (update
->add_addresses
[i
] != NULL
) {
1345 selected_addr
= update
->add_addresses
[i
];
1346 remove_preexisting
= true;
1350 // If there's no new address, see if there's an old address we didn't use before.
1351 if (selected_addr
== NULL
) {
1352 for (i
= 1; i
< host
->num_addresses
; i
++) {
1353 addr
= host
->addresses
[i
];
1356 selected_addr
= addr
;
1357 remove_preexisting
= true;
1364 // If we didn't find an address, we're just deleting the address.
1365 if (selected_addr
== NULL
) {
1366 INFO("start_host_update: No address was selected.");
1367 remove_preexisting
= true;
1368 add_rdata
= host
->key_rdata
;
1369 add_rrtype
= dns_rrtype_key
;
1370 add_rdlen
= host
->key_rdlen
;
1371 update
->registering_key
= true;
1373 // We don't need to update the host address if it didn't change.
1374 if (remove_preexisting
) {
1375 if (host
->num_addresses
> 0) {
1376 INFO("start_host_update: Replacing existing address %p.", selected_addr
);
1378 INFO("start_host_update: Adding new address %p.", selected_addr
);
1380 add_rdata
= selected_addr
->rdata
;
1381 add_rrtype
= selected_addr
->rrtype
;
1382 add_rdlen
= selected_addr
->rdlen
;
1384 INFO("start_host_update: Retaining existing address.");
1386 update
->registering_key
= false;
1387 if (update
->selected_addr
!= NULL
) {
1388 RELEASE_HERE(update
->selected_addr
, adv_address_finalize
);
1390 update
->selected_addr
= selected_addr
;
1391 RETAIN_HERE(update
->selected_addr
);
1393 INFO("update->selected_addr = %p", update
->selected_addr
);
1395 // At present, the DNSService* API doesn't provide a clean way to update a record registered with
1396 // DNSServiceRegisterRecord, because it assumes that you'd only ever want to update it with a record
1397 // of the same type. We can't use that, so we just remove the record (if it exists) and then add
1398 // the intended record.
1399 if (remove_preexisting
&& host
->txn
!= NULL
) {
1400 ioloop_dnssd_txn_release(host
->txn
);
1404 // If we don't think we have a connection, make one.
1405 if (host
->txn
== NULL
) {
1406 DNSServiceRef sdref
;
1407 err
= DNSServiceCreateConnection(&sdref
);
1408 // In principle the only way this can fail is if the daemon isn't running.
1409 if (err
!= kDNSServiceErr_NoError
) {
1410 // If this is a new update, just send a response to the client. Otherwise maybe try to re-add it.
1411 if (update
->client
!= NULL
) {
1412 ERROR("DNSServiceCreateConnection: something went wrong: %d.", err
);
1413 update_failed(update
, dns_rcode_servfail
, true);
1414 } else if (err
== kDNSServiceErr_DefunctConnection
|| err
== kDNSServiceErr_ServiceNotRunning
) {
1415 ERROR("DNSServiceCreateConnection: " PUB_S_SRP
".",
1416 err
== kDNSServiceErr_DefunctConnection
? "defunct connection" : "service not running");
1417 service_disconnected(host
);
1418 } else if (err
!= kDNSServiceErr_NoError
) {
1419 ERROR("DNSServiceCreateConnection: something went wrong: %d.", err
);
1424 INFO("Adding transaction %p", sdref
);
1425 host
->txn
= ioloop_dnssd_txn_add(sdref
, host
, host_txn_finalize_callback
);
1426 if (host
->txn
== NULL
) {
1427 ERROR("start_host_update: no memory for host transaction");
1428 if (update
->client
!= NULL
) {
1429 update_failed(update
, dns_rcode_servfail
, true);
1437 if (add_rdata
!= NULL
) {
1438 INFO("start_host_update: DNSServiceRegisterRecord(%p %p %d %d %p %d %d %d %p %d %p %p)",
1439 host
? (host
->txn
? host
->txn
->sdref
: 0) : 0, host
? &host
->rref
: 0,
1440 kDNSServiceFlagsUnique
| kDNSServiceFlagsNoAutoRename
,
1441 advertise_interface
, host
? host
->registered_name
: 0,
1442 add_rrtype
, dns_qclass_in
, add_rdlen
, add_rdata
, 3600,
1443 register_host_completion
, host
? host
->txn
: 0);
1444 ioloop_dnssd_txn_set_aux_pointer(host
->txn
, update
);
1445 err
= DNSServiceRegisterRecord(host
->txn
->sdref
, &host
->rref
,
1446 kDNSServiceFlagsUnique
| kDNSServiceFlagsNoAutoRename
,
1447 advertise_interface
, host
->registered_name
,
1448 add_rrtype
, dns_qclass_in
, add_rdlen
, add_rdata
, 3600,
1449 register_host_completion
, host
->txn
);
1450 if (err
!= kDNSServiceErr_NoError
) {
1451 ERROR("start_host_update: DNSServiceRegisterRecord failed on host: %d", err
);
1452 if (update
->client
!= NULL
) {
1453 update_failed(update
, dns_rcode_servfail
, true);
1455 } else if (err
== kDNSServiceErr_DefunctConnection
|| err
== kDNSServiceErr_ServiceNotRunning
) {
1456 service_disconnected(host
);
1461 // If we didn't have to do an add, start the service updates immediately.
1463 INFO("start_host_update: no host address rdata, so no host update");
1464 start_service_updates(host
);
1469 // When a host has no update in progress, and there is a client update ready to process, we need to analyze
1470 // the client update to see what work needs to be done. This work is constructed as an translation from the
1471 // raw update sent by the client (host->clients) into a prepared update that can be used directly to
1472 // register the information with mDNSResponder.
1474 // Normally a host will only have one prepared update in progress; however, if we lose our connection to
1475 // mDNSResponder, then we need to re-create the host advertisement. If there was an update in progress when
1476 // this happened, we then need to reapply that as well. In this case an update is constructed from the host, to
1477 // get the host into the intended state, and the in-progress update is pushed below that; when the host has
1478 // been re-created on the daemon, the pending update is popped back off the stack and restarted.
1480 prepare_update(adv_host_t
*host
)
1484 service_instance_t
*instance
;
1485 adv_address_t
**remove_addrs
= NULL
;
1486 int num_remove_addrs
= 0;
1487 adv_address_t
**add_addrs
= NULL
;
1488 int num_add_addrs
= 0;
1489 int num_update_instances
= 0;
1490 int num_add_instances
= 0;
1491 int num_remove_instances
= 0;
1492 adv_instance_vec_t
*update_instances
= NULL
, *add_instances
= NULL
, *remove_instances
= NULL
;
1493 client_update_t
*client_update
= host
->clients
;
1494 adv_update_t
*update
= NULL
;
1497 // - Figure out what address records to add and what address records to delete.
1498 // - Because we can only have one address record at a time currently, figure out which address record we want
1499 // - If we already have an address record published, and it's the same, do nothing
1500 // - else if we already have an address record published, and it's changed to a different address, do an update
1501 // - else if we have a new address record, publish it
1502 // - else publish the key to hold the name
1503 // - Go through the set of service instances, identifying deletes, changes and adds
1504 // - We don't currently allow deletes, but what that would look like would be an instance with no SRV or TXT
1506 // - What about a delete that keeps the name but un-advertises the service? How would we indicate that?
1507 // Maybe if there's no service PTR for the service?
1508 // - Changes means that the contents of the text record changed, or the contents of the SRV record
1509 // changed (but not the hostname) or both.
1510 // - New means that we don't have a service with that service instance name on the host (and we previously
1511 // eliminated the possibility that it exists on some other host).
1513 // Allocate the update structure.
1514 update
= calloc(1, sizeof *update
);
1515 if (update
== NULL
) {
1516 ERROR("prepare_update: no memory for update.");
1520 // The maximum number of addresses we could be deleting is all the ones the host currently has.
1521 num_remove_addrs
= host
->num_addresses
;
1522 if (num_remove_addrs
!= 0) {
1523 remove_addrs
= calloc(num_remove_addrs
, sizeof *remove_addrs
);
1524 // If we can't allocate space, just wait a bit.
1525 if (remove_addrs
== NULL
) {
1526 ERROR("prepare_update: no memory for remove_addrs");
1530 remove_addrs
= NULL
;
1534 for (addr
= client_update
->host
->addrs
; addr
!= NULL
; addr
= addr
->next
) {
1537 add_addrs
= calloc(num_add_addrs
, sizeof *add_addrs
);
1538 if (add_addrs
== NULL
) {
1539 ERROR("prepare_update: no memory for add_addrs");
1543 // Copy all of the addresses in the update into add_addresses
1545 for (addr
= client_update
->host
->addrs
; addr
; addr
= addr
->next
) {
1546 adv_address_t
*prepared_address
= adv_address_create(addr
, host
);
1547 if (prepared_address
== NULL
) {
1548 ERROR("prepare_update: No memory for prepared address");
1551 add_addrs
[num_add_addrs
++] = prepared_address
;
1554 // For every host address, see if it's in add_addresses. If it's not, it needs to be removed.
1555 // If it is, it doesn't need to be added.
1556 if (num_remove_addrs
!= 0) {
1557 memcpy(remove_addrs
, host
->addresses
, num_remove_addrs
* sizeof *remove_addrs
);
1558 for (i
= 0; i
< num_remove_addrs
; i
++) {
1559 if (host
->addresses
[i
] != NULL
) {
1560 remove_addrs
[i
] = host
->addresses
[i
];
1561 RETAIN_HERE(remove_addrs
[i
]);
1563 for (j
= 0; j
< num_add_addrs
; j
++) {
1564 // If the address is present in both places, remove it from the list of addresses to
1565 // add, and also remove it from the list of addresses to remove. When we're done,
1566 // all that will be remaining in the list to remove will be addresses that weren't present
1568 if (remove_addrs
[i
] != NULL
&& add_addrs
[j
] != NULL
&&
1569 add_addrs
[j
]->rrtype
== remove_addrs
[i
]->rrtype
&&
1570 !memcmp(&add_addrs
[j
]->rdata
, remove_addrs
[i
]->rdata
, remove_addrs
[i
]->rdlen
))
1572 RELEASE_HERE(remove_addrs
[i
], adv_address_finalize
);
1573 remove_addrs
[i
] = NULL
;
1574 RELEASE_HERE(add_addrs
[j
], adv_address_finalize
);
1575 add_addrs
[j
] = NULL
;
1581 // We can never update more instances than currently exist for this host.
1582 num_update_instances
= host
->instances
->num
;
1583 num_remove_instances
= host
->instances
->num
;
1585 update_instances
= adv_instance_vec_create(num_update_instances
);
1586 if (update_instances
== NULL
) {
1587 ERROR("prepare_update: no memory for update_instances");
1590 update_instances
->num
= num_update_instances
;
1592 // We aren't actually deleting any instances, but...
1593 remove_instances
= adv_instance_vec_create(num_remove_instances
);
1594 if (remove_instances
== NULL
) {
1595 ERROR("prepare_update: no memory for remove_instances");
1598 remove_instances
->num
= num_remove_instances
;
1600 // The number of instances to add can be as many as there are instances in the update.
1601 num_add_instances
= 0;
1602 for (instance
= client_update
->instances
; instance
; instance
= instance
->next
) {
1603 num_add_instances
++;
1605 add_instances
= adv_instance_vec_create(num_add_instances
);
1606 if (add_instances
== NULL
) {
1607 ERROR("prepare_update: no memory for add_instances");
1611 // Convert all of the instances in the client update to adv_instance_t structures for easy comparison.
1612 // Any that are unchanged will have to be freed--oh well.
1614 for (instance
= client_update
->instances
; instance
!= NULL
; instance
= instance
->next
) {
1615 adv_instance_t
*prepared_instance
= adv_instance_create(instance
, host
, update
);
1616 if (prepared_instance
== NULL
) {
1617 // prepare_instance logs.
1620 if (i
>= num_add_instances
) {
1621 ERROR("prepare_update: while preparing client update instances, i >= num_add_instances");
1624 add_instances
->vec
[i
++] = prepared_instance
;
1626 add_instances
->num
= i
;
1628 // The instances in the update are now in add_instances. If they are updates, move them to update_instances.
1629 // If they are unchanged, free them and null them out. If they are adds, leave them.
1630 for (i
= 0; i
< num_add_instances
; i
++) {
1631 adv_instance_t
*add_instance
= add_instances
->vec
[i
];
1633 for (j
= 0; j
< host
->instances
->num
; j
++) {
1634 adv_instance_t
*host_instance
= host
->instances
->vec
[j
];
1636 // See if the instance names match.
1637 if (!strcmp(add_instance
->instance_name
, host_instance
->instance_name
) &&
1638 !strcmp(add_instance
->service_type
, host_instance
->service_type
))
1640 // If the rdata is the same, it's not an add or an update.
1641 if (add_instance
->txt_length
== host_instance
->txt_length
&&
1642 add_instance
->port
== host_instance
->port
&&
1643 (add_instance
->txt_length
== 0 ||
1644 !memcmp(add_instance
->txt_data
, host_instance
->txt_data
, add_instance
->txt_length
)))
1646 RELEASE_HERE(add_instance
, adv_instance_finalize
);
1648 // Implicit RETAIN/RELEASE
1649 update_instances
->vec
[j
] = add_instance
;
1651 add_instances
->vec
[i
] = NULL
;
1657 // At this point we have figured out all the work we need to do, so hang it off an update structure.
1658 update
->host
= host
;
1659 update
->client
= client_update
;
1660 host
->clients
= client_update
->next
;
1661 update
->num_remove_addresses
= num_remove_addrs
;
1662 update
->remove_addresses
= remove_addrs
;
1663 update
->num_add_addresses
= num_add_addrs
;
1664 update
->add_addresses
= add_addrs
;
1665 update
->remove_instances
= remove_instances
;
1666 update
->add_instances
= add_instances
;
1667 update
->update_instances
= update_instances
;
1668 update
->host_lease
= client_update
->host_lease
;
1669 update
->key_lease
= client_update
->key_lease
;
1671 update
->next
= host
->updates
;
1672 host
->updates
= update
;
1674 start_host_update(host
);
1678 if (remove_addrs
!= NULL
) {
1679 // Addresses in remove_addrs are owned by the host and don't need to be freed.
1682 if (add_addrs
!= NULL
) {
1683 // Addresses in add_addrs are ours, so we have to free them.
1684 for (i
= 0; i
< num_add_addrs
; i
++) {
1685 if (add_addrs
[i
] != NULL
) {
1686 RELEASE_HERE(add_addrs
[i
], adv_address_finalize
);
1691 if (add_instances
!= NULL
) {
1692 RELEASE_HERE(add_instances
, adv_instance_vec_finalize
);
1693 add_instances
= NULL
;
1695 if (remove_instances
!= NULL
) {
1696 RELEASE_HERE(remove_instances
, adv_instance_vec_finalize
);
1697 remove_instances
= NULL
;
1699 if (update_instances
!= NULL
) {
1700 RELEASE_HERE(update_instances
, adv_instance_vec_finalize
);
1701 update_instances
= NULL
;
1704 if (update
->client
!= NULL
) {
1705 update
->client
->next
= host
->clients
;
1706 host
->clients
= update
->client
;
1711 // Try again sometime later.
1715 typedef enum { missed
, match
, conflict
} instance_outcome_t
;
1716 static instance_outcome_t
1717 compare_instance(adv_instance_t
*instance
,
1718 dns_host_description_t
*new_host
, adv_host_t
*host
,
1719 char *instance_name
, char *service_type
)
1721 if (instance
== NULL
) {
1724 if (!strcmp(instance_name
, instance
->instance_name
) && !strcmp(service_type
, instance
->service_type
)) {
1725 if (!dns_names_equal_text(new_host
->name
, host
->name
)) {
1734 srp_update_start(comm_t
*connection
, dns_message_t
*parsed_message
, message_t
*raw_message
,
1735 dns_host_description_t
*new_host
, service_instance_t
*instances
, service_t
*services
,
1736 dns_name_t
*update_zone
, uint32_t lease_time
, uint32_t key_lease_time
)
1738 adv_host_t
*host
, **p_hosts
= NULL
;
1739 char pres_name
[DNS_MAX_NAME_SIZE_ESCAPED
+ 1];
1741 service_instance_t
*new_instance
, *client_instance
;
1742 instance_outcome_t outcome
= missed
;
1743 adv_update_t
*update
;
1744 client_update_t
*client_update
, **p_client_update
;
1745 char instance_name
[DNS_MAX_LABEL_SIZE_ESCAPED
+ 1];
1746 char service_type
[DNS_MAX_LABEL_SIZE_ESCAPED
* 2 + 2];
1747 uint32_t key_id
= 0;
1748 char new_host_name
[DNS_MAX_NAME_SIZE_ESCAPED
+ 1];
1750 const bool remove
= lease_time
== 0;
1751 const char *updatestr
= lease_time
== 0 ? "remove" : "update";
1752 dns_name_print(new_host
->name
, new_host_name
, sizeof new_host_name
);
1754 // Compute a checksum on the key, ignoring up to three bytes at the end.
1755 for (i
= 0; i
< new_host
->key
->data
.key
.len
; i
+= 4) {
1756 key_id
+= ((new_host
->key
->data
.key
.key
[i
] << 24) | (new_host
->key
->data
.key
.key
[i
+ 1] << 16) |
1757 (new_host
->key
->data
.key
.key
[i
+ 2] << 8) | (new_host
->key
->data
.key
.key
[i
+ 3]));
1760 // Log the update info.
1761 INFO("srp_update_start: host update for " PRI_S_SRP
", key id %" PRIx32
, new_host_name
, key_id
);
1762 for (addr
= new_host
->addrs
; addr
!= NULL
; addr
= addr
->next
) {
1763 if (addr
->rr
.type
== dns_rrtype_a
) {
1764 IPv4_ADDR_GEN_SRP(&addr
->rr
.data
.a
.s_addr
, addr_buf
);
1765 INFO("srp_update_start: host " PUB_S_SRP
" for " PRI_S_SRP
", address " PRI_IPv4_ADDR_SRP
, updatestr
,
1766 new_host_name
, IPv4_ADDR_PARAM_SRP(&addr
->rr
.data
.a
.s_addr
, addr_buf
));
1768 SEGMENTED_IPv6_ADDR_GEN_SRP(addr
->rr
.data
.aaaa
.s6_addr
, addr_buf
);
1769 INFO("srp_update_start: host " PUB_S_SRP
" for " PRI_S_SRP
", address " PRI_SEGMENTED_IPv6_ADDR_SRP
,
1770 updatestr
, new_host_name
, SEGMENTED_IPv6_ADDR_PARAM_SRP(addr
->rr
.data
.aaaa
.s6_addr
, addr_buf
));
1773 for (new_instance
= instances
; new_instance
!= NULL
; new_instance
= new_instance
->next
) {
1774 extract_instance_name(instance_name
, sizeof instance_name
, service_type
, sizeof service_type
, new_instance
);
1775 INFO("srp_update_start: host " PUB_S_SRP
" for " PRI_S_SRP
", instance name " PRI_S_SRP
", type " PRI_S_SRP
1776 ", port %d", updatestr
, new_host_name
, instance_name
, service_type
,
1777 new_instance
->srv
!= NULL
? new_instance
->srv
->data
.srv
.port
: -1);
1780 // SRP doesn't currently support removal. I think it needs to, but I'm going to mostly leave that
1781 // out of this code for now.
1783 // Look for matching service instance names. A service instance name that matches, but has a different
1784 // hostname, means that there is a conflict. We have to look through all the entries; the presence of
1785 // a matching hostname doesn't mean we are done UNLESS there's a matching service instance name pointing
1786 // to that hostname.
1787 for (host
= hosts
; host
; host
= host
->next
) {
1788 // We need to look for matches both in the registered instances for this registration, and also in
1789 // the list of new instances, in case we get a duplicate update while a previous update is in progress.
1790 for (new_instance
= instances
; new_instance
; new_instance
= new_instance
->next
) {
1791 extract_instance_name(instance_name
, sizeof instance_name
, service_type
, sizeof service_type
, new_instance
);
1793 // First check for a match or conflict in the host itself.
1794 for (i
= 0; i
< host
->instances
->num
; i
++) {
1795 outcome
= compare_instance(host
->instances
->vec
[i
], new_host
, host
,
1796 instance_name
, service_type
);
1797 if (outcome
!= missed
) {
1798 goto found_something
;
1801 // Then look for the same thing in any subsequent updates that have been baked.
1802 for (update
= host
->updates
; update
; update
= update
->next
) {
1803 for (i
= 0; i
< update
->add_instances
->num
; i
++) {
1804 outcome
= compare_instance(update
->add_instances
->vec
[i
], new_host
, host
,
1805 instance_name
, service_type
);
1806 if (outcome
!= missed
) {
1807 goto found_something
;
1811 // Finally, look for it in any updates that _haven't_ been baked.
1812 for (client_update
= host
->clients
; client_update
; client_update
= client_update
->next
) {
1813 for (client_instance
= client_update
->instances
; client_instance
;
1814 client_instance
= client_instance
->next
) {
1815 if (dns_names_equal(client_instance
->name
, new_instance
->name
)) {
1816 if (!dns_names_equal_text(new_host
->name
, host
->name
)) {
1821 goto found_something
;
1828 if (outcome
== conflict
) {
1829 ERROR("srp_update_start: service instance name " PRI_S_SRP
"/" PRI_S_SRP
" already pointing to host "
1830 PRI_S_SRP
", not host " PRI_S_SRP
, instance_name
, service_type
, host
->name
, new_host_name
);
1831 advertise_finished(connection
, raw_message
, dns_rcode_yxdomain
, NULL
);
1835 // If we fall off the end looking for a matching service instance, there isn't a matching
1836 // service instance, but there may be a matching host, so look for that.
1837 if (outcome
== missed
) {
1838 for (p_hosts
= &hosts
; *p_hosts
; p_hosts
= &host
->next
) {
1840 if (dns_names_equal_text(new_host
->name
, host
->name
)) {
1841 if (key_id
== host
->key_id
&& dns_keys_rdata_equal(new_host
->key
, &host
->key
)) {
1845 ERROR("srp_update_start: update for host " PRI_S_SRP
" has key id %" PRIx32
1846 " which doesn't match host key id %" PRIx32
".",
1847 host
->name
, key_id
, host
->key_id
);
1848 advertise_finished(connection
, raw_message
, dns_rcode_yxdomain
, NULL
);
1853 if (key_id
!= host
->key_id
|| !dns_keys_rdata_equal(new_host
->key
, &host
->key
)) {
1854 ERROR("srp_update_start: new host with name " PRI_S_SRP
" and key id %" PRIx32
1855 " conflicts with existing host %s with key id %" PRIx32
,
1856 new_host_name
, key_id
, host
->name
, host
->key_id
);
1857 advertise_finished(connection
, raw_message
, dns_rcode_yxdomain
, NULL
);
1862 // If we didn't find a matching host, we can make a new one. When we create it, it just has
1863 // a name and no records. The update that we then construct will have the missing records.
1864 // We don't want to do this for a remove, obviously.
1865 if (outcome
== missed
) {
1867 ERROR("Remove for host " PRI_S_SRP
" which doesn't exist.", new_host_name
);
1868 advertise_finished(connection
, raw_message
, dns_rcode_nxdomain
, NULL
);
1872 host
= calloc(1, sizeof *host
);
1874 ERROR("srp_update_start: no memory for host data structure.");
1875 advertise_finished(connection
, raw_message
, dns_rcode_servfail
, NULL
);
1878 host
->instances
= adv_instance_vec_create(0);
1879 if (host
->instances
== NULL
) {
1880 ERROR("srp_update_start: no memory for host instance vector.");
1881 advertise_finished(connection
, raw_message
, dns_rcode_servfail
, NULL
);
1882 host_finalize(host
);
1886 host
->retry_wakeup
= ioloop_wakeup_create();
1887 if (host
->retry_wakeup
!= NULL
) {
1888 host
->lease_wakeup
= ioloop_wakeup_create();
1890 if (host
->lease_wakeup
== NULL
) {
1891 ERROR("srp_update_start: no memory for wake event on host");
1892 advertise_finished(connection
, raw_message
, dns_rcode_servfail
, NULL
);
1893 host_finalize(host
);
1896 dns_name_print(new_host
->name
, pres_name
, sizeof pres_name
);
1897 host
->name
= strdup(pres_name
);
1898 if (host
->name
== NULL
) {
1899 host_finalize(host
);
1900 ERROR("srp_update_start: no memory for hostname.");
1901 advertise_finished(connection
, raw_message
, dns_rcode_servfail
, NULL
);
1904 host
->key
= *new_host
->key
;
1905 #ifndef __clang_analyzer__
1906 // Normally this would be invalid, but we never use the name of the key record.
1907 host
->key
.name
= NULL
;
1909 host
->key_rdlen
= new_host
->key
->data
.key
.len
+ 4;
1910 host
->key_rdata
= malloc(host
->key_rdlen
);
1911 if (host
->key_rdata
== NULL
) {
1912 host_finalize(host
);
1913 ERROR("srp_update_start: no memory for host key.");
1914 advertise_finished(connection
, raw_message
, dns_rcode_servfail
, NULL
);
1917 memcpy(host
->key_rdata
, &new_host
->key
->data
.key
.flags
, 2);
1918 host
->key_rdata
[2] = new_host
->key
->data
.key
.protocol
;
1919 host
->key_rdata
[3] = new_host
->key
->data
.key
.algorithm
;
1920 memcpy(&host
->key_rdata
[4], new_host
->key
->data
.key
.key
, new_host
->key
->data
.key
.len
);
1921 host
->key
.data
.key
.key
= &host
->key_rdata
[4];
1922 host
->key_id
= key_id
;
1924 // Tack this on to the end of the list. The if test is because the optimizer doesn't notice
1925 // that p_hosts can never be null here--it will always be pointing to the end of the list of
1926 // hosts if we get here.
1927 if (p_hosts
!= NULL
) {
1933 // See if this is a retransmission.
1934 for (update
= host
->updates
; update
; update
= update
->next
) {
1935 if (update
->client
!= NULL
&&
1936 update
->client
->message
->wire
.id
== raw_message
->wire
.id
) {
1938 INFO("srp_update_start: dropping retransmission of in-progress update for host " PRI_S_SRP
, host
->name
);
1940 srp_update_free_parts(instances
, NULL
, services
, new_host
);
1941 dns_message_free(parsed_message
);
1945 // Do the same for client updates.
1946 for (p_client_update
= &host
->clients
; *p_client_update
; p_client_update
= &client_update
->next
) {
1947 client_update
= *p_client_update
;
1948 if (client_update
->message
->wire
.id
== raw_message
->wire
.id
) {
1949 goto retransmission
;
1953 // If this is a remove, just remove the host.
1955 lease_callback(host
);
1956 advertise_finished(connection
, raw_message
, dns_rcode_noerror
, NULL
);
1960 // At this point we have an update and a host to which to apply it. We may already be doing an earlier
1961 // update, or not. Create a client update structure to hold the communication, so that when we are done,
1963 client_update
= calloc(1, sizeof *client_update
);
1964 if (client_update
== NULL
) {
1965 ERROR("srp_update_start: no memory for host data structure.");
1966 advertise_finished(connection
, raw_message
, dns_rcode_servfail
, NULL
);
1970 if (outcome
== missed
) {
1971 INFO("srp_update_start: New host " PRI_S_SRP
", key id %" PRIx32
, host
->name
, host
->key_id
);
1973 if (host
->registered_name
!= host
->name
) {
1974 INFO("srp_update_start: Renewing host " PRI_S_SRP
", alias %s, key id %" PRIx32
,
1975 host
->name
, host
->registered_name
, host
->key_id
);
1977 INFO("srp_update_start: Renewing host " PRI_S_SRP
", key id %" PRIx32
, host
->name
, host
->key_id
);
1981 if (host
->registered_name
== NULL
) {
1982 host
->registered_name
= host
->name
;
1985 client_update
->connection
= connection
;
1986 ioloop_comm_retain(client_update
->connection
);
1987 client_update
->parsed_message
= parsed_message
;
1988 client_update
->message
= raw_message
;
1989 ioloop_message_retain(client_update
->message
);
1990 client_update
->host
= new_host
;
1991 client_update
->instances
= instances
;
1992 client_update
->services
= services
;
1993 client_update
->update_zone
= update_zone
;
1994 if (lease_time
< max_lease_time
) {
1995 client_update
->host_lease
= lease_time
;
1997 client_update
->host_lease
= max_lease_time
;
1999 if (key_lease_time
< max_lease_time
* 7) {
2000 client_update
->key_lease
= key_lease_time
;
2002 client_update
->key_lease
= max_lease_time
* 7;
2004 *p_client_update
= client_update
;
2006 // If we aren't already applying an update to this host, apply this update now.
2007 if (host
->updates
== NULL
) {
2008 INFO("srp_update_start: No ongoing host update: preparing this update to be applied.");
2009 prepare_update(host
);
2011 INFO("srp_update_start: waiting for existing update to complete on host " PRI_S_SRP
" before applying another.",
2017 #if defined(IOLOOP_MACOS)
2019 adv_proxy_enable(xpc_object_t request
, xpc_connection_t connection
)
2021 srp_xpc_client_t
*client
, **p_client
;
2022 xpc_object_t response
;
2023 int err
= kDNSSDAdvertisingProxyStatus_NoError
;
2025 response
= xpc_dictionary_create_reply(request
);
2026 if (response
== NULL
) {
2027 ERROR("adv_proxy_enable: Unable to create reply dictionary.");
2031 client
= calloc(1, sizeof(*client
));
2032 if (client
== NULL
) {
2033 ERROR("adv_proxy_enable: unable to allocate client state structure.");
2034 err
= kDNSSDAdvertisingProxyStatus_NoMemory
;
2037 if (srp_wanted
== NULL
) {
2038 srp_wanted
= calloc(1, sizeof(*srp_wanted
));
2039 if (srp_wanted
== NULL
) {
2041 ERROR("adv_proxy_enable: unable to allocate srp_wanted structure.");
2042 err
= kDNSSDAdvertisingProxyStatus_NoMemory
;
2045 srp_wanted
->transaction
= os_transaction_create("com.apple.srp-mdns-proxy.ostransaction");
2047 thread_network_startup();
2049 RETAIN_HERE(srp_wanted
);
2051 client
->connection
= connection
;
2052 xpc_retain(client
->connection
);
2053 client
->enabler
= true;
2055 INFO("adv_proxy_enable: connection from client: %p", client
);
2057 // Find the end of the list.
2058 for (p_client
= &srp_xpc_clients
; *p_client
!= NULL
; p_client
= &(*p_client
)->next
) {
2063 xpc_dictionary_set_uint64(response
, kDNSAdvertisingProxyResponseStatus
, err
);
2064 xpc_connection_send_message(connection
, response
);
2065 xpc_release(response
);
2066 if (err
== kDNSSDAdvertisingProxyStatus_NoError
) {
2073 srp_wanted_finalize(srp_wanted_state_t
*__unused wanted
)
2075 INFO("adv_proxy_enable: No longer wanted.");
2076 os_release(srp_wanted
->transaction
);
2079 thread_network_shutdown();
2083 adv_xpc_connection_delete(xpc_connection_t connection
)
2085 srp_xpc_client_t
**p_client
, *client
;
2087 for (p_client
= &srp_xpc_clients
; *p_client
!= NULL
; ) {
2089 if (client
->connection
== connection
) {
2090 xpc_release(client
->connection
);
2091 if (client
->enabler
) {
2092 RELEASE_HERE(srp_wanted
, srp_wanted_finalize
);
2094 *p_client
= client
->next
;
2095 INFO("adv_xpc_connection_delete: deleting client: %p", client
);
2099 p_client
= &(*p_client
)->next
;
2104 adv_xpc_disconnect(void)
2106 srp_xpc_client_t
*client
;
2108 for (client
= srp_xpc_clients
; client
!= NULL
; client
= client
->next
) {
2109 if (client
->connection
!= NULL
&& !client
->connection_canceled
) {
2110 INFO("adv_xpc_disconnect: disconnecting " PUB_S_SRP
"client: %p", client
->enabler
? "enabler " : "",
2112 client
->connection_canceled
= true;
2113 xpc_connection_cancel(client
->connection
);
2118 static bool adv_xpc_message(xpc_connection_t NULLABLE connection
, xpc_object_t NULLABLE request
);
2120 static wakeup_t
*adv_xpc_wakeup
;
2123 adv_xpc_restart(void *__unused context
)
2125 xpc_listener
= ioloop_create_xpc_service(kDNSAdvertisingProxyService
, adv_xpc_message
);
2126 if (xpc_listener
== NULL
) {
2127 ioloop_add_wake_event(adv_xpc_wakeup
, NULL
, adv_xpc_restart
, NULL
, 10000);
2132 adv_xpc_list_services(xpc_connection_t request
, xpc_object_t connection
)
2134 xpc_object_t instances
= xpc_array_create(NULL
, 0);
2136 xpc_object_t response
;
2138 char addrbuf
[INET6_ADDRSTRLEN
];
2139 int64_t now
= ioloop_timenow();
2141 adv_instance_t
*instance
= NULL
;
2143 if (instances
== NULL
) {
2144 ERROR("adv_xpc_list_services: Unable to create service array");
2148 response
= xpc_dictionary_create_reply(request
);
2149 if (response
== NULL
) {
2150 ERROR("adv_xpc_list_services: Unable to create reply dictionary.");
2153 xpc_dictionary_set_uint64(response
, kDNSAdvertisingProxyResponseStatus
, kDNSSDAdvertisingProxyStatus_NoError
);
2155 for (host
= hosts
; host
!= NULL
; host
= host
->next
) {
2156 if (host
->num_addresses
> 0) {
2157 inet_ntop(AF_INET6
, host
->addresses
[0]->rdata
, addrbuf
, sizeof(addrbuf
));
2159 if (instances
== NULL
) {
2160 ERROR("adv_xpc_list_services: failed to allocate instance array for " PRI_S_SRP
, host
->name
);
2165 for (i
= 0; i
< host
->instances
->num
; i
++) {
2166 if (host
->instances
->vec
[i
] != NULL
) {
2167 instance
= host
->instances
->vec
[i
];
2169 dict
= xpc_dictionary_create(NULL
, NULL
, 0);
2171 ERROR("adv_xpc_list_services: failed to allocate instance dictionary for " PRI_S_SRP
, host
->name
);
2174 xpc_dictionary_set_string(dict
, "hostname", host
->name
);
2175 xpc_dictionary_set_string(dict
, "regname", host
->registered_name
);
2178 xpc_dictionary_set_string(dict
, "name", instance
->instance_name
);
2179 xpc_dictionary_set_string(dict
, "type", instance
->service_type
);
2180 snprintf(portbuf
, sizeof(portbuf
), "%u", instance
->port
);
2181 xpc_dictionary_set_string(dict
, "port", portbuf
);
2182 xpc_dictionary_set_data(dict
, "txt", instance
->txt_data
, instance
->txt_length
);
2184 if (host
->num_addresses
> 0) {
2185 xpc_dictionary_set_string(dict
, "address", addrbuf
);
2187 xpc_dictionary_set_int64(dict
, "lease", host
->lease_expiry
>= now
? host
->lease_expiry
- now
: -1);
2188 xpc_array_append_value(instances
, dict
);
2199 xpc_dictionary_set_value(response
, "instances", instances
);
2200 xpc_release(instances
);
2201 xpc_connection_send_message(connection
, response
);
2202 xpc_release(response
);
2205 if (instances
!= NULL
) {
2206 xpc_release(instances
);
2208 if (response
!= NULL
) {
2209 xpc_release(response
);
2215 adv_xpc_block_service(xpc_connection_t request
, xpc_object_t connection
, bool enable
)
2217 xpc_object_t response
;
2218 int status
= kDNSSDAdvertisingProxyStatus_NoError
;
2219 extern srp_proxy_listener_state_t
*srp_listener
;
2221 response
= xpc_dictionary_create_reply(request
);
2222 if (response
== NULL
) {
2223 ERROR("adv_xpc_list_services: Unable to create reply dictionary.");
2228 if (srp_listener
!= NULL
) {
2229 srp_proxy_listener_cancel(srp_listener
);
2230 srp_listener
= NULL
;
2232 status
= kDNSSDAdvertisingProxyStatus_UnknownErr
;
2235 if (srp_listener
== NULL
) {
2236 partition_start_srp_listener();
2238 status
= kDNSSDAdvertisingProxyStatus_UnknownErr
;
2242 xpc_dictionary_set_uint64(response
, kDNSAdvertisingProxyResponseStatus
, status
);
2243 xpc_connection_send_message(connection
, response
);
2244 xpc_release(response
);
2249 adv_xpc_regenerate_ula(xpc_connection_t request
, xpc_object_t connection
)
2251 xpc_object_t response
;
2252 int status
= kDNSSDAdvertisingProxyStatus_NoError
;
2254 response
= xpc_dictionary_create_reply(request
);
2255 if (response
== NULL
) {
2256 ERROR("adv_xpc_list_services: Unable to create reply dictionary.");
2260 partition_stop_advertising_pref_id();
2261 thread_network_shutdown();
2263 thread_network_startup();
2265 xpc_dictionary_set_uint64(response
, kDNSAdvertisingProxyResponseStatus
, status
);
2266 xpc_connection_send_message(connection
, response
);
2267 xpc_release(response
);
2273 srp_mdns_flush(void)
2275 adv_host_t
*host
, *host_next
;
2277 INFO("srp_mdns_flush: flushing all host entries.");
2278 for (host
= hosts
; host
; host
= host_next
) {
2279 INFO("srp_mdns_flush: Flushing services and host entry for " PRI_S_SRP
" (" PRI_S_SRP
")",
2280 host
->name
, host
->registered_name
);
2281 // Get rid of the updates before calling lease_callback, which will fail if update is not NULL.
2282 if (host
->updates
!= NULL
) {
2283 adv_update_t
*update_next
, *update
= host
->updates
->next
;
2284 update_failed(host
->updates
, dns_rcode_refused
, false);
2285 while (update
!= NULL
) {
2286 update_next
= update
->next
;
2287 update
->host
= NULL
;
2288 update_finalize(update
);
2289 update
= update_next
;
2291 host
->updates
= NULL
;
2293 // Get rid of clients for the same reason.
2294 if (host
->clients
!= NULL
) {
2295 client_update_t
*client
, *client_next
;
2296 for (client
= host
->clients
; client
; client
= client_next
) {
2297 client_next
= client
->next
;
2298 client_finalize(client
);
2300 host
->clients
= NULL
;
2302 host_next
= host
->next
;
2303 host_finalize(host
);
2309 adv_xpc_message(xpc_connection_t connection
, xpc_object_t request
)
2314 // This means that the listener failed for some reason. Try again in ten seconds.
2315 if (connection
== NULL
&& request
== NULL
) {
2316 if (adv_xpc_wakeup
== NULL
) {
2317 adv_xpc_wakeup
= ioloop_wakeup_create();
2318 if (adv_xpc_wakeup
== NULL
) {
2319 INFO("adv_xpc_message: can't create a wakeup to try to recover.");
2323 ioloop_cancel_wake_event(adv_xpc_wakeup
);
2325 ioloop_add_wake_event(adv_xpc_wakeup
, NULL
, adv_xpc_restart
, NULL
, 10000);
2329 if (connection
== NULL
) {
2330 INFO("adv_xpc_message: disconnected.");
2334 pid
= xpc_connection_get_pid(connection
);
2335 uid
= xpc_connection_get_euid(connection
);
2337 if (request
== NULL
) {
2338 INFO("adv_xpc_message: Client uid %d pid %d disconnected.", uid
, pid
);
2339 adv_xpc_connection_delete(connection
);
2343 const char *message_type
= xpc_dictionary_get_string(request
, kDNSAdvertisingProxyCommand
);
2345 if (message_type
== NULL
) {
2346 ERROR("Client uid %d pid %d sent a request with no message type.", uid
, pid
);
2347 adv_xpc_connection_delete(connection
);
2348 // Close the connection
2352 if (!strcmp(message_type
, kDNSAdvertisingProxyEnable
)) {
2353 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP
" request.", uid
, pid
, message_type
);
2354 return adv_proxy_enable(request
, connection
);
2355 } else if (!strcmp(message_type
, kDNSAdvertisingProxyListServiceTypes
)) {
2356 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP
" request.", uid
, pid
, message_type
);
2357 } else if (!strcmp(message_type
, kDNSAdvertisingProxyListServices
)) {
2358 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP
" request.", uid
, pid
, message_type
);
2359 return adv_xpc_list_services(request
, connection
);
2360 } else if (!strcmp(message_type
, kDNSAdvertisingProxyListHosts
)) {
2361 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP
" request.", uid
, pid
, message_type
);
2362 } else if (!strcmp(message_type
, kDNSAdvertisingProxyGetHost
)) {
2363 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP
" request.", uid
, pid
, message_type
);
2364 } else if (!strcmp(message_type
, kDNSAdvertisingProxyFlushEntries
)) {
2365 INFO("adv_xpc_message: Client uid %d pid %d sent a %s request.", uid
, pid
, message_type
);
2367 } else if (!strcmp(message_type
, kDNSAdvertisingProxyBlockService
)) {
2368 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP
" request.", uid
, pid
, message_type
);
2369 adv_xpc_block_service(request
, connection
, true);
2370 } else if (!strcmp(message_type
, kDNSAdvertisingProxyUnblockService
)) {
2371 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP
" request.", uid
, pid
, message_type
);
2372 adv_xpc_block_service(request
, connection
, false);
2373 } else if (!strcmp(message_type
, kDNSAdvertisingProxyRegenerateULA
)) {
2374 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP
" request.", uid
, pid
, message_type
);
2375 adv_xpc_regenerate_ula(request
, connection
);
2377 ERROR("Client uid %d pid %d sent a request with unknown message type " PUB_S_SRP
".", uid
, pid
, message_type
);
2378 // Close the connection
2379 adv_xpc_connection_delete(connection
);
2383 xpc_object_t response
;
2384 response
= xpc_dictionary_create_reply(request
);
2385 if (response
== NULL
) {
2386 ERROR("adv_xpc_message: Unable to create reply dictionary.");
2389 xpc_dictionary_set_uint64(response
, kDNSAdvertisingProxyResponseStatus
, kDNSSDAdvertisingProxyStatus_NoError
);
2390 xpc_connection_send_message(connection
, response
);
2391 xpc_release(response
);
2399 ERROR("srp-mdns-proxy [--max-lease-time <seconds>] [--log-stderr]");
2404 main(int argc
, char **argv
)
2408 int log_stderr
= false;
2410 for (i
= 1; i
< argc
; i
++) {
2411 if (!strcmp(argv
[i
], "--max-lease-time")) {
2412 if (i
+ 1 == argc
) {
2415 max_lease_time
= (uint32_t)strtoul(argv
[i
+ 1], &end
, 10);
2416 if (end
== argv
[i
+ 1] || end
[0] != 0) {
2420 } else if (!strcmp(argv
[i
], "--log-stderr")) {
2427 OPENLOG(log_stderr
);
2428 INFO("--------------------------------srp-mdns-proxy starting--------------------------------");
2430 if (!ioloop_init()) {
2434 if (!start_icmp_listener()) {
2439 // On MacOS, drop privileges once we have the ICMP listener.
2440 #ifdef DROP_PRIVILEGES
2442 ssize_t bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
);
2446 char *getpwnam_r_buf
= malloc(bufsize
);
2447 struct passwd mdnsresponder_pwd
;
2448 int mdnsresponder_uid
= 65; // This is what's in /etc/passwd now.
2449 if (getpwnam_r_buf
!= NULL
) {
2450 struct passwd
*result
;
2451 ret
= getpwnam_r("_mdnsresponder", &mdnsresponder_pwd
, getpwnam_r_buf
, bufsize
, &result
);
2452 if (ret
< 0 || result
== NULL
) {
2453 ERROR("getpwnam_r failed: " PUB_S_SRP
, strerror(ret
));
2455 mdnsresponder_uid
= mdnsresponder_pwd
.pw_uid
;
2457 free(getpwnam_r_buf
);
2460 ERROR("Unable to allocate getpwnam_r buffer.");
2462 ret
= setuid(mdnsresponder_uid
);
2464 ERROR("setuid failed: " PUB_S_SRP
, strerror(errno
));
2468 // On MacOS, we can set up an XPC service to check on registrations and also to start the service
2470 xpc_listener
= ioloop_create_xpc_service(kDNSAdvertisingProxyService
, adv_xpc_message
);
2471 if (xpc_listener
== NULL
) {
2476 // We require one open file per service and one per instance.
2477 struct rlimit limits
;
2478 if (getrlimit(RLIMIT_NOFILE
, &limits
) < 0) {
2479 ERROR("getrlimit failed: " PUB_S_SRP
, strerror(errno
));
2483 if (limits
.rlim_cur
< 1024) {
2484 if (limits
.rlim_max
< 1024) {
2485 INFO("getrlimit: file descriptor hard limit is %llu", limits
.rlim_max
);
2486 if (limits
.rlim_cur
!= limits
.rlim_max
) {
2487 limits
.rlim_cur
= limits
.rlim_max
;
2490 limits
.rlim_cur
= 1024;
2492 if (setrlimit(RLIMIT_NOFILE
, &limits
) < 0) {
2493 ERROR("setrlimit failed: " PUB_S_SRP
, strerror(errno
));
2500 INFO("dispatched %d events.", something
);
2507 // c-file-style: "bsd"
2508 // c-basic-offset: 4
2510 // indent-tabs-mode: nil