srp-mdns-proxy.c revision 1.1 1 /* srp-mdns-proxy.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 * This file contains the SRP Advertising Proxy, which is an SRP Server
18 * that offers registered addresses using mDNS.
19 */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <time.h>
25 #include <unistd.h>
26 #include <pwd.h>
27 #include <errno.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <fcntl.h>
32 #include <time.h>
33 #include <dns_sd.h>
34 #include <net/if.h>
35 #include <inttypes.h>
36 #include <sys/resource.h>
37 #include <ctype.h>
38 #include <mdns/pf.h>
39
40 #include "srp.h"
41 #include "dns-msg.h"
42 #include "srp-crypto.h"
43 #include "ioloop.h"
44 #include "srp-gw.h"
45 #include "srp-proxy.h"
46 #include "srp-mdns-proxy.h"
47 #include "dnssd-proxy.h"
48 #include "config-parse.h"
49 #include "cti-services.h"
50 #include "route.h"
51 #include "adv-ctl-server.h"
52 #include "srp-replication.h"
53 #include "ioloop-common.h"
54 #include "thread-device.h"
55 #include "nat64-macos.h"
56 #include "srp-dnssd.h"
57 #include "ifpermit.h"
58 #include "state-machine.h"
59 #include "thread-service.h"
60 #include "omr-watcher.h"
61 #include "omr-publisher.h"
62 #include "service-publisher.h"
63
64
65 #if SRP_FEATURE_NAT64
66 #include "nat64.h"
67 #endif
68
69
70 #ifdef SRP_TEST_SERVER
71 #include "srp-test-runner.h"
72 #endif
73
74 #define ADDRESS_RECORD_TTL 4500
75 #define OTHER_RECORD_TTL 4500
76
77 #define _DNSSD_API_AVAILABLE_FALL_2024 (1)
78
79 static const char local_suffix_ld[] = ".local";
80 static const char *local_suffix = &local_suffix_ld[1];
81
82 os_log_t global_os_log;
83 void *dns_service_op_not_to_be_freed;
84 srp_server_t *srp_servers;
85 const uint8_t thread_anycast_preamble[7] = { 0, 0, 0, 0xff, 0xfe, 0, 0xfc };
86 const uint8_t thread_rloc_preamble[6] = { 0, 0, 0, 0xff, 0xfe, 0 };
87
88 extern int num_push_sessions;
89 extern int dp_num_outstanding_queries;
90 extern int num_push_sessions_dropped_for_load;
91 extern int num_queries_dropped_for_load;
92
93 //======================================================================================================================
94 // MARK: - Forward references
95
96 static bool register_host_record(adv_host_t *host, adv_record_t *record, const bool skipping);
97 static void register_host_record_completion(DNSServiceRef sdref, DNSRecordRef rref,
98 DNSServiceFlags flags, DNSServiceErrorType error_code, void *context);
99 static bool register_instance(adv_instance_t *instance);
100 static void register_instance_completion(DNSServiceRef sdref, DNSServiceFlags flags, DNSServiceErrorType error_code,
101 const char *name, const char *regtype, const char *domain, void *context);
102 static void update_from_host(adv_host_t *host);
103 static void start_host_update(adv_host_t *host);
104 static void prepare_update(adv_host_t *host, client_update_t *client_update);
105 static void delete_host(void *context);
106 static void lease_callback(void *context);
107 static void adv_host_finalize(adv_host_t *host);
108 static void adv_record_finalize(adv_record_t *record);
109 static void adv_update_finalize(adv_update_t *update);
110
111 //======================================================================================================================
112 // MARK: - Functions
113
114 void
115 srp_mdns_shared_record_remove(srp_server_t *server_state, adv_record_t *record)
116 {
117 RETAIN_HERE(record, adv_record);
118 if (record->rref != NULL) {
119 if (record->shared_txn != 0 && record->shared_txn == (intptr_t)server_state->shared_registration_txn) {
120 INFO("removing rref %p", record->rref);
121 int err = dns_service_remove_record(server_state,
122 server_state->shared_registration_txn->sdref, record->rref, 0);
123 // We can't release the record here if we got an error removing it, because if we get an error removing it,
124 // it doesn't get removed from the list. This should never happen, but if it does, the record will leak.
125 if (err == kDNSServiceErr_NoError) {
126 RELEASE_HERE(record, adv_record); // Release the DNSService callback's reference
127 } else {
128 // At this point we should never see an error calling DNSServiceRemoveRecord, so if we do, call
129 // attention to it.
130 if (!record->update_pending) {
131 FAULT("DNSServiceRemoveRecord(%p, %p, %p, 0) returned %d",
132 server_state->shared_registration_txn->sdref, record, record->rref, err);
133 }
134 }
135 } else {
136 INFO("didn't remove stale rref %p because %lx != %p",
137 record->rref, record->shared_txn, server_state->shared_registration_txn);
138 }
139 record->rref = NULL;
140 }
141 record->shared_txn = 0;
142 RELEASE_HERE(record, adv_record);
143 }
144
145
146 static void
147 adv_record_finalize(adv_record_t *record)
148 {
149 // We should not be able to get to the finalize function without having removed the rref, because the DNSService
150 // callback always holds a reference to the record.
151 if (record->update != NULL) {
152 RELEASE_HERE(record->update, adv_update);
153 }
154 if (record->host != NULL) {
155 RELEASE_HERE(record->host, adv_host);
156 }
157
158 free(record->rdata);
159 free(record);
160 }
161
162 static void
163 adv_instance_finalize(adv_instance_t *instance)
164 {
165 if (instance->txn != NULL) {
166 ioloop_dnssd_txn_cancel_srp(instance->host->server_state, instance->txn);
167 ioloop_dnssd_txn_release(instance->txn);
168 }
169 if (instance->txt_data != NULL) {
170 free(instance->txt_data);
171 }
172 if (instance->instance_name != NULL) {
173 free(instance->instance_name);
174 }
175 if (instance->service_type != NULL) {
176 free(instance->service_type);
177 }
178 if (instance->host != NULL) {
179 RELEASE_HERE(instance->host, adv_host);
180 instance->host = NULL;
181 }
182 if (instance->message != NULL) {
183 ioloop_message_release(instance->message);
184 instance->message = NULL;
185 }
186 if (instance->update != NULL) {
187 RELEASE_HERE(instance->update, adv_update);
188 instance->update = NULL;
189 }
190 if (instance->retry_wakeup != NULL) {
191 ioloop_wakeup_release(instance->retry_wakeup);
192 instance->retry_wakeup = NULL;
193 }
194 free(instance);
195 }
196
197 void
198 adv_instance_context_release(void *NONNULL context)
199 {
200 adv_instance_t *instance = context;
201 RELEASE_HERE(instance, adv_instance);
202 }
203
204 void
205 adv_instance_retain_(adv_instance_t *instance, const char *file, int line)
206 {
207 RETAIN(instance, adv_instance);
208 }
209
210 void
211 adv_instance_release_(adv_instance_t *instance, const char *file, int line)
212 {
213 RELEASE(instance, adv_instance);
214 }
215
216 void
217 adv_record_retain_(adv_record_t *record, const char *file, int line)
218 {
219 RETAIN(record, adv_record);
220 }
221
222 void
223 adv_record_release_(adv_record_t *record, const char *file, int line)
224 {
225 RELEASE(record, adv_record);
226 }
227
228 #define DECLARE_VEC_CREATE(type) \
229 static type ## _vec_t * \
230 type ## _vec_create(int size) \
231 { \
232 type ## _vec_t *vec; \
233 \
234 vec = calloc(1, sizeof(*vec)); \
235 if (vec != NULL) { \
236 if (size == 0) { \
237 size = 1; \
238 } \
239 vec->vec = calloc(size, sizeof (*(vec->vec))); \
240 if (vec->vec == NULL) { \
241 free(vec); \
242 vec = NULL; \
243 } else { \
244 RETAIN_HERE(vec, type##_vec); \
245 } \
246 } \
247 return vec; \
248 }
249
250 #define DECLARE_VEC_COPY(type) \
251 static type ## _vec_t * \
252 type ## _vec_copy(type ## _vec_t *vec) \
253 { \
254 type ## _vec_t *new_vec; \
255 int i; \
256 \
257 new_vec = type ## _vec_create(vec->num); \
258 if (new_vec != NULL) { \
259 for (i = 0; i < vec->num; i++) { \
260 if (vec->vec[i] != NULL) { \
261 new_vec->vec[i] = vec->vec[i]; \
262 RETAIN_HERE(new_vec->vec[i], type); \
263 } \
264 } \
265 new_vec->num = vec->num; \
266 } \
267 return new_vec; \
268 }
269
270 #define DECLARE_VEC_FINALIZE(type) \
271 static void \
272 type ## _vec_finalize(type ## _vec_t *vec) \
273 { \
274 int i; \
275 \
276 for (i = 0; i < vec->num; i++) { \
277 if (vec->vec[i] != NULL) { \
278 RELEASE_HERE(vec->vec[i], type); \
279 vec->vec[i] = NULL; \
280 } \
281 } \
282 free(vec->vec); \
283 free(vec); \
284 }
285
286 DECLARE_VEC_CREATE(adv_instance);
287 DECLARE_VEC_COPY(adv_instance);
288 DECLARE_VEC_FINALIZE(adv_instance);
289
290 DECLARE_VEC_CREATE(adv_record);
291 DECLARE_VEC_COPY(adv_record);
292 DECLARE_VEC_FINALIZE(adv_record);
293
294 static void
295 srp_dump_server_stats(srp_server_t *server_state, bool full, bool periodic)
296 {
297 // For testing, emit a count of how many hosts, services and address records there are
298 int host_count = 0;
299 int a_record_count = 0;
300 int aaaa_record_count = 0;
301 int instance_count = 0;
302 int matter_host_count = 0;
303 int hap_host_count = 0;
304 int64_t now = ioloop_timenow();
305 static int last_num_push_sessions;
306 static int last_dp_num_outstanding_queries;
307 static int last_num_push_sessions_dropped_for_load;
308 static int last_num_queries_dropped_for_load;
309
310 for (adv_host_t *hp = server_state->hosts; hp != NULL; hp = hp->next) {
311 if (hp->removed) {
312 continue;
313 }
314 host_count++;
315 int expiry;
316 if (hp->lease_expiry < now) {
317 expiry = -1;
318 } else {
319 expiry = (int)((hp->lease_expiry - now) / 1000); // This should never be >MAXINT
320 }
321 if (full) {
322 INFO("host " PRI_S_SRP " key_id %xu stable %" PRIx64 " lease %d key_lease %d expiry %d" PUB_S_SRP PUB_S_SRP,
323 hp->name, hp->key_id, hp->server_stable_id, hp->lease_interval, hp->key_lease, expiry,
324 hp->removed ? " removed" : "", hp->update_pending ? " update-pending" : "");
325 }
326 if (hp->addresses != NULL) {
327 for (int i = 0; i < hp->addresses->num; i++) {
328 if (hp->addresses->vec[i] != NULL) {
329 adv_record_t *record = hp->addresses->vec[i];
330 if (record->rrtype == dns_rrtype_a) {
331 if (full) {
332 IPv4_ADDR_GEN_SRP(record->rdata, addr_buf);
333 INFO(" IN A " PRI_IPv4_ADDR_SRP PRI_S_SRP, IPv4_ADDR_PARAM_SRP(record->rdata, addr_buf),
334 record->shared_txn == (intptr_t)server_state->shared_registration_txn ? " live" : "");
335 }
336 a_record_count++;
337 } else if (record->rrtype == dns_rrtype_aaaa) {
338 if (full) {
339 IPv6_ADDR_GEN_SRP((const uint8_t *)record->rdata, addr_buf);
340 INFO(" IN AAAA " PRI_IPv6_ADDR_SRP PRI_S_SRP, IPv6_ADDR_PARAM_SRP(record->rdata, addr_buf),
341 record->shared_txn == (intptr_t)server_state->shared_registration_txn ? " live" : "");
342 }
343 aaaa_record_count++;
344 }
345 }
346 }
347 }
348 bool matter_instance_present = false, hap_instance_present = false;
349 if (hp->instances != NULL) {
350 for (int i = 0; i < hp->instances->num; i++) {
351 adv_instance_t *instance = hp->instances->vec[i];
352 if (instance != NULL) {
353 if (full) {
354 char txt_buf[DNS_DATA_SIZE];
355 if (instance->txt_data != NULL) {
356 dns_txt_data_print(txt_buf, DNS_DATA_SIZE, instance->txt_length, instance->txt_data);
357 } else {
358 txt_buf[0] = 0;
359 }
360 const char *status = "removed";
361 if (!instance->removed) {
362 if (instance->txn == NULL) {
363 status = "unregistered";
364 } else if (instance->shared_txn != (intptr_t)server_state->shared_registration_txn) {
365 status = "stale";
366 } else {
367 status = "live";
368 }
369 }
370 INFO(" " PUB_S_SRP " instance " PRI_S_SRP " " PRI_S_SRP " %d (" PRI_S_SRP ")",
371 status, instance->instance_name, instance->service_type, instance->port, txt_buf);
372 }
373 if (!instance->removed) {
374 instance_count++;
375 if (instance->service_type != NULL) {
376 const char matter_prefix[] = "_matter";
377 const char hap_prefix[] = "_hap._udp";
378 if (!strncmp(instance->service_type, matter_prefix, sizeof(matter_prefix) - 1)) {
379 matter_instance_present = true;
380 } else if (!strncmp(instance->service_type, hap_prefix, sizeof(hap_prefix) - 1)) {
381 hap_instance_present = true;
382 }
383 }
384 }
385 }
386 }
387 }
388 if (matter_instance_present) {
389 matter_host_count++;
390 } else if (hap_instance_present) { // If both, only count matter.
391 hap_host_count++;
392 }
393 }
394 INFO(PUB_S_SRP "%d hosts (%d matter, %d hap), %d instances, %d a records, %d aaaa records at %.6lf",
395 periodic ? "" : "after update, ", host_count, matter_host_count, hap_host_count, instance_count, a_record_count,
396 aaaa_record_count, srp_fractional_time());
397
398 #if STUB_ROUTER
399 route_state_t *route_state = server_state->route_state;
400 if (route_state) {
401 SEGMENTED_IPv6_ADDR_GEN_SRP(&route_state->srp_listener_ip_address, addr_buf);
402 // do we have an SRP listener?
403 if (route_state->srp_listener != NULL) {
404 INFO("have SRP listener on " PRI_SEGMENTED_IPv6_ADDR_SRP "/%d",
405 SEGMENTED_IPv6_ADDR_PARAM_SRP(&route_state->srp_listener_ip_address, addr_buf),
406 route_state->srp_service_listen_port);
407 } else {
408 INFO("no SRP listener");
409 }
410
411 // are we publishing anycast services?
412 INFO(PUB_S_SRP "advertising anycast service", route_state->advertising_srp_anycast_service ? "" : "not ");
413
414 // are we publishing unicast service?
415 if (route_state->advertising_srp_unicast_service) {
416 INFO("advertising unicast service on " PRI_SEGMENTED_IPv6_ADDR_SRP "/%d",
417 SEGMENTED_IPv6_ADDR_PARAM_SRP(&route_state->srp_listener_ip_address, addr_buf),
418 route_state->srp_service_listen_port);
419 } else {
420 INFO("not advertising unicast service");
421 }
422
423 // what SRP replication peers do we see? and how many are we actively connected to?
424 srpl_dump_connection_states(server_state);
425
426 // are we publishing OMR prefix?
427 if (route_state->omr_publisher != NULL &&
428 omr_publisher_publishing_prefix(route_state->omr_publisher))
429 {
430 omr_prefix_t *prefix = omr_publisher_published_prefix_get(route_state->omr_publisher);
431 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, prefix_buf);
432 INFO("publishing " PUB_S_SRP " OMR prefix " PRI_SEGMENTED_IPv6_ADDR_SRP "/%d",
433 omr_publisher_publishing_dhcp(route_state->omr_publisher) ? "dhcp" : "ula",
434 SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, prefix_buf),
435 prefix->prefix_length);
436 } else {
437 INFO("not publishing OMR prefix");
438 }
439
440 // what prefixes do we see on Thread?
441 if (route_state->omr_watcher != NULL) {
442 omr_prefix_t *thread_prefixes = omr_watcher_prefixes_get(route_state->omr_watcher);
443 for (struct omr_prefix *prefix = thread_prefixes; prefix != NULL; prefix = prefix->next) {
444 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, prefix_buf);
445 INFO("OMR prefix " PRI_SEGMENTED_IPv6_ADDR_SRP "/%d seen on thread" PUB_S_SRP PUB_S_SRP
446 PUB_S_SRP, SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, prefix_buf),
447 prefix->prefix_length, prefix->user ? " (user)" : "", prefix->ncp ? " (ncp)": "",
448 prefix->stable ? " (stable)" : "");
449 }
450 }
451
452 // are we publishing infrastructure prefix?
453 interface_t *interface;
454 bool is_advertising = false;
455 for (interface = route_state->interfaces; interface; interface = interface->next) {
456 if (interface->our_prefix_advertised) {
457 SEGMENTED_IPv6_ADDR_GEN_SRP(interface->ipv6_prefix.s6_addr, ipv6_prefix_buf);
458 INFO("advertising infrastructure prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " on " PUB_S_SRP,
459 SEGMENTED_IPv6_ADDR_PARAM_SRP(interface->ipv6_prefix.s6_addr, ipv6_prefix_buf),
460 interface->name);
461 is_advertising = true;
462 }
463 }
464 if (!is_advertising) {
465 INFO("not advertising infrastructure prefix");
466 }
467 }
468 #endif // STUB_ROUTER
469
470 // how many DNS push queries added since last state dump?
471 // how many DNS queries seen since last state dump?
472 // how many DNS queries dropped for load?
473 // how many DNS Push connections dropped for load?
474 INFO("%d push sessions and %d queries added, %d push sessions and %d queries dropped for load",
475 num_push_sessions - last_num_push_sessions,
476 dp_num_outstanding_queries - last_dp_num_outstanding_queries,
477 num_push_sessions_dropped_for_load - last_num_push_sessions_dropped_for_load,
478 num_queries_dropped_for_load - last_num_queries_dropped_for_load);
479 last_num_push_sessions = num_push_sessions;
480 last_dp_num_outstanding_queries = dp_num_outstanding_queries;
481 last_num_push_sessions_dropped_for_load = num_push_sessions_dropped_for_load;
482 last_num_queries_dropped_for_load = num_queries_dropped_for_load;
483 }
484
485 // We call advertise_finished when a client request has finished, successfully or otherwise.
486 #if SRP_FEATURE_REPLICATION
487 static bool
488 srp_replication_advertise_finished(adv_host_t *host, char *hostname, srp_server_t *server_state,
489 srpl_connection_t *srpl_connection, comm_t *connection, int rcode, bool last)
490 {
491 if (server_state->srp_replication_enabled) {
492 INFO("hostname = " PRI_S_SRP " host = %p server_state = %p srpl_connection = %p connection = %p rcode = "
493 PUB_S_SRP, hostname, host, server_state, srpl_connection, connection, dns_rcode_name(rcode));
494 if (connection == NULL) {
495 // connection is the SRP client connection on which an update arrived. If it's null,
496 // this is an SRP replication update, not an actual client we're communicating with.
497 INFO("replication advertise finished: host " PRI_S_SRP ": rcode = " PUB_S_SRP,
498 hostname, dns_rcode_name(rcode));
499 if (srpl_connection != NULL) {
500 if (last) {
501 srpl_advertise_finished_event_send(hostname, rcode, server_state);
502 #ifdef SRP_TEST_SERVER
503 if (srpl_connection->srpl_advertise_finished_callback != NULL) {
504 srpl_connection->srpl_advertise_finished_callback(srpl_connection);
505 }
506 #endif
507 }
508
509 if (host != NULL && host->srpl_connection != NULL) {
510 if (rcode == dns_rcode_noerror) {
511 host->update_server_id = host->srpl_connection->remote_partner_id;
512 host->server_stable_id = host->srpl_connection->stashed_host.server_stable_id;
513 INFO("replicated host " PRI_S_SRP " server stable ID %" PRIx64, hostname, host->server_stable_id);
514 }
515
516 // This is the safest place to clear this pointer--we do not want the srpl_connection pointer to not
517 // get reset because of some weird sequence of events, leaving this host unable to be further updated
518 // or worse.
519 srpl_connection_release(host->srpl_connection);
520 host->srpl_connection = NULL;
521 } else {
522 if (host != NULL) {
523 INFO("disconnected host " PRI_S_SRP " server stable ID %" PRIx64, hostname, host->server_stable_id);
524 }
525 }
526 } else {
527 if (host != NULL) {
528 INFO("context-free host " PRI_S_SRP " server stable ID %" PRIx64, hostname, host->server_stable_id);
529 }
530 }
531 return true;
532 }
533
534 if (host != NULL) {
535 if (rcode == dns_rcode_noerror) {
536 memcpy(&host->server_stable_id, &host->server_state->ula_prefix, sizeof(host->server_stable_id));
537 }
538 INFO("local host " PRI_S_SRP " server stable ID %" PRIx64, hostname, host->server_stable_id);
539 srpl_srp_client_update_finished_event_send(host, rcode);
540 host->update_server_id = 0;
541 }
542 } else
543 {
544 if (host != NULL && host->server_state != NULL) {
545 memcpy(&host->server_stable_id, &host->server_state->ula_prefix, sizeof(host->server_stable_id));
546 host->update_server_id = 0;
547 }
548 }
549 return false;
550 }
551 #endif // SRP_FEATURE_REPLICATION
552
553 static void
554 srp_ml_eid_mapping_callback(void *context, cti_status_t status)
555 {
556 adv_record_t *arec = context;
557 adv_host_t *host = arec->host;
558 SEGMENTED_IPv6_ADDR_GEN_SRP(arec->rdata, omr_buf);
559 if (status == kCTIStatus_NoError) {
560 if (host == NULL) {
561 INFO("mapping for address " PRI_SEGMENTED_IPv6_ADDR_SRP " was orphaned.",
562 SEGMENTED_IPv6_ADDR_PARAM_SRP(arec->rdata, omr_buf));
563 } else {
564 INFO("mapping for address " PRI_SEGMENTED_IPv6_ADDR_SRP " to host " PRI_S_SRP " succeeded",
565 SEGMENTED_IPv6_ADDR_PARAM_SRP(arec->rdata, omr_buf), host->name);
566 }
567 } else {
568 if (host == NULL) {
569 INFO("orphaned mapping for address " PRI_SEGMENTED_IPv6_ADDR_SRP " failed: %d",
570 SEGMENTED_IPv6_ADDR_PARAM_SRP(arec->rdata, omr_buf), status);
571 } else {
572 INFO("mapping for address " PRI_SEGMENTED_IPv6_ADDR_SRP " to host " PRI_S_SRP " failed: %d",
573 SEGMENTED_IPv6_ADDR_PARAM_SRP(arec->rdata, omr_buf), host->name, status);
574 }
575 }
576 RELEASE_HERE(arec, adv_record);
577 }
578
579 // We call advertise_finished when a client request has finished, successfully or otherwise.
580 static void
581 advertise_finished(adv_host_t *host, char *hostname, srp_server_t *server_state, srpl_connection_t *srpl_connection,
582 comm_t *connection, message_t *message, int rcode, client_update_t *client, bool send_response,
583 bool last)
584 {
585 struct iovec iov;
586 dns_wire_t response;
587
588 #if SRP_FEATURE_REPLICATION
589 if (srp_replication_advertise_finished(host, hostname, server_state, srpl_connection, connection, rcode, last)) {
590 return;
591 }
592 #else
593 (void)host;
594 (void)server_state;
595 (void)srpl_connection;
596 (void)last;
597 #endif // SRP_FEATURE_REPLICATION
598 INFO("host " PRI_S_SRP ": rcode = " PUB_S_SRP ", lease = %d, key_lease = %d connection = %p", hostname, dns_rcode_name(rcode),
599 client ? client->host_lease : 0, client ? client->key_lease : 0, connection);
600
601 // This can happen if we turn off replication in the middle of an update of a replicated host.
602 if (connection == NULL) {
603 return;
604 }
605 if (!send_response) {
606 INFO("not sending response.");
607 return;
608 }
609
610 memset(&response, 0, DNS_HEADER_SIZE);
611 response.id = message->wire.id;
612 response.bitfield = message->wire.bitfield;
613 dns_rcode_set(&response, rcode);
614 dns_qr_set(&response, dns_qr_response);
615
616 iov.iov_base = &response;
617 // If this was a successful update, send back the lease time, which will either
618 // be what the client asked for, or a shorter lease, depending on what limit has
619 // been set.
620 if (client != NULL) {
621 dns_towire_state_t towire;
622 memset(&towire, 0, sizeof towire);
623 towire.p = &response.data[0]; // We start storing RR data here.
624 towire.lim = &response.data[DNS_DATA_SIZE]; // This is the limit to how much we can store.
625 towire.message = &response;
626 response.qdcount = 0;
627 response.ancount = 0;
628 response.nscount = 0;
629 response.arcount = htons(1);
630 dns_edns0_header_to_wire(&towire, DNS_MAX_UDP_PAYLOAD, 0, 0, 1);
631 dns_rdlength_begin(&towire);
632 dns_u16_to_wire(&towire, dns_opt_update_lease); // OPTION-CODE
633 dns_edns0_option_begin(&towire); // OPTION-LENGTH
634 dns_u32_to_wire(&towire, client->host_lease); // LEASE (e.g. 1 hour)
635 dns_u32_to_wire(&towire, client->key_lease); // KEY-LEASE (7 days)
636 dns_edns0_option_end(&towire); // Now we know OPTION-LENGTH
637 dns_rdlength_end(&towire);
638 // It should not be possible for this to happen; if it does, the client
639 // might not renew its lease in a timely manner.
640 if (towire.error) {
641 ERROR("unexpectedly failed to send EDNS0 lease option.");
642 iov.iov_len = DNS_HEADER_SIZE;
643 } else {
644 iov.iov_len = towire.p - (uint8_t *)&response;
645 }
646 } else {
647 iov.iov_len = DNS_HEADER_SIZE;
648 }
649 ioloop_send_message(connection, message, &iov, 1);
650 }
651
652 static void
653 retry_callback(void *context)
654 {
655 adv_host_t *host = (adv_host_t *)context;
656 if (host->update == NULL) {
657 update_from_host(host);
658 } else {
659 start_host_update(host);
660 }
661 }
662
663 static void
664 srp_adv_host_context_release(void *context)
665 {
666 adv_host_t *host = context;
667 RELEASE_HERE(host, adv_host);
668 }
669
670 static void
671 wait_retry(adv_host_t *host)
672 {
673 int64_t now = ioloop_timenow();
674 #define MIN_HOST_RETRY_INTERVAL 15
675 #define MAX_HOST_RETRY_INTERVAL 120
676 // If we've been retrying long enough for the lease to expire, give up.
677 if (!host->lease_expiry || host->lease_expiry < now) {
678 INFO("host lease has expired, not retrying: lease_expiry = %" PRId64
679 " now = %" PRId64 " difference = %" PRId64, host->lease_expiry, now, host->lease_expiry - now);
680 delete_host(host);
681 return;
682 }
683 if (host->retry_interval == 0) {
684 host->retry_interval = MIN_HOST_RETRY_INTERVAL;
685 } else if (host->retry_interval < MAX_HOST_RETRY_INTERVAL) {
686 host->retry_interval *= 2;
687 }
688 INFO("waiting %d seconds...", host->retry_interval);
689 ioloop_add_wake_event(host->retry_wakeup, host, retry_callback, srp_adv_host_context_release, host->retry_interval * 1000);
690 RETAIN_HERE(host, adv_host);
691 }
692
693 static void
694 shared_registration_fail(void *context, int UNUSED status)
695 {
696 srp_server_t *server_state = context;
697 dnssd_txn_t *txn = server_state->shared_registration_txn;
698 DNSServiceRef sdref = txn == NULL ? NULL : txn->sdref;
699 INFO("shared registration failed: txn %p sdref %p", server_state->shared_registration_txn, sdref);
700 if (txn != NULL) {
701 ioloop_dnssd_txn_cancel(txn);
702 ioloop_dnssd_txn_release(txn);
703 server_state->shared_registration_txn = NULL;
704 }
705 }
706
707 bool
708 srp_mdns_shared_registration_txn_setup(srp_server_t *server_state)
709 {
710 if (server_state->shared_registration_txn == NULL) {
711 DNSServiceRef sdref;
712 int err = DNSServiceCreateConnection(&sdref);
713 if (err != kDNSServiceErr_NoError) {
714 return false;
715 }
716 server_state->shared_registration_txn = ioloop_dnssd_txn_add(sdref, server_state, NULL, shared_registration_fail);
717 if (server_state->shared_registration_txn == NULL) {
718 ERROR("unable to create shared connection for registration.");
719 dns_service_op_not_to_be_freed = NULL;
720 DNSServiceRefDeallocate(sdref);
721 return false;
722 }
723 dns_service_op_not_to_be_freed = server_state->shared_registration_txn->sdref;
724 INFO("server_state->shared_registration_txn = %p sdref = %p", server_state->shared_registration_txn, sdref);
725 }
726 return true;
727 }
728
729 static void
730 record_txn_forget(adv_record_t *record, intptr_t affected_service_pointer,
731 const char *parent_type, const void *parent_pointer, const char *hostname)
732 {
733 if (record == NULL) {
734 return;
735 }
736 if (record->rref != NULL && record->shared_txn == affected_service_pointer) {
737 INFO("forgetting rref %p on " PUB_S_SRP " %p " PRI_S_SRP, record->rref, parent_type, parent_pointer, hostname);
738 record->rref = NULL;
739 }
740 }
741
742 static void
743 record_vec_txns_forget(adv_record_vec_t *records, intptr_t affected_service_pointer,
744 const char *parent_type, const void *parent_pointer, const char *hostname)
745 {
746 if (records == NULL) {
747 return;
748 }
749 for (int i = 0; i < records->num; i++) {
750 record_txn_forget(records->vec[i], affected_service_pointer, parent_type, parent_pointer, hostname);
751 }
752 }
753
754 static void
755 instance_vec_txns_forget(adv_instance_vec_t *instances, intptr_t affected_service_pointer,
756 const char *parent_type, const void *parent_pointer, const char *hostname)
757 {
758 if (instances == NULL) {
759 return;
760 }
761 for (int i = 0; i < instances->num; i++) {
762 adv_instance_t *instance = instances->vec[i];
763 if (instance != NULL && instance->txn != NULL && instance->txn->sdref != NULL &&
764 instance->shared_txn == affected_service_pointer)
765 {
766 INFO("forgetting sdref %p on " PUB_S_SRP " %p " PRI_S_SRP " instance " PRI_S_SRP " . " PRI_S_SRP,
767 instance->txn->sdref,
768 parent_type, parent_pointer, hostname, instance->instance_name, instance->service_type);
769 instance->txn->sdref = NULL;
770 }
771 }
772 }
773
774 static void
775 host_txns_forget(adv_host_t *host, intptr_t affected_service_pointer)
776 {
777 // We call this when the shared transaction fails for some reason. That failure invalidates all the subsidiary
778 // RecordRefs and ServiceRefs hanging off of the shared transaction; to avoid holding on to invalid pointers,
779 // we traverse the registration database and NULL out all the rrefs and sdrefs that relate to the subsidiary
780 // service pointer.
781 record_vec_txns_forget(host->addresses, affected_service_pointer, "host", host, host->name);
782 instance_vec_txns_forget(host->instances, affected_service_pointer, "host", host, host->name);
783 record_txn_forget(host->key_record, affected_service_pointer, "host key", host, host->name);
784 if (host->update != NULL) {
785 record_vec_txns_forget(host->update->remove_addresses, affected_service_pointer,
786 "host update remove addresses", host->update, host->name);
787 record_vec_txns_forget(host->update->add_addresses, affected_service_pointer,
788 "host update add addresses", host->update, host->name);
789 record_txn_forget(host->update->key, affected_service_pointer, "host update key", host->update, host->name);
790 instance_vec_txns_forget(host->update->update_instances, affected_service_pointer,
791 "host update update instances", host->update, host->name);
792 instance_vec_txns_forget(host->update->remove_instances, affected_service_pointer,
793 "host update remove instances", host->update, host->name);
794 instance_vec_txns_forget(host->update->renew_instances, affected_service_pointer,
795 "host update renew instances", host->update, host->name);
796 instance_vec_txns_forget(host->update->add_instances, affected_service_pointer,
797 "host update add instances", host->update, host->name);
798 }
799 }
800
801 static void
802 service_disconnected(srp_server_t *server_state, intptr_t service_pointer)
803 {
804 if (service_pointer == (intptr_t)server_state->shared_registration_txn &&
805 server_state->shared_registration_txn != NULL)
806 {
807 INFO("server_state->shared_registration_txn = %p sdref = %p",
808 server_state->shared_registration_txn, server_state->shared_registration_txn->sdref);
809 // For every host that's active right now that has transactions on this shared transaction, forget all those
810 // transactions. The txn_cancel following this will free all of the memory in the client stub.
811 for (adv_host_t *host = server_state->hosts; host != NULL; host = host->next) {
812 host_txns_forget(host, service_pointer);
813 }
814 dns_service_op_not_to_be_freed = NULL;
815 ioloop_dnssd_txn_cancel(server_state->shared_registration_txn);
816 ioloop_dnssd_txn_release(server_state->shared_registration_txn);
817 server_state->shared_registration_txn = NULL;
818 }
819 }
820
821 static void
822 adv_record_vec_remove_update(adv_record_vec_t *vec, adv_update_t *update)
823 {
824 for (int i = 0; i < vec->num; i++) {
825 if (vec->vec[i] != NULL && vec->vec[i]->update != NULL && vec->vec[i]->update == update) {
826 RELEASE_HERE(vec->vec[i]->update, adv_update);
827 vec->vec[i]->update = NULL;
828 }
829 }
830 }
831
832 static void
833 adv_instance_vec_remove_update(adv_instance_vec_t *vec, adv_update_t *update)
834 {
835 for (int i = 0; i < vec->num; i++) {
836 if (vec->vec[i] != NULL && vec->vec[i]->update != NULL && vec->vec[i]->update == update) {
837 RELEASE_HERE(vec->vec[i]->update, adv_update);
838 vec->vec[i]->update = NULL;
839 }
840 }
841 }
842
843 static void
844 adv_instances_cancel(adv_instance_vec_t *instances)
845 {
846 for (int i = 0; i < instances->num; i++) {
847 adv_instance_t *instance = instances->vec[i];
848 if (instance != NULL) {
849 if (instance->txn != NULL) {
850 ioloop_dnssd_txn_cancel_srp(instance->host->server_state, instance->txn);
851 ioloop_dnssd_txn_release(instance->txn);
852 instance->txn = NULL;
853 }
854 if (instance->retry_wakeup != NULL) {
855 ioloop_cancel_wake_event(instance->retry_wakeup);
856 ioloop_wakeup_release(instance->retry_wakeup);
857 instance->retry_wakeup = NULL;
858 }
859 }
860 }
861 }
862
863 static void
864 adv_update_free_instance_vectors(adv_update_t *NONNULL update)
865 {
866 if (update->update_instances != NULL) {
867 adv_instance_vec_remove_update(update->update_instances, update);
868 adv_instances_cancel(update->update_instances);
869 RELEASE_HERE(update->update_instances, adv_instance_vec);
870 update->update_instances = NULL;
871 }
872 if (update->remove_instances != NULL) {
873 adv_instance_vec_remove_update(update->remove_instances, update);
874 RELEASE_HERE(update->remove_instances, adv_instance_vec);
875 update->remove_instances = NULL;
876 }
877 if (update->renew_instances != NULL) {
878 adv_instance_vec_remove_update(update->renew_instances, update);
879 RELEASE_HERE(update->renew_instances, adv_instance_vec);
880 update->renew_instances = NULL;
881 }
882 if (update->add_instances != NULL) {
883 adv_instance_vec_remove_update(update->add_instances, update);
884 adv_instances_cancel(update->add_instances);
885 RELEASE_HERE(update->add_instances, adv_instance_vec);
886 update->add_instances = NULL;
887 }
888 }
889
890 static void
891 adv_update_finalize(adv_update_t *NONNULL update)
892 {
893 if (update->host != NULL) {
894 RELEASE_HERE(update->host, adv_host);
895 }
896
897 if (update->client != NULL) {
898 srp_parse_client_updates_free(update->client);
899 update->client = NULL;
900 }
901
902 if (update->remove_addresses != NULL) {
903 adv_record_vec_remove_update(update->remove_addresses, update);
904 RELEASE_HERE(update->remove_addresses, adv_record_vec);
905 }
906
907 if (update->add_addresses != NULL) {
908 adv_record_vec_remove_update(update->add_addresses, update);
909 RELEASE_HERE(update->add_addresses, adv_record_vec);
910 }
911
912 adv_update_free_instance_vectors(update);
913 if (update->key != NULL) {
914 RELEASE_HERE(update->key, adv_record);
915 }
916 free(update);
917 }
918
919 static void
920 adv_update_cancel(adv_update_t *NONNULL update)
921 {
922 adv_host_t *host = update->host;
923 bool faulted = false;
924
925 RETAIN_HERE(update, adv_update); // ensure that update remains valid for the duration of this function call.
926
927 if (host != NULL) {
928 RETAIN_HERE(host, adv_host); // in case the update is holding the last reference to the host
929 RELEASE_HERE(update->host, adv_host);
930 update->host = NULL;
931
932 INFO("cancelling update %p for host " PRI_S_SRP, update, host->registered_name);
933
934 if (host->update == update) {
935 RELEASE_HERE(host->update, adv_update);
936 host->update = NULL;
937 }
938
939 // In case we needed to re-register some of the host's addresses, remove the update pointer from them.
940 if (host->addresses != NULL) {
941 for (int i = 0; i < host->addresses->num; i++) {
942 adv_record_t *record = host->addresses->vec[i];
943 if (record->update == update) {
944 RELEASE_HERE(host->addresses->vec[i]->update, adv_update);
945 record->update = NULL;
946 }
947 }
948 }
949 } else {
950 INFO("canceling update with no host.");
951 }
952
953 adv_update_free_instance_vectors(update);
954
955 if (update->add_addresses != NULL) {
956 // Any record that we attempted to add as part of this update should be removed because the update failed.
957 for (int i = 0; i < update->add_addresses->num; i++) {
958 adv_record_t *record = update->add_addresses->vec[i];
959 if (record != NULL) {
960 if (host == NULL) {
961 if (!faulted) {
962 FAULT("unable to clean up host address registration because host object is gone from update.");
963 faulted = true;
964 }
965 } else {
966 if (record->rref != NULL) {
967 srp_mdns_shared_record_remove(host->server_state, record);
968 }
969 }
970 }
971 }
972 adv_record_vec_remove_update(update->add_addresses, update);
973 RELEASE_HERE(update->add_addresses, adv_record_vec);
974 update->add_addresses = NULL;
975 }
976
977 if (update->remove_addresses != NULL) {
978 adv_record_vec_remove_update(update->remove_addresses, update);
979 RELEASE_HERE(update->remove_addresses, adv_record_vec);
980 update->remove_addresses = NULL;
981 }
982
983 if (update->key != NULL) {
984 if (update->key->update != NULL) {
985 RELEASE_HERE(update->key->update, adv_update);
986 update->key->update = NULL;
987 }
988 // Any record that we attempted to add as part of this update should be removed because the update failed.
989 if (update->key->rref != NULL) {
990 if (host == NULL) {
991 if (!faulted) {
992 FAULT("unable to clean up host key registration because host object is gone from update.");
993 faulted = true;
994 }
995 } else {
996 srp_mdns_shared_record_remove(host->server_state, update->key);
997 }
998 }
999 RELEASE_HERE(update->key, adv_record);
1000 update->key = NULL;
1001 }
1002 if (host != NULL) {
1003 RELEASE_HERE(host, adv_host);
1004 }
1005 RELEASE_HERE(update, adv_update);
1006 }
1007
1008 static void
1009 update_failed(adv_update_t *update, int rcode, bool expire, bool send_response)
1010 {
1011 // Retain the update for the life of this function call, since we may well release the last other reference to it.
1012 RETAIN_HERE(update, adv_update);
1013
1014 // If we still have a client waiting for the result of this update, tell it we failed.
1015 // Updates that have never worked are abandoned when the client is notified.
1016 if (update->client != NULL) {
1017 adv_host_t *host = update->host;
1018 client_update_t *client = update->client;
1019 adv_update_cancel(update);
1020 advertise_finished(host, host->name, host->server_state, host->srpl_connection,
1021 client->connection, client->message, rcode, NULL, send_response, true);
1022 srp_parse_client_updates_free(client);
1023 update->client = NULL;
1024 // If we don't have a lease yet, or the old lease has expired, remove the host.
1025 // However, if the expire flag is false, it's because we're already finalizing the
1026 // host, so doing an expiry here would double free the host. In this case, we leave
1027 // it to the caller to do the expiry (really, to finalize the host).
1028 if (expire && (host->lease_expiry == 0 || host->lease_expiry <= ioloop_timenow())) {
1029 delete_host(host);
1030 }
1031 RELEASE_HERE(update, adv_update);
1032 return;
1033 }
1034 adv_update_cancel(update);
1035 RELEASE_HERE(update, adv_update);
1036 }
1037
1038 static void
1039 host_addr_free(adv_host_t *host)
1040 {
1041 int i;
1042
1043 // We can't actually deallocate the address vector until the host object is collected, so deallocate the address
1044 // records.
1045 if (host->addresses != NULL) {
1046 for (i = 0; i < host->addresses->num; i++) {
1047 if (host->addresses->vec[i] != NULL) {
1048 INFO("Removing AAAA record for " PRI_S_SRP, host->registered_name);
1049 srp_mdns_shared_record_remove(host->server_state, host->addresses->vec[i]);
1050 RELEASE_HERE(host->addresses->vec[i], adv_record);
1051 host->addresses->vec[i] = NULL;
1052 }
1053 }
1054 host->addresses->num = 0;
1055 }
1056 }
1057
1058 // Free just those parts that are no longer needed when the host is no longer valid.
1059 static void
1060 host_invalidate(adv_host_t *host)
1061 {
1062 // Get rid of the retry wake event.
1063 if (host->retry_wakeup != NULL) {
1064 ioloop_cancel_wake_event(host->retry_wakeup);
1065 }
1066 if (host->re_register_wakeup != NULL) {
1067 ioloop_cancel_wake_event(host->re_register_wakeup);
1068 }
1069
1070 // Remove the address records.
1071 host_addr_free(host);
1072
1073 // Remove the services.
1074 if (host->instances != NULL) {
1075 adv_instances_cancel(host->instances);
1076 RELEASE_HERE(host->instances, adv_instance_vec);
1077 host->instances = NULL;
1078 }
1079
1080 if (host->update != NULL) {
1081 RELEASE_HERE(host->update, adv_update);
1082 host->update = NULL;
1083 }
1084 if (host->key_record != NULL) {
1085 srp_mdns_shared_record_remove(host->server_state, host->key_record);
1086 RELEASE_HERE(host->key_record, adv_record);
1087 host->key_record = NULL;
1088 }
1089 host->update = NULL;
1090 host->removed = true;
1091 }
1092
1093 // Free everything associated with the host, including the host object.
1094 static void
1095 adv_host_finalize(adv_host_t *host)
1096 {
1097 // Just in case this hasn't happened yet, free the non-identifying host data and cancel any outstanding
1098 // transactions.
1099 host_invalidate(host);
1100
1101 if (host->addresses != NULL) {
1102 RELEASE_HERE(host->addresses, adv_record_vec);
1103 host->addresses = NULL;
1104 }
1105
1106 if (host->key_rdata != NULL) {
1107 free(host->key_rdata);
1108 host->key_rdata = NULL;
1109 }
1110 if (host->key_record != NULL) {
1111 RELEASE_HERE(host->key_record, adv_record);
1112 host->key_record = NULL;
1113 }
1114
1115 if (host->message != NULL) {
1116 ioloop_message_release(host->message);
1117 host->message = NULL;
1118 }
1119
1120 // We definitely don't want a lease callback at this point.
1121 if (host->lease_wakeup != NULL) {
1122 ioloop_cancel_wake_event(host->lease_wakeup);
1123 ioloop_wakeup_release(host->lease_wakeup);
1124 host->lease_wakeup = NULL; // this will make us crash if we use it after free
1125 }
1126 // Get rid of the retry wake event.
1127 if (host->retry_wakeup != NULL) {
1128 ioloop_cancel_wake_event(host->retry_wakeup);
1129 ioloop_wakeup_release(host->retry_wakeup);
1130 host->retry_wakeup = NULL;
1131 }
1132
1133 if (host->re_register_wakeup != NULL) {
1134 ioloop_cancel_wake_event(host->re_register_wakeup);
1135 ioloop_wakeup_release(host->re_register_wakeup);
1136 host->re_register_wakeup = NULL;
1137 }
1138 INFO("removed " PRI_S_SRP ", key_id %x", host->name ? host->name : "<null>", host->key_id);
1139
1140 // In the default case, host->name and host->registered_name point to the same memory: we don't want a double free.
1141 if (host->registered_name == host->name) {
1142 host->registered_name = NULL;
1143 }
1144 if (host->name != NULL) {
1145 free(host->name);
1146 }
1147 if (host->registered_name != NULL) {
1148 free(host->registered_name);
1149 }
1150 free(host);
1151 }
1152
1153 void
1154 srp_adv_host_release_(adv_host_t *host, const char *file, int line)
1155 {
1156 RELEASE(host, adv_host);
1157 }
1158
1159 void
1160 srp_adv_host_retain_(adv_host_t *host, const char *file, int line)
1161 {
1162 RETAIN(host, adv_host);
1163 }
1164
1165 bool
1166 srp_adv_host_valid(adv_host_t *host)
1167 {
1168 // If the host has been removed, it's not valid.
1169 if (host->removed) {
1170 return false;
1171 }
1172 // If there is no key data, the host is invalid.
1173 if (host->key_rdata == NULL) {
1174 return false;
1175 }
1176 return true;
1177 }
1178
1179 int
1180 srp_current_valid_host_count(srp_server_t *server_state)
1181 {
1182 adv_host_t *host;
1183 int count = 0;
1184 for (host = server_state->hosts; host; host = host->next) {
1185 if (srp_adv_host_valid(host)) {
1186 count++;
1187 }
1188 }
1189 return count;
1190 }
1191
1192 int
1193 srp_hosts_to_array(srp_server_t *server_state, adv_host_t **host_array, int max)
1194 {
1195 int count = 0;
1196 for (adv_host_t *host = server_state->hosts; count < max && host != NULL; host = host->next) {
1197 if (srp_adv_host_valid(host)) {
1198 host_array[count] = host;
1199 RETAIN_HERE(host_array[count], adv_host);
1200 count++;
1201 }
1202 }
1203 return count;
1204 }
1205
1206 adv_host_t *
1207 srp_adv_host_copy_(srp_server_t *server_state, dns_name_t *name, const char *file, int line)
1208 {
1209 for (adv_host_t *host = server_state->hosts; host; host = host->next) {
1210 if (srp_adv_host_valid(host) && dns_names_equal_text(name, host->name)) {
1211 RETAIN(host, adv_host);
1212 return host;
1213 }
1214 }
1215 return NULL;
1216 }
1217
1218 static void
1219 host_remove(adv_host_t *host)
1220 {
1221 // This host is no longer valid. Get rid of the associated transactions and other stuff that's not required to
1222 // identify it, and then release the host list reference to it.
1223 host_invalidate(host);
1224 // Note that while adv_host_finalize calls host_invalidate, adv_host_finalize won't necessarily be called here because there
1225 // may be outstanding references on the host. It's okay to call host_invalidate twice--the second time it should be
1226 // a no-op.
1227 RELEASE_HERE(host, adv_host);
1228 }
1229
1230 static adv_host_t **
1231 host_ready(adv_host_t *host)
1232 {
1233 adv_host_t **p_hosts;
1234
1235 // Find the host on the list of hosts.
1236 for (p_hosts = &host->server_state->hosts; *p_hosts != NULL; p_hosts = &(*p_hosts)->next) {
1237 if (*p_hosts == host) {
1238 break;
1239 }
1240 }
1241 if (*p_hosts == NULL) {
1242 ERROR("called with nonexistent host.");
1243 return NULL;
1244 }
1245
1246 // It's possible that we got an update to this host, but haven't processed it yet. In this
1247 // case, we don't want to get rid of the host, but we do want to get rid of it later if the
1248 // update fails. So postpone the removal for a bit.
1249 if (host->update != NULL) {
1250 INFO("reached with pending updates on host " PRI_S_SRP ".", host->registered_name);
1251 ioloop_add_wake_event(host->lease_wakeup, host, lease_callback, srp_adv_host_context_release, 10 * 1000);
1252 RETAIN_HERE(host, adv_host);
1253 host->lease_expiry = ioloop_timenow() + 10 * 1000; // ten seconds
1254 return NULL;
1255 }
1256
1257 return p_hosts;
1258 }
1259
1260 static void
1261 lease_callback(void *context)
1262 {
1263 int64_t now = ioloop_timenow();
1264 adv_host_t **p_hosts, *host = context;
1265 int i, num_instances = 0;
1266
1267 p_hosts = host_ready(host);
1268 if (p_hosts == NULL) {
1269 INFO("host expired");
1270 return;
1271 }
1272
1273 INFO("host " PRI_S_SRP, host->name);
1274
1275 // If the host entry lease has expired, any instance leases have also.
1276 if (host->lease_expiry < now) {
1277 delete_host(host);
1278 return;
1279 }
1280
1281 INFO("host " PRI_S_SRP " is still alive", host->name);
1282
1283 if (host->instances == NULL) {
1284 INFO("no instances");
1285 return;
1286 }
1287
1288 // Find instances that have expired and release them.
1289 for (i = 0; i < host->instances->num; i++) {
1290 adv_instance_t *instance = host->instances->vec[i];
1291 if (instance == NULL) {
1292 continue;
1293 }
1294 if (instance->lease_expiry < now) {
1295 INFO("host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP " has expired",
1296 host->name, instance->instance_name, instance->service_type);
1297 // We have to release the transaction so that we can release the reference the transaction has to the instance.
1298 if (instance->txn != NULL) {
1299 dnssd_txn_t *txn = instance->txn;
1300 instance->txn = NULL;
1301 ioloop_dnssd_txn_release(txn);
1302 }
1303 host->instances->vec[i] = NULL;
1304 RELEASE_HERE(instance, adv_instance);
1305 continue;
1306 } else {
1307 INFO("host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP " has not expired",
1308 host->name, instance->instance_name, instance->service_type);
1309 }
1310 num_instances++;
1311 }
1312
1313 int64_t next_lease_expiry = host->lease_expiry;
1314
1315 // Get rid of holes in the host instance vector and compute the next lease callback time
1316 int j = 0;
1317
1318 for (i = 0; i < host->instances->num; i++) {
1319 if (host->instances->vec[i] != NULL) {
1320 adv_instance_t *instance = host->instances->vec[i];
1321 host->instances->vec[j++] = instance;
1322 if (next_lease_expiry > instance->lease_expiry) {
1323 next_lease_expiry = instance->lease_expiry;
1324 }
1325 }
1326 }
1327 INFO("host " PRI_S_SRP " lost %d instances", host->name, host->instances->num - j);
1328 host->instances->num = j;
1329
1330 // Now set a timer for the next lease expiry event
1331 uint64_t when = next_lease_expiry - now;
1332 if (when > INT32_MAX) {
1333 when = INT32_MAX;
1334 }
1335
1336 ioloop_add_wake_event(host->lease_wakeup, host, lease_callback, srp_adv_host_context_release, (uint32_t)when);
1337 RETAIN_HERE(host, adv_host);
1338 }
1339
1340 // Called when we definitely want to make all the advertisements associated with a host go away.
1341 static void
1342 delete_host(void *context)
1343 {
1344 adv_host_t **p_hosts, *host = context;
1345
1346
1347 p_hosts = host_ready(host);
1348 if (p_hosts == NULL) {
1349 return;
1350 }
1351
1352 INFO("deleting host " PRI_S_SRP, host->name);
1353
1354 // De-link the host.
1355 *p_hosts = host->next;
1356
1357 // Get rid of any transactions attached to the host, any timer events, and any other associated data.
1358 host_remove(host);
1359 }
1360
1361 // We remember the message that produced this instance so that if we get an update that doesn't update everything,
1362 // we know which instances /were/ updated by this particular message. instance->recent_message is a copy of the pointer
1363 // to the message that most recently updated this instance. When we set instance->recent_message, we don't yet know
1364 // if the update is going to succeed; if it fails, we can't have changed update->message. If it succeeds, then when we
1365 // get down to srp_mdns_update_finished, we can compare the message that did the update to instance->recent_message; if they
1366 // are the same, then we set the message on the instance.
1367 // Note that we only set instance->recent_message during register_instance_completion, so there's no timing race that
1368 // could happen as a result of receiving a second update to the same instance before the first has been processed.
1369 static void
1370 set_instance_message(adv_instance_t *instance, message_t *message)
1371 {
1372 if (message != NULL && (ptrdiff_t)message == instance->recent_message) {
1373 if (instance->message != NULL) {
1374 ioloop_message_release(instance->message);
1375 }
1376 instance->message = message;
1377 ioloop_message_retain(instance->message);
1378 instance->recent_message = 0;
1379 }
1380 }
1381
1382 void
1383 srp_mdns_update_finished(adv_update_t *update)
1384 {
1385 adv_host_t *host = update->host;
1386 client_update_t *client = update->client;
1387 int num_addresses = 0;
1388 adv_record_vec_t *addresses = NULL;
1389 int num_instances = 0;
1390 adv_instance_vec_t *instances = NULL;
1391 int i, j;
1392 int num_host_addresses = 0;
1393 int num_add_addresses = 0;
1394 int num_host_instances = 0;
1395 int num_add_instances = 0;
1396 message_t *message = NULL;
1397 client_update_t *remaining_updates = NULL;
1398 srp_server_t *server_state = host->server_state;
1399
1400 // Get the message that produced the update, if any
1401 if (client != NULL) {
1402 message = client->message;
1403 }
1404
1405 // Once an update has finished, we need to apply all of the proposed changes to the host object.
1406 if (host->addresses != NULL) {
1407 for (i = 0; i < host->addresses->num; i++) {
1408 if (host->addresses->vec[i] != NULL &&
1409 (update->remove_addresses == NULL || update->remove_addresses->vec[i] == NULL))
1410 {
1411 num_host_addresses++;
1412 }
1413 }
1414 }
1415
1416 if (update->add_addresses != NULL) {
1417 for (i = 0; i < update->add_addresses->num; i++) {
1418 if (update->add_addresses->vec[i] != NULL) {
1419 num_add_addresses++;
1420 }
1421 }
1422 }
1423
1424 num_addresses = num_host_addresses + num_add_addresses;
1425 if (num_addresses > 0) {
1426 addresses = adv_record_vec_create(num_addresses);
1427 if (addresses == NULL) {
1428 update_failed(update, dns_rcode_servfail, true, true);
1429 return;
1430 }
1431
1432 j = 0;
1433
1434 if (host->addresses != NULL) {
1435 for (i = 0; i < host->addresses->num; i++) {
1436 adv_record_t *rec = host->addresses->vec[i];
1437 if (rec != NULL && (update->remove_addresses == NULL || update->remove_addresses->vec[i] == NULL))
1438 {
1439 #ifdef DEBUG_VERBOSE
1440 uint8_t *rdp = rec->rdata;
1441 if (rec->rrtype == dns_rrtype_aaaa) {
1442 SEGMENTED_IPv6_ADDR_GEN_SRP(rdp, rdp_buf);
1443 INFO("retaining " PRI_SEGMENTED_IPv6_ADDR_SRP "on host " PRI_S_SRP,
1444 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdp, rdp_buf), host->registered_name);
1445 } else {
1446 IPv4_ADDR_GEN_SRP(rdp, rdp_buf);
1447 INFO("retaining " PRI_IPv4_ADDR_SRP "on host " PRI_S_SRP,
1448 IPv4_ADDR_PARAM_SRP(rdp, rdp_buf), host->registered_name);
1449 }
1450 #endif
1451 addresses->vec[j] = rec;
1452 RETAIN_HERE(addresses->vec[j], adv_record);
1453 j++;
1454 }
1455 }
1456 }
1457 if (update->add_addresses != NULL) {
1458 for (i = 0; i < update->add_addresses->num; i++) {
1459 adv_record_t *rec = update->add_addresses->vec[i];
1460 if (rec != NULL) {
1461 #ifdef DEBUG_VERBOSE
1462 uint8_t *rdp = rec->rdata;
1463 if (rec->rrtype == dns_rrtype_aaaa) {
1464 SEGMENTED_IPv6_ADDR_GEN_SRP(rdp, rdp_buf);
1465 INFO("adding " PRI_SEGMENTED_IPv6_ADDR_SRP "to host " PRI_S_SRP,
1466 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdp, rdp_buf), host->registered_name);
1467 } else {
1468 IPv4_ADDR_GEN_SRP(rdp, rdp_buf);
1469 INFO("adding " PRI_IPv4_ADDR_SRP "to host " PRI_S_SRP,
1470 IPv4_ADDR_PARAM_SRP(rdp, rdp_buf), host->registered_name);
1471 }
1472 #endif
1473 addresses->vec[j] = rec;
1474 RETAIN_HERE(addresses->vec[j], adv_record);
1475 j++;
1476 if (rec->update != NULL) {
1477 RELEASE_HERE(update->add_addresses->vec[i]->update, adv_update);
1478 update->add_addresses->vec[i]->update = NULL;
1479 }
1480 RELEASE_HERE(update->add_addresses->vec[i], adv_record);
1481 update->add_addresses->vec[i] = NULL;
1482 }
1483 }
1484 }
1485 addresses->num = j;
1486 }
1487
1488 // Do the same for instances.
1489 if (host->instances != NULL) {
1490 for (i = 0; i < host->instances->num; i++) {
1491 // We're counting the number of non-NULL instances in the host instance vector, which is probably always
1492 // going to be the same as host->instances->num, but we are not relying on this.
1493 if (host->instances->vec[i] != NULL) {
1494 num_host_instances++;
1495 }
1496 }
1497 }
1498
1499 if (update->add_instances != NULL) {
1500 for (i = 0; i < update->add_instances->num; i++) {
1501 if (update->add_instances->vec[i] != NULL) {
1502 num_add_instances++;
1503 }
1504 }
1505 }
1506
1507 num_instances = num_add_instances + num_host_instances;
1508 instances = adv_instance_vec_create(num_instances);
1509 if (instances == NULL) {
1510 if (addresses != NULL) {
1511 RELEASE_HERE(addresses, adv_record_vec);
1512 addresses = NULL;
1513 }
1514 update_failed(update, dns_rcode_servfail, true, true);
1515 return;
1516 }
1517
1518 j = 0;
1519 if (host->instances != NULL) {
1520 for (i = 0; i < host->instances->num; i++) {
1521 if (j == num_instances) {
1522 FAULT("j (%d) == num_instances (%d)", j, num_instances);
1523 break;
1524 }
1525 if (update->update_instances != NULL && update->update_instances->vec[i] != NULL) {
1526 adv_instance_t *instance = update->update_instances->vec[i];
1527 if (update->remove_instances != NULL && update->remove_instances->vec[i] != NULL) {
1528 adv_instance_t *removed_instance = update->remove_instances->vec[i];
1529 INFO("removed instance " PRI_S_SRP " " PRI_S_SRP " %d",
1530 removed_instance->instance_name, removed_instance->service_type, removed_instance->port);
1531 INFO("added instance " PRI_S_SRP " " PRI_S_SRP " %d",
1532 instance->instance_name, instance->service_type, instance->port);
1533 } else {
1534 INFO("updated instance " PRI_S_SRP " " PRI_S_SRP " %d",
1535 instance->instance_name, instance->service_type, instance->port);
1536 }
1537 instances->vec[j] = instance;
1538 RETAIN_HERE(instances->vec[j], adv_instance);
1539 j++;
1540 RELEASE_HERE(update->update_instances->vec[i], adv_instance);
1541 update->update_instances->vec[i] = NULL;
1542 if (instance->update != NULL) {
1543 RELEASE_HERE(instance->update, adv_update);
1544 instance->update = NULL;
1545 }
1546 set_instance_message(instance, message);
1547 } else {
1548 if (update->remove_instances != NULL && update->remove_instances->vec[i] != NULL) {
1549 adv_instance_t *instance = update->remove_instances->vec[i];
1550 INFO("removed instance " PRI_S_SRP " " PRI_S_SRP " %d",
1551 instance->instance_name, instance->service_type, instance->port);
1552 instances->vec[j] = instance;
1553 RETAIN_HERE(instances->vec[j], adv_instance);
1554 j++;
1555 instance->removed = true;
1556 if (message != NULL) {
1557 if (instance->message != NULL) {
1558 ioloop_message_release(instance->message);
1559 }
1560 instance->message = message;
1561 ioloop_message_retain(instance->message);
1562 }
1563 if (instance->txn == NULL) {
1564 ERROR("instance " PRI_S_SRP "." PRI_S_SRP " for host " PRI_S_SRP " has no connection.",
1565 instance->instance_name, instance->service_type, host->name);
1566 } else {
1567 ioloop_dnssd_txn_cancel_srp(host->server_state, instance->txn);
1568 ioloop_dnssd_txn_release(instance->txn);
1569 instance->txn = NULL;
1570 }
1571 } else {
1572 if (host->instances->vec[i] != NULL) {
1573 adv_instance_t *instance = host->instances->vec[i];
1574 INFO("kept instance " PRI_S_SRP " " PRI_S_SRP " %d, instance->message = %p",
1575 instance->instance_name, instance->service_type, instance->port, instance->message);
1576 instances->vec[j] = instance;
1577 RETAIN_HERE(instances->vec[j], adv_instance);
1578 j++;
1579 set_instance_message(instance, message);
1580 }
1581 }
1582 }
1583 }
1584 }
1585
1586 // Set the message on all of the instances that were renewed to the current message.
1587 if (update->renew_instances != NULL) {
1588 for (i = 0; i < update->renew_instances->num; i++) {
1589 adv_instance_t *instance = update->renew_instances->vec[i];
1590 if (instance != NULL) {
1591 if (message != NULL) { // Should never not be NULL for a renew, of course.
1592 if (instance->message != NULL) {
1593 ioloop_message_release(instance->message);
1594 }
1595 instance->message = message;
1596 ioloop_message_retain(instance->message);
1597 }
1598 instance->recent_message = 0;
1599 INFO("renewed instance " PRI_S_SRP " " PRI_S_SRP " %d",
1600 instance->instance_name, instance->service_type, instance->port);
1601 }
1602 }
1603 }
1604
1605 if (update->add_instances != NULL) {
1606 for (i = 0; i < update->add_instances->num; i++) {
1607 adv_instance_t *instance = update->add_instances->vec[i];
1608 if (instance != NULL) {
1609 INFO("added instance " PRI_S_SRP " " PRI_S_SRP " %d",
1610 instance->instance_name, instance->service_type, instance->port);
1611 instances->vec[j] = instance;
1612 RETAIN_HERE(instances->vec[j], adv_instance);
1613 j++;
1614 RELEASE_HERE(update->add_instances->vec[i], adv_instance);
1615 update->add_instances->vec[i] = NULL;
1616 if (instance->update != NULL) {
1617 RELEASE_HERE(instance->update, adv_update);
1618 instance->update = NULL;
1619 }
1620 set_instance_message(instance, message);
1621 }
1622 }
1623 }
1624 instances->num = j;
1625 // Clear "skip update" flag on instances.
1626 for (i = 0; i < instances->num; i++) {
1627 if (instances->vec[i] != NULL) {
1628 instances->vec[i]->skip_update = false;
1629 }
1630 }
1631
1632 // At this point we can safely modify the host object because we aren't doing any more
1633 // allocations.
1634 if (host->addresses != NULL) {
1635 RELEASE_HERE(host->addresses, adv_record_vec);
1636 }
1637 host->addresses = addresses; // Either NULL or else returned retained by adv_record_vec_create().
1638
1639 if (host->instances != NULL) {
1640 for (i = 0; i < host->instances->num; i++) {
1641 adv_instance_t *instance = host->instances->vec[i];
1642 if (instance != NULL) {
1643 INFO("old host instance %d " PRI_S_SRP "." PRI_S_SRP " for host " PRI_S_SRP " has ref_count %d",
1644 i, instance->instance_name, instance->service_type, host->name, instance->ref_count);
1645 } else {
1646 INFO("old host instance %d is NULL", i);
1647 }
1648 }
1649 RELEASE_HERE(host->instances, adv_instance_vec);
1650 }
1651 host->instances = instances;
1652
1653 if (host->key_record != NULL && update->key != NULL && host->key_record != update->key) {
1654 srp_mdns_shared_record_remove(host->server_state, host->key_record);
1655 RELEASE_HERE(host->key_record, adv_record);
1656 host->key_record = NULL;
1657 }
1658 if (host->key_record == NULL && update->key != NULL) {
1659 host->key_record = update->key;
1660 RETAIN_HERE(host->key_record, adv_record);
1661 if (update->key->update != NULL) {
1662 RELEASE_HERE(update->key->update, adv_update);
1663 update->key->update = NULL;
1664 }
1665 }
1666
1667 // Remove any instances that are to be removed
1668 if (update->remove_addresses != NULL) {
1669 for (i = 0; i < update->remove_addresses->num; i++) {
1670 adv_record_t *record = update->remove_addresses->vec[i];
1671 if (record != NULL) {
1672 srp_mdns_shared_record_remove(host->server_state, record);
1673 }
1674 }
1675 }
1676
1677 time_t lease_offset = 0;
1678
1679 if (client) {
1680 if (host->message != NULL) {
1681 ioloop_message_release(host->message);
1682 }
1683 host->message = client->message;
1684 ioloop_message_retain(host->message);
1685 advertise_finished(host, host->name, host->server_state, host->srpl_connection,
1686 client->connection, client->message, dns_rcode_noerror, client, true,
1687 client->next == NULL);
1688 remaining_updates = client->next;
1689 client->next = NULL;
1690 srp_parse_client_updates_free(client);
1691 update->client = NULL;
1692 if (host->message->received_time != 0) {
1693 host->update_time = host->message->received_time;
1694 lease_offset = srp_time() - host->update_time;
1695 INFO("setting host update time based on message received time: %ld, lease offset = %ld",
1696 host->update_time, lease_offset);
1697 } else {
1698 INFO("setting host update time based on current time: %ld", host->message->received_time);
1699 host->update_time = srp_time();
1700 }
1701 } else {
1702 INFO("lease offset = %ld", lease_offset);
1703 lease_offset = srp_time() - host->update_time;
1704 }
1705 RETAIN_HERE(update, adv_update); // We need to hold a reference to the update since this might be the last.
1706
1707 // The update should still be on the host.
1708 if (host->update == NULL) {
1709 ERROR("p_update is null.");
1710 } else {
1711 RELEASE_HERE(host->update, adv_update);
1712 host->update = NULL;
1713 }
1714
1715 // Reset the retry interval, since we succeeded in updating.
1716 host->retry_interval = 0;
1717
1718 // Set the lease time based on this update. Even if we scheduled an update for the next time we
1719 // enter the dispatch loop, we still want to schedule a lease expiry here, because it's possible
1720 // that in the process of returning to the dispatch loop, the scheduled update will be removed.
1721 if (0) {
1722 #if STUB_ROUTER
1723 } else if (server_state->stub_router_enabled) {
1724 host->lease_interval = update->host_lease;
1725 host->key_lease = update->key_lease;
1726 #endif
1727 } else {
1728 // For the Thread in Mobile use case, use the duration of the key lease to determine when to expire host
1729 // entries, rather than expiring them when the host lease expires. This is technically out of spec, but
1730 // accomplishes part of the stated goal of keeping usable cached data around for use immediately after
1731 // connecting to a Thread mesh.
1732 host->lease_interval = update->key_lease;
1733 host->key_lease = update->key_lease;
1734 }
1735
1736 // It would probably be harmless to set this for replications, since the value currently wouldn't change,
1737 // but to avoid future issues we only set this if it's a direct SRP update and not a replicated update.
1738 // We know it's a direct SRP update because host->message->lease is zero. It would not be zero if we
1739 // had received this as an SRP update, but is always zero when received directly via UDP.
1740 INFO("host->message->lease = %d, host->lease_interval = %d, host->key_lease = %d",
1741 host->message->lease, host->lease_interval, host->key_lease);
1742 if (host->message->lease == 0) {
1743 host->message->lease = host->lease_interval;
1744 host->message->key_lease = host->key_lease;
1745 }
1746
1747 // We want the lease expiry event to fire the next time the lease on any instance expires, or
1748 // at the time the lease for the current update would expire, whichever is sooner.
1749 int64_t next_lease_expiry = INT64_MAX;
1750 int64_t now = ioloop_timenow();
1751
1752 #define LEASE_EXPIRY_DEBUGGING 1
1753 // update->lease_expiry is nonzero if we are re-doing a previous registration.
1754 if (update->lease_expiry != 0) {
1755 if (update->lease_expiry < now) {
1756 #ifdef LEASE_EXPIRY_DEBUGGING
1757 ERROR("lease expiry for host " PRI_S_SRP " happened %" PRIu64 " milliseconds ago.",
1758 host->registered_name, now - update->lease_expiry);
1759 #endif
1760 // Expire the lease when next we hit the run loop
1761 next_lease_expiry = now;
1762 } else {
1763 #ifdef LEASE_EXPIRY_DEBUGGING
1764 INFO("lease_expiry (1) for host " PRI_S_SRP " set to %" PRId64, host->name,
1765 (int64_t)(update->lease_expiry - now));
1766 #endif
1767 next_lease_expiry = update->lease_expiry;
1768 }
1769 host->lease_expiry = update->lease_expiry;
1770 }
1771 // This is the more usual case.
1772 else {
1773 #ifdef LEASE_EXPIRY_DEBUGGING
1774 INFO("lease_expiry (2) for host " PRI_S_SRP " set to %ld", host->name, (host->lease_interval - lease_offset) * 1000);
1775 #endif
1776 next_lease_expiry = now + (host->lease_interval - lease_offset) * 1000;
1777 if (next_lease_expiry < now) {
1778 next_lease_expiry = now;
1779 }
1780 host->lease_expiry = next_lease_expiry;
1781 }
1782
1783 // We're doing two things here: setting the lease expiry on instances that were touched by the current
1784 // update, and also finding the soonest update.
1785 for (i = 0; i < host->instances->num; i++) {
1786 adv_instance_t *instance = host->instances->vec[i];
1787
1788 if (instance != NULL) {
1789 // This instance was updated by the current update, so set its lease time to
1790 // next_lease_expiry.
1791 if (instance->message == message) {
1792 if (instance->removed) {
1793 #ifdef LEASE_EXPIRY_DEBUGGING
1794 INFO("lease_expiry (7) for host " PRI_S_SRP " removed instance " PRI_S_SRP "." PRI_S_SRP
1795 " left at %" PRId64, host->name, instance->instance_name, instance->service_type,
1796 (int64_t)(instance->lease_expiry - now));
1797 #endif
1798 } else {
1799 #ifdef LEASE_EXPIRY_DEBUGGING
1800 INFO("lease_expiry (4) for host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP " set to %" PRId64,
1801 host->name, instance->instance_name, instance->service_type,
1802 (int64_t)(host->lease_expiry - now));
1803 #endif
1804 instance->lease_expiry = host->lease_expiry;
1805 }
1806 }
1807 // Instance was not updated by this update, so see if it expires sooner than this update
1808 // (which is likely).
1809 else if (instance->lease_expiry > now && instance->lease_expiry < next_lease_expiry) {
1810 #ifdef LEASE_EXPIRY_DEBUGGING
1811 INFO("lease_expiry (3) for host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP " set to %" PRId64,
1812 host->name, instance->instance_name, instance->service_type,
1813 (int64_t)(instance->lease_expiry - now));
1814 #endif
1815 next_lease_expiry = instance->lease_expiry;
1816 } else {
1817 if (instance->lease_expiry <= now) {
1818 #ifdef LEASE_EXPIRY_DEBUGGING
1819 INFO("lease_expiry (5) for host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP
1820 " in the past at %" PRId64,
1821 host->name, instance->instance_name, instance->service_type,
1822 (int64_t)(now - instance->lease_expiry));
1823 #endif
1824 next_lease_expiry = now;
1825 #ifdef LEASE_EXPIRY_DEBUGGING
1826 } else {
1827 INFO("lease_expiry (6) for host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP
1828 " is later than next_lease_expiry by %" PRId64, host->name, instance->instance_name,
1829 instance->service_type, (int64_t)(next_lease_expiry - instance->lease_expiry));
1830
1831 #endif
1832 }
1833 }
1834 }
1835 }
1836
1837 // Now set a timer for the next lease expiry.
1838 uint64_t when = next_lease_expiry - now;
1839 if (when > INT32_MAX) {
1840 when = INT32_MAX;
1841 }
1842
1843 if (next_lease_expiry == now) {
1844 INFO("scheduling immediate call to lease_callback in the run loop for " PRI_S_SRP, host->name);
1845 ioloop_run_async(lease_callback, host);
1846 } else {
1847 INFO("scheduling wakeup to lease_callback in %" PRIu64 " for host " PRI_S_SRP,
1848 when / 1000, host->name);
1849 ioloop_add_wake_event(host->lease_wakeup, host, lease_callback, srp_adv_host_context_release, (uint32_t)when);
1850 RETAIN_HERE(host, adv_host);
1851 }
1852
1853 // Instance vectors can hold circular references to the update object, which won't get freed until we call
1854 // adv_update_finalize, which we will never do because of the circular reference. So break any remaining
1855 // circular references before releasing the update.
1856 adv_update_free_instance_vectors(update);
1857
1858 // This is letting go of the reference we retained earlier in this function, not some outstanding reference retained elsewhere.
1859 RELEASE_HERE(update, adv_update);
1860
1861 // If we were processing an SRP update, we may have additional updates to do. Start the next one now if so.
1862 if (remaining_updates != NULL) {
1863 srp_update_start(remaining_updates);
1864 } else {
1865 srp_dump_server_stats(server_state, false, false);
1866 }
1867 }
1868
1869 #ifdef USE_DNSSERVICE_QUEUING
1870 static void
1871 process_dnsservice_error(adv_update_t *update, int err)
1872 {
1873 if (err != kDNSServiceErr_NoError) {
1874 update_failed(update, dns_rcode_servfail, true, true);
1875 if (err == kDNSServiceErr_ServiceNotRunning || err == kDNSServiceErr_DefunctConnection || err == 1) {
1876 if (err == 1) {
1877 FAULT("bogus error code 1");
1878 }
1879 if (update->host != NULL) {
1880 if (update->host->server_state != NULL) {
1881 service_disconnected(update->host->server_state,
1882 (intptr_t)update->host->server_state->shared_registration_txn);
1883 }
1884 wait_retry(update->host);
1885 }
1886 }
1887 }
1888 }
1889 #endif // USE_DNSSERVICE_QUEUING
1890
1891 #define GENERATE_WAKEUP(ptr) \
1892 if ((*ptr) == NULL) { \
1893 (*ptr) = ioloop_wakeup_create(); \
1894 } \
1895 if ((*ptr) == NULL) { \
1896 ERROR("unable to make wakeup " #ptr); \
1897 } else
1898
1899 static void
1900 srp_instance_retry_callback(void *context)
1901 {
1902 adv_instance_t *instance = context;
1903 adv_host_t *host = instance->host;
1904 if (host == NULL || host->removed) {
1905 INFO("no longer updating instance %p because host is no longer valid.", instance);
1906 return;
1907 }
1908 INFO("re-registering updating instance %p.", instance);
1909 register_instance(instance);
1910 }
1911
1912 static void
1913 srp_schedule_instance_retry(adv_instance_t *instance)
1914 {
1915 GENERATE_WAKEUP(&instance->retry_wakeup) {
1916 if (instance->wakeup_interval == 0) {
1917 instance->wakeup_interval = 5 * 1000;
1918 } else {
1919 instance->wakeup_interval *= 2;
1920 }
1921 unsigned interval = instance->wakeup_interval * 1.5 - (srp_random32() % instance->wakeup_interval);
1922 RETAIN_HERE(instance, adv_instance);
1923 ioloop_add_wake_event(instance->retry_wakeup, instance, srp_instance_retry_callback, adv_instance_context_release, interval);
1924 INFO("will attempt to reregister instance %p in %.3lf seconds", instance, ((double)interval) / 1000.0);
1925 }
1926 }
1927
1928 static void
1929 srp_host_record_retry_callback(void *context)
1930 {
1931 adv_host_t *host = context;
1932 if (host != NULL) {
1933 host->re_register_pending = false;
1934 }
1935 if (host == NULL || host->removed) {
1936 INFO("no longer updating host %p because host is no longer valid.", host);
1937 return;
1938 }
1939
1940 if (host->addresses != NULL) {
1941 for (int i = 0; i < host->addresses->num; i++) {
1942 adv_record_t *record = host->addresses->vec[i];
1943 if (record != NULL) {
1944 INFO("re-registering host record %p.", record);
1945 register_host_record(host, record, false);
1946 }
1947 }
1948 }
1949 if (host->key_record != NULL) {
1950 INFO("re-registering host record %p.", host->key_record);
1951 register_host_record(host, host->key_record, false);
1952 }
1953 }
1954
1955 static void
1956 srp_schedule_host_record_retry(adv_record_t *record)
1957 {
1958 // If the host isn't valid or we're already re-registering, don't schedule a retry.
1959 if (record->host == NULL || record->host->removed) {
1960 INFO("will not attempt to reregister record %p", record);
1961 return;
1962 }
1963 if (record->host->re_register_pending) {
1964 INFO("already scheduled attempt to reregister record %p", record);
1965 return;
1966 }
1967
1968 adv_host_t *host = record->host;
1969 GENERATE_WAKEUP(&host->re_register_wakeup) {
1970 if (host->wakeup_interval == 0) {
1971 host->wakeup_interval = 5 * 1000;
1972 } else {
1973 host->wakeup_interval *= 2;
1974 }
1975 unsigned interval = host->wakeup_interval * 1.5 - (srp_random32() % host->wakeup_interval);
1976 RETAIN_HERE(host, adv_host);
1977 ioloop_add_wake_event(host->re_register_wakeup, host, srp_host_record_retry_callback, srp_adv_host_context_release, interval);
1978 INFO("will attempt to reregister record %p in %.3lf seconds", record, ((double)interval) / 1000.0);
1979 }
1980 }
1981
1982
1983 // When the host registration has completed, we get this callback. Completion either means that we succeeded in
1984 // registering the record, or that something went wrong and the registration has failed.
1985 static void
1986 register_instance_completion(DNSServiceRef sdref, DNSServiceFlags flags, DNSServiceErrorType error_code,
1987 const char *name, const char *regtype, const char *domain, void *context)
1988 {
1989 (void)flags;
1990 (void)sdref;
1991 adv_instance_t *instance = context;
1992 adv_update_t *update = instance->update;
1993 adv_host_t *host = instance->host;
1994
1995 // Retain the instance for the life of this function, just in case we release stuff that is holding the last reference to it.
1996 RETAIN_HERE(instance, adv_instance);
1997
1998 // It's possible that we could restart a host update due to an error while a callback is still pending on a stale
1999 // update. In this case, we just cancel all of the work that's been done on the stale update (it's probably already
2000 // moot anyway.
2001 if (update != NULL && host->update != update) {
2002 INFO("registration for service " PRI_S_SRP "." PRI_S_SRP " completed with invalid state.", name, regtype);
2003 RELEASE_HERE(instance->update, adv_update);
2004 instance->update = NULL;
2005 RELEASE_HERE(instance, adv_instance);
2006 return;
2007 }
2008
2009 // We will generally get a callback on success or failure of the initial registration; this is what causes
2010 // the update to complete or fail. We may get subsequent callbacks because of name conflicts. So the first
2011 // time we get a callback, instance->update will always be valid; thereafter, it will not, so null it out.
2012 if (update != NULL) {
2013 RETAIN_HERE(update, adv_update); // We need to hold onto this until we are done with the update.
2014 RELEASE_HERE(instance->update, adv_update);
2015 instance->update = NULL;
2016 }
2017
2018 if (error_code == kDNSServiceErr_NoError || error_code == kDNSServiceErr_NameConflict) {
2019 INFO("registration for service " PRI_S_SRP "." PRI_S_SRP "." PRI_S_SRP " -> "
2020 PRI_S_SRP " has completed" PUB_S_SRP ".", instance->instance_name, instance->service_type, domain,
2021 host->registered_name, error_code == kDNSServiceErr_NoError ? ":" : " with a conflict");
2022 INFO("registration is under " PRI_S_SRP "." PRI_S_SRP PRI_S_SRP, name, regtype,
2023 domain);
2024
2025 if (error_code != kDNSServiceErr_NoError) {
2026 if (instance->txn == NULL) {
2027 FAULT("instance->txn is NULL for instance %p!", instance);
2028 } else {
2029 ioloop_dnssd_txn_cancel_srp(host->server_state, instance->txn);
2030 ioloop_dnssd_txn_release(instance->txn);
2031 instance->txn = NULL;
2032 }
2033 srp_schedule_instance_retry(instance);
2034 }
2035
2036 // In principle update->instance should always be non-NULL here because a no-error response should
2037 // only happen once or not at all. But just to be safe...
2038 if (update != NULL) {
2039 if (instance->update_pending) {
2040 if (update->client != NULL) {
2041 instance->recent_message = (ptrdiff_t)update->client->message; // for comparison later in srp_mdns_update_finished
2042 }
2043 update->num_instances_completed++;
2044 if (update->num_records_completed == update->num_records_started &&
2045 update->num_instances_completed == update->num_instances_started)
2046 {
2047 srp_mdns_update_finished(update);
2048 }
2049 RELEASE_HERE(update, adv_update);
2050 instance->update_pending = false;
2051 update = NULL;
2052 }
2053 } else {
2054 INFO("re-update succeeded for instance " PRI_S_SRP " (" PRI_S_SRP
2055 " " PRI_S_SRP " " PRI_S_SRP ")", instance->instance_name, name, regtype, domain);
2056 }
2057 } else {
2058 INFO("registration for service " PRI_S_SRP "." PRI_S_SRP "." PRI_S_SRP " -> "
2059 PRI_S_SRP " failed with code %d", instance->instance_name, instance->service_type, domain,
2060 host->registered_name, error_code);
2061
2062 // If the reason this failed is that we couldn't talk to mDNSResponder, or mDNSResponder disconnected, then we want to retry
2063 // later on in the hopes that mDNSResponder will come back.
2064 if (error_code == kDNSServiceErr_ServiceNotRunning || error_code == kDNSServiceErr_DefunctConnection) {
2065 service_disconnected(host->server_state, instance->shared_txn);
2066 instance->shared_txn = 0;
2067 wait_retry(host);
2068 } else {
2069 if (update != NULL) {
2070 update_failed(update, (error_code == kDNSServiceErr_NameConflict
2071 ? dns_rcode_yxdomain
2072 : dns_rcode_servfail), true, true);
2073 if (instance->update != NULL) {
2074 RELEASE_HERE(instance->update, adv_update);
2075 instance->update = NULL;
2076 }
2077 RELEASE_HERE(update, adv_update);
2078 } else {
2079 }
2080 }
2081
2082 // The transaction still holds a reference to the instance. instance->txn should never be NULL here. When we cancel
2083 // the transaction, the reference the transaction held on the instance will be released.
2084 if (instance->txn == NULL) {
2085 FAULT("instance->txn is NULL for instance %p!", instance);
2086 } else {
2087 ioloop_dnssd_txn_cancel_srp(host->server_state, instance->txn);
2088 ioloop_dnssd_txn_release(instance->txn);
2089 instance->txn = NULL;
2090 }
2091 }
2092 RELEASE_HERE(instance, adv_instance);
2093 }
2094
2095 static bool
2096 extract_instance_name(char *instance_name, size_t instance_name_max,
2097 char *service_type, size_t service_type_max, service_instance_t *instance)
2098 {
2099 dns_name_t *end_of_service_type = instance->service->rr->name->next;
2100 size_t service_index;
2101 service_t *service, *base_type;
2102 if (end_of_service_type != NULL) {
2103 if (end_of_service_type->next != NULL) {
2104 end_of_service_type = end_of_service_type->next;
2105 }
2106 }
2107 dns_name_print_to_limit(instance->service->rr->name, end_of_service_type, service_type, service_type_max);
2108
2109 // It's possible that the registration might include subtypes. If so, we need to convert them to the
2110 // format that DNSServiceRegister expects: service_type,subtype,subtype...
2111 service_index = strlen(service_type);
2112 base_type = instance->service->base_type;
2113 for (service = instance->service->next; service != NULL && service->base_type == base_type; service = service->next)
2114 {
2115 if (service_index + service->rr->name->len + 2 > service_type_max) {
2116 ERROR("service name: " PRI_S_SRP " is too long for additional subtype " PRI_S_SRP,
2117 service_type, service->rr->name->data);
2118 return false;
2119 }
2120 service_type[service_index++] = ',';
2121 memcpy(&service_type[service_index], service->rr->name->data, service->rr->name->len + 1);
2122 service_index += service->rr->name->len;
2123 }
2124
2125 // Make a presentation-format version of the service instance name.
2126 dns_name_print_to_limit(instance->name, instance->name != NULL ? instance->name->next : NULL,
2127 instance_name, instance_name_max);
2128 return true;
2129 }
2130
2131 void
2132 srp_format_time_offset(char *buf, size_t buf_len, time_t offset)
2133 {
2134 struct tm tm_now;
2135 time_t when = time(NULL) - offset;
2136 localtime_r(&when, &tm_now);
2137 strftime(buf, buf_len, "%F %T", &tm_now);
2138 }
2139
2140 DNSServiceAttributeRef
2141 srp_message_tsr_attribute_generate(message_t *message, uint32_t key_id, char *time_buf, size_t time_buf_size)
2142 {
2143 DNSServiceAttributeRef attribute = DNSServiceAttributeCreate();
2144 if (attribute == NULL) {
2145 ERROR("Failed to create new DNSServiceAttributeRef");
2146 } else {
2147 uint32_t offset = 0;
2148
2149 if (message != NULL && message->received_time != 0) {
2150 offset = (uint32_t)(srp_time() - message->received_time);
2151 srp_format_time_offset(time_buf, time_buf_size, offset);
2152 } else {
2153 static char msg[] = "now";
2154 if (time_buf_size < sizeof(msg)) {
2155 FAULT("bogus time buf size %zd", time_buf_size);
2156 time_buf[0] = 0;
2157 } else {
2158 memcpy(time_buf, msg, sizeof(msg));
2159 }
2160 }
2161 if (_DNSSD_API_AVAILABLE_FALL_2024) {
2162 DNSServiceAttributeSetHostKeyHash(attribute, key_id);
2163 }
2164 DNSServiceAttributeSetTimestamp(attribute, offset);
2165 }
2166 return attribute;
2167 }
2168
2169 DNSServiceAttributeRef
2170 srp_adv_instance_tsr_attribute_generate(adv_instance_t *instance, char *time_buf, size_t time_buf_size)
2171 {
2172 message_t *message = NULL;
2173 if (instance->update != NULL && instance->update->client != NULL && instance->update->client->message != NULL) {
2174 message = instance->update->client->message;
2175 } else if (instance->update == NULL && instance->message != NULL) {
2176 message = instance->message;
2177 }
2178 return srp_message_tsr_attribute_generate(message, instance->host->key_id, time_buf, time_buf_size);
2179 }
2180
2181 static bool
2182 register_instance(adv_instance_t *instance)
2183 {
2184 int err = kDNSServiceErr_Unknown;
2185 bool exit_status = false;
2186 srp_server_t *server_state = instance->host->server_state;
2187
2188 // If we don't yet have a shared connection, create one.
2189 if (!srp_mdns_shared_registration_txn_setup(server_state)) {
2190 goto exit;
2191 }
2192 DNSServiceRef service_ref = server_state->shared_registration_txn->sdref;
2193
2194 INFO(PUB_S_SRP "DNSServiceRegister(%p, " PRI_S_SRP ", " PRI_S_SRP ", " PRI_S_SRP ", %d, %p)",
2195 instance->skip_update ? "skipping " : "", service_ref, instance->instance_name, instance->service_type,
2196 instance->host->registered_name, instance->port, instance);
2197
2198 if (instance->skip_update) {
2199 if (instance->update->client != NULL) {
2200 instance->recent_message = (ptrdiff_t)instance->update->client->message; // for comparison later in srp_mdns_update_finished
2201 }
2202 exit_status = true;
2203 goto exit;
2204 }
2205
2206 char time_buf[TSR_TIMESTAMP_STRING_LEN];
2207 DNSServiceAttributeRef tsr_attribute =
2208 srp_adv_instance_tsr_attribute_generate(instance, time_buf, sizeof(time_buf));
2209 if (tsr_attribute == NULL) {
2210 err = kDNSServiceErr_NoMemory;
2211 } else {
2212 uint32_t flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename;
2213 if (_DNSSD_API_AVAILABLE_FALL_2024) {
2214 flags |= kDNSServiceFlagsKnownUnique;
2215 }
2216 err = dns_service_register_wa(server_state, &service_ref, flags,
2217 server_state->advertise_interface,
2218 instance->instance_name, instance->service_type, local_suffix,
2219 instance->host->registered_name, htons(instance->port), instance->txt_length,
2220 instance->txt_data, tsr_attribute, register_instance_completion, instance);
2221 DNSServiceAttributeDeallocate(tsr_attribute);
2222 if (err == kDNSServiceErr_NoError) {
2223 INFO("DNSServiceRegister, TSR for instance " PRI_S_SRP " host " PRI_S_SRP " set to " PUB_S_SRP
2224 "(instance %p sdref %p)", instance->instance_name,
2225 instance->host->name == NULL ? "<null>" : instance->host->name, time_buf, instance, service_ref);
2226 }
2227 }
2228
2229 // This would happen if we pass NULL for regtype, which we don't, or if we run out of memory, or if
2230 // the server isn't running; in the second two cases, we can always try again later.
2231 if (err != kDNSServiceErr_NoError) {
2232 if (err == kDNSServiceErr_ServiceNotRunning || err == kDNSServiceErr_DefunctConnection ||
2233 err == kDNSServiceErr_BadParam || err == kDNSServiceErr_BadReference || err == 1)
2234 {
2235 if (err == 1) {
2236 FAULT("bogus error code 1");
2237 }
2238 INFO("DNSServiceRegister failed: " PUB_S_SRP " (instance %p)",
2239 err == kDNSServiceErr_ServiceNotRunning ? "not running" : "defunct", instance);
2240 service_disconnected(server_state, (intptr_t)server_state->shared_registration_txn);
2241 } else {
2242 INFO("DNSServiceRegister failed: %d (instance %p)", err, instance);
2243 }
2244 goto exit;
2245 }
2246 if (instance->update != NULL) {
2247 instance->update->num_instances_started++;
2248 instance->update_pending = true;
2249 }
2250 // After DNSServiceRegister succeeds, it creates a copy of DNSServiceRef that indirectly uses the shared connection,
2251 // so we update it here.
2252 instance->txn = ioloop_dnssd_txn_add_subordinate(service_ref, instance, adv_instance_context_release, NULL);
2253 if (instance->txn == NULL) {
2254 ERROR("no memory for instance transaction.");
2255 goto exit;
2256 }
2257 instance->shared_txn = (intptr_t)server_state->shared_registration_txn;
2258 RETAIN_HERE(instance, adv_instance); // for the callback
2259 exit_status = true;
2260
2261 exit:
2262 return exit_status;
2263 }
2264
2265 // When we get a late name conflict on the hostname, we need to update the host registration and all of the
2266 // service registrations. To do this, we construct an update and then apply it. If there is already an update
2267 // in progress, we put this update at the end of the list.
2268 static void
2269 update_from_host(adv_host_t *host)
2270 {
2271 adv_update_t *update = NULL;
2272 int i;
2273
2274 if (host->update != NULL) {
2275 ERROR("already have an update.");
2276 }
2277
2278 // Allocate the update structure.
2279 update = calloc(1, sizeof *update);
2280 if (update == NULL) {
2281 ERROR("no memory for update.");
2282 goto fail;
2283 }
2284 RETAIN_HERE(update, adv_update);
2285
2286 if (host->addresses != NULL) {
2287 update->add_addresses = adv_record_vec_copy(host->addresses);
2288 if (update->add_addresses == NULL) {
2289 ERROR("no memory for addresses");
2290 goto fail;
2291 }
2292 for (i = 0; i < update->add_addresses->num; i++) {
2293 if (update->add_addresses->vec[i] != NULL) {
2294 update->add_addresses->vec[i]->update = update;
2295 RETAIN_HERE(update, adv_update);
2296 }
2297 }
2298 }
2299
2300 // We can never update more instances than currently exist for this host.
2301 if (host->instances != NULL) {
2302 update->update_instances = adv_instance_vec_copy(host->instances);
2303 if (update->update_instances == NULL) {
2304 ERROR("no memory for update_instances");
2305 goto fail;
2306 }
2307 for (i = 0; i < update->update_instances->num; i++) {
2308 if (update->update_instances->vec[i] != NULL) {
2309 update->update_instances->vec[i]->update = update;
2310 RETAIN_HERE(update, adv_update);
2311 }
2312 }
2313
2314 // We aren't actually adding or deleting any instances, but...
2315 update->remove_instances = adv_instance_vec_create(host->instances->num);
2316 if (update->remove_instances == NULL) {
2317 ERROR("no memory for remove_instances");
2318 goto fail;
2319 }
2320 update->remove_instances->num = host->instances->num;
2321
2322 update->add_instances = adv_instance_vec_create(host->instances->num);
2323 if (update->add_instances == NULL) {
2324 ERROR("no memory for add_instances");
2325 goto fail;
2326 }
2327 update->add_instances->num = host->instances->num;
2328 }
2329
2330
2331 // At this point we have figured out all the work we need to do, so hang it off an update structure.
2332 update->host = host;
2333 RETAIN_HERE(update->host, adv_host);
2334 update->host_lease = host->lease_interval;
2335 update->key_lease = host->key_lease;
2336 update->lease_expiry = host->lease_expiry;
2337
2338 // Stash the update on the host.
2339 host->update = update;
2340 RETAIN_HERE(host->update, adv_update); // host gets a reference
2341 RELEASE_HERE(update, adv_update); // we're done with our reference.
2342 start_host_update(host);
2343 return;
2344
2345 fail:
2346 if (update != NULL) {
2347 adv_update_cancel(update);
2348 RELEASE_HERE(update, adv_update);
2349 }
2350 wait_retry(host);
2351 return;
2352 }
2353
2354 // When the host registration has completed, we get this callback. Completion either means that we succeeded in
2355 // registering the record, or that something went wrong and the registration has failed.
2356 static void
2357 register_host_record_completion(DNSServiceRef sdref, DNSRecordRef rref,
2358 DNSServiceFlags flags, DNSServiceErrorType error_code, void *context)
2359 {
2360 adv_record_t *record = context;
2361 adv_host_t *host = NULL;
2362 adv_update_t *update = NULL;
2363 (void)sdref;
2364 (void)rref;
2365 (void)error_code;
2366 (void)flags;
2367
2368 // This can happen if for some reason DNSServiceRemoveRecord returns something other than success. In this case, all
2369 // the cleanup that can be done has already been done, and all we can do is ignore the problem.
2370 if (record->rref == NULL) {
2371 ERROR("null rref");
2372 return;
2373 }
2374 // For analyzer, can't actually happen.
2375 if (record == NULL) {
2376 ERROR("null record");
2377 return;
2378 }
2379 host = record->host;
2380 if (host == NULL) {
2381 ERROR("no host");
2382 return;
2383 }
2384
2385 // Make sure record remains valid for the duration of this call.
2386 RETAIN_HERE(record, adv_record);
2387
2388 // It's possible that we could restart a host update due to an error while a callback is still pending on a stale
2389 // update. In this case, we just cancel all of the work that's been done on the stale update (it's probably already
2390 // moot anyway.
2391 if (record->update != NULL && host->update != record->update) {
2392 INFO("registration for host record completed with invalid state.");
2393 adv_update_cancel(record->update);
2394 RELEASE_HERE(record->update, adv_update);
2395 record->update = NULL;
2396 srp_mdns_shared_record_remove(host->server_state, record); // This will prevent further callbacks and release the reference held by the transaction.
2397 RELEASE_HERE(record, adv_record); // The callback has a reference to the record.
2398 RELEASE_HERE(record, adv_record); // Release the reference to the record that we retained at the beginning
2399 return;
2400
2401 }
2402 update = record->update;
2403 if (update != NULL) {
2404 RETAIN_HERE(update, adv_update);
2405 }
2406
2407 if (error_code == kDNSServiceErr_NoError || error_code == kDNSServiceErr_NameConflict) {
2408 // If the update is pending, it means that we just finished registering this record for the first time,
2409 // so we can count it as complete and check to see if there is any work left to do; if not, we call
2410 // srp_mdns_update_finished to apply the update to the host object.
2411 const char *note = " has completed.";
2412 if (record->update_pending) {
2413 record->update_pending = false;
2414 if (update != NULL) {
2415 update->num_records_completed++;
2416 if (update->num_records_completed == update->num_records_started &&
2417 update->num_instances_completed == update->num_instances_started)
2418 {
2419 srp_mdns_update_finished(update);
2420 }
2421 }
2422 } else {
2423 note = " got spurious success callback after completion.";
2424 }
2425
2426 if (error_code != kDNSServiceErr_NoError) {
2427 // Shared record is no longer good.
2428 srp_mdns_shared_record_remove(host->server_state, record);
2429 note = " completed with conflict.";
2430 srp_schedule_host_record_retry(record);
2431 }
2432
2433 if (record->rrtype == dns_rrtype_a) {
2434 IPv4_ADDR_GEN_SRP(record->rdata, addr_buf);
2435 INFO("registration for host " PRI_S_SRP " address " PRI_IPv4_ADDR_SRP PUB_S_SRP,
2436 host->registered_name, IPv4_ADDR_PARAM_SRP(record->rdata, addr_buf), note);
2437 } else if (record->rrtype == dns_rrtype_aaaa) {
2438 SEGMENTED_IPv6_ADDR_GEN_SRP(record->rdata, addr_buf);
2439 INFO("registration for host " PRI_S_SRP " address " PRI_SEGMENTED_IPv6_ADDR_SRP PUB_S_SRP,
2440 host->registered_name, SEGMENTED_IPv6_ADDR_PARAM_SRP(record->rdata, addr_buf), note);
2441 } else if (record->rrtype == dns_rrtype_key) {
2442 INFO("registration for host " PRI_S_SRP " key" PUB_S_SRP, host->registered_name, note);
2443 } else {
2444 INFO("registration for host " PRI_S_SRP " unknown record type %d " PUB_S_SRP, host->registered_name, record->rrtype, note);
2445 }
2446 } else {
2447 if (record->rrtype == dns_rrtype_a) {
2448 IPv4_ADDR_GEN_SRP(record->rdata, addr_buf);
2449 INFO("registration for host " PRI_S_SRP " address " PRI_IPv4_ADDR_SRP " failed, error code = %d.",
2450 host->registered_name, IPv4_ADDR_PARAM_SRP(record->rdata, addr_buf), error_code);
2451 } else if (record->rrtype == dns_rrtype_aaaa) {
2452 SEGMENTED_IPv6_ADDR_GEN_SRP(record->rdata, addr_buf);
2453 INFO("registration for host " PRI_S_SRP " address " PRI_SEGMENTED_IPv6_ADDR_SRP " failed, error code = %d.",
2454 host->registered_name, SEGMENTED_IPv6_ADDR_PARAM_SRP(record->rdata, addr_buf), error_code);
2455 } else if (record->rrtype == dns_rrtype_key) {
2456 INFO("registration for host " PRI_S_SRP " key failed, error code = %d.", host->registered_name, error_code);
2457 } else {
2458 INFO("registration for host " PRI_S_SRP " unknown record type %d failed, error code = %d.",
2459 host->registered_name, record->rrtype, error_code);
2460 }
2461
2462 // If the reason this failed is that we couldn't talk to mDNSResponder, or mDNSResponder disconnected, then we want to retry
2463 // later on in the hopes that mDNSResponder will come back.
2464 if (error_code == kDNSServiceErr_ServiceNotRunning || error_code == kDNSServiceErr_DefunctConnection) {
2465 service_disconnected(host->server_state, record->shared_txn);
2466 if (update != NULL) {
2467 wait_retry(host);
2468 }
2469 } else {
2470 // The other error we could get is a name conflict. This means that some other advertising proxy or host on
2471 // the network is advertising the hostname we chose, and either got there first with no TSR record, or got
2472 // its copy of the host information later than ours. So if we get a name conflict, it's up to the client or
2473 // the replication peer to make the next move.
2474
2475 if (update != NULL) {
2476 update_failed(update, (error_code == kDNSServiceErr_NameConflict
2477 ? dns_rcode_yxdomain
2478 : dns_rcode_servfail), true, true);
2479 } else {
2480 }
2481 }
2482 // Regardless of what else happens, this transaction is dead, so get rid of our references to it.
2483 srp_mdns_shared_record_remove(host->server_state, record);
2484 }
2485 if (update != NULL) {
2486 RELEASE_HERE(update, adv_update);
2487 }
2488 RELEASE_HERE(record, adv_record); // Release the reference to the record that we retained at the beginning
2489 }
2490
2491 static adv_instance_t *
2492 adv_instance_create(service_instance_t *raw, adv_host_t *host, adv_update_t *update)
2493 {
2494 char service_type[DNS_MAX_LABEL_SIZE_ESCAPED * 2 + 2]; // sizeof '.' + sizeof '\0'.
2495 char instance_name[DNS_MAX_NAME_SIZE_ESCAPED + 1];
2496 uint8_t *txt_data;
2497
2498 // Allocate the raw registration
2499 adv_instance_t *instance = calloc(1, sizeof *instance);
2500 if (instance == NULL) {
2501 ERROR("adv_instance:create: unable to allocate raw registration struct.");
2502 return NULL;
2503 }
2504 RETAIN_HERE(instance, adv_instance);
2505 instance->host = host;
2506 RETAIN_HERE(instance->host, adv_host);
2507 instance->update = update;
2508 RETAIN_HERE(instance->update, adv_update);
2509
2510 // SRV records have priority, weight and port, but DNSServiceRegister only uses port.
2511 instance->port = (raw->srv == NULL) ? 0 : raw->srv->data.srv.port;
2512
2513 // Make a presentation-format version of the service name.
2514 if (!extract_instance_name(instance_name, sizeof instance_name, service_type, sizeof service_type, raw)) {
2515 RELEASE_HERE(instance, adv_instance);
2516 return NULL;
2517 }
2518
2519 instance->instance_name = strdup(instance_name);
2520 if (instance->instance_name == NULL) {
2521 ERROR("adv_instance:create: unable to allocate instance name.");
2522 RELEASE_HERE(instance, adv_instance);
2523 return NULL;
2524 }
2525 instance->service_type = strdup(service_type);
2526 if (instance->service_type == NULL) {
2527 ERROR("adv_instance:create: unable to allocate instance type.");
2528 RELEASE_HERE(instance, adv_instance);
2529 return NULL;
2530 }
2531
2532 // Allocate the text record buffer
2533 if (raw->txt != NULL) {
2534 txt_data = malloc(raw->txt->data.txt.len);
2535 if (txt_data == NULL) {
2536 RELEASE_HERE(instance, adv_instance);
2537 ERROR("adv_instance:create: unable to allocate txt_data buffer");
2538 return NULL;
2539 }
2540 // Format the txt buffer as required by DNSServiceRegister().
2541 memcpy(txt_data, raw->txt->data.txt.data, raw->txt->data.txt.len);
2542 instance->txt_data = txt_data;
2543 instance->txt_length = raw->txt->data.txt.len;
2544 } else {
2545 instance->txt_data = NULL;
2546 instance->txt_length = 0;
2547 }
2548
2549 // If the service_instance_t is marked to skip updating, mark the adv_instance_t as well.
2550 instance->skip_update = raw->skip_update;
2551
2552 return instance;
2553 }
2554
2555 #define adv_record_create(rrtype, rdlen, rdata, host) \
2556 adv_record_create_(rrtype, rdlen, rdata, host, __FILE__, __LINE__)
2557 static adv_record_t *
2558 adv_record_create_(uint16_t rrtype, uint16_t rdlen, uint8_t *rdata, adv_host_t *host, const char *file, int line)
2559 {
2560
2561 adv_record_t *new_record = calloc(1, sizeof(*new_record) + rdlen - 1);
2562 if (new_record == NULL) {
2563 ERROR("no memory for new_record");
2564 return NULL;
2565 }
2566 new_record->rdata = malloc(rdlen);
2567 if (new_record->rdata == NULL) {
2568 ERROR("no memory for new_record->rdata");
2569 free(new_record);
2570 return NULL;
2571 }
2572 new_record->host = host;
2573 RETAIN(host, adv_host);
2574 new_record->rrtype = rrtype;
2575 new_record->rdlen = rdlen;
2576 memcpy(new_record->rdata, rdata, rdlen);
2577 RETAIN(new_record, adv_record);
2578 return new_record;
2579 }
2580
2581 // Given a pair of service types which may or may not have subtypes, e.g. _foo._tcp, which doesn't have subtypes, or
2582 // _foo.tcp,bar, which does, return true if type1 matches the type2 for the base type, ignoring subtypes.
2583 static bool
2584 service_types_equal(const char *type1, const char *type2)
2585 {
2586 size_t len1;
2587 char *comma1 = strchr(type1, ',');
2588 if (comma1 == NULL) {
2589 len1 = strlen(type1);
2590 } else {
2591 len1 = comma1 - type1;
2592 }
2593 char *comma2 = strchr(type2, ',');
2594 size_t len2;
2595 if (comma2 != NULL) {
2596 len2 = comma2 - type2;
2597 } else {
2598 len2 = strlen(type2);
2599 }
2600 if (len1 != len2) {
2601 return false;
2602 }
2603 if (memcmp(type2, type1, len1)) {
2604 return false;
2605 }
2606 return true;
2607 }
2608
2609 DNSServiceAttributeRef
2610 srp_adv_host_tsr_attribute_generate(adv_host_t *host, char *time_buf, size_t time_buf_size)
2611 {
2612 message_t *message = NULL;
2613 if (host->update != NULL && host->update->client != NULL && host->update->client->message != NULL) {
2614 message = host->update->client->message;
2615 } else if (host->update == NULL && host->message != NULL) {
2616 message = host->message;
2617 }
2618 return srp_message_tsr_attribute_generate(message, host->key_id, time_buf, time_buf_size);
2619 }
2620
2621 static bool
2622 register_host_record(adv_host_t *host, adv_record_t *record, bool skipping)
2623 {
2624 int err;
2625
2626 // If this record is already registered, get rid of the old transaction.
2627 if (record->rref != NULL && !skipping) {
2628 srp_mdns_shared_record_remove(host->server_state, record);
2629 }
2630
2631 // If we don't yet have a shared connection, create one.
2632 if (!srp_mdns_shared_registration_txn_setup(host->server_state)) {
2633 return false;
2634 }
2635
2636 const DNSServiceRef service_ref = host->server_state->shared_registration_txn->sdref;
2637
2638 if (record->rrtype == dns_rrtype_a) {
2639 IPv4_ADDR_GEN_SRP(record->rdata, rdata_buf);
2640 INFO(PUB_S_SRP "DNSServiceRegisterRecord(%p %p %d %d %s %d %d %d " PRI_IPv4_ADDR_SRP " %d %p %p)",
2641 skipping ? "skipping " : "", service_ref, &record->rref, kDNSServiceFlagsShared,
2642 host->server_state->advertise_interface, host->registered_name, record->rrtype, dns_qclass_in,
2643 record->rdlen, IPv4_ADDR_PARAM_SRP(record->rdata, rdata_buf),
2644 ADDRESS_RECORD_TTL, register_host_record_completion, record);
2645 } else if (record->rrtype == dns_rrtype_aaaa) {
2646 SEGMENTED_IPv6_ADDR_GEN_SRP(record->rdata, rdata_buf);
2647 INFO(PUB_S_SRP "DNSServiceRegisterRecord(%p %p %d %d %s %d %d %d " PRI_SEGMENTED_IPv6_ADDR_SRP " %d %p %p)",
2648 skipping ? "skipping " : "", service_ref, &record->rref, kDNSServiceFlagsShared,
2649 host->server_state->advertise_interface, host->registered_name, record->rrtype, dns_qclass_in,
2650 record->rdlen, SEGMENTED_IPv6_ADDR_PARAM_SRP(record->rdata, rdata_buf),
2651 ADDRESS_RECORD_TTL, register_host_record_completion, record);
2652 } else {
2653 INFO(PUB_S_SRP "DNSServiceRegisterRecord(%p %p %d %d %s %d %d %d %p %d %p %p)",
2654 skipping ? "skipping " : "", service_ref, &record->rref,
2655 kDNSServiceFlagsShared,
2656 host->server_state->advertise_interface, host->registered_name,
2657 record->rrtype, dns_qclass_in, record->rdlen, record->rdata, ADDRESS_RECORD_TTL,
2658 register_host_record_completion, record);
2659 }
2660 // If we're skipping, we don't actually have to do any work.
2661 if (skipping) {
2662 return true;
2663 }
2664
2665 char time_buf[TSR_TIMESTAMP_STRING_LEN];
2666 DNSServiceAttributeRef tsr_attribute =
2667 srp_adv_host_tsr_attribute_generate(host, time_buf, sizeof(time_buf));
2668 if (tsr_attribute == NULL) {
2669 ERROR("Failed to create new DNSServiceAttributeRef");
2670 return false;
2671 } else {
2672 err = dns_service_register_record_wa(host->server_state, service_ref, &record->rref,
2673 kDNSServiceFlagsKnownUnique,
2674 host->server_state->advertise_interface, host->registered_name,
2675 record->rrtype, dns_qclass_in, record->rdlen, record->rdata,
2676 ADDRESS_RECORD_TTL, tsr_attribute, register_host_record_completion,
2677 record);
2678 DNSServiceAttributeDeallocate(tsr_attribute);
2679 if (err == kDNSServiceErr_NoError) {
2680 INFO("DNSServiceRegisterRecord for " PRI_S_SRP ", TSR set to " PUB_S_SRP " (record %p rref %p)",
2681 host->name, time_buf, record, record->rref);
2682 }
2683 }
2684
2685 if (err != kDNSServiceErr_NoError) {
2686 if (err == kDNSServiceErr_ServiceNotRunning || err == kDNSServiceErr_DefunctConnection ||
2687 err == kDNSServiceErr_BadParam || err == kDNSServiceErr_BadReference || err == 1)
2688 {
2689 if (err == 1) { // This is for an old bug that probably doesn't happen anymore.
2690 FAULT("bogus error code 1");
2691 }
2692 INFO("DNSServiceRegisterRecord failed on host " PUB_S_SRP ": " PUB_S_SRP " (record %p)", host->name,
2693 err == kDNSServiceErr_ServiceNotRunning ? "not running" : "defunct", record);
2694 service_disconnected(host->server_state, (intptr_t)host->server_state->shared_registration_txn);
2695 } else {
2696 INFO("DNSServiceRegisterRecord failed: %d (record %p)", err, record);
2697 }
2698 return false;
2699 }
2700 record->shared_txn = (intptr_t)host->server_state->shared_registration_txn;
2701 RETAIN_HERE(record, adv_record); // for the callback
2702 if (host->update != NULL) {
2703 record->update_pending = true;
2704 }
2705 return true;
2706 }
2707
2708 static bool
2709 update_instance_tsr(adv_instance_t *instance, adv_instance_t *new_instance)
2710 {
2711 int err = kDNSServiceErr_NoError;
2712 bool success = false;
2713
2714 if (instance->txn == NULL) {
2715 ERROR("txn is NULL updating instance TSR.");
2716 goto out;
2717 }
2718 if (instance->txn->sdref == NULL) {
2719 ERROR("sdref is NULL when updating instance TSR.");
2720 goto out;
2721 }
2722 // Currently if we want to update the rdata, we need to do that separately from the TSR.
2723 if (new_instance != NULL) {
2724 if (instance->skip_update) {
2725 err = kDNSServiceErr_NoError;
2726 } else {
2727 err = dns_service_update_record(instance->host->server_state, instance->txn->sdref,
2728 NULL, 0, new_instance->txt_length, new_instance->txt_data, 0);
2729 }
2730 if (err != kDNSServiceErr_NoError) {
2731 INFO("DNSServiceUpdateRecord for instance " PRI_S_SRP " TXT record failed: %d (instance %p)",
2732 instance->instance_name, err, instance);
2733 goto out;
2734 } else {
2735 INFO("updated TXT record for " PRI_S_SRP " . " PRI_S_SRP " (instance %p sdref %p).",
2736 instance->instance_name, instance->service_type, instance, instance->txn->sdref);
2737 success = true;
2738 }
2739 }
2740
2741 DNSServiceAttributeRef attr;
2742
2743 if (instance->skip_update) {
2744 INFO("skipping DNSServiceUpdateRecord for instance " PRI_S_SRP " TSR (instance %p)",
2745 instance->instance_name, instance);
2746 } else {
2747 success = false;
2748 attr = DNSServiceAttributeCreate();
2749 if (attr == NULL) {
2750 ERROR("failed to create new DNSServiceAttributeRef");
2751 } else {
2752 uint32_t offset = 0;
2753 char time_buf[TSR_TIMESTAMP_STRING_LEN];
2754 if (instance->update != NULL && instance->update->client != NULL && instance->update->client->message != NULL &&
2755 instance->update->client->message->received_time != 0)
2756 {
2757 offset = (uint32_t)(srp_time() - instance->update->client->message->received_time);
2758 srp_format_time_offset(time_buf, sizeof(time_buf), offset);
2759 } else {
2760 static char msg[] = "now";
2761 memcpy(time_buf, msg, sizeof(msg));
2762 }
2763 if (_DNSSD_API_AVAILABLE_FALL_2024) {
2764 DNSServiceAttributeSetHostKeyHash(attr, instance->host->key_id);
2765 }
2766 DNSServiceAttributeSetTimestamp(attr, offset);
2767 err = dns_service_update_record_wa(instance->host->server_state,
2768 instance->txn->sdref, NULL, 0, 0, NULL, 0, attr);
2769 DNSServiceAttributeDeallocate(attr);
2770 if (err == kDNSServiceErr_NoError) {
2771 INFO("DNSServiceUpdateRecord for " PRI_S_SRP ", TSR set to " PUB_S_SRP " (instance %p sdref %p)",
2772 instance->host == NULL ? "<null>" : instance->host->name, time_buf, instance, instance->txn->sdref);
2773 success = true;
2774 } else {
2775 INFO("DNSServiceUpdateRecord for instance " PRI_S_SRP ", TSR failed: %d (instance %p sdref %p)",
2776 instance->instance_name, err, instance, instance->txn->sdref);
2777 }
2778 }
2779 }
2780
2781 out:
2782 if (success == false) {
2783 if (instance->txn != NULL) {
2784 // We should never get a bad reference error.
2785 if (err == kDNSServiceErr_BadReference || err == kDNSServiceErr_BadParam) {
2786 FAULT("we got a bad reference error: why?");
2787 }
2788 // For all errors, we should cancel and release the transaction.
2789 ioloop_dnssd_txn_cancel_srp(instance->host->server_state, instance->txn);
2790 ioloop_dnssd_txn_release(instance->txn);
2791 instance->txn = NULL;
2792 }
2793 } else if (new_instance != NULL) {
2794 // If we have new_instance, the caller is going to get rid of it, so we need to
2795 // steal the (possibly changed) data from it and put it on instance.
2796 free(instance->txt_data);
2797 instance->txt_data = new_instance->txt_data;
2798 instance->txt_length = new_instance->txt_length;
2799 new_instance->txt_data = NULL;
2800 new_instance->txt_length = 0;
2801 }
2802 return success;
2803 }
2804
2805 static void
2806 update_host_tsr(adv_record_t *record, adv_update_t *update)
2807 {
2808 DNSServiceAttributeRef attr;
2809 int err;
2810 dnssd_txn_t *shared_txn;
2811
2812 if (record->host == NULL || record->rref == NULL) {
2813 ERROR("record->host[%p], record->rref[%p] when we update host TSR.", record->host, record->rref);
2814 return;
2815 }
2816
2817 shared_txn = record->host->server_state->shared_registration_txn;
2818 if (shared_txn == NULL) {
2819 ERROR("shared_txn is NULL when we update host TSR.");
2820 return;
2821 }
2822 if (shared_txn->sdref == NULL) {
2823 ERROR("shared_txn->sdref is NULL when we update host TSR.");
2824 return;
2825 }
2826
2827 attr = DNSServiceAttributeCreate();
2828 if (attr == NULL) {
2829 ERROR("failed to create new DNSServiceAttributeRef");
2830 } else {
2831 uint32_t offset = 0;
2832 char time_buf[TSR_TIMESTAMP_STRING_LEN];
2833 if (update->client != NULL && update->client->message != NULL && update->client->message->received_time != 0) {
2834 offset = (uint32_t)(srp_time() - update->client->message->received_time);
2835 srp_format_time_offset(time_buf, sizeof(time_buf), offset);
2836 } else {
2837 static char msg[] = "now";
2838 memcpy(time_buf, msg, sizeof(msg));
2839 }
2840 if (_DNSSD_API_AVAILABLE_FALL_2024) {
2841 DNSServiceAttributeSetHostKeyHash(attr, record->host->key_id);
2842 }
2843 DNSServiceAttributeSetTimestamp(attr, offset);
2844 err = dns_service_update_record_wa(record->host->server_state,
2845 shared_txn->sdref, record->rref, 0, 0, NULL, 0, attr);
2846 DNSServiceAttributeDeallocate(attr);
2847 if (err == kDNSServiceErr_NoError) {
2848 INFO("DNSServiceUpdateRecord TSR for " PRI_S_SRP " set to " PUB_S_SRP " (record %p rref %p)",
2849 record->host == NULL ? "<null>" : record->host->name, time_buf, record, record->rref);
2850 } else {
2851 INFO("DNSServiceUpdateRecordWithAttribute for host tsr failed: %d (record %p rref %p)",
2852 err, record, record->rref);
2853 }
2854 }
2855 }
2856
2857 // When we need to register a host with mDNSResponder, start_host_update is called. This can be either because
2858 // we just got a new registration for a host, or if the daemon dies and we need to re-do the host registration.
2859 // This just registers the host; if that succeeds, then we register the service instances.
2860 static void
2861 start_host_update(adv_host_t *host)
2862 {
2863 adv_update_t *update = host->update;
2864 #ifdef USE_DNSSERVICE_QUEUING
2865 int err;
2866 #endif
2867 int i;
2868
2869 // No work to do?
2870 if (update == NULL) {
2871 ERROR("start_host_update: no work to do for host " PRI_S_SRP, host->registered_name);
2872 return;
2873 }
2874
2875 bool skip_host_updates = (update->client != NULL && update->client->skip_host_updates);
2876
2877
2878 update->num_records_started = 0;
2879
2880 // Add all of the addresses that have been registered.
2881 if (update->add_addresses != NULL) {
2882 for (i = 0; i < update->add_addresses->num; i++) {
2883 if (update->add_addresses->vec[i] != NULL) {
2884 if (!register_host_record(host, update->add_addresses->vec[i], skip_host_updates)) {
2885 update_failed(update, dns_rcode_servfail, true, true);
2886 return;
2887 } else if (!skip_host_updates) {
2888 update->num_records_started++;
2889 }
2890 }
2891 }
2892 }
2893
2894 // It's possible that some existing addresses are no longer registered because of a service disconnect. Check all the
2895 // existing addresses for this situation: if an existing address has no rref, and does not appear in update->remove_addrs,
2896 // then re-register it.
2897 if (host->addresses != NULL) {
2898 for (i = 0; i < host->addresses->num; i++) {
2899 adv_record_t *record = host->addresses->vec[i];
2900 adv_record_t *remove_address = NULL;
2901 if (update->remove_addresses != NULL) {
2902 remove_address = update->remove_addresses->vec[i];
2903 }
2904 if (remove_address == NULL && record != NULL && record->rref == NULL) {
2905 host->addresses->vec[i]->update = update;
2906 RETAIN_HERE(host->addresses->vec[i]->update, adv_update);
2907 if (!register_host_record(host, record, skip_host_updates)) {
2908 update_failed(update, dns_rcode_servfail, true, true);
2909 return;
2910 } else if (!skip_host_updates) {
2911 update->num_records_started++;
2912 }
2913 }
2914 }
2915 }
2916
2917 if (update->key != NULL) {
2918 if (!register_host_record(host, update->key, skip_host_updates)) {
2919 update_failed(update, dns_rcode_servfail, true, true);
2920 return;
2921 } else if (!skip_host_updates) {
2922 update->num_records_started++;
2923 }
2924 }
2925
2926 // If the shared transaction has changed since the key record was added, add it again.
2927 if (update->key == NULL && host->key_record != NULL &&
2928 (host->key_record->shared_txn != (intptr_t)host->server_state->shared_registration_txn ||
2929 host->key_record->rref == NULL))
2930 {
2931 update->key = host->key_record;
2932 RETAIN_HERE(update->key, adv_record);
2933 RELEASE_HERE(host->key_record, adv_record);
2934 host->key_record = NULL;
2935 update->key->rref = NULL;
2936 update->key->update = update;
2937 RETAIN_HERE(update, adv_update);
2938 if (!register_host_record(host, update->key, skip_host_updates)) {
2939 update_failed(update, dns_rcode_servfail, true, true);
2940 return;
2941 } else if (!skip_host_updates) {
2942 update->num_records_started++;
2943 }
2944 }
2945
2946 if (update->num_records_started == 0) {
2947 adv_record_t *record = update->key != NULL ? update->key : (host->key_record != NULL ? host->key_record : NULL);
2948 if (record == NULL) {
2949 } else {
2950 if (record->rref == NULL) {
2951 if (!register_host_record(host, record, skip_host_updates)) {
2952 update_failed(update, dns_rcode_servfail, true, true);
2953 return;
2954 } else if (!skip_host_updates) {
2955 update->num_records_started++;
2956 }
2957 } else if (!skip_host_updates) {
2958 update_host_tsr(record, update);
2959 }
2960 }
2961 }
2962
2963 if (host->instances != NULL) {
2964 // For each service instance that's being added, register it.
2965 if (update->add_instances != NULL) {
2966 for (i = 0; i < update->add_instances->num; i++) {
2967 if (update->add_instances->vec[i] != NULL) {
2968 if (!register_instance(update->add_instances->vec[i])) {
2969 update_failed(update, dns_rcode_servfail, true, true);
2970 return;
2971 }
2972 }
2973 }
2974 }
2975
2976 // For each service instance that's being renewed, update its TSR if the original registration still exist,
2977 // Otherwise re-register the instance.
2978 if (update->renew_instances != NULL) {
2979 for (i = 0; i < update->renew_instances->num; i++) {
2980 if (update->renew_instances->vec[i] != NULL) {
2981 adv_instance_t *instance = update->renew_instances->vec[i];
2982 bool must_update = true;
2983 bool renew_failed = instance->txn != NULL;
2984 if (instance->txn != NULL) {
2985 bool must_remove = false;
2986 // Make sure the instance is still registered and is registered on the current shared connection.
2987 if (instance->txn->sdref != NULL) {
2988 if (((intptr_t)host->server_state->shared_registration_txn == instance->shared_txn)) {
2989 if (update_instance_tsr(instance, NULL)) {
2990 must_remove = false;
2991 must_update = false;
2992 instance->recent_message = (ptrdiff_t)update->client->message;
2993 } else {
2994 INFO("instance " PRI_S_SRP " (%p) tsr update failed, re-registering",
2995 instance->instance_name, instance);
2996 must_remove = true;
2997 }
2998 } else {
2999 // If the shared transaction has changed, then the registration no longer exists, and
3000 // the sdref is no longer valid.
3001 INFO("instance " PRI_S_SRP " (%p) shared connection (%" PRIxPTR ") is stale, re-registering",
3002 instance->instance_name, instance, instance->shared_txn);
3003 instance->txn->sdref = NULL;
3004 must_remove = true;
3005 must_update = true;
3006 renew_failed = false;
3007 }
3008 }
3009 if (must_remove) {
3010 // If not, dispose of the transaction and re-register.
3011 if (instance->txn != NULL) {
3012 ioloop_dnssd_txn_cancel_srp(host->server_state, instance->txn);
3013 ioloop_dnssd_txn_release(instance->txn);
3014 instance->txn = NULL;
3015 }
3016 }
3017 }
3018 if (must_update) {
3019 if (renew_failed) {
3020 INFO(PRI_S_SRP " (%p): failed to update TSR, re-registering", instance->instance_name, instance);
3021 }
3022 if (!register_instance(update->renew_instances->vec[i])) {
3023 update_failed(update, dns_rcode_servfail, true, true);
3024 return;
3025 }
3026 }
3027 }
3028 }
3029 }
3030
3031 // Sanity check that the instance vector sizes match between host and update.
3032 if (update->update_instances != NULL && update->update_instances->num != host->instances->num) {
3033 FAULT("update instance count %d differs from host instance count %d",
3034 update->update_instances->num, host->instances->num);
3035 update_failed(update, dns_rcode_servfail, true, true);
3036 return;
3037 }
3038 if (update->remove_instances != NULL && update->remove_instances->num != host->instances->num) {
3039 FAULT("delete instance count %d differs from host instance count %d",
3040 update->remove_instances->num, host->instances->num);
3041 update_failed(update, dns_rcode_servfail, true, true);
3042 return;
3043 }
3044 for (i = 0; i < host->instances->num; i++) {
3045 adv_instance_t *update_instance = update->update_instances->vec[i];
3046 if (update_instance != NULL && !update_instance->removed) {
3047 adv_instance_t *host_instance = host->instances->vec[i];
3048 bool must_register = true;
3049 // Check to see if just the TXT record changes; in this case use DNSServiceUpdateRecord rather than re-registering
3050 // the instance. If we can't update, we have to remove and then add. We could do this as a pair of atomic transactions
3051 // if we used DNSServiceRegisterRecord rather than DNSServiceRegister, but currently we don't do that.
3052 // Of course if the previous registration is no longer valid, re-register.
3053 if (host_instance->txn != NULL && host_instance->txn->sdref != NULL && host->server_state != NULL &&
3054 ((intptr_t)host->server_state->shared_registration_txn == host_instance->shared_txn))
3055 {
3056 if (update_instance->port == host_instance->port &&
3057 update_instance->txt_length != 0 &&
3058 memcmp(update_instance->txt_data, host_instance->txt_data, update_instance->txt_length))
3059 {
3060 // If we are able to update the TXT record using DNSServiceUpdateRecord, we don't actually need
3061 // this update instance.
3062 if (update_instance_tsr(host_instance, update_instance)) {
3063 host_instance->recent_message = (ptrdiff_t)update->client->message;
3064 RELEASE_HERE(update->update_instances->vec[i], adv_instance);
3065 update_instance = NULL;
3066 update->update_instances->vec[i] = NULL;
3067 must_register = false;
3068 }
3069 }
3070 }
3071 if (must_register) {
3072 if (host_instance->txn != NULL) {
3073 ioloop_dnssd_txn_cancel_srp(host->server_state, host->instances->vec[i]->txn);
3074 ioloop_dnssd_txn_release(host->instances->vec[i]->txn);
3075 host->instances->vec[i]->txn = NULL;
3076 }
3077
3078 if (!register_instance(update->update_instances->vec[i])) {
3079 INFO("register instance failed.");
3080 update_failed(update, dns_rcode_servfail, true, true);
3081 return;
3082 }
3083 }
3084 }
3085 }
3086 }
3087
3088 if (update->num_instances_started == 0 && update->num_records_started == 0) {
3089 INFO("no service or record updates, so we're finished.");
3090 srp_mdns_update_finished(update);
3091 return;
3092 }
3093
3094 }
3095
3096 // When a host has no update in progress, and there is a client update ready to process, we need to analyze
3097 // the client update to see what work needs to be done. This work is constructed as an translation from the
3098 // raw update sent by the client (host->clients) into a prepared update that can be used directly to
3099 // register the information with mDNSResponder.
3100 //
3101 // Normally a host will only have one prepared update in progress; however, if we lose our connection to
3102 // mDNSResponder, then we need to re-create the host advertisement. If there was an update in progress when
3103 // this happened, we then need to reapply that as well. In this case an update is constructed from the host, to
3104 // get the host into the intended state, and the in-progress update is pushed below that; when the host has
3105 // been re-created on the daemon, the pending update is popped back off the stack and restarted.
3106 static void
3107 prepare_update(adv_host_t *host, client_update_t *client_update)
3108 {
3109 host_addr_t *addr;
3110 int i, j;
3111 service_instance_t *instance;
3112 adv_record_vec_t *remove_addrs = NULL;
3113 int num_remove_addrs = 0;
3114 adv_record_vec_t *add_addrs = NULL;
3115 int num_add_addrs = 0;
3116 int num_update_instances = 0;
3117 int num_add_instances = 0;
3118 int num_remove_instances = 0;
3119 int num_renew_instances = 0;
3120 adv_instance_vec_t *update_instances = NULL, *add_instances = NULL;
3121 adv_instance_vec_t *remove_instances = NULL, *renew_instances = NULL;
3122 adv_update_t *update = NULL;
3123
3124 // Work to do:
3125 // - Figure out what address records to add and what address records to delete.
3126 // - Because we can only have one address record at a time currently, figure out which address record we want
3127 // - If we already have an address record published, and it's the same, do nothing
3128 // - else if we already have an address record published, and it's changed to a different address, do an update
3129 // - else if we have a new address record, publish it
3130 // - else publish the key to hold the name
3131 // - Go through the set of service instances, identifying deletes, changes and adds
3132 // - We don't currently allow deletes, but what that would look like would be an instance with no SRV or TXT
3133 // record.
3134 // - What about a delete that keeps the name but un-advertises the service? How would we indicate that?
3135 // Maybe if there's no service PTR for the service?
3136 // - Changes means that the contents of the text record changed, or the contents of the SRV record
3137 // changed (but not the hostname) or both.
3138 // - New means that we don't have a service with that service instance name on the host (and we previously
3139 // eliminated the possibility that it exists on some other host).
3140
3141 // Allocate the update structure.
3142 update = calloc(1, sizeof *update);
3143 if (update == NULL) {
3144 ERROR("no memory for update.");
3145 goto fail;
3146 }
3147 RETAIN_HERE(update, adv_update); // For the lifetime of this function
3148
3149 if (host->re_register_wakeup != NULL) {
3150 ioloop_cancel_wake_event(host->re_register_wakeup);
3151 }
3152 host->re_register_pending = false;
3153 update->start_time = srp_time();
3154
3155 // The maximum number of addresses we could be deleting is all the ones the host currently has.
3156 if (host->addresses == NULL || host->addresses->num == 0) {
3157 num_remove_addrs = 0;
3158 remove_addrs = NULL;
3159 } else {
3160 num_remove_addrs = host->addresses->num;
3161 if (num_remove_addrs != 0) {
3162 remove_addrs = adv_record_vec_create(num_remove_addrs);
3163 // If we can't allocate space, just wait a bit.
3164 if (remove_addrs == NULL) {
3165 ERROR("no memory for remove_addrs");
3166 goto fail;
3167 }
3168 remove_addrs->num = num_remove_addrs;
3169 }
3170 }
3171
3172 num_add_addrs = 0;
3173 for (addr = client_update->host->addrs; addr != NULL; addr = addr->next) {
3174 num_add_addrs++;
3175 }
3176 add_addrs = adv_record_vec_create(num_add_addrs);
3177 if (add_addrs == NULL) {
3178 ERROR("no memory for add_addrs");
3179 goto fail;
3180 }
3181
3182 // Copy all of the addresses in the update into add_addresses
3183 num_add_addrs = 0;
3184 for (addr = client_update->host->addrs; addr; addr = addr->next) {
3185 bool add = true;
3186 for (i = 0; i < num_add_addrs; i++) {
3187 // If the client sends duplicate addresses, only add one of them.
3188 if (add_addrs->vec[i] != NULL &&
3189 add_addrs->vec[i]->rrtype == addr->rr.type &&
3190 add_addrs->vec[i]->rdlen == (addr->rr.type == dns_rrtype_a ? 4 : 16) &&
3191 !memcmp(add_addrs->vec[i]->rdata, (uint8_t *)&addr->rr.data, add_addrs->vec[i]->rdlen))
3192 {
3193 add = false;
3194 }
3195 }
3196 if (add) {
3197 adv_record_t *prepared_address = adv_record_create(addr->rr.type, addr->rr.type == dns_rrtype_a ? 4 : 16,
3198 (uint8_t *)&addr->rr.data, host);
3199 if (prepared_address == NULL) {
3200 ERROR("No memory for prepared address");
3201 goto fail;
3202 }
3203 add_addrs->vec[num_add_addrs++] = prepared_address;
3204 }
3205 }
3206 add_addrs->num = num_add_addrs;
3207 for (i = 0; i < add_addrs->num; i++) {
3208 if (add_addrs->vec[i] != NULL) {
3209 add_addrs->vec[i]->update = update;
3210 RETAIN_HERE(add_addrs->vec[i]->update, adv_update);
3211 }
3212 }
3213
3214 #ifdef DEBUG_HOST_RECORDS_VERBOSE
3215 for (i = 0; i < 2; i++) {
3216 for (j = 0; j < (i ? num_add_addrs : num_remove_addrs); j++) {
3217 adv_record_t *address = i ? add_addrs->vec[j] : (host->addresses != NULL ? host->addresses->vec[j] : NULL);
3218 if (address == NULL) {
3219 INFO(PUB_S_SRP " before: %d NULL", i ? "add" : "rmv", j);
3220 } else {
3221 char foobuf[385], *foop = foobuf;
3222 for (unsigned long k = 0; k < address->rdlen && k * 3 + 1 < sizeof(foobuf); k++) {
3223 snprintf(foop, 4, k ? ":%02x" : "%02x", address->rdata[k]);
3224 foop += k ? 3 : 2;
3225 }
3226 *foop = 0;
3227 INFO(PUB_S_SRP " before: %d rrtype %d rdlen %d rdata " PRI_S_SRP, i ? "add" : "rmv", j,
3228 address->rrtype, address->rdlen, foobuf);
3229 }
3230 }
3231 }
3232 #endif // DEBUG_HOST_RECORDS_VERBOSE
3233
3234 // For every host address, see if it's in add_addresses. If it's not, it needs to be removed.
3235 // If it is, it doesn't need to be added.
3236 if (num_remove_addrs != 0) {
3237 for (i = 0; i < num_remove_addrs; i++) {
3238 if (host->addresses != NULL && host->addresses->vec[i] != NULL) {
3239 remove_addrs->vec[i] = host->addresses->vec[i];
3240 RETAIN_HERE(remove_addrs->vec[i], adv_record);
3241 }
3242 for (j = 0; j < num_add_addrs; j++) {
3243 // If the address is present in both places, and has a valid registration, remove it from the list of
3244 // addresses to add, and also remove it from the list of addresses to remove. When we're done, all that
3245 // will be remaining in the list to remove will be addresses that weren't present in the add list.
3246 if (remove_addrs->vec[i] != NULL && add_addrs->vec[j] != NULL &&
3247 remove_addrs->vec[i]->rref != NULL && host->server_state != NULL &&
3248 (intptr_t)host->server_state->shared_registration_txn == remove_addrs->vec[i]->shared_txn &&
3249 add_addrs->vec[j]->rrtype == remove_addrs->vec[i]->rrtype &&
3250 add_addrs->vec[j]->rdlen == remove_addrs->vec[i]->rdlen &&
3251 !memcmp(add_addrs->vec[j]->rdata, remove_addrs->vec[i]->rdata, remove_addrs->vec[i]->rdlen))
3252 {
3253 RELEASE_HERE(remove_addrs->vec[i], adv_record);
3254 remove_addrs->vec[i] = NULL;
3255 RELEASE_HERE(add_addrs->vec[j], adv_record);
3256 add_addrs->vec[j] = NULL;
3257 }
3258 }
3259 }
3260 remove_addrs->num = num_remove_addrs;
3261 }
3262
3263 #ifdef DEBUG_HOST_RECORDS_VERBOSE
3264 for (i = 0; i < 2; i++) {
3265 for (j = 0; j < (i ? num_add_addrs : num_remove_addrs); j++) {
3266 adv_record_t *address = i ? add_addrs->vec[j] : (remove_addrs != NULL ? remove_addrs->vec[j] : NULL);
3267 if (address == NULL) {
3268 INFO(PUB_S_SRP " after: %d NULL", i ? "add" : "rmv", j);
3269 } else {
3270 char foobuf[385], *foop = foobuf;
3271 for (unsigned long k = 0; k < address->rdlen && k * 3 + 1 < sizeof(foobuf); k++) {
3272 snprintf(foop, 4, k ? ":%02x" : "%02x", address->rdata[k]);
3273 foop += k ? 3 : 2;
3274 }
3275 *foop = 0;
3276 INFO(PUB_S_SRP " after: %d rrtype %d rdlen %d rdata " PRI_S_SRP, i ? "add" : "rmv", j,
3277 address->rrtype, address->rdlen, foobuf);
3278 }
3279 }
3280 }
3281 #endif // DEBUG_HOST_RECORDS_VERBOSE
3282
3283 // Make a key record
3284 if (host->key_record == NULL) {
3285 update->key = adv_record_create(dns_rrtype_key, host->key_rdlen, host->key_rdata, host);
3286 if (update->key == NULL) {
3287 ERROR("no memory for key record");
3288 goto fail;
3289 }
3290 update->key->update = update;
3291 RETAIN_HERE(update->key->update, adv_update);
3292 }
3293
3294 // We can never update more instances than currently exist for this host.
3295 num_update_instances = host->instances->num;
3296 num_remove_instances = host->instances->num;
3297 num_renew_instances = host->instances->num;
3298
3299 update_instances = adv_instance_vec_create(num_update_instances);
3300 if (update_instances == NULL) {
3301 ERROR("no memory for update_instances");
3302 goto fail;
3303 }
3304 update_instances->num = num_update_instances;
3305
3306 remove_instances = adv_instance_vec_create(num_remove_instances);
3307 if (remove_instances == NULL) {
3308 ERROR("no memory for remove_instances");
3309 goto fail;
3310 }
3311 remove_instances->num = num_remove_instances;
3312
3313 renew_instances = adv_instance_vec_create(num_renew_instances);
3314 if (renew_instances == NULL) {
3315 ERROR("no memory for renew_instances");
3316 goto fail;
3317 }
3318 renew_instances->num = num_renew_instances;
3319
3320 // Handle removes. Service instance removes have to remove the whole service instance, not some subset.
3321 for (delete_t *dp = client_update->removes; dp; dp = dp->next) {
3322 // Removes can be for services or service instances. Because we're acting as an
3323 // Advertising Proxy and not a regular name server, we don't track service instances,
3324 // and so we don't need to match them here. This if statement checks to see if the
3325 // name could possibly be a service instance name followed by a service type. We
3326 // can then extract the putative service instance name and service type and compare;
3327 // if they match, they are in fact those things, and if they don't, we don't care.
3328 if (dp->name != NULL && dp->name->next != NULL && dp->name->next->next != NULL) {
3329 char instance_name[DNS_MAX_LABEL_SIZE_ESCAPED + 1];
3330 char service_type[DNS_MAX_LABEL_SIZE_ESCAPED + 2];
3331
3332 dns_name_print_to_limit(dp->name, dp->name->next, instance_name, sizeof(instance_name));
3333 dns_name_print_to_limit(dp->name->next, dp->name->next->next->next, service_type, sizeof(service_type));
3334
3335 for (i = 0; i < host->instances->num; i++) {
3336 adv_instance_t *remove_instance = host->instances->vec[i];
3337 if (remove_instance != NULL) {
3338 if (!strcmp(instance_name, remove_instance->instance_name) &&
3339 service_types_equal(service_type, remove_instance->service_type))
3340 {
3341 remove_instances->vec[i] = remove_instance;
3342 RETAIN_HERE(remove_instances->vec[i], adv_instance);
3343 break;
3344 }
3345 }
3346 }
3347 }
3348 }
3349
3350 // The number of instances to add can be as many as there are instances in the update.
3351 num_add_instances = 0;
3352 for (instance = client_update->instances; instance; instance = instance->next) {
3353 num_add_instances++;
3354 }
3355 add_instances = adv_instance_vec_create(num_add_instances);
3356 if (add_instances == NULL) {
3357 ERROR("prepare_update: no memory for add_instances");
3358 goto fail;
3359 }
3360
3361 // Convert all of the instances in the client update to adv_instance_t structures for easy comparison.
3362 // Any that are unchanged will have to be freed--oh well.
3363 i = 0;
3364 for (instance = client_update->instances; instance != NULL; instance = instance->next) {
3365 adv_instance_t *prepared_instance = adv_instance_create(instance, host, update);
3366 if (prepared_instance == NULL) {
3367 // prepare_instance logs.
3368 goto fail;
3369 }
3370 if (i >= num_add_instances) {
3371 FAULT("while preparing client update instances, i >= num_add_instances");
3372 RELEASE_HERE(prepared_instance, adv_instance);
3373 prepared_instance = NULL;
3374 goto fail;
3375 }
3376
3377 prepared_instance->anycast = false;
3378 if (client_update != NULL && client_update->connection != NULL) {
3379 const struct sockaddr *server_addr = connection_get_local_address(client_update->message);
3380 if (server_addr && server_addr->sa_family == AF_INET6) {
3381 const struct in6_addr *const ipv6_address = &(((const struct sockaddr_in6 *)server_addr)->sin6_addr);
3382 uint16_t server_port = ntohs(((const struct sockaddr_in6 *)server_addr)->sin6_port);
3383 SEGMENTED_IPv6_ADDR_GEN_SRP(ipv6_address, addr_buf);
3384 INFO("server address " PRI_SEGMENTED_IPv6_ADDR_SRP "; server port %d",
3385 SEGMENTED_IPv6_ADDR_PARAM_SRP(ipv6_address, addr_buf), server_port);
3386 if (is_thread_mesh_anycast_address(ipv6_address) && server_port == 53) {
3387 prepared_instance->anycast = true;
3388 }
3389 }
3390 }
3391 add_instances->vec[i++] = prepared_instance;
3392 }
3393 add_instances->num = i;
3394
3395 // The instances in the update are now in add_instances. If they are updates, move them to update_instances. If
3396 // they are unchanged, free them and null them out, and remember the current instance in renew_instances. If they
3397 // are adds, leave them.
3398 for (i = 0; i < num_add_instances; i++) {
3399 adv_instance_t *add_instance = add_instances->vec[i];
3400
3401 if (add_instance != NULL) {
3402 for (j = 0; j < host->instances->num; j++) {
3403 adv_instance_t *host_instance = host->instances->vec[j];
3404
3405 // See if the instance names match.
3406 if (host_instance != NULL &&
3407 !strcmp(add_instance->instance_name, host_instance->instance_name) &&
3408 service_types_equal(add_instance->service_type, host_instance->service_type))
3409 {
3410 // If the rdata is the same, and the service type is the same (including subtypes), and it's not
3411 // deleted, it's not an add or an update.
3412 if (!host_instance->removed && add_instance->txt_length == host_instance->txt_length &&
3413 add_instance->port == host_instance->port &&
3414 !strcmp(add_instance->service_type, host_instance->service_type) &&
3415 (add_instance->txt_length == 0 ||
3416 !memcmp(add_instance->txt_data, host_instance->txt_data, add_instance->txt_length)))
3417 {
3418 RELEASE_HERE(add_instances->vec[i], adv_instance);
3419 add_instances->vec[i] = NULL;
3420 renew_instances->vec[j] = host_instance;
3421 RETAIN_HERE(host_instance, adv_instance);
3422 renew_instances->vec[j]->update = update;
3423 RETAIN_HERE(renew_instances->vec[j]->update, adv_update);
3424 INFO(PRI_S_SRP "." PRI_S_SRP " renewed for host " PRI_S_SRP,
3425 host_instance->instance_name, host_instance->service_type, host->name);
3426 } else {
3427 update_instances->vec[j] = add_instance;
3428 RETAIN_HERE(update_instances->vec[j], adv_instance);
3429 RELEASE_HERE(add_instances->vec[i], adv_instance);
3430 add_instances->vec[i] = NULL;
3431 }
3432 break;
3433 }
3434 }
3435 }
3436 }
3437
3438 // At this point we have figured out all the work we need to do, so hang it off an update structure.
3439 update->host = host;
3440 RETAIN_HERE(update->host, adv_host);
3441 update->client = client_update;
3442 update->remove_addresses = remove_addrs;
3443 update->add_addresses = add_addrs;
3444 update->remove_instances = remove_instances;
3445 update->add_instances = add_instances;
3446 update->update_instances = update_instances;
3447 update->renew_instances = renew_instances;
3448 update->host_lease = client_update->host_lease;
3449 update->key_lease = client_update->key_lease;
3450
3451 // Register any added addresses with threadradiod before we actually advertise them, to avoid a spurious
3452 // address query.
3453
3454 host->update = update;
3455 RETAIN_HERE(host->update, adv_update);
3456 RELEASE_HERE(update, adv_update);
3457 update = NULL;
3458
3459
3460 start_host_update(host);
3461 return;
3462
3463 fail:
3464 if (client_update != NULL) {
3465 srp_parse_client_updates_free(client_update);
3466 client_update = NULL;
3467 }
3468 if (remove_addrs != NULL) {
3469 // Addresses in remove_addrs are owned by the host and don't need to be freed.
3470 RELEASE_HERE(remove_addrs, adv_record_vec);
3471 remove_addrs = NULL;
3472 }
3473 if (add_addrs != NULL) {
3474 RELEASE_HERE(add_addrs, adv_record_vec);
3475 add_addrs = NULL;
3476 }
3477 if (add_instances != NULL) {
3478 RELEASE_HERE(add_instances, adv_instance_vec);
3479 add_instances = NULL;
3480 }
3481 if (remove_instances != NULL) {
3482 RELEASE_HERE(remove_instances, adv_instance_vec);
3483 remove_instances = NULL;
3484 }
3485 if (update_instances != NULL) {
3486 RELEASE_HERE(update_instances, adv_instance_vec);
3487 update_instances = NULL;
3488 }
3489 if (update) {
3490 RELEASE_HERE(update, adv_update);
3491 }
3492 }
3493
3494 typedef enum { missed, match, conflict } instance_outcome_t;
3495 static instance_outcome_t
3496 compare_instance(adv_instance_t *instance,
3497 dns_host_description_t *new_host, adv_host_t *host,
3498 char *instance_name, char *service_type)
3499 {
3500 if (instance == NULL) {
3501 return missed;
3502 }
3503 if (host->removed) {
3504 return missed;
3505 }
3506 if (!strcmp(instance_name, instance->instance_name) && service_types_equal(service_type, instance->service_type)) {
3507 if (!dns_names_equal_text(new_host->name, host->name)) {
3508 return conflict;
3509 }
3510 return match;
3511 }
3512 return missed;
3513 }
3514
3515 bool
3516 srp_update_start(client_update_t *client_update)
3517 {
3518 dns_host_description_t *new_host = client_update->host;
3519 char new_host_name[DNS_MAX_NAME_SIZE_ESCAPED + 1];
3520 srp_server_t *server_state = client_update->server_state;
3521 uint32_t key_id = 0;
3522 dns_name_print(new_host->name, new_host_name, sizeof new_host_name);
3523 adv_host_t *host = NULL;
3524 srpl_connection_t *srpl_connection = client_update->srpl_connection;
3525 message_t *raw_message = client_update->message;
3526 comm_t *connection = client_update->connection;
3527
3528
3529 // Compute a checksum on the key, ignoring up to three bytes at the end.
3530 for (client_update_t *update = client_update; update != NULL; update = update->next) {
3531 dns_host_description_t *update_host = update->host;
3532
3533 uint32_t update_key_id = 0;
3534 for (unsigned i = 0; i < update_host->key->data.key.len; i += 4) {
3535 update_key_id += ((update_host->key->data.key.key[i] << 24) | (update_host->key->data.key.key[i + 1] << 16) |
3536 (update_host->key->data.key.key[i + 2] << 8) | (update_host->key->data.key.key[i + 3]));
3537 }
3538 if (update == client_update) {
3539 key_id = update_key_id;
3540 } else if (key_id != update_key_id) {
3541 ERROR("update contains multiple key ids %x and %x", key_id, update_key_id);
3542 advertise_finished(NULL, new_host_name, server_state,
3543 srpl_connection, NULL, raw_message, dns_rcode_refused, NULL, false, true);
3544 goto cleanup;
3545 }
3546 }
3547
3548 char seenbuf[200];
3549 char *already_seen = seenbuf;
3550 const char *plural = "";
3551
3552 // For replicated updates, check the transaction IDs to make sure we aren't applying an update we've already gotten.
3553 if (srpl_connection != NULL) {
3554 for (host = server_state->hosts; host != NULL; host = host->next) {
3555 if (host->key_id == key_id && !strcmp(host->name, new_host_name)) {
3556 break;
3557 }
3558 }
3559
3560 if (host != NULL) {
3561 bool replay = true;
3562 while (client_update != NULL && replay) {
3563 replay = false;
3564 if (host->message != NULL && host->message->wire.id == client_update->message->wire.id) {
3565 replay = true;
3566 } else if (host->instances != NULL) {
3567 for (int i = 0; i < host->instances->num; i++) {
3568 adv_instance_t *instance = host->instances->vec[i];
3569 if (instance != NULL) {
3570 if (instance->message != NULL &&
3571 instance->message->wire.id == client_update->message->wire.id)
3572 {
3573 replay = true;
3574 break;
3575 }
3576 }
3577 }
3578 }
3579 if (replay) {
3580 client_update_t *skip_update = client_update;
3581 client_update = client_update->next;
3582 if (already_seen != seenbuf) {
3583 plural = "s";
3584 }
3585 if (already_seen + 6 < &seenbuf[sizeof(seenbuf)]) {
3586 snprintf(already_seen, 6, " %04x", skip_update->message->wire.id);
3587 already_seen += 5;
3588 }
3589 skip_update->next = NULL;
3590 srp_parse_client_updates_free(skip_update);
3591 if (client_update != NULL) {
3592 new_host = client_update->host;
3593 } else {
3594 new_host = NULL;
3595 }
3596 }
3597 }
3598 }
3599 }
3600 if (already_seen != seenbuf) {
3601 INFO("host update for " PRI_S_SRP ", key id %" PRIx32 " " PUB_S_SRP " (skipped xid" PUB_S_SRP PUB_S_SRP ")",
3602 new_host_name, key_id, srpl_connection == NULL ? "" : srpl_connection->name, plural, seenbuf);
3603 } else {
3604 INFO("host update for " PRI_S_SRP ", key id %" PRIx32 " " PUB_S_SRP,
3605 new_host_name, key_id, srpl_connection == NULL ? "" : srpl_connection->name);
3606 }
3607 if (client_update == NULL) {
3608 advertise_finished(host, new_host_name, server_state, srpl_connection,
3609 NULL, raw_message, dns_rcode_noerror, NULL, false, true);
3610 return true; // It's safe to just return here because we've freed all the client updates.
3611 }
3612
3613 service_instance_t *instances = client_update->instances;
3614 delete_t *removes = client_update->removes;
3615 adv_host_t **p_hosts = NULL;
3616 char pres_name[DNS_MAX_NAME_SIZE_ESCAPED + 1];
3617 service_instance_t *new_instance;
3618 instance_outcome_t outcome = missed;
3619 char instance_name[DNS_MAX_LABEL_SIZE_ESCAPED + 1];
3620 char service_type[DNS_MAX_LABEL_SIZE_ESCAPED * 2 + 2];
3621 host_addr_t *addr;
3622 const bool remove = client_update->host_lease == 0;
3623 const char *updatestr = client_update->host_lease == 0 ? "remove" : "update";
3624 delete_t *dp;
3625
3626
3627 for (addr = new_host->addrs; addr != NULL; addr = addr->next) {
3628 if (addr->rr.type == dns_rrtype_a) {
3629 IPv4_ADDR_GEN_SRP(&addr->rr.data.a.s_addr, addr_buf);
3630 INFO("host " PUB_S_SRP " for " PRI_S_SRP ", address " PRI_IPv4_ADDR_SRP " " PUB_S_SRP, updatestr,
3631 new_host_name, IPv4_ADDR_PARAM_SRP(&addr->rr.data.a.s_addr, addr_buf),
3632 srpl_connection == NULL ? "" : srpl_connection->name);
3633 } else {
3634 SEGMENTED_IPv6_ADDR_GEN_SRP(addr->rr.data.aaaa.s6_addr, addr_buf);
3635 INFO("host " PUB_S_SRP " for " PRI_S_SRP ", address " PRI_SEGMENTED_IPv6_ADDR_SRP " " PUB_S_SRP,
3636 updatestr, new_host_name, SEGMENTED_IPv6_ADDR_PARAM_SRP(addr->rr.data.aaaa.s6_addr, addr_buf),
3637 srpl_connection == NULL ? "" : srpl_connection->name);
3638 }
3639 }
3640 for (new_instance = instances; new_instance != NULL; new_instance = new_instance->next) {
3641 extract_instance_name(instance_name, sizeof instance_name, service_type, sizeof service_type, new_instance);
3642 INFO("host " PUB_S_SRP " for " PRI_S_SRP ", instance name " PRI_S_SRP ", type " PRI_S_SRP
3643 ", port %d " PUB_S_SRP, updatestr, new_host_name, instance_name, service_type,
3644 new_instance->srv != NULL ? new_instance->srv->data.srv.port : -1,
3645 srpl_connection == NULL ? "" : srpl_connection->name);
3646 if (new_instance->txt != NULL) {
3647 char txt_buf[DNS_DATA_SIZE];
3648 dns_txt_data_print(txt_buf, DNS_DATA_SIZE, new_instance->txt->data.txt.len, new_instance->txt->data.txt.data);
3649 INFO("text data for instance " PRI_S_SRP ": " PRI_S_SRP, instance_name, txt_buf);
3650 }
3651 }
3652
3653 // Look for matching service instance names. A service instance name that matches, but has a different
3654 // hostname, means that there is a conflict. We have to look through all the entries; the presence of
3655 // a matching hostname doesn't mean we are done UNLESS there's a matching service instance name pointing
3656 // to that hostname.
3657 for (host = server_state->hosts; host; host = host->next) {
3658 // If a host has been removed, it won't have any instances to compare against. Later on, if we find that
3659 // there is no matching host for this update, we look through the host list again and remove the
3660 // "removed" host if it has the same name, so we don't need to do anything further here.
3661 if (host->removed) {
3662 continue;
3663 }
3664 // We need to look for matches both in the registered instances for this registration, and also in
3665 // the list of new instances, in case we get a duplicate update while a previous update is in progress.
3666 for (new_instance = instances; new_instance; new_instance = new_instance->next) {
3667 extract_instance_name(instance_name, sizeof instance_name, service_type, sizeof service_type, new_instance);
3668
3669 // First check for a match or conflict in the host itself.
3670 for (int i = 0; i < host->instances->num; i++) {
3671 outcome = compare_instance(host->instances->vec[i], new_host, host,
3672 instance_name, service_type);
3673 if (outcome != missed) {
3674 goto found_something;
3675 }
3676 }
3677
3678 // Then look for the same thing in any subsequent updates that have been baked.
3679 if (host->update != NULL) {
3680 if (host->update->add_instances != NULL) {
3681 for (int i = 0; i < host->update->add_instances->num; i++) {
3682 outcome = compare_instance(host->update->add_instances->vec[i], new_host, host,
3683 instance_name, service_type);
3684 if (outcome != missed) {
3685 goto found_something;
3686 }
3687 }
3688 }
3689 }
3690 }
3691 }
3692 found_something:
3693 if (outcome == conflict) {
3694 ERROR("service instance name " PRI_S_SRP "/" PRI_S_SRP " already pointing to host "
3695 PRI_S_SRP ", not host " PRI_S_SRP, instance_name, service_type, host->name, new_host_name);
3696 advertise_finished(NULL, host->name,
3697 server_state, srpl_connection, connection, raw_message, dns_rcode_yxdomain, NULL, true, true);
3698 goto cleanup;
3699 }
3700
3701 // We may have received removes for individual records. In this case, we need to make sure they only remove
3702 // records that have been added to the host that matches.
3703 for (adv_host_t *rhp = server_state->hosts; rhp != NULL; rhp = rhp->next) {
3704 if (rhp->removed) {
3705 continue;
3706 }
3707
3708 // Look for removes that conflict
3709 for (dp = removes; dp != NULL; dp = dp->next) {
3710 // We only need to do this for service instance names. We don't really know what is and isn't a
3711 // service instance name, but if it /could/ be a service instance name, we compare; if it matches,
3712 // it is a service instance name, and if not, no problem.
3713 if (dp->name != NULL && dp->name->next != NULL && dp->name->next->next != NULL) {
3714 dns_name_print_to_limit(dp->name, dp->name->next, instance_name, sizeof(instance_name));
3715 dns_name_print_to_limit(dp->name->next, dp->name->next->next->next, service_type, sizeof(service_type));
3716
3717 // See if the delete deletes an instance on the host
3718 for (int i = 0; i < rhp->instances->num; i++) {
3719 adv_instance_t *instance = rhp->instances->vec[i];
3720 if (instance != NULL) {
3721 if (!strcmp(instance_name, instance->instance_name) &&
3722 service_types_equal(service_type, instance->service_type))
3723 {
3724 if (!strcmp(new_host_name, rhp->name)) {
3725 ERROR("remove for " PRI_S_SRP "." PRI_S_SRP " matches instance on host " PRI_S_SRP,
3726 instance_name, service_type, rhp->name);
3727 dp->consumed = true;
3728 } else {
3729 ERROR("remove for " PRI_S_SRP "." PRI_S_SRP " conflicts with instance on host " PRI_S_SRP,
3730 instance_name, service_type, rhp->name);
3731 advertise_finished(NULL, rhp->name, server_state, srpl_connection,
3732 connection, raw_message, dns_rcode_formerr, NULL, true, true);
3733 goto cleanup;
3734 }
3735 }
3736 }
3737 }
3738
3739 // See if the remove removes an instance on an update on the host
3740 if (rhp->update) {
3741 if (rhp->update->add_instances != NULL) {
3742 for (int i = 0; i < rhp->update->add_instances->num; i++) {
3743 adv_instance_t *instance = rhp->update->add_instances->vec[i];
3744 if (instance != NULL) {
3745 if (!strcmp(instance_name, instance->instance_name) &&
3746 service_types_equal(service_type, instance->service_type))
3747 {
3748 if (!strcmp(new_host_name, rhp->name)) {
3749 dp->consumed = true;
3750 } else {
3751 ERROR("remove for " PRI_S_SRP " conflicts with instance on update to host " PRI_S_SRP,
3752 instance->instance_name, rhp->name);
3753 advertise_finished(NULL, rhp->name, server_state, srpl_connection,
3754 connection, raw_message, dns_rcode_formerr, NULL, true, true);
3755 goto cleanup;
3756 }
3757 }
3758 }
3759 }
3760 }
3761 }
3762 }
3763 }
3764 }
3765
3766 // Log any unmatched deletes, but we don't consider these to be errors.
3767 for (dp = removes; dp != NULL; dp = dp->next) {
3768 if (!dp->consumed) {
3769 DNS_NAME_GEN_SRP(dp->name, name_buf);
3770 INFO("remove for " PRI_DNS_NAME_SRP " doesn't match any instance on any host.",
3771 DNS_NAME_PARAM_SRP(dp->name, name_buf));
3772 }
3773 }
3774
3775 // If we fall off the end looking for a matching service instance, there isn't a matching
3776 // service instance, but there may be a matching host, so look for that.
3777 if (outcome == missed) {
3778 // Search for the new hostname in the list of hosts, which is sorted.
3779 for (p_hosts = &server_state->hosts; *p_hosts; p_hosts = &host->next) {
3780 host = *p_hosts;
3781 int comparison = strcasecmp(new_host_name, host->name);
3782 if (comparison == 0) {
3783 // If we get an update for a host that was removed, and it's not also a remove,
3784 // remove the host entry that's marking the remove. If this is a remove, just flag
3785 // it as a miss.
3786 if (host->removed) {
3787 outcome = missed;
3788 if (remove) {
3789 break;
3790 }
3791 // if remove is more recent than this message (for example, we firt receive remove
3792 // from the actual client and then receive a stale update message from a replication
3793 // peer), we don't apply this message and end processing here.
3794 if (host->remove_received_time > client_update->message->received_time) {
3795 INFO("update for host " PRI_S_SRP " which has been deleted.", host->name);
3796 advertise_finished(NULL, host->name, server_state, srpl_connection,
3797 connection, raw_message, dns_rcode_servfail, NULL, true, true);
3798 goto cleanup;
3799 }
3800 *p_hosts = host->next;
3801 host_invalidate(host);
3802 RELEASE_HERE(host, adv_host);
3803 host = NULL;
3804 break;
3805 }
3806 if (key_id == host->key_id && dns_keys_rdata_equal(new_host->key, &host->key)) {
3807 outcome = match;
3808 break;
3809 }
3810 ERROR("update for host " PRI_S_SRP " has key id %" PRIx32
3811 " which doesn't match host key id %" PRIx32 ".",
3812 host->name, key_id, host->key_id);
3813 advertise_finished(NULL, host->name, server_state, srpl_connection,
3814 connection, raw_message, dns_rcode_yxdomain, NULL, true, true);
3815 goto cleanup;
3816 } else if (comparison < 0) {
3817 break;
3818 }
3819 }
3820 } else {
3821 if (key_id != host->key_id || !dns_keys_rdata_equal(new_host->key, &host->key)) {
3822 ERROR("new host with name " PRI_S_SRP " and key id %" PRIx32
3823 " conflicts with existing host " PRI_S_SRP " with key id %" PRIx32,
3824 new_host_name, key_id, host->name, host->key_id);
3825 advertise_finished(NULL, host->name, server_state, srpl_connection,
3826 connection, raw_message, dns_rcode_yxdomain, NULL, true, true);
3827 goto cleanup;
3828 }
3829 }
3830
3831 // If we didn't find a matching host, we can make a new one. When we create it, it just has
3832 // a name and no records. The update that we then construct will have the missing records.
3833 // We don't want to do this for a remove, obviously.
3834 if (outcome == missed) {
3835 if (remove) {
3836 ERROR("Remove for host " PRI_S_SRP " which doesn't exist.", new_host_name);
3837 advertise_finished(NULL, new_host_name, server_state, srpl_connection,
3838 connection, raw_message, dns_rcode_noerror, NULL, true, true);
3839 goto cleanup;
3840 }
3841 host = calloc(1, sizeof *host);
3842 if (host == NULL) {
3843 ERROR("no memory for host data structure.");
3844 advertise_finished(NULL, new_host_name, server_state, srpl_connection,
3845 connection, raw_message, dns_rcode_servfail, NULL, true, true);
3846 goto cleanup;
3847 }
3848 RETAIN_HERE(host, adv_host);
3849 host->server_state = server_state;
3850 host->instances = adv_instance_vec_create(0);
3851 if (host->instances == NULL) {
3852 ERROR("no memory for host instance vector.");
3853 advertise_finished(NULL, new_host_name, server_state, srpl_connection,
3854 connection, raw_message, dns_rcode_servfail, NULL, true, true);
3855 RELEASE_HERE(host, adv_host);
3856 host = NULL;
3857 goto cleanup;
3858 }
3859 host->addresses = adv_record_vec_create(0);
3860 if (host->addresses == NULL) {
3861 ERROR("no memory for host address vector.");
3862 advertise_finished(NULL, new_host_name, server_state, srpl_connection,
3863 connection, raw_message, dns_rcode_servfail, NULL, true, true);
3864 RELEASE_HERE(host, adv_host);
3865 host = NULL;
3866 goto cleanup;
3867 }
3868
3869 host->retry_wakeup = ioloop_wakeup_create();
3870 if (host->retry_wakeup != NULL) {
3871 host->lease_wakeup = ioloop_wakeup_create();
3872 }
3873 if (host->lease_wakeup == NULL) {
3874 ERROR("no memory for wake event on host");
3875 advertise_finished(NULL, new_host_name, server_state, srpl_connection,
3876 connection, raw_message, dns_rcode_servfail, NULL, true, true);
3877 RELEASE_HERE(host, adv_host);
3878 host = NULL;
3879 goto cleanup;
3880 }
3881 dns_name_print(new_host->name, pres_name, sizeof pres_name);
3882 host->name = strdup(pres_name);
3883 if (host->name == NULL) {
3884 RELEASE_HERE(host, adv_host);
3885 host = NULL;
3886 ERROR("no memory for hostname.");
3887 advertise_finished(NULL, new_host_name, server_state, srpl_connection,
3888 connection, raw_message, dns_rcode_servfail, NULL, true, true);
3889 goto cleanup;
3890 }
3891 host->key = *new_host->key;
3892 #ifndef __clang_analyzer__
3893 // Normally this would be invalid, but we never use the name of the key record.
3894 host->key.name = NULL;
3895 #endif
3896 host->key_rdlen = new_host->key->data.key.len + 4;
3897 host->key_rdata = malloc(host->key_rdlen);
3898 if (host->key_rdata == NULL) {
3899 RELEASE_HERE(host, adv_host);
3900 host = NULL;
3901 ERROR("no memory for host key.");
3902 advertise_finished(NULL, new_host_name, server_state, srpl_connection,
3903 connection, raw_message, dns_rcode_servfail, NULL, true, true);
3904 goto cleanup;
3905 }
3906 memcpy(host->key_rdata, &new_host->key->data.key.flags, 2);
3907 host->key_rdata[2] = new_host->key->data.key.protocol;
3908 host->key_rdata[3] = new_host->key->data.key.algorithm;
3909 memcpy(&host->key_rdata[4], new_host->key->data.key.key, new_host->key->data.key.len);
3910 host->key.data.key.key = &host->key_rdata[4];
3911 host->key_id = key_id;
3912
3913 // Insert this in the list where it would have sorted. The if test is because the optimizer doesn't notice that
3914 // p_hosts can never be null here--it will always be pointing to the end of the list of hosts if we get here.
3915 if (p_hosts != NULL) {
3916 host->next = *p_hosts;
3917 *p_hosts = host;
3918 }
3919 p_hosts = NULL;
3920 }
3921
3922 // If we are already updating this host, either this is a retransmission, or it's a new transaction. In the case
3923 // of a retransmission, we need to keep doing the work we've been asked to do, and hopefully we'll reply before the
3924 // client gives up. In the case of a new request, we aren't ready for it yet; the client really shouldn't have sent
3925 // it so quickly, but if it's behaving correctly, we should be done with the current update before it retransmits,
3926 // so we can safely ignore it. If we're getting a replication update, it can't be newer than the current update.
3927 // So we can ignore it--we'll send a replication update when we're done processing the client update.
3928 if (host->update != NULL) {
3929 #ifdef SRP_DETECT_STALLS
3930 time_t now = srp_time();
3931 // It's possible that we could get an update that stalls due to a problem communicating with mDNSResponder
3932 // and that a timing race prevents this from being detected correctly. In this case, cancel the update and
3933 // let the retry go through. We don't want to do this unless there's a clear stall, so we're allowing ten
3934 // seconds.
3935 if (now - host->update->start_time > 10) {
3936 INFO("update has stalled, failing it silently.");
3937 update_failed(host->update, dns_rcode_servfail, false, false);
3938 service_disconnected(server_state, (intptr_t)server_state->shared_registration_txn);
3939 } else {
3940 #endif // SRP_DETECT_STALLS
3941 INFO("dropping retransmission of in-progress update for host " PRI_S_SRP, host->name);
3942 #if SRP_FEATURE_REPLICATION
3943 srp_replication_advertise_finished(host, host->name, server_state, srpl_connection,
3944 connection, dns_rcode_servfail, true);
3945 #endif
3946 cleanup:
3947 srp_parse_client_updates_free(client_update);
3948 return false;
3949 #ifdef SRP_DETECT_STALLS
3950 }
3951 #endif
3952 }
3953
3954 // If this is a remove, remove the host registrations and mark the host removed. We keep it around until the
3955 // lease expires to prevent replication accidentally re-adding a removed host as a result of a bad timing
3956 // coincidence.
3957 if (remove) {
3958 host_invalidate(host);
3959 // We need to propagate the remove message.
3960 if (host->message != NULL) {
3961 ioloop_message_release(host->message);
3962 }
3963 host->message = raw_message;
3964 // remember the time when the message that removes the host was received
3965 host->remove_received_time = host->message->received_time;
3966 ioloop_message_retain(host->message);
3967 advertise_finished(host, new_host_name, server_state, srpl_connection,
3968 connection, raw_message, dns_rcode_noerror, NULL, true, true);
3969 goto cleanup;
3970 }
3971
3972 // At this point we have an update and a host to which to apply it. We may already be doing an earlier
3973 // update, or not. Create a client update structure to hold the communication, so that when we are done,
3974 // we can respond.
3975 if (outcome == missed) {
3976 INFO("New host " PRI_S_SRP ", key id %" PRIx32 , host->name, host->key_id);
3977 } else {
3978 if (host->registered_name != host->name) {
3979 INFO("Renewing host " PRI_S_SRP ", alias " PRI_S_SRP ", key id %" PRIx32,
3980 host->name, host->registered_name, host->key_id);
3981 } else {
3982 INFO("Renewing host " PRI_S_SRP ", key id %" PRIx32, host->name, host->key_id);
3983 }
3984 }
3985
3986 if (host->registered_name == NULL) {
3987 host->registered_name = host->name;
3988 }
3989
3990 // We have to take the lease from the SRP update--the original registrar negotiated it, and if it's out
3991 // of our range, that's too bad (ish).
3992 if (raw_message->lease != 0) {
3993 INFO("basing lease time on message: raw_message->lease = %d, raw_message->key_lease = %d",
3994 raw_message->lease, raw_message->key_lease);
3995 client_update->host_lease = raw_message->lease;
3996 client_update->key_lease = raw_message->key_lease;
3997 } else {
3998 if (client_update->host_lease < server_state->max_lease_time) {
3999 if (client_update->host_lease < server_state->min_lease_time) {
4000 INFO("basing lease time on server_state->min_lease_time: %d", server_state->min_lease_time);
4001 client_update->host_lease = server_state->min_lease_time;
4002 } else {
4003 INFO("basing lease time on client_update->host_lease: %d", client_update->host_lease);
4004 // client_update->host_lease = client_update->host_lease;
4005 }
4006 } else {
4007 client_update->host_lease = server_state->max_lease_time;
4008 INFO("basing lease time on server_state->max_lease_time: %d", server_state->max_lease_time);
4009 }
4010 if (client_update->key_lease < server_state->key_max_lease_time) {
4011 if (client_update->key_lease < server_state->key_min_lease_time) {
4012 client_update->key_lease = server_state->key_min_lease_time;
4013 } else {
4014 // client_update->key_lease = client_update->key_lease;
4015 }
4016 } else {
4017 client_update->key_lease = server_state->key_max_lease_time;
4018 }
4019 }
4020
4021 #if SRP_FEATURE_REPLICATION
4022 if (srpl_connection != NULL) {
4023 host->srpl_connection = srpl_connection;
4024 srpl_connection_retain(host->srpl_connection);
4025 }
4026 #endif // SRP_FEATURE_REPLICATION
4027
4028 // Apply the update.
4029 prepare_update(host, client_update);
4030 return true;
4031 }
4032
4033 void
4034 srp_mdns_flush(srp_server_t *server_state)
4035 {
4036 adv_host_t *host, *host_next;
4037
4038 INFO("flushing all host entries.");
4039 for (host = server_state->hosts; host; host = host_next) {
4040 INFO("Flushing services and host entry for " PRI_S_SRP " (" PRI_S_SRP ")",
4041 host->name, host->registered_name);
4042 // Get rid of the updates before calling delete_host, which will fail if update is not NULL.
4043 if (host->update != NULL) {
4044 update_failed(host->update, dns_rcode_refused, false, true);
4045 }
4046 host_next = host->next;
4047 host_remove(host);
4048 }
4049 server_state->hosts = NULL;
4050 }
4051
4052 static void
4053 usage(void)
4054 {
4055 ERROR("srp-mdns-proxy [--max-lease-time <seconds>] [--min-lease-time <seconds>] [--log-stderr]");
4056 ERROR(" [--enable-replication | --disable-replication]");
4057 #if SRP_FEATURE_NAT64
4058 ERROR(" [--enable-nat64 | --disable-nat64]");
4059 #endif
4060 exit(1);
4061 }
4062
4063 srp_server_t *
4064 server_state_create(const char *name, int max_lease_time, int min_lease_time,
4065 int key_max_lease_time, int key_min_lease_time)
4066 {
4067 srp_server_t *server_state = calloc(1, sizeof(*server_state));
4068 if (server_state == NULL || (server_state->name = strdup(name)) == NULL) {
4069 ERROR("no memory for server state");
4070 free(server_state);
4071 return NULL;
4072 }
4073 server_state->max_lease_time = max_lease_time;
4074 server_state->min_lease_time = min_lease_time;
4075 server_state->key_max_lease_time = key_max_lease_time;
4076 server_state->key_min_lease_time = key_min_lease_time;
4077 server_state->priority = PRIORITY_DEFAULT;
4078 #if TARGET_OS_TV
4079 #endif
4080 INFO("priority set to %d", server_state->priority);
4081 return server_state;
4082 }
4083
4084 static void
4085 object_allocation_stats_dump_callback(void *context)
4086 {
4087 srp_server_t *server_state = context;
4088
4089 ioloop_dump_object_allocation_stats();
4090
4091 if (server_state->full_dump_count == 0) {
4092 srp_dump_server_stats(server_state, true, true);
4093 server_state->full_dump_count = 12;
4094 } else {
4095 srp_dump_server_stats(server_state, false, true);
4096 }
4097 --server_state->full_dump_count;
4098
4099 // Do the next object memory allocation statistics dump in five minutes
4100 ioloop_add_wake_event(server_state->object_allocation_stats_dump_wakeup, server_state,
4101 object_allocation_stats_dump_callback, NULL, 5 * 60 * 1000);
4102 }
4103
4104 int
4105 main(int argc, char **argv)
4106 {
4107 int i;
4108 char *end;
4109 int log_stderr = false;
4110 #ifdef SRP_TEST_SERVER
4111 char *test_to_run = NULL;
4112 bool normal_srp_startup = false;
4113 #else
4114 bool normal_srp_startup = true;
4115 #endif
4116 #if STUB_ROUTER
4117 bool stub_router_enabled = false;
4118 #endif
4119 bool thread_device_enabled = false;
4120
4121 srp_servers = server_state_create("srp-mdns-proxy",
4122 3600 * 27, // max lease time one day plus 20%
4123 30, // min lease time 30 seconds
4124 3600 * 24 * 7, // max key lease 7 days
4125 30); // min key lease time 30s
4126 if (srp_servers == NULL) {
4127 return 1;
4128 }
4129
4130 if (normal_srp_startup) {
4131 srp_servers->srp_replication_enabled = true;
4132 # if SRP_FEATURE_NAT64
4133 srp_servers->srp_nat64_enabled = true;
4134 # endif
4135 }
4136
4137
4138 // Set the advertise interface
4139 if (0) {
4140 #if STUB_ROUTER
4141 } else if (stub_router_enabled) {
4142 srp_servers->advertise_interface = kDNSServiceInterfaceIndexAny;
4143 #endif
4144 } else {
4145 srp_servers->advertise_interface = if_nametoindex("lo0");
4146 }
4147 for (i = 1; i < argc; i++) {
4148 if (!strcmp(argv[i], "--max-lease-time")) {
4149 if (i + 1 == argc) {
4150 usage();
4151 }
4152 srp_servers->max_lease_time = (uint32_t)strtoul(argv[i + 1], &end, 10);
4153 if (end == argv[i + 1] || end[0] != 0) {
4154 usage();
4155 }
4156 i++;
4157 } else if (!strcmp(argv[i], "--min-lease-time")) {
4158 if (i + 1 == argc) {
4159 usage();
4160 }
4161 srp_servers->min_lease_time = (uint32_t)strtoul(argv[i + 1], &end, 10);
4162 if (end == argv[i + 1] || end[0] != 0) {
4163 usage();
4164 }
4165 i++;
4166 } else if (!strcmp(argv[i], "--log-stderr")) {
4167 log_stderr = true;
4168 #ifdef LOG_FPRINTF_STDERR
4169 } else if (!strcmp(argv[i], "--log-relative-timestamp")) {
4170 srp_log_timestamp_relative = true;
4171 #endif
4172 } else if (!strcmp(argv[i], "--enable-replication")) {
4173 srp_servers->srp_replication_enabled = true;
4174 } else if (!strcmp(argv[i], "--disable-replication")) {
4175 srp_servers->srp_replication_enabled = false;
4176 } else if (!strcmp(argv[i], "--fake-xpanid")) {
4177 if (i + 1 == argc) {
4178 usage();
4179 }
4180 srp_servers->xpanid = strtoul(argv[i + 1], &end, 16);
4181 if (end == argv[i + 1] || end[0] != 0) {
4182 usage();
4183 }
4184 #ifdef SRP_TEST_SERVER
4185 } else if (!strcmp(argv[i], "--test")) {
4186 if (i + 1 == argc) {
4187 usage();
4188 }
4189 test_to_run = argv[i + 1];
4190 i++;
4191 #endif
4192 #if SRP_FEATURE_NAT64
4193 } else if (!strcmp(argv[i], "--enable-nat64")) {
4194 srp_servers->srp_nat64_enabled = true;
4195 } else if (!strcmp(argv[i], "--disable-nat64")) {
4196 srp_servers->srp_nat64_enabled = false;
4197 #endif
4198 } else {
4199 usage();
4200 }
4201 }
4202
4203 // Setup log category for srp-mdns-prox and dnssd-proxy.
4204 OPENLOG("srp-mdns-proxy", log_stderr);
4205
4206 #ifdef SRP_TEST_SERVER
4207 INFO("srp-test-server starting, compiled on " PUB_S_SRP ", " PUB_S_SRP, __DATE__, __TIME__);
4208 #else
4209 INFO("--------------------------------"
4210 "srp-mdns-proxy starting, compiled on " PUB_S_SRP ", " PUB_S_SRP
4211 "--------------------------------", __DATE__, __TIME__);
4212 #endif
4213
4214 if (!ioloop_init()) {
4215 return 1;
4216 }
4217
4218 if (normal_srp_startup) {
4219 #if THREAD_DEVICE
4220 if (0) {
4221 #if STUB_ROUTER
4222 } else if (stub_router_enabled) {
4223 srp_servers->route_state = route_state_create(srp_servers, "srp-mdns-proxy");
4224 if (srp_servers->route_state == NULL) {
4225 return 1;
4226 }
4227 #endif // STUB_ROUTER
4228 }
4229
4230 if (!srp_mdns_shared_registration_txn_setup(srp_servers)) {
4231 return 1;
4232 }
4233 dns_service_op_not_to_be_freed = srp_servers->shared_registration_txn->sdref;
4234 #endif // THREAD_DEVICE
4235
4236 #if STUB_ROUTER
4237 if (stub_router_enabled) {
4238 // Set up the ULA early just in case we get an early registration, nat64 will use the ula
4239 route_ula_setup(srp_servers->route_state);
4240 }
4241 #endif
4242
4243
4244 #if (SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY)
4245 if (!init_dnssd_proxy(srp_servers)) {
4246 ERROR("failed to setup dnssd-proxy");
4247 }
4248 #endif // #if (SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY)
4249
4250 #if STUB_ROUTER
4251 if (stub_router_enabled) {
4252 if (!start_icmp_listener()) {
4253 ERROR("failed to start icmp listener");
4254 }
4255 }
4256 #endif
4257
4258
4259 infrastructure_network_startup(srp_servers->route_state);
4260
4261 if (adv_ctl_init(srp_servers) != kDNSServiceErr_NoError) {
4262 ERROR("Can't start advertising proxy control server.");
4263 }
4264
4265 // We require one open file per service and one per instance.
4266 struct rlimit limits;
4267 if (getrlimit(RLIMIT_NOFILE, &limits) < 0) {
4268 ERROR("getrlimit failed: " PUB_S_SRP, strerror(errno));
4269 }
4270
4271 if (limits.rlim_cur < 1024) {
4272 if (limits.rlim_max < 1024) {
4273 INFO("file descriptor hard limit is %llu", (unsigned long long)limits.rlim_max);
4274 if (limits.rlim_cur != limits.rlim_max) {
4275 limits.rlim_cur = limits.rlim_max;
4276 }
4277 } else {
4278 limits.rlim_cur = 1024;
4279 }
4280 if (setrlimit(RLIMIT_NOFILE, &limits) < 0) {
4281 ERROR("setrlimit failed: " PUB_S_SRP, strerror(errno));
4282 }
4283 }
4284
4285 srp_proxy_init("local");
4286 #ifdef SRP_TEST_SERVER
4287 } else {
4288 ioloop_run_async(srp_test_server_run_test, test_to_run);
4289 #endif
4290 }
4291
4292 srp_servers->object_allocation_stats_dump_wakeup = ioloop_wakeup_create();
4293 if (srp_servers->object_allocation_stats_dump_wakeup == NULL) {
4294 INFO("no memory for srp_servers->object_allocation_stats_dump_wakeup");
4295 } else {
4296 // Do an object memory allocation statistics dump every five minutes, and a full database dump every half hour
4297 // starting after the first five minutes
4298 srp_servers->full_dump_count = 1;
4299 object_allocation_stats_dump_callback(srp_servers);
4300 }
4301
4302 ioloop();
4303 }
4304
4305 // Local Variables:
4306 // mode: C
4307 // tab-width: 4
4308 // c-file-style: "bsd"
4309 // c-basic-offset: 4
4310 // fill-column: 120
4311 // indent-tabs-mode: nil
4312 // End:
4313