Home | History | Annotate | Line # | Download | only in ServiceRegistration
      1 /* srp-client.c
      2  *
      3  * Copyright (c) 2018-2023 Apple Inc. All rights reserved.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     https://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  * SRP Client
     18  *
     19  * DNSServiceRegister API for SRP.   See dns_sd.h for details on the API.
     20  */
     21 
     22 #include <stdio.h>
     23 #include <string.h>
     24 #include <strings.h>
     25 #include <stdlib.h>
     26 #include <unistd.h>
     27 #include <inttypes.h>
     28 #include <errno.h>
     29 #include "srp.h"
     30 #ifdef SRP_TEST_SERVER
     31 #undef DNSServiceRegister
     32 #define DNSServiceRegister      srp_client_register
     33 #undef DNSServiceUpdateRecord
     34 #define DNSServiceUpdateRecord  srp_client_update_record
     35 #undef DNSServiceRefDeallocate
     36 #define DNSServiceRefDeallocate srp_client_ref_deallocate
     37 #endif
     38 #ifdef THREAD_DEVKIT_ADK
     39 #include "../mDNSShared/dns_sd.h"
     40 #else
     41 #include <dns_sd.h>
     42 #include <arpa/inet.h>
     43 #endif
     44 #include "srp-api.h"
     45 #include "dns-msg.h"
     46 #include "srp-crypto.h"
     47 
     48 // By default, never wait longer than an hour to do another registration attempt.
     49 #define DEFAULT_MAX_ATTEMPT_INTERVAL       1000 * 60 * 60
     50 
     51 // Default retry interval is 15 seconds--three attempts. This is how long we will remain in the process of retrying
     52 // an update on a particular server before we give up on that server.
     53 
     54 #define DEFAULT_MAX_RETRY_INTERVAL         1000 * 15
     55 
     56 // When we start talking to a particular server, we allow 2 seconds before the first retransmission
     57 #define INITIAL_NEXT_RETRANSMISSION_TIME   2000
     58 
     59 // When we fail to get through to any server, we will initially re-attempt contacting that server after
     60 // this amount of time
     61 #define INITIAL_NEXT_ATTEMPT_TIME          1000 * 2 * 60
     62 
     63 typedef struct client_state client_state_t;
     64 
     65 typedef struct service_addr service_addr_t;
     66 struct service_addr {
     67     service_addr_t *NULLABLE next;
     68     dns_rr_t rr;
     69     uint8_t port[2];
     70 };
     71 
     72 typedef struct _DNSServiceRef_t reg_state_t;
     73 typedef struct update_context {
     74     void *udp_context;
     75     void *message;
     76     client_state_t *NONNULL client;
     77     service_addr_t *server;
     78     size_t message_length;
     79     uint32_t next_retransmission_time;
     80     uint32_t next_attempt_time;
     81     uint32_t lease_time;
     82     uint32_t key_lease_time;
     83     uint32_t serial;
     84     uint32_t interface_serial;
     85     bool notified;  // Callers have been notified.
     86     bool connected; // UDP context is connected.
     87     bool removing;  // We are removing the current registration(s)
     88 } update_context_t;
     89 
     90 struct _DNSServiceRef_t {
     91     reg_state_t *NULLABLE next;
     92     uint32_t serial;
     93     DNSServiceFlags flags;
     94     uint32_t interfaceIndex;
     95     char *NULLABLE name;
     96     char *NULLABLE regtype;
     97     char *NULLABLE domain;
     98     char *NULLABLE host;
     99     int port;
    100     uint16_t txtLen;
    101     void *NULLABLE txtRecord;
    102     DNSServiceRegisterReply callback;
    103     bool succeeded;
    104     bool called_back;
    105     bool removing;
    106     bool skip;
    107     void *NULLABLE context;
    108 };
    109 
    110 struct client_state {
    111     client_state_t *next;
    112     reg_state_t *registrations;
    113     char *hostname;
    114     int hostname_rename_number; // If we've had a naming conflict, this will be nonzero.
    115     srp_hostname_conflict_callback_t hostname_conflict_callback;
    116     srp_key_t *key;
    117     void *os_context;
    118     uint32_t lease_time;
    119     uint32_t key_lease_time;
    120     uint32_t srp_max_attempt_interval;
    121     uint32_t registration_serial;
    122     uint32_t srp_max_retry_interval;
    123     service_addr_t stable_server;
    124     bool srp_server_synced;
    125 
    126     // Currently we only ever have one update in flight.  If we decide we need to send another,
    127     // we need to cancel the one we're currently doing.
    128     update_context_t *active_update;
    129 };
    130 
    131 // Implementation of SRP network entry points, which can be called by the network implementation on the
    132 // hosting platform.
    133 
    134 static bool network_state_changed = false;
    135 static bool doing_refresh = false;
    136 static service_addr_t *interfaces;
    137 static service_addr_t *servers;
    138 static service_addr_t *interface_refresh_state;
    139 static service_addr_t *server_refresh_state;
    140 static uint8_t no_port[2];
    141 static uint32_t interface_serial;
    142 
    143 client_state_t *clients;
    144 client_state_t *current_client;
    145 bool zero_addresses = false; // for testing, used by srp-ioloop.c.
    146 
    147 // Forward references
    148 static int do_srp_update(client_state_t *client, bool definite, bool *did_something);
    149 static void udp_response(void *v_update_context, void *v_message, size_t message_length);
    150 
    151 static bool srp_is_network_active(void);
    152 
    153 #define VALIDATE_IP_ADDR                                         \
    154     if ((rrtype != dns_rrtype_a && rrtype != dns_rrtype_aaaa) || \
    155         (rrtype == dns_rrtype_a && rdlen != 4) ||                \
    156         (rrtype == dns_rrtype_aaaa && rdlen != 16)) {            \
    157         return kDNSServiceErr_Invalid;                           \
    158     }
    159 
    160 
    161 client_state_t *
    162 srp_client_get_current(void)
    163 {
    164     return current_client;
    165 }
    166 
    167 void
    168 srp_client_set_current(client_state_t *new_client)
    169 {
    170     current_client = new_client;
    171 }
    172 
    173 // Call this before calling anything else.   Context will be passed back whenever the srp code
    174 // calls any of the host functions.
    175 int
    176 srp_host_init(void *context)
    177 {
    178     client_state_t *new_client = calloc(1, sizeof(*new_client));
    179     if (new_client == NULL) {
    180         return kDNSServiceErr_NoMemory;
    181     }
    182     new_client->os_context = context;
    183     new_client->lease_time = 3600;       // 1 hour for registration leases
    184     new_client->key_lease_time = 604800; // 7 days for key leases
    185     new_client->registration_serial = 1;
    186     new_client->srp_max_attempt_interval = DEFAULT_MAX_ATTEMPT_INTERVAL;
    187     new_client->srp_max_retry_interval = DEFAULT_MAX_RETRY_INTERVAL;
    188 
    189     current_client = new_client;
    190     new_client->next = clients;
    191     clients = current_client;
    192     return kDNSServiceErr_NoError;
    193 }
    194 
    195 int
    196 srp_host_key_reset_for_client(client_state_t *client)
    197 {
    198     if (client->key != NULL) {
    199         srp_keypair_free(client->key);
    200         client->key = NULL;
    201     }
    202     return srp_reset_key("com.apple.srp-client.host-key", client->os_context);
    203 }
    204 
    205 int
    206 srp_host_key_reset(void)
    207 {
    208     return srp_host_key_reset_for_client(current_client);
    209 }
    210 
    211 int
    212 srp_set_lease_times(uint32_t new_lease_time, uint32_t new_key_lease_time)
    213 {
    214     current_client->lease_time = new_lease_time;
    215     current_client->key_lease_time = new_key_lease_time;
    216     return kDNSServiceErr_NoError;
    217 }
    218 
    219 static void
    220 sync_from_stable_storage(update_context_t *update)
    221 {
    222     service_addr_t *server;
    223     client_state_t *client = update->client;
    224     if (!client->srp_server_synced) {
    225         client->srp_server_synced =
    226             srp_get_last_server(&client->stable_server.rr.type, (uint8_t *)&client->stable_server.rr.data,
    227                                 sizeof(client->stable_server.rr.data), &client->stable_server.port[0],
    228                                 client->os_context);
    229         // Nothing read.
    230         if (!client->srp_server_synced) {
    231             return;
    232         }
    233     } else {
    234         if (update->server != NULL) {
    235             return;
    236         }
    237     }
    238 
    239     // See if one of the advertised servers is the one we last updated.
    240     for (server = servers; server; server = server->next) {
    241         if (server->rr.type == client->stable_server.rr.type &&
    242             !memcmp(&server->port, &client->stable_server.port, 2) &&
    243             ((server->rr.type == dns_rrtype_a && !memcmp(&server->rr.data, &client->stable_server.rr.data, 4)) ||
    244              (server->rr.type == dns_rrtype_aaaa && !memcmp(&server->rr.data, &client->stable_server.rr.data, 16))))
    245         {
    246             update->server = server;
    247             return;
    248         }
    249     }
    250 }
    251 
    252 static void
    253 sync_to_stable_storage(update_context_t *update)
    254 {
    255     client_state_t *client = update->client;
    256     if (!client->srp_server_synced) {
    257         client->srp_server_synced =
    258             srp_save_last_server(client->stable_server.rr.type, (uint8_t *)&client->stable_server.rr.data,
    259                                  client->stable_server.rr.type == dns_rrtype_a ? 4 : 16,
    260                                  client->stable_server.port, client->os_context);
    261     }
    262 }
    263 
    264 // Find an address on a list of addresses.
    265 static service_addr_t **
    266 find_address(service_addr_t **addrs, const uint8_t *port, uint16_t rrtype, const uint8_t *rdata, uint16_t rdlen)
    267 {
    268     service_addr_t *addr, **p_addr = addrs;
    269 
    270     while (*p_addr != NULL) {
    271         addr = *p_addr;
    272         if (addr->rr.type == rrtype && !memcmp(&addr->rr.data, rdata, rdlen) && !memcmp(addr->port, port, 2)) {
    273             break;
    274         }
    275         p_addr = &addr->next;
    276     }
    277     return p_addr;
    278 }
    279 
    280 // Worker function to add an address and notice whether the network state has changed (so as to trigger a
    281 // refresh).
    282 static int
    283 add_address(service_addr_t **list, service_addr_t **refresh,
    284             const uint8_t *port, uint16_t rrtype, const uint8_t *rdata, uint16_t rdlen, bool interface_serial_update)
    285 {
    286     service_addr_t *addr, **p_addr, **p_refresh;
    287 
    288     VALIDATE_IP_ADDR;
    289 
    290     // See if the address is on the refresh list.
    291     p_refresh = find_address(refresh, port, rrtype, rdata, rdlen);
    292 
    293     // See also if it's on the address list (shouldn't be on both).  This also finds the end of the list.
    294     p_addr = find_address(list, port, rrtype, rdata, rdlen);
    295     if (*p_addr != NULL) {
    296         return kDNSServiceErr_NoError;
    297     }
    298 
    299     if (*p_refresh != NULL) {
    300         addr = *p_refresh;
    301 
    302         // This shouldn't happen, but if it does, free the old address.
    303         if (*p_addr != NULL) {
    304             ERROR("duplicate address during refresh!");
    305             free(addr);
    306             return kDNSServiceErr_NoError;
    307         }
    308 
    309         *p_refresh = addr->next;
    310         addr->next = NULL;
    311         *p_addr = addr;
    312 
    313         // In this case, the network state has not changed.
    314         return kDNSServiceErr_NoError;
    315     }
    316 
    317     addr = calloc(1, sizeof *addr);
    318     if (addr == NULL) {
    319         return kDNSServiceErr_NoMemory;
    320     }
    321     addr->rr.type = rrtype;
    322     addr->rr.qclass = dns_qclass_in;
    323     memcpy(&addr->rr.data, rdata, rdlen);
    324     memcpy(&addr->port, port, 2);
    325     *p_addr = addr;
    326     network_state_changed = true;
    327     if (interface_serial_update) {
    328         interface_serial++;
    329     }
    330 
    331     // Print IPv6 address directly here because the code has to be portable for ADK, and OpenThread environment
    332     // has no support for INET6_ADDRSTRLEN.
    333     INFO("added " PUB_S_SRP
    334          " address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x port %u (%04x)",
    335          *list == servers ? "server" : "interface",
    336          rdata[0], rdata[1], rdata[2], rdata[3], rdata[4], rdata[5], rdata[6], rdata[7],
    337          rdata[8], rdata[9], rdata[10], rdata[11], rdata[12], rdata[13], rdata[14], rdata[15],
    338          port != NULL ? (port[0] << 8 | port[1]) : 0, port != NULL ? (port[0] << 8 | port[1]) : 0);
    339 
    340     return kDNSServiceErr_NoError;
    341 }
    342 
    343 // Called when a new address is configured that should be advertised.  This can be called during a refresh,
    344 // in which case it doesn't mark the network state as changed if the address was already present.
    345 int
    346 srp_add_interface_address(uint16_t rrtype, const uint8_t *NONNULL rdata, uint16_t rdlen)
    347 {
    348     return add_address(&interfaces, &interface_refresh_state, no_port, rrtype, rdata, rdlen, true);
    349 }
    350 
    351 // Called whenever the SRP server address changes or the SRP server becomes newly reachable.  This can be
    352 // called during a refresh, in which case it doesn't mark the network state as changed if the address was
    353 // already present.
    354 int
    355 srp_add_server_address(const uint8_t *port, uint16_t rrtype, const uint8_t *NONNULL rdata, uint16_t rdlen)
    356 {
    357     VALIDATE_IP_ADDR;
    358 
    359     return add_address(&servers, &server_refresh_state, port, rrtype, rdata, rdlen, false);
    360 }
    361 
    362 // Called when the node knows its hostname (usually once).   The callback is called if we try to do an SRP
    363 // update and find out that the hostname is in use; in this case, the callback is expected to generate a new
    364 // hostname and re-register it.   It is permitted to call srp_set_hostname() from the callback.
    365 // If the hostname is changed by the callback, then it is used immediately on return from the callback;
    366 // if the hostname is changed in any other situation, nothing is done with the new name until
    367 // srp_network_state_stable() is called.
    368 int
    369 srp_set_hostname(const char *NONNULL name, srp_hostname_conflict_callback_t callback)
    370 {
    371     if (current_client->hostname != NULL) {
    372         free(current_client->hostname);
    373     }
    374     current_client->hostname = strdup(name);
    375     if (current_client->hostname == NULL) {
    376         return kDNSServiceErr_NoMemory;
    377     }
    378     current_client->hostname_conflict_callback = callback;
    379     network_state_changed = true;
    380     return kDNSServiceErr_NoError;
    381 }
    382 
    383 // Called when a network state change is complete (that is, all new addresses have been saved and
    384 // any update to the SRP server address has been provided).   This is only needed when not using the
    385 // refresh mechanism.
    386 static bool
    387 srp_is_network_active(void)
    388 {
    389     INFO("nsc = %d servers = %p interfaces = %p, hostname = " PRI_S_SRP,
    390           network_state_changed, servers, interfaces,
    391          current_client->hostname ? current_client->hostname : "<not set>");
    392     return servers != NULL && (interfaces != NULL || zero_addresses) && current_client->hostname != NULL;
    393 }
    394 
    395 int
    396 srp_network_state_stable(bool *did_something)
    397 {
    398     client_state_t *client;
    399     int status = kDNSServiceErr_NoError;
    400     if (network_state_changed && srp_is_network_active()) {
    401         network_state_changed = false;
    402         for (client = clients; client; client = client->next) {
    403             int ret = do_srp_update(client, false, did_something);
    404             // In the normal case, there will only be one client, and therefore one return status.  For testing,
    405             // we allow more than one client; if we get an error here, we return it, but we still launch all the
    406             // updates.
    407             if (ret != kDNSServiceErr_NoError && status == kDNSServiceErr_NoError) {
    408                 status = ret;
    409             }
    410         }
    411     }
    412     return kDNSServiceErr_NoError;
    413 }
    414 
    415 // Worker function to delete a server or interface address that was previously configured.
    416 static int
    417 delete_address(service_addr_t **list, const uint8_t *port, uint16_t rrtype, const uint8_t *NONNULL rdata,
    418                uint16_t rdlen, bool interface_serial_update)
    419 {
    420     service_addr_t *addr, **p_addr;
    421 
    422     // Delete API and refresh API are incompatible.
    423     if (doing_refresh) {
    424         return kDNSServiceErr_BadState;
    425     }
    426     VALIDATE_IP_ADDR;
    427 
    428     // See if we know this address.
    429     p_addr = find_address(list, port, rrtype, rdata, rdlen);
    430     if (*p_addr != NULL) {
    431         addr = *p_addr;
    432         *p_addr = addr->next;
    433         free(addr);
    434         network_state_changed = true;
    435         if (interface_serial_update) {
    436             interface_serial++;
    437         }
    438         return kDNSServiceErr_NoError;
    439     }
    440     return kDNSServiceErr_NoSuchRecord;
    441 }
    442 
    443 // Delete a previously-configured SRP server address.  This should not be done during a refresh.
    444 int
    445 srp_delete_interface_address(uint16_t rrtype, const uint8_t *NONNULL rdata, uint16_t rdlen)
    446 {
    447     return delete_address(&interfaces, no_port, rrtype, rdata, rdlen, true);
    448 }
    449 
    450 // Delete a previously-configured SRP server address.  This should not be done during a refresh.
    451 int
    452 srp_delete_server_address(uint16_t rrtype, const uint8_t *port, const uint8_t *NONNULL rdata, uint16_t rdlen)
    453 {
    454     return delete_address(&servers, port, rrtype, rdata, rdlen, false);
    455 }
    456 
    457 // Call this to start an address refresh.   This makes sense to do in cases where the caller
    458 // is not tracking changes, but rather is just doing a full refresh whenever the network state
    459 // is seen to have changed.   When the refresh is done, if any addresses were added or removed,
    460 // network_state_changed will be true, and so a call to dnssd_network_state_change_finished()
    461 // will trigger an update; if nothing changed, no update will be sent.
    462 int
    463 srp_start_address_refresh(void)
    464 {
    465     if (doing_refresh) {
    466         return kDNSServiceErr_BadState;
    467     }
    468     doing_refresh = true;
    469     interface_refresh_state = interfaces;
    470     server_refresh_state = servers;
    471     interfaces = NULL;
    472     servers = NULL;
    473     network_state_changed = false;
    474     return kDNSServiceErr_NoError;
    475 }
    476 
    477 // Call this when the address refresh is done.   This invokes srp_network_state_stable().
    478 int
    479 srp_finish_address_refresh(bool *did_something)
    480 {
    481     service_addr_t *addr, *next;
    482     int i;
    483     if (!doing_refresh) {
    484         return kDNSServiceErr_BadState;
    485     }
    486     for (i = 0; i < 2; i++) {
    487         if (i == 0) {
    488             next = server_refresh_state;
    489             server_refresh_state = NULL;
    490         } else {
    491             if (interface_refresh_state != NULL) {
    492                 interface_serial++;
    493             }
    494             next = interface_refresh_state;
    495             interface_refresh_state = NULL;
    496         }
    497         if (next != NULL) {
    498             network_state_changed = true;
    499         }
    500         while (next) {
    501             uint8_t *rdata = (uint8_t *)&next->rr.data;
    502             // Print IPv6 address directly here because the code has to be portable for ADK, and OpenThread environment
    503             // has no support for INET6_ADDRSTRLEN.
    504             INFO("deleted " PUB_S_SRP
    505                  " address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x port %u (%x)",
    506                  i ? "interface" : "server",
    507                  rdata[0], rdata[1], rdata[2], rdata[3], rdata[4], rdata[5], rdata[6], rdata[7],
    508                  rdata[8], rdata[9], rdata[10], rdata[11], rdata[12], rdata[13], rdata[14], rdata[15],
    509                  (next->port[0] << 8) | next->port[1], (next->port[0] << 8) | next->port[1]);
    510             addr = next;
    511             next = addr->next;
    512             free(addr);
    513         }
    514     }
    515     doing_refresh = false;
    516     return srp_network_state_stable(did_something);
    517 }
    518 
    519 // Implementation of the API that the application will call to update the TXT record after having registered
    520 // a service previously with a different TXT record.   In principle this can also update a record added with
    521 // DNSServiceAddRecord or DNSServiceRegisterRecord, but we don't support those APIs at present.
    522 
    523 DNSServiceErrorType
    524 DNSServiceUpdateRecord(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags,
    525                        uint16_t rdlen, const void *rdata, uint32_t ttl)
    526 {
    527     reg_state_t *registration;
    528     void *txtRecord = NULL;
    529 
    530     (void)RecordRef;
    531     (void)flags;
    532     (void)ttl;
    533 
    534     if (sdRef == NULL || RecordRef != NULL || rdata == NULL) {
    535         return kDNSServiceErr_Invalid;
    536     }
    537 
    538     // Add it to the list (so it will appear valid to DNSServiceRefDeallocate()).
    539     for (registration = current_client->registrations; registration != NULL; registration = registration->next) {
    540         if (registration == sdRef) {
    541             break;
    542         }
    543     }
    544     if (registration == NULL) {
    545         return kDNSServiceErr_BadReference;
    546     }
    547 
    548     if (rdlen != 0) {
    549         txtRecord = malloc(rdlen);
    550         if (txtRecord == NULL) {
    551             return kDNSServiceErr_NoMemory;
    552         }
    553         memcpy(txtRecord, rdata, rdlen);
    554     } else {
    555         registration->txtRecord = NULL;
    556     }
    557 
    558     if (registration->txtRecord != NULL) {
    559         free(registration->txtRecord);
    560     }
    561 
    562     registration->txtRecord = txtRecord;
    563     registration->txtLen = rdlen;
    564     network_state_changed = true;
    565     interface_serial++;
    566     return kDNSServiceErr_NoError;
    567 }
    568 
    569 // Implementation of the API that applications will call to register services.   This is independent of the
    570 // hosting platform API.
    571 DNSServiceErrorType
    572 DNSServiceRegister(DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
    573                    const char *NULLABLE name, const char *NULLABLE regtype, const char *NULLABLE domain,
    574                    const char *NULLABLE host, uint16_t port,
    575                    uint16_t txtLen, const void *txtRecord,
    576                    DNSServiceRegisterReply callBack, void *context)
    577 {
    578     reg_state_t **rp, *reg = calloc(1, sizeof *reg);
    579     if (reg == NULL) {
    580         return kDNSServiceErr_NoMemory;
    581     }
    582 
    583     // Add it to the list (so it will appear valid to DNSServiceRefDeallocate()).
    584     rp = &current_client->registrations;
    585     while (*rp) {
    586         rp = &((*rp)->next);
    587     }
    588     *rp = reg;
    589 
    590     // If we don't already have a hostname, use the one from the registration.
    591     if (current_client->hostname == NULL) {
    592         srp_set_hostname(host, NULL);
    593     }
    594 
    595     reg->serial = current_client->registration_serial++;
    596     reg->flags = flags;
    597     reg->interfaceIndex = interfaceIndex;
    598     reg->called_back = true;
    599 #define stashName(thing)                        \
    600     if (thing != NULL) {                        \
    601         reg->thing = strdup(thing);             \
    602         if (reg->thing == NULL) {               \
    603             DNSServiceRefDeallocate(reg);       \
    604             return kDNSServiceErr_NoMemory;     \
    605         }                                       \
    606     } else {                                    \
    607         reg->thing = NULL;                      \
    608     }
    609     stashName(name);
    610     stashName(regtype);
    611     stashName(domain);
    612     stashName(host);
    613     reg->port = port;
    614     reg->txtLen = txtLen;
    615     if (txtLen != 0) {
    616         reg->txtRecord = malloc(txtLen);
    617         if (reg->txtRecord == NULL) {
    618             DNSServiceRefDeallocate(reg);
    619             return kDNSServiceErr_NoMemory;
    620         }
    621         memcpy(reg->txtRecord, txtRecord, txtLen);
    622     } else {
    623         reg->txtRecord = NULL;
    624     }
    625     reg->callback = callBack;
    626     reg->context = context;
    627     *sdRef = reg;
    628     network_state_changed = true;
    629     return kDNSServiceErr_NoError;
    630 }
    631 
    632 DNSServiceErrorType
    633 srp_update_service_type(DNSServiceRef NONNULL reg, const char *NONNULL regtype, DNSServiceRegisterReply callback, void *context)
    634 {
    635     if (reg != NULL) {
    636         client_state_t *client = NULL;
    637 
    638         for (client_state_t *cp = clients; client == NULL && cp != NULL; cp = cp->next) {
    639             // Remove it from the list.
    640             for (reg_state_t *rp = cp->registrations; client == NULL && rp != NULL; rp = rp->next) {
    641                 if (rp == reg) {
    642                     client = cp;
    643                 }
    644             }
    645         }
    646         if (client == NULL) {
    647             return kDNSServiceErr_Unknown;
    648         }
    649 
    650         stashName(regtype);
    651         reg->serial = client->registration_serial++;
    652         reg->callback = callback;
    653         reg->context = context;
    654         network_state_changed = true;
    655     } else {
    656         return kDNSServiceErr_Invalid;
    657     }
    658     return kDNSServiceErr_NoError;
    659 }
    660 
    661 void
    662 DNSServiceRefDeallocate(DNSServiceRef sdRef)
    663 {
    664     reg_state_t **rp, *reg = NULL;
    665     bool found = false;
    666     client_state_t *client;
    667 
    668     if (sdRef == NULL) {
    669         return;
    670     }
    671 
    672     for (client = clients; client; client = client->next) {
    673         // Remove it from the list.
    674         rp = &client->registrations;
    675         reg = *rp;
    676         while (*rp) {
    677             if (reg == sdRef) {
    678                 *rp = reg->next;
    679                 found = true;
    680                 break;
    681             }
    682             rp = &((*rp)->next);
    683             reg = *rp;
    684         }
    685 
    686         if (found) {
    687             break;
    688         }
    689     }
    690 
    691     // This avoids a bogus free.
    692     if (!found || reg == NULL) {
    693         return;
    694     }
    695     if (reg->name != NULL) {
    696         free(reg->name);
    697     }
    698     if (reg->regtype != NULL) {
    699         free(reg->regtype);
    700     }
    701     if (reg->domain != NULL) {
    702         free(reg->domain);
    703     }
    704     if (reg->host != NULL) {
    705         free(reg->host);
    706     }
    707     if (reg->txtRecord != NULL) {
    708         free(reg->txtRecord);
    709     }
    710     free(reg);
    711 }
    712 
    713 static void
    714 update_finalize(update_context_t *update)
    715 {
    716     client_state_t *client = update->client;
    717     INFO("%p %p %p", update, update->udp_context, update->message);
    718     if (update->udp_context != NULL) {
    719         srp_deactivate_udp_context(client->os_context, update->udp_context);
    720     }
    721     if (update->message != NULL) {
    722         free(update->message);
    723     }
    724     free(update);
    725 }
    726 
    727 static void
    728 do_callbacks(client_state_t *client, reg_state_t *registration, uint32_t serial, int err, bool succeeded)
    729 {
    730     reg_state_t *rp;
    731     bool work;
    732 
    733     // The callback can modify the list, so we use a marker to remember where we are in the list rather
    734     // than remembering a pointer which could be invalidated.  If a callback adds a registration, that
    735     // registration doesn't get called because called_back is set to true when a registration is added.
    736     for (rp = client->registrations; rp; rp = rp->next) {
    737         if (rp->serial <= serial) {
    738             rp->called_back = false;
    739         }
    740     }
    741     do {
    742         work = false;
    743         for (rp = client->registrations; rp; rp = rp->next) {
    744             if (registration != NULL && registration != rp) {
    745                 continue;
    746             }
    747             if (rp->serial > serial || rp->callback == NULL || rp->called_back) {
    748                 continue;
    749             }
    750             work = true;
    751             rp->called_back = true;
    752             if (succeeded) {
    753                 rp->succeeded = true;
    754             }
    755             if (rp->callback != NULL) {
    756                 rp->callback(rp, kDNSServiceFlagsAdd, err, rp->name, rp->regtype, rp->domain, rp->context);
    757                 break;
    758             }
    759         }
    760     } while (work);
    761 }
    762 
    763 static void
    764 udp_retransmit(void *v_update_context)
    765 {
    766     update_context_t *context = v_update_context;
    767     client_state_t *client;
    768     service_addr_t *next_server = NULL;
    769     int err;
    770 
    771     client = context->client;
    772 
    773     if (!srp_is_network_active()) {
    774         INFO("network is down, discontinuing renewals.");
    775         if (client->active_update != NULL) {
    776             update_finalize(client->active_update);
    777             client->active_update = NULL;
    778         }
    779         return;
    780     }
    781     // It shouldn't be possible for this to happen.
    782     if (client->active_update == NULL) {
    783         INFO("no active update for " PRI_S_SRP " (%p).",
    784              client->hostname ? client->hostname : "<null>", client);
    785         return;
    786     }
    787     INFO("next_attempt %" PRIu32 " next_retransmission %" PRIu32 " for " PRI_S_SRP " (%p)",
    788          context->next_attempt_time, context->next_retransmission_time,
    789          client->hostname ? client->hostname : "<null>", client);
    790 
    791     // If the interface serial number has changed, we need to generate a new update message.
    792     if (client->active_update->interface_serial != interface_serial) {
    793         client->active_update->next_retransmission_time = INITIAL_NEXT_RETRANSMISSION_TIME;
    794         client->active_update->next_attempt_time = INITIAL_NEXT_ATTEMPT_TIME;
    795         free(context->message);
    796         context->message = NULL;
    797     }
    798 
    799     // If next retransmission time is zero, this means that we gave up our last attempt to register, and have
    800     // now waited long enough to try again.  We will then use an exponential backoff for 90 seconds before giving
    801     // up again; if we give up again, we will wait longer to retry, up to an hour.
    802     else if (context->next_retransmission_time == 0) {
    803         // If there are no servers, we don't need to schedule a re-attempt: when a server is seen, we will do
    804         // an update immediately.
    805         if (servers == NULL) {
    806             return;
    807         }
    808         next_server = servers;
    809 
    810         // If this attempt fails, don't try again for a while longer, but limit the retry interval to an hour.
    811         context->next_attempt_time *= 2;
    812         if (context->next_attempt_time > client->srp_max_attempt_interval) {
    813             context->next_attempt_time = client->srp_max_attempt_interval;
    814         }
    815         context->next_retransmission_time = INITIAL_NEXT_RETRANSMISSION_TIME;
    816     }
    817     // If this would be our fourth retry on a particular server, try the next server.
    818     else if (context->next_retransmission_time > client->srp_max_retry_interval) {
    819         // If we are removing, there is no point in trying the next server--just give up and report a timeout.
    820         if (context->removing) {
    821             do_callbacks(client, NULL, context->serial, kDNSServiceErr_Timeout, false);
    822             // Once the goodbye retransmission has timed out, we're done.
    823             return;
    824         }
    825         for (next_server = servers; next_server; next_server = next_server->next) {
    826             if (next_server == context->server) {
    827                 // We're going to use the next server after the one we just tried.  If we run out of servers,
    828                 // we'll give up for a while.
    829                 next_server = next_server->next;
    830                 break;
    831             }
    832         }
    833 
    834         // If we run off the end of the list, give up for a bit.
    835         if (next_server == NULL) {
    836             context->next_retransmission_time = 0;
    837         } else {
    838             context->next_retransmission_time = INITIAL_NEXT_RETRANSMISSION_TIME;
    839         }
    840     }
    841     // Otherwise, we are still trying to win with a particular server, so back off exponentially.
    842     else {
    843         context->next_retransmission_time *= 2;
    844     }
    845 
    846     // If we are giving up on the current server, get rid of any udp state.
    847     if (context->next_retransmission_time == 0 || next_server != NULL) {
    848         if (next_server != NULL) {
    849             context->server = next_server;
    850         }
    851         srp_disconnect_udp(context->udp_context);
    852         context->connected = false;
    853         if (context->message != NULL) {
    854             free(context->message);
    855         }
    856         context->message = NULL;
    857         context->message_length = 0;
    858         context->next_retransmission_time = INITIAL_NEXT_RETRANSMISSION_TIME;
    859         context->next_attempt_time = INITIAL_NEXT_ATTEMPT_TIME;
    860     }
    861 
    862     // If we are not giving up, send the next packet.
    863     if (context->server != NULL && context->next_retransmission_time != 0) {
    864         if (!context->connected) {
    865             // Create a UDP context for this transaction.
    866             err = srp_connect_udp(context->udp_context, context->server->port, context->server->rr.type,
    867                                   (uint8_t *)&context->server->rr.data,
    868                                   context->server->rr.type == dns_rrtype_a ? 4 : 16);
    869             // In principle if it fails here, it might succeed later, so we just don't send a packet and let
    870             // the timeout take care of it.
    871             if (err != kDNSServiceErr_NoError) {
    872                 ERROR("udp_retransmit: error %d connecting udp context.", err);
    873             } else {
    874                 if (context->server->rr.type == dns_rrtype_a) {
    875 #ifdef THREAD_DEVKIT_ADK
    876                     INFO("updating server at address %d.%d.%d.%d", (context->server->rr.data.a.s_addr >> 24) & 255,
    877                          (context->server->rr.data.a.s_addr >> 16) & 255,
    878                          (context->server->rr.data.a.s_addr >> 8) & 255, (context->server->rr.data.a.s_addr) & 255);
    879 #else
    880                     IPv4_ADDR_GEN_SRP(&context->server->rr.data.a, addr_buf);
    881                     INFO("updating server at address " PRI_IPv4_ADDR_SRP,
    882                          IPv4_ADDR_PARAM_SRP(&context->server->rr.data.a, addr_buf));
    883 #endif
    884                 } else if (context->server->rr.type == dns_rrtype_aaaa) {
    885 #ifdef THREAD_DEVKIT_ADK
    886                     INFO("updating server at address "
    887                          "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
    888                          context->server->rr.data.aaaa.s6_addr[0], context->server->rr.data.aaaa.s6_addr[1],
    889                          context->server->rr.data.aaaa.s6_addr[2], context->server->rr.data.aaaa.s6_addr[3],
    890                          context->server->rr.data.aaaa.s6_addr[4], context->server->rr.data.aaaa.s6_addr[5],
    891                          context->server->rr.data.aaaa.s6_addr[6], context->server->rr.data.aaaa.s6_addr[7],
    892                          context->server->rr.data.aaaa.s6_addr[8], context->server->rr.data.aaaa.s6_addr[9],
    893                          context->server->rr.data.aaaa.s6_addr[10], context->server->rr.data.aaaa.s6_addr[11],
    894                          context->server->rr.data.aaaa.s6_addr[12], context->server->rr.data.aaaa.s6_addr[13],
    895                          context->server->rr.data.aaaa.s6_addr[14], context->server->rr.data.aaaa.s6_addr[15]);
    896 #else
    897                     SEGMENTED_IPv6_ADDR_GEN_SRP(&context->server->rr.data.aaaa, addr_buf);
    898                     INFO("updating server at address " PRI_SEGMENTED_IPv6_ADDR_SRP,
    899                          SEGMENTED_IPv6_ADDR_PARAM_SRP(&context->server->rr.data.aaaa, addr_buf));
    900 #endif
    901                 }
    902                 context->connected = true;
    903             }
    904         }
    905 
    906         if (context->message == NULL) {
    907             context->message = srp_client_generate_update(client, client->lease_time, client->key_lease_time,
    908                                                           &context->message_length, NULL, context->serial,
    909                                                           context->removing);
    910             if (context->message == NULL) {
    911                 ERROR("No memory for message.");
    912                 return;
    913             }
    914         }
    915 
    916         if (context->connected) {
    917             // Send the datagram to the server
    918             err = srp_send_datagram(client->os_context, context->udp_context, context->message, context->message_length);
    919             if (err != kDNSServiceErr_NoError) {
    920                 ERROR("udp_retransmit: error %d sending a datagram.", err);
    921             }
    922         }
    923     }
    924 
    925     // If we've given up for now, either schedule a next attempt or notify the caller; otherwise, schedule the next retransmission.
    926     if (context->next_retransmission_time == 0) {
    927         bool timeout_requested = false;
    928         reg_state_t *registration;
    929         for (registration = client->registrations; registration; registration = registration->next) {
    930             if (registration->callback != NULL && registration->serial <= context->serial &&
    931                 (registration->flags & kDNSServiceFlagsTimeout))
    932             {
    933                 timeout_requested = true;
    934             }
    935         }
    936         // If any of the callers requested a timeout, we treat it as if they all did, and call all the callbacks with the "timed out"
    937         // error.
    938         if (timeout_requested) {
    939             do_callbacks(client, NULL, context->serial, kDNSServiceErr_Timeout, false);
    940             err = kDNSServiceErr_NoError;
    941         } else {
    942             err = srp_set_wakeup(client->os_context, context->udp_context, context->next_attempt_time, udp_retransmit);
    943         }
    944     } else {
    945         err = srp_set_wakeup(client->os_context, context->udp_context,
    946                              context->next_retransmission_time - 512 + srp_random16() % 1024, udp_retransmit);
    947     }
    948     if (err != kDNSServiceErr_NoError) {
    949         INFO("error %d setting wakeup", err);
    950         // what to do?
    951     }
    952 }
    953 
    954 static void
    955 renew_callback(void *v_update_context)
    956 {
    957     update_context_t *context = v_update_context;
    958     client_state_t *client = context->client;
    959     INFO("renew callback");
    960     do_srp_update(client, true, NULL);
    961 }
    962 
    963 // This function will, if hostname_rename_number is nonzero, create a hostname using the chosen hostname plus
    964 // space plus the number as ascii text.   The caller is responsible for freeing the return value if it's not NULL.
    965 static char *
    966 conflict_print(client_state_t *client, dns_towire_state_t *towire, char **return_hostname, char *chosen_hostname)
    967 {
    968     char *conflict_hostname;
    969     size_t hostname_len;
    970 
    971     if (client->hostname_rename_number == 0) {
    972         *return_hostname = chosen_hostname;
    973         return NULL;
    974     }
    975 
    976     hostname_len = strlen(chosen_hostname);
    977     // 7 is max length of decimal short (5) plus space plus NUL
    978     if (hostname_len + 7 > DNS_MAX_LABEL_SIZE) {
    979         hostname_len = DNS_MAX_LABEL_SIZE - 7;
    980     }
    981     conflict_hostname = malloc(hostname_len + 7);
    982     if (conflict_hostname == NULL) {
    983         if (towire != NULL) {
    984             towire->line = __LINE__;
    985             towire->outer_line = -1;
    986             towire->error = true;
    987         }
    988         *return_hostname = chosen_hostname;
    989         return NULL;
    990     }
    991 
    992     memcpy(conflict_hostname, chosen_hostname, hostname_len);
    993     snprintf(conflict_hostname + hostname_len, 7, " %d", client->hostname_rename_number);
    994     *return_hostname = conflict_hostname;
    995     return conflict_hostname;
    996 }
    997 
    998 static void
    999 udp_response(void *v_update_context, void *v_message, size_t message_length)
   1000 {
   1001     update_context_t *context = v_update_context;
   1002     client_state_t *client = context->client;
   1003     dns_wire_t *message = v_message;
   1004     int err;
   1005     int rcode = dns_rcode_get(message);
   1006     (void)message_length;
   1007     uint32_t new_lease_time = 0;
   1008     bool lease_time_sent = false;
   1009     reg_state_t *registration;
   1010     const uint8_t *p = message->data;
   1011     const uint8_t *end = (const uint8_t *)v_message + message_length;
   1012     bool resolve_name_conflict = false;
   1013     char *conflict_hostname = NULL, *chosen_hostname;
   1014 
   1015     INFO("Got a response for %p, rcode = %d", client, dns_rcode_get(message));
   1016 
   1017     // Cancel the existing retransmit wakeup, since we definitely don't want to retransmit to the current
   1018     // server.
   1019     err = srp_cancel_wakeup(client->os_context, context->udp_context);
   1020     if (err != kDNSServiceErr_NoError) {
   1021         INFO("%d", err);
   1022     }
   1023 
   1024     // We want a different UDP source port for each transaction, so cancel the current UDP state.
   1025     srp_disconnect_udp(context->udp_context);
   1026     if (context->message != NULL) {
   1027         free(context->message);
   1028     }
   1029     context->message = NULL;
   1030     context->message_length = 0;
   1031     context->connected = false;
   1032     context->next_retransmission_time = INITIAL_NEXT_RETRANSMISSION_TIME;
   1033     context->next_attempt_time = INITIAL_NEXT_ATTEMPT_TIME;
   1034 
   1035     // When we are doing a remove, we don't actually care what the result is--if we get back an answer, we call
   1036     // the callback.
   1037     if (context->removing) {
   1038         do_callbacks(client, NULL, context->serial, kDNSServiceErr_NoSuchRecord, false);
   1039         goto out;
   1040     }
   1041 
   1042     // Deal with the response.
   1043     switch (rcode) {
   1044     case dns_rcode_noerror:
   1045         // Remember the server we connected with.  active_update and active_update->server should always be
   1046         // non-NULL here.
   1047         if (client->active_update != NULL) {
   1048             if (client->active_update->server != NULL) {
   1049                 // If the new server is not the one that's mentioned in stable_server, then update the one
   1050                 // in stable_server.
   1051                 if (client->active_update->server->rr.type != client->stable_server.rr.type ||
   1052                     (client->stable_server.rr.type == dns_rrtype_a
   1053                      ? memcmp(&client->stable_server.rr.data, &client->active_update->server->rr.data, 4)
   1054                      : (client->stable_server.rr.type == dns_rrtype_aaaa
   1055                         ? memcmp(&client->stable_server.rr.data, &client->active_update->server->rr.data, 16)
   1056                         : true)) ||
   1057                     memcmp(client->stable_server.port, client->active_update->server->port, 2))
   1058                 {
   1059                     memcpy(&client->stable_server, client->active_update->server, sizeof(client->stable_server));
   1060                     client->srp_server_synced = false;
   1061                 }
   1062                 sync_to_stable_storage(client->active_update);
   1063             }
   1064             client->active_update->interface_serial = interface_serial;
   1065         }
   1066 
   1067         for (reg_state_t *rp = client->registrations; rp != NULL; rp = rp->next) {
   1068             if (rp->removing) {
   1069                 INFO("removal for " PRI_S_SRP "." PRI_S_SRP " completed.", rp->name, rp->regtype);
   1070                 do_callbacks(client, rp, context->serial, kDNSServiceErr_NoSuchRecord, false);
   1071                 rp->skip = true; // The caller should do DNSServiceRefDeallocate, but if they don't, we don't want
   1072                                  // to either continually send removes, nor to send the update again.
   1073             }
   1074         }
   1075 
   1076         // Get the renewal time
   1077         // At present, there's no code to actually parse a real DNS packet in the client, so
   1078         // we rely on the server returning just an EDNS0 option; if this assumption fails, we
   1079         // are out of luck.
   1080         if (message->qdcount == 0 && message->ancount == 0 && message->nscount == 0 && ntohs(message->arcount) == 1 &&
   1081             // We expect the edns0 option to be:
   1082             // root label - 1 byte
   1083             // type = 2 bytes
   1084             // class = 2 bytes
   1085             // ttl = 4 bytes
   1086             // rdlength = 2 bytes
   1087             // total of 11 bytes
   1088             // data
   1089             end - p > 11 && // Enough room for an EDNS0 option
   1090             *p == 0 &&       // root label
   1091             p[1] == (dns_rrtype_opt >> 8) && p[2] == (dns_rrtype_opt & 255)) // opt rrtype
   1092         {
   1093             // skip class and ttl, we don't care
   1094             const uint8_t *opt_start = &p[11]; // Start of opt data
   1095             uint16_t opt_len = (((uint16_t)p[9]) << 8) + p[10]; // length of opt data
   1096             const uint8_t *opt_cur = opt_start;
   1097             uint16_t opt_remaining = opt_len;
   1098             // Scan for options until there's no room.
   1099             while (opt_cur + 4 <= end) {
   1100                 int option_code = (((uint16_t)opt_cur[0]) << 8) + opt_cur[1];
   1101                 int option_len =  (((uint16_t)opt_cur[2]) << 8) + opt_cur[3];
   1102                 const uint8_t *option_data = opt_cur + 4;
   1103                 if (option_len + option_data <= end) {
   1104                     if (option_code == dns_opt_update_lease) {
   1105                         if (option_len == 8) {
   1106                             new_lease_time = (((uint32_t)option_data[0] << 24) | ((uint32_t)option_data[1] << 16) |
   1107                                               ((uint32_t)option_data[2] << 8) | ((uint32_t)option_data[3]));
   1108                             INFO("Lease time set to %" PRIu32, new_lease_time);
   1109                             lease_time_sent = true;
   1110                         }
   1111                     }
   1112                 }
   1113                 opt_cur = option_data + option_len;
   1114                 opt_remaining = opt_remaining - (option_len + 4);
   1115             }
   1116         }
   1117 
   1118         if (!lease_time_sent) {
   1119             new_lease_time = context->lease_time;
   1120             INFO("Lease time defaults to %" PRIu32, new_lease_time);
   1121             DEBUG("len %zd qd %d an %d ns %d ar %d data %02x %02x %02x %02x %02x %02x %02x %02x %02x"
   1122                   " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
   1123                   end - p, ntohs(message->qdcount), ntohs(message->ancount),
   1124                   ntohs(message->nscount), ntohs(message->arcount),
   1125                   p[0], p[1], p[2], p[3], p[3], p[5], p[6], p[7], p[8], p[9], p[10], p[11],
   1126                   p[12], p[13], p[14], p[15], p[16], p[17], p[18], p[19], p[20], p[21], p[22]);
   1127         }
   1128 
   1129         // Set up to renew.  Time is in milliseconds, and we want to renew at 80% of the lease time.
   1130         srp_set_wakeup(client->os_context, context->udp_context, (new_lease_time * 1000) * 8 / 10, renew_callback);
   1131 
   1132         do_callbacks(client, NULL, context->serial, kDNSServiceErr_NoError, true);
   1133         break;
   1134     case dns_rcode_yxdomain:
   1135         // Get the actual hostname that we sent.
   1136         if (client->hostname_conflict_callback != NULL && client->hostname != NULL) {
   1137             conflict_hostname = conflict_print(client, NULL, &chosen_hostname, client->hostname);
   1138             client->hostname_conflict_callback(chosen_hostname);
   1139             if (conflict_hostname != NULL) {
   1140                 free(conflict_hostname);
   1141             }
   1142         }
   1143 
   1144         bool resolve_with_callback = false;
   1145         for (registration = client->registrations; registration; registration = registration->next) {
   1146             if (registration->callback != NULL && registration->serial <= context->serial &&
   1147                 (registration->flags & kDNSServiceFlagsNoAutoRename))
   1148             {
   1149                 resolve_with_callback = true;
   1150             }
   1151         }
   1152         if (resolve_with_callback) {
   1153             do_callbacks(client, NULL, context->serial, kDNSServiceErr_NameConflict, false);
   1154             resolve_name_conflict = false;
   1155         } else {
   1156             resolve_name_conflict = true;
   1157         }
   1158 
   1159         if (resolve_name_conflict) {
   1160             // If we get a name conflict, try using a low number to rename, but only twice; it's time consuming to do
   1161             // this, so if we get two conflicts, we switch to using a random number.
   1162             if (client->hostname_rename_number < 2) {
   1163                 client->hostname_rename_number++;
   1164             } else {
   1165                 client->hostname_rename_number = srp_random16();
   1166             }
   1167             // When we get a name conflict response, we need to re-do the update immediately
   1168             // (with a 0-500ms delay of course).
   1169             do_srp_update(client, true, NULL);
   1170             return;
   1171         }
   1172         break;
   1173 
   1174     default:
   1175         // If we get here, it means that the server failed to process the transmission, and there is no
   1176         // action we can take to change the situation other than trying another server. We set the
   1177         // retransmission time for the current server long enough to force a switch to the next server,
   1178         // if any.
   1179         context->next_retransmission_time = client->srp_max_retry_interval + 1;
   1180         err = srp_set_wakeup(client->os_context, context->udp_context,
   1181                              context->next_retransmission_time - 512 + srp_random16() % 1024, udp_retransmit);
   1182         return;
   1183     }
   1184 out:
   1185     if (client->active_update != NULL) {
   1186         client->active_update->serial = client->registration_serial;
   1187     }
   1188 }
   1189 
   1190 // Generate a new SRP update message
   1191 dns_wire_t *
   1192 srp_client_generate_update(client_state_t *client, uint32_t update_lease_time, uint32_t update_key_lease_time,
   1193                            size_t *NONNULL p_length, dns_wire_t *in_wire, uint32_t serial, bool removing)
   1194 {
   1195     dns_wire_t *message;
   1196     const char *zone_name = "default.service.arpa";
   1197     const char *service_type = "_ipps._tcp";
   1198     const char *txt_record = "0";
   1199     uint16_t key_tag;
   1200     dns_towire_state_t towire;
   1201     dns_name_pointer_t p_host_name;
   1202     dns_name_pointer_t p_zone_name;
   1203     dns_name_pointer_t p_service_name;
   1204     dns_name_pointer_t p_service_instance_name;
   1205     int line;
   1206     service_addr_t *addr;
   1207     reg_state_t *reg;
   1208     char *conflict_hostname = NULL, *chosen_hostname;
   1209 
   1210 #define INCREMENT(x) (x) = htons(ntohs(x) + 1)
   1211     memset(&towire, 0, sizeof towire);
   1212 
   1213     // Get the key if we don't already have it.
   1214     if (client->key == NULL) {
   1215         client->key = srp_get_key("com.apple.srp-client.host-key", client->os_context);
   1216         if (client->key == NULL) {
   1217             INFO("No key gotten.");
   1218             return NULL;
   1219         }
   1220     }
   1221 
   1222 #define CH if (towire.error) { line = __LINE__; goto fail; }
   1223 
   1224     if (client->hostname == NULL) {
   1225         ERROR("called with NULL hostname.");
   1226         return NULL;
   1227     }
   1228 
   1229     // If we were given a message buffer, use it, otherwise allocate one.
   1230     if (in_wire != NULL) {
   1231         message = in_wire;
   1232         towire.p = &message->data[0];
   1233         towire.lim = towire.p + *p_length;
   1234         towire.message = in_wire;
   1235     } else {
   1236         // Allocate a message buffer.
   1237         message = calloc(1, sizeof *message);
   1238         if (message == NULL) {
   1239             return NULL;
   1240         }
   1241         towire.p = &message->data[0];               // We start storing RR data here.
   1242         towire.lim = &message->data[DNS_DATA_SIZE]; // This is the limit to how much we can store.
   1243         towire.message = message;
   1244     }
   1245 
   1246     // Generate a random UUID.
   1247     message->id = srp_random16();
   1248     message->bitfield = 0;
   1249     dns_qr_set(message, dns_qr_query);
   1250     dns_opcode_set(message, dns_opcode_update);
   1251 
   1252     message->qdcount = 0;
   1253     // Copy in Zone name (and save pointer)
   1254     // ZTYPE = SOA
   1255     // ZCLASS = IN
   1256     dns_full_name_to_wire(&p_zone_name, &towire, zone_name); CH;
   1257     dns_u16_to_wire(&towire, dns_rrtype_soa); CH;
   1258     dns_u16_to_wire(&towire, dns_qclass_in); CH;
   1259     INCREMENT(message->qdcount);
   1260 
   1261     message->ancount = 0;
   1262     // PRCOUNT = 0
   1263 
   1264     message->nscount = 0;
   1265     // UPCOUNT = ...
   1266 
   1267     // Host Description:
   1268     //  * Delete all RRsets from <hostname>; remember the pointer to hostname
   1269     //      NAME = hostname label followed by pointer to SOA name.
   1270     //      TYPE = ANY
   1271     //      CLASS = ANY
   1272     //      TTL = 0
   1273     //      RDLENGTH = 0
   1274 
   1275     conflict_hostname = conflict_print(client, &towire, &chosen_hostname, client->hostname); CH;
   1276     dns_name_to_wire(&p_host_name, &towire, chosen_hostname); CH;
   1277     dns_pointer_to_wire(&p_host_name, &towire, &p_zone_name); CH;
   1278     dns_u16_to_wire(&towire, dns_rrtype_any); CH;
   1279     dns_u16_to_wire(&towire, dns_qclass_any); CH;
   1280     dns_ttl_to_wire(&towire, 0); CH;
   1281     dns_u16_to_wire(&towire, 0); CH;
   1282     INCREMENT(message->nscount);
   1283 
   1284     //  * Add addresses: A and/or AAAA RRsets, each of which contains one
   1285     //    or more A or AAAA RRs.
   1286     //      NAME = pointer to hostname from Delete (above)
   1287     //      TYPE = A or AAAA
   1288     //      CLASS = IN
   1289     //      TTL = 3600 ?
   1290     //      RDLENGTH = number of RRs * RR length (4 or 16)
   1291     //      RDATA = <the data>
   1292     if (!removing) {
   1293         for (addr = interfaces; addr; addr = addr->next) {
   1294             dns_pointer_to_wire(NULL, &towire, &p_host_name); CH;
   1295             dns_u16_to_wire(&towire, addr->rr.type); CH;
   1296             dns_u16_to_wire(&towire, dns_qclass_in); CH;
   1297             dns_ttl_to_wire(&towire, 3600); CH;
   1298             dns_rdlength_begin(&towire); CH;
   1299             dns_rdata_raw_data_to_wire(&towire, &addr->rr.data,
   1300                                        addr->rr.type == dns_rrtype_a ? 4 : 16); CH;
   1301             dns_rdlength_end(&towire); CH;
   1302             INCREMENT(message->nscount);
   1303         }
   1304    }
   1305 
   1306     //  * Exactly one KEY RR:
   1307     //      NAME = pointer to hostname from Delete (above)
   1308     //      TYPE = KEY
   1309     //      CLASS = IN
   1310     //      TTL = 3600
   1311     //      RDLENGTH = length of key + 4 (32 bits)
   1312     //      RDATA = <flags(16) = 0000 0010 0000 0001, protocol(8) = 3, algorithm(8) = 8?, public key(variable)>
   1313     dns_pointer_to_wire(NULL, &towire, &p_host_name); CH;
   1314     dns_u16_to_wire(&towire, dns_rrtype_key); CH;
   1315     dns_u16_to_wire(&towire, dns_qclass_in); CH;
   1316     dns_ttl_to_wire(&towire, 3600); CH;
   1317     dns_rdlength_begin(&towire); CH;
   1318     key_tag = dns_rdata_key_to_wire(&towire, 0, 2, 1, client->key); CH;
   1319     dns_rdlength_end(&towire); CH;
   1320     INCREMENT(message->nscount);
   1321 
   1322     // If we are removing the host, we don't need to send instances.
   1323     if (!removing) {
   1324 
   1325         // Emit any registrations.
   1326         for (reg = client->registrations; reg; reg = reg->next) {
   1327             // Only remove the registrations that are actually registered. Normally this will be all of them, but it's
   1328             // possible for a registration to be added but not to have been updated yet, and then for us to get a remove
   1329             // call, in which case we don't need to remove it.
   1330             if (((removing || reg->removing) && reg->serial > serial) || reg->skip) {
   1331                 continue;
   1332             }
   1333 
   1334             // Service:
   1335             //   * Update PTR RR
   1336             //     NAME = service name (_a._b.service.arpa)
   1337             //     TYPE = PTR
   1338             //     CLASS = IN
   1339             //     TTL = 3600
   1340             //     RDLENGTH = 2
   1341             //     RDATA = service instance name
   1342 
   1343             // Service registrations can have subtypes, in which case we need to send multiple PTR records, one for
   1344             // the main type and one for each subtype. Subtypes are represented in the regtype by following the
   1345             // primary service type with subtypes, separated by commas. So we have to parse through that to get
   1346             // the actual domain names to register.
   1347             const char *commap = reg->regtype == NULL ? service_type : reg->regtype;
   1348             dns_name_pointer_t p_sub_service_name;
   1349             bool primary = true;
   1350             do {
   1351                 char regtype[DNS_MAX_LABEL_SIZE_ESCAPED + 6]; // plus NUL, ._sub
   1352                 int i;
   1353                 // Copy the next service type into regtype, ending when we hit the end of reg->regtype
   1354                 // or when we hit a comma.
   1355                 for (i = 0; *commap != '\0' && *commap != ',' && i < DNS_MAX_LABEL_SIZE_ESCAPED; i++) {
   1356                     regtype[i] = *commap;
   1357                     commap++;
   1358                 }
   1359 
   1360                 // If we hit a comma, skip over the comma for the beginning of the next subtype.
   1361                 if (*commap == ',') {
   1362                     commap++;
   1363                 }
   1364 
   1365                 // If we aren't at a NULL or a comma, it means that the label was too long, so the output
   1366                 // is invalid.
   1367                 else if (*commap != '\0') {
   1368                     towire.error = ENOBUFS; CH;
   1369                 }
   1370 
   1371                 // First time through, it's the base type, so emit the service name and a pointer to the
   1372                 // zone name. Other times through, it's a subtype, so the pointer is now to the base type,
   1373                 // and since the API makes ._sub implicit, we have to add that.
   1374                 if (primary) {
   1375                     regtype[i] = 0;
   1376                     dns_name_to_wire(&p_service_name, &towire, regtype); CH;
   1377                     dns_pointer_to_wire(&p_service_name, &towire, &p_zone_name); CH;
   1378                 } else {
   1379                     // Copy in the string and the NUL. We know there's space (see above).
   1380                     memcpy(&regtype[i], "._sub", 6);
   1381                     dns_name_to_wire(&p_sub_service_name, &towire, regtype); CH;
   1382                     dns_pointer_to_wire(&p_sub_service_name, &towire, &p_service_name); CH;
   1383                 }
   1384                 dns_u16_to_wire(&towire, dns_rrtype_ptr); CH;
   1385                 if (reg->removing) {
   1386                     dns_u16_to_wire(&towire, dns_qclass_none); CH;
   1387                     dns_ttl_to_wire(&towire, 0); CH;
   1388                 } else {
   1389                     dns_u16_to_wire(&towire, dns_qclass_in); CH;
   1390                     dns_ttl_to_wire(&towire, 3600); CH;
   1391                 }
   1392                 dns_rdlength_begin(&towire); CH;
   1393                 if (reg->name != NULL) {
   1394                     char *service_instance_name, *to_free = conflict_print(client, &towire, &service_instance_name, reg->name);
   1395                     dns_name_to_wire(&p_service_instance_name, &towire, service_instance_name); CH;
   1396                     if (to_free != NULL) {
   1397                         free(to_free);
   1398                     }
   1399                 } else {
   1400                     dns_name_to_wire(&p_service_instance_name, &towire, chosen_hostname); CH;
   1401                 }
   1402                 dns_pointer_to_wire(&p_service_instance_name, &towire, &p_service_name); CH;
   1403                 dns_rdlength_end(&towire); CH;
   1404                 INCREMENT(message->nscount);
   1405                 primary = false;
   1406                 // We don't need to remove subtypes: removing the instance removes all its subtypes.
   1407                 if (reg->removing) {
   1408                     break;
   1409                 }
   1410             } while (*commap != '\0');
   1411 
   1412             // Service Instance:
   1413             //   * Delete all RRsets from service instance name
   1414             //      NAME = service instance name (save pointer to service name, which is the second label)
   1415             //      TYPE = ANY
   1416             //      CLASS = ANY
   1417             //      TTL = 0
   1418             //      RDLENGTH = 0
   1419             dns_pointer_to_wire(NULL, &towire, &p_service_instance_name); CH;
   1420             dns_u16_to_wire(&towire, dns_rrtype_any); CH;
   1421             dns_u16_to_wire(&towire, dns_qclass_any); CH;
   1422             dns_ttl_to_wire(&towire, 0); CH;
   1423             dns_u16_to_wire(&towire, 0); CH;
   1424             INCREMENT(message->nscount);
   1425 
   1426             if (!reg->removing) {
   1427                 //   * Add one SRV RRset pointing to Host Description
   1428                 //      NAME = pointer to service instance name from above
   1429                 //      TYPE = SRV
   1430                 //      CLASS = IN
   1431                 //      TTL = 3600
   1432                 //      RDLENGTH = 8
   1433                 //      RDATA = <priority(16) = 0, weight(16) = 0, port(16) = service port, target = pointer to hostname>
   1434                 dns_pointer_to_wire(NULL, &towire, &p_service_instance_name); CH;
   1435                 dns_u16_to_wire(&towire, dns_rrtype_srv); CH;
   1436                 dns_u16_to_wire(&towire, dns_qclass_in); CH;
   1437                 dns_ttl_to_wire(&towire, 3600); CH;
   1438                 dns_rdlength_begin(&towire); CH;
   1439                 dns_u16_to_wire(&towire, 0); CH; // priority
   1440                 dns_u16_to_wire(&towire, 0); CH; // weight
   1441                 dns_u16_to_wire(&towire, reg->port); CH; // port
   1442                 dns_pointer_to_wire(NULL, &towire, &p_host_name); CH;
   1443                 dns_rdlength_end(&towire); CH;
   1444                 INCREMENT(message->nscount);
   1445 
   1446                 //   * Add one or more TXT records
   1447                 //      NAME = pointer to service instance name from above
   1448                 //      TYPE = TXT
   1449                 //      CLASS = IN
   1450                 //      TTL = 3600
   1451                 //      RDLENGTH = <length of text>
   1452                 //      RDATA = <text>
   1453                 dns_pointer_to_wire(NULL, &towire, &p_service_instance_name); CH;
   1454                 dns_u16_to_wire(&towire, dns_rrtype_txt); CH;
   1455                 dns_u16_to_wire(&towire, dns_qclass_in); CH;
   1456                 dns_ttl_to_wire(&towire, 3600); CH;
   1457                 dns_rdlength_begin(&towire); CH;
   1458                 if (reg->txtRecord != NULL) {
   1459                     dns_rdata_raw_data_to_wire(&towire, reg->txtRecord, reg->txtLen);
   1460                 } else {
   1461                     dns_rdata_txt_to_wire(&towire, txt_record); CH;
   1462                 }
   1463                 dns_rdlength_end(&towire); CH;
   1464                 INCREMENT(message->nscount);
   1465             }
   1466         }
   1467     }
   1468 
   1469     // What about services with more than one name?   Are these multiple service descriptions?
   1470 
   1471     // ARCOUNT = 2
   1472     //   EDNS(0) options
   1473     //     ...
   1474     //   SIG(0)
   1475 
   1476     message->arcount = 0;
   1477     dns_edns0_header_to_wire(&towire, DNS_MAX_UDP_PAYLOAD, 0, 0, 1); CH; // XRCODE = 0; VERSION = 0; DO=1
   1478     dns_rdlength_begin(&towire); CH;
   1479     dns_u16_to_wire(&towire, dns_opt_update_lease); CH;  // OPTION-CODE
   1480     dns_edns0_option_begin(&towire); CH;                 // OPTION-LENGTH
   1481     if (removing) {
   1482         // If we are removing the record, lease time should be zero. Key_lease_time can be nonzero, but we
   1483         // aren't currently offering a way to do that in the server. Nevertheless, we send a key lease time.
   1484         dns_u32_to_wire(&towire, 0); CH;
   1485         dns_u32_to_wire(&towire, update_key_lease_time); CH;
   1486     } else {
   1487         dns_u32_to_wire(&towire, update_lease_time); CH;     // LEASE (e.g. 1 hour)
   1488         dns_u32_to_wire(&towire, update_key_lease_time); CH; // KEY-LEASE (7 days)
   1489     }
   1490     dns_edns0_option_end(&towire); CH;                   // Now we know OPTION-LENGTH
   1491     dns_rdlength_end(&towire); CH;
   1492     INCREMENT(message->arcount);
   1493 
   1494     // The signature must be computed before counting the signature RR in the header counts.
   1495     dns_sig0_signature_to_wire(&towire,
   1496                                client->key, key_tag, &p_host_name, chosen_hostname, zone_name, srp_timenow()); CH;
   1497     INCREMENT(message->arcount);
   1498     *p_length = towire.p - (uint8_t *)message;
   1499 
   1500     if (conflict_hostname != NULL) {
   1501         free(conflict_hostname);
   1502     }
   1503     return message;
   1504 
   1505 fail:
   1506     if (conflict_hostname != NULL) {
   1507         free(conflict_hostname);
   1508     }
   1509 
   1510     if (towire.error) {
   1511         ERROR("Ran out of message space at srp-client.c:%d (%d, %d)",
   1512               line, towire.line, towire.outer_line);
   1513     }
   1514     if (client->active_update != NULL) {
   1515         update_finalize(client->active_update);
   1516         client->active_update = NULL;
   1517     }
   1518     if (in_wire == NULL && message != NULL) {
   1519         free(message);
   1520     }
   1521     return NULL;
   1522 }
   1523 
   1524 // Send SRP updates for host records that have changed.
   1525 static int
   1526 do_srp_update(client_state_t *client, bool definite, bool *did_something)
   1527 {
   1528     int err;
   1529     service_addr_t *server;
   1530 
   1531     // Cancel any ongoing active update.
   1532     if (!definite && client->active_update != NULL && client->registration_serial == client->active_update->serial) {
   1533         bool server_changed = true;
   1534         for (server = servers; server != NULL; server = server->next) {
   1535             if (server == client->active_update->server) {
   1536                 server_changed = false;
   1537             }
   1538         }
   1539         if (client->active_update->interface_serial == interface_serial && !server_changed) {
   1540             INFO("addresses to register are the same; server is the same.");
   1541             return kDNSServiceErr_NoError;
   1542         }
   1543     }
   1544 
   1545     // At this point we're definitely doing something.
   1546     if (did_something) {
   1547         *did_something = true;
   1548     }
   1549 
   1550     // Get rid of the previous update, if any.
   1551     if (client->active_update != NULL) {
   1552         update_finalize(client->active_update);
   1553         client->active_update = NULL;
   1554     }
   1555 
   1556     // Make an update context.
   1557     update_context_t *active_update = calloc(1, sizeof(*active_update));
   1558     if (active_update == NULL) {
   1559         err = kDNSServiceErr_NoMemory;
   1560     } else {
   1561         // If possible, use the server we used last time.
   1562         active_update->client = client;
   1563         sync_from_stable_storage(active_update);
   1564         if (active_update->server == NULL) {
   1565             active_update->server = servers;
   1566         }
   1567         active_update->serial = client->registration_serial;
   1568         active_update->message = NULL;
   1569         active_update->message_length = 0;
   1570         active_update->lease_time = client->lease_time;
   1571         active_update->key_lease_time = client->key_lease_time;
   1572         err = srp_make_udp_context(client->os_context, &active_update->udp_context, udp_response, active_update);
   1573 
   1574         if (err == kDNSServiceErr_NoError) {
   1575             // XXX use some random jitter on these times.
   1576             active_update->next_retransmission_time = INITIAL_NEXT_RETRANSMISSION_TIME;
   1577             active_update->next_attempt_time = INITIAL_NEXT_ATTEMPT_TIME;
   1578             err = srp_set_wakeup(client->os_context, active_update->udp_context, srp_random16() % 1023, udp_retransmit);
   1579         }
   1580     }
   1581     client->active_update = active_update;
   1582     return err;
   1583 }
   1584 
   1585 // Deregister all existing registrations.
   1586 int
   1587 srp_deregister(void *os_context)
   1588 {
   1589     reg_state_t *rp;
   1590     bool something_to_deregister = false;
   1591     client_state_t *client;
   1592 
   1593     for (client = clients; client; client = client->next) {
   1594         if (client->os_context == os_context) {
   1595             break;
   1596         }
   1597     }
   1598     if (client == NULL) {
   1599         return kDNSServiceErr_Invalid;
   1600     }
   1601 
   1602     if (client->active_update == NULL) {
   1603         INFO("no active update.");
   1604         return kDNSServiceErr_NoSuchRecord;
   1605     }
   1606 
   1607     // See if there are any registrations that have succeeded.
   1608     for (rp = client->registrations; rp; rp = rp->next) {
   1609         if (rp->serial <= client->active_update->serial && rp->succeeded) {
   1610             something_to_deregister = true;
   1611         }
   1612     }
   1613 
   1614     // If so, start a deregistration update; otherwise return NoSuchRecord.
   1615     if (something_to_deregister) {
   1616         if (client->active_update->message) {
   1617             free(client->active_update->message);
   1618             client->active_update->message = NULL;
   1619         }
   1620         client->active_update->removing = true;
   1621         client->active_update->next_retransmission_time = INITIAL_NEXT_RETRANSMISSION_TIME;
   1622         client->active_update->next_attempt_time = INITIAL_NEXT_ATTEMPT_TIME;
   1623         udp_retransmit(client->active_update);
   1624         return kDNSServiceErr_NoError;
   1625     } else {
   1626         return kDNSServiceErr_NoSuchRecord;
   1627     }
   1628 }
   1629 
   1630 // Deregister a specific registration
   1631 int
   1632 srp_deregister_instance(DNSServiceRef sdRef)
   1633 {
   1634     client_state_t *client;
   1635     reg_state_t *rp;
   1636 
   1637     // We only expect to find one match.
   1638     for (client = clients; client; client = client->next) {
   1639         for (rp = client->registrations; rp; rp = rp->next) {
   1640             if (rp == sdRef) {
   1641                 goto found;
   1642             }
   1643         }
   1644     }
   1645     return kDNSServiceErr_NoSuchRecord;
   1646 found:
   1647     rp->removing = true;
   1648     if (client->active_update != NULL) {
   1649         if (client->active_update->message) {
   1650             free(client->active_update->message);
   1651             client->active_update->message = NULL;
   1652         }
   1653         client->active_update->next_retransmission_time = INITIAL_NEXT_RETRANSMISSION_TIME;
   1654         client->active_update->next_attempt_time = INITIAL_NEXT_ATTEMPT_TIME;
   1655         udp_retransmit(client->active_update);
   1656     }
   1657     return kDNSServiceErr_NoError;
   1658 }
   1659 
   1660 #ifdef THREAD_DEVKIT_ADK
   1661 uint32_t
   1662 srp_timenow(void)
   1663 {
   1664     return 0;
   1665 }
   1666 #endif // THREAD_DEVKIT_ADK
   1667 
   1668 // Local Variables:
   1669 // mode: C
   1670 // tab-width: 4
   1671 // c-file-style: "bsd"
   1672 // c-basic-offset: 4
   1673 // fill-column: 108
   1674 // indent-tabs-mode: nil
   1675 // End:
   1676