1 1.1 christos /* srputil.c 2 1.1 christos * 3 1.1 christos * Copyright (c) 2020-2024 Apple Inc. All rights reserved. 4 1.1 christos * 5 1.1 christos * Licensed under the Apache License, Version 2.0 (the "License"); 6 1.1 christos * you may not use this file except in compliance with the License. 7 1.1 christos * You may obtain a copy of the License at 8 1.1 christos * 9 1.1 christos * https://www.apache.org/licenses/LICENSE-2.0 10 1.1 christos * 11 1.1 christos * Unless required by applicable law or agreed to in writing, software 12 1.1 christos * distributed under the License is distributed on an "AS IS" BASIS, 13 1.1 christos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 1.1 christos * See the License for the specific language governing permissions and 15 1.1 christos * limitations under the License. 16 1.1 christos * 17 1.1 christos * SRP Advertising Proxy utility program, allows: 18 1.1 christos * start/stop advertising proxy 19 1.1 christos * get/track list of service types 20 1.1 christos * get/track list of services of a particular type 21 1.1 christos * get/track list of hosts 22 1.1 christos * get/track information about a particular host 23 1.1 christos */ 24 1.1 christos 25 1.1 christos #include <stdlib.h> 26 1.1 christos #include <string.h> 27 1.1 christos #include <stdio.h> 28 1.1 christos #include <unistd.h> 29 1.1 christos #include <errno.h> 30 1.1 christos #include <sys/socket.h> 31 1.1 christos #include <netinet/in.h> 32 1.1 christos #include <arpa/inet.h> 33 1.1 christos #include <fcntl.h> 34 1.1 christos #include <time.h> 35 1.1 christos #include <dns_sd.h> 36 1.1 christos #include <net/if.h> 37 1.1 christos #include <inttypes.h> 38 1.1 christos 39 1.1 christos void *main_queue = NULL; 40 1.1 christos 41 1.1 christos #include "srp.h" 42 1.1 christos #include "dns-msg.h" 43 1.1 christos #include "ioloop.h" 44 1.1 christos #include "advertising_proxy_services.h" 45 1.1 christos #include "route-tracker.h" 46 1.1 christos #include "state-machine.h" 47 1.1 christos #include "thread-service.h" 48 1.1 christos #include "service-tracker.h" 49 1.1 christos #include "probe-srp.h" 50 1.1 christos #include "cti-services.h" 51 1.1 christos #include "adv-ctl-server.h" 52 1.1 christos 53 1.1 christos 54 1.1 christos static void 55 1.1 christos flushed_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 56 1.1 christos { 57 1.1 christos INFO("flushed: cref %p response %p err %d.", cref, result, err); 58 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 59 1.1 christos exit(1); 60 1.1 christos } 61 1.1 christos // We don't need to wait around after flushing. 62 1.1 christos exit(0); 63 1.1 christos } 64 1.1 christos 65 1.1 christos static void 66 1.1 christos block_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 67 1.1 christos { 68 1.1 christos INFO("blocked: cref %p response %p err %d.", cref, result, err); 69 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 70 1.1 christos exit(1); 71 1.1 christos } 72 1.1 christos // We don't need to wait around after blocking. 73 1.1 christos exit(0); 74 1.1 christos } 75 1.1 christos 76 1.1 christos static void 77 1.1 christos unblock_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 78 1.1 christos { 79 1.1 christos INFO("unblocked: cref %p response %p err %d.", cref, result, err); 80 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 81 1.1 christos exit(1); 82 1.1 christos } 83 1.1 christos // We don't need to wait around after unblocking. 84 1.1 christos exit(0); 85 1.1 christos } 86 1.1 christos 87 1.1 christos static void 88 1.1 christos regenerate_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 89 1.1 christos { 90 1.1 christos INFO("regenerated ula: cref %p response %p err %d.", cref, result, err); 91 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 92 1.1 christos exit(1); 93 1.1 christos } 94 1.1 christos // We don't need to wait around after unblocking. 95 1.1 christos exit(0); 96 1.1 christos } 97 1.1 christos 98 1.1 christos static void 99 1.1 christos prefix_advertise_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 100 1.1 christos { 101 1.1 christos INFO("advertise prefix: cref %p response %p err %d.", cref, result, err); 102 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 103 1.1 christos exit(1); 104 1.1 christos } 105 1.1 christos // We don't need to wait around after advertising prefix. 106 1.1 christos exit(0); 107 1.1 christos } 108 1.1 christos 109 1.1 christos static void 110 1.1 christos add_prefix_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 111 1.1 christos { 112 1.1 christos INFO("add prefix: cref %p response %p err %d.", cref, result, err); 113 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 114 1.1 christos exit(1); 115 1.1 christos } 116 1.1 christos // We don't need to wait around after advertising prefix. 117 1.1 christos exit(0); 118 1.1 christos } 119 1.1 christos 120 1.1 christos static void 121 1.1 christos remove_prefix_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 122 1.1 christos { 123 1.1 christos INFO("remove prefix: cref %p response %p err %d.", cref, result, err); 124 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 125 1.1 christos exit(1); 126 1.1 christos } 127 1.1 christos // We don't need to wait around after advertising prefix. 128 1.1 christos exit(0); 129 1.1 christos } 130 1.1 christos 131 1.1 christos static void 132 1.1 christos add_nat64_prefix_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 133 1.1 christos { 134 1.1 christos INFO("add nat64 prefix: cref %p response %p err %d.", cref, result, err); 135 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 136 1.1 christos exit(1); 137 1.1 christos } 138 1.1 christos exit(0); 139 1.1 christos } 140 1.1 christos 141 1.1 christos static void 142 1.1 christos remove_nat64_prefix_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 143 1.1 christos { 144 1.1 christos INFO("remove nat64 prefix: cref %p response %p err %d.", cref, result, err); 145 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 146 1.1 christos exit(1); 147 1.1 christos } 148 1.1 christos exit(0); 149 1.1 christos } 150 1.1 christos 151 1.1 christos static void 152 1.1 christos stop_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 153 1.1 christos { 154 1.1 christos INFO("stopped: cref %p response %p err %d.", cref, result, err); 155 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 156 1.1 christos exit(1); 157 1.1 christos } 158 1.1 christos // We don't need to wait around after stopping. 159 1.1 christos exit(0); 160 1.1 christos } 161 1.1 christos 162 1.1 christos static const char * 163 1.1 christos print_address(advertising_proxy_host_address_t *address, char *addrbuf, size_t addrbuf_size) 164 1.1 christos { 165 1.1 christos if (address->rrtype == 0) { 166 1.1 christos return (char *)address->rdata; 167 1.1 christos } else if (address->rrtype == dns_rrtype_a && address->rdlen == 4) { 168 1.1 christos inet_ntop(AF_INET, address->rdata, addrbuf, (socklen_t)addrbuf_size); 169 1.1 christos return addrbuf; 170 1.1 christos } else if (address->rrtype == dns_rrtype_aaaa && address->rdlen == 16) { 171 1.1 christos inet_ntop(AF_INET6, address->rdata, addrbuf, (socklen_t)addrbuf_size); 172 1.1 christos return addrbuf; 173 1.1 christos } else { 174 1.1 christos sprintf(addrbuf, "Family-%d", address->rrtype); 175 1.1 christos return addrbuf; 176 1.1 christos } 177 1.1 christos } 178 1.1 christos 179 1.1 christos static void 180 1.1 christos services_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 181 1.1 christos { 182 1.1 christos int i; 183 1.1 christos int64_t lease, hours, minutes, seconds; 184 1.1 christos advertising_proxy_host_t *host = result; 185 1.1 christos const char *address = "<no address>"; 186 1.1 christos char *addrbuf = NULL; 187 1.1 christos size_t addrbuflen; 188 1.1 christos uint64_t ula; 189 1.1 christos 190 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 191 1.1 christos INFO("services: cref %p response %p err %d.", cref, result, err); 192 1.1 christos exit(1); 193 1.1 christos } 194 1.1 christos if (result == NULL) { 195 1.1 christos INFO("services: cref %p response %p err %d.", cref, result, err); 196 1.1 christos exit(0); 197 1.1 christos } 198 1.1 christos 199 1.1 christos if (host->num_instances == 0) { 200 1.1 christos i = -1; 201 1.1 christos } else { 202 1.1 christos i = 0; 203 1.1 christos } 204 1.1 christos for (; i < host->num_instances; i++) { 205 1.1 christos const char *instance_name, *service_type, *reg_type; 206 1.1 christos char port[6]; // uint16_t as ascii 207 1.1 christos 208 1.1 christos if (i == -1 || host->instances[i].instance_name == NULL) { 209 1.1 christos instance_name = "<no instances>"; 210 1.1 christos service_type = ""; 211 1.1 christos port[0] = 0; 212 1.1 christos reg_type = ""; 213 1.1 christos } else { 214 1.1 christos instance_name = host->instances[i].instance_name; 215 1.1 christos service_type = host->instances[i].service_type; 216 1.1 christos snprintf(port, sizeof(port), "%u", host->instances[i].port); 217 1.1 christos reg_type = host->instances[i].reg_type; 218 1.1 christos } 219 1.1 christos 220 1.1 christos if (host->num_addresses > 0) { 221 1.1 christos addrbuflen = host->num_addresses * (INET6_ADDRSTRLEN + 1); 222 1.1 christos addrbuf = malloc(addrbuflen); 223 1.1 christos if (addrbuf == NULL) { 224 1.1 christos address = "<no memory for address buffer>"; 225 1.1 christos } else { 226 1.1 christos char *ap = addrbuf; 227 1.1 christos for (int j = 0; j < host->num_addresses; j++) { 228 1.1 christos *ap++ = ' '; 229 1.1 christos address = print_address(&host->addresses[j], ap, addrbuflen - (ap - addrbuf)); 230 1.1 christos size_t len = strlen(address); 231 1.1 christos if (address != ap) { 232 1.1 christos if (len + ap + 1 > addrbuf + addrbuflen) { 233 1.1 christos len = addrbuflen - (ap - addrbuf) - 1; 234 1.1 christos } 235 1.1 christos memcpy(ap, address, len + 1); // Includes NUL 236 1.1 christos } 237 1.1 christos ap += len; 238 1.1 christos } 239 1.1 christos address = addrbuf; 240 1.1 christos } 241 1.1 christos } 242 1.1 christos lease = host->lease_time; 243 1.1 christos hours = lease / 3600 / 1000; 244 1.1 christos lease -= hours * 3600 * 1000; 245 1.1 christos minutes = lease / 60 / 1000; 246 1.1 christos lease -= minutes * 60 * 1000; 247 1.1 christos seconds = lease / 1000; 248 1.1 christos lease -= seconds * 1000; 249 1.1 christos 250 1.1 christos // Our implementation of the stable server ID uses the server ULA, so just copy out those 48 bits, 251 1.1 christos // which are in network byte order. 252 1.1 christos ula = 0; 253 1.1 christos for (int j = 1; j < 6; j++) { 254 1.1 christos ula = ula << 8 | (((uint8_t *)&host->server_id)[j]); 255 1.1 christos } 256 1.1 christos printf("\"%s\" \"%s\" %s %s %s %" PRIu64 ":%" PRIu64 ":%" PRIu64 ".%" PRIu64 " \"%s\" \"%s\" %s %" PRIx64 "\n", 257 1.1 christos host->regname, instance_name, service_type, port, 258 1.1 christos address == NULL ? "" : address, hours, minutes, seconds, lease, host->hostname, 259 1.1 christos reg_type, host->removed ? "invalid" : "valid", ula); 260 1.1 christos if (addrbuf != NULL) { 261 1.1 christos free(addrbuf); 262 1.1 christos } 263 1.1 christos } 264 1.1 christos } 265 1.1 christos 266 1.1 christos static void 267 1.1 christos ula_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 268 1.1 christos { 269 1.1 christos INFO("get_ula: cref %p response %p err %d.", cref, result, err); 270 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 271 1.1 christos fprintf(stderr, "ULA get failed: %d\n", err); 272 1.1 christos exit(1); 273 1.1 christos } 274 1.1 christos uint64_t ula = *((uint64_t *)result); 275 1.1 christos printf("ULA: %" PRIx64 "\n", ula); 276 1.1 christos exit(0); 277 1.1 christos } 278 1.1 christos 279 1.1 christos static void 280 1.1 christos disable_srp_replication_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 281 1.1 christos { 282 1.1 christos INFO("disable_srp_replication: cref %p response %p err %d.", cref, result, err); 283 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 284 1.1 christos exit(1); 285 1.1 christos } 286 1.1 christos // We don't need to wait around after SRP replication disabled. 287 1.1 christos exit(0); 288 1.1 christos } 289 1.1 christos 290 1.1 christos static void 291 1.1 christos drop_srpl_connection_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 292 1.1 christos { 293 1.1 christos INFO("drop_srpl_connection: cref %p response %p err %d.", cref, result, err); 294 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 295 1.1 christos exit(1); 296 1.1 christos } 297 1.1 christos exit(0); 298 1.1 christos } 299 1.1 christos 300 1.1 christos static void 301 1.1 christos undrop_srpl_connection_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 302 1.1 christos { 303 1.1 christos INFO("undrop_srpl_connection: cref %p response %p err %d.", cref, result, err); 304 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 305 1.1 christos exit(1); 306 1.1 christos } 307 1.1 christos exit(0); 308 1.1 christos } 309 1.1 christos 310 1.1 christos static void 311 1.1 christos drop_srpl_advertisement_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 312 1.1 christos { 313 1.1 christos INFO("drop_srpl_advertisement: cref %p response %p err %d.", cref, result, err); 314 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 315 1.1 christos exit(1); 316 1.1 christos } 317 1.1 christos exit(0); 318 1.1 christos } 319 1.1 christos 320 1.1 christos static void 321 1.1 christos undrop_srpl_advertisement_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 322 1.1 christos { 323 1.1 christos INFO("undrop_srpl_advertisement: cref %p response %p err %d.", cref, result, err); 324 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 325 1.1 christos exit(1); 326 1.1 christos } 327 1.1 christos exit(0); 328 1.1 christos } 329 1.1 christos 330 1.1 christos static void 331 1.1 christos start_dropping_push_connections_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 332 1.1 christos { 333 1.1 christos INFO("start_dropping_push_connections: cref %p response %p err %d.", cref, result, err); 334 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 335 1.1 christos exit(1); 336 1.1 christos } 337 1.1 christos exit(0); 338 1.1 christos } 339 1.1 christos 340 1.1 christos static void 341 1.1 christos start_breaking_time_validation_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 342 1.1 christos { 343 1.1 christos INFO("start_breaking_time_validation: cref %p response %p err %d.", cref, result, err); 344 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 345 1.1 christos exit(1); 346 1.1 christos } 347 1.1 christos exit(0); 348 1.1 christos } 349 1.1 christos 350 1.1 christos static void 351 1.1 christos block_anycast_service_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 352 1.1 christos { 353 1.1 christos INFO("block_anycast_service: cref %p response %p err %d.", cref, result, err); 354 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 355 1.1 christos exit(1); 356 1.1 christos } 357 1.1 christos exit(0); 358 1.1 christos } 359 1.1 christos 360 1.1 christos static void 361 1.1 christos unblock_anycast_service_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 362 1.1 christos { 363 1.1 christos INFO("unblock_anycast_service: cref %p response %p err %d.", cref, result, err); 364 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 365 1.1 christos exit(1); 366 1.1 christos } 367 1.1 christos exit(0); 368 1.1 christos } 369 1.1 christos 370 1.1 christos static void 371 1.1 christos start_thread_shutdown_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err) 372 1.1 christos { 373 1.1 christos INFO("cref %p response %p err %d.", cref, result, err); 374 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 375 1.1 christos exit(1); 376 1.1 christos } 377 1.1 christos exit(0); 378 1.1 christos } 379 1.1 christos 380 1.1 christos typedef struct variable variable_t; 381 1.1 christos struct variable { 382 1.1 christos variable_t *next; 383 1.1 christos const char *name, *value; 384 1.1 christos }; 385 1.1 christos 386 1.1 christos static void 387 1.1 christos set_variable_callback(advertising_proxy_conn_ref cref, void *context, void *result, advertising_proxy_error_type err) 388 1.1 christos { 389 1.1 christos variable_t *variable = context; 390 1.1 christos INFO("set_variable: cref %p response %p err %d, variable name %s, value %s.", 391 1.1 christos cref, result, err, variable->name, variable->value); 392 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 393 1.1 christos if (variable->next == NULL) { 394 1.1 christos exit(1); 395 1.1 christos } 396 1.1 christos } 397 1.1 christos if (variable->next == NULL) { 398 1.1 christos exit(0); 399 1.1 christos } 400 1.1 christos } 401 1.1 christos 402 1.1 christos static comm_t *tcp_connection; 403 1.1 christos bool do_tcp_zero_test = false; 404 1.1 christos bool do_tcp_fin_length = false; 405 1.1 christos bool do_tcp_fin_payload = false; 406 1.1 christos 407 1.1 christos service_tracker_t *tracker; 408 1.1 christos 409 1.1 christos // Dummy functions required to use service tracker here 410 1.1 christos void 411 1.1 christos adv_ctl_thread_shutdown_status_check(srp_server_t *UNUSED server_state) { 412 1.1 christos } 413 1.1 christos 414 1.1 christos static void 415 1.1 christos service_done_callback(void *context, cti_status_t status) 416 1.1 christos { 417 1.1 christos const char *action = context; 418 1.1 christos if (status != kCTIStatus_NoError) { 419 1.1 christos fprintf(stderr, PUB_S_SRP " failed, status %d", action, status); 420 1.1 christos exit(1); 421 1.1 christos } else { 422 1.1 christos fprintf(stderr, PUB_S_SRP " done", action); 423 1.1 christos exit(0); 424 1.1 christos } 425 1.1 christos } 426 1.1 christos 427 1.1 christos static void 428 1.1 christos service_set_changed(bool unicast) 429 1.1 christos { 430 1.1 christos thread_service_t *winner = NULL; 431 1.1 christos for (thread_service_t *service = service_tracker_services_get(tracker); service != NULL; service = service->next) { 432 1.1 christos if (service->ignore) { 433 1.1 christos continue; 434 1.1 christos } 435 1.1 christos if (unicast && service->service_type == unicast_service) { 436 1.1 christos if (winner == NULL || in6addr_compare(&service->u.unicast.address, &winner->u.unicast.address) < 0) { 437 1.1 christos winner = service; 438 1.1 christos } 439 1.1 christos } 440 1.1 christos } 441 1.1 christos if (winner == NULL) { 442 1.1 christos fprintf(stderr, "no services present!"); 443 1.1 christos exit(1); 444 1.1 christos } 445 1.1 christos winner->u.unicast.address.s6_addr[15] = 0; 446 1.1 christos uint8_t service_data[1] = { THREAD_SRP_SERVER_OPTION }; 447 1.1 christos uint8_t server_data[18]; 448 1.1 christos memcpy(server_data, &winner->u.unicast.address, 15); 449 1.1 christos server_data[15] = 0; 450 1.1 christos server_data[16] = winner->u.unicast.port[0]; 451 1.1 christos server_data[17] = winner->u.unicast.port[1]; 452 1.1 christos int ret = cti_add_service(NULL, "add", service_done_callback, NULL, 453 1.1 christos THREAD_ENTERPRISE_NUMBER, service_data, 1, server_data, 18); 454 1.1 christos if (ret != kCTIStatus_NoError) { 455 1.1 christos fprintf(stderr, "add_service failed: %d", ret); 456 1.1 christos exit(1); 457 1.1 christos } 458 1.1 christos } 459 1.1 christos 460 1.1 christos static void 461 1.1 christos unicast_service_set_changed(void *UNUSED context) 462 1.1 christos { 463 1.1 christos service_set_changed(true); 464 1.1 christos } 465 1.1 christos 466 1.1 christos static void 467 1.1 christos start_advertising_winning_unicast_service(void) 468 1.1 christos { 469 1.1 christos tracker = service_tracker_create(NULL); 470 1.1 christos if (tracker != NULL) { 471 1.1 christos service_tracker_callback_add(tracker, unicast_service_set_changed, NULL, NULL); 472 1.1 christos service_tracker_start(tracker); 473 1.1 christos } else { 474 1.1 christos fprintf(stderr, "unable to allocate tracker"); 475 1.1 christos exit(1); 476 1.1 christos } 477 1.1 christos } 478 1.1 christos 479 1.1 christos static void 480 1.1 christos start_removing_unicast_service(void) 481 1.1 christos { 482 1.1 christos uint8_t service_data[1] = { THREAD_SRP_SERVER_OPTION }; 483 1.1 christos int ret = cti_remove_service(NULL, "remove", service_done_callback, NULL, THREAD_ENTERPRISE_NUMBER, service_data, 1); 484 1.1 christos if (ret != kCTIStatus_NoError) { 485 1.1 christos fprintf(stderr, "remove_service failed: %d", ret); 486 1.1 christos exit(1); 487 1.1 christos } 488 1.1 christos } 489 1.1 christos 490 1.1 christos static void 491 1.1 christos tcp_datagram_callback(comm_t *NONNULL comm, message_t *NONNULL message, void *NULLABLE context) 492 1.1 christos { 493 1.1 christos (void)comm; 494 1.1 christos (void)context; 495 1.1 christos fprintf(stderr, "tcp datagram received, length %d", message->length); 496 1.1 christos } 497 1.1 christos 498 1.1 christos static void 499 1.1 christos tcp_connect_callback(comm_t *NONNULL connection, void *NULLABLE context) 500 1.1 christos { 501 1.1 christos fprintf(stderr, "tcp connection succeeded...\n"); 502 1.1 christos uint8_t length[2]; 503 1.1 christos struct iovec iov[2]; 504 1.1 christos char databuf[128]; 505 1.1 christos memset(databuf, 0, sizeof(databuf)); 506 1.1 christos memset(iov, 0, sizeof(iov)); 507 1.1 christos 508 1.1 christos (void)context; 509 1.1 christos 510 1.1 christos if (do_tcp_zero_test) { 511 1.1 christos memset(length, 0, sizeof(length)); 512 1.1 christos iov[0].iov_len = 2; 513 1.1 christos iov[0].iov_base = length; 514 1.1 christos ioloop_send_data(connection, NULL, iov, 1); 515 1.1 christos } else if (do_tcp_fin_length) { 516 1.1 christos memset(length, 0, sizeof(length)); 517 1.1 christos iov[0].iov_len = 1; 518 1.1 christos iov[0].iov_base = &length; 519 1.1 christos ioloop_send_final_data(connection, NULL, iov, 1); 520 1.1 christos } else if (do_tcp_fin_payload) { 521 1.1 christos length[0] = 0; 522 1.1 christos length[1] = 255; 523 1.1 christos iov[0].iov_len = 2; 524 1.1 christos iov[0].iov_base = length; 525 1.1 christos iov[1].iov_len = 128; 526 1.1 christos iov[1].iov_base = databuf; 527 1.1 christos ioloop_send_final_data(connection, NULL, iov, 2); 528 1.1 christos } 529 1.1 christos } 530 1.1 christos 531 1.1 christos static void 532 1.1 christos tcp_disconnect_callback(comm_t *NONNULL comm, void *NULLABLE context, int error) 533 1.1 christos { 534 1.1 christos (void)comm; 535 1.1 christos (void)context; 536 1.1 christos (void)error; 537 1.1 christos fprintf(stderr, "tcp remote close.\n"); 538 1.1 christos exit(0); 539 1.1 christos } 540 1.1 christos 541 1.1 christos static int 542 1.1 christos start_tcp_test(void) 543 1.1 christos { 544 1.1 christos addr_t address; 545 1.1 christos memset(&address, 0, sizeof(address)); 546 1.1 christos address.sa.sa_family = AF_INET; 547 1.1 christos address.sin.sin_addr.s_addr = htonl(0x7f000001); 548 1.1 christos address.sin.sin_port = htons(53); 549 1.1 christos #ifndef NOT_HAVE_SA_LEN 550 1.1 christos address.sin.sin_len = sizeof(address.sin); 551 1.1 christos #endif 552 1.1 christos tcp_connection = ioloop_connection_create(&address, false, true, false, false, tcp_datagram_callback, 553 1.1 christos tcp_connect_callback, tcp_disconnect_callback, NULL, NULL); 554 1.1 christos if (tcp_connection == NULL) { 555 1.1 christos return kDNSSDAdvertisingProxyStatus_NoMemory; 556 1.1 christos } 557 1.1 christos return kDNSSDAdvertisingProxyStatus_NoError; 558 1.1 christos } 559 1.1 christos 560 1.1 christos const char *need_name, *need_service; 561 1.1 christos bool needed_flag; 562 1.1 christos 563 1.1 christos advertising_proxy_conn_ref service_sub; 564 1.1 christos 565 1.1 christos static void 566 1.1 christos service_callback(advertising_proxy_conn_ref UNUSED sub, void *UNUSED context, advertising_proxy_error_type error) 567 1.1 christos { 568 1.1 christos fprintf(stderr, "service callback: %d\n", error); 569 1.1 christos exit(0); 570 1.1 christos } 571 1.1 christos 572 1.1 christos static void 573 1.1 christos start_needing_service(void) 574 1.1 christos { 575 1.1 christos advertising_proxy_error_type ret = advertising_proxy_set_service_needed(&service_sub, dispatch_get_main_queue(), 576 1.1 christos service_callback, NULL, NULL, need_service, 577 1.1 christos needed_flag); 578 1.1 christos if (ret != kDNSSDAdvertisingProxyStatus_NoError) { 579 1.1 christos fprintf(stderr, "advertising_proxy_service_create failed: %d\n", ret); 580 1.1 christos exit(1); 581 1.1 christos } 582 1.1 christos } 583 1.1 christos 584 1.1 christos advertising_proxy_conn_ref instance_sub; 585 1.1 christos 586 1.1 christos static void 587 1.1 christos instance_callback(advertising_proxy_conn_ref UNUSED sub, void *UNUSED context, advertising_proxy_error_type error) 588 1.1 christos { 589 1.1 christos fprintf(stderr, "instance callback: %d\n", error); 590 1.1 christos exit(0); 591 1.1 christos } 592 1.1 christos 593 1.1 christos static void 594 1.1 christos start_needing_instance(void) 595 1.1 christos { 596 1.1 christos advertising_proxy_error_type ret = advertising_proxy_set_service_needed(&instance_sub, dispatch_get_main_queue(), 597 1.1 christos instance_callback, NULL, need_name, 598 1.1 christos need_service, needed_flag); 599 1.1 christos if (ret != kDNSSDAdvertisingProxyStatus_NoError) { 600 1.1 christos fprintf(stderr, "advertising_proxy_set_service_needed failed: %d\n", ret); 601 1.1 christos exit(1); 602 1.1 christos } 603 1.1 christos } 604 1.1 christos 605 1.1 christos const char *browse_service, *resolve_name, *resolve_service; 606 1.1 christos 607 1.1 christos advertising_proxy_subscription_t *browse_sub; 608 1.1 christos 609 1.1 christos static void 610 1.1 christos browse_callback(advertising_proxy_subscription_t *UNUSED sub, advertising_proxy_error_type error, uint32_t interface_index, 611 1.1 christos bool add, const char *instance_name, const char *service_type, void *UNUSED context) 612 1.1 christos { 613 1.1 christos if (error != kDNSSDAdvertisingProxyStatus_NoError) { 614 1.1 christos fprintf(stderr, "browse_callback: %d\n", error); 615 1.1 christos exit(1); 616 1.1 christos } 617 1.1 christos 618 1.1 christos fprintf(stderr, "browse: %d %s %s %s\n", interface_index, add ? "add" : "rmv", instance_name, service_type); 619 1.1 christos } 620 1.1 christos 621 1.1 christos static void 622 1.1 christos start_browsing_service(void) 623 1.1 christos { 624 1.1 christos advertising_proxy_error_type ret = advertising_proxy_browse_create(&browse_sub, dispatch_get_main_queue(), 625 1.1 christos browse_service, browse_callback, NULL); 626 1.1 christos if (ret != kDNSSDAdvertisingProxyStatus_NoError) { 627 1.1 christos fprintf(stderr, "advertising_proxy_browse_create failed: %d\n", ret); 628 1.1 christos exit(1); 629 1.1 christos } 630 1.1 christos } 631 1.1 christos 632 1.1 christos advertising_proxy_subscription_t *resolve_sub; 633 1.1 christos 634 1.1 christos static void 635 1.1 christos resolve_callback(advertising_proxy_subscription_t *UNUSED sub, advertising_proxy_error_type error, 636 1.1 christos uint32_t interface_index, bool add, const char *fullname, const char *hostname, uint16_t port, 637 1.1 christos uint16_t txt_length, const uint8_t *UNUSED txt_record, void *UNUSED context) 638 1.1 christos { 639 1.1 christos if (error != kDNSSDAdvertisingProxyStatus_NoError) { 640 1.1 christos fprintf(stderr, "resolve_create callback: %d\n", error); 641 1.1 christos exit(1); 642 1.1 christos } 643 1.1 christos 644 1.1 christos fprintf(stderr, "resolved: %d %s %s %s %d %d\n", interface_index, add ? "add" : "rmv", 645 1.1 christos fullname, hostname, port, txt_length); 646 1.1 christos } 647 1.1 christos 648 1.1 christos static void 649 1.1 christos start_resolving_service(void) 650 1.1 christos { 651 1.1 christos advertising_proxy_error_type ret = advertising_proxy_resolve_create(&resolve_sub, dispatch_get_main_queue(), 652 1.1 christos resolve_name, resolve_service, NULL, 653 1.1 christos resolve_callback, NULL); 654 1.1 christos if (ret != kDNSSDAdvertisingProxyStatus_NoError) { 655 1.1 christos fprintf(stderr, "advertising_proxy_resolve_create failed: %d\n", ret); 656 1.1 christos exit(1); 657 1.1 christos } 658 1.1 christos } 659 1.1 christos 660 1.1 christos advertising_proxy_subscription_t *registrar_sub; 661 1.1 christos 662 1.1 christos static void 663 1.1 christos registrar_callback(advertising_proxy_subscription_t *UNUSED sub, 664 1.1 christos advertising_proxy_error_type error, void *UNUSED context) 665 1.1 christos { 666 1.1 christos if (error != kDNSSDAdvertisingProxyStatus_NoError) { 667 1.1 christos fprintf(stderr, "registrar_callback: %d\n", error); 668 1.1 christos exit(1); 669 1.1 christos } 670 1.1 christos 671 1.1 christos INFO("SRP registrar is enabled."); 672 1.1 christos } 673 1.1 christos 674 1.1 christos static void 675 1.1 christos start_registrar(void) 676 1.1 christos { 677 1.1 christos advertising_proxy_error_type ret = advertising_proxy_registrar_create(®istrar_sub, dispatch_get_main_queue(), 678 1.1 christos registrar_callback, NULL); 679 1.1 christos if (ret != kDNSSDAdvertisingProxyStatus_NoError) { 680 1.1 christos fprintf(stderr, "advertising_proxy_registrar_create failed: %d", ret); 681 1.1 christos exit(1); 682 1.1 christos } 683 1.1 christos } 684 1.1 christos 685 1.1 christos 686 1.1 christos static void 687 1.1 christos usage(void) 688 1.1 christos { 689 1.1 christos fprintf(stderr, "srputil start [if1 .. ifN -] -- start the SRP MDNS Proxy through launchd\n"); 690 1.1 christos fprintf(stderr, " tcp-zero -- connect to port 53, send a DNS message that's got a zero-length payload\n"); 691 1.1 christos fprintf(stderr, " tcp-fin-length -- connect to port 53, send a DNS message that ends before length is complete\n"); 692 1.1 christos fprintf(stderr, " tcp-fin-payload -- connect to port 53, send a DNS message that ends before payload is complete\n"); 693 1.1 christos fprintf(stderr, " services -- get the list of services currently being advertised\n"); 694 1.1 christos fprintf(stderr, " block -- block the SRP listener\n"); 695 1.1 christos fprintf(stderr, " unblock -- unblock the SRP listener\n"); 696 1.1 christos fprintf(stderr, " regenerate-ula -- generate a new ULA and restart the network\n"); 697 1.1 christos fprintf(stderr, " adv-prefix-high -- advertise high-priority prefix to thread network\n"); 698 1.1 christos fprintf(stderr, " adv-prefix -- advertise prefix to thread network\n"); 699 1.1 christos fprintf(stderr, " stop -- stop advertising as SRP server\n"); 700 1.1 christos fprintf(stderr, " get-ula -- fetch the current ULA prefix configured on the SRP server\n"); 701 1.1 christos fprintf(stderr, " disable-srpl -- disable SRP replication\n"); 702 1.1 christos fprintf(stderr, " add-prefix <ipv6 prefix> -- add an OMR prefix\n"); 703 1.1 christos fprintf(stderr, " remove-prefix <ipv6 prefix -- remove an OMR prefix\n"); 704 1.1 christos fprintf(stderr, " add-nat64-prefix <nat64 prefix> -- add an nat64 prefix\n"); 705 1.1 christos fprintf(stderr, " remove-nat64-prefix <nat64 prefix> -- remove an nat64 prefix\n"); 706 1.1 christos fprintf(stderr, " drop-srpl-connection -- drop existing srp replication connections\n"); 707 1.1 christos fprintf(stderr, " undrop-srpl-connection -- restart srp replication connections that were dropped \n"); 708 1.1 christos fprintf(stderr, " drop-srpl-advertisement -- stop advertising srpl service (but keep it around)\n"); 709 1.1 christos fprintf(stderr, " undrop-srpl-advertisement -- resume advertising srpl service\n"); 710 1.1 christos fprintf(stderr, " start-dropping-push -- start repeatedly dropping any active push connections after 90 seconds\n"); 711 1.1 christos fprintf(stderr, " start-breaking-time -- start breaking time validation on replicated SRP registrations\n"); 712 1.1 christos fprintf(stderr, " set [variable] [value] -- set the value of variable to value (e.g. set min-lease-time 100)\n"); 713 1.1 christos fprintf(stderr, " block-anycast-service -- block advertising anycast service\n"); 714 1.1 christos fprintf(stderr, " unblock-anycast-service -- unblock advertising anycast service\n"); 715 1.1 christos fprintf(stderr, " start-thread-shutdown -- start thread network shutdown\n"); 716 1.1 christos fprintf(stderr, " advertise-winning-unicast-service -- advertise a unicast service that wins over the current service\n"); 717 1.1 christos fprintf(stderr, " browse <service> -- start an advertising_proxy_browse on the specified service\n"); 718 1.1 christos fprintf(stderr, " resolve <name> <service> -- start an advertising_proxy_resolve on the specified service instance\n"); 719 1.1 christos fprintf(stderr, " need-service <service> <flag> -- signal to srp-mdns-proxy that we need to discover a service\n"); 720 1.1 christos fprintf(stderr, " need-instance <name> <service> <flag> -- signal to srp-mdns-proxy that we need to discover a service\n"); 721 1.1 christos fprintf(stderr, " start-srp -- on thread device, enable srp registration\n"); 722 1.1 christos #ifdef NOTYET 723 1.1 christos fprintf(stderr, " flush -- flush all entries from the SRP proxy (for testing only)\n"); 724 1.1 christos #endif 725 1.1 christos } 726 1.1 christos 727 1.1 christos bool start_proxy = false; 728 1.1 christos bool flush_entries = false; 729 1.1 christos bool list_services = false; 730 1.1 christos bool block = false; 731 1.1 christos bool unblock = false; 732 1.1 christos bool regenerate_ula = false; 733 1.1 christos bool adv_prefix = false; 734 1.1 christos bool adv_prefix_high = false; 735 1.1 christos bool stop_proxy = false; 736 1.1 christos bool dump_stdin = false; 737 1.1 christos bool get_ula = false; 738 1.1 christos bool disable_srp_replication = false; 739 1.1 christos bool dso_test = false; 740 1.1 christos bool drop_srpl_connection; 741 1.1 christos bool undrop_srpl_connection; 742 1.1 christos bool drop_srpl_advertisement; 743 1.1 christos bool undrop_srpl_advertisement; 744 1.1 christos bool start_dropping_push_connections; 745 1.1 christos bool add_thread_prefix = false; 746 1.1 christos bool remove_thread_prefix = false; 747 1.1 christos bool add_nat64_prefix = false; 748 1.1 christos bool remove_nat64_prefix = false; 749 1.1 christos bool start_breaking_time_validation = false; 750 1.1 christos bool test_route_tracker = false; 751 1.1 christos bool block_anycast_service = false; 752 1.1 christos bool unblock_anycast_service = false; 753 1.1 christos bool start_thread_shutdown = false; 754 1.1 christos bool advertise_winning_unicast_service = false; 755 1.1 christos bool remove_unicast_service = false; 756 1.1 christos bool start_srp = false; 757 1.1 christos uint8_t prefix_buf[16]; 758 1.1 christos #ifdef NOTYET 759 1.1 christos bool watch = false; 760 1.1 christos bool get = false; 761 1.1 christos #endif 762 1.1 christos variable_t *variables; 763 1.1 christos int num_permitted_interfaces; 764 1.1 christos char **permitted_interfaces; 765 1.1 christos 766 1.1 christos static void 767 1.1 christos start_activities(void *context) 768 1.1 christos { 769 1.1 christos advertising_proxy_error_type err = kDNSSDAdvertisingProxyStatus_NoError;; 770 1.1 christos advertising_proxy_conn_ref cref = NULL; 771 1.1 christos (void)context; 772 1.1 christos 773 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && flush_entries) { 774 1.1 christos err = advertising_proxy_flush_entries(&cref, main_queue, flushed_callback); 775 1.1 christos } 776 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && (do_tcp_zero_test || 777 1.1 christos do_tcp_fin_length || do_tcp_fin_payload)) { 778 1.1 christos err = start_tcp_test(); 779 1.1 christos } 780 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && list_services) { 781 1.1 christos err = advertising_proxy_get_service_list(&cref, main_queue, services_callback); 782 1.1 christos } 783 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && block) { 784 1.1 christos err = advertising_proxy_block_service(&cref, main_queue, block_callback); 785 1.1 christos } 786 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && unblock) { 787 1.1 christos err = advertising_proxy_unblock_service(&cref, main_queue, unblock_callback); 788 1.1 christos } 789 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && regenerate_ula) { 790 1.1 christos err = advertising_proxy_regenerate_ula(&cref, main_queue, regenerate_callback); 791 1.1 christos } 792 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && adv_prefix) { 793 1.1 christos err = advertising_proxy_advertise_prefix(&cref, adv_prefix_high, main_queue, prefix_advertise_callback); 794 1.1 christos } 795 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && stop_proxy) { 796 1.1 christos err = advertising_proxy_stop(&cref, main_queue, stop_callback); 797 1.1 christos } 798 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && get_ula) { 799 1.1 christos err = advertising_proxy_get_ula(&cref, main_queue, ula_callback); 800 1.1 christos } 801 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && disable_srp_replication) { 802 1.1 christos err = advertising_proxy_disable_srp_replication(&cref, main_queue, disable_srp_replication_callback); 803 1.1 christos } 804 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && add_thread_prefix) { 805 1.1 christos err = advertising_proxy_add_prefix(&cref, main_queue, add_prefix_callback, prefix_buf, sizeof(prefix_buf)); 806 1.1 christos } 807 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && remove_thread_prefix) { 808 1.1 christos err = advertising_proxy_remove_prefix(&cref, main_queue, remove_prefix_callback, prefix_buf, sizeof(prefix_buf)); 809 1.1 christos } 810 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && add_nat64_prefix) { 811 1.1 christos err = advertising_proxy_add_nat64_prefix(&cref, main_queue, add_nat64_prefix_callback, prefix_buf, sizeof(prefix_buf)); 812 1.1 christos } 813 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && remove_nat64_prefix) { 814 1.1 christos err = advertising_proxy_remove_nat64_prefix(&cref, main_queue, remove_nat64_prefix_callback, prefix_buf, sizeof(prefix_buf)); 815 1.1 christos } 816 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && drop_srpl_connection) { 817 1.1 christos err = advertising_proxy_drop_srpl_connection(&cref, main_queue, drop_srpl_connection_callback); 818 1.1 christos } 819 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && undrop_srpl_connection) { 820 1.1 christos err = advertising_proxy_undrop_srpl_connection(&cref, main_queue, undrop_srpl_connection_callback); 821 1.1 christos } 822 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && drop_srpl_advertisement) { 823 1.1 christos err = advertising_proxy_drop_srpl_advertisement(&cref, main_queue, drop_srpl_advertisement_callback); 824 1.1 christos } 825 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && undrop_srpl_advertisement) { 826 1.1 christos err = advertising_proxy_undrop_srpl_advertisement(&cref, main_queue, undrop_srpl_advertisement_callback); 827 1.1 christos } 828 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && start_dropping_push_connections) { 829 1.1 christos err = advertising_proxy_start_dropping_push_connections(&cref, main_queue, start_dropping_push_connections_callback); 830 1.1 christos } 831 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && start_breaking_time_validation) { 832 1.1 christos err = advertising_proxy_start_breaking_time_validation(&cref, main_queue, start_breaking_time_validation_callback); 833 1.1 christos } 834 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && block_anycast_service) { 835 1.1 christos err = advertising_proxy_block_anycast_service(&cref, main_queue, block_anycast_service_callback); 836 1.1 christos } 837 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && unblock_anycast_service) { 838 1.1 christos err = advertising_proxy_unblock_anycast_service(&cref, main_queue, unblock_anycast_service_callback); 839 1.1 christos } 840 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && start_thread_shutdown) { 841 1.1 christos err = advertising_proxy_start_thread_shutdown(&cref, main_queue, start_thread_shutdown_callback); 842 1.1 christos } 843 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && test_route_tracker) { 844 1.1 christos route_tracker_test_start(1000); 845 1.1 christos } 846 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && advertise_winning_unicast_service) { 847 1.1 christos start_advertising_winning_unicast_service(); 848 1.1 christos } 849 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && remove_unicast_service) { 850 1.1 christos start_removing_unicast_service(); 851 1.1 christos } 852 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && advertise_winning_unicast_service) { 853 1.1 christos start_advertising_winning_unicast_service(); 854 1.1 christos } 855 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && browse_service != NULL) { 856 1.1 christos start_browsing_service(); 857 1.1 christos } 858 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && resolve_service != NULL) { 859 1.1 christos start_resolving_service(); 860 1.1 christos } 861 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && need_service != NULL && need_name == NULL) { 862 1.1 christos start_needing_service(); 863 1.1 christos } 864 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && need_service != NULL && need_name != NULL) { 865 1.1 christos start_needing_instance(); 866 1.1 christos } 867 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && start_srp) { 868 1.1 christos start_registrar(); 869 1.1 christos } 870 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && variables != NULL) { 871 1.1 christos for (variable_t *variable = variables; variable != NULL; variable = variable->next) { 872 1.1 christos err = advertising_proxy_set_variable(&cref, main_queue, set_variable_callback, variable, variable->name, variable->value); 873 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 874 1.1 christos break; 875 1.1 christos } 876 1.1 christos } 877 1.1 christos } 878 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) { 879 1.1 christos exit(1); 880 1.1 christos } 881 1.1 christos } 882 1.1 christos 883 1.1 christos static void 884 1.1 christos dump_packet(void) 885 1.1 christos { 886 1.1 christos ssize_t len; 887 1.1 christos dns_message_t *message = NULL; 888 1.1 christos dns_wire_t wire; 889 1.1 christos 890 1.1 christos len = read(0, &wire, sizeof(wire)); 891 1.1 christos if (len < 0) { 892 1.1 christos ERROR("stdin: %s", strerror(errno)); 893 1.1 christos return; 894 1.1 christos } 895 1.1 christos if (len < DNS_HEADER_SIZE) { 896 1.1 christos ERROR("stdin: too short: %zd bytes", len); 897 1.1 christos return; 898 1.1 christos } 899 1.1 christos if (!dns_wire_parse(&message, &wire, (unsigned)len, true)) { 900 1.1 christos fprintf(stderr, "DNS message parse failed\n"); 901 1.1 christos return; 902 1.1 christos } 903 1.1 christos } 904 1.1 christos 905 1.1 christos int 906 1.1 christos main(int argc, char **argv) 907 1.1 christos { 908 1.1 christos int i; 909 1.1 christos bool something = false; 910 1.1 christos bool log_stderr = false; 911 1.1 christos 912 1.1 christos for (i = 1; i < argc; i++) { 913 1.1 christos if (!strcmp(argv[i], "start")) { 914 1.1 christos start_proxy = true; 915 1.1 christos something = true; 916 1.1 christos int j; 917 1.1 christos for (j = i + 1; j < argc; j++) { 918 1.1 christos if (!strcmp(argv[j], "-")) { 919 1.1 christos break; 920 1.1 christos } 921 1.1 christos } 922 1.1 christos num_permitted_interfaces = j - i - 1; 923 1.1 christos permitted_interfaces = argv + i + 1; 924 1.1 christos i = j; 925 1.1 christos } else if (!strcmp(argv[i], "tcp-zero")) { 926 1.1 christos do_tcp_zero_test = true; 927 1.1 christos something = true; 928 1.1 christos } else if (!strcmp(argv[i], "tcp-fin-length")) { 929 1.1 christos do_tcp_fin_length = true; 930 1.1 christos something = true; 931 1.1 christos } else if (!strcmp(argv[i], "tcp-fin-payload")) { 932 1.1 christos do_tcp_fin_payload = true; 933 1.1 christos something = true; 934 1.1 christos } else if (!strcmp(argv[i], "flush")) { 935 1.1 christos flush_entries = true; 936 1.1 christos something = true; 937 1.1 christos } else if (!strcmp(argv[i], "services")) { 938 1.1 christos list_services = true; 939 1.1 christos something = true; 940 1.1 christos } else if (!strcmp(argv[i], "block")) { 941 1.1 christos block = true; 942 1.1 christos something = true; 943 1.1 christos } else if (!strcmp(argv[i], "unblock")) { 944 1.1 christos unblock = true; 945 1.1 christos something = true; 946 1.1 christos } else if (!strcmp(argv[i], "regenerate-ula")) { 947 1.1 christos regenerate_ula = true; 948 1.1 christos something = true; 949 1.1 christos } else if (!strcmp(argv[i], "adv-prefix")) { 950 1.1 christos adv_prefix = true; 951 1.1 christos something = true; 952 1.1 christos } else if (!strcmp(argv[i], "adv-prefix-high")) { 953 1.1 christos adv_prefix = true; 954 1.1 christos adv_prefix_high = true; 955 1.1 christos something = true; 956 1.1 christos } else if (!strcmp(argv[i], "stop")) { 957 1.1 christos stop_proxy = true; 958 1.1 christos something = true; 959 1.1 christos } else if (!strcmp(argv[i], "dump")) { 960 1.1 christos dump_packet(); 961 1.1 christos exit(0); 962 1.1 christos } else if (!strcmp(argv[i], "get-ula")) { 963 1.1 christos get_ula = true; 964 1.1 christos something = true; 965 1.1 christos } else if (!strcmp(argv[i], "disable-srpl")) { 966 1.1 christos disable_srp_replication = true; 967 1.1 christos something = true; 968 1.1 christos } else if (!strcmp(argv[i], "add-prefix")) { 969 1.1 christos if (i + 1 >= argc) { 970 1.1 christos usage(); 971 1.1 christos } 972 1.1 christos if (inet_pton(AF_INET6, argv[i + 1], prefix_buf) < 1) { 973 1.1 christos fprintf(stderr, "Invalid ipv6 prefix %s.\n", argv[i + 1]); 974 1.1 christos usage(); 975 1.1 christos } else { 976 1.1 christos add_thread_prefix = true; 977 1.1 christos something = true; 978 1.1 christos i++; 979 1.1 christos } 980 1.1 christos } else if (!strcmp(argv[i], "remove-prefix")) { 981 1.1 christos if (i + 1 >= argc) { 982 1.1 christos usage(); 983 1.1 christos } 984 1.1 christos if (inet_pton(AF_INET6, argv[i + 1], prefix_buf) < 1) { 985 1.1 christos fprintf(stderr, "Invalid ipv6 prefix %s.\n", argv[i + 1]); 986 1.1 christos usage(); 987 1.1 christos } else { 988 1.1 christos remove_thread_prefix = true; 989 1.1 christos something = true; 990 1.1 christos i++; 991 1.1 christos } 992 1.1 christos } else if (!strcmp(argv[i], "add-nat64-prefix")) { 993 1.1 christos if (i + 1 >= argc) { 994 1.1 christos usage(); 995 1.1 christos } 996 1.1 christos if (inet_pton(AF_INET6, argv[i + 1], prefix_buf) < 1) { 997 1.1 christos fprintf(stderr, "Invalid ipv6 prefix %s.\n", argv[i + 1]); 998 1.1 christos usage(); 999 1.1 christos } else { 1000 1.1 christos add_nat64_prefix = true; 1001 1.1 christos something = true; 1002 1.1 christos i++; 1003 1.1 christos } 1004 1.1 christos } else if (!strcmp(argv[i], "remove-nat64-prefix")) { 1005 1.1 christos if (i + 1 >= argc) { 1006 1.1 christos usage(); 1007 1.1 christos } 1008 1.1 christos if (inet_pton(AF_INET6, argv[i + 1], prefix_buf) < 1) { 1009 1.1 christos fprintf(stderr, "Invalid ipv6 prefix %s.\n", argv[i + 1]); 1010 1.1 christos usage(); 1011 1.1 christos } else { 1012 1.1 christos remove_nat64_prefix = true; 1013 1.1 christos something = true; 1014 1.1 christos i++; 1015 1.1 christos } 1016 1.1 christos } else if (!strcmp(argv[i], "browse")) { 1017 1.1 christos if (i + 1 >= argc) { 1018 1.1 christos usage(); 1019 1.1 christos } 1020 1.1 christos browse_service = argv[i + 1]; 1021 1.1 christos i++; 1022 1.1 christos something = true; 1023 1.1 christos } else if (!strcmp(argv[i], "resolve")) { 1024 1.1 christos if (i + 2 >= argc) { 1025 1.1 christos usage(); 1026 1.1 christos } 1027 1.1 christos resolve_name = argv[i + 1]; 1028 1.1 christos resolve_service = argv[i + 2]; 1029 1.1 christos i += 2; 1030 1.1 christos something = true; 1031 1.1 christos } else if (!strcmp(argv[i], "need-service")) { 1032 1.1 christos if (i + 2 >= argc) { 1033 1.1 christos usage(); 1034 1.1 christos } 1035 1.1 christos need_service = argv[i + 1]; 1036 1.1 christos if (!strcmp(argv[i + 2], "true")) { 1037 1.1 christos needed_flag = true; 1038 1.1 christos } else { 1039 1.1 christos needed_flag = false; 1040 1.1 christos } 1041 1.1 christos i += 2; 1042 1.1 christos something = true; 1043 1.1 christos } else if (!strcmp(argv[i], "need-instance")) { 1044 1.1 christos if (i + 3 >= argc) { 1045 1.1 christos usage(); 1046 1.1 christos } 1047 1.1 christos need_name = argv[i + 1]; 1048 1.1 christos need_service = argv[i + 2]; 1049 1.1 christos if (!strcmp(argv[i + 3], "true")) { 1050 1.1 christos needed_flag = true; 1051 1.1 christos } else { 1052 1.1 christos needed_flag = false; 1053 1.1 christos } 1054 1.1 christos i += 3; 1055 1.1 christos something = true; 1056 1.1 christos } else if (!strcmp(argv[i], "start-srp")) { 1057 1.1 christos start_srp = true; 1058 1.1 christos something = true; 1059 1.1 christos } else if (!strcmp(argv[i], "drop-srpl-connection")) { 1060 1.1 christos drop_srpl_connection = true; 1061 1.1 christos something = true; 1062 1.1 christos } else if (!strcmp(argv[i], "undrop-srpl-connection")) { 1063 1.1 christos undrop_srpl_connection = true; 1064 1.1 christos something = true; 1065 1.1 christos } else if (!strcmp(argv[i], "drop-srpl-advertisement")) { 1066 1.1 christos drop_srpl_advertisement = true; 1067 1.1 christos something = true; 1068 1.1 christos } else if (!strcmp(argv[i], "undrop-srpl-advertisement")) { 1069 1.1 christos undrop_srpl_advertisement = true; 1070 1.1 christos something = true; 1071 1.1 christos } else if (!strcmp(argv[i], "start-dropping-push")) { 1072 1.1 christos start_dropping_push_connections = true; 1073 1.1 christos something = true; 1074 1.1 christos } else if (!strcmp(argv[i], "start-breaking-time")) { 1075 1.1 christos start_breaking_time_validation = true; 1076 1.1 christos something = true; 1077 1.1 christos } else if (!strcmp(argv[i], "block-anycast-service")) { 1078 1.1 christos block_anycast_service = true; 1079 1.1 christos something = true; 1080 1.1 christos } else if (!strcmp(argv[i], "unblock-anycast-service")) { 1081 1.1 christos unblock_anycast_service = true; 1082 1.1 christos something = true; 1083 1.1 christos } else if (!strcmp(argv[i], "test-route-tracker")) { 1084 1.1 christos test_route_tracker = true; 1085 1.1 christos something = true; 1086 1.1 christos } else if (!strcmp(argv[i], "start-thread-shutdown")) { 1087 1.1 christos start_thread_shutdown = true; 1088 1.1 christos something = true; 1089 1.1 christos } else if (!strcmp(argv[i], "advertise-winning-unicast-service")) { 1090 1.1 christos advertise_winning_unicast_service = true; 1091 1.1 christos something = true; 1092 1.1 christos } else if (!strcmp(argv[i], "remove-unicast-service")) { 1093 1.1 christos remove_unicast_service = true; 1094 1.1 christos something = true; 1095 1.1 christos } else if (!strcmp(argv[i], "set")) { 1096 1.1 christos if (i + 2 >= argc) { 1097 1.1 christos usage(); 1098 1.1 christos } 1099 1.1 christos variable_t *variable = calloc(1, sizeof(*variable)); 1100 1.1 christos if (variable == NULL) { 1101 1.1 christos fprintf(stderr, "no memory for variable %s", argv[i + 1]); 1102 1.1 christos exit(1); 1103 1.1 christos } 1104 1.1 christos variable->name = argv[i + 1]; 1105 1.1 christos variable->value = argv[i + 2]; 1106 1.1 christos variable->next = variables; 1107 1.1 christos variables = variable; 1108 1.1 christos i += 2; 1109 1.1 christos something = true; 1110 1.1 christos #ifdef NOTYET 1111 1.1 christos } else if (!strcmp(argv[i], "watch")) { 1112 1.1 christos fprintf(stderr, "Watching not implemented yet.\n"); 1113 1.1 christos exit(1); 1114 1.1 christos } else if (!strcmp(argv[i], "get")) { 1115 1.1 christos fprintf(stderr, "Getting not implemented yet.\n"); 1116 1.1 christos exit(1); 1117 1.1 christos #endif 1118 1.1 christos } else if (!strcmp(argv[i], "--debug")) { 1119 1.1 christos OPENLOG("srputil", true); 1120 1.1 christos log_stderr = true; 1121 1.1 christos } else { 1122 1.1 christos usage(); 1123 1.1 christos exit(1); 1124 1.1 christos } 1125 1.1 christos } 1126 1.1 christos 1127 1.1 christos if (!something) { 1128 1.1 christos usage(); 1129 1.1 christos exit(1); 1130 1.1 christos } 1131 1.1 christos 1132 1.1 christos if (log_stderr == false) { 1133 1.1 christos OPENLOG("srputil", log_stderr); 1134 1.1 christos } 1135 1.1 christos 1136 1.1 christos ioloop_init(); 1137 1.1 christos // Start the queue, //then// do the work 1138 1.1 christos ioloop_run_async(start_activities, NULL); 1139 1.1 christos ioloop(); 1140 1.1 christos } 1141 1.1 christos 1142 1.1 christos // Local Variables: 1143 1.1 christos // mode: C 1144 1.1 christos // tab-width: 4 1145 1.1 christos // c-file-style: "bsd" 1146 1.1 christos // c-basic-offset: 4 1147 1.1 christos // fill-column: 108 1148 1.1 christos // indent-tabs-mode: nil 1149 1.1 christos // End: 1150