]> git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/srp-ioloop.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / ServiceRegistration / srp-ioloop.c
1 /* srp-ioloop.c
2 *
3 * Copyright (c) 2019 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 * srp host API implementation for Posix using ioloop primitives.
18 */
19
20 #include <stdio.h>
21 #include <arpa/inet.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <dns_sd.h>
26 #include <errno.h>
27 #include <fcntl.h>
28
29 #include "srp.h"
30 #include "srp-api.h"
31 #include "dns-msg.h"
32 #include "srp-crypto.h"
33 #include "ioloop.h"
34
35 #include "cti-services.h"
36 #if !defined(OPEN_SOURCE) && defined(TARGET_OS_TV)
37 #define LIVE_TRANSACTION_CLEANUP 1
38 #include "advertising_proxy_services.h"
39 #endif
40
41 static int lease_time = 0;
42 static bool random_leases = false;
43 static bool delete_registrations = false;
44 static bool use_thread_services = false;
45 #ifdef LIVE_TRANSACTION_CLEANUP
46 static bool live_transaction_cleanup = false;
47 static int live_transaction_cleanup_time;
48 static wakeup_t *live_transaction_wakeup;
49 static advertising_proxy_conn_ref live_transaction_cref;
50 #endif
51 static int num_clients = 1;
52 static int bogusify_signatures = false;
53
54 const uint64_t thread_enterprise_number = 52627;
55
56 cti_connection_t thread_service_context;
57
58 #define SRP_IO_CONTEXT_MAGIC 0xFEEDFACEFADEBEEFULL // BEES! Everybody gets BEES!
59 typedef struct io_context {
60 uint64_t magic_cookie1;
61 wakeup_t *wakeup;
62 void *NONNULL srp_context;
63 comm_t *NULLABLE connection;
64 srp_wakeup_callback_t wakeup_callback;
65 srp_datagram_callback_t datagram_callback;
66 uint64_t magic_cookie2;
67 } io_context_t;
68 wakeup_t *remove_wakeup;
69
70 typedef struct srp_client {
71 DNSServiceRef sdref;
72 int index;
73 wakeup_t *wakeup;
74 char *name;
75 } srp_client_t;
76
77 static int
78 validate_io_context(io_context_t **dest, void *src)
79 {
80 io_context_t *context = src;
81 if (context->magic_cookie1 == SRP_IO_CONTEXT_MAGIC &&
82 context->magic_cookie2 == SRP_IO_CONTEXT_MAGIC)
83 {
84 *dest = context;
85 return kDNSServiceErr_NoError;
86 }
87 return kDNSServiceErr_BadState;
88 }
89
90 static void
91 datagram_callback(comm_t *connection, message_t *message, void *context)
92 {
93 (void)connection;
94 io_context_t *io_context = context;
95 io_context->datagram_callback(io_context->srp_context,
96 &message->wire, message->length);
97 }
98
99 static void
100 wakeup_callback(void *context)
101 {
102 io_context_t *io_context;
103 if (validate_io_context(&io_context, context) == kDNSServiceErr_NoError) {
104 INFO("wakeup on context %p srp_context %p", io_context, io_context->srp_context);
105 io_context->wakeup_callback(io_context->srp_context);
106 } else {
107 INFO("wakeup with invalid context: %p", context);
108 }
109 }
110
111 int
112 srp_deactivate_udp_context(void *host_context, void *in_context)
113 {
114 io_context_t *io_context;
115 int err;
116 (void)host_context;
117
118 err = validate_io_context(&io_context, in_context);
119 if (err == kDNSServiceErr_NoError) {
120 if (io_context->connection) {
121 ioloop_comm_release(io_context->connection);
122 }
123 free(io_context);
124 }
125 return err;
126 }
127
128 int
129 srp_disconnect_udp(void *context)
130 {
131 io_context_t *io_context;
132 int err;
133
134 err = validate_io_context(&io_context, context);
135 if (err == kDNSServiceErr_NoError) {
136 if (io_context->connection) {
137 ioloop_comm_cancel(io_context->connection);
138 ioloop_comm_release(io_context->connection);
139 io_context->connection = NULL;
140 }
141 }
142 return err;
143 }
144
145 int
146 srp_connect_udp(void *context, const uint8_t *port, uint16_t address_type, const uint8_t *address, uint16_t addrlen)
147 {
148 io_context_t *io_context;
149 addr_t remote;
150 int err;
151
152 err = validate_io_context(&io_context, context);
153 if (err == kDNSServiceErr_NoError) {
154 if (io_context->connection) {
155 ERROR("srp_connect_udp called with non-null I/O context.");
156 return kDNSServiceErr_Invalid;
157 }
158
159 if (address_type == dns_rrtype_a) {
160 if (addrlen != 4) {
161 return kDNSServiceErr_Invalid;
162 }
163 remote.sa.sa_family = AF_INET;
164 memcpy(&remote.sin.sin_addr, address, addrlen);
165 #ifndef NOT_HAVE_SA_LEN
166 remote.sa.sa_len = sizeof remote.sin;
167 #endif
168 memcpy(&remote.sin.sin_port, port, 2);
169 } else {
170 if (addrlen != 16) {
171 return kDNSServiceErr_Invalid;
172 }
173 remote.sa.sa_family = AF_INET6;
174 memcpy(&remote.sin6.sin6_addr, address, addrlen);
175 #ifndef NOT_HAVE_SA_LEN
176 remote.sa.sa_len = sizeof remote.sin;
177 #endif
178 memcpy(&remote.sin6.sin6_port, port, 2);
179 }
180
181 io_context->connection = ioloop_connection_create(&remote, false, false, datagram_callback,
182 NULL, NULL, NULL, io_context);
183 if (io_context->connection == NULL) {
184 return kDNSServiceErr_NoMemory;
185 }
186 }
187 return err;
188 }
189
190 int
191 srp_make_udp_context(void *host_context, void **p_context, srp_datagram_callback_t callback, void *context)
192 {
193 (void)host_context;
194
195 io_context_t *io_context = calloc(1, sizeof *io_context);
196 if (io_context == NULL) {
197 return kDNSServiceErr_NoMemory;
198 }
199 io_context->magic_cookie1 = io_context->magic_cookie2 = SRP_IO_CONTEXT_MAGIC;
200 io_context->datagram_callback = callback;
201 io_context->srp_context = context;
202
203 io_context->wakeup = ioloop_wakeup_create();
204 if (io_context->wakeup == NULL) {
205 free(io_context);
206 return kDNSServiceErr_NoMemory;
207 }
208
209 *p_context = io_context;
210 return kDNSServiceErr_NoError;
211 }
212
213 int
214 srp_set_wakeup(void *host_context, void *context, int milliseconds, srp_wakeup_callback_t callback)
215 {
216 int err;
217 io_context_t *io_context;
218 (void)host_context;
219
220 err = validate_io_context(&io_context, context);
221 if (err == kDNSServiceErr_NoError) {
222 io_context->wakeup_callback = callback;
223 INFO("srp_set_wakeup on context %p, srp_context %p", io_context, io_context->srp_context);
224 ioloop_add_wake_event(io_context->wakeup, io_context, wakeup_callback, NULL, milliseconds);
225 }
226 return err;
227 }
228
229 int
230 srp_cancel_wakeup(void *host_context, void *context)
231 {
232 int err;
233 io_context_t *io_context;
234 (void)host_context;
235
236 err = validate_io_context(&io_context, context);
237 if (err == kDNSServiceErr_NoError) {
238 ioloop_cancel_wake_event(io_context->wakeup);
239 }
240 return err;
241 }
242
243 int
244 srp_send_datagram(void *host_context, void *context, void *message, size_t message_length)
245 {
246 int err;
247 struct iovec iov;
248 io_context_t *io_context;
249 (void)host_context;
250
251 memset(&iov, 0, sizeof iov);
252 iov.iov_base = message;
253 iov.iov_len = message_length;
254
255 if (bogusify_signatures) {
256 ((uint8_t *)message)[message_length - 10] = ~(((uint8_t *)message)[message_length - 10]);
257 }
258
259 err = validate_io_context(&io_context, context);
260 if (err == kDNSServiceErr_NoError) {
261 if (!ioloop_send_message(io_context->connection, message, &iov, 1)) {
262 return kDNSServiceErr_Unknown;
263 }
264 }
265 return err;
266 }
267
268 static bool
269 srp_load_file_data(void *host_context, const char *filename, uint8_t *buffer, uint16_t *length, uint16_t buffer_size)
270 {
271 off_t flen;
272 ssize_t len;
273 int file;
274 (void)host_context;
275
276 file = open(filename, O_RDONLY);
277 if (file < 0) {
278 ERROR("srp_load_file_data: %s: open: %s", filename, strerror(errno));
279 return false;
280 }
281
282 // Get the length of the file.
283 flen = lseek(file, 0, SEEK_END);
284 lseek(file, 0, SEEK_SET);
285 if (flen > buffer_size) {
286 ERROR("srp_load_file_data: %s: lseek: %s", filename, strerror(errno));
287 close(file);
288 return false;
289 }
290 len = read(file, buffer, flen);
291 if (len < 0 || len != flen) {
292 if (len < 0) {
293 ERROR("srp_load_file_data: %s: read: %s", filename, strerror(errno));
294 } else {
295 ERROR("srp_load_file_data: %s: short read %d out of %d", filename, (int)len, (int)flen);
296 }
297 close(file);
298 return false;
299 }
300 close(file);
301 *length = (uint16_t)len;
302 return true;
303 }
304
305 static bool
306 srp_store_file_data(void *host_context, const char *filename, uint8_t *buffer, uint16_t length)
307 {
308 ssize_t len;
309 int file;
310 (void)host_context;
311 file = open(filename, O_WRONLY | O_CREAT, 0600);
312 if (file < 0) {
313 ERROR("srp_store_file_data: %s: %s", filename, strerror(errno));
314 return false;
315 }
316 len = write(file, buffer, length);
317 if (len < 0 || len != length) {
318 if (len < 0) {
319 ERROR("srp_store_file_data: " PUB_S_SRP ": " PUB_S_SRP, filename, strerror(errno));
320 } else {
321 ERROR("srp_store_file_data: short write %d out of %d on file %s", (int)len, (int)length, filename);
322 }
323 unlink(filename);
324 close(file);
325 return kDNSServiceErr_Unknown;
326 }
327 close(file);
328 return kDNSServiceErr_NoError;
329 }
330
331
332 bool
333 srp_get_last_server(uint16_t *NONNULL rrtype, uint8_t *NONNULL rdata, uint16_t rdlim,
334 uint8_t *NONNULL port, void *NULLABLE host_context)
335 {
336 uint8_t buffer[22];
337 unsigned offset = 0;
338 uint16_t length;
339 uint16_t rdlength;
340
341 if (!srp_load_file_data(host_context, "/var/run/srp-last-server", buffer, &length, sizeof(buffer))) {
342 return false;
343 }
344 if (length < 10) { // rrtype + rdlength + ipv4 address + port
345 ERROR("srp_get_last_server: stored server data is too short: %d", length);
346 return false;
347 }
348 *rrtype = (((uint16_t)buffer[offset]) << 8) | buffer[offset + 1];
349 offset += 2;
350 rdlength = (((uint16_t)buffer[offset]) << 8) | buffer[offset + 1];
351 offset += 2;
352 if ((*rrtype == dns_rrtype_a && rdlength != 4) || (*rrtype == dns_rrtype_aaaa && rdlength != 16)) {
353 ERROR("srp_get_last_server: invalid rdlength %d for %s record",
354 rdlength, *rrtype == dns_rrtype_a ? "A" : "AAAA");
355 return false;
356 }
357 if (length < rdlength + 6) { // rrtype + rdlength + address + port
358 ERROR("srp_get_last_server: stored server data length %d is too short", length);
359 return false;
360 }
361 if (rdlength > rdlim) {
362 ERROR("srp_get_last_server: no space for %s data in provided buffer size %d",
363 *rrtype == dns_rrtype_a ? "A" : "AAAA", rdlim);
364 return false;
365 }
366 memcpy(rdata, &buffer[offset], rdlength);
367 offset += rdlength;
368 memcpy(port, &buffer[offset], 2);
369 return true;
370 }
371
372 bool
373 srp_save_last_server(uint16_t rrtype, uint8_t *NONNULL rdata, uint16_t rdlength,
374 uint8_t *NONNULL port, void *NULLABLE host_context)
375 {
376 dns_towire_state_t towire;
377 uint8_t buffer[24];
378 size_t length;
379 memset(&towire, 0, sizeof(towire));
380 towire.p = buffer;
381 towire.lim = towire.p + sizeof(buffer);
382
383 if (rdlength != 4 && rdlength != 16) {
384 ERROR("srp_save_last_server: invalid IP address length %d", rdlength);
385 return false;
386 }
387 dns_u16_to_wire(&towire, rrtype);
388 dns_u16_to_wire(&towire, rdlength);
389 dns_rdata_raw_data_to_wire(&towire, rdata, rdlength);
390 dns_rdata_raw_data_to_wire(&towire, port, 2);
391
392 if (towire.error) {
393 ERROR("srp_save_last_server: " PUB_S_SRP " at %d (%p:%p:%p) while constructing output buffer",
394 strerror(towire.error), towire.line, towire.p, towire.lim, buffer);
395 return false;
396 }
397
398 length = towire.p - buffer;
399 if (!srp_store_file_data(host_context, "/var/run/srp-last-server", buffer, length)) {
400 return false;
401 }
402 return true;
403 }
404
405 #ifdef NO_KEYCHAIN
406 int
407 srp_load_key_data(void *host_context, const char *key_name, uint8_t *buffer, uint16_t *length, uint16_t buffer_size)
408 {
409 if (srp_load_file_data(key_name, buffer, length, buffer_size)) {
410 return kDNSServiceErr_NoError;
411 }
412 return kDNSServiceErr_Unknown;
413 }
414
415 int
416 srp_store_key_data(void *host_context, const char *key_name, uint8_t *buffer, uint16_t length)
417 {
418 if (!srp_store_file_data(host_context, key_name, buffer, length)) {
419 return kDNSServiceErr_Unknown;
420 return kDNSServiceErr_NoError;
421 }
422 #endif // NO_KEYCHAIN
423
424 static void
425 interface_callback(void *context, const char *NONNULL name,
426 const addr_t *NONNULL address, const addr_t *NONNULL netmask,
427 uint32_t flags, enum interface_address_change event_type)
428 {
429 bool drop = false;
430 uint8_t *rdata;
431 uint16_t rdlen;
432 uint16_t rrtype;
433 cti_service_vec_t *cti_services = context;
434
435 (void)netmask;
436 (void)index;
437 (void)event_type;
438
439 if (address->sa.sa_family == AF_INET) {
440 rrtype = dns_rrtype_a;
441 rdata = (uint8_t *)&address->sin.sin_addr;
442 rdlen = 4;
443
444 // Should use IN_LINKLOCAL and IN_LOOPBACK macros here, but for some reason they are not present on
445 // OpenWRT.
446 if (rdata[0] == 127) {
447 drop = true;
448 } else if (rdata[0] == 169 && rdata[1] == 254) {
449 drop = true;
450 }
451 } else if (address->sa.sa_family == AF_INET6) {
452 rrtype = dns_rrtype_aaaa;
453 rdata = (uint8_t *)&address->sin6.sin6_addr;
454 rdlen = 16;
455 if (IN6_IS_ADDR_LOOPBACK(&address->sin6.sin6_addr)) {
456 drop = true;
457 } else if (IN6_IS_ADDR_LINKLOCAL(&address->sin6.sin6_addr)) {
458 drop = true;
459 }
460 } else {
461 return;
462 }
463 if (drop) {
464 if (address->sa.sa_family == AF_INET) {
465 IPv4_ADDR_GEN_SRP(rdata, ipv4_rdata_buf);
466 DEBUG("interface_callback: ignoring " PUB_S_SRP " " PRI_IPv4_ADDR_SRP, name,
467 IPv4_ADDR_PARAM_SRP(rdata, ipv4_rdata_buf));
468 } else if (address->sa.sa_family == AF_INET6) {
469 SEGMENTED_IPv6_ADDR_GEN_SRP(rdata, ipv6_rdata_buf);
470 DEBUG("interface_callback: ignoring " PUB_S_SRP " " PRI_SEGMENTED_IPv6_ADDR_SRP, name,
471 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdata, ipv6_rdata_buf));
472 } else {
473 INFO("interface_callback: ignoring with non-v4/v6 address" PUB_S_SRP, name);
474 }
475 return;
476 }
477
478 if (address->sa.sa_family == AF_INET) {
479 IPv4_ADDR_GEN_SRP(rdata, ipv4_rdata_buf);
480 DEBUG("interface_callback: " PUB_S_SRP " " PRI_IPv4_ADDR_SRP " %x", name,
481 IPv4_ADDR_PARAM_SRP(rdata, ipv4_rdata_buf), flags);
482 } else if (address->sa.sa_family == AF_INET6) {
483 SEGMENTED_IPv6_ADDR_GEN_SRP(rdata, ipv6_rdata_buf);
484 DEBUG("interface_callback: " PUB_S_SRP " " PRI_SEGMENTED_IPv6_ADDR_SRP " %x", name,
485 SEGMENTED_IPv6_ADDR_PARAM_SRP(rdata, ipv6_rdata_buf), flags);
486 } else {
487 DEBUG("interface_callback: " PUB_S_SRP "<none IPv4/IPv6 address> %x", name, flags);
488 }
489
490 // This is a workaround for a bug in the utun0 code, where packets sent to the IP address of the local
491 // thread interface are dropped and do not reach the SRP server. To address this, if we find a service
492 // that is on a local IPv6 address, we replace the address with ::1.
493 if (cti_services != NULL && rrtype == dns_rrtype_aaaa) {
494 size_t i;
495 for (i = 0; i < cti_services->num; i++) {
496 cti_service_t *cti_service = cti_services->services[i];
497 // Look for SRP service advertisements only.
498 if (IS_SRP_SERVICE(cti_service)) {
499 // Local IP address?
500 if (!memcmp(cti_service->server, rdata, 16)) {
501 // ::
502 memset(cti_service->server, 0, 15);
503 // 1
504 cti_service->server[15] = 1;
505 }
506 }
507 }
508 }
509
510 srp_add_interface_address(rrtype, rdata, rdlen);
511 }
512
513 static void
514 remove_callback(void *context)
515 {
516 srp_client_t *client = context;
517 srp_deregister(client);
518 }
519
520 static void
521 register_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode,
522 const char *name, const char *regtype, const char *domain, void *context)
523 {
524 srp_client_t *client = context;
525
526 (void)sdRef;
527 (void)regtype;
528 (void)flags;
529 (void)name;
530 (void)regtype;
531 (void)domain;
532 INFO("Register Reply for %s: %d", client->name, errorCode);
533
534 if (errorCode == kDNSServiceErr_NoError && delete_registrations) {
535 client->wakeup = ioloop_wakeup_create();
536 if (client->wakeup == NULL) {
537 ERROR("Unable to allocate a wakeup for %s.", client->name);
538 exit(1);
539 }
540
541 // Do a remove in five seconds.
542 ioloop_add_wake_event(client->wakeup, client, remove_callback, NULL, 5000);
543 }
544 }
545
546 static void
547 usage(void)
548 {
549 fprintf(stderr,
550 "srp-client [--lease-time <seconds>] [--client-count <client count>] [--server <address>%%<port>]\n"
551 #ifdef LIVE_TRANSACTION_CLEANUP
552 " [--live-transaction-cleanup <milliseconds>]\n"
553 #endif
554 " [--random-leases] [--delete-registrations] [--use-thread-services] [--bogusify-signatures]\n");
555 exit(1);
556 }
557
558 #ifdef LIVE_TRANSACTION_CLEANUP
559 static void
560 flushed_callback(advertising_proxy_conn_ref cref, xpc_object_t response, advertising_proxy_error_type err)
561 {
562 INFO("flushed: cref %p response %p err %d.", cref, response, err);
563 if (err != kDNSSDAdvertisingProxyStatus_NoError) {
564 exit(1);
565 }
566 // We don't need to wait around after flushing.
567 exit(0);
568 }
569
570 static void
571 live_transaction_wakeup_callback(void *__unused context)
572 {
573 int err = advertising_proxy_flush_entries(&live_transaction_cref, dispatch_get_main_queue(), flushed_callback);
574 if (err != kDNSSDAdvertisingProxyStatus_NoError) {
575 ERROR("live_transaction_wakeup_callback: advertising_proxy_flush_entries failed: %d", err);
576 }
577 }
578
579 // This is a test to see if, if we have an update pending, we can safely remove all hosts without there being a
580 // problem.
581 static void
582 maybe_schedule_live_transaction_cleanup(void)
583 {
584 if (live_transaction_cleanup) {
585 live_transaction_wakeup = ioloop_wakeup_create();
586 if (live_transaction_wakeup == NULL) {
587 ERROR("maybe_schedule_live_transaction_cleanup: unable to allocate wakeup!");
588 exit(1);
589 }
590 // Schedule the wakeup for 100ms in the future.
591 ioloop_add_wake_event(live_transaction_wakeup, NULL, live_transaction_wakeup_callback, NULL, live_transaction_cleanup_time);
592 }
593 }
594 #endif
595
596 static void
597 cti_service_list_callback(void *__unused context, cti_service_vec_t *services, cti_status_t status)
598 {
599 size_t i;
600
601 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) {
602 INFO("cti_get_service_list_callback: disconnected");
603 exit(1);
604 }
605
606 srp_start_address_refresh();
607 ioloop_map_interface_addresses(services, interface_callback);
608 for (i = 0; i < services->num; i++) {
609 cti_service_t *cti_service = services->services[i];
610 // Look for SRP service advertisements only.
611 if (IS_SRP_SERVICE(cti_service)) {
612 srp_add_server_address(&cti_service->server[16], dns_rrtype_aaaa, cti_service->server, 16);
613 }
614 }
615 srp_finish_address_refresh();
616 srp_network_state_stable();
617 #ifdef LIVE_TRANSACTION_CLEANUP
618 maybe_schedule_live_transaction_cleanup();
619 #endif
620 }
621
622 int
623 main(int argc, char **argv)
624 {
625
626 uint8_t server_address[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 };
627 uint8_t bogus_address[16] = { 0xfc,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 };
628 // { 0x26, 0x20, 0x01, 0x49, 0x00, 0x0f, 0x1a, 0x4d, 0x04, 0xff, 0x61, 0x5a, 0xa2, 0x2a, 0xab, 0xe8 };
629 uint8_t port[2];
630 uint16_t iport;
631 int err;
632 DNSServiceRef sdref;
633 int *nump;
634 char *end;
635 (void)argc;
636 (void)argv;
637 int i;
638 bool have_server_address = false;
639
640 ioloop_init();
641
642 for (i = 1; i < argc; i++) {
643 if (!strcmp(argv[i], "--lease-time")) {
644 nump = &lease_time;
645 number:
646 if (i + 1 == argc) {
647 usage();
648 }
649 *nump = (uint32_t)strtoul(argv[i + 1], &end, 10);
650 if (end == argv[i + 1] || end[0] != 0) {
651 usage();
652 }
653 i++;
654 } else if (!strcmp(argv[i], "--client-count")) {
655 nump = &num_clients;
656 goto number;
657 } else if (!strcmp(argv[i], "--server")) {
658 char *percent;
659 int server_port;
660 uint8_t addrbuf[16];
661 uint16_t addrtype = dns_rrtype_aaaa;
662 int addrlen = 16;
663
664 if (i + 1 == argc) {
665 usage();
666 }
667 percent = strchr(argv[i + 1], '%');
668 if (percent == NULL || percent[1] == 0) {
669 usage();
670 }
671 *percent = 0;
672 percent++;
673
674 server_port = (uint32_t)strtoul(percent, &end, 10);
675 if (end == percent || end[0] != 0) {
676 usage();
677 }
678 port[0] = server_port >> 8;
679 port[1] = server_port & 255;
680
681 if (inet_pton(AF_INET6, argv[i + 1], addrbuf) < 1) {
682 if (inet_pton(AF_INET, argv[i + 1], addrbuf) < 1) {
683 usage();
684 } else {
685 addrtype = dns_rrtype_a;
686 addrlen = 4;
687 }
688 }
689 srp_add_server_address(port, addrtype, addrbuf, addrlen);
690 have_server_address = true;
691 i++;
692 } else if (!strcmp(argv[i], "--random-leases")) {
693 random_leases = true;
694 } else if (!strcmp(argv[i], "--delete-registrations")) {
695 delete_registrations = true;
696 } else if (!strcmp(argv[i], "--use-thread-services")) {
697 use_thread_services = true;
698 } else if (!strcmp(argv[i], "--bogusify-signatures")) {
699 bogusify_signatures = true;
700 #ifdef LIVE_TRANSACTION_CLEANUP
701 } else if (!strcmp(argv[i], "--live-transaction-cleanup")) {
702 nump = &live_transaction_cleanup_time;
703 live_transaction_cleanup = true;
704 goto number;
705 #endif
706 } else {
707 usage();
708 }
709 }
710
711 if (!use_thread_services) {
712 ioloop_map_interface_addresses(NULL, interface_callback);
713 }
714
715 if (!have_server_address && !use_thread_services) {
716 port[0] = 0;
717 port[1] = 53;
718 srp_add_server_address(port, dns_rrtype_aaaa, bogus_address, 16);
719 srp_add_server_address(port, dns_rrtype_aaaa, server_address, 16);
720 }
721
722 for (i = 0; i < num_clients; i++) {
723 srp_client_t *client;
724 char hnbuf[128];
725
726 client = calloc(1, sizeof(*client));
727 if (client == NULL) {
728 ERROR("no memory for client %d", i);
729 exit(1);
730 }
731
732 if (num_clients == 1) {
733 strcpy(hnbuf, "srp-api-test");
734 } else {
735 snprintf(hnbuf, sizeof(hnbuf), "srp-api-test-%d", i);
736 }
737 client->name = strdup(hnbuf);
738 if (client->name == NULL) {
739 ERROR("No memory for client name %s", hnbuf);
740 exit(1);
741 }
742 client->index = i;
743
744 srp_host_init(client);
745 srp_set_hostname(hnbuf, NULL);
746
747 if (random_leases) {
748 int random_lease_time = 30 + srp_random16() % 1800; // random
749 INFO("Client %d, lease time = %d", i, random_lease_time);
750 srp_set_lease_times(random_lease_time, 7 * 24 * 3600); // random host lease, 7 day key lease
751 } else if (lease_time > 0) {
752 srp_set_lease_times(lease_time, 7 * 24 * 3600); // specified host lease, 7 day key lease
753 }
754
755 memcpy(&iport, port, 2);
756 err = DNSServiceRegister(&sdref, 0, 0, hnbuf, "_ipps._tcp",
757 NULL, NULL, iport, 0, NULL, register_callback, client);
758 if (err != kDNSServiceErr_NoError) {
759 ERROR("DNSServiceRegister failed: %d", err);
760 exit(1);
761 }
762 }
763
764 if (use_thread_services) {
765 cti_get_service_list(&thread_service_context, NULL, cti_service_list_callback, dispatch_get_main_queue());
766 } else {
767 srp_network_state_stable();
768 #ifdef LIVE_TRANSACTION_CLEANUP
769 maybe_schedule_live_transaction_cleanup();
770 #endif
771 }
772 ioloop();
773 }
774
775 // Local Variables:
776 // mode: C
777 // tab-width: 4
778 // c-file-style: "bsd"
779 // c-basic-offset: 4
780 // fill-column: 108
781 // indent-tabs-mode: nil
782 // End: