]> git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/srp-mdns-proxy.c
mDNSResponder-1310.60.4.tar.gz
[apple/mdnsresponder.git] / ServiceRegistration / srp-mdns-proxy.c
1 /* srp-mdns-proxy.c
2 *
3 * Copyright (c) 2019-2020 Apple Computer, 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 * http://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 <unistd.h>
25 #include <pwd.h>
26 #include <errno.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <fcntl.h>
31 #include <sys/time.h>
32 #include <dns_sd.h>
33 #include <net/if.h>
34 #include <sys/resource.h>
35
36 #include "srp.h"
37 #include "dns-msg.h"
38 #include "srp-crypto.h"
39 #include "ioloop.h"
40 #include "dnssd-proxy.h"
41 #include "srp-gw.h"
42 #include "srp-proxy.h"
43 #include "srp-mdns-proxy.h"
44 #include "config-parse.h"
45 #include "route.h"
46
47 #ifdef IOLOOP_MACOS
48 #include "xpc_client_advertising_proxy.h"
49 #include "advertising_proxy_services.h"
50 #include <os/transaction_private.h>
51 #endif
52
53 // Server internal state
54 struct {
55 struct in6_addr addr;
56 int width;
57 } *preferred_prefix;
58
59 typedef struct srp_xpc_client srp_xpc_client_t;
60 struct srp_xpc_client {
61 srp_xpc_client_t *next;
62 xpc_connection_t connection;
63 bool connection_canceled; // If true, we've initiated an xpc_connection_cancel on this client.
64 bool enabler; // If true, this client has asked to enable the proxy.
65 };
66
67 typedef struct srp_wanted_state srp_wanted_state_t;
68 struct srp_wanted_state {
69 int ref_count;
70 os_transaction_t transaction;
71 };
72
73 adv_host_t *hosts;
74 int advertise_interface = kDNSServiceInterfaceIndexAny;
75
76 const char local_suffix_ld[] = ".local";
77 const char *local_suffix = &local_suffix_ld[1];
78 uint32_t max_lease_time = 3600 * 27; // One day plus 20%
79
80 static xpc_connection_t xpc_listener;
81
82 srp_wanted_state_t *srp_wanted;
83 srp_xpc_client_t *srp_xpc_clients;
84
85 // Forward references...
86 static void try_new_hostname(adv_host_t *host);
87 static void register_host_completion(DNSServiceRef sdref, DNSRecordRef rref,
88 DNSServiceFlags flags, DNSServiceErrorType error_code, void *context);
89 static void register_instance_completion(DNSServiceRef sdref, DNSServiceFlags flags, DNSServiceErrorType error_code,
90 const char *name, const char *regtype, const char *domain, void *context);
91 static void update_from_host(adv_host_t *host);
92 static void start_host_update(adv_host_t *host);
93 static void prepare_update(adv_host_t *host);
94 static void lease_callback(void *context);
95
96
97 static void
98 adv_address_finalize(adv_address_t *address)
99 {
100 free(address);
101 }
102
103 static void
104 adv_instance_finalize(adv_instance_t *instance)
105 {
106 if (instance->txn != NULL) {
107 ioloop_dnssd_txn_release(instance->txn);
108 }
109 if (instance->txt_data != NULL) {
110 free(instance->txt_data);
111 }
112 if (instance->instance_name != NULL) {
113 free(instance->instance_name);
114 }
115 if (instance->service_type != NULL) {
116 free(instance->service_type);
117 }
118 free(instance);
119 }
120
121 static adv_instance_vec_t *
122 adv_instance_vec_create(int size)
123 {
124 adv_instance_vec_t *vec;
125
126 vec = calloc(1, sizeof(*vec));
127 if (vec != NULL) {
128 if (size == 0) {
129 size = 1;
130 }
131 vec->vec = calloc(size, sizeof (*(vec->vec)));
132 if (vec->vec == NULL) {
133 free(vec);
134 vec = NULL;
135 } else {
136 RETAIN_HERE(vec);
137 }
138 }
139 return vec;
140 }
141
142 static adv_instance_vec_t *
143 adv_instance_vec_copy(adv_instance_vec_t *vec)
144 {
145 adv_instance_vec_t *new_vec;
146 int i;
147
148 new_vec = adv_instance_vec_create(vec->num);
149 if (new_vec != NULL) {
150 RETAIN_HERE(new_vec);
151 for (i = 0; i < vec->num; i++) {
152 if (vec->vec[i] != NULL) {
153 new_vec->vec[i] = vec->vec[i];
154 RETAIN_HERE(new_vec->vec[i]);
155 }
156 }
157 new_vec->num = vec->num;
158 }
159 return new_vec;
160 }
161
162 static void
163 adv_instance_vec_finalize(adv_instance_vec_t *vec)
164 {
165 int i;
166
167 for (i = 0; i < vec->num; i++) {
168 if (vec->vec[i] != NULL) {
169 RELEASE_HERE(vec->vec[i], adv_instance_finalize);
170 vec->vec[i] = NULL;
171 }
172 }
173 free(vec->vec);
174 free(vec);
175 }
176
177 static bool
178 same_prefix(void *ai, void *bi, int width)
179 {
180 int bite;
181 uint8_t *a = ai, *b = bi;
182 static int masks[] = {0xff, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
183 static int mask;
184 for (bite = 0; bite * 8 < width; bite++) {
185 if (a[bite] != b[bite]) {
186 return false;
187 }
188 }
189 if ((width % 8) == 0) {
190 return true;
191 }
192 mask = masks[width % 8];
193 if ((a[bite] & mask) == (b[bite] & mask)) {
194 return true;
195 }
196 return false;
197 }
198
199 // We call advertise_finished when a client request has finished, successfully or otherwise.
200 static void
201 advertise_finished(comm_t *connection, message_t *message, int rcode, client_update_t *client)
202 {
203 struct iovec iov;
204 dns_wire_t response;
205 INFO("advertise_finished: rcode = " PUB_S_SRP, dns_rcode_name(rcode));
206
207 memset(&response, 0, DNS_HEADER_SIZE);
208 response.id = message->wire.id;
209 response.bitfield = message->wire.bitfield;
210 dns_rcode_set(&response, rcode);
211 dns_qr_set(&response, dns_qr_response);
212
213 iov.iov_base = &response;
214 // If this was a successful update, send back the lease time, which will either
215 // be what the client asked for, or a shorter lease, depending on what limit has
216 // been set.
217 if (client != NULL) {
218 dns_towire_state_t towire;
219 memset(&towire, 0, sizeof towire);
220 towire.p = &response.data[0]; // We start storing RR data here.
221 towire.lim = &response.data[DNS_DATA_SIZE]; // This is the limit to how much we can store.
222 towire.message = &response;
223 response.qdcount = 0;
224 response.ancount = 0;
225 response.nscount = 0;
226 response.arcount = htons(1);
227 dns_edns0_header_to_wire(&towire, DNS_MAX_UDP_PAYLOAD, 0, 0, 1);
228 dns_rdlength_begin(&towire);
229 dns_u16_to_wire(&towire, dns_opt_update_lease); // OPTION-CODE
230 dns_edns0_option_begin(&towire); // OPTION-LENGTH
231 dns_u32_to_wire(&towire, client->host_lease); // LEASE (e.g. 1 hour)
232 dns_u32_to_wire(&towire, client->key_lease); // KEY-LEASE (7 days)
233 dns_edns0_option_end(&towire); // Now we know OPTION-LENGTH
234 dns_rdlength_end(&towire);
235 // It should not be possible for this to happen; if it does, the client
236 // might not renew its lease in a timely manner.
237 if (towire.error) {
238 ERROR("advertise_finished: unexpectedly failed to send EDNS0 lease option.");
239 iov.iov_len = DNS_HEADER_SIZE;
240 } else {
241 iov.iov_len = towire.p - (uint8_t *)&response;
242 }
243 } else {
244 iov.iov_len = DNS_HEADER_SIZE;
245 }
246 ioloop_send_message(connection, message, &iov, 1);
247 }
248
249 static void
250 host_txn_finalize_callback(void *context)
251 {
252 adv_host_t *host = context;
253 host->txn = NULL;
254 host->rref = NULL;
255 }
256
257 static void
258 instance_txn_finalize_callback(void *context)
259 {
260 adv_instance_t *instance = context;
261 instance->txn = NULL;
262 }
263
264 static void
265 retry_callback(void *context)
266 {
267 adv_host_t *host = (adv_host_t *)context;
268 if (host->updates == NULL && host->clients == NULL) {
269 update_from_host(host);
270 } else {
271 start_host_update(host);
272 }
273 }
274
275 static void
276 wait_retry(adv_host_t *host)
277 {
278 #define MIN_HOST_RETRY_INTERVAL 15
279 #define MAX_HOST_RETRY_INTERVAL 120
280 // If we've been retrying long enough for the lease to expire, give up.
281 if (!host->lease_expiry || host->lease_expiry >= ioloop_timenow()) {
282 lease_callback(host);
283 }
284 if (host->retry_interval == 0) {
285 host->retry_interval = MIN_HOST_RETRY_INTERVAL;
286 } else if (host->retry_interval < MAX_HOST_RETRY_INTERVAL) {
287 host->retry_interval *= 2;
288 }
289 INFO("wait_retry: waiting %d seconds...", host->retry_interval);
290 ioloop_add_wake_event(host->retry_wakeup, host, retry_callback, NULL, host->retry_interval * 1000);
291 }
292
293 // When the connection to mDNSResponder has died, the registration dies with it.
294 // In order to get back to where we were, we use the contents of the host to create an
295 // update. We push that update in front of any update that was pending, and restart
296 // the registration. There is no guarantee that this will succeed. If it fails, then
297 // the registration is abandoned.
298
299 static void
300 service_disconnected(adv_host_t *host)
301 {
302 // If we don't have any updates we can do, this host is dead.
303 if (host->updates == NULL) {
304 // lease_callback will get rid of this host.
305 lease_callback(host);
306 } else {
307 wait_retry(host);
308 }
309 }
310
311 static void
312 client_finalize(client_update_t *client)
313 {
314 srp_update_free_parts(client->instances, NULL, client->services, client->host);
315 if (client->parsed_message != NULL) {
316 dns_message_free(client->parsed_message);
317 }
318 if (client->message != NULL) {
319 ioloop_message_release(client->message);
320 }
321 if (client->connection != NULL) {
322 ioloop_comm_release(client->connection);
323 }
324 free(client);
325 }
326
327 static void
328 update_finalize(adv_update_t *NONNULL update)
329 {
330 adv_host_t *host = update->host;
331 int i;
332 if (host != NULL) {
333 adv_update_t **p_updates = &host->updates;
334
335 // Once the update is done, we want to make sure that any results that come in on the host registration do not
336 // reference the update, which will we are about to free. So get rid of the update pointer that's in the
337 // host address transaction aux data.
338 if (update->host->txn != NULL) {
339 adv_update_t *host_txn_update = ioloop_dnssd_txn_get_aux_pointer(host->txn);
340 // If we are retrying an update, the update on the host DNSServiceRegisterRecord transaction might not be
341 // the transaction we are finalizing, but if it is, we definitely want to make it go away.
342 if (host_txn_update == update) {
343 ioloop_dnssd_txn_set_aux_pointer(host->txn, NULL);
344 }
345 }
346 INFO("finalizing update %p for host " PRI_S_SRP, update, host->registered_name);
347
348 // Take this update off the host's update list (it might already be gone)
349 while (*p_updates != NULL) {
350 if (*p_updates == update) {
351 *p_updates = update->next;
352 break;
353 } else {
354 p_updates = &((*p_updates)->next);
355 }
356 }
357 } else {
358 INFO("finalizing update with no host.");
359 }
360
361 // Release instances and instance vectors.
362 if (update->add_instances != NULL) {
363 RELEASE_HERE(update->add_instances, adv_instance_vec_finalize);
364 }
365
366 if (update->update_instances != NULL) {
367 RELEASE_HERE(update->update_instances, adv_instance_vec_finalize);
368 }
369
370 if (update->remove_instances != NULL) {
371 RELEASE_HERE(update->remove_instances, adv_instance_vec_finalize);
372 }
373
374 if (update->add_addresses != NULL) {
375 for (i = 0; i < update->num_add_addresses; i++) {
376 if (update->add_addresses[i] != NULL) {
377 RELEASE_HERE(update->add_addresses[i], adv_address_finalize);
378 }
379 }
380 free(update->add_addresses);
381 }
382
383 if (update->remove_addresses != NULL) {
384 for (i = 0; i < update->num_remove_addresses; i++) {
385 if (update->remove_addresses[i] != NULL) {
386 RELEASE_HERE(update->remove_addresses[i], adv_address_finalize);
387 }
388 }
389 free(update->remove_addresses);
390 }
391
392 if (update->selected_addr != NULL) {
393 RELEASE_HERE(update->selected_addr, adv_address_finalize);
394 }
395
396 free(update);
397 }
398
399 static void
400 update_failed(adv_update_t *update, int rcode, bool expire)
401 {
402 // If we still have a client waiting for the result of this update, tell it we failed.
403 // Updates that have never worked are abandoned when the client is notified.
404 if (update->client != NULL) {
405 adv_host_t *host = update->host;
406 client_update_t *client = update->client;
407 advertise_finished(client->connection, client->message, rcode, NULL);
408 update_finalize(update);
409 client_finalize(client);
410 // If we don't have a lease yet, or the old lease has expired, remove the host.
411 // However, if the expire flag is false, it's because we're already finalizing the
412 // host, so doing an expiry here would double free the host. In this case, we leave
413 // it to the caller to do the expiry (really, to finalize the host).
414 if (expire && (host->lease_expiry == 0 || host->lease_expiry <= ioloop_timenow())) {
415 lease_callback(host);
416 }
417 return;
418 }
419
420 // The only time that we will not have a client waiting for a result from an update is if
421 // we are trying to recover from an mDNSResponder crash. mDNSResponder doesn't crash much,
422 // so the likelihood of us even finding out if this behavior is correct is pretty low.
423 // That said, we do take this possibility into account; if it happens, we try to restore
424 // all the registrations that were present prior to the crash.
425
426 // In the case of an update that previously succeeded, but that now has failed because of a naming
427 // conflict (yxdomain), we have to abandon it, even though we have no way to notify the owner.
428 if (rcode == dns_rcode_yxdomain) {
429 update_finalize(update);
430 return;
431 }
432 }
433
434 static void
435 host_addr_free(adv_host_t *host)
436 {
437 int i;
438
439 if (host->addresses != NULL) {
440 for (i = 0; i < host->num_addresses; i++) {
441 if (host->addresses[i] != NULL) {
442 RELEASE_HERE(host->addresses[i], adv_address_finalize);
443 }
444 }
445 free(host->addresses);
446 }
447 host->addresses = NULL;
448 host->num_addresses = 0;
449 }
450
451 static void
452 host_finalize(adv_host_t *host)
453 {
454 int i;
455
456 // Get rid of the host wake events.
457 if (host->lease_wakeup != NULL) {
458 ioloop_cancel_wake_event(host->lease_wakeup);
459 ioloop_wakeup_release(host->lease_wakeup);
460 }
461 if (host->retry_wakeup != NULL) {
462 ioloop_cancel_wake_event(host->retry_wakeup);
463 ioloop_wakeup_release(host->retry_wakeup);
464 }
465
466
467 // Remove all the advertised address records (currently only one).
468 if (host->txn != NULL) {
469 if (host->txn->sdref == NULL) {
470 INFO("host_finalize: releasing DNSSD transaction for " PRI_S_SRP ", but there's no sdref.", host->name);
471 } else {
472 INFO("host_finalize: removing AAAA record(s) for " PRI_S_SRP, host->registered_name);
473 }
474 ioloop_dnssd_txn_release(host->txn);
475 } else {
476 INFO("host_finalize: no host address transaction for " PRI_S_SRP, host->registered_name);
477 }
478
479 // Remove the address records.
480 host_addr_free(host);
481
482 // Remove the services.
483
484 if (host->instances != NULL) {
485 for (i = 0; i < host->instances->num; i++) {
486 if (host->instances->vec[i] != NULL) {
487 if (host->instances->vec[i]->txn) {
488 ioloop_dnssd_txn_release(host->instances->vec[i]->txn);
489 }
490 }
491 }
492 RELEASE_HERE(host->instances, adv_instance_vec_finalize);
493 }
494
495 // At this point we could claim the key, but for now just get rid of the host.
496 if (host->key_rdata != NULL) {
497 free(host->key_rdata);
498 }
499 INFO("host_finalize: removed " PRI_S_SRP ", key_id %x", host->name ? host->name : "<null>", host->key_id);
500
501 // In the default case, host->name and host->registered_name point to the same memory: we don't want a double free.
502 if (host->registered_name == host->name) {
503 host->registered_name = NULL;
504 }
505 if (host->name != NULL) {
506 free(host->name);
507 }
508 if (host->registered_name != NULL) {
509 free(host->registered_name);
510 }
511 free(host);
512 }
513
514 static void
515 lease_callback(void *context)
516 {
517 adv_host_t **p_hosts, *host = context;
518
519 // Find the host on the list of hosts.
520 for (p_hosts = &hosts; *p_hosts != NULL; p_hosts = &(*p_hosts)->next) {
521 if (*p_hosts == host) {
522 break;
523 }
524 }
525 if (*p_hosts == NULL) {
526 ERROR("lease-callback: called with nonexistent host.");
527 return;
528 }
529
530 // It's possible that we got an update to this host, but haven't processed it yet. In this
531 // case, we don't want to get rid of the host, but we do want to get rid of it later if the
532 // update fails. So postpone the removal for another lease interval.
533 if (host->updates != NULL || host->clients != NULL) {
534 INFO("lease_callback: reached with pending updates on host " PRI_S_SRP ".", host->registered_name);
535 ioloop_add_wake_event(host->lease_wakeup, host, lease_callback, NULL, host->lease_interval * 1000);
536 host->lease_expiry = ioloop_timenow() + host->lease_interval * 1000;
537 return;
538 }
539
540 // De-link the host.
541 *p_hosts = host->next;
542
543 // Get rid of any transactions attached to the host, any timer events, and any other associated data.
544 host_finalize(host);
545 }
546
547 static void
548 update_finished(adv_update_t *update)
549 {
550 adv_host_t *host = update->host;
551 client_update_t *client = update->client;
552 int num_addresses = 0;
553 adv_address_t **addresses = NULL;
554 int num_instances = 0;
555 adv_instance_vec_t *instances = NULL;
556 int i, j;
557 int num_host_addresses = 0;
558 int num_add_addresses = 0;
559 int num_host_instances = 0;
560 int num_add_instances = 0;
561 uint8_t *rdata;
562 adv_update_t **p_update;
563
564 // Reset the retry interval, since we succeeded in updating.
565 host->retry_interval = 0;
566
567 // Once an update has finished, we need to apply all of the proposed changes to the host object.
568 if (host->addresses != NULL) {
569 for (i = 0; i < host->num_addresses; i++) {
570 if (host->addresses[i] != NULL &&
571 (update->remove_addresses == NULL || update->remove_addresses[i] == NULL))
572 {
573 num_host_addresses++;
574 }
575 }
576 }
577
578 if (update->add_addresses != NULL) {
579 for (i = 0; i < update->num_add_addresses; i++) {
580 if (update->add_addresses[i] != NULL) {
581 num_add_addresses++;
582 }
583 }
584 }
585
586 num_addresses = num_host_addresses + num_add_addresses;
587 if (num_addresses > 0) {
588 addresses = calloc(num_addresses, sizeof *addresses);
589 if (addresses == NULL) {
590 update_failed(update, dns_rcode_servfail, true);
591 return;
592 }
593
594 j = 0;
595 addresses[j] = update->selected_addr;
596 RETAIN_HERE(addresses[j]);
597 j++;
598
599 rdata = update->selected_addr->rdata;
600 SEGMENTED_IPv6_ADDR_GEN_SRP(rdata, rdata_buf);
601 INFO("update_finished: selected " PRI_SEGMENTED_IPv6_ADDR_SRP " on host " PRI_S_SRP,
602 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdata, rdata_buf), host->registered_name);
603
604 if (host->addresses != NULL) {
605 for (i = 0; i < host->num_addresses; i++) {
606 if (host->addresses[i] != NULL && host->addresses[i] != update->selected_addr &&
607 (update->remove_addresses == NULL || update->remove_addresses[i] == NULL))
608 {
609 #ifdef DEBUG_VERBOSE
610 uint8_t *rdp = host->addresses[i]->rdata;
611 SEGMENTED_IPv6_ADDR_GEN_SRP(rdp, rdp_buf);
612 INFO("update_finished: retaining " PRI_SEGMENTED_IPv6_ADDR_SRP "on host " PRI_S_SRP,
613 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdp, rdp_buf), host->registered_name);
614 #endif
615 addresses[j] = host->addresses[i];
616 RETAIN_HERE(addresses[j]);
617 j++;
618 }
619 }
620 }
621 if (update->add_addresses != NULL) {
622 for (i = 0; i < update->num_add_addresses; i++) {
623 if (update->add_addresses[i] != NULL) {
624 if (update->add_addresses[i] != update->selected_addr) {
625 #ifdef DEBUG_VERBOSE
626 uint8_t *rdp = update->add_addresses[i]->rdata;
627 SEGMENTED_IPv6_ADDR_GEN_SRP(rdp, rdp_buf);
628 INFO("update_finished: adding " PRI_SEGMENTED_IPv6_ADDR_SRP "to host " PRI_S_SRP,
629 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdp, rdp_buf), host->registered_name);
630 #endif
631 addresses[j] = update->add_addresses[i];
632 RETAIN_HERE(addresses[j]);
633 j++;
634 }
635 RELEASE_HERE(update->add_addresses[i], adv_address_finalize);
636 update->add_addresses[i] = NULL;
637 }
638 }
639 }
640 if (update->selected_addr != NULL) {
641 RELEASE_HERE(update->selected_addr, adv_address_finalize);
642 update->selected_addr = NULL;
643 }
644 }
645
646 // Do the same for instances.
647 for (i = 0; i < host->instances->num; i++) {
648 if (host->instances->vec[i] != NULL &&
649 (update->remove_instances == NULL || update->remove_instances->vec[i] == NULL))
650 {
651 num_host_instances++;
652 }
653 }
654
655 if (update->add_instances != NULL) {
656 for (i = 0; i < update->add_instances->num; i++) {
657 if (update->add_instances->vec[i] != NULL) {
658 num_add_instances++;
659 }
660 }
661 }
662
663 num_instances = num_add_instances + num_host_instances;
664 instances = adv_instance_vec_create(num_instances);
665 if (instances == NULL) {
666 if (addresses != NULL) {
667 for (i = 0; i < num_addresses; i++) {
668 if (addresses[i] != NULL) {
669 RELEASE_HERE(addresses[i], adv_address_finalize);
670 }
671 }
672 free(addresses);
673 }
674 update_failed(update, dns_rcode_servfail, true);
675 return;
676 }
677 instances->num = num_instances;
678
679 j = 0;
680 for (i = 0; i < host->instances->num; i++) {
681 if (update->remove_instances != NULL && update->remove_instances->vec[i] == NULL) {
682 if (update->update_instances->vec[i] != NULL) {
683 adv_instance_t *instance = update->update_instances->vec[i];
684 INFO("update_finished: updated instance " PRI_S_SRP " " PRI_S_SRP " %d",
685 instance->instance_name, instance->service_type, instance->port);
686 // Implicit RETAIN/RELEASE
687 instances->vec[j] = instance;
688 update->update_instances->vec[i] = NULL;
689 } else {
690 if (host->instances->vec[i] != NULL) {
691 adv_instance_t *instance = host->instances->vec[i];
692 INFO("update_finished: retained instance " PRI_S_SRP " " PRI_S_SRP " %d",
693 instance->instance_name, instance->service_type, instance->port);
694 instances->vec[j++] = instance;
695 RETAIN_HERE(instance);
696 }
697 }
698 }
699 }
700 if (update->add_instances != NULL) {
701 for (i = 0; i < update->add_instances->num; i++) {
702 adv_instance_t *instance = update->add_instances->vec[i];
703 if (instance != NULL) {
704 INFO("update_finished: added instance " PRI_S_SRP " " PRI_S_SRP " %d",
705 instance->instance_name, instance->service_type, instance->port);
706 // Implicit RETAIN/RELEASE
707 instances->vec[j++] = instance;
708 update->add_instances->vec[i] = NULL;
709 }
710 }
711 }
712
713 // At this point we can safely modify the host object because we aren't doing any more
714 // allocations.
715 host_addr_free(host);
716 RELEASE_HERE(host->instances, adv_instance_vec_finalize);
717
718 host->addresses = addresses;
719 host->num_addresses = num_addresses;
720 host->instances = instances;
721
722 if (client) {
723 advertise_finished(client->connection, client->message, dns_rcode_noerror, client);
724 client_finalize(client);
725 update->client = NULL;
726 }
727
728 // The update should still be on the host.
729 for (p_update = &host->updates; *p_update != NULL; p_update = &(*p_update)->next) {
730 if (*p_update == update) {
731 break;
732 }
733 }
734
735 if (*p_update == NULL) {
736 ERROR("update_finished: p_update is null.");
737 } else {
738 *p_update = update->next;
739 }
740
741 // If we have another prepared update to do, apply it first.
742 if (host->updates) {
743 start_host_update(host);
744 goto out;
745 }
746
747 // If we have an update that hasn't yet been prepared, prepare it and apply it.
748 if (host->clients) {
749 prepare_update(host);
750 goto out;
751 }
752
753 // If we got a late name conflict while processing the previous update, try to get a new hostname.
754 // We won't get here if the update caused the host to be reregistered--in that case we will either
755 // return a failure to the client and delete the host, or else we'll have resolved the conflict.
756 if (host->hostname_update_pending) {
757 try_new_hostname(host);
758 }
759
760 // Otherwise, there's no work left to do, so just wait until the lease expires.
761 host->lease_interval = update->host_lease;
762 host->key_lease = update->key_lease;
763
764 if (update->lease_expiry != 0) {
765 uint64_t now = ioloop_timenow();
766 if (update->lease_expiry < now) {
767 ERROR("update_finished: lease expiry for host %s happened %" PRIu64 " milliseconds ago.",
768 host->registered_name, now - update->lease_expiry);
769 // Expire the lease in 1000 ms.
770 ioloop_add_wake_event(host->lease_wakeup, host, lease_callback, NULL, 1000);
771 } else {
772 uint64_t when = update->lease_expiry - now;
773 if (when > INT32_MAX) {
774 when = INT32_MAX;
775 }
776 ioloop_add_wake_event(host->lease_wakeup, host, lease_callback, NULL, (uint32_t)when);
777 host->lease_expiry = update->lease_expiry;
778 }
779 } else {
780 ioloop_add_wake_event(host->lease_wakeup, host, lease_callback, NULL, host->lease_interval * 1000);
781 host->lease_expiry = ioloop_timenow() + host->lease_interval * 1000;
782 }
783 out:
784 update_finalize(update);
785 }
786
787 // When the host registration has completed, we get this callback. Completion either means that we succeeded in
788 // registering the record, or that something went wrong and the registration has failed.
789 static void
790 register_instance_completion(DNSServiceRef sdref, DNSServiceFlags flags, DNSServiceErrorType error_code,
791 const char *name, const char *regtype, const char *domain, void *context)
792 {
793 (void)flags;
794 (void)sdref;
795 (void)name;
796 (void)regtype;
797 adv_instance_t *instance = context;
798 adv_update_t *update = instance->update;
799 adv_host_t *host = instance->host;
800
801 // It's possible that we could restart a host update due to an error while a callback is still pending on a stale
802 // update. In this case, we just cancel all of the work that's been done on the stale update (it's probably already
803 // moot anyway.
804 if (update != NULL && host->updates != update) {
805 INFO("register_instance_completion: registration for service " PRI_S_SRP "." PRI_S_SRP
806 " completed with invalid state.", name, regtype);
807 update_finalize(update);
808 return;
809 }
810
811 // We will generally get a callback on success or failure of the initial registration; this is what causes
812 // the update to complete or fail. We may get subsequent callbacks because of name conflicts. So the first
813 // time we get a callback, instance->update will always be valid; thereafter, it will not, so null it out.
814 instance->update = NULL;
815
816 if (error_code == kDNSServiceErr_NoError) {
817 INFO("register_instance_completion: registration for service " PRI_S_SRP "." PRI_S_SRP "." PRI_S_SRP " -> "
818 PRI_S_SRP " has completed.", instance->instance_name, instance->service_type, domain,
819 host->registered_name);
820 INFO("register_instance_completion: registration is under " PRI_S_SRP "." PRI_S_SRP PRI_S_SRP, name, regtype,
821 domain);
822
823 // In principle update->instance should always be non-NULL here because a no-error response should
824 // only happen once or not at all. But just to be safe...
825 if (update != NULL) {
826 update->num_instances_completed++;
827 if (update->num_instances_completed == update->num_instances_started) {
828 // We have successfully advertised the service.
829 update_finished(update);
830 }
831 } else {
832 ERROR("register_instance_completion: no error, but update is NULL for instance " PRI_S_SRP " (" PRI_S_SRP
833 " " PRI_S_SRP " " PRI_S_SRP ")", instance->instance_name, name, regtype, domain);
834 }
835 } else {
836 INFO("register_instance_completion: registration for service " PRI_S_SRP "." PRI_S_SRP "." PRI_S_SRP " -> "
837 PRI_S_SRP " failed with code %d", instance->instance_name, instance->service_type, domain,
838 host->registered_name, error_code);
839
840 // If this is the immediate result of a registration, we can inform the SRP client that it failed.
841 if (update != NULL) {
842 // At present we will never get this error because mDNSResponder will just choose a new name.
843 if (error_code == kDNSServiceErr_NameConflict) {
844 update_failed(update, dns_rcode_yxdomain, true);
845 } else {
846 update_failed(update, dns_rcode_servfail, true);
847 }
848 } else {
849 ERROR("Late failure for instance " PRI_S_SRP "--can't update client.", instance->instance_name);
850 }
851
852 if (error_code == kDNSServiceErr_ServiceNotRunning || error_code == kDNSServiceErr_DefunctConnection) {
853 service_disconnected(host);
854 }
855 }
856 }
857
858 static void
859 extract_instance_name(char *instance_name, int instance_name_max,
860 char *service_name, int service_name_max, service_instance_t *instance)
861 {
862 dns_name_t *end_of_service_name = instance->service->rr->name->next;
863 if (end_of_service_name != NULL) {
864 if (end_of_service_name->next != NULL) {
865 end_of_service_name = end_of_service_name->next;
866 }
867 }
868 dns_name_print_to_limit(instance->service->rr->name, end_of_service_name, service_name, service_name_max);
869
870 // Make a presentation-format version of the service instance name.
871 dns_name_print_to_limit(instance->name, instance->name != NULL ? instance->name->next : NULL,
872 instance_name, instance_name_max);
873 }
874
875 static bool
876 register_instance(adv_instance_t *instance)
877 {
878 int err;
879 DNSServiceRef sdref;
880
881 INFO("DNSServiceRegister(" PRI_S_SRP ", " PRI_S_SRP ", " PRI_S_SRP ", %d)",
882 instance->instance_name, instance->service_type, instance->host->registered_name, instance->port);
883 err = DNSServiceRegister(&sdref, kDNSServiceFlagsUnique, advertise_interface,
884 instance->instance_name, instance->service_type, local_suffix,
885 instance->host->registered_name, htons(instance->port), instance->txt_length,
886 instance->txt_data, register_instance_completion, instance);
887 // This would happen if we pass NULL for regtype, which we don't, or if we run out of memory, or if
888 // the server isn't running; in the second two cases, we can always try again later.
889 if (err != kDNSServiceErr_NoError) {
890 // If we can, always send status to the client.
891 if (instance->update != NULL) {
892 if (instance->update->client == NULL &&
893 (err == kDNSServiceErr_ServiceNotRunning || err == kDNSServiceErr_DefunctConnection))
894 {
895 INFO("DNSServiceRegister failed: " PUB_S_SRP ,
896 err == kDNSServiceErr_ServiceNotRunning ? "not running" : "defunct");
897 service_disconnected(instance->host);
898 } else {
899 INFO("DNSServiceRegister failed: %d", err);
900 update_failed(instance->update, dns_rcode_servfail, true);
901 }
902 }
903 return false;
904 }
905 instance->txn = ioloop_dnssd_txn_add(sdref, instance, instance_txn_finalize_callback);
906 if (instance->txn == NULL) {
907 ERROR("register_instance: no memory.");
908 DNSServiceRefDeallocate(sdref);
909 return false;
910 }
911 if (instance->update != NULL) {
912 instance->update->num_instances_started++;
913 }
914 return true;
915 }
916
917 #ifdef UNUSED
918 // When an update fails on some record, abandon_update is called to stop advertising the other records
919 // that were proposed in the update. The state associated with the update is then freed. The caller is
920 // responsible for sending the result back to the SRP client. If anything was deleted by the update, it's
921 // also abandoned, which is somewhat problematic.
922 static void
923 abandon_update(adv_host_t *host)
924 {
925 (void)host;
926 }
927
928 // When a registration that's been successfully added in the past is attempted, and fails in a way
929 // that indicates a conflict or unrecoverable error, we have to abandon it. abandon_registration
930 // takes care of that.
931 static void
932 abandon_registration(adv_host_t *host)
933 {
934 (void)host;
935 }
936 #endif
937
938 static void
939 start_service_updates(adv_host_t *host)
940 {
941 int i;
942 adv_update_t *update = host->updates;
943
944 if (update == NULL) {
945 ERROR("start_service_updates: no work to do.");
946 return;
947 }
948
949 // For each service instance that's being added, register it.
950 for (i = 0; i < update->add_instances->num; i++) {
951 if (update->add_instances->vec[i] != NULL) {
952 if (!register_instance(update->add_instances->vec[i])) {
953 return;
954 }
955 }
956 }
957 // For each service instance that's being updated or deleted, delete it.
958 if (update->update_instances->num != host->instances->num) {
959 ERROR("start_service_updates: update instance count %d differs from host instance count %d",
960 update->update_instances->num, host->instances->num);
961 update_failed(update, dns_rcode_servfail, true);
962 return;
963 }
964 if (update->remove_instances->num != host->instances->num) {
965 ERROR("start_service_updates: delete instance count %d differs from host instance count %d",
966 update->remove_instances->num, host->instances->num);
967 update_failed(update, dns_rcode_servfail, true);
968 return;
969 }
970 for (i = 0; i < host->instances->num; i++) {
971 if (update->update_instances->vec[i] != NULL || update->remove_instances->vec[i] != NULL) {
972 if (host->instances->vec[i]->txn != NULL) {
973 ioloop_dnssd_txn_release(host->instances->vec[i]->txn);
974 host->instances->vec[i]->txn = NULL;
975 }
976 }
977 if (update->update_instances->vec[i] != NULL) {
978 if (!register_instance(update->update_instances->vec[i])) {
979 INFO("start_service_update: register instance failed.");
980 return;
981 }
982 }
983 }
984 if (update->num_instances_started == 0) {
985 INFO("start_service_update: no service updates, so we're finished.");
986 update_finished(update);
987 }
988 }
989
990 // When we get a late name conflict on the hostname, we need to update the host registration and all of the
991 // service registrations. To do this, we construct an update and then apply it. If there is already an update
992 // in progress, we put this update at the end of the list.
993 static void
994 update_from_host(adv_host_t *host)
995 {
996 adv_update_t *update = NULL;
997 int i;
998
999 // Allocate the update structure.
1000 update = calloc(1, sizeof *update);
1001 if (update == NULL) {
1002 ERROR("update_from_host: no memory for update.");
1003 goto fail;
1004 }
1005
1006 update->add_addresses = calloc(host->num_addresses, sizeof (*update->add_addresses));
1007 if (update->add_addresses == NULL) {
1008 ERROR("update_from_host: no memory for addresses");
1009 goto fail;
1010 }
1011 update->num_add_addresses = 0;
1012
1013 // Copy all of the addresses in the host into add_addresses
1014 for (i = 0; i < host->num_addresses; i++) {
1015 if (host->addresses[i] != NULL) {
1016 update->add_addresses[update->num_add_addresses] = host->addresses[i];
1017 RETAIN_HERE(update->add_addresses[update->num_add_addresses]);
1018 update->num_add_addresses++;
1019 }
1020 }
1021
1022 // We can never update more instances than currently exist for this host.
1023 update->update_instances = adv_instance_vec_copy(host->instances);
1024 for (i = 0; i < update->update_instances->num; i++) {
1025 if (update->update_instances->vec[i] != NULL) {
1026 update->update_instances->vec[i]->update = update;
1027 }
1028 }
1029
1030 // We aren't actually adding or deleting any instances, but...
1031 update->remove_instances = adv_instance_vec_create(host->instances->num);
1032 if (update->remove_instances == NULL) {
1033 ERROR("update_from_host: no memory for remove_instances");
1034 goto fail;
1035 }
1036 update->remove_instances->num = host->instances->num;
1037
1038 update->add_instances = adv_instance_vec_create(host->instances->num);
1039 if (update->add_instances == NULL) {
1040 ERROR("update_from_host: no memory for add_instances");
1041 goto fail;
1042 }
1043 update->add_instances->num = host->instances->num;
1044
1045 // At this point we have figured out all the work we need to do, so hang it off an update structure.
1046 update->host = host;
1047 update->num_remove_addresses = 0;
1048 update->num_add_addresses = host->num_addresses;
1049 update->host_lease = host->lease_interval;
1050 update->key_lease = host->key_lease;
1051 update->lease_expiry = host->lease_expiry;
1052
1053 // The only time we can expect this to happen is as a result of a retry, in which case we want to
1054 // get the host back to its correct state before continuing.
1055 update->next = host->updates;
1056 host->updates = update;
1057 start_host_update(host);
1058 return;
1059
1060 fail:
1061 update_finalize(update);
1062 wait_retry(host);
1063 return;
1064 }
1065
1066 // If we get a name conflict, we need to choose a new name for the host.
1067 static void
1068 try_new_hostname(adv_host_t *host)
1069 {
1070 char *s, *t;
1071 char separator = '-';
1072 char namebuf[DNS_MAX_LABEL_SIZE_ESCAPED];
1073
1074 t = namebuf;
1075 for (s = host->name; *s; s++) {
1076 if (*s == '.') {
1077 *t = 0;
1078 break;
1079 }
1080 if (t - namebuf >= DNS_MAX_LABEL_SIZE_ESCAPED - 13) { // 13: "-12345.local\0"
1081 *t = 0;
1082 ERROR("try_new_hostname: truncating " PRI_S_SRP " to " PRI_S_SRP, host->name, namebuf);
1083 break;
1084 }
1085 if (*s == '\\') {
1086 if (s[1] == 0 || s[2] == 0 || s[3] == 0) {
1087 ERROR("try_new_hostname: escaped hostname " PRI_S_SRP " is invalid", host->name);
1088 *t = 0;
1089 break;
1090 }
1091 *t++ = *s++;
1092 *t++ = *s++;
1093 *t++ = *s++;
1094 *t++ = *s;
1095 continue;
1096 }
1097 if (*s == ' ' || *s == '-' || *s == '_') {
1098 separator = *s;
1099 }
1100 *t++ = *s;
1101 }
1102 INFO("try_new_hostname: using base name %s", namebuf);
1103 // Append a random number to the end of the name.
1104 host->name_serial = srp_random16();
1105 snprintf(t, 13, "-%d.local", host->name_serial);
1106 INFO("try_new_hostname: using full name %s", namebuf);
1107
1108 if (host->registered_name != host->name) {
1109 free(host->registered_name);
1110 }
1111 host->registered_name = strdup(namebuf);
1112 if (host->registered_name == NULL) {
1113 ERROR("try_new_hostname: No memory for alternative name for " PRI_S_SRP ": " PRI_S_SRP, host->name, namebuf);
1114 // We pretty much can't do anything at this point.
1115 lease_callback(host);
1116 return;
1117 }
1118
1119 // Generate an update from the host entry and do it.
1120 update_from_host(host);
1121 }
1122
1123 // When the host registration has completed, we get this callback. Completion either means that we succeeded in
1124 // registering the record, or that something went wrong and the registration has failed.
1125 static void
1126 register_host_completion(DNSServiceRef sdref, DNSRecordRef rref,
1127 DNSServiceFlags flags, DNSServiceErrorType error_code, void *context)
1128 {
1129 dnssd_txn_t *txn = context;
1130 adv_update_t *update = ioloop_dnssd_txn_get_aux_pointer(txn);
1131 adv_host_t *host = ioloop_dnssd_txn_get_context(txn);
1132 (void)sdref;
1133 (void)rref;
1134 (void)error_code;
1135 (void)flags;
1136
1137 // It's possible that we could restart a host update due to an error while a callback is still pending on a stale
1138 // update. In this case, we just cancel all of the work that's been done on the stale update (it's probably already
1139 // moot anyway.
1140 if (update != NULL && (host == NULL || host->updates != update)) {
1141 INFO("register_host_completion: registration for host completed with invalid state.");
1142 update_finalize(update);
1143 return;
1144 }
1145
1146 if (host == NULL) {
1147 ERROR("register_host_completion called on null host.");
1148 return;
1149 }
1150
1151 if (error_code == kDNSServiceErr_NoError) {
1152 // If we get here while a hostname update is pending, it means that the conflict was resolved when
1153 // we re-registered the host as a side effect of the update, so we no longer need to update the
1154 // hostname.
1155 host->hostname_update_pending = false;
1156
1157 // Now that the hostname has been registered, we can register services that point at it.
1158 INFO("register_host_completion: registration for host " PRI_S_SRP " has completed.", host->registered_name);
1159 start_service_updates(host);
1160 } else {
1161 INFO("register_host_completion: registration for host " PRI_S_SRP " failed, status = %d", host->registered_name,
1162 error_code);
1163 if (update == NULL) {
1164 // We shouldn't get any error here other than a name conflict or daemon not running.
1165 // If we get a name conflict, that means that some other BR or host on the network has
1166 // started advertising the hostname we chose, so we need to choose a new name and fix
1167 // all of the service registrations.
1168 if (error_code == kDNSServiceErr_NameConflict) {
1169 if (host->updates != NULL || host->clients != NULL) {
1170 host->hostname_update_pending = true;
1171 } else {
1172 try_new_hostname(host);
1173 }
1174 }
1175 } else {
1176 if (error_code == kDNSServiceErr_NameConflict) {
1177 update_failed(update, dns_rcode_yxdomain, true);
1178 } else {
1179 update_failed(update, dns_rcode_servfail, true);
1180 }
1181 }
1182 }
1183 }
1184
1185 static adv_instance_t *
1186 adv_instance_create(service_instance_t *raw, adv_host_t *host, adv_update_t *update)
1187 {
1188 char service_type[DNS_MAX_LABEL_SIZE_ESCAPED * 2 + 2]; // sizeof '.' + sizeof '\0'.
1189 char instance_name[DNS_MAX_NAME_SIZE_ESCAPED + 1];
1190 char *txt_data;
1191
1192 // Allocate the raw registration
1193 adv_instance_t *instance = calloc(1, sizeof *instance);
1194 if (instance == NULL) {
1195 ERROR("adv_instance:create: unable to allocate raw registration struct.");
1196 return NULL;
1197 }
1198 RETAIN_HERE(instance);
1199 instance->host = host;
1200 instance->update = update;
1201 // SRV records have priority, weight and port, but DNSServiceRegister only uses port.
1202 instance->port = (raw->srv == NULL) ? 0 : raw->srv->data.srv.port;
1203
1204 // Make a presentation-format version of the service name.
1205 extract_instance_name(instance_name, sizeof instance_name, service_type, sizeof service_type, raw);
1206 instance->instance_name = strdup(instance_name);
1207 if (instance->instance_name == NULL) {
1208 ERROR("adv_instance:create: unable to allocate instance name.");
1209 RELEASE_HERE(instance, adv_instance_finalize);
1210 return NULL;
1211 }
1212 instance->service_type = strdup(service_type);
1213 if (instance->service_type == NULL) {
1214 ERROR("adv_instance:create: unable to allocate instance type.");
1215 RELEASE_HERE(instance, adv_instance_finalize);
1216 return NULL;
1217 }
1218
1219 // Allocate the text record buffer
1220 if (raw->txt != NULL) {
1221 txt_data = malloc(raw->txt->data.txt.len);
1222 if (txt_data == NULL) {
1223 RELEASE_HERE(instance, adv_instance_finalize);
1224 ERROR("adv_instance:create: unable to allocate txt_data buffer");
1225 return NULL;
1226 }
1227 // Format the txt buffer as required by DNSServiceRegister().
1228 memcpy(txt_data, raw->txt->data.txt.data, raw->txt->data.txt.len);
1229 instance->txt_data = txt_data;
1230 instance->txt_length = raw->txt->data.txt.len;
1231 } else {
1232 instance->txt_data = NULL;
1233 instance->txt_length = 0;
1234 }
1235 return instance;
1236 }
1237
1238 #define adv_address_create(addr, host) \
1239 adv_address_create_(addr, host, __FILE__, __LINE__)
1240 static adv_address_t *
1241 adv_address_create_(host_addr_t *addr, adv_host_t *host, const char *file, int line)
1242 {
1243
1244 adv_address_t *new_addr = calloc(1, sizeof *new_addr);
1245 if (new_addr == NULL) {
1246 ERROR("adv_address_create: no memory for new_addr");
1247 return NULL;
1248 }
1249 new_addr->host = host;
1250 new_addr->rrtype = addr->rr.type;
1251 new_addr->rdlen = addr->rr.type == dns_rrtype_a ? 4 : 16;
1252 memcpy(new_addr->rdata, &addr->rr.data, new_addr->rdlen);
1253 RETAIN(new_addr);
1254 return new_addr;
1255 }
1256
1257 // When we need to register a host with mDNSResponder, start_host_update is called. This can be either because
1258 // we just got a new registration for a host, or if the daemon dies and we need to re-do the host registration.
1259 // This just registers the host; if that succeeds, then we register the service instances.
1260 static void
1261 start_host_update(adv_host_t *host)
1262 {
1263 adv_update_t *update = host->updates;
1264 int err;
1265 bool remove_preexisting;
1266 uint8_t *add_rdata;
1267 uint16_t add_rrtype;
1268 uint16_t add_rdlen;
1269 adv_address_t *selected_addr = NULL, *preferred_addr = NULL;
1270 int i;
1271 adv_address_t *addr;
1272
1273 // No work to do?
1274 if (host->updates == NULL) {
1275 ERROR("start_host_update: no work to do for host " PRI_S_SRP, host->registered_name);
1276 return;
1277 }
1278
1279 // If we haven't published an address yet, or if we are going to remove the currently published address,
1280 // or if we have new addresses to add, then choose the address that is best suited, preferring recently
1281 // added addresses over existing addresses.
1282 remove_preexisting = false;
1283 add_rdata = NULL;
1284 add_rrtype = 0;
1285 add_rdlen = 0;
1286
1287 // If the host address isn't about to be removed, and is an IPv6 address on the preferred prefix,
1288 // store it in preferred_addr for comparison and possible retention.
1289 if (preferred_prefix != NULL &&
1290 host->num_addresses > 0 && host->addresses[0] != NULL &&
1291 update->remove_addresses != NULL && update->remove_addresses[0] == NULL &&
1292 host->addresses[0]->rrtype == dns_rrtype_aaaa &&
1293 same_prefix(host->addresses[0]->rdata, &preferred_prefix->addr, preferred_prefix->width))
1294 {
1295 preferred_addr = host->addresses[0];
1296 }
1297
1298 if ((host->num_addresses != 0 && update->remove_addresses != NULL && update->remove_addresses[0] != NULL) ||
1299 update->num_add_addresses != 0)
1300 {
1301 if (preferred_prefix != NULL) {
1302 for (i = 0; i < update->num_add_addresses; i++) {
1303 addr = update->add_addresses[i];
1304 if (// there is an address
1305 addr != NULL && addr->rrtype == dns_rrtype_aaaa &&
1306 // it's on the preferred prefix
1307 same_prefix(addr->rdata, &preferred_prefix->addr, preferred_prefix->width))
1308 {
1309 // If this address is the same as the currently selected address, we don't need
1310 // to add it. Preferred_addr is always a AAAA.
1311 if (preferred_addr != NULL && preferred_addr->rrtype == dns_rrtype_aaaa &&
1312 !memcmp(addr->rdata, preferred_addr->rdata, 16))
1313 {
1314 selected_addr = preferred_addr;
1315 }
1316 // But if the current address is not preferred, or there isn't one, then choose this
1317 // address. If there's more than one address in the preferred prefix, we choose the first
1318 // one we come to. SRP client should not be sending temporary addresses or deprecated addresses.
1319 else {
1320 selected_addr = addr;
1321 remove_preexisting = true;
1322 break;
1323 }
1324 }
1325 }
1326 }
1327 }
1328
1329 // If none of the new addresses were different than the current address and in the preferred prefix,
1330 // keep the current address.
1331 if (selected_addr == NULL &&
1332 host->num_addresses > 0 && host->addresses[0] != NULL &&
1333 update->remove_addresses != NULL && update->remove_addresses[0] == NULL)
1334 {
1335 selected_addr = host->addresses[0];
1336 remove_preexisting = false;
1337 update->registering_key = false;
1338 }
1339
1340 // If the current address is being removed, and we don't have a new address in the preferred
1341 // prefix, just use the first address in the add list.
1342 if (selected_addr == NULL) {
1343 for (i = 0; i < update->num_add_addresses; i++) {
1344 if (update->add_addresses[i] != NULL) {
1345 selected_addr = update->add_addresses[i];
1346 remove_preexisting = true;
1347 break;
1348 }
1349 }
1350 // If there's no new address, see if there's an old address we didn't use before.
1351 if (selected_addr == NULL) {
1352 for (i = 1; i < host->num_addresses; i++) {
1353 addr = host->addresses[i];
1354 if (addr != NULL)
1355 {
1356 selected_addr = addr;
1357 remove_preexisting = true;
1358 break;
1359 }
1360 }
1361 }
1362 }
1363
1364 // If we didn't find an address, we're just deleting the address.
1365 if (selected_addr == NULL) {
1366 INFO("start_host_update: No address was selected.");
1367 remove_preexisting = true;
1368 add_rdata = host->key_rdata;
1369 add_rrtype = dns_rrtype_key;
1370 add_rdlen = host->key_rdlen;
1371 update->registering_key = true;
1372 } else {
1373 // We don't need to update the host address if it didn't change.
1374 if (remove_preexisting) {
1375 if (host->num_addresses > 0) {
1376 INFO("start_host_update: Replacing existing address %p.", selected_addr);
1377 } else {
1378 INFO("start_host_update: Adding new address %p.", selected_addr);
1379 }
1380 add_rdata = selected_addr->rdata;
1381 add_rrtype = selected_addr->rrtype;
1382 add_rdlen = selected_addr->rdlen;
1383 } else {
1384 INFO("start_host_update: Retaining existing address.");
1385 }
1386 update->registering_key = false;
1387 if (update->selected_addr != NULL) {
1388 RELEASE_HERE(update->selected_addr, adv_address_finalize);
1389 }
1390 update->selected_addr = selected_addr;
1391 RETAIN_HERE(update->selected_addr);
1392 }
1393 INFO("update->selected_addr = %p", update->selected_addr);
1394
1395 // At present, the DNSService* API doesn't provide a clean way to update a record registered with
1396 // DNSServiceRegisterRecord, because it assumes that you'd only ever want to update it with a record
1397 // of the same type. We can't use that, so we just remove the record (if it exists) and then add
1398 // the intended record.
1399 if (remove_preexisting && host->txn != NULL) {
1400 ioloop_dnssd_txn_release(host->txn);
1401 host->txn = NULL;
1402 }
1403
1404 // If we don't think we have a connection, make one.
1405 if (host->txn == NULL) {
1406 DNSServiceRef sdref;
1407 err = DNSServiceCreateConnection(&sdref);
1408 // In principle the only way this can fail is if the daemon isn't running.
1409 if (err != kDNSServiceErr_NoError) {
1410 // If this is a new update, just send a response to the client. Otherwise maybe try to re-add it.
1411 if (update->client != NULL) {
1412 ERROR("DNSServiceCreateConnection: something went wrong: %d.", err);
1413 update_failed(update, dns_rcode_servfail, true);
1414 } else if (err == kDNSServiceErr_DefunctConnection || err == kDNSServiceErr_ServiceNotRunning) {
1415 ERROR("DNSServiceCreateConnection: " PUB_S_SRP ".",
1416 err == kDNSServiceErr_DefunctConnection ? "defunct connection" : "service not running");
1417 service_disconnected(host);
1418 } else if (err != kDNSServiceErr_NoError) {
1419 ERROR("DNSServiceCreateConnection: something went wrong: %d.", err);
1420 wait_retry(host);
1421 }
1422 return;
1423 }
1424 INFO("Adding transaction %p", sdref);
1425 host->txn = ioloop_dnssd_txn_add(sdref, host, host_txn_finalize_callback);
1426 if (host->txn == NULL) {
1427 ERROR("start_host_update: no memory for host transaction");
1428 if (update->client != NULL) {
1429 update_failed(update, dns_rcode_servfail, true);
1430 } else {
1431 wait_retry(host);
1432 }
1433 return;
1434 }
1435 }
1436
1437 if (add_rdata != NULL) {
1438 INFO("start_host_update: DNSServiceRegisterRecord(%p %p %d %d %p %d %d %d %p %d %p %p)",
1439 host ? (host->txn ? host->txn->sdref : 0) : 0, host ? &host->rref : 0,
1440 kDNSServiceFlagsUnique | kDNSServiceFlagsNoAutoRename,
1441 advertise_interface, host ? host->registered_name : 0,
1442 add_rrtype, dns_qclass_in, add_rdlen, add_rdata, 3600,
1443 register_host_completion, host ? host->txn : 0);
1444 ioloop_dnssd_txn_set_aux_pointer(host->txn, update);
1445 err = DNSServiceRegisterRecord(host->txn->sdref, &host->rref,
1446 kDNSServiceFlagsUnique | kDNSServiceFlagsNoAutoRename,
1447 advertise_interface, host->registered_name,
1448 add_rrtype, dns_qclass_in, add_rdlen, add_rdata, 3600,
1449 register_host_completion, host->txn);
1450 if (err != kDNSServiceErr_NoError) {
1451 ERROR("start_host_update: DNSServiceRegisterRecord failed on host: %d", err);
1452 if (update->client != NULL) {
1453 update_failed(update, dns_rcode_servfail, true);
1454 return;
1455 } else if (err == kDNSServiceErr_DefunctConnection || err == kDNSServiceErr_ServiceNotRunning) {
1456 service_disconnected(host);
1457 return;
1458 }
1459 }
1460 }
1461 // If we didn't have to do an add, start the service updates immediately.
1462 else {
1463 INFO("start_host_update: no host address rdata, so no host update");
1464 start_service_updates(host);
1465 }
1466 return;
1467 }
1468
1469 // When a host has no update in progress, and there is a client update ready to process, we need to analyze
1470 // the client update to see what work needs to be done. This work is constructed as an translation from the
1471 // raw update sent by the client (host->clients) into a prepared update that can be used directly to
1472 // register the information with mDNSResponder.
1473 //
1474 // Normally a host will only have one prepared update in progress; however, if we lose our connection to
1475 // mDNSResponder, then we need to re-create the host advertisement. If there was an update in progress when
1476 // this happened, we then need to reapply that as well. In this case an update is constructed from the host, to
1477 // get the host into the intended state, and the in-progress update is pushed below that; when the host has
1478 // been re-created on the daemon, the pending update is popped back off the stack and restarted.
1479 static void
1480 prepare_update(adv_host_t *host)
1481 {
1482 host_addr_t *addr;
1483 int i, j;
1484 service_instance_t *instance;
1485 adv_address_t **remove_addrs = NULL;
1486 int num_remove_addrs = 0;
1487 adv_address_t **add_addrs = NULL;
1488 int num_add_addrs = 0;
1489 int num_update_instances = 0;
1490 int num_add_instances = 0;
1491 int num_remove_instances = 0;
1492 adv_instance_vec_t *update_instances = NULL, *add_instances = NULL, *remove_instances = NULL;
1493 client_update_t *client_update = host->clients;
1494 adv_update_t *update = NULL;
1495
1496 // Work to do:
1497 // - Figure out what address records to add and what address records to delete.
1498 // - Because we can only have one address record at a time currently, figure out which address record we want
1499 // - If we already have an address record published, and it's the same, do nothing
1500 // - else if we already have an address record published, and it's changed to a different address, do an update
1501 // - else if we have a new address record, publish it
1502 // - else publish the key to hold the name
1503 // - Go through the set of service instances, identifying deletes, changes and adds
1504 // - We don't currently allow deletes, but what that would look like would be an instance with no SRV or TXT
1505 // record.
1506 // - What about a delete that keeps the name but un-advertises the service? How would we indicate that?
1507 // Maybe if there's no service PTR for the service?
1508 // - Changes means that the contents of the text record changed, or the contents of the SRV record
1509 // changed (but not the hostname) or both.
1510 // - New means that we don't have a service with that service instance name on the host (and we previously
1511 // eliminated the possibility that it exists on some other host).
1512
1513 // Allocate the update structure.
1514 update = calloc(1, sizeof *update);
1515 if (update == NULL) {
1516 ERROR("prepare_update: no memory for update.");
1517 goto fail;
1518 }
1519
1520 // The maximum number of addresses we could be deleting is all the ones the host currently has.
1521 num_remove_addrs = host->num_addresses;
1522 if (num_remove_addrs != 0) {
1523 remove_addrs = calloc(num_remove_addrs, sizeof *remove_addrs);
1524 // If we can't allocate space, just wait a bit.
1525 if (remove_addrs == NULL) {
1526 ERROR("prepare_update: no memory for remove_addrs");
1527 goto fail;
1528 }
1529 } else {
1530 remove_addrs = NULL;
1531 }
1532
1533 num_add_addrs = 0;
1534 for (addr = client_update->host->addrs; addr != NULL; addr = addr->next) {
1535 num_add_addrs++;
1536 }
1537 add_addrs = calloc(num_add_addrs, sizeof *add_addrs);
1538 if (add_addrs == NULL) {
1539 ERROR("prepare_update: no memory for add_addrs");
1540 goto fail;
1541 }
1542
1543 // Copy all of the addresses in the update into add_addresses
1544 num_add_addrs = 0;
1545 for (addr = client_update->host->addrs; addr; addr = addr->next) {
1546 adv_address_t *prepared_address = adv_address_create(addr, host);
1547 if (prepared_address == NULL) {
1548 ERROR("prepare_update: No memory for prepared address");
1549 goto fail;
1550 }
1551 add_addrs[num_add_addrs++] = prepared_address;
1552 }
1553
1554 // For every host address, see if it's in add_addresses. If it's not, it needs to be removed.
1555 // If it is, it doesn't need to be added.
1556 if (num_remove_addrs != 0) {
1557 memcpy(remove_addrs, host->addresses, num_remove_addrs * sizeof *remove_addrs);
1558 for (i = 0; i < num_remove_addrs; i++) {
1559 if (host->addresses[i] != NULL) {
1560 remove_addrs[i] = host->addresses[i];
1561 RETAIN_HERE(remove_addrs[i]);
1562 }
1563 for (j = 0; j < num_add_addrs; j++) {
1564 // If the address is present in both places, remove it from the list of addresses to
1565 // add, and also remove it from the list of addresses to remove. When we're done,
1566 // all that will be remaining in the list to remove will be addresses that weren't present
1567 // in the add list.
1568 if (remove_addrs[i] != NULL && add_addrs[j] != NULL &&
1569 add_addrs[j]->rrtype == remove_addrs[i]->rrtype &&
1570 !memcmp(&add_addrs[j]->rdata, remove_addrs[i]->rdata, remove_addrs[i]->rdlen))
1571 {
1572 RELEASE_HERE(remove_addrs[i], adv_address_finalize);
1573 remove_addrs[i] = NULL;
1574 RELEASE_HERE(add_addrs[j], adv_address_finalize);
1575 add_addrs[j] = NULL;
1576 }
1577 }
1578 }
1579 }
1580
1581 // We can never update more instances than currently exist for this host.
1582 num_update_instances = host->instances->num;
1583 num_remove_instances = host->instances->num;
1584
1585 update_instances = adv_instance_vec_create(num_update_instances);
1586 if (update_instances == NULL) {
1587 ERROR("prepare_update: no memory for update_instances");
1588 goto fail;
1589 }
1590 update_instances->num = num_update_instances;
1591
1592 // We aren't actually deleting any instances, but...
1593 remove_instances = adv_instance_vec_create(num_remove_instances);
1594 if (remove_instances == NULL) {
1595 ERROR("prepare_update: no memory for remove_instances");
1596 goto fail;
1597 }
1598 remove_instances->num = num_remove_instances;
1599
1600 // The number of instances to add can be as many as there are instances in the update.
1601 num_add_instances = 0;
1602 for (instance = client_update->instances; instance; instance = instance->next) {
1603 num_add_instances++;
1604 }
1605 add_instances = adv_instance_vec_create(num_add_instances);
1606 if (add_instances == NULL) {
1607 ERROR("prepare_update: no memory for add_instances");
1608 goto fail;
1609 }
1610
1611 // Convert all of the instances in the client update to adv_instance_t structures for easy comparison.
1612 // Any that are unchanged will have to be freed--oh well.
1613 i = 0;
1614 for (instance = client_update->instances; instance != NULL; instance = instance->next) {
1615 adv_instance_t *prepared_instance = adv_instance_create(instance, host, update);
1616 if (prepared_instance == NULL) {
1617 // prepare_instance logs.
1618 goto fail;
1619 }
1620 if (i >= num_add_instances) {
1621 ERROR("prepare_update: while preparing client update instances, i >= num_add_instances");
1622 goto fail;
1623 }
1624 add_instances->vec[i++] = prepared_instance;
1625 }
1626 add_instances->num = i;
1627
1628 // The instances in the update are now in add_instances. If they are updates, move them to update_instances.
1629 // If they are unchanged, free them and null them out. If they are adds, leave them.
1630 for (i = 0; i < num_add_instances; i++) {
1631 adv_instance_t *add_instance = add_instances->vec[i];
1632
1633 for (j = 0; j < host->instances->num; j++) {
1634 adv_instance_t *host_instance = host->instances->vec[j];
1635
1636 // See if the instance names match.
1637 if (!strcmp(add_instance->instance_name, host_instance->instance_name) &&
1638 !strcmp(add_instance->service_type, host_instance->service_type))
1639 {
1640 // If the rdata is the same, it's not an add or an update.
1641 if (add_instance->txt_length == host_instance->txt_length &&
1642 add_instance->port == host_instance->port &&
1643 (add_instance->txt_length == 0 ||
1644 !memcmp(add_instance->txt_data, host_instance->txt_data, add_instance->txt_length)))
1645 {
1646 RELEASE_HERE(add_instance, adv_instance_finalize);
1647 } else {
1648 // Implicit RETAIN/RELEASE
1649 update_instances->vec[j] = add_instance;
1650 }
1651 add_instances->vec[i] = NULL;
1652 break;
1653 }
1654 }
1655 }
1656
1657 // At this point we have figured out all the work we need to do, so hang it off an update structure.
1658 update->host = host;
1659 update->client = client_update;
1660 host->clients = client_update->next;
1661 update->num_remove_addresses = num_remove_addrs;
1662 update->remove_addresses = remove_addrs;
1663 update->num_add_addresses = num_add_addrs;
1664 update->add_addresses = add_addrs;
1665 update->remove_instances = remove_instances;
1666 update->add_instances = add_instances;
1667 update->update_instances = update_instances;
1668 update->host_lease = client_update->host_lease;
1669 update->key_lease = client_update->key_lease;
1670
1671 update->next = host->updates;
1672 host->updates = update;
1673
1674 start_host_update(host);
1675 return;
1676
1677 fail:
1678 if (remove_addrs != NULL) {
1679 // Addresses in remove_addrs are owned by the host and don't need to be freed.
1680 free(remove_addrs);
1681 }
1682 if (add_addrs != NULL) {
1683 // Addresses in add_addrs are ours, so we have to free them.
1684 for (i = 0; i < num_add_addrs; i++) {
1685 if (add_addrs[i] != NULL) {
1686 RELEASE_HERE(add_addrs[i], adv_address_finalize);
1687 }
1688 }
1689 free(add_addrs);
1690 }
1691 if (add_instances != NULL) {
1692 RELEASE_HERE(add_instances, adv_instance_vec_finalize);
1693 add_instances = NULL;
1694 }
1695 if (remove_instances != NULL) {
1696 RELEASE_HERE(remove_instances, adv_instance_vec_finalize);
1697 remove_instances = NULL;
1698 }
1699 if (update_instances != NULL) {
1700 RELEASE_HERE(update_instances, adv_instance_vec_finalize);
1701 update_instances = NULL;
1702 }
1703 if (update) {
1704 if (update->client != NULL) {
1705 update->client->next = host->clients;
1706 host->clients = update->client;
1707 }
1708 free(update);
1709 }
1710
1711 // Try again sometime later.
1712 wait_retry(host);
1713 }
1714
1715 typedef enum { missed, match, conflict } instance_outcome_t;
1716 static instance_outcome_t
1717 compare_instance(adv_instance_t *instance,
1718 dns_host_description_t *new_host, adv_host_t *host,
1719 char *instance_name, char *service_type)
1720 {
1721 if (instance == NULL) {
1722 return missed;
1723 }
1724 if (!strcmp(instance_name, instance->instance_name) && !strcmp(service_type, instance->service_type)) {
1725 if (!dns_names_equal_text(new_host->name, host->name)) {
1726 return conflict;
1727 }
1728 return match;
1729 }
1730 return missed;
1731 }
1732
1733 bool
1734 srp_update_start(comm_t *connection, dns_message_t *parsed_message, message_t *raw_message,
1735 dns_host_description_t *new_host, service_instance_t *instances, service_t *services,
1736 dns_name_t *update_zone, uint32_t lease_time, uint32_t key_lease_time)
1737 {
1738 adv_host_t *host, **p_hosts = NULL;
1739 char pres_name[DNS_MAX_NAME_SIZE_ESCAPED + 1];
1740 int i;
1741 service_instance_t *new_instance, *client_instance;
1742 instance_outcome_t outcome = missed;
1743 adv_update_t *update;
1744 client_update_t *client_update, **p_client_update;
1745 char instance_name[DNS_MAX_LABEL_SIZE_ESCAPED + 1];
1746 char service_type[DNS_MAX_LABEL_SIZE_ESCAPED * 2 + 2];
1747 uint32_t key_id = 0;
1748 char new_host_name[DNS_MAX_NAME_SIZE_ESCAPED + 1];
1749 host_addr_t *addr;
1750 const bool remove = lease_time == 0;
1751 const char *updatestr = lease_time == 0 ? "remove" : "update";
1752 dns_name_print(new_host->name, new_host_name, sizeof new_host_name);
1753
1754 // Compute a checksum on the key, ignoring up to three bytes at the end.
1755 for (i = 0; i < new_host->key->data.key.len; i += 4) {
1756 key_id += ((new_host->key->data.key.key[i] << 24) | (new_host->key->data.key.key[i + 1] << 16) |
1757 (new_host->key->data.key.key[i + 2] << 8) | (new_host->key->data.key.key[i + 3]));
1758 }
1759
1760 // Log the update info.
1761 INFO("srp_update_start: host update for " PRI_S_SRP ", key id %" PRIx32, new_host_name, key_id);
1762 for (addr = new_host->addrs; addr != NULL; addr = addr->next) {
1763 if (addr->rr.type == dns_rrtype_a) {
1764 IPv4_ADDR_GEN_SRP(&addr->rr.data.a.s_addr, addr_buf);
1765 INFO("srp_update_start: host " PUB_S_SRP " for " PRI_S_SRP ", address " PRI_IPv4_ADDR_SRP, updatestr,
1766 new_host_name, IPv4_ADDR_PARAM_SRP(&addr->rr.data.a.s_addr, addr_buf));
1767 } else {
1768 SEGMENTED_IPv6_ADDR_GEN_SRP(addr->rr.data.aaaa.s6_addr, addr_buf);
1769 INFO("srp_update_start: host " PUB_S_SRP " for " PRI_S_SRP ", address " PRI_SEGMENTED_IPv6_ADDR_SRP,
1770 updatestr, new_host_name, SEGMENTED_IPv6_ADDR_PARAM_SRP(addr->rr.data.aaaa.s6_addr, addr_buf));
1771 }
1772 }
1773 for (new_instance = instances; new_instance != NULL; new_instance = new_instance->next) {
1774 extract_instance_name(instance_name, sizeof instance_name, service_type, sizeof service_type, new_instance);
1775 INFO("srp_update_start: host " PUB_S_SRP " for " PRI_S_SRP ", instance name " PRI_S_SRP ", type " PRI_S_SRP
1776 ", port %d", updatestr, new_host_name, instance_name, service_type,
1777 new_instance->srv != NULL ? new_instance->srv->data.srv.port : -1);
1778 }
1779
1780 // SRP doesn't currently support removal. I think it needs to, but I'm going to mostly leave that
1781 // out of this code for now.
1782
1783 // Look for matching service instance names. A service instance name that matches, but has a different
1784 // hostname, means that there is a conflict. We have to look through all the entries; the presence of
1785 // a matching hostname doesn't mean we are done UNLESS there's a matching service instance name pointing
1786 // to that hostname.
1787 for (host = hosts; host; host = host->next) {
1788 // We need to look for matches both in the registered instances for this registration, and also in
1789 // the list of new instances, in case we get a duplicate update while a previous update is in progress.
1790 for (new_instance = instances; new_instance; new_instance = new_instance->next) {
1791 extract_instance_name(instance_name, sizeof instance_name, service_type, sizeof service_type, new_instance);
1792
1793 // First check for a match or conflict in the host itself.
1794 for (i = 0; i < host->instances->num; i++) {
1795 outcome = compare_instance(host->instances->vec[i], new_host, host,
1796 instance_name, service_type);
1797 if (outcome != missed) {
1798 goto found_something;
1799 }
1800 }
1801 // Then look for the same thing in any subsequent updates that have been baked.
1802 for (update = host->updates; update; update = update->next) {
1803 for (i = 0; i < update->add_instances->num; i++) {
1804 outcome = compare_instance(update->add_instances->vec[i], new_host, host,
1805 instance_name, service_type);
1806 if (outcome != missed) {
1807 goto found_something;
1808 }
1809 }
1810 }
1811 // Finally, look for it in any updates that _haven't_ been baked.
1812 for (client_update = host->clients; client_update; client_update = client_update->next) {
1813 for (client_instance = client_update->instances; client_instance;
1814 client_instance = client_instance->next) {
1815 if (dns_names_equal(client_instance->name, new_instance->name)) {
1816 if (!dns_names_equal_text(new_host->name, host->name)) {
1817 outcome = conflict;
1818 } else {
1819 outcome = match;
1820 }
1821 goto found_something;
1822 }
1823 }
1824 }
1825 }
1826 }
1827 found_something:
1828 if (outcome == conflict) {
1829 ERROR("srp_update_start: service instance name " PRI_S_SRP "/" PRI_S_SRP " already pointing to host "
1830 PRI_S_SRP ", not host " PRI_S_SRP, instance_name, service_type, host->name, new_host_name);
1831 advertise_finished(connection, raw_message, dns_rcode_yxdomain, NULL);
1832 goto cleanup;
1833 }
1834
1835 // If we fall off the end looking for a matching service instance, there isn't a matching
1836 // service instance, but there may be a matching host, so look for that.
1837 if (outcome == missed) {
1838 for (p_hosts = &hosts; *p_hosts; p_hosts = &host->next) {
1839 host = *p_hosts;
1840 if (dns_names_equal_text(new_host->name, host->name)) {
1841 if (key_id == host->key_id && dns_keys_rdata_equal(new_host->key, &host->key)) {
1842 outcome = match;
1843 break;
1844 }
1845 ERROR("srp_update_start: update for host " PRI_S_SRP " has key id %" PRIx32
1846 " which doesn't match host key id %" PRIx32 ".",
1847 host->name, key_id, host->key_id);
1848 advertise_finished(connection, raw_message, dns_rcode_yxdomain, NULL);
1849 goto cleanup;
1850 }
1851 }
1852 } else {
1853 if (key_id != host->key_id || !dns_keys_rdata_equal(new_host->key, &host->key)) {
1854 ERROR("srp_update_start: new host with name " PRI_S_SRP " and key id %" PRIx32
1855 " conflicts with existing host %s with key id %" PRIx32,
1856 new_host_name, key_id, host->name, host->key_id);
1857 advertise_finished(connection, raw_message, dns_rcode_yxdomain, NULL);
1858 goto cleanup;
1859 }
1860 }
1861
1862 // If we didn't find a matching host, we can make a new one. When we create it, it just has
1863 // a name and no records. The update that we then construct will have the missing records.
1864 // We don't want to do this for a remove, obviously.
1865 if (outcome == missed) {
1866 if (remove) {
1867 ERROR("Remove for host " PRI_S_SRP " which doesn't exist.", new_host_name);
1868 advertise_finished(connection, raw_message, dns_rcode_nxdomain, NULL);
1869 goto cleanup;
1870 }
1871
1872 host = calloc(1, sizeof *host);
1873 if (host == NULL) {
1874 ERROR("srp_update_start: no memory for host data structure.");
1875 advertise_finished(connection, raw_message, dns_rcode_servfail, NULL);
1876 goto cleanup;
1877 }
1878 host->instances = adv_instance_vec_create(0);
1879 if (host->instances == NULL) {
1880 ERROR("srp_update_start: no memory for host instance vector.");
1881 advertise_finished(connection, raw_message, dns_rcode_servfail, NULL);
1882 host_finalize(host);
1883 goto cleanup;
1884 }
1885
1886 host->retry_wakeup = ioloop_wakeup_create();
1887 if (host->retry_wakeup != NULL) {
1888 host->lease_wakeup = ioloop_wakeup_create();
1889 }
1890 if (host->lease_wakeup == NULL) {
1891 ERROR("srp_update_start: no memory for wake event on host");
1892 advertise_finished(connection, raw_message, dns_rcode_servfail, NULL);
1893 host_finalize(host);
1894 goto cleanup;
1895 }
1896 dns_name_print(new_host->name, pres_name, sizeof pres_name);
1897 host->name = strdup(pres_name);
1898 if (host->name == NULL) {
1899 host_finalize(host);
1900 ERROR("srp_update_start: no memory for hostname.");
1901 advertise_finished(connection, raw_message, dns_rcode_servfail, NULL);
1902 goto cleanup;
1903 }
1904 host->key = *new_host->key;
1905 #ifndef __clang_analyzer__
1906 // Normally this would be invalid, but we never use the name of the key record.
1907 host->key.name = NULL;
1908 #endif
1909 host->key_rdlen = new_host->key->data.key.len + 4;
1910 host->key_rdata = malloc(host->key_rdlen);
1911 if (host->key_rdata == NULL) {
1912 host_finalize(host);
1913 ERROR("srp_update_start: no memory for host key.");
1914 advertise_finished(connection, raw_message, dns_rcode_servfail, NULL);
1915 goto cleanup;
1916 }
1917 memcpy(host->key_rdata, &new_host->key->data.key.flags, 2);
1918 host->key_rdata[2] = new_host->key->data.key.protocol;
1919 host->key_rdata[3] = new_host->key->data.key.algorithm;
1920 memcpy(&host->key_rdata[4], new_host->key->data.key.key, new_host->key->data.key.len);
1921 host->key.data.key.key = &host->key_rdata[4];
1922 host->key_id = key_id;
1923
1924 // Tack this on to the end of the list. The if test is because the optimizer doesn't notice
1925 // that p_hosts can never be null here--it will always be pointing to the end of the list of
1926 // hosts if we get here.
1927 if (p_hosts != NULL) {
1928 *p_hosts = host;
1929 }
1930 p_hosts = NULL;
1931 }
1932
1933 // See if this is a retransmission.
1934 for (update = host->updates; update; update = update->next) {
1935 if (update->client != NULL &&
1936 update->client->message->wire.id == raw_message->wire.id) {
1937 retransmission:
1938 INFO("srp_update_start: dropping retransmission of in-progress update for host " PRI_S_SRP, host->name);
1939 cleanup:
1940 srp_update_free_parts(instances, NULL, services, new_host);
1941 dns_message_free(parsed_message);
1942 return true;
1943 }
1944 }
1945 // Do the same for client updates.
1946 for (p_client_update = &host->clients; *p_client_update; p_client_update = &client_update->next) {
1947 client_update = *p_client_update;
1948 if (client_update->message->wire.id == raw_message->wire.id) {
1949 goto retransmission;
1950 }
1951 }
1952
1953 // If this is a remove, just remove the host.
1954 if (remove) {
1955 lease_callback(host);
1956 advertise_finished(connection, raw_message, dns_rcode_noerror, NULL);
1957 goto cleanup;
1958 }
1959
1960 // At this point we have an update and a host to which to apply it. We may already be doing an earlier
1961 // update, or not. Create a client update structure to hold the communication, so that when we are done,
1962 // we can respond.
1963 client_update = calloc(1, sizeof *client_update);
1964 if (client_update == NULL) {
1965 ERROR("srp_update_start: no memory for host data structure.");
1966 advertise_finished(connection, raw_message, dns_rcode_servfail, NULL);
1967 goto cleanup;
1968 }
1969
1970 if (outcome == missed) {
1971 INFO("srp_update_start: New host " PRI_S_SRP ", key id %" PRIx32 , host->name, host->key_id);
1972 } else {
1973 if (host->registered_name != host->name) {
1974 INFO("srp_update_start: Renewing host " PRI_S_SRP ", alias %s, key id %" PRIx32,
1975 host->name, host->registered_name, host->key_id);
1976 } else {
1977 INFO("srp_update_start: Renewing host " PRI_S_SRP ", key id %" PRIx32, host->name, host->key_id);
1978 }
1979 }
1980
1981 if (host->registered_name == NULL) {
1982 host->registered_name = host->name;
1983 }
1984
1985 client_update->connection = connection;
1986 ioloop_comm_retain(client_update->connection);
1987 client_update->parsed_message = parsed_message;
1988 client_update->message = raw_message;
1989 ioloop_message_retain(client_update->message);
1990 client_update->host = new_host;
1991 client_update->instances = instances;
1992 client_update->services = services;
1993 client_update->update_zone = update_zone;
1994 if (lease_time < max_lease_time) {
1995 client_update->host_lease = lease_time;
1996 } else {
1997 client_update->host_lease = max_lease_time;
1998 }
1999 if (key_lease_time < max_lease_time * 7) {
2000 client_update->key_lease = key_lease_time;
2001 } else {
2002 client_update->key_lease = max_lease_time * 7;
2003 }
2004 *p_client_update = client_update;
2005
2006 // If we aren't already applying an update to this host, apply this update now.
2007 if (host->updates == NULL) {
2008 INFO("srp_update_start: No ongoing host update: preparing this update to be applied.");
2009 prepare_update(host);
2010 } else {
2011 INFO("srp_update_start: waiting for existing update to complete on host " PRI_S_SRP " before applying another.",
2012 host->name);
2013 }
2014 return true;
2015 }
2016
2017 #if defined(IOLOOP_MACOS)
2018 static bool
2019 adv_proxy_enable(xpc_object_t request, xpc_connection_t connection)
2020 {
2021 srp_xpc_client_t *client, **p_client;
2022 xpc_object_t response;
2023 int err = kDNSSDAdvertisingProxyStatus_NoError;
2024
2025 response = xpc_dictionary_create_reply(request);
2026 if (response == NULL) {
2027 ERROR("adv_proxy_enable: Unable to create reply dictionary.");
2028 return false;
2029 }
2030
2031 client = calloc(1, sizeof(*client));
2032 if (client == NULL) {
2033 ERROR("adv_proxy_enable: unable to allocate client state structure.");
2034 err = kDNSSDAdvertisingProxyStatus_NoMemory;
2035 goto out;
2036 }
2037 if (srp_wanted == NULL) {
2038 srp_wanted = calloc(1, sizeof(*srp_wanted));
2039 if (srp_wanted == NULL) {
2040 free(client);
2041 ERROR("adv_proxy_enable: unable to allocate srp_wanted structure.");
2042 err = kDNSSDAdvertisingProxyStatus_NoMemory;
2043 goto out;
2044 }
2045 srp_wanted->transaction = os_transaction_create("com.apple.srp-mdns-proxy.ostransaction");
2046 INFO("Wanted.");
2047 thread_network_startup();
2048 }
2049 RETAIN_HERE(srp_wanted);
2050
2051 client->connection = connection;
2052 xpc_retain(client->connection);
2053 client->enabler = true;
2054
2055 INFO("adv_proxy_enable: connection from client: %p", client);
2056
2057 // Find the end of the list.
2058 for (p_client = &srp_xpc_clients; *p_client != NULL; p_client = &(*p_client)->next) {
2059 }
2060
2061 *p_client = client;
2062 out:
2063 xpc_dictionary_set_uint64(response, kDNSAdvertisingProxyResponseStatus, err);
2064 xpc_connection_send_message(connection, response);
2065 xpc_release(response);
2066 if (err == kDNSSDAdvertisingProxyStatus_NoError) {
2067 return true;
2068 }
2069 return false;
2070 }
2071
2072 static void
2073 srp_wanted_finalize(srp_wanted_state_t *__unused wanted)
2074 {
2075 INFO("adv_proxy_enable: No longer wanted.");
2076 os_release(srp_wanted->transaction);
2077 free(srp_wanted);
2078 srp_wanted = NULL;
2079 thread_network_shutdown();
2080 }
2081
2082 static void
2083 adv_xpc_connection_delete(xpc_connection_t connection)
2084 {
2085 srp_xpc_client_t **p_client, *client;
2086
2087 for (p_client = &srp_xpc_clients; *p_client != NULL; ) {
2088 client = *p_client;
2089 if (client->connection == connection) {
2090 xpc_release(client->connection);
2091 if (client->enabler) {
2092 RELEASE_HERE(srp_wanted, srp_wanted_finalize);
2093 }
2094 *p_client = client->next;
2095 INFO("adv_xpc_connection_delete: deleting client: %p", client);
2096 free(client);
2097 return;
2098 }
2099 p_client = &(*p_client)->next;
2100 }
2101 }
2102
2103 void
2104 adv_xpc_disconnect(void)
2105 {
2106 srp_xpc_client_t *client;
2107
2108 for (client = srp_xpc_clients; client != NULL; client = client->next) {
2109 if (client->connection != NULL && !client->connection_canceled) {
2110 INFO("adv_xpc_disconnect: disconnecting " PUB_S_SRP "client: %p", client->enabler ? "enabler " : "",
2111 client);
2112 client->connection_canceled = true;
2113 xpc_connection_cancel(client->connection);
2114 }
2115 }
2116 }
2117
2118 static bool adv_xpc_message(xpc_connection_t NULLABLE connection, xpc_object_t NULLABLE request);
2119
2120 static wakeup_t *adv_xpc_wakeup;
2121
2122 static void
2123 adv_xpc_restart(void *__unused context)
2124 {
2125 xpc_listener = ioloop_create_xpc_service(kDNSAdvertisingProxyService, adv_xpc_message);
2126 if (xpc_listener == NULL) {
2127 ioloop_add_wake_event(adv_xpc_wakeup, NULL, adv_xpc_restart, NULL, 10000);
2128 }
2129 }
2130
2131 static bool
2132 adv_xpc_list_services(xpc_connection_t request, xpc_object_t connection)
2133 {
2134 xpc_object_t instances = xpc_array_create(NULL, 0);
2135 adv_host_t *host;
2136 xpc_object_t response;
2137 int i;
2138 char addrbuf[INET6_ADDRSTRLEN];
2139 int64_t now = ioloop_timenow();
2140 bool sent = false;
2141 adv_instance_t *instance = NULL;
2142
2143 if (instances == NULL) {
2144 ERROR("adv_xpc_list_services: Unable to create service array");
2145 return false;
2146 }
2147
2148 response = xpc_dictionary_create_reply(request);
2149 if (response == NULL) {
2150 ERROR("adv_xpc_list_services: Unable to create reply dictionary.");
2151 return false;
2152 }
2153 xpc_dictionary_set_uint64(response, kDNSAdvertisingProxyResponseStatus, kDNSSDAdvertisingProxyStatus_NoError);
2154
2155 for (host = hosts; host != NULL; host = host->next) {
2156 if (host->num_addresses > 0) {
2157 inet_ntop(AF_INET6, host->addresses[0]->rdata, addrbuf, sizeof(addrbuf));
2158 }
2159 if (instances == NULL) {
2160 ERROR("adv_xpc_list_services: failed to allocate instance array for " PRI_S_SRP, host->name);
2161 goto fail;
2162 }
2163 sent = false;
2164 xpc_object_t *dict;
2165 for (i = 0; i < host->instances->num; i++) {
2166 if (host->instances->vec[i] != NULL) {
2167 instance = host->instances->vec[i];
2168 send_host:
2169 dict = xpc_dictionary_create(NULL, NULL, 0);
2170 if (dict == NULL) {
2171 ERROR("adv_xpc_list_services: failed to allocate instance dictionary for " PRI_S_SRP, host->name);
2172 goto fail;
2173 }
2174 xpc_dictionary_set_string(dict, "hostname", host->name);
2175 xpc_dictionary_set_string(dict, "regname", host->registered_name);
2176 if (instance) {
2177 char portbuf[6];
2178 xpc_dictionary_set_string(dict, "name", instance->instance_name);
2179 xpc_dictionary_set_string(dict, "type", instance->service_type);
2180 snprintf(portbuf, sizeof(portbuf), "%u", instance->port);
2181 xpc_dictionary_set_string(dict, "port", portbuf);
2182 xpc_dictionary_set_data(dict, "txt", instance->txt_data, instance->txt_length);
2183 }
2184 if (host->num_addresses > 0) {
2185 xpc_dictionary_set_string(dict, "address", addrbuf);
2186 }
2187 xpc_dictionary_set_int64(dict, "lease", host->lease_expiry >= now ? host->lease_expiry - now : -1);
2188 xpc_array_append_value(instances, dict);
2189 xpc_release(dict);
2190 sent = true;
2191 }
2192 }
2193 if (!sent) {
2194 instance = NULL;
2195 goto send_host;
2196 }
2197 }
2198
2199 xpc_dictionary_set_value(response, "instances", instances);
2200 xpc_release(instances);
2201 xpc_connection_send_message(connection, response);
2202 xpc_release(response);
2203 return true;
2204 fail:
2205 if (instances != NULL) {
2206 xpc_release(instances);
2207 }
2208 if (response != NULL) {
2209 xpc_release(response);
2210 }
2211 return false;
2212 }
2213
2214 static bool
2215 adv_xpc_block_service(xpc_connection_t request, xpc_object_t connection, bool enable)
2216 {
2217 xpc_object_t response;
2218 int status = kDNSSDAdvertisingProxyStatus_NoError;
2219 extern srp_proxy_listener_state_t *srp_listener;
2220
2221 response = xpc_dictionary_create_reply(request);
2222 if (response == NULL) {
2223 ERROR("adv_xpc_list_services: Unable to create reply dictionary.");
2224 return false;
2225 }
2226
2227 if (enable) {
2228 if (srp_listener != NULL) {
2229 srp_proxy_listener_cancel(srp_listener);
2230 srp_listener = NULL;
2231 } else {
2232 status = kDNSSDAdvertisingProxyStatus_UnknownErr;
2233 }
2234 } else {
2235 if (srp_listener == NULL) {
2236 partition_start_srp_listener();
2237 } else {
2238 status = kDNSSDAdvertisingProxyStatus_UnknownErr;
2239 }
2240 }
2241
2242 xpc_dictionary_set_uint64(response, kDNSAdvertisingProxyResponseStatus, status);
2243 xpc_connection_send_message(connection, response);
2244 xpc_release(response);
2245 return true;
2246 }
2247
2248 static bool
2249 adv_xpc_regenerate_ula(xpc_connection_t request, xpc_object_t connection)
2250 {
2251 xpc_object_t response;
2252 int status = kDNSSDAdvertisingProxyStatus_NoError;
2253
2254 response = xpc_dictionary_create_reply(request);
2255 if (response == NULL) {
2256 ERROR("adv_xpc_list_services: Unable to create reply dictionary.");
2257 return false;
2258 }
2259
2260 partition_stop_advertising_pref_id();
2261 thread_network_shutdown();
2262 ula_generate();
2263 thread_network_startup();
2264
2265 xpc_dictionary_set_uint64(response, kDNSAdvertisingProxyResponseStatus, status);
2266 xpc_connection_send_message(connection, response);
2267 xpc_release(response);
2268
2269 return true;
2270 }
2271
2272 void
2273 srp_mdns_flush(void)
2274 {
2275 adv_host_t *host, *host_next;
2276
2277 INFO("srp_mdns_flush: flushing all host entries.");
2278 for (host = hosts; host; host = host_next) {
2279 INFO("srp_mdns_flush: Flushing services and host entry for " PRI_S_SRP " (" PRI_S_SRP ")",
2280 host->name, host->registered_name);
2281 // Get rid of the updates before calling lease_callback, which will fail if update is not NULL.
2282 if (host->updates != NULL) {
2283 adv_update_t *update_next, *update = host->updates->next;
2284 update_failed(host->updates, dns_rcode_refused, false);
2285 while (update != NULL) {
2286 update_next = update->next;
2287 update->host = NULL;
2288 update_finalize(update);
2289 update = update_next;
2290 }
2291 host->updates = NULL;
2292 }
2293 // Get rid of clients for the same reason.
2294 if (host->clients != NULL) {
2295 client_update_t *client, *client_next;
2296 for (client = host->clients; client; client = client_next) {
2297 client_next = client->next;
2298 client_finalize(client);
2299 }
2300 host->clients = NULL;
2301 }
2302 host_next = host->next;
2303 host_finalize(host);
2304 }
2305 hosts = NULL;
2306 }
2307
2308 static bool
2309 adv_xpc_message(xpc_connection_t connection, xpc_object_t request)
2310 {
2311 int pid = -1;
2312 int uid = -1;
2313
2314 // This means that the listener failed for some reason. Try again in ten seconds.
2315 if (connection == NULL && request == NULL) {
2316 if (adv_xpc_wakeup == NULL) {
2317 adv_xpc_wakeup = ioloop_wakeup_create();
2318 if (adv_xpc_wakeup == NULL) {
2319 INFO("adv_xpc_message: can't create a wakeup to try to recover.");
2320 return false;
2321 }
2322 } else {
2323 ioloop_cancel_wake_event(adv_xpc_wakeup);
2324 }
2325 ioloop_add_wake_event(adv_xpc_wakeup, NULL, adv_xpc_restart, NULL, 10000);
2326 return false;
2327 }
2328
2329 if (connection == NULL) {
2330 INFO("adv_xpc_message: disconnected.");
2331 return false;
2332 }
2333
2334 pid = xpc_connection_get_pid(connection);
2335 uid = xpc_connection_get_euid(connection);
2336
2337 if (request == NULL) {
2338 INFO("adv_xpc_message: Client uid %d pid %d disconnected.", uid, pid);
2339 adv_xpc_connection_delete(connection);
2340 return false;
2341 }
2342
2343 const char *message_type = xpc_dictionary_get_string(request, kDNSAdvertisingProxyCommand);
2344
2345 if (message_type == NULL) {
2346 ERROR("Client uid %d pid %d sent a request with no message type.", uid, pid);
2347 adv_xpc_connection_delete(connection);
2348 // Close the connection
2349 return false;
2350 }
2351
2352 if (!strcmp(message_type, kDNSAdvertisingProxyEnable)) {
2353 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP " request.", uid, pid, message_type);
2354 return adv_proxy_enable(request, connection);
2355 } else if (!strcmp(message_type, kDNSAdvertisingProxyListServiceTypes)) {
2356 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP " request.", uid, pid, message_type);
2357 } else if (!strcmp(message_type, kDNSAdvertisingProxyListServices)) {
2358 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP " request.", uid, pid, message_type);
2359 return adv_xpc_list_services(request, connection);
2360 } else if (!strcmp(message_type, kDNSAdvertisingProxyListHosts)) {
2361 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP " request.", uid, pid, message_type);
2362 } else if (!strcmp(message_type, kDNSAdvertisingProxyGetHost)) {
2363 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP " request.", uid, pid, message_type);
2364 } else if (!strcmp(message_type, kDNSAdvertisingProxyFlushEntries)) {
2365 INFO("adv_xpc_message: Client uid %d pid %d sent a %s request.", uid, pid, message_type);
2366 srp_mdns_flush();
2367 } else if (!strcmp(message_type, kDNSAdvertisingProxyBlockService)) {
2368 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP " request.", uid, pid, message_type);
2369 adv_xpc_block_service(request, connection, true);
2370 } else if (!strcmp(message_type, kDNSAdvertisingProxyUnblockService)) {
2371 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP " request.", uid, pid, message_type);
2372 adv_xpc_block_service(request, connection, false);
2373 } else if (!strcmp(message_type, kDNSAdvertisingProxyRegenerateULA)) {
2374 INFO("adv_xpc_message: Client uid %d pid %d sent a " PUB_S_SRP " request.", uid, pid, message_type);
2375 adv_xpc_regenerate_ula(request, connection);
2376 } else {
2377 ERROR("Client uid %d pid %d sent a request with unknown message type " PUB_S_SRP ".", uid, pid, message_type);
2378 // Close the connection
2379 adv_xpc_connection_delete(connection);
2380 return false;
2381 }
2382
2383 xpc_object_t response;
2384 response = xpc_dictionary_create_reply(request);
2385 if (response == NULL) {
2386 ERROR("adv_xpc_message: Unable to create reply dictionary.");
2387 return false;
2388 }
2389 xpc_dictionary_set_uint64(response, kDNSAdvertisingProxyResponseStatus, kDNSSDAdvertisingProxyStatus_NoError);
2390 xpc_connection_send_message(connection, response);
2391 xpc_release(response);
2392 return false;
2393 }
2394 #endif
2395
2396 static void
2397 usage(void)
2398 {
2399 ERROR("srp-mdns-proxy [--max-lease-time <seconds>] [--log-stderr]");
2400 exit(1);
2401 }
2402
2403 int
2404 main(int argc, char **argv)
2405 {
2406 int i;
2407 char *end;
2408 int log_stderr = false;
2409
2410 for (i = 1; i < argc; i++) {
2411 if (!strcmp(argv[i], "--max-lease-time")) {
2412 if (i + 1 == argc) {
2413 usage();
2414 }
2415 max_lease_time = (uint32_t)strtoul(argv[i + 1], &end, 10);
2416 if (end == argv[i + 1] || end[0] != 0) {
2417 usage();
2418 }
2419 i++;
2420 } else if (!strcmp(argv[i], "--log-stderr")) {
2421 log_stderr = true;
2422 } else {
2423 usage();
2424 }
2425 }
2426
2427 OPENLOG(log_stderr);
2428 INFO("--------------------------------srp-mdns-proxy starting--------------------------------");
2429
2430 if (!ioloop_init()) {
2431 return 1;
2432 }
2433
2434 if (!start_icmp_listener()) {
2435 return 1;
2436 }
2437
2438 #ifdef IOLOOP_MACOS
2439 // On MacOS, drop privileges once we have the ICMP listener.
2440 #ifdef DROP_PRIVILEGES
2441 int ret;
2442 ssize_t bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
2443 if (bufsize < 0) {
2444 bufsize = 1024;
2445 }
2446 char *getpwnam_r_buf = malloc(bufsize);
2447 struct passwd mdnsresponder_pwd;
2448 int mdnsresponder_uid = 65; // This is what's in /etc/passwd now.
2449 if (getpwnam_r_buf != NULL) {
2450 struct passwd *result;
2451 ret = getpwnam_r("_mdnsresponder", &mdnsresponder_pwd, getpwnam_r_buf, bufsize, &result);
2452 if (ret < 0 || result == NULL) {
2453 ERROR("getpwnam_r failed: " PUB_S_SRP, strerror(ret));
2454 } else {
2455 mdnsresponder_uid = mdnsresponder_pwd.pw_uid;
2456 }
2457 free(getpwnam_r_buf);
2458 endpwent();
2459 } else {
2460 ERROR("Unable to allocate getpwnam_r buffer.");
2461 }
2462 ret = setuid(mdnsresponder_uid);
2463 if (ret < 0) {
2464 ERROR("setuid failed: " PUB_S_SRP, strerror(errno));
2465 }
2466 #endif
2467
2468 // On MacOS, we can set up an XPC service to check on registrations and also to start the service
2469 // from launchd.
2470 xpc_listener = ioloop_create_xpc_service(kDNSAdvertisingProxyService, adv_xpc_message);
2471 if (xpc_listener == NULL) {
2472 return 1;
2473 }
2474 #endif
2475
2476 // We require one open file per service and one per instance.
2477 struct rlimit limits;
2478 if (getrlimit(RLIMIT_NOFILE, &limits) < 0) {
2479 ERROR("getrlimit failed: " PUB_S_SRP, strerror(errno));
2480 return 1;
2481 }
2482
2483 if (limits.rlim_cur < 1024) {
2484 if (limits.rlim_max < 1024) {
2485 INFO("getrlimit: file descriptor hard limit is %llu", limits.rlim_max);
2486 if (limits.rlim_cur != limits.rlim_max) {
2487 limits.rlim_cur = limits.rlim_max;
2488 }
2489 } else {
2490 limits.rlim_cur = 1024;
2491 }
2492 if (setrlimit(RLIMIT_NOFILE, &limits) < 0) {
2493 ERROR("setrlimit failed: " PUB_S_SRP, strerror(errno));
2494 }
2495 }
2496
2497 do {
2498 int something = 0;
2499 ioloop();
2500 INFO("dispatched %d events.", something);
2501 } while (1);
2502 }
2503
2504 // Local Variables:
2505 // mode: C
2506 // tab-width: 4
2507 // c-file-style: "bsd"
2508 // c-basic-offset: 4
2509 // fill-column: 120
2510 // indent-tabs-mode: nil
2511 // End: