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