Home | History | Annotate | Line # | Download | only in srputil
      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(&registrar_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