Home | History | Annotate | Line # | Download | only in ServiceRegistration
      1 /* dnssd-proxy.c
      2  *
      3  * Copyright (c) 2018-2024 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  * This is a Discovery Proxy module for the SRP gateway.
     18  *
     19  * The motivation here is that it makes sense to co-locate the SRP relay and the Discovery Proxy because
     20  * these functions are likely to co-exist on the same node, listening on the same port.  For homenet-style
     21  * name resolution, we need a DNS proxy that implements DNSSD Discovery Proxy for local queries, but
     22  * forwards other queries to an ISP resolver.  The SRP gateway is already expecting to do this.
     23  * This module implements the functions required to allow the SRP gateway to also do Discovery Relay.
     24  *
     25  * The Discovery Proxy relies on Apple's DNS-SD library and the mDNSResponder DNSSD server, which is included
     26  * in Apple's open source mDNSResponder package, available here:
     27  *
     28  *            https://opensource.apple.com/tarballs/mDNSResponder/
     29  */
     30 
     31 #ifndef __APPLE_USE_RFC_3542
     32     #define __APPLE_USE_RFC_3542
     33 #endif // #ifndef __APPLE_USE_RFC_3542
     34 
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <stdio.h>
     38 #include <unistd.h>
     39 #include <errno.h>
     40 #include <sys/socket.h>
     41 #include <netinet/in.h>
     42 #include <arpa/inet.h>
     43 #include <fcntl.h>
     44 #include <sys/time.h>
     45 #include <ctype.h>
     46 #include <sys/types.h>
     47 #include <ifaddrs.h>
     48 #include <net/if.h>
     49 #include <stdarg.h>
     50 #include <notify.h>
     51 #ifdef IOLOOP_MACOS
     52 #include <AssertMacros.h>
     53 #include <SystemConfiguration/SystemConfiguration.h>
     54 #endif // #ifdef IOLOOP_MACOS
     55 
     56 #include "dns_sd.h"
     57 #include "srp.h"
     58 #include "dns-msg.h"
     59 #include "srp-crypto.h"
     60 #include "ioloop.h"
     61 #include "dso-utils.h"
     62 #include "dso.h"
     63 #include "srp-tls.h"
     64 #include "config-parse.h"
     65 #include "srp-mdns-proxy.h"
     66 #include "dnssd-proxy.h"
     67 #include "srp-tls.h"
     68 #include "srp-gw.h"
     69 #include "srp-proxy.h"
     70 #include "cti-services.h"
     71 #include "route.h"
     72 #include "srp-replication.h"
     73 #if THREAD_DEVICE
     74 #  include "state-machine.h"
     75 #  include "service-publisher.h"
     76 #endif
     77 #if SRP_FEATURE_NAT64
     78 #include "dns_sd_private.h"
     79 #include "nat64-macos.h"
     80 #endif
     81 #include "advertising_proxy_services.h"
     82 #include "srp-dnssd.h"
     83 
     84 #define RESPONSE_WINDOW_MSECS 800
     85 #define RESPONSE_WINDOW_USECS (RESPONSE_WINDOW_MSECS * 1000) // 800ms in microseconds.
     86 
     87 extern srp_server_t *srp_servers;
     88 #define SERIAL(x) ((x) == NULL ? 0 : (x)->serial)
     89 
     90 // When do we build dnssd-proxy?
     91 // 1. When we are integrating dnssd-proxy into srp-mdns-proxy: SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY == 1
     92 // 2. When we are building standalone dnssd-proxy: !defined(BUILD_SRP_MDNS_PROXY) || (BUILD_SRP_MDNS_PROXY == 0)
     93 // When do we not build dnssd-proxy?
     94 // 3. When we are building srp-mdns-proxy without dnssd-proxy: other than the two cases above.
     95 #if (SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY) || (!defined(BUILD_SRP_MDNS_PROXY) || (BUILD_SRP_MDNS_PROXY == 0))
     96 
     97 // Enumerate the list of interfaces, map them to interface indexes, give each one a name
     98 // Have a tree of subdomains for matching
     99 
    100 // Structures
    101 
    102 typedef struct interface_addr interface_addr_t;
    103 struct interface_addr {
    104     interface_addr_t *next;
    105     addr_t addr, mask;
    106 };
    107 
    108 typedef struct dp_interface dp_interface_t;
    109 struct dp_interface {
    110     int ifindex;                            // The interface index (for use with sendmsg() and recvmsg().
    111     bool no_push;                           // If true, don't set up DNS Push for this domain
    112     char *NONNULL name;                     // The name of the interface
    113     interface_addr_t *NULLABLE addresses;   // Addresses on this interface.
    114 };
    115 
    116 typedef struct hardwired hardwired_t;
    117 struct hardwired {
    118     hardwired_t *NULLABLE next;
    119     uint16_t type;
    120     char *NONNULL name;
    121     char *NONNULL fullname;
    122     uint8_t *NULLABLE rdata;
    123     uint16_t rdlen;
    124 };
    125 
    126 typedef struct question question_t;
    127 typedef struct answer answer_t;
    128 typedef struct served_domain served_domain_t;
    129 struct served_domain {
    130     served_domain_t *NULLABLE next;             // Active configurations, used for identifying a domain that matches
    131     char *NONNULL domain;                       // The domain name of the interface, represented as a text string.
    132     char *NONNULL domain_ld;                    // The same name, with a leading dot (if_domain_lp == if_domain + 1)
    133     dns_name_t *NONNULL domain_name;            // The domain name, parsed into labels.
    134     hardwired_t *NULLABLE hardwired_responses;  // Hardwired responses for this interface.
    135     dp_interface_t *NULLABLE interface;         // Interface to which this domain applies (may be NULL).
    136     question_t *NULLABLE questions;             // Questions that have been asked in the served domain.
    137 };
    138 
    139 // There are two ways that a dnssd_query_t can be created. One is that a DNS datagram comes in that's a DNS
    140 // query.  In this case, we create the query, ask the question, generate a single DNS response, send it, and
    141 // the dnssd query is finished. We could optimize retransmissions, but currently do not. UDP queries can
    142 // happen either over a TCP connection or a UDP connection--the behavior is the same in either case.  The
    143 // other way is that it can be a DNS Push subscribe. A DNS Push subscribe query is finished either when the
    144 // connection dies, or when we get a corresponding unsubscribe.
    145 
    146 // For DNS Push queries, there is an "activity" object which tracks a particular subscription. Each activity
    147 // can hold a reference to the comm_t. A disconnect from the comm_t should cancel all activities. Otherwise,
    148 // the lifecycle of activities should not affect the comm_t.
    149 
    150 // For DNS queries, a disconnect should cancel every query associated with the connection. This is complicated
    151 // by the fact that we are not tracking outstanding queries--the query survives because the dnssd_txn_t object
    152 // holds a reference to it; when the txn_t goes away, the connection will have no remaining references.
    153 
    154 // In order to make this work, dnssd_query_t objects are tracked per connection. Dnssd_query_t objects do not
    155 // hold a reference to their comm_t, but rather to their tracker.
    156 
    157 // When a connection drops, the tracker object gets a disconnect callback, which triggers it to cancel out any
    158 // remaining DNS transactions, and to cancel the associated DSO object. Cancelling the DSO object cancels all
    159 // of the activities on that object; each activity is a dnssd_query_t object. Consequently, the tracker does
    160 // not directly track DSO activities.
    161 
    162 // In order to follow RFC 7766, the tracker keeps an idle timer going. If no DNS messages have been received
    163 // on a connection for that amount of time, the tracker closes the connection; when the disconnect event arrives,
    164 // the tracker is collected. If there is a DSO object on the tracker, the tracker is not responsible for tracking
    165 // idle state.
    166 
    167 typedef enum {
    168     dp_tracker_session_none,
    169     dp_tracker_session_push,
    170     dp_tracker_session_srpl
    171 } dp_tracker_session_type_t;
    172 
    173 int cur_tracker_serial;
    174 typedef struct dnssd_query dnssd_query_t;
    175 typedef struct dp_tracker {
    176     int ref_count;
    177     int serial;
    178     comm_t *connection;
    179     dnssd_query_t *dns_queries;
    180     dso_state_t *dso;
    181     wakeup_t *idle_timeout;
    182     dp_tracker_session_type_t session_type;
    183 } dp_tracker_t;
    184 
    185 struct answer {
    186     answer_t *next;                 // List of answers to a question.
    187     char *fullname;                 // Name returned in callback.
    188     uint8_t *rdata;                 // Rdata returned in callback (wire format).
    189     uint32_t interface_index;       // Interface index returned in callback.
    190     uint32_t ttl;                   // Time-to-live returned in callback (probably not useful for LLQ).
    191     uint16_t rrtype;                // Resource record type returned in callback.
    192     uint16_t rrclass;               // Resource record class returned in callback.
    193     uint16_t rdlen;                 // Length of resource record data returned in callback.
    194 };
    195 
    196 static int cur_question_serial;
    197 struct question {
    198     question_t *next;               // List of questions that are being asked.
    199     served_domain_t *served_domain;
    200     dnssd_query_t *queries;         // dnssd queries that are asking this question.
    201     dnssd_txn_t *txn;               // Subordinate DNSServiceRef for this question
    202     char *name;                     // The name we are looking up.
    203     answer_t *answers;              // Answers this question has received.
    204     int64_t start_time;             // When this question was started.
    205     int serviceFlags;               // Service flags to use with this question.
    206     int ref_count;                  // Reference count.
    207     int serial;
    208     uint32_t interface_index;       // Which interface the query should use.
    209     uint16_t type;                  // The type.
    210     uint16_t qclass;                // The class.
    211     bool no_data;                   // True if "no such record" is received or all data gets removed
    212 };
    213 
    214 static int cur_query_serial;
    215 struct dnssd_query {
    216     int ref_count;
    217     int serial;
    218     dp_tracker_t *tracker;          // Tracks the connection that delivered this query.
    219     dnssd_query_t *next;            // For DNS queries, tracks other queries on the same connection, if any.
    220     wakeup_t *wakeup;
    221     dns_name_pointer_t enclosing_domain_pointer;
    222 
    223     message_t *message;
    224     dso_state_t *dso;               // If this is a DNS Push query, the DSO state associated with it.
    225     dso_activity_t *activity;
    226     int num_questions;              // In case of a multi-question query, how many questions were asked
    227     bool is_edns0;
    228     dns_towire_state_t towire;
    229     uint8_t *p_dso_length;          // Where to store the DSO length just before we write out a push notification.
    230     dns_wire_t *response;
    231     dns_message_t *response_msg;    // In case we need to decompose the message to construct a multi-answer message.
    232     size_t data_size;               // Size of the data payload of the response.
    233     dnssd_query_t *question_next;   // Linked list of queries on the question this query is subscribed to.
    234     question_t *question;           // Question asked by this query pointing to a cache entry.
    235     bool satisfied;                 // If true, this query has gotten an answer. Only relevant for straight DNS.
    236     bool canceled;                  // If true, dnssd_query_cancel has been called on this query, so don't cancel it again.
    237 };
    238 
    239 // Structure that is used to setup the mDNS discovery for dnssd-proxy.
    240 struct dnssd_proxy_advertisements {
    241     wakeup_t *wakeup_timer;         // Used to setup a timer to advertise records repeatedly until it succeeds.
    242     dnssd_txn_t *txn;               // Contains event loop.
    243     DNSServiceRef service_ref;      // Shared DNSServiceRef for all registering operation.
    244     DNSRecordRef ns_record_ref;     // Used to update the advertised NS record.
    245     DNSRecordRef ptr_record_ref;    // Used to update the advertised PTR record.
    246     char *domain_to_advertise;      // The domain to be advertised in NS and PTR records.
    247     srp_server_t *server_state;
    248     SCDynamicStoreContext sc_context;
    249 };
    250 
    251 #if SRP_FEATURE_DISCOVERY_PROXY_SERVER
    252 // Structure that is used to advertise the push discovery service in .local domain.
    253 struct dnssd_dp_proxy_advertisements {
    254     wakeup_t *wakeup_timer;     // Used to setup a timer to advertise push service repeatedly until it succeeds.
    255     dnssd_txn_t *txn;           // The event loop.
    256     DNSServiceRef service_ref;  // DNSServiceRef to register the service.
    257     srp_server_t *server_state;
    258 };
    259 #endif
    260 
    261 // Configuration file settings
    262 
    263 uint16_t dnssd_proxy_udp_port;
    264 uint16_t dnssd_proxy_tcp_port;
    265 uint16_t dnssd_proxy_tls_port;
    266 const char *my_name = "discoveryproxy.home.arpa.";
    267 char *listen_addrs[MAX_ADDRS];
    268 int num_listen_addrs;
    269 char *publish_addrs[MAX_ADDRS];
    270 int num_publish_addrs;
    271 char *tls_cacert_filename;
    272 char *tls_cert_filename = "/etc/dnssd-proxy/server.crt";
    273 char *tls_key_filename = "/etc/dnssd-proxy/server.key";
    274 
    275 comm_t *dnssd_proxy_listeners[4 + MAX_ADDRS];
    276 int dnssd_proxy_num_listeners;
    277 question_t *questions_without_domain; // Questions that aren't in a served domain
    278 served_domain_t *served_domains;
    279 int num_push_sessions; // Number of connections from DNS Push clients
    280 int dp_num_outstanding_queries;
    281 int num_push_sessions_dropped_for_load;
    282 int num_queries_dropped_for_load;
    283 
    284 #if SRP_FEATURE_DNSSD_PROXY_SHARED_CONNECTIONS
    285 dnssd_txn_t *shared_discovery_txn;
    286 #endif // SRP_FEATURE_DNSSD_PROXY_SHARED_CONNECTIONS
    287 wakeup_t *discovery_restart_wakeup;
    288 
    289 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
    290 static char uuid_name[DNS_MAX_NAME_SIZE + 1];
    291 static char my_name_buf[DNS_MAX_NAME_SIZE + 1];
    292 static CFStringRef sc_dynamic_store_key_host_name;
    293 static char local_host_name[DNS_MAX_NAME_SIZE + 1];
    294 static char local_host_name_dot_local[DNS_MAX_NAME_SIZE + 1];
    295 #endif // #if (SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY)
    296 
    297 #if THREAD_BORDER_ROUTER && SRP_FEATURE_SRP_COMBINED_DNSSD_PROXY
    298 extern char *thread_interface_name;
    299 #endif // THREAD_BORDER_ROUTER && SRP_FEATURE_COMBINED_DNSSD_PROXY
    300 
    301 // Globals
    302 
    303 const char push_subscription_activity_type[] = "push subscription";
    304 
    305 static const char local_suffix[] = ".local.";
    306 
    307 bool tls_fail = false; // Command line argument, for testing.
    308 
    309 // Macros
    310 
    311 #define THREAD_DOMAIN "thread.home.arpa."
    312 // "openthread." will change in the future once we have a way to get thread network ID
    313 #define THREAD_DOMAIN_WITH_ID "openthread." THREAD_DOMAIN
    314 #define DEFAULT_SERVICE_ARPA_DOMAIN "default.service.arpa."
    315 #define HOME_NET_DOMAIN "home.arpa."
    316 #define DOT_HOME_NET_DOMAIN ".home.arpa."
    317 #define DOT_LOCAL_DOMAIN "local."
    318 #define LOCAL "local."
    319 #define DOT_LOCAL ".local."
    320 #define IPV4_REVERSE_LOOKUP_DOMAIN "in-addr.arpa."
    321 #define IPV6_REVERSE_LOOKUP_DOMAIN "ip6.arpa."
    322 #define SRV_TYPE_FOR_AUTOMATIC_BROWSING_DOMAIN "lb._dns-sd._udp"
    323 #define TOWIRE_CHECK(note, towire, func) { func; if ((towire)->error != 0 && failnote == NULL) failnote = (note); }
    324 #define BUSY_RETRY_DELAY_MS (5 * 60 * 1000) // Five minutes.
    325 #define MAX_DSO_CONNECTIONS 15 // Should be enough for a typical home network, assuming more hosts -> more BRs
    326 
    327 // RFC8766 says for us to clamp the TTL on proxied mDNS records to 10s. In practice this appears to be much
    328 // too short, because if the DNSSD server (e.g. mDNSResponder) is doing an LLQ, this results in a refresh
    329 // interval of <10s, which is kind of painful.
    330 #define RFC8766_TTL_CLAMP 300
    331 
    332 #define VALIDATE_TRACKER_CONNECTION_NON_NULL()                                                            \
    333     do {                                                                                                  \
    334         if (query->tracker == NULL) {                                                                     \
    335             ERROR("[Q%d] query->tracker NULL for query!", SERIAL(query));                                 \
    336             return;                                                                                       \
    337         }                                                                                                 \
    338         if (query->tracker->connection == NULL) {                                                         \
    339             ERROR("[Q%d][TRK%d] query->tracker->connection NULL", SERIAL(query), SERIAL(query->tracker)); \
    340             return;                                                                                       \
    341         }                                                                                                 \
    342     } while (false)
    343 
    344 #ifdef SRP_TEST_SERVER
    345 extern void (*srp_test_dso_message_finished)(void *context, message_t *message, dso_state_t *dso);
    346 extern ready_callback_t srp_test_dnssd_tls_listener_ready;
    347 extern void *srp_test_tls_listener_context;
    348 #endif
    349 
    350 // Forward references
    351 
    352 static void dns_push_start(dnssd_query_t *query);
    353 
    354 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
    355 static void served_domain_free(served_domain_t *const served_domain);
    356 #endif
    357 
    358 static served_domain_t *NULLABLE
    359 new_served_domain(dp_interface_t *const NULLABLE interface, const char * NONNULL domain);
    360 
    361 #if STUB_ROUTER
    362 static served_domain_t *NULLABLE
    363 find_served_domain(const char *const NONNULL domain);
    364 
    365 static bool
    366 string_ends_with(const char *const NONNULL str, const char *const NONNULL suffix);
    367 #endif // STUB_ROUTER
    368 
    369 static void dp_query_towire_reset(dnssd_query_t *query);
    370 
    371 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
    372 static served_domain_t *NONNULL
    373 add_new_served_domain_with_interface(const char *const NONNULL name,
    374     const addr_t *const NULLABLE address, const addr_t *const NULLABLE mask);;
    375 
    376 #if STUB_ROUTER
    377 static bool
    378 dnssd_hardwired_add_or_remove_address_in_domain(const char *const NONNULL name,
    379     const char *const NONNULL domain_to_change, const addr_t *const NONNULL address, const bool add);
    380 #endif // STUB_ROUTER
    381 
    382 static bool
    383 dnssd_hardwired_setup_dns_push_for_domain(served_domain_t *const NONNULL served_domain);
    384 #endif // SRP_FEATURE_DYNAMIC_CONFIGURATION
    385 
    386 #if STUB_ROUTER
    387 static bool
    388 start_timer_to_advertise(dnssd_proxy_advertisements_t *NONNULL context,
    389     const char *const NULLABLE domain_to_advertise, const uint32_t interval);
    390 #endif
    391 
    392 static bool
    393 interface_process_addr_change(dp_interface_t *const NONNULL interface, const addr_t *const NONNULL address,
    394                               const addr_t *const NONNULL mask, const enum interface_address_change event_type);
    395 
    396 static void dns_question_callback(DNSServiceRef UNUSED sdRef, DNSServiceFlags flags, uint32_t UNUSED interfaceIndex,
    397                                   DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype,
    398                                   uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context);
    399 static void dns_push_callback(void *context, void *event_context, dso_state_t *dso, dso_event_type_t eventType);
    400 #if SRP_FEATURE_DNSSD_PROXY_SHARED_CONNECTIONS
    401 static void dp_setup_shared_discovery_txn(void);
    402 #endif
    403 static void dp_query_reply_from_cache(question_t *question, dnssd_query_t *query, bool remove);
    404 static void dp_handle_server_disconnect(void *UNUSED context, int status);
    405 static void dp_question_answers_free(question_t *question);
    406 static void question_finalize(question_t *question);
    407 
    408 // For debugging
    409 static wakeup_t *connection_dropper;
    410 extern dso_state_t *dso_connections;
    411 static void dp_drop_connections(void *UNUSED context);
    412 #ifdef SRP_TEST_SERVER
    413 served_domain_t *NULLABLE last_freed_domain;
    414 #endif
    415 
    416 static void
    417 dp_question_context_release(void *context)
    418 {
    419     question_t *question = context;
    420     RELEASE_HERE(question, question);
    421 }
    422 
    423 static DNSServiceErrorType
    424 dp_start_question(question_t *question, bool dns64)
    425 {
    426     DNSServiceErrorType err;
    427     DNSServiceRef sdref;
    428     size_t len;
    429     char name[DNS_MAX_NAME_SIZE + 1];
    430     char *np;
    431 
    432     // If a query has a served domain, query->question->name is the subdomain of the served domain that is
    433     // being queried; otherwise query->question->name is the whole name.
    434     if (question->served_domain != NULL) {
    435         len = strlen(question->name);
    436         if (question->served_domain->interface != NULL) {
    437             if (len + sizeof local_suffix > sizeof name) {
    438                 ERROR("[QU%d] question name %s is too long for .local.", SERIAL(question), name);
    439                 return kDNSServiceErr_BadParam;
    440             }
    441             memcpy(name, question->name, len);
    442             memcpy(&name[len], local_suffix, sizeof local_suffix);
    443         } else {
    444             size_t dlen = strlen(question->served_domain->domain_ld) + 1;
    445             if (len + dlen > sizeof name) {
    446                 ERROR("[QU%d] question name %s is too long for %s.", SERIAL(question), name, question->served_domain->domain);
    447                 return kDNSServiceErr_BadParam;
    448             }
    449             memcpy(name, question->name, len);
    450             memcpy(&name[len], question->served_domain->domain_ld, dlen);
    451         }
    452         np = name;
    453     } else {
    454         np = question->name;
    455     }
    456 
    457     int shared_connection_flag = 0;
    458 #if SRP_FEATURE_DNSSD_PROXY_SHARED_CONNECTIONS
    459     dp_setup_shared_discovery_txn();
    460     if (shared_discovery_txn != NULL) {
    461         sdref = shared_discovery_txn->sdref;
    462         shared_connection_flag = kDNSServiceFlagsShareConnection;
    463     }
    464 #endif // SRP_FEATURE_DNSSD_PROXY_SHARED_CONNECTIONS
    465 
    466     uint32_t question_interface = question->interface_index;
    467 #if SRP_FEATURE_LOCAL_DISCOVERY
    468     if (question_interface == kDNSServiceInterfaceIndexInfra) {
    469         int ret = -1;
    470 #if STUB_ROUTER
    471         ret = route_get_current_infra_interface_index();
    472 #else
    473         static unsigned en0_ifindex = 0;
    474         if (en0_ifindex == 0) {
    475             en0_ifindex = if_nametoindex("en0");
    476             if (en0_ifindex == 0) {
    477                 ERROR("getting en0 ifindex failed!");
    478             }
    479         }
    480         if (en0_ifindex != 0) {
    481             ret = en0_ifindex;
    482         }
    483 #endif // STUB_ROUTER
    484         // If we don't have an infrastructure interface, refuse the query.
    485         if (ret < 0) {
    486             return kDNSServiceErr_Refused;
    487         }
    488         question_interface = ret;
    489     }
    490 #endif // SRP_FEATURE_LOCAL_DISCOVERY
    491 
    492 #if SRP_FEATURE_NAT64
    493     const DNSServiceAttribute *attr = NULL;
    494     if (dns64 && (question->type == dns_rrtype_aaaa) && (question->qclass == dns_qclass_in)) {
    495         attr = &kDNSServiceAttributeAAAAFallback;
    496     }
    497     err = dns_service_query_record_wa(srp_servers, &sdref, question->serviceFlags | shared_connection_flag,
    498                                       question_interface, np, question->type,
    499                                       question->qclass, attr, dns_question_callback, question);
    500 #else
    501     (void)dns64;
    502     err = dns_service_query_record(srp_servers, &sdref, question->serviceFlags | shared_connection_flag, question_interface, np,
    503                                    question->type, question->qclass, dns_question_callback, question);
    504 #endif
    505     if (err != kDNSServiceErr_NoError) {
    506         ERROR("[QU%d] DNSServiceQueryRecord failed for '%s': %d", SERIAL(question), np, err);
    507     } else {
    508         INFO("[QU%d] txn %p new sdref %p", SERIAL(question), question->txn, sdref);
    509 #if SRP_FEATURE_DNSSD_PROXY_SHARED_CONNECTION
    510         question->txn = ioloop_dnssd_txn_add_subordinate(sdref, dp_question_context_release, NULL);
    511 #else
    512         question->txn = dns_service_ioloop_txn_add(srp_servers, sdref, question, dp_question_context_release, dp_handle_server_disconnect);
    513 #endif // SRP_FEATURE_DNSSD_PROXY_SHARED_CONNECTIONS
    514         RETAIN_HERE(question, question); // For the callback
    515 #if SRP_FEATURE_NAT64
    516         INFO("[QU%d] DNSServiceQueryRecordWithAttribute started for '" PRI_S_SRP "': %d", SERIAL(question), np, err);
    517 #else
    518         INFO("[QU%d] DNSServiceQueryRecord started for '" PRI_S_SRP "': %d", SERIAL(question), np, err);
    519 #endif // SRP_FEATURE_NAT64
    520     }
    521     return err;
    522 }
    523 
    524 static bool
    525 dp_iterate_questions_on_list(question_t *list, bool (*callback)(question_t *question, void *context), void *context)
    526 {
    527     for (question_t *question = list; question; question = question->next) {
    528         if (callback(question, context)) {
    529             return true;
    530         }
    531     }
    532     return false;
    533 }
    534 
    535 static bool
    536 dp_iterate_questions(bool (*callback)(question_t *question, void *context), void *context)
    537 {
    538     if (dp_iterate_questions_on_list(questions_without_domain, callback, context)) {
    539         return true;
    540     }
    541 
    542     for (served_domain_t *domain = served_domains; domain != NULL; domain = domain->next) {
    543         if (dp_iterate_questions_on_list(domain->questions, callback, context)) {
    544             return true;
    545         }
    546     }
    547     return false;
    548 }
    549 
    550 static bool
    551 dp_restart_question(question_t *question, void *context)
    552 {
    553     bool dns64 = *((bool *)context);
    554     if (question->txn == NULL) {
    555         dp_start_question(question, dns64);
    556     }
    557     return false;
    558 }
    559 
    560 static void
    561 dp_restart_all_questions(void *UNUSED context)
    562 {
    563     bool dns64 = false;
    564 #if SRP_FEATURE_NAT64
    565     if (srp_servers->srp_nat64_enabled) {
    566         dns64 = nat64_is_active();
    567     }
    568 #endif
    569     dp_iterate_questions(dp_restart_question, &dns64);
    570 }
    571 
    572 static bool
    573 dp_void_question(question_t *question, void *UNUSED context)
    574 {
    575     if (question->txn != NULL) {
    576         INFO("[QU%d] question->txn = %p", SERIAL(question), question->txn);
    577 #if SRP_FEATURE_DNSSD_PROXY_SHARED_CONNECTIONS
    578         question->txn->sdref = NULL;
    579 #else
    580         ioloop_dnssd_txn_cancel(question->txn);
    581 #endif
    582         ioloop_dnssd_txn_release(question->txn);
    583         question->txn = NULL;
    584     }
    585     if (question->answers != NULL) {
    586         dnssd_query_t *next, *query = question->queries;
    587         while(query != NULL) {
    588             next = query->question_next;
    589             if (query->dso != NULL) {
    590                 dp_query_reply_from_cache(question, query, true);
    591             }
    592             query = next;
    593         }
    594         dp_question_answers_free(question);
    595     }
    596 
    597     return false;
    598 }
    599 
    600 // NULLs out all outstanding questions (after an mDNSResponder crash). These pointers are rendered invalid when the
    601 // parent transaction is deallocated, so this should not result in any leaks.
    602 static void
    603 dp_void_all_questions(void)
    604 {
    605     dp_iterate_questions(dp_void_question, NULL);
    606 }
    607 
    608 static void
    609 dp_handle_server_disconnect(void *UNUSED context, int status)
    610 {
    611     INFO("status %d", status);
    612     dp_void_all_questions();
    613     if (discovery_restart_wakeup == NULL) {
    614         discovery_restart_wakeup = ioloop_wakeup_create();
    615     }
    616     if (discovery_restart_wakeup != NULL) {
    617         // Try to reconnect to mDNSResponder after a second.
    618         ioloop_add_wake_event(discovery_restart_wakeup, NULL, dp_restart_all_questions, NULL, 1000);
    619     }
    620 }
    621 
    622 #if SRP_FEATURE_DNSSD_PROXY_SHARED_CONNECTIONS
    623 static void
    624 dp_setup_shared_discovery_txn(void)
    625 {
    626     if (shared_discovery_txn == NULL) {
    627         DNSServiceRef sdref;
    628         int err = DNSServiceCreateConnection(&sdref);
    629         if (err != kDNSServiceErr_NoError) {
    630             return false;
    631         }
    632         shared_discovery_txn = ioloop_dnssd_txn_add(sdref, NULL, NULL, dp_handle_server_disconnect);
    633         if (shared_discovery_txn == NULL) {
    634             ERROR("unable to create shared connection for registration.");
    635             DNSServiceRefDeallocate(sdref);
    636             return false;
    637         }
    638         INFO("shared_discovery_txn = %p  sdref = %p", shared_discovery_txn, sdref);
    639     }
    640 }
    641 #endif // SRP_FEATURE_DNSSD_PROXY_SHARED_CONNECTIONS
    642 
    643 void
    644 dp_start_dropping(void)
    645 {
    646     if (connection_dropper == NULL) {
    647         connection_dropper = ioloop_wakeup_create();
    648         if (connection_dropper == NULL) {
    649             ERROR("can't create connection dropper.");
    650             return;
    651         }
    652     }
    653     ioloop_add_wake_event(connection_dropper, NULL, dp_drop_connections, NULL, 90 * 1000);
    654 }
    655 
    656 static void
    657 dp_drop_connections(void *UNUSED context)
    658 {
    659     for (dso_state_t *dso = dso_connections; dso != NULL; dso = dso->next) {
    660         if (dso->cb == dns_push_callback) {
    661             dp_tracker_t *tracker = dso->context;
    662             INFO("dropping connection for " PRI_S_SRP ".", dso->remote_name);
    663             if (tracker->connection != NULL) {
    664                 ioloop_comm_cancel(tracker->connection);
    665             }
    666         }
    667     }
    668     dp_start_dropping();
    669 }
    670 
    671 static void
    672 dp_tracker_finalize(dp_tracker_t *tracker)
    673 {
    674     // At this point tracker should have nothing attached to it that we need to get rid of, except maybe the
    675     // wakeup timer.
    676     if (tracker->idle_timeout != NULL) {
    677         ioloop_wakeup_release(tracker->idle_timeout);
    678     }
    679     // The only case where tracker->connection should still exist at this point is when the connection turned
    680     // out to be an srp replication connection.
    681     if (tracker->connection) {
    682         ioloop_comm_release(tracker->connection);
    683     }
    684     free(tracker);
    685 }
    686 
    687 static void
    688 dp_answer_free(answer_t *answer)
    689 {
    690     if (answer != NULL) {
    691         free(answer->fullname);
    692         free(answer);
    693     }
    694 }
    695 
    696 static void
    697 dp_question_answers_free(question_t *question)
    698 {
    699     // De-allocate answers
    700     answer_t *answer = question->answers;
    701     answer_t *next;
    702     while (answer != NULL) {
    703         next = answer->next;
    704         dp_answer_free(answer);
    705         answer = next;
    706     }
    707     question->answers = NULL;
    708 }
    709 
    710 // The finalize function will deallocate answers associated with the question,
    711 // remove question from the question list and deallocate the question.
    712 static void
    713 question_finalize(question_t *question)
    714 {
    715     INFO("[QU%d] type %d class %d " PRI_S_SRP, SERIAL(question), question->type, question->qclass, question->name);
    716     dp_question_answers_free(question);
    717     free(question->name);
    718     free(question);
    719 }
    720 
    721 static void
    722 dp_question_cancel(question_t *question)
    723 {
    724     if (question->txn != NULL) {
    725         INFO("[QU%d] question->txn = %p sdref=%p", SERIAL(question), question->txn, question->txn->sdref);
    726         ioloop_dnssd_txn_cancel(question->txn);
    727         ioloop_dnssd_txn_release(question->txn);
    728         question->txn = NULL;
    729     }
    730 
    731     // Remove the question from its list.
    732     question_t **questions, *q_cur;
    733     if (question->served_domain != NULL) {
    734         questions = &question->served_domain->questions;
    735     } else {
    736         questions = &questions_without_domain;
    737     }
    738     while (*questions != NULL ) {
    739         q_cur = *questions;
    740         if (q_cur == question) {
    741             *questions = q_cur->next;
    742             break;
    743         } else {
    744             questions = &q_cur->next;
    745         }
    746     }
    747     // If this was the last question, see if the served domain is still on the served domain list; if not,
    748     // this is the last reference, so free it.
    749     if (question->served_domain != NULL && question->served_domain->questions == NULL) {
    750         served_domain_t *served_domain;
    751         for (served_domain = served_domains; served_domain; served_domain = served_domain->next) {
    752             if (served_domain == question->served_domain) {
    753                 break;
    754             }
    755         }
    756         if (served_domain == NULL) {
    757             served_domain_free(question->served_domain);
    758         }
    759     }
    760     RELEASE_HERE(question, question); // Release from the list.
    761 }
    762 
    763 // Called when the last reference on the query has been released.
    764 static void
    765 dnssd_query_finalize(void *context)
    766 {
    767     dnssd_query_t *query = context;
    768     if (query->tracker != NULL) {
    769         RELEASE_HERE(query->tracker, dp_tracker);
    770         query->tracker = NULL;
    771     }
    772     if (query->message != NULL) {
    773         ioloop_message_release(query->message);
    774         query->message = NULL;
    775     }
    776     if (query->wakeup != NULL) {
    777         ioloop_wakeup_release(query->wakeup);
    778         query->wakeup = NULL;
    779     }
    780     if (query->response != NULL) {
    781         free(query->response);
    782         query->response = NULL;
    783     }
    784     if (query->response_msg != NULL) {
    785         dns_message_free(query->response_msg);
    786         query->response_msg = NULL;
    787     }
    788     if (query->question != NULL) {
    789         RELEASE_HERE(query->question, question);
    790         query->question = NULL;
    791     }
    792     free(query);
    793     dp_num_outstanding_queries--;
    794 }
    795 
    796 // Remove any finished queries from the question cache query list.
    797 static void
    798 dp_question_cache_remove_queries(question_t *question)
    799 {
    800     // Convenience
    801     if (question == NULL) {
    802         return;
    803     }
    804 
    805     dnssd_query_t **pptr = &(question->queries);
    806     RETAIN_HERE(question, question);
    807     if (question->queries != NULL) {
    808         while (*pptr != NULL) {
    809             dnssd_query_t *cquery = *pptr;
    810             if (cquery->satisfied) {
    811                 *pptr = cquery->question_next;
    812                 RELEASE_HERE(cquery, dnssd_query);
    813             } else {
    814                 pptr = &cquery->question_next;
    815             }
    816         }
    817         if (question->queries == NULL) {
    818             dp_question_cancel(question);
    819         }
    820     }
    821     RELEASE_HERE(question, question);
    822 }
    823 
    824 static void
    825 dp_tracker_context_release(void *context)
    826 {
    827     dp_tracker_t *tracker = context;
    828     RELEASE_HERE(tracker, dp_tracker);
    829 }
    830 
    831 static void
    832 dp_tracker_went_away(dp_tracker_t *tracker)
    833 {
    834     // Reduce the number of outstanding connections (should never go below zero).
    835     if (tracker->session_type == dp_tracker_session_push) {
    836         if (--num_push_sessions < 0) {
    837             FAULT("DNS Push connection count went negative");
    838             num_push_sessions = 0;
    839         } else {
    840             INFO("[TRK%d][DSO%d][C%d] dso connection count dropped: %d", SERIAL(tracker), SERIAL(tracker->dso), SERIAL(tracker->connection), num_push_sessions);
    841         }
    842     }
    843 }
    844 
    845 static void
    846 dp_tracker_idle(void *context)
    847 {
    848     dp_tracker_t *tracker = context;
    849     // Shouldn't be NULL.
    850     if (tracker->connection != NULL) {
    851         comm_t *connection = tracker->connection;
    852         INFO("[TRK%d][DSO%d][C%d] tracker for connection " PRI_S_SRP " has gone idle.",
    853              SERIAL(tracker), SERIAL(tracker->dso), SERIAL(connection), connection->name);
    854 
    855         // If the connection is already disconnected, it's already released its reference to the tracker. If not,
    856         // the release below will release tracker as a side effect. So in case tracker survives, clear the
    857         // connection pointer.
    858         tracker->connection = NULL;
    859         // The POSIX ioloop just hands us the "listener", which we do not want to cancel.
    860         if (!connection->is_listener) {
    861             ioloop_comm_cancel(connection);
    862         }
    863         ioloop_comm_release(connection);
    864     }
    865 }
    866 
    867 static void
    868 dp_tracker_idle_after(dp_tracker_t *tracker, int seconds, dnssd_query_t *query)
    869 {
    870     if (tracker->connection != NULL && !tracker->connection->is_listener &&
    871         tracker->dso == NULL && (query == NULL ||
    872                                  (tracker->dns_queries == NULL ||
    873                                   (tracker->dns_queries == query && query->next == NULL))))
    874     {
    875         if (tracker->idle_timeout == NULL) {
    876             tracker->idle_timeout = ioloop_wakeup_create();
    877         }
    878         if (tracker->idle_timeout == NULL) {
    879             ERROR("[TRK%d] no memory for idle timeout", SERIAL(tracker));
    880         } else {
    881             ioloop_add_wake_event(tracker->idle_timeout, tracker, dp_tracker_idle, dp_tracker_context_release, seconds * MSEC_PER_SEC);
    882             RETAIN_HERE(tracker, dp_tracker);
    883         }
    884     }
    885 }
    886 
    887 static bool
    888 dp_same_message(message_t *a, message_t *b)
    889 {
    890     // Code commented out below catches retransmissions, but right now this won't work and we'll leak queries,
    891     // so saving it for rdar://111808637 (dnssd-proxy is way too complicated)
    892     if (a == b /*  || (a != NULL && b != NULL && a->wire.id == b->wire.id) */ ) {
    893         return true;
    894     }
    895     return false;
    896 }
    897 
    898 // Called at any time (prior to release!) to cancel a query.
    899 static void
    900 dnssd_query_cancel(dnssd_query_t *query)
    901 {
    902     INFO("[Q%d][QU%d] " PRI_S_SRP PUB_S_SRP PUB_S_SRP, SERIAL(query), SERIAL(query->question),
    903          query->question == NULL ? "<null>" : query->question->name,
    904          query->question == NULL ? "" : ((query->question->served_domain
    905                                           ? (query->question->served_domain->interface
    906                                              ? DOT_LOCAL
    907                                              : query->question->served_domain->domain_ld)
    908                                           : "")),
    909          query->canceled ? " canceled" : "");
    910     // Avoid double-cancellation
    911     if (query->canceled) {
    912         return;
    913     }
    914     // Retain the query for the duration of dnssd_query_cancel so that it doesn't get finalized while we are working on it.
    915     RETAIN_HERE(query, dnssd_query);
    916     query->canceled = true; // prevent double-cancellation
    917     if (query->tracker != NULL) {
    918         dp_tracker_t *tracker = query->tracker;
    919 
    920         // Retain the tracker so it doesn't get released while we are working on it.
    921         RETAIN_HERE(tracker, dp_tracker);
    922 
    923         if (query->dso == NULL) {
    924             bool unsatisfied = false;
    925             for (dnssd_query_t *list_query = tracker->dns_queries; list_query != NULL; list_query = list_query->next) {
    926                 if (dp_same_message(query->message, list_query->message)) {
    927                     if (!query->satisfied) {
    928                         unsatisfied = true;
    929                     }
    930                 }
    931             }
    932 
    933             if (!unsatisfied) {
    934                 // Scan the list freeing all queries relating to the message attached to the query that's been canceled.
    935                 // A UDP message will never have any other queries, but TCP connections can have multiple messages.
    936                 for (dnssd_query_t **qp = &tracker->dns_queries; *qp != NULL; ) {
    937                     dnssd_query_t *list_query = *qp;
    938 
    939                     // Release the current query either if it's the query that's being canceled, or this is a UDP message.
    940                     if (dp_same_message(query->message, list_query->message)) {
    941                         *qp = list_query->next;
    942 
    943                         // This might release the query, but we know that the tracker holds a reference to it, so
    944                         // we don't need another reference to it.
    945                         if (list_query->wakeup != NULL) {
    946                             ioloop_wakeup_release(list_query->wakeup);
    947                             list_query->wakeup = NULL;
    948                         }
    949 
    950                         // Release this query's reference to the tracker
    951                         RELEASE_HERE(tracker, dp_tracker);
    952                         list_query->tracker = NULL;
    953 
    954                         // The tracker was holding a reference to the query.
    955                         RELEASE_HERE(list_query, dnssd_query);
    956                     } else {
    957                         qp = &list_query->next;
    958                     }
    959                 }
    960             }
    961         } else {
    962             // For DNS Push queries, drop the activity, which will release the query.
    963             if (query->activity != NULL && query->dso != NULL) {
    964                 dso_activity_t *activity = query->activity;
    965                 dso_state_t *dso = query->dso;
    966                 dso_drop_activity(dso, activity);
    967                 query->activity = NULL;
    968             }
    969             // Now release the reference the query had on the tracker.
    970             query->tracker = NULL;
    971             RELEASE_HERE(tracker, dp_tracker);
    972         }
    973 
    974         // For TCP connections, wait for it to become idle before closing.
    975         if (tracker->connection != NULL && tracker->dns_queries == NULL) {
    976             if (tracker->connection->tcp_stream) {
    977                 dp_tracker_idle_after(tracker, 15, query);
    978             } else {
    979 #if UDP_LISTENER_USES_CONNECTION_GROUPS
    980                 ioloop_comm_cancel(tracker->connection);
    981 #else
    982                 ioloop_comm_release(tracker->connection);
    983                 tracker->connection = NULL;
    984 #endif
    985             }
    986         }
    987 
    988         // Release the reference we retained on entry.
    989         RELEASE_HERE(tracker, dp_tracker);
    990     } else {
    991         if (query->wakeup != NULL) {
    992             ioloop_wakeup_release(query->wakeup);
    993             query->wakeup = NULL;
    994         }
    995     }
    996     query->satisfied = true;
    997     RELEASE_HERE(query, dnssd_query);
    998 }
    999 
   1000 static void
   1001 dp_query_track(dp_tracker_t *tracker, dnssd_query_t *query)
   1002 {
   1003     dnssd_query_t **qp = &tracker->dns_queries;
   1004 
   1005     while (*qp != NULL) {
   1006         if (*qp == query) {
   1007             ERROR("[Q%d][TRK%d] query is already being tracked.", SERIAL(query), SERIAL(query->tracker));
   1008             return;
   1009         }
   1010         qp = &(*qp)->next;
   1011     }
   1012     *qp = query;
   1013     RETAIN_HERE(query, dnssd_query);
   1014 }
   1015 
   1016 static void
   1017 dp_tracker_disconnected(comm_t *UNUSED connection, void *context, int UNUSED error)
   1018 {
   1019     dp_tracker_t *tracker = context;
   1020     dnssd_query_t *dns_queries = tracker->dns_queries, **qp, *query;
   1021     comm_t *tracker_connection = tracker->connection;
   1022     tracker->connection = NULL;
   1023     tracker->dns_queries = NULL;
   1024 
   1025     INFO("[TRK%d][DSO%d][C%d] queries %p", SERIAL(tracker), SERIAL(tracker->dso), SERIAL(tracker_connection), dns_queries);
   1026 
   1027     // If there is a DSO state outstanding on the tracker, cancel any activities connected to it.
   1028     if (tracker->dso != NULL) {
   1029         dso_activity_t *activity = tracker->dso->activities;
   1030         while (activity != NULL) {
   1031             dso_drop_activity(tracker->dso, tracker->dso->activities);
   1032             // Failsafe in case dso_drop_activity for some reason doesn't drop the activity.
   1033             if (tracker->dso->activities == activity) {
   1034                 break;
   1035             }
   1036             activity = tracker->dso->activities;
   1037         }
   1038         dso_state_cancel(tracker->dso);
   1039         dp_tracker_went_away(tracker);
   1040         tracker->session_type = dp_tracker_session_none;
   1041         tracker->dso = NULL;
   1042     }
   1043 
   1044     // We probably still have the connection object at this point, so we should release it, which could
   1045     // in turn finalize the tracker.
   1046     if (tracker_connection != NULL) {
   1047         ioloop_comm_release(tracker_connection);
   1048         tracker->connection = NULL;
   1049     }
   1050 
   1051     // If dns_queries is non-null, tracker still exists, but it might go away when we cancel the last
   1052     // query.
   1053     qp = &dns_queries;
   1054     while (*qp != NULL) {
   1055         query = *qp;
   1056         *qp = query->next;
   1057         RELEASE_HERE(query, dnssd_query);
   1058     }
   1059 }
   1060 
   1061 static void
   1062 dns_push_cancel(dso_activity_t *activity)
   1063 {
   1064     dnssd_query_t *query = (dnssd_query_t *)activity->context;
   1065     INFO("[Q%d][QU%d] " PUB_S_SRP, SERIAL(query), SERIAL(query->question), activity->name);
   1066     // We can either get here because the dso object is being finalized, or because the activity is being dropped.
   1067     // In the former case, we need to cancel the query. In the latter case, we've been called as a result of
   1068     // dnssd_query_cancel calling dso_drop_activity. dnssd_query_cancel sets query->activity to NULL before dropping
   1069     // it, so we mustn't call back in to dnssd_query_cancel.
   1070     if (query->activity != NULL) {
   1071         query->activity = NULL;
   1072         query->satisfied = true;
   1073         dp_question_cache_remove_queries(query->question);
   1074         dnssd_query_cancel(query);
   1075     }
   1076     // The activity held a reference to the query.
   1077     RELEASE_HERE(query, dnssd_query);
   1078 }
   1079 
   1080 static void
   1081 dp_tracker_not_idle(dp_tracker_t *tracker)
   1082 {
   1083     if (tracker->idle_timeout) {
   1084         ioloop_cancel_wake_event(tracker->idle_timeout);
   1085     }
   1086 }
   1087 
   1088 static served_domain_t *
   1089 dp_served(dns_name_t *name, char *buf, size_t bufsize)
   1090 {
   1091     served_domain_t *sdt;
   1092     dns_label_t *lim;
   1093 
   1094     for (sdt = served_domains; sdt; sdt = sdt->next) {
   1095         if ((lim = dns_name_subdomain_of(name, sdt->domain_name))) {
   1096             dns_name_print_to_limit(name, lim, buf, bufsize);
   1097             return sdt;
   1098         }
   1099     }
   1100     return NULL;
   1101 }
   1102 
   1103 static bool
   1104 is_in_local_domain(const dns_name_t *const NONNULL name)
   1105 {
   1106     const dns_label_t *prev_root_label;
   1107     const dns_label_t *root_label;
   1108 
   1109     for (prev_root_label = NULL, root_label = name;
   1110          root_label->next != NULL;
   1111          prev_root_label = root_label, root_label = root_label->next)
   1112         ;
   1113 
   1114     if (prev_root_label == NULL) {
   1115         return false;
   1116     }
   1117 
   1118 #define LOCAL_DOMAIN_LABEL "local"
   1119     if (prev_root_label->len != strlen(LOCAL_DOMAIN_LABEL)) {
   1120         return false;
   1121     }
   1122 
   1123     if (!dns_labels_equal(prev_root_label->data, LOCAL_DOMAIN_LABEL, strlen(LOCAL_DOMAIN_LABEL))) {
   1124         return false;
   1125     }
   1126 #undef LOCAL_DOMAIN_LABEL
   1127 
   1128     return true;
   1129 }
   1130 
   1131 // Utility function to find "local" on the end of a string of labels.
   1132 static bool
   1133 truncate_local(dns_name_t *name)
   1134 {
   1135     dns_label_t *lp, *prev, *prevprev;
   1136 
   1137     prevprev = prev = NULL;
   1138     // Find the root label.
   1139     for (lp = name; lp && lp->len; lp = lp->next) {
   1140         prevprev = prev;
   1141         prev = lp;
   1142     }
   1143     if (lp && prev && prevprev) {
   1144         if (prev->len == 5 && dns_labels_equal(prev->data, "local", 5)) {
   1145             dns_name_free(prev);
   1146             prevprev->next = NULL;
   1147             return true;
   1148         }
   1149     }
   1150     return false;
   1151 }
   1152 
   1153 static bool
   1154 dp_query_add_data_to_response(dnssd_query_t *query, const char *fullname, uint16_t rrtype, uint16_t rrclass,
   1155                               uint16_t rdlen, const void *rdata, int32_t ttl, const bool hardwired_response,
   1156                               bool dont_elide, uint16_t *counter)
   1157 {
   1158     bool record_added;
   1159     dns_towire_state_t *towire = &query->towire;
   1160     const char *failnote = NULL;
   1161     const uint8_t *rd = rdata;
   1162     char pbuf[DNS_MAX_NAME_SIZE + 1];
   1163     char rbuf[DNS_MAX_NAME_SIZE + 1];
   1164     uint8_t *revert = query->towire.p; // Remember where we were in case there's no room.
   1165     question_t *question = query->question;
   1166 
   1167     // Only do the translation if:
   1168     // 1. We serve the domain.
   1169     // 2. The response we will add does not come from our hardwired response set.
   1170     const bool translate = (question->served_domain != NULL) && (!hardwired_response);
   1171 
   1172     if (rdlen == 0) {
   1173         INFO("[Q%d][QU%d] eliding zero-length response for " PRI_S_SRP " " PUB_S_SRP " %d",
   1174              SERIAL(query), SERIAL(question), fullname, dns_rrtype_to_string(rrtype), rrclass);
   1175         record_added = false;
   1176         goto exit;
   1177     }
   1178     // Don't send A records for 127.* nor AAAA records for ::1
   1179     if (dont_elide) {
   1180     } else if (rrtype == dns_rrtype_a && rdlen == 4) {
   1181         // Should use IN_LINKLOCAL and IN_LOOPBACK macros here, but for some reason they are not present on
   1182         // OpenWRT.
   1183         if (rd[0] == 127) {
   1184             IPv4_ADDR_GEN_SRP(rd, rd_buf);
   1185             INFO("[Q%d][QU%d] eliding localhost response for " PRI_S_SRP ": " PRI_IPv4_ADDR_SRP,
   1186                  SERIAL(query), SERIAL(question), fullname, IPv4_ADDR_PARAM_SRP(rd, rd_buf));
   1187             record_added = false;
   1188             goto exit;
   1189         }
   1190         if (rd[0] == 169 && rd[1] == 254) {
   1191             IPv4_ADDR_GEN_SRP(rd, rd_buf);
   1192             INFO("[Q%d][QU%d] eliding link-local response for " PRI_S_SRP ": " PRI_IPv4_ADDR_SRP,
   1193                  SERIAL(query), SERIAL(question), fullname, IPv4_ADDR_PARAM_SRP(rd, rd_buf));
   1194             record_added = false;
   1195             goto exit;
   1196         }
   1197     } else if (rrtype == dns_rrtype_aaaa && rdlen == 16) {
   1198         struct in6_addr addr = *(struct in6_addr *)rdata;
   1199         if (IN6_IS_ADDR_LOOPBACK(&addr)) {
   1200             SEGMENTED_IPv6_ADDR_GEN_SRP(rdata, rdata_buf);
   1201             INFO("[Q%d][QU%d] eliding localhost response for " PRI_S_SRP ": " PRI_SEGMENTED_IPv6_ADDR_SRP,
   1202                  SERIAL(query), SERIAL(question), fullname, SEGMENTED_IPv6_ADDR_PARAM_SRP(rdata, rdata_buf));
   1203             record_added = false;
   1204             goto exit;
   1205         }
   1206         if (IN6_IS_ADDR_LINKLOCAL(&addr)) {
   1207             SEGMENTED_IPv6_ADDR_GEN_SRP(rdata, rdata_buf);
   1208             INFO("[Q%d][QU%d] eliding link-local response for " PRI_S_SRP ": " PRI_SEGMENTED_IPv6_ADDR_SRP,
   1209                  SERIAL(query), SERIAL(question), fullname, SEGMENTED_IPv6_ADDR_PARAM_SRP(rdata, rdata_buf));
   1210             record_added = false;
   1211             goto exit;
   1212         }
   1213     }
   1214     INFO("survived for rrtype " PUB_S_SRP " rdlen %d", dns_rrtype_to_string(rrtype), rdlen);
   1215 
   1216     if (query->dso != NULL) {
   1217         dns_push_start(query);
   1218     }
   1219     // Rewrite the domain if it's .local.
   1220     if (question->served_domain != NULL) {
   1221         TOWIRE_CHECK("concatenate_name_to_wire", towire,
   1222                      dns_concatenate_name_to_wire(towire, NULL, question->name, question->served_domain->domain));
   1223         INFO("[Q%d][QU%d] " PUB_S_SRP " answer:  type " PUB_S_SRP " class %02d " PRI_S_SRP "." PRI_S_SRP, SERIAL(query), SERIAL(question),
   1224              query->dso != NULL ? "PUSH" : "DNS ", dns_rrtype_to_string(rrtype), rrclass, question->name, question->served_domain->domain);
   1225     } else {
   1226         TOWIRE_CHECK("compress_name_to_wire", towire, dns_concatenate_name_to_wire(towire, NULL, NULL, question->name));
   1227         INFO("[Q%d][QU%d] " PUB_S_SRP " answer:  type " PUB_S_SRP " class %02d " PRI_S_SRP " (p)",
   1228              SERIAL(query), SERIAL(question), query->dso != NULL ? "push" : " dns", dns_rrtype_to_string(rrtype), rrclass, question->name);
   1229     }
   1230     TOWIRE_CHECK("rrtype", towire, dns_u16_to_wire(towire, rrtype));
   1231     TOWIRE_CHECK("rrclass", towire, dns_u16_to_wire(towire, rrclass));
   1232     TOWIRE_CHECK("ttl", towire, dns_ttl_to_wire(towire, ttl));
   1233 
   1234     // If necessary, correct domain names inside of rrdata.
   1235     dns_rr_t answer;
   1236     dns_name_t *name;
   1237     unsigned offp = 0;
   1238 
   1239     answer.type = rrtype;
   1240     answer.qclass = rrclass;
   1241     if (dns_rdata_parse_data(&answer, rdata, &offp, rdlen, rdlen, 0)) {
   1242         switch(rrtype) {
   1243             case dns_rrtype_cname:
   1244             case dns_rrtype_ptr:
   1245             case dns_rrtype_ns:
   1246             case dns_rrtype_md:
   1247             case dns_rrtype_mf:
   1248             case dns_rrtype_mb:
   1249             case dns_rrtype_mg:
   1250             case dns_rrtype_mr:
   1251             case dns_rrtype_nsap_ptr:
   1252             case dns_rrtype_dname:
   1253                 name = answer.data.ptr.name;
   1254                 TOWIRE_CHECK("rdlength begin", towire, dns_rdlength_begin(towire));
   1255                 break;
   1256             case dns_rrtype_srv:
   1257                 name = answer.data.srv.name;
   1258                 TOWIRE_CHECK("rdlength begin", towire, dns_rdlength_begin(towire));
   1259                 TOWIRE_CHECK("answer.data.srv.priority", towire, dns_u16_to_wire(towire, answer.data.srv.priority));
   1260                 TOWIRE_CHECK("answer.data.srv.weight", towire, dns_u16_to_wire(towire, answer.data.srv.weight));
   1261                 TOWIRE_CHECK("answer.data.srv.port", towire, dns_u16_to_wire(towire, answer.data.srv.port));
   1262                 break;
   1263             default:
   1264                 INFO("[Q%d][QU%d] record type " PUB_S_SRP " not translated", SERIAL(query), SERIAL(question), dns_rrtype_to_string(rrtype));
   1265                 dns_rrdata_free(&answer);
   1266                 goto raw;
   1267         }
   1268 
   1269         dns_name_print(name, rbuf, sizeof rbuf);
   1270 
   1271         if (translate && is_in_local_domain(name)) {
   1272             // If the response requires the translation from <served domain> to ".local." and the response ends in
   1273             // ".local.", truncate it.
   1274             truncate_local(name);
   1275             dns_name_print(name, pbuf, sizeof pbuf);
   1276             TOWIRE_CHECK("concatenate_name_to_wire 2", towire,
   1277                          dns_concatenate_name_to_wire(towire, name, NULL, question->served_domain->domain));
   1278             INFO("[Q%d][QU%d] translating " PRI_S_SRP " to " PRI_S_SRP " . " PRI_S_SRP,
   1279                  SERIAL(query), SERIAL(question), rbuf, pbuf, question->served_domain->domain);
   1280         } else {
   1281             TOWIRE_CHECK("concatenate_name_to_wire 2", towire,
   1282                          dns_concatenate_name_to_wire(towire, name, NULL, NULL));
   1283             INFO("[Q%d][QU%d] compressing " PRI_S_SRP, SERIAL(query), SERIAL(question), rbuf);
   1284         }
   1285 
   1286         dns_name_free(name);
   1287         dns_rdlength_end(towire);
   1288     } else {
   1289         ERROR("[Q%d][QU%d] rdata from mDNSResponder didn't parse!!", SERIAL(query), SERIAL(question));
   1290     raw:
   1291         TOWIRE_CHECK("rdlen", towire, dns_u16_to_wire(towire, rdlen));
   1292         TOWIRE_CHECK("rdata", towire, dns_rdata_raw_data_to_wire(towire, rdata, rdlen));
   1293     }
   1294 
   1295     if (towire->truncated || failnote) {
   1296         ERROR("[Q%d][QU%d] RR ADD FAIL: " PUB_S_SRP, SERIAL(query), SERIAL(question), failnote);
   1297         query->towire.p = revert;
   1298         record_added = false;
   1299         goto exit;
   1300     }
   1301 
   1302     record_added = true;
   1303     if (counter != NULL && query->dso == NULL) {
   1304         *counter = htons(ntohs(*counter) + 1);
   1305     }
   1306 exit:
   1307     return record_added;
   1308 }
   1309 
   1310 static void
   1311 dnssd_hardwired_add(served_domain_t *sdt,
   1312                     const char *name, const char *domain, size_t rdlen, const uint8_t *rdata, uint16_t type)
   1313 {
   1314     hardwired_t *hp, **hrp;
   1315     size_t namelen = strlen(name);
   1316     size_t domainlen = strlen(domain);
   1317     size_t total = sizeof *hp;
   1318     uint8_t *trailer;
   1319     total += rdlen; // Space for RDATA
   1320     total += namelen; // Space for name
   1321     total += 1; // NUL
   1322     total += namelen;// space for FQDN
   1323     total += domainlen;
   1324     total += 1; // NUL
   1325 
   1326     hp = calloc(1, total + 4);
   1327     if (hp == NULL) {
   1328         ERROR("no memory for %s %s", name, domain);
   1329         return;
   1330     }
   1331     trailer = ((uint8_t *)hp) + total;
   1332     memcpy(trailer, "abcd", 4);
   1333     hp->rdata = (uint8_t *)(hp + 1);
   1334     hp->rdlen = rdlen;
   1335     memcpy(hp->rdata, rdata, rdlen);
   1336     hp->name = (char *)hp->rdata + rdlen;
   1337     memcpy(hp->name, name, namelen);
   1338     hp->name[namelen] = '\0';
   1339     hp->fullname = hp->name + namelen + 1;
   1340     if (namelen != 0) {
   1341         snprintf(hp->fullname, namelen + domainlen + 1, "%s%s", name, domain);
   1342     } else {
   1343         memcpy(hp->fullname, domain, domainlen);
   1344         hp->fullname[domainlen] = '\0';
   1345     }
   1346     if (hp->fullname + strlen(hp->fullname) + 1 != (char *)hp + total) {
   1347         ERROR("%p != %p", hp->fullname + strlen(hp->fullname) + 1, ((char *)hp) + total);
   1348         return;
   1349     }
   1350     if (memcmp(trailer, "abcd", 4)) {
   1351         ERROR("ran off the end.");
   1352         return;
   1353     }
   1354     hp->type = type;
   1355     hp->next = NULL;
   1356 
   1357     // Store this new hardwired_t at the end of the list unless a hardwired_t with the same name
   1358     // is already on the list.   If it is, splice it in.
   1359     for (hrp = &sdt->hardwired_responses; *hrp != NULL; hrp = &(*hrp)->next) {
   1360         hardwired_t *old = *hrp;
   1361         if (old->type != hp->type) {
   1362             continue;
   1363         }
   1364         if (strcasecmp(old->fullname, hp->fullname) != 0) {
   1365             continue;
   1366         }
   1367         // The same name and type
   1368         bool superseded;
   1369         switch (type) {
   1370             case dns_rrtype_a:
   1371             case dns_rrtype_aaaa:
   1372             case dns_rrtype_ns:
   1373             case dns_rrtype_ptr:
   1374                 superseded = false;
   1375                 break;
   1376             default:
   1377                 // dns_rrtype_soa
   1378                 // dns_rrtype_srv
   1379                 superseded = true;
   1380                 break;
   1381         }
   1382 
   1383         if (superseded) {
   1384             INFO("superseding " PRI_S_SRP " name " PRI_S_SRP " type %d rdlen %d", old->fullname,
   1385                  old->name, old->type, old->rdlen);
   1386             hp->next = old->next;
   1387             free(old);
   1388         } else {
   1389             INFO("inserting before " PRI_S_SRP " name " PRI_S_SRP " type %d rdlen %d", old->fullname,
   1390                  old->name, old->type, old->rdlen);
   1391             hp->next = old;
   1392         }
   1393         break;
   1394     }
   1395     *hrp = hp;
   1396 
   1397     INFO("fullname " PRI_S_SRP " name " PRI_S_SRP " type %d rdlen %d",
   1398          hp->fullname, hp->name, hp->type, hp->rdlen);
   1399 }
   1400 
   1401 #if STUB_ROUTER
   1402 static bool
   1403 dnssd_hardwired_remove_record(served_domain_t *const NONNULL sdt, const char *const NONNULL name, const char *const NONNULL domain, size_t rdlen,
   1404     const void *const NULLABLE rdata, uint16_t type)
   1405 {
   1406     bool removed;
   1407     hardwired_t *prev = NULL;
   1408     hardwired_t *current;
   1409     char full_name[DNS_MAX_NAME_SIZE + 1];
   1410 
   1411     int bytes_written = snprintf(full_name, sizeof(full_name), "%s%s", name, domain);
   1412     require_action_quiet(bytes_written > 0 && (size_t)bytes_written < sizeof(full_name), exit, removed = false;
   1413         ERROR("snprintf truncates the string - name length: %zu, domain length: %zu, buffer length: %zu",
   1414             strlen(name), strlen(domain), sizeof(full_name))
   1415     );
   1416 
   1417     for (current = sdt->hardwired_responses; current != NULL; prev = current, current = current->next) {
   1418         if (current->type != type) {
   1419             continue;
   1420         }
   1421         if (rdata != NULL && current->rdlen != rdlen) {
   1422             continue;
   1423         }
   1424         if (strcasecmp(current->fullname, full_name) != 0) {
   1425             continue;
   1426         }
   1427         if (rdata != NULL && memcmp(current->rdata, rdata, rdlen) != 0) {
   1428             continue;
   1429         }
   1430         // record found
   1431         break;
   1432     }
   1433     require_action_quiet(current != NULL, exit, removed = false;
   1434         ERROR("no matching hardwired_t found - record name: " PUB_S_SRP ", record type: %d", full_name, type));
   1435 
   1436     if (prev != NULL) {
   1437         prev->next = current->next;
   1438     } else {
   1439         sdt->hardwired_responses = current->next;
   1440     }
   1441     free(current);
   1442 
   1443     removed = true;
   1444 exit:
   1445     return removed;
   1446 }
   1447 
   1448 static bool
   1449 dnssd_hardwired_add_or_remove_addr_record(served_domain_t *const NONNULL sdt, const addr_t *const NONNULL addr,
   1450     const char *const NONNULL name, bool add)
   1451 {
   1452     dns_wire_t wire;
   1453     dns_towire_state_t towire;
   1454     bool succeeded;
   1455 
   1456     memset(&towire, 0, sizeof towire);
   1457     towire.message = &wire;
   1458     towire.p = wire.data;
   1459     towire.lim = towire.p + sizeof wire.data;
   1460 
   1461     const void *rdata_ptr;
   1462     size_t addr_len;
   1463     uint16_t addr_type;
   1464     if (addr->sa.sa_family == AF_INET) {
   1465         rdata_ptr = &addr->sin.sin_addr;
   1466         addr_len = sizeof(addr->sin.sin_addr);
   1467         addr_type = dns_rrtype_a;
   1468     } else { // addr.sa.sa_family == AF_INET6
   1469         rdata_ptr = &addr->sin6.sin6_addr;
   1470         addr_len = sizeof(addr->sin6.sin6_addr);
   1471         addr_type = dns_rrtype_aaaa;
   1472     }
   1473     dns_rdata_raw_data_to_wire(&towire, rdata_ptr, addr_len);
   1474 
   1475     if (add) {
   1476         dnssd_hardwired_add(sdt, name, name[0] == '\0' ? sdt->domain : sdt->domain_ld, towire.p - wire.data, wire.data,
   1477             addr_type);
   1478         succeeded = true;
   1479     } else {
   1480         succeeded = dnssd_hardwired_remove_record(sdt, name,  name[0] == '\0' ? sdt->domain : sdt->domain_ld,
   1481             towire.p - wire.data, wire.data, addr_type);
   1482     }
   1483 
   1484     return succeeded;
   1485 }
   1486 
   1487 static bool
   1488 dnssd_hardwired_add_or_remove_address_in_domain(const char *const NONNULL name,
   1489     const char *const NONNULL domain_to_change, const addr_t *const NONNULL address, const bool add)
   1490 {
   1491     bool succeeded;
   1492 
   1493     served_domain_t *served_domain = find_served_domain(domain_to_change);
   1494     require_action_quiet(served_domain != NULL, exit, succeeded = false;
   1495         ERROR("could not find served domain with the specified domain name - domain name: " PRI_S_SRP, domain_to_change)
   1496     );
   1497 
   1498     succeeded = dnssd_hardwired_add_or_remove_addr_record(served_domain, address, name, add);
   1499     require_action_quiet(succeeded, exit, succeeded = false;
   1500         ERROR("failed to " PUB_S_SRP " address record - domain name: " PRI_S_SRP,
   1501             domain_to_change, add ? "add" : "remove")
   1502     );
   1503 
   1504 exit:
   1505     return succeeded;
   1506 }
   1507 
   1508 static bool
   1509 dnssd_hardwired_generate_ptr_name(const addr_t *const NONNULL addr, const addr_t *const NONNULL mask,
   1510                                   char *name_buf, size_t buf_size)
   1511 {
   1512     char *name_ptr = name_buf;
   1513     const char *const name_limit = name_ptr + buf_size;
   1514     int bytes_written;
   1515     bool succeeded;
   1516 
   1517 #define RESET \
   1518     memset(&towire, 0, sizeof towire); \
   1519     towire.message = &wire; \
   1520     towire.p = wire.data; \
   1521     towire.lim = towire.p + sizeof wire.data
   1522 
   1523     bytes_written = snprintf(name_ptr, name_limit - name_ptr, SRV_TYPE_FOR_AUTOMATIC_BROWSING_DOMAIN);
   1524     require_action_quiet(bytes_written > 0 && bytes_written < name_limit - name_ptr, exit, succeeded = false;
   1525         ERROR("snprintf truncates the string - bytes_written: %d, limit: %zd", bytes_written, name_limit - name_ptr));
   1526     name_ptr += bytes_written;
   1527 
   1528 
   1529     if (addr->sa.sa_family == AF_INET) {
   1530         const uint32_t subnet = (ntohl(addr->sin.sin_addr.s_addr) & ntohl(mask->sin.sin_addr.s_addr));
   1531         bytes_written = snprintf(name_ptr, name_limit - name_ptr, ".%u.%u.%u.%u",
   1532             subnet & 0xFFU, (subnet >> 8) & 0xFFU, (subnet >> 16) & 0xFFU, (subnet >> 24) & 0xFFU);
   1533         require_action(bytes_written > 0 && bytes_written < name_limit - name_ptr, exit, succeeded = false);
   1534         // Remember to increase the name_ptr by bytes_written bytes if name_ptr is used later.
   1535 
   1536     } else if (addr->sa.sa_family == AF_INET6) {
   1537         const uint8_t *const addr_bytes = addr->sin6.sin6_addr.s6_addr;
   1538         const uint8_t *const mask_bytes = mask->sin6.sin6_addr.s6_addr;
   1539         for (int i = 15; i >= 0; i--) {
   1540             for (int shift = 0; shift < 8; shift += 4) {
   1541                 bytes_written = snprintf(name_ptr, name_limit - name_ptr, ".%x",
   1542                     (addr_bytes[i] >> shift) & (mask_bytes[i] >> shift) & 15);
   1543                 require_action_quiet(bytes_written > 0 && bytes_written < name_limit - name_ptr, exit, succeeded = false;
   1544                     ERROR("snprintf truncates the string - bytes_written: %d, limit: %zd",
   1545                         bytes_written, name_limit - name_ptr)
   1546                 );
   1547                 name_ptr += bytes_written;
   1548             }
   1549         }
   1550 
   1551     } else {
   1552         FAULT("skipping address type other than IPv4/IPv6 - type: %u", addr->sa.sa_family);
   1553         succeeded = false;
   1554         goto exit;
   1555     }
   1556 
   1557     succeeded = true;
   1558 exit:
   1559     return succeeded;
   1560 }
   1561 
   1562 static bool
   1563 dnssd_hardwired_add_or_remove_ptr_record(served_domain_t *const NONNULL sdt, const addr_t *const NONNULL addr,
   1564     const addr_t *const NONNULL mask, bool add)
   1565 {
   1566     char name[DNS_MAX_NAME_SIZE + 1];
   1567     dns_wire_t wire;
   1568     dns_towire_state_t towire;
   1569     bool succeeded;
   1570 
   1571 #define RESET \
   1572     memset(&towire, 0, sizeof towire); \
   1573     towire.message = &wire; \
   1574     towire.p = wire.data; \
   1575     towire.lim = towire.p + sizeof wire.data
   1576 
   1577     succeeded = dnssd_hardwired_generate_ptr_name(addr, mask, name, sizeof(name));
   1578     if (!succeeded) {
   1579         INFO("address is not eligible to construct PTR record");
   1580         goto exit;
   1581     }
   1582 
   1583     for (served_domain_t *if_domain = served_domains; if_domain != NULL; if_domain = if_domain->next) {
   1584         if (if_domain->interface == NULL || if_domain->interface->ifindex == 0) {
   1585             continue;
   1586         }
   1587         RESET;
   1588         INFO(PUB_S_SRP " PTR from " PRI_S_SRP " to " PRI_S_SRP, add ? "Adding" : "Removing", name, if_domain->domain);
   1589         dns_full_name_to_wire(NULL, &towire, if_domain->domain);
   1590 
   1591         if (add) {
   1592             dnssd_hardwired_add(sdt, name, sdt->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_ptr);
   1593             succeeded = true;
   1594         } else {
   1595             succeeded = dnssd_hardwired_remove_record(sdt, name, sdt->domain_ld, towire.p - wire.data, wire.data,
   1596                 dns_rrtype_ptr);
   1597         }
   1598     }
   1599 
   1600 exit:
   1601     return succeeded;
   1602 }
   1603 
   1604 static bool
   1605 dnssd_hardwired_add_or_remove_ptr_in_domain(const char *const NONNULL domain_to_change,
   1606     const addr_t *const NONNULL address, const addr_t *const NONNULL mask, const bool add)
   1607 {
   1608     bool succeeded;
   1609 
   1610     served_domain_t *served_domain = find_served_domain(domain_to_change);
   1611     require_action_quiet(served_domain != NULL, exit, succeeded = false;
   1612         ERROR("could not find served domain with the specified domain name - domain name: " PRI_S_SRP, domain_to_change)
   1613     );
   1614 
   1615     succeeded = dnssd_hardwired_add_or_remove_ptr_record(served_domain, address, mask, add);
   1616     require_action_quiet(succeeded, exit, succeeded = false;
   1617         ERROR("failed to " PUB_S_SRP " address record - domain name: " PRI_S_SRP,
   1618             add ? "adding" : "removing", domain_to_change)
   1619     );
   1620 
   1621 exit:
   1622     return succeeded;
   1623 }
   1624 
   1625 static bool
   1626 is_valid_address_to_publish(const addr_t *const NONNULL address)
   1627 {
   1628     bool is_valid = true;
   1629 
   1630     if (address->sa.sa_family == AF_INET) {
   1631         const struct in_addr *const ipv4_address = &(address->sin.sin_addr);
   1632         const bool is_linklocal = is_in_addr_link_local(ipv4_address);
   1633         const bool is_loopback = is_in_addr_loopback(ipv4_address);
   1634 
   1635         if (is_linklocal || is_loopback) {
   1636             IPv4_ADDR_GEN_SRP(&ipv4_address, ipv4_address_buf);
   1637             INFO("ignoring the address for interface - address: " PRI_IPv4_ADDR_SRP ", address type: " PUB_S_SRP ".",
   1638                 IPv4_ADDR_PARAM_SRP(&ipv4_address, ipv4_address_buf), is_linklocal ? "link local" : "loopback");
   1639             is_valid = false;
   1640         }
   1641 
   1642     } else if (address->sa.sa_family == AF_INET6) {
   1643         const struct in6_addr *const ipv6_address = &(address->sin6.sin6_addr);
   1644         const bool is_linklocal = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
   1645         const bool is_loopback = IN6_IS_ADDR_LOOPBACK(ipv6_address);
   1646 
   1647         if (is_linklocal || is_loopback) {
   1648             IPv6_ADDR_GEN_SRP(ipv6_address->s6_addr, ipv6_address_buf);
   1649             INFO("ignoring the address for interface - address: " PRI_IPv6_ADDR_SRP ", address type: " PUB_S_SRP ".",
   1650                 IPv6_ADDR_PARAM_SRP(ipv6_address->s6_addr, ipv6_address_buf), is_linklocal ? "link local" : "loopback");
   1651             is_valid = false;
   1652         }
   1653 
   1654     } else {
   1655         // It is possible that MAC address is added for the interface, so ignore it.
   1656         INFO("Non IPv4/IPv6 address added for the interface - sa_family: %u", address->sa.sa_family);
   1657         is_valid = false;
   1658     }
   1659 
   1660     return is_valid;
   1661 }
   1662 
   1663 static bool
   1664 dnssd_hardwired_process_addr_change(const addr_t *const NONNULL addr, const addr_t *const NONNULL mask, const bool add)
   1665 {
   1666     bool succeeded;
   1667 
   1668     if (!is_valid_address_to_publish(addr)) {
   1669         succeeded = true;
   1670         goto exit;
   1671     }
   1672 
   1673     // Update the <local host name>.home.arpa. address mapping.
   1674     succeeded = dnssd_hardwired_add_or_remove_address_in_domain("", my_name, addr, add);
   1675     if (!succeeded) {
   1676         ERROR("failed to update address record for domain - domain: " PRI_S_SRP, my_name);
   1677         goto exit;
   1678     }
   1679 
   1680     // Update the <local host name>.<Thread ID>.thread.home.arpa. address mapping.
   1681     succeeded = dnssd_hardwired_add_or_remove_address_in_domain(local_host_name, THREAD_DOMAIN_WITH_ID, addr, add);
   1682     if (!succeeded) {
   1683         ERROR("failed to update address record for domain - domain: " PUB_S_SRP, THREAD_DOMAIN_WITH_ID);
   1684         goto exit;
   1685     }
   1686 
   1687     // Update the default.service.arpa. address mapping.
   1688     succeeded = dnssd_hardwired_add_or_remove_address_in_domain(local_host_name, DEFAULT_SERVICE_ARPA_DOMAIN, addr, add);
   1689     if (!succeeded) {
   1690         ERROR("failed to update address record for domain - domain: " PUB_S_SRP, DEFAULT_SERVICE_ARPA_DOMAIN);
   1691         goto exit;
   1692     }
   1693 
   1694 #if SRP_FEATURE_LOCAL_DISCOVERY
   1695     // Update the default.service.arpa. address mapping.
   1696     succeeded = dnssd_hardwired_add_or_remove_address_in_domain(local_host_name, DOT_LOCAL_DOMAIN, addr, add);
   1697     if (!succeeded) {
   1698         ERROR("failed to update address record for domain - domain: " PUB_S_SRP, LOCAL);
   1699         goto exit;
   1700     }
   1701 #endif
   1702 
   1703     // Setup the "_lb.dns-sd"
   1704     // Update the "reverse mapping from address to browsing domain" for each eligible served domain under IPv6 or IPv4
   1705     // reverse lookup domain.
   1706     if (addr->sa.sa_family == AF_INET6) {
   1707         succeeded = dnssd_hardwired_add_or_remove_ptr_in_domain(IPV6_REVERSE_LOOKUP_DOMAIN, addr, mask, add);
   1708     } else if (addr->sa.sa_family == AF_INET) {
   1709         succeeded = dnssd_hardwired_add_or_remove_ptr_in_domain(IPV4_REVERSE_LOOKUP_DOMAIN, addr, mask, add);
   1710     } else {
   1711         char buf[INET6_ADDRSTRLEN];
   1712         IOLOOP_NTOP(addr, buf);
   1713         INFO("Skipping non IPv6/IPv4 address - addr:" PRI_S_SRP, buf);
   1714         succeeded = true;
   1715     }
   1716 
   1717 exit:
   1718     return succeeded;
   1719 }
   1720 
   1721 static void
   1722 dnssd_hardwired_lbdomains_setup(void)
   1723 {
   1724     served_domain_t *ipv6, *ipv4;
   1725 #if (SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY)
   1726     // When dnssd-proxy is combined with srp-mdns-proxy, IPv4 and IPv6 reverse look up domain is set from the begining.
   1727     ipv4 = find_served_domain(IPV4_REVERSE_LOOKUP_DOMAIN);
   1728     ipv6 = find_served_domain(IPV6_REVERSE_LOOKUP_DOMAIN);
   1729 #else // #if (SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY)
   1730     ipv4 = new_served_domain(NULL, IPV4_REVERSE_LOOKUP_DOMAIN);
   1731     ipv6 = new_served_domain(NULL, IPV6_REVERSE_LOOKUP_DOMAIN);
   1732 #endif // #if (SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY)
   1733     require_action_quiet(ipv4 != NULL && ipv6 != NULL, exit, ERROR("cannot find/create new served domain"));
   1734 
   1735     for (served_domain_t *addr_domain = served_domains; addr_domain; addr_domain = addr_domain->next) {
   1736         dp_interface_t *interface = addr_domain->interface;
   1737         interface_addr_t *ifaddr;
   1738         if (interface == NULL) {
   1739             INFO("Domain " PRI_S_SRP " has no interface", addr_domain->domain);
   1740             continue;
   1741         }
   1742         INFO("Interface " PUB_S_SRP, interface->name);
   1743         // Add lb domain support for link domain
   1744         for (ifaddr = interface->addresses; ifaddr != NULL; ifaddr = ifaddr->next) {
   1745             // Do not publish link-local or loopback address
   1746             if (!is_valid_address_to_publish(&ifaddr->addr)) {
   1747                 continue;
   1748             }
   1749 
   1750             if (ifaddr->addr.sa.sa_family == AF_INET) {
   1751                 dnssd_hardwired_add_or_remove_ptr_record(ipv4, &ifaddr->addr, &ifaddr->mask, true);
   1752             } else if (ifaddr->addr.sa.sa_family == AF_INET6) {
   1753                 dnssd_hardwired_add_or_remove_ptr_record(ipv6, &ifaddr->addr, &ifaddr->mask, true);
   1754             } else {
   1755                 char buf[INET6_ADDRSTRLEN];
   1756                 IOLOOP_NTOP(&ifaddr->addr, buf);
   1757                 INFO("Skipping " PRI_S_SRP, buf);
   1758             }
   1759         }
   1760     }
   1761 exit:
   1762     return;
   1763 }
   1764 #endif
   1765 
   1766 static void
   1767 dnssd_hardwired_setup(void)
   1768 {
   1769     dns_wire_t wire;
   1770     dns_towire_state_t towire;
   1771     served_domain_t *sdt;
   1772 #if STUB_ROUTER
   1773     dns_name_t *my_name_parsed = my_name == NULL ? NULL : dns_pres_name_parse(my_name);
   1774 #endif
   1775 
   1776 #define RESET \
   1777     memset(&towire, 0, sizeof towire); \
   1778     towire.message = &wire; \
   1779     towire.p = wire.data; \
   1780     towire.lim = towire.p + sizeof wire.data
   1781 
   1782     // For each interface, set up the hardwired names.
   1783     for (sdt = served_domains; sdt; sdt = sdt->next) {
   1784         if (sdt->interface == NULL) {
   1785             continue;
   1786         }
   1787 
   1788         // SRV
   1789         // _dns-llq._udp
   1790         // _dns-llq-tls._tcp
   1791         // _dns-update._udp
   1792         // _dns-update-tls._udp
   1793         // We deny the presence of support for LLQ, because we only support DNS Push
   1794         RESET;
   1795         dnssd_hardwired_add(sdt, "_dns-llq._udp", sdt->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
   1796         dnssd_hardwired_add(sdt, "_dns-llq-tls._tcp", sdt->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
   1797 
   1798         // We deny the presence of support for DNS Update, because a Discovery Proxy zone is stateless.
   1799         dnssd_hardwired_add(sdt, "_dns-update._udp", sdt->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
   1800         dnssd_hardwired_add(sdt, "_dns-update-tls._tcp", sdt->domain_ld, towire.p - wire.data, wire.data,
   1801                             dns_rrtype_srv);
   1802 
   1803         // Until we set up the DNS Push listener, we deny its existence.   If TLS is ready to go, this will be
   1804         // overwritten immediately; otherwise it will be overwritten when the TLS key has been generated and signed.
   1805         dnssd_hardwired_add(sdt, "_dns-push-tls._tcp", sdt->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
   1806 
   1807 #if STUB_ROUTER
   1808         char namebuf[DNS_MAX_NAME_SIZE + 1];
   1809         const char *local_name;
   1810         addr_t addr;
   1811 
   1812         // If my_name wasn't set, or if my_name is in this interface's domain, we need to answer
   1813         // for it when queried.
   1814         if (my_name == NULL || my_name_parsed != NULL) {
   1815             const char *local_domain = NULL;
   1816             if (my_name == NULL) {
   1817                 local_name = "ns";
   1818                 local_domain = sdt->domain_ld;
   1819             } else {
   1820                 dns_name_t *lim;
   1821                 local_name = NULL;
   1822 
   1823                 // See if my_name is a subdomain of this interface's domain
   1824                 if ((lim = dns_name_subdomain_of(my_name_parsed, sdt->domain_name)) != NULL) {
   1825                     dns_name_print_to_limit(my_name_parsed, lim, namebuf, sizeof namebuf);
   1826                     local_name = namebuf;
   1827                     dns_name_free(my_name_parsed);
   1828                     my_name_parsed = NULL;
   1829                     if (local_name[0] == '\0') {
   1830                         local_domain = sdt->domain;
   1831                     } else {
   1832                         local_domain = sdt->domain_ld;
   1833                     }
   1834                 }
   1835             }
   1836             if (local_name != NULL) {
   1837                 for (int i = 0; i < num_publish_addrs; i++) {
   1838                     RESET;
   1839                     memset(&addr, 0, sizeof addr);
   1840                     getipaddr(&addr, publish_addrs[i]);
   1841                     if (addr.sa.sa_family == AF_INET) {
   1842                         // A
   1843                         // ns
   1844                         dns_rdata_raw_data_to_wire(&towire, &addr.sin.sin_addr, sizeof addr.sin.sin_addr);
   1845                         dnssd_hardwired_add(sdt, local_name, local_domain, towire.p - wire.data, wire.data,
   1846                                             dns_rrtype_a);
   1847                     } else {
   1848                         // AAAA
   1849                         RESET;
   1850                         dns_rdata_raw_data_to_wire(&towire, &addr.sin6.sin6_addr, sizeof addr.sin6.sin6_addr);
   1851                         dnssd_hardwired_add(sdt, local_name, local_domain, towire.p - wire.data, wire.data,
   1852                                             dns_rrtype_aaaa);
   1853                     }
   1854                 }
   1855             }
   1856         }
   1857 #endif // STUB_ROUTER
   1858 
   1859         // NS
   1860         RESET;
   1861 #if STUB_ROUTER
   1862         if (string_ends_with(sdt->domain, THREAD_DOMAIN)) {
   1863             // For served domain in the THREAD_DOMAIN, set the NS record to the local host name:
   1864             // For example, openthread.thread.home.arpa. NS Office.local.
   1865             // XXX is this right?
   1866             require_quiet(local_host_name_dot_local[0] != 0, exit);
   1867             dns_full_name_to_wire(NULL, &towire, local_host_name_dot_local);
   1868         } else
   1869 #endif
   1870         if (uuid_name[0] != 0) {
   1871             dns_name_to_wire(NULL, &towire, uuid_name);
   1872             dns_full_name_to_wire(NULL, &towire, sdt->domain);
   1873         } else {
   1874             dns_name_to_wire(NULL, &towire, "ns");
   1875             dns_full_name_to_wire(NULL, &towire, sdt->domain);
   1876         }
   1877         dnssd_hardwired_add(sdt, "", sdt->domain, towire.p - wire.data, wire.data, dns_rrtype_ns);
   1878 
   1879         // SOA (piggybacking on what we already did for NS, which starts the same.
   1880         dns_name_to_wire(NULL, &towire, "postmaster");
   1881         dns_full_name_to_wire(NULL, &towire, sdt->domain);
   1882         dns_u32_to_wire(&towire, 0);     // serial
   1883         dns_ttl_to_wire(&towire, 7200);  // refresh
   1884         dns_ttl_to_wire(&towire, 3600);  // retry
   1885         dns_ttl_to_wire(&towire, 86400); // expire
   1886         dns_ttl_to_wire(&towire, 120);    // minimum
   1887         dnssd_hardwired_add(sdt, "", sdt->domain, towire.p - wire.data, wire.data, dns_rrtype_soa);
   1888     }
   1889 
   1890     // Setup hardwired response A/AAAA record for <local host name>.home.arpa.
   1891 #if SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY
   1892 #if STUB_ROUTER
   1893     // When dnssd-proxy is combined with srp-mdns-proxy, we get the address from the interface address list not from the
   1894     // config file, so we search through the served domains for all available address.
   1895     if (my_name_parsed != NULL) {
   1896         dns_name_free(my_name_parsed);
   1897         my_name_parsed = NULL;
   1898     }
   1899 
   1900     require_action_quiet(my_name != NULL, exit, ERROR("Failed to get my_name and unable to set hardwired response"));
   1901     served_domain_t *const my_name_served_domain = find_served_domain(my_name);
   1902     require_action_quiet(my_name_served_domain != NULL, exit,
   1903         ERROR("Failed to find my_name domain - my_name: " PRI_S_SRP, my_name));
   1904 
   1905     served_domain_t *const thread_served_domain = find_served_domain(THREAD_DOMAIN_WITH_ID);
   1906     require_action(thread_served_domain != NULL, exit,
   1907         ERROR("Failed to find thread domain - domain: " PUB_S_SRP, THREAD_DOMAIN_WITH_ID));
   1908 
   1909     served_domain_t *const default_service_arpa_domain = find_served_domain(DEFAULT_SERVICE_ARPA_DOMAIN);
   1910     require_action(default_service_arpa_domain != NULL, exit,
   1911         ERROR("Failed to find thread domain - domain: " PUB_S_SRP, DEFAULT_SERVICE_ARPA_DOMAIN));
   1912 
   1913 #if SRP_FEATURE_LOCAL_DISCOVERY
   1914     served_domain_t *const dot_local_domain = find_served_domain(DOT_LOCAL_DOMAIN);
   1915     require_action(dot_local_domain != NULL, exit,
   1916         ERROR("Failed to find thread domain - domain: " PUB_S_SRP, DOT_LOCAL_DOMAIN));
   1917 #endif
   1918     for (const served_domain_t *domain = served_domains; domain != NULL; domain = domain->next) {
   1919         if (domain->interface == NULL) {
   1920             continue;
   1921         }
   1922         for (const interface_addr_t *if_addrs = domain->interface->addresses; if_addrs != NULL;
   1923              if_addrs = if_addrs->next) {
   1924             const addr_t *const if_addr = &if_addrs->addr;
   1925             // Only publish routable IP address.
   1926             if (!is_valid_address_to_publish(if_addr)) {
   1927                 continue;
   1928             }
   1929 
   1930             RESET;
   1931             uint16_t rr_type;
   1932             if (if_addr->sa.sa_family == AF_INET) {
   1933                 dns_rdata_raw_data_to_wire(&towire, &if_addr->sin.sin_addr, sizeof(if_addr->sin.sin_addr));
   1934                 rr_type = dns_rrtype_a;
   1935             } else if (if_addr->sa.sa_family == AF_INET6) {
   1936                 dns_rdata_raw_data_to_wire(&towire, &if_addr->sin6.sin6_addr, sizeof(if_addr->sin6.sin6_addr));
   1937                 rr_type = dns_rrtype_aaaa;
   1938             } else {
   1939                 ERROR("Non IPv4/IPv6 address in interface addresses - sa_family: %u", if_addr->sa.sa_family);
   1940                 continue;
   1941             }
   1942 
   1943             // <local host name>.home.arpa. A/AAAA <IP address>
   1944             dnssd_hardwired_add(my_name_served_domain, "", my_name_served_domain->domain, towire.p - wire.data,
   1945                 wire.data, rr_type);
   1946 
   1947             // <local host name>.openthread.thread.home.arpa. A/AAAA <IP address>
   1948             dnssd_hardwired_add(thread_served_domain, local_host_name, thread_served_domain->domain_ld,
   1949                 towire.p - wire.data, wire.data, rr_type);
   1950 
   1951             // <local host name>.default.service.arpa. A/AAAA <IP address>
   1952             dnssd_hardwired_add(default_service_arpa_domain, local_host_name, default_service_arpa_domain->domain_ld,
   1953                 towire.p - wire.data, wire.data, rr_type);
   1954 
   1955 #if SRP_FEATURE_LOCAL_DISCOVERY
   1956             // <local host name>.local. A/AAAA <IP address>
   1957             dnssd_hardwired_add(dot_local_domain, local_host_name, dot_local_domain->domain_ld,
   1958                 towire.p - wire.data, wire.data, rr_type);
   1959 #endif
   1960         }
   1961     }
   1962 #endif
   1963 #else // SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY
   1964     if (my_name_parsed != NULL) {
   1965         dns_name_free(my_name_parsed);
   1966         my_name_parsed = NULL;
   1967 
   1968         sdt = new_served_domain(NULL, my_name);
   1969         if (sdt == NULL) {
   1970             ERROR("Unable to allocate domain for %s", my_name);
   1971         } else {
   1972             for (int i = 0; i < num_publish_addrs; i++) {
   1973                 // AAAA
   1974                 // A
   1975                 RESET;
   1976                 memset(&addr, 0, sizeof addr);
   1977                 getipaddr(&addr, publish_addrs[i]);
   1978                 if (addr.sa.sa_family == AF_INET) {
   1979                     dns_rdata_raw_data_to_wire(&towire, &addr.sin.sin_addr, sizeof addr.sin.sin_addr);
   1980                     dnssd_hardwired_add(sdt, "", sdt->domain, towire.p - wire.data, wire.data, dns_rrtype_a);
   1981                 } else {
   1982                     dns_rdata_raw_data_to_wire(&towire, &addr.sin6.sin6_addr, sizeof addr.sin6.sin6_addr);
   1983                     dnssd_hardwired_add(sdt, "", sdt->domain, towire.p - wire.data, wire.data, dns_rrtype_aaaa);
   1984                 }
   1985             }
   1986         }
   1987     }
   1988 #endif // SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY
   1989 
   1990 #if STUB_ROUTER
   1991     // Setup _lb._udp.<reversed IP address> PTR record for the domain we are advertising, for example:
   1992     // _lb._udp.0.0.168.192.in-addr.arpa. PTR my-discovery-proxy-en0.home.arpa.
   1993     dnssd_hardwired_lbdomains_setup();
   1994 
   1995 exit:
   1996 #endif
   1997     return;
   1998 }
   1999 
   2000 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
   2001 static void
   2002 dnssd_hardwired_clear(void)
   2003 {
   2004     INFO("Clearing all hardwired response");
   2005     for (served_domain_t *domain = served_domains; domain != NULL; domain = domain->next) {
   2006         hardwired_t *hardwired_responses = domain->hardwired_responses;
   2007         if (hardwired_responses == NULL) {
   2008             continue;
   2009         }
   2010 
   2011         domain->hardwired_responses = NULL;
   2012         hardwired_t *next_response;
   2013         for (hardwired_t *response = hardwired_responses; response != NULL; response = next_response) {
   2014             next_response = response->next;
   2015             free(response);
   2016         }
   2017     }
   2018 }
   2019 
   2020 static void
   2021 dnssd_hardwired_push_setup(void)
   2022 {
   2023     // For each interface, set up the hardwired names.
   2024     for (served_domain_t *sdt = served_domains; sdt; sdt = sdt->next) {
   2025         if (sdt->interface == NULL) {
   2026             continue;
   2027         }
   2028 
   2029         if (!sdt->interface->no_push) {
   2030             // SRV
   2031             // _dns-push-tls._tcp
   2032             // _dns-query-tls._udp
   2033             dnssd_hardwired_setup_dns_push_for_domain(sdt);
   2034         }
   2035     }
   2036 }
   2037 
   2038 static void
   2039 dnssd_hardwired_deny_service_existence_for_served_domain(served_domain_t *const NONNULL served_domain)
   2040 {
   2041     dns_wire_t wire;
   2042     dns_towire_state_t towire;
   2043 
   2044 #define RESET \
   2045     memset(&towire, 0, sizeof towire); \
   2046     towire.message = &wire; \
   2047     towire.p = wire.data; \
   2048     towire.lim = towire.p + sizeof wire.data
   2049 
   2050     RESET;
   2051     // We deny the presence of support for LLQ, because we only support DNS Push.
   2052     dnssd_hardwired_add(served_domain, "_dns-llq._udp", served_domain->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
   2053     dnssd_hardwired_add(served_domain, "_dns-llq-tls._tcp", served_domain->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
   2054 
   2055     // We deny the presence of support for DNS Update, because a Discovery Proxy zone is stateless.
   2056     dnssd_hardwired_add(served_domain, "_dns-update._udp", served_domain->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
   2057     dnssd_hardwired_add(served_domain, "_dns-update-tls._tcp", served_domain->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
   2058 
   2059     // We deny the presence of support for UDP with TLS, because we have not implemented DTLS (datagram TLS).
   2060     dnssd_hardwired_add(served_domain, "_dns-query-tls._udp", served_domain->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
   2061 
   2062     // We deny the presence of "lb._dns-sd._udp" for the served domain, to avoid the response like:
   2063     // lb._dns-sd._udp.openthread.thread.home.arpa. PTR openthread.thread.home.arpa.
   2064     dnssd_hardwired_add(served_domain, SRV_TYPE_FOR_AUTOMATIC_BROWSING_DOMAIN, served_domain->domain_ld,
   2065         towire.p - wire.data, wire.data, dns_rrtype_ptr);
   2066     dnssd_hardwired_add(served_domain, "b._dns-sd._udp", served_domain->domain_ld,
   2067         towire.p - wire.data, wire.data, dns_rrtype_ptr);
   2068     dnssd_hardwired_add(served_domain, "db._dns-sd._udp", served_domain->domain_ld,
   2069         towire.p - wire.data, wire.data, dns_rrtype_ptr);
   2070 }
   2071 
   2072 static bool
   2073 dnssd_hardwired_setup_for_served_domain(served_domain_t *const NONNULL served_domain)
   2074 {
   2075     bool succeeded = false;
   2076     dns_wire_t wire;
   2077     dns_towire_state_t towire;
   2078 
   2079 #define RESET \
   2080     memset(&towire, 0, sizeof towire); \
   2081     towire.message = &wire; \
   2082     towire.p = wire.data; \
   2083     towire.lim = towire.p + sizeof wire.data
   2084 
   2085     require_action_quiet(served_domain->interface != NULL, exit, succeeded = false;
   2086         ERROR("only domain with usable interface can setup hardwired response - domain name: " PRI_S_SRP,
   2087             served_domain->domain)
   2088     );
   2089 
   2090     // deny the existence of the following services:
   2091     // _dns-llq._udp
   2092     // _dns-llq-tls._tcp
   2093     // _dns-update._udp
   2094     dnssd_hardwired_deny_service_existence_for_served_domain(served_domain);
   2095 
   2096     // Setup NS record for this served domain.
   2097     RESET;
   2098 #if STUB_ROUTER
   2099     if (string_ends_with(served_domain->domain, THREAD_DOMAIN)) {
   2100         // If the response requires the translation from <served domain> to ".local." and the response ends in
   2101         // ".local.", truncate it.
   2102         require_action_quiet(local_host_name_dot_local[0] != 0, exit, succeeded = false);
   2103         dns_full_name_to_wire(NULL, &towire, local_host_name_dot_local);
   2104     } else
   2105 #endif
   2106     if (uuid_name[0] != 0) {
   2107         dns_name_to_wire(NULL, &towire, uuid_name);
   2108         dns_full_name_to_wire(NULL, &towire, served_domain->domain);
   2109     } else {
   2110         dns_name_to_wire(NULL, &towire, "ns");
   2111         dns_full_name_to_wire(NULL, &towire, served_domain->domain);
   2112     }
   2113     dnssd_hardwired_add(served_domain, "", served_domain->domain, towire.p - wire.data, wire.data, dns_rrtype_ns);
   2114 
   2115     // Setup SOA record for this served domain. (piggybacking on what we already did for NS, which starts the same.)
   2116     dns_name_to_wire(NULL, &towire, "postmaster");
   2117     dns_full_name_to_wire(NULL, &towire, served_domain->domain);
   2118     dns_u32_to_wire(&towire, 0);     // serial
   2119     dns_ttl_to_wire(&towire, 7200);  // refresh
   2120     dns_ttl_to_wire(&towire, 3600);  // retry
   2121     dns_ttl_to_wire(&towire, 86400); // expire
   2122     dns_ttl_to_wire(&towire, 120);    // minimum
   2123     dnssd_hardwired_add(served_domain, "", served_domain->domain, towire.p - wire.data, wire.data, dns_rrtype_soa);
   2124 
   2125     // Setup DNS push
   2126     if (served_domain->interface == NULL || !served_domain->interface->no_push) {
   2127         succeeded = dnssd_hardwired_setup_dns_push_for_domain(served_domain);
   2128         if (!succeeded) {
   2129             ERROR("failed to setup DNS push service for hardwired response - domain: " PRI_S_SRP,
   2130                   served_domain->domain);
   2131             goto exit;
   2132         }
   2133     }
   2134     succeeded = true;
   2135 
   2136 exit:
   2137     return succeeded;
   2138 }
   2139 
   2140 static bool
   2141 dnssd_hardwired_setup_dns_push_for_domain(served_domain_t *const NONNULL served_domain)
   2142 {
   2143     bool succeeded;
   2144 
   2145     require_action_quiet(served_domain->interface != NULL && !served_domain->interface->no_push, exit, succeeded = false;
   2146         ERROR("the associated interface does not enable DNS push - domain: " PRI_S_SRP, served_domain->domain));
   2147 
   2148     require_action_quiet(my_name != NULL, exit, succeeded = false; ERROR("my_name is not set"));
   2149 
   2150     dns_wire_t wire;
   2151     dns_towire_state_t towire;
   2152 #define RESET \
   2153     memset(&towire, 0, sizeof towire); \
   2154     towire.message = &wire; \
   2155     towire.p = wire.data; \
   2156     towire.lim = towire.p + sizeof wire.data
   2157 
   2158     RESET;
   2159     dns_u16_to_wire(&towire, 0); // priority
   2160     dns_u16_to_wire(&towire, 0); // weight
   2161     dns_u16_to_wire(&towire, 853); // port
   2162 
   2163 #if STUB_ROUTER
   2164     if (string_ends_with(served_domain->domain, THREAD_DOMAIN)) {
   2165         // If the served domain is subdomain of "thread.home.arpa.", use name <local host name>.local for the DNS push
   2166         // service. Currently we only support DNS push in "thread.home.arpa." domain in local subnet, so DNS push
   2167         // service for "thread.home.arpa." will be registered with a name in ".local.".
   2168         require_action_quiet(local_host_name_dot_local[0] != 0, exit, succeeded = false);
   2169         dns_full_name_to_wire(NULL, &towire, local_host_name_dot_local);
   2170     } else
   2171 #endif
   2172     if (uuid_name[0] != 0) {
   2173         // Use <local host name>.<domain>
   2174         dns_name_to_wire(NULL, &towire, uuid_name);
   2175         dns_full_name_to_wire(NULL, &towire, served_domain->domain);
   2176     } else {
   2177         // Use name ns.<served domain>.
   2178         dns_name_to_wire(NULL, &towire, "ns");
   2179         dns_full_name_to_wire(NULL, &towire, served_domain->domain);
   2180     }
   2181 
   2182     dnssd_hardwired_add(served_domain, "_dns-push-tls._tcp", served_domain->domain_ld, towire.p - wire.data, wire.data,
   2183         dns_rrtype_srv);
   2184 
   2185     succeeded = true;
   2186 exit:
   2187     return succeeded;
   2188 }
   2189 #endif // SRP_FEATURE_DYNAMIC_CONFIGURATION
   2190 
   2191 static bool
   2192 embiggen(dnssd_query_t *query)
   2193 {
   2194     dns_wire_t *nr = malloc(query->data_size + DNS_DATA_SIZE + DNS_HEADER_SIZE); // increments wire size by DNS_DATA_SIZE
   2195     if (nr == NULL) {
   2196         return false;
   2197     }
   2198     memcpy(nr, query->response, query->data_size + DNS_HEADER_SIZE);
   2199     query->data_size += DNS_DATA_SIZE;
   2200     size_t len = query->towire.p - &query->response->data[0];
   2201     query->towire.p = &nr->data[0] + len;
   2202     query->towire.lim = &nr->data[0] + query->data_size;
   2203     query->towire.p_rdlength = NULL;
   2204     query->towire.p_opt = NULL;
   2205     query->towire.message = nr;
   2206     free(query->response);
   2207     query->response = nr;
   2208     return true;
   2209 }
   2210 
   2211 static void
   2212 dp_move_rrs(dns_rr_t *first_section, unsigned *p_first_count, dns_rr_t *source_section, unsigned source_count, unsigned count, bool rdata_present)
   2213 {
   2214     unsigned first_count = *p_first_count;
   2215 
   2216     // Copy the rrs into the combined section.
   2217     for (unsigned i = 0; i < source_count; i++) {
   2218         // Skip this RR if there's already another one just like it in the section (most likely to happen
   2219         // with authority records.
   2220         bool duplicate = false;
   2221         for (unsigned j = 0; j < first_count; j++) {
   2222             if (dns_rrs_equal(&first_section[j], &source_section[i], rdata_present)) {
   2223                 duplicate = true;
   2224                 break;
   2225             }
   2226         }
   2227         if (duplicate) {
   2228             continue;
   2229         }
   2230 
   2231         // Only if there is space...
   2232         if (first_count < count) {
   2233             first_section[first_count] = source_section[i];
   2234             first_count++;
   2235             source_section[i].type = dns_invalid_rr;
   2236         } else {
   2237             ERROR("first_count %d unexpectedly equal to count %d with i = %d", first_count, count, i);
   2238         }
   2239     }
   2240     *p_first_count = first_count;
   2241 }
   2242 
   2243 static dnssd_query_t *
   2244 dp_dns_queries_finished(dnssd_query_t *answered_query)
   2245 {
   2246     dns_message_t *first_message = NULL;
   2247     unsigned qdcount = 0, ancount = 0, nscount = 0, arcount = 0;
   2248     unsigned first_qdcount, first_ancount, first_nscount, first_arcount;
   2249     dnssd_query_t *first_query = NULL;
   2250     dp_tracker_t *tracker = answered_query->tracker;
   2251 
   2252     // response_query will be set to NULL if we don't want anything sent yet, to query if query is the
   2253     // only query or if there's an error in this function, or to the query that holds the aggregate response
   2254     // otherwise.
   2255     dnssd_query_t *response_query = answered_query;
   2256     const char *name = answered_query->question != NULL ? answered_query->question->name : "(null)";
   2257 
   2258     require_action_quiet(tracker != NULL, exit,
   2259                          dns_rcode_set(answered_query->response, dns_rcode_servfail);
   2260                          ERROR("NULL tracker on " PRI_S_SRP, name));
   2261     require_action_quiet(tracker->dns_queries != NULL, exit,
   2262                          dns_rcode_set(answered_query->response, dns_rcode_servfail);
   2263                          ERROR("NULL tracker->dns_queries on " PRI_S_SRP, name));
   2264 
   2265     // The usual case, there's only one question in the DNS message, so we can just
   2266     // return the answer now.
   2267     if (answered_query->num_questions == 1) {
   2268         goto exit;
   2269     }
   2270 
   2271     // Otherwise, we have more than one query, so see if any remain unsatisfied.
   2272     int satisfied = 0;
   2273     for (dnssd_query_t *match = tracker->dns_queries; match != NULL; match = match->next) {
   2274         // It's possible we could creep in here without actually generating one of the responses,
   2275         // in which case we should definitely fail at this point.
   2276         require_action_quiet(match->response != NULL,
   2277                              exit,
   2278                              ERROR("null response on match query");
   2279                              dns_rcode_set(response_query->response, dns_rcode_servfail));
   2280         if (match->message == answered_query->message) {
   2281             if (!match->satisfied) {
   2282                 response_query = NULL; // More answers coming.
   2283                 goto exit;
   2284             }
   2285             satisfied++;
   2286         }
   2287     }
   2288     if (satisfied != answered_query->num_questions) {
   2289         response_query = NULL;
   2290         goto exit;
   2291     }
   2292     // All queries have been satisfied.
   2293 
   2294     // Parse all of the messages (this is gross--later on we should just never convert to wire format until
   2295     // we get here.
   2296     for (dnssd_query_t *source = tracker->dns_queries; source != NULL; source = source->next) {
   2297         if (source->message == answered_query->message) {
   2298             // This should never fail, but...
   2299             require_action_quiet(dns_wire_parse(&source->response_msg, source->response,
   2300                                                 (unsigned)(source->towire.p - source->response->data) + DNS_HEADER_SIZE, false),
   2301                                  exit,
   2302                                  dns_rcode_set(response_query->response, dns_rcode_servfail));
   2303 
   2304             if (first_query == NULL) {
   2305                 first_query = source;
   2306                 first_message = first_query->response_msg;
   2307                 first_qdcount = first_message->qdcount;
   2308                 first_ancount = first_message->ancount;
   2309                 first_nscount = first_message->nscount;
   2310                 first_arcount = first_message->arcount;
   2311             }
   2312             qdcount += source->response_msg->qdcount;
   2313             ancount += source->response_msg->ancount;
   2314             nscount += source->response_msg->nscount;
   2315             arcount += source->response_msg->arcount;
   2316         }
   2317     }
   2318 
   2319     // Copy records from the response.
   2320     for (int i = 0; i < 4; i++) {
   2321         dns_rr_t *section, **first_section = NULL, **source_section = NULL;
   2322         unsigned section_count = 0, source_count = 0, *first_count = NULL;
   2323 
   2324         // Start with the second message, since the first is already populated.
   2325         for (dnssd_query_t *source = tracker->dns_queries;
   2326              source != NULL && answered_query->message == source->message ; source = source->next)
   2327         {
   2328 #define SECTION_CASE(index, counter_name, section_name)                   \
   2329             case index:                                                   \
   2330                 first_section = &first_message->section_name;             \
   2331                 source_section = &source->response_msg->section_name;     \
   2332                 section_count = counter_name;                             \
   2333                 source_count = source->response_msg->counter_name;        \
   2334                 first_count = &first_message->counter_name;               \
   2335                 break
   2336 
   2337             switch (i) {
   2338                     SECTION_CASE(0, qdcount, questions);
   2339                     SECTION_CASE(1, ancount, answers);
   2340                     SECTION_CASE(2, nscount, authority);
   2341                     SECTION_CASE(3, arcount, additional);
   2342             }
   2343 
   2344             // If this is the first matching query, expand the current section to be able to fit all of the data we're
   2345             // copying in, and then copy the data from the first section.
   2346             if (first_section == source_section) {
   2347                 section = calloc(section_count, sizeof(*section));
   2348                 require_action_quiet(section != NULL, exit,
   2349                                      dns_rcode_set(answered_query->response, dns_rcode_servfail);
   2350                                      ERROR("Unable to allocate memory for query response section on " PRI_S_SRP, name));
   2351                 memcpy(section, *first_section, source_count * sizeof(*section));
   2352                 memset(*first_section, 0, source_count * sizeof(*section)); // NULL out any pointers
   2353                 free(*first_section);
   2354                 *first_section = section;
   2355             } else {
   2356                 dp_move_rrs(*first_section, first_count, *source_section, source_count, section_count, i != 0);
   2357             }
   2358         }
   2359     }
   2360 
   2361     // Use the response in the first query to turn the answer to wire format.
   2362 redo_message:
   2363     dp_query_towire_reset(first_query);
   2364     dns_message_rrs_to_wire(&first_query->towire, first_query->response_msg);
   2365     if (first_query->towire.truncated) {
   2366         if (first_query->tracker->connection->tcp_stream) {
   2367             if (embiggen(first_query)) {
   2368                 first_query->towire.error = false;
   2369                 first_query->towire.truncated = false;
   2370                 goto redo_message;
   2371             }
   2372         }
   2373     }
   2374     first_query->response->qdcount = htons(first_message->qdcount);
   2375     first_query->response->ancount = htons(first_message->ancount);
   2376     first_query->response->nscount = htons(first_message->nscount);
   2377     first_query->response->arcount = htons(first_message->arcount);
   2378     response_query = first_query;
   2379 
   2380 exit:
   2381     return response_query;
   2382 }
   2383 
   2384 static void
   2385 dp_query_send_dns_response(dnssd_query_t *query, const char *context_description)
   2386 {
   2387     struct iovec iov;
   2388     dns_towire_state_t *towire = &query->towire;
   2389     const char *failnote = NULL;
   2390     uint8_t *revert = towire->p;
   2391     uint16_t tc = towire->truncated ? dns_flags_tc : 0;
   2392     uint16_t bitfield = ntohs(query->response->bitfield);
   2393     uint16_t mask = 0;
   2394     int rcode = dns_rcode_get(query->response);
   2395     question_t *question = query->question;
   2396 
   2397     // Mark this query as complete.
   2398     query->satisfied = true;
   2399 
   2400     VALIDATE_TRACKER_CONNECTION_NON_NULL();
   2401 
   2402     // Send an SOA record if it's a .local query.
   2403     if (question->served_domain != NULL && question->served_domain->interface != NULL &&
   2404         !towire->truncated && (question->type != dns_rrtype_soa || question->name[0] != '\0'))
   2405     {
   2406     redo:
   2407         // DNSSD Hybrid, Section 6.1.
   2408         TOWIRE_CHECK("&query->enclosing_domain_pointer 1", towire,
   2409                      dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
   2410         TOWIRE_CHECK("dns_rrtype_soa", towire,
   2411                      dns_u16_to_wire(towire, dns_rrtype_soa));
   2412         TOWIRE_CHECK("dns_qclass_in", towire,
   2413                      dns_u16_to_wire(towire, dns_qclass_in));
   2414         TOWIRE_CHECK("ttl", towire, dns_ttl_to_wire(towire, 3600));
   2415         TOWIRE_CHECK("rdlength_begin ", towire, dns_rdlength_begin(towire));
   2416         if (0) {
   2417 #if STUB_ROUTER
   2418         } else if (srp_servers->stub_router_enabled && my_name != NULL) {
   2419             TOWIRE_CHECK(my_name, towire, dns_full_name_to_wire(NULL, towire, my_name));
   2420 #endif
   2421         } else if (uuid_name[0] != 0) {
   2422             TOWIRE_CHECK("uuid_name", towire, dns_name_to_wire(NULL, towire, uuid_name));
   2423             TOWIRE_CHECK("&query->enclosing_domain_pointer 2", towire,
   2424                          dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
   2425         } else {
   2426             TOWIRE_CHECK("\"ns\"", towire, dns_name_to_wire(NULL, towire, "ns"));
   2427             TOWIRE_CHECK("&query->enclosing_domain_pointer 2", towire,
   2428                          dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
   2429         }
   2430         TOWIRE_CHECK("\"postmaster\"", towire,
   2431                      dns_name_to_wire(NULL, towire, "postmaster"));
   2432         TOWIRE_CHECK("&query->enclosing_domain_pointer 3", towire,
   2433                      dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
   2434         TOWIRE_CHECK("serial", towire,dns_u32_to_wire(towire, 0));     // serial
   2435         TOWIRE_CHECK("refresh", towire, dns_ttl_to_wire(towire, 7200));  // refresh
   2436         TOWIRE_CHECK("retry", towire, dns_ttl_to_wire(towire, 3600));  // retry
   2437         TOWIRE_CHECK("expire", towire, dns_ttl_to_wire(towire, 86400)); // expire
   2438         TOWIRE_CHECK("minimum", towire, dns_ttl_to_wire(towire, 120));    // minimum
   2439         dns_rdlength_end(towire);
   2440         if (towire->truncated) {
   2441             query->towire.p = revert;
   2442             if (query->tracker->connection->tcp_stream) {
   2443                 if (embiggen(query)) {
   2444                     query->towire.error = 0;
   2445                     towire->truncated = false;
   2446                     goto redo;
   2447                 }
   2448             } else {
   2449                 tc = dns_flags_tc;
   2450             }
   2451         } else {
   2452             query->response->nscount = htons(1);
   2453         }
   2454 
   2455         // Response is authoritative and not recursive.
   2456     authoritative:
   2457         mask = ~dns_flags_ra;
   2458         bitfield = bitfield | dns_flags_aa | tc;
   2459         bitfield = bitfield & mask;
   2460     } else {
   2461         // Response is recursive and not authoritative.
   2462         if (question->type != dns_rrtype_soa) {
   2463             mask = ~dns_flags_aa;
   2464             bitfield = bitfield | dns_flags_ra | tc;
   2465             bitfield = bitfield & mask;
   2466         } else {
   2467             goto authoritative;
   2468         }
   2469     }
   2470 
   2471     INFO("[Q%d][QU%d][QID %x] ->p %p ->lim %p len %zd rcode %d " PUB_S_SRP, SERIAL(query), SERIAL(question),
   2472          ntohs(query->message->wire.id), query->towire.p, &query->towire.message->data[0],
   2473          query->towire.p - &query->towire.message->data[0], dns_rcode_get(query->response), context_description);
   2474 
   2475     // In the case that we get an error looking something up, we return that error immediately on the query that failed,
   2476     // rather than trying to assemble a complete answer. In returning the error, we cancel any outstanding queries.
   2477     dnssd_query_t *send_query;
   2478 
   2479     if (!towire->error && rcode == dns_rcode_noerror) {
   2480         // It's possible that we got a query with qdcount > 1. In this case, we are going to marshal all of the
   2481         // answers from the responses we've constructed into a new response and send it after all of the queries
   2482         // have responses.  So at this point, if we don't have all the responses yet, there's no point in adding
   2483         // the edns0 option.  If we do, dp_dns_update_queries_finished will marshal all the answers into one
   2484         // message and after that we can add the edns0 option. If there's only one query, this is a no-op.
   2485         send_query = dp_dns_queries_finished(query);
   2486         if (send_query == NULL) {
   2487 #ifdef DNSSD_PROXY_DUMP_TRACKER_QUERIES
   2488             if (query->tracker == NULL) {
   2489                 ERROR("[Q%d] query->tracker is NULL", SERIAL(query));
   2490             } else {
   2491                 char logbuf[200];
   2492                 char *lbp = logbuf;
   2493                 char *lbend = logbuf + sizeof(logbuf);
   2494                 char *lbrestart;
   2495                 bool print_last = true;
   2496                 if (query->tracker->connection != NULL && query->tracker->connection->tcp_stream) {
   2497                     int len = snprintf(logbuf, sizeof(logbuf), "[Q%d] TCP %d: ", SERIAL(query), query->num_questions);
   2498                     lbrestart = logbuf + len;
   2499                 } else {
   2500                     int len = snprintf(logbuf, sizeof(logbuf), "[Q%d] UDP %p %d: ", SERIAL(query), query->num_questions);
   2501                     lbrestart = logbuf + len;
   2502                 }
   2503                 lbp = logbuf + strlen(logbuf);
   2504                 for (dnssd_query_t *list_query = query->tracker->dns_queries;
   2505                      list_query != NULL; list_query = list_query->next)
   2506                 {
   2507                     if (list_query->message != query->message) {
   2508                         continue;
   2509                     }
   2510                     int len = snprintf(lbp, lbend - lbp, "%p%s ", list_query, list_query->satisfied ? "+" : "=");
   2511                     if (lbp + len < lbend) {
   2512                         lbp += len;
   2513                         print_last = true;
   2514                     } else {
   2515                         *lbp = 0;
   2516                         INFO("[Q%d] " PUB_S_SRP, SERIAL(query), logbuf);
   2517                         lbp = lbrestart;
   2518                         *lbp = 0;
   2519                         print_last = false;
   2520                     }
   2521                 }
   2522                 if (print_last) {
   2523                     INFO("[Q%d] " PUB_S_SRP, SERIAL(query), logbuf);
   2524                 }
   2525             }
   2526 #endif // DNSSD_PROXY_DUMP_TRACKER_QUERIES
   2527             return;
   2528         }
   2529         if (dns_rcode_get(send_query->response) != dns_rcode_noerror) {
   2530             rcode = dns_rcode_get(send_query->response);
   2531         }
   2532 
   2533         towire = &send_query->towire;
   2534         revert = towire->p;
   2535     } else {
   2536         send_query = query;
   2537     }
   2538 
   2539     // Not authentic, checking not disabled.
   2540     mask = ~(dns_flags_rd | dns_flags_ad | dns_flags_cd);
   2541     bitfield = bitfield & mask;
   2542     send_query->response->bitfield = htons(bitfield);
   2543 
   2544     // This is a response
   2545     dns_qr_set(send_query->response, dns_qr_response);
   2546 
   2547     // If we got a failure from dp_dns_queries_finished(), skip adding the opt RR and checking for a towire error.
   2548     if (rcode == dns_rcode_noerror) {
   2549     // Send an OPT RR if we got one
   2550     // XXX reserve space so we can always send an OPT RR?
   2551         if (send_query->is_edns0) {
   2552         redo_edns0:
   2553             TOWIRE_CHECK("Root label", towire, dns_u8_to_wire(towire, 0));     // Root label
   2554             TOWIRE_CHECK("dns_rrtype_opt", towire, dns_u16_to_wire(towire, dns_rrtype_opt));
   2555             TOWIRE_CHECK("UDP Payload size", towire, dns_u16_to_wire(towire, 4096)); // UDP Payload size
   2556             TOWIRE_CHECK("extended-rcode", towire, dns_u8_to_wire(towire, 0));     // extended-rcode
   2557             TOWIRE_CHECK("EDNS version 0", towire, dns_u8_to_wire(towire, 0));     // EDNS version 0
   2558             TOWIRE_CHECK("No extended flags", towire, dns_u16_to_wire(towire, 0));    // No extended flags
   2559             TOWIRE_CHECK("No payload", towire, dns_u16_to_wire(towire, 0));    // No payload
   2560             if (towire->truncated) {
   2561                 send_query->towire.p = revert;
   2562                 if (send_query->tracker->connection->tcp_stream) {
   2563                     if (embiggen(send_query)) {
   2564                         send_query->towire.error = false;
   2565                         send_query->towire.truncated = false;
   2566                         goto redo_edns0;
   2567                     }
   2568                 }
   2569             } else {
   2570 #if SRP_FEATURE_NAT64
   2571                 send_query->response->arcount = htons(ntohs(send_query->response->arcount) + 1);
   2572 #else
   2573                 send_query->response->arcount = htons(1);
   2574 #endif
   2575             }
   2576         }
   2577 
   2578         if (towire->error) {
   2579             ERROR("[Q%d][QU%d][QID%x] failed on %s", SERIAL(query), SERIAL(question), ntohs(send_query->message->wire.id), failnote);
   2580             if (tc == dns_flags_tc) {
   2581                 dns_rcode_set(send_query->response, dns_rcode_noerror);
   2582             } else {
   2583                 dns_rcode_set(send_query->response, dns_rcode_servfail);
   2584             }
   2585         } else {
   2586             // No error.
   2587             dns_rcode_set(send_query->response, dns_rcode_noerror);
   2588         }
   2589     } else {
   2590         dns_rcode_set(send_query->response, rcode);
   2591     }
   2592 
   2593     iov.iov_len = (send_query->towire.p - (uint8_t *)send_query->response);
   2594     iov.iov_base = send_query->response;
   2595     INFO("[Q%d][QU%d] (len %zd)", SERIAL(query), SERIAL(question), iov.iov_len);
   2596 
   2597     ioloop_send_message(send_query->tracker->connection, send_query->message, &iov, 1);
   2598 
   2599     // Cancel the send_query.
   2600     dnssd_query_cancel(send_query);
   2601 }
   2602 
   2603 static void
   2604 dp_query_towire_reset(dnssd_query_t *query)
   2605 {
   2606     query->towire.p = &query->response->data[0];  // We start storing RR data here.
   2607     query->towire.lim = &query->response->data[0] + query->data_size; // This is the limit to how much we can store.
   2608     query->towire.message = query->response;
   2609     query->towire.p_rdlength = NULL;
   2610     query->towire.p_opt = NULL;
   2611     query->p_dso_length = NULL;
   2612 }
   2613 
   2614 static void
   2615 dns_push_start(dnssd_query_t *query)
   2616 {
   2617     const char *failnote = NULL;
   2618 
   2619     // If we don't have a dso header yet, start one.
   2620     if (query->p_dso_length == NULL) {
   2621         memset(query->response, 0, (sizeof *query->response) - DNS_DATA_SIZE);
   2622         dns_opcode_set(query->response, dns_opcode_dso);
   2623         // This is a unidirectional DSO message, which is marked as a query
   2624         dns_qr_set(query->response, dns_qr_query);
   2625         // No error cuz not a response.
   2626         dns_rcode_set(query->response, dns_rcode_noerror);
   2627 
   2628         TOWIRE_CHECK("kDSOType_DNSPushUpdate", &query->towire,
   2629                      dns_u16_to_wire(&query->towire, kDSOType_DNSPushUpdate));
   2630         if (query->towire.p + 2 > query->towire.lim) {
   2631             ERROR("[Q%d] No room for dso length in DNS Push notification message.", SERIAL(query));
   2632             dp_query_towire_reset(query);
   2633             return;
   2634         }
   2635         query->p_dso_length = query->towire.p;
   2636         query->towire.p += 2;
   2637     }
   2638     if (failnote != NULL) {
   2639         ERROR("[Q%d] couldn't start update: %s", SERIAL(query), failnote);
   2640     }
   2641 }
   2642 
   2643 static void
   2644 dp_push_response(dnssd_query_t *query, dns_rr_t *original_question)
   2645 {
   2646     struct iovec iov;
   2647     question_t *question = query->question;
   2648     char nbuf[DNS_MAX_NAME_SIZE_ESCAPED + 1];
   2649     char *name = "<null question name>";
   2650     if (question != NULL) {
   2651         name = question->name;
   2652     } else if (original_question != NULL) {
   2653         dns_name_print(original_question->name, nbuf, sizeof(nbuf));
   2654         name = nbuf;
   2655     }
   2656 
   2657     VALIDATE_TRACKER_CONNECTION_NON_NULL();
   2658 
   2659     if (query->p_dso_length != NULL) {
   2660         int16_t dso_length = query->towire.p - query->p_dso_length - 2;
   2661         iov.iov_len = (query->towire.p - (uint8_t *)query->response);
   2662         iov.iov_base = query->response;
   2663         INFO("[Q%d][QU%d] " PRI_S_SRP " (len %zd)", SERIAL(query), SERIAL(question), name, iov.iov_len);
   2664 
   2665         query->towire.p = query->p_dso_length;
   2666         dns_u16_to_wire(&query->towire, dso_length);
   2667         ioloop_send_message(query->tracker->connection, query->message, &iov, 1);
   2668         dp_query_towire_reset(query);
   2669     }
   2670 }
   2671 
   2672 static bool
   2673 dnssd_hardwired_response(dnssd_query_t *query, DNSServiceQueryRecordReply UNUSED callback)
   2674 {
   2675     hardwired_t *hp;
   2676     question_t *question = query->question;
   2677     const char *response_type = NULL;
   2678     uint8_t v4mapped[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
   2679 
   2680     // If the question is for our uuid name in a domain we're authoritative for, respond with the IP address that
   2681     // the question was received on.
   2682     if (!strcasecmp(question->name, uuid_name) && (question->type == dns_rrtype_a || question->type == dns_rrtype_aaaa)) {
   2683         addr_t *local = NULL;
   2684         if (query->message != NULL) {
   2685             local = &query->message->local;
   2686         } else {
   2687             local = &query->dso->transport->local;
   2688         }
   2689 
   2690         // If it's an IPv4 address we can respond with an A record.
   2691         if (question->type == dns_rrtype_a && local->sa.sa_family == AF_INET) {
   2692             dp_query_add_data_to_response(query, question->name, question->type, dns_qclass_in, 4,
   2693                                           &local->sin.sin_addr, 300, true, true, &query->response->ancount);
   2694             response_type = "local host IPv4 address";
   2695         }
   2696         // If it's an IPv4-mapped IPv6 address, we can respond with an A record
   2697         else if (local->sa.sa_family == AF_INET6 && question->type == dns_rrtype_a &&
   2698                  !memcmp(&local->sin6.sin6_addr, v4mapped, sizeof(v4mapped)))
   2699         {
   2700             dp_query_add_data_to_response(query, question->name, question->type, dns_qclass_in, 4,
   2701                                           ((uint8_t *)&local->sin6.sin6_addr) + 12, 3600, true, true,
   2702                                           &query->response->ancount);
   2703             response_type = "local host v4-mapped address";
   2704         }
   2705         // If it's an IPv6 address and NOT a v4-mapped address, we can respond with an AAAA record.
   2706         else if (local->sa.sa_family == AF_INET6 && question->type == dns_rrtype_aaaa &&
   2707                  memcmp(&local->sin6.sin6_addr, v4mapped, sizeof(v4mapped)))
   2708         {
   2709             struct in6_addr response = local->sin6.sin6_addr;
   2710             bool address_is_usable = false;
   2711             // If it's not a synthesized anycast or rloc address, we can just use it.
   2712             if (!is_thread_mesh_synthetic_address(&response)) {
   2713                 address_is_usable = true;
   2714                 response_type = "local host IPv6 address";
   2715             } else {
   2716                 // Otherwise, we need to find the mesh-local address and respond with that.
   2717                 srp_server_t *server_state = srp_servers;
   2718 #if SRP_TEST_SERVER
   2719                 for (; !address_is_usable && server_state != NULL; server_state = server_state->next)
   2720 #endif
   2721                 {
   2722                     if (0) {
   2723 #if STUB_ROUTER
   2724                     } else if (server_state->stub_router_enabled) {
   2725                         route_state_t *route_state = server_state->route_state;
   2726                         if (route_state->thread_interface_name != NULL) {
   2727                             for (interface_address_state_t *address = route_state->interface_addresses;
   2728                                  !address_is_usable && address != NULL; address = address->next)
   2729                             {
   2730                                 // Wrong interface or wrong type of address
   2731                                 if (strcmp(address->name, route_state->thread_interface_name) ||
   2732                                     address->addr.sa.sa_family != AF_INET6)
   2733                                 {
   2734                                     continue;
   2735                                 }
   2736                                 if (!is_thread_mesh_synthetic_or_link_local(&address->addr.sin6.sin6_addr))
   2737                                 {
   2738                                     memcpy(&response, &address->addr.sin6.sin6_addr, sizeof(response));
   2739                                     response_type = "thread interface address";
   2740                                     address_is_usable = true;
   2741                                 }
   2742                             }
   2743                             if (address_is_usable == false) {
   2744                                 response_type = "no usable address on thread interface";
   2745                             }
   2746                         } else {
   2747                             address_is_usable = false;
   2748                             response_type = "thread interface name unknown";
   2749                         }
   2750 #endif
   2751                     } else {
   2752                         // For thread device, the only thing that can work is the ML-EID.
   2753                         if (service_publisher_get_ml_eid(server_state->service_publisher, &response)) {
   2754                             address_is_usable = true;
   2755                             response_type = "thread device ML-EID";
   2756                         } else {
   2757                             response_type = "thread ML-EID not known";
   2758                         }
   2759                     }
   2760                 }
   2761             }
   2762             if (address_is_usable) {
   2763                 SEGMENTED_IPv6_ADDR_GEN_SRP(&response, response_buf);
   2764                 INFO(PUB_S_SRP " IN AAAA " PRI_SEGMENTED_IPv6_ADDR_SRP " " PUB_S_SRP, question->name,
   2765                      SEGMENTED_IPv6_ADDR_PARAM_SRP(&response, response_buf), response_type);
   2766                 dp_query_add_data_to_response(query, question->name, question->type, dns_qclass_in, 16,
   2767                                               &response, 300, true, true, &query->response->ancount);
   2768             }
   2769         }
   2770     } else {
   2771         for (hp = query->question->served_domain->hardwired_responses; hp; hp = hp->next) {
   2772             if ((query->question->type == hp->type || query->question->type == dns_rrtype_any) &&
   2773                 query->question->qclass == dns_qclass_in && !strcasecmp(hp->name, query->question->name))
   2774             {
   2775                 if (query->dso != NULL) {
   2776                     // Since hardwired response is set by the dnssd-proxy itself, do not do ".local" translation.
   2777                     dp_query_add_data_to_response(query, hp->fullname, hp->type, dns_qclass_in, hp->rdlen, hp->rdata,
   2778                                                   3600, true, false, NULL);
   2779                 } else {
   2780                     // Store the response
   2781                     if (!query->towire.truncated) {
   2782                         // Since hardwired response is set by the dnssd-proxy itself, do not do ".local" translation.
   2783                         dp_query_add_data_to_response(query, hp->fullname, hp->type, dns_qclass_in,
   2784                                                       hp->rdlen, hp->rdata, 3600, true, false,
   2785                                                       &query->response->ancount);
   2786                     }
   2787                 }
   2788                 response_type = "hardwired";
   2789             }
   2790         }
   2791     }
   2792     if (response_type != NULL) {
   2793         return true;
   2794     }
   2795     return false;
   2796 }
   2797 
   2798 #if SRP_FEATURE_NAT64
   2799 static void
   2800 dp_query_append_nat64_prefix_records(dnssd_query_t *query)
   2801 {
   2802     // 192.0.0.170 and 192.0.0.171 are reserved IPv4 addresses for ipv4only.arpa.
   2803     // See <https://tools.ietf.org/html/rfc7050#section-8.2>.
   2804     const uint8_t ipv4_addrs[2][4] = {
   2805         {192, 0, 0, 170},
   2806         {192, 0, 0, 171}
   2807     };
   2808     uint8_t rdata[16] = {0};
   2809 
   2810     VALIDATE_TRACKER_CONNECTION_NON_NULL();
   2811 
   2812     const struct in6_addr *prefix = nat64_get_ipv6_prefix();
   2813     memcpy(rdata, prefix->s6_addr, sizeof(rdata));
   2814     for (size_t i = 0; i < countof(ipv4_addrs);) {
   2815         memcpy(&rdata[12], ipv4_addrs[i], 4);
   2816         uint8_t *revert = query->towire.p;
   2817         dp_query_add_data_to_response(query, "ipv4only.arpa.", dns_rrtype_aaaa, query->question->qclass,
   2818                                       (uint16_t)sizeof(rdata), rdata, RFC8766_TTL_CLAMP, true, false,
   2819                                       &query->response->arcount);
   2820         if (query->towire.truncated) {
   2821             query->towire.p = revert;
   2822             if (query->tracker->connection->tcp_stream) {
   2823                 if (embiggen(query)) {
   2824                     query->towire.truncated = false;
   2825                     query->towire.error = false;
   2826                     continue;
   2827                 } else {
   2828                     dns_rcode_set(query->response, dns_rcode_servfail);
   2829                 }
   2830             }
   2831             return;
   2832         }
   2833         i++;
   2834     }
   2835 }
   2836 #endif // SRP_FEATURE_NAT64
   2837 
   2838 static void
   2839 dns_query_answer_process(DNSServiceFlags flags, DNSServiceErrorType errorCode,
   2840                          const char *fullname, uint16_t rrtype, uint16_t rrclass,
   2841                          uint16_t rdlen, const void *rdata, uint32_t ttl, dnssd_query_t *query, bool send)
   2842 {
   2843     question_t *question = query->question;
   2844 
   2845     INFO("[Q%d][QU%d] " PRI_S_SRP PUB_S_SRP PUB_S_SRP " %d %x %d %p", SERIAL(query), SERIAL(question),
   2846          fullname, (flags & kDNSServiceFlagsMoreComing) ? " m " : " ", dns_rrtype_to_string(rrtype), rrclass, rdlen,
   2847          errorCode, query);
   2848 
   2849     VALIDATE_TRACKER_CONNECTION_NON_NULL();
   2850 
   2851     if (errorCode == kDNSServiceErr_NoError) {
   2852 #if SRP_FEATURE_NAT64
   2853         const bool aaaa_query_got_a_record = (question->type == dns_rrtype_aaaa) && (rrtype == dns_rrtype_a);
   2854         if (srp_servers->srp_nat64_enabled && (ntohs(query->response->arcount) != 0) && !aaaa_query_got_a_record) {
   2855             return;
   2856         }
   2857 #endif
   2858     re_add:
   2859         if (send) {
   2860             uint16_t *counter = &query->response->ancount;
   2861 #if SRP_FEATURE_NAT64
   2862             if (srp_servers->srp_nat64_enabled && aaaa_query_got_a_record) {
   2863                 counter = &query->response->arcount;
   2864             }
   2865 #endif
   2866             uint8_t *revert = query->towire.p;
   2867             dp_query_add_data_to_response(query, fullname, rrtype, rrclass, rdlen, rdata,
   2868                                           ttl > RFC8766_TTL_CLAMP ? RFC8766_TTL_CLAMP : ttl, false, false, counter);
   2869             if (query->towire.truncated) {
   2870                 query->towire.p = revert;
   2871                 if (query->tracker->connection->tcp_stream) {
   2872                     if (embiggen(query)) {
   2873                         query->towire.truncated = false;
   2874                         query->towire.error = false;
   2875                         goto re_add;
   2876                     } else {
   2877                         dns_rcode_set(query->response, dns_rcode_servfail);
   2878                         dp_query_send_dns_response(query, "failed embiggen");
   2879                         return;
   2880                     }
   2881                 }
   2882             }
   2883         }
   2884         // If there isn't more coming, send the response now
   2885         if (!(flags & kDNSServiceFlagsMoreComing) || query->towire.truncated) {
   2886             // When we get a CNAME response, we may not get the record it points to with the MoreComing
   2887             // flag set, so don't respond yet.
   2888             if (question->type != dns_rrtype_cname && rrtype == dns_rrtype_cname) {
   2889                 INFO("[Q%d][QU%d] not responding yet because CNAME.", SERIAL(query), SERIAL(question));
   2890             } else {
   2891 #if SRP_FEATURE_NAT64
   2892                 if (srp_servers->srp_nat64_enabled && (ntohs(query->response->arcount) != 0)) {
   2893                     dp_query_append_nat64_prefix_records(query);
   2894                 }
   2895 #endif
   2896                 dp_query_send_dns_response(query, "normal success");
   2897             }
   2898         }
   2899     } else if (errorCode == kDNSServiceErr_NoSuchRecord) {
   2900         // If we get "no such record," we can't really do much except return the answer.
   2901         dp_query_send_dns_response(query, "no such record");
   2902     } else {
   2903         dns_rcode_set(query->response, dns_rcode_servfail);
   2904         dp_query_send_dns_response(query, "unhandled error");
   2905     }
   2906 }
   2907 
   2908 // answer_match is to decide if an answer matches the one requested to be removed.
   2909 // Based on rfc8765
   2910 // Remove all RRsets from a name in all classes:
   2911 //      TTL = 0xFFFFFFFE, RDLEN = 0, CLASS = 255 (ANY).
   2912 // Remove all RRsets from a name in given class:
   2913 //      TTL = 0xFFFFFFFE, RDLEN = 0, CLASS gives class, TYPE = 255 (ANY).
   2914 // Remove specified RRset from a name in given class:
   2915 //      TTL = 0xFFFFFFFE, RDLEN = 0,
   2916 //      CLASS and TYPE specify the RRset being removed.
   2917 // Remove an individual RR from a name:
   2918 //      TTL = 0xFFFFFFFF,
   2919 //      CLASS, TYPE, RDLEN, and RDATA specify the RR being removed.
   2920 static bool
   2921 answer_match(const answer_t *answer, uint32_t rdlen, const char *fullname, uint16_t rrtype, uint16_t rrclass, const void *rdata)
   2922 {
   2923     return (((rrclass == dns_qclass_any) || (rrclass == answer->rrclass)) &&
   2924             ((rrtype == dns_rrtype_any) || (rrtype == answer->rrtype)) &&
   2925             ((rdlen == 0) || ((rdlen == answer->rdlen) && (memcmp(answer->rdata, rdata, rdlen) == 0))) &&
   2926             (!strcmp(answer->fullname, fullname))
   2927             );
   2928 }
   2929 
   2930 static void
   2931 dns_push_query_answer_process(DNSServiceFlags flags, DNSServiceErrorType errorCode,
   2932                               const char *fullname, uint16_t rrtype, uint16_t rrclass,
   2933                               uint16_t rdlen, const void *rdata, uint32_t ttl, dnssd_query_t *query, bool send);
   2934 
   2935 // This is the callback for both dns query and dns push query results.
   2936 static void
   2937 dns_question_callback(DNSServiceRef UNUSED sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
   2938                       DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass,
   2939                       uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
   2940 {
   2941     question_t *question = context;
   2942     dnssd_query_t *query, *next;
   2943     bool send = true;
   2944 
   2945     // For dns push query,  insert or remove answer from the question cache depending on the flags
   2946     // For dns query (dso==NULL), add answer when receiving callback to the question
   2947     if (errorCode == kDNSServiceErr_NoError) {
   2948         if (flags & kDNSServiceFlagsAdd) {
   2949             // Eliminate duplicates (appears on more than one interface)
   2950             for (answer_t *answer = question->answers; answer != NULL; answer = answer->next) {
   2951                 if (answer_match(answer, rdlen, fullname, rrtype, rrclass, rdata)) {
   2952                     INFO("[QU%d] duplicate answer in cache - name: " PRI_S_SRP ", rrtype: " PUB_S_SRP
   2953                          ", rrclass: " PUB_S_SRP ", rdlen: %u." PUB_S_SRP, SERIAL(question),
   2954                          fullname, dns_rrtype_to_string(rrtype), dns_qclass_to_string(rrclass), rdlen,
   2955                          (flags & kDNSServiceFlagsMoreComing) ? " more coming" : " done");
   2956                     send = false;
   2957                     break;
   2958                 }
   2959             }
   2960             if (send) {
   2961                 // Add the extra space rdlen stores rdata at the end
   2962                 answer_t *answer = calloc(1, sizeof(*answer) + rdlen);
   2963                 if (answer == NULL) {
   2964                     ERROR("[QU%d] unable to allocate memory for answer - name: " PRI_S_SRP ", rrtype: " PUB_S_SRP
   2965                           ", rrclass: " PUB_S_SRP ", rdlen: %u.", SERIAL(question),
   2966                           fullname, dns_rrtype_to_string(rrtype), dns_qclass_to_string(rrclass), rdlen);
   2967                     return;
   2968                 }
   2969                 answer->fullname = strdup(fullname);
   2970                 if (answer->fullname == NULL) {
   2971                     ERROR("[QU%d] strdup failed to copy the answer name: " PRI_S_SRP, SERIAL(question), fullname);
   2972                     free(answer);
   2973                     return;
   2974                 }
   2975                 answer->interface_index = interfaceIndex;
   2976                 answer->ttl = ttl;
   2977                 answer->rrtype = rrtype;
   2978                 answer->rrclass = rrclass;
   2979                 answer->rdlen = rdlen;
   2980                 answer->rdata = (uint8_t *)(answer + 1);
   2981                 memcpy(answer->rdata, rdata, rdlen);
   2982                 answer->next = NULL;
   2983                 // Insert answer at the tail
   2984                 answer_t **tail = &(question->answers);
   2985                 while (*tail != NULL) {
   2986                     tail = &((*tail)->next);
   2987                 }
   2988                 *tail = answer;
   2989                 // Received data; reset no_data flag.
   2990                 question->no_data = false;
   2991                 INFO("[QU%d] add answer to cache - name: " PRI_S_SRP ", rrtype: " PUB_S_SRP
   2992                      ", rrclass: " PUB_S_SRP ", rdlen: %u." PUB_S_SRP, SERIAL(question),
   2993                      fullname, dns_rrtype_to_string(rrtype), dns_qclass_to_string(rrclass), rdlen,
   2994                  (flags & kDNSServiceFlagsMoreComing) ? " more coming" : " done");
   2995             }
   2996         } else {
   2997             // Remove
   2998             answer_t **answer = &(question->answers);
   2999             answer_t *cur = NULL;
   3000             bool matched = false;
   3001             while (*answer != NULL) {
   3002                 cur = *answer;
   3003                 if (answer_match(cur, rdlen, fullname, rrtype, rrclass, rdata)) {
   3004                     INFO("[QU%d] remove answer from cache - "
   3005                          "name: " PRI_S_SRP ", rrtype: " PUB_S_SRP ", rrclass: " PUB_S_SRP ", rdlen: %u." PUB_S_SRP,
   3006                          SERIAL(question), fullname, dns_rrtype_to_string(rrtype), dns_qclass_to_string(rrclass), rdlen,
   3007                          (flags & kDNSServiceFlagsMoreComing) ? " more coming" : " done");
   3008                     *answer = cur->next;
   3009                     dp_answer_free(cur);
   3010                     matched = true;
   3011                     // If individual RR to be removed, get out of the loop once the RR has been removed
   3012                     if (rdlen != 0) {
   3013                         break;
   3014                     }
   3015                 } else {
   3016                     answer = &cur->next;
   3017                 }
   3018             }
   3019             if (!matched) {
   3020                 INFO("[Q%d] remove not found in cache - name: " PRI_S_SRP
   3021                      ", rrtype: " PUB_S_SRP ", rrclass: " PUB_S_SRP ", rdlen: %u." PUB_S_SRP, SERIAL(question),
   3022                      fullname, dns_rrtype_to_string(rrtype), dns_qclass_to_string(rrclass), rdlen,
   3023                      (flags & kDNSServiceFlagsMoreComing) ? " more coming" : " done");
   3024             }
   3025             if (*answer == NULL) {
   3026                 // All the answers get removed; set no_data flag.
   3027                 question->no_data = true;
   3028             }
   3029         }
   3030     } else if (errorCode == kDNSServiceErr_NoSuchRecord) {
   3031         INFO("[QU%d] no data - name: " PRI_S_SRP ", rrtype: " PUB_S_SRP
   3032              ", rrclass: " PUB_S_SRP ", rdlen: %u." PUB_S_SRP, SERIAL(question), fullname, dns_rrtype_to_string(rrtype),
   3033              dns_qclass_to_string(rrclass), rdlen, (flags & kDNSServiceFlagsMoreComing) ? " more coming" : " done");
   3034         question->no_data = true;
   3035     } else if (errorCode == kDNSServiceErr_ServiceNotRunning || errorCode == kDNSServiceErr_DefunctConnection) {
   3036 #if SRP_FEATURE_DNSSD_PROXY_SHARED_CONNECTIONS
   3037         if (shared_discovery_txn != NULL) {
   3038             ioloop_dnssd_txn_cancel(shared_discovery_txn);
   3039             ioloop_dnssd_txn_release(shared_discovery_txn);
   3040             shared_discovery_txn = NULL;
   3041             dp_handle_server_disconnect(NULL, errorCode);
   3042         }
   3043 #else
   3044         ioloop_dnssd_txn_cancel(question->txn);
   3045         ioloop_dnssd_txn_release(question->txn);
   3046         question->txn = NULL;
   3047         dp_handle_server_disconnect(NULL, errorCode);
   3048 #endif
   3049         return; // This doesn't count as a result.
   3050     }
   3051     query = question->queries;
   3052     while(query != NULL) {
   3053         next = query->question_next;
   3054         if (query->dso != NULL) {
   3055             dns_push_query_answer_process(flags, errorCode, fullname, rrtype, rrclass,
   3056                                           rdlen, rdata, ttl, query, send);
   3057         } else {
   3058             dns_query_answer_process(flags, errorCode, fullname, rrtype, rrclass,
   3059                                      rdlen, rdata, ttl, query, send);
   3060         }
   3061         query = next;
   3062     }
   3063     dp_question_cache_remove_queries(question);
   3064 }
   3065 
   3066 static void
   3067 dp_query_wakeup(void *context)
   3068 {
   3069     dnssd_query_t *query = context;
   3070     char name[DNS_MAX_NAME_SIZE + 1];
   3071     size_t namelen = strlen(query->question->name);
   3072     question_t *question = query->question;
   3073 
   3074     if (question->answers != NULL) {
   3075         FAULT("[Q%d][QU%d] answers present, but dp_query_wakeup reached for name " PRI_S_SRP,
   3076               SERIAL(query), SERIAL(question), question->name);
   3077     } else {
   3078         question->no_data = true;
   3079     }
   3080 
   3081     // Should never happen.
   3082     if (namelen + (question->served_domain
   3083                    ? (question->served_domain->interface != NULL
   3084                       ? sizeof local_suffix
   3085                       // XXX why are we checking this but not copying in the served domain name below?
   3086                       : strlen(question->served_domain->domain_ld) + 1)
   3087                    : 0) > sizeof name) {
   3088         ERROR("[Q%d][QU%d] no space to construct name.", SERIAL(query), SERIAL(question));
   3089         dnssd_query_cancel(query);
   3090         return;
   3091     }
   3092 
   3093     memcpy(name, question->name, namelen + 1);
   3094     if (question->served_domain != NULL) {
   3095         memcpy(name + namelen, local_suffix, sizeof(local_suffix));
   3096     }
   3097     RETAIN_HERE(query, dnssd_query);
   3098     dp_query_send_dns_response(query, "query wakeup");
   3099     dp_question_cache_remove_queries(question);
   3100     RELEASE_HERE(query, dnssd_query);
   3101 }
   3102 
   3103 // Search asked question in the cache; if not existing, create one.
   3104 static question_t *
   3105 dp_query_question_cache_copy(dns_rr_t *search_term, bool *new)
   3106 {
   3107     char name[DNS_MAX_NAME_SIZE + 1];
   3108     served_domain_t *sdt = dp_served(search_term->name, name, sizeof(name));
   3109 
   3110     if (sdt == NULL) {
   3111         dns_name_print(search_term->name, name, sizeof name);
   3112     }
   3113     question_t **questions, *ret = NULL;
   3114     question_t *new_question = NULL;
   3115     // if the query is in served domain, lookup in served_domain->questions
   3116     // otherwise lookup in the out-of-domain question cache
   3117     if (sdt != NULL) {
   3118         questions = &sdt->questions;
   3119     } else {
   3120         questions = &questions_without_domain;
   3121     }
   3122     *new = false;
   3123     while (*questions != NULL) {
   3124         question_t *question = *questions;
   3125         if (search_term->type == question->type &&
   3126             search_term->qclass == question->qclass &&
   3127             !strcmp(name, question->name))
   3128         {
   3129             ret = question;
   3130             break;
   3131         }
   3132         questions = &question->next;
   3133     }
   3134 
   3135     // If no cache entry was found, create one
   3136     if (*questions == NULL) {
   3137         new_question = calloc(1, sizeof(*new_question));
   3138         require_action_quiet(new_question != NULL, exit,
   3139                              ERROR("Unable to allocate memory for question entry on " PRI_S_SRP, name));
   3140         new_question->name = strdup(name);
   3141         require_action_quiet(new_question->name != NULL, exit,
   3142                              ERROR("unable to allocate memory for question name on " PRI_S_SRP, name));
   3143         new_question->type = search_term->type;
   3144         new_question->qclass = search_term->qclass;
   3145         new_question->start_time = srp_utime();
   3146         new_question->answers = NULL;
   3147         new_question->served_domain = sdt;
   3148         new_question->queries = NULL;
   3149         new_question->no_data = false;
   3150         new_question->serial = ++cur_question_serial;
   3151 
   3152         if (sdt != NULL && sdt->interface != NULL) {
   3153             new_question->interface_index = sdt->interface->ifindex;
   3154             new_question->serviceFlags = kDNSServiceFlagsForceMulticast;
   3155         } else {
   3156             new_question->interface_index = kDNSServiceInterfaceIndexAny;
   3157             new_question->serviceFlags = kDNSServiceFlagsReturnIntermediates;
   3158         }
   3159 
   3160         // Link the new_question to the question list.
   3161         new_question->next = *questions;
   3162         *questions = new_question;
   3163         RETAIN_HERE(*questions, question); // retain
   3164 
   3165         // Successfully created a new question, which will be the returned question.
   3166         ret = new_question;
   3167         new_question = NULL;
   3168         *new = true;
   3169     }
   3170 exit:
   3171     if (new_question != NULL) {
   3172         RELEASE_HERE(new_question, question);
   3173     }
   3174     if (ret != NULL) {
   3175         RETAIN_HERE(ret, question);
   3176     }
   3177     return ret;
   3178 }
   3179 
   3180 // Look for answers in the cache for the current query. Remove flag is used when mDNSResponder connection is broken, to signal to
   3181 // DNS Push clients only that the records previously sent should be discarded.
   3182 static void
   3183 dp_query_reply_from_cache(question_t *question, dnssd_query_t *query, bool remove)
   3184 {
   3185     // For dns query, if no_data is flagged or it's been six seconds since the question
   3186     // was started and there is still no answer yet, we should also respond immediately.
   3187     // [DNS Discovery Proxy RFC, RFC 8766, Section 5.6]
   3188     // Note that six seconds as stated in RFC8766 is probably too long, currently we're using 800ms.
   3189     if (query->dso == NULL &&
   3190         (question->no_data == true ||
   3191          (question->answers == NULL &&
   3192           srp_utime() - question->start_time > RESPONSE_WINDOW_USECS)))
   3193     {
   3194         INFO("[Q%d][QU%d] no data for question - type %d class %d " PRI_S_SRP,
   3195              SERIAL(query), SERIAL(question), question->type, question->qclass, question->name);
   3196         dns_query_answer_process(0, kDNSServiceErr_NoSuchRecord, question->name,
   3197                                  question->type, question->qclass, 0,
   3198                                  NULL, 0, query, true);
   3199         dp_question_cache_remove_queries(question);
   3200         return;
   3201     }
   3202     // answers are available for the question being asked
   3203     if (question->answers != NULL) {
   3204         INFO("[Q%d][QU%d] reply from cache for question - type %d class %d " PRI_S_SRP,
   3205              SERIAL(query), SERIAL(question), question->type, question->qclass, question->name);
   3206         DNSServiceFlags flags;
   3207         answer_t *answer = question->answers;
   3208         while (answer != NULL) {
   3209             if (remove) {
   3210                 flags = 0;
   3211             } else {
   3212                 flags = kDNSServiceFlagsAdd;
   3213             }
   3214 
   3215             answer_t *next = answer->next;
   3216             if (next != NULL) {
   3217                 flags |= kDNSServiceFlagsMoreComing;
   3218             }
   3219             if (query->dso == NULL) {
   3220                 if (!remove) {
   3221                     dns_query_answer_process(flags, kDNSServiceErr_NoError, answer->fullname,
   3222                                              answer->rrtype, answer->rrclass, answer->rdlen,
   3223                                              answer->rdata, answer->ttl, query, true);
   3224                 }
   3225             } else {
   3226                 dns_push_query_answer_process(flags, kDNSServiceErr_NoError, answer->fullname,
   3227                                               answer->rrtype, answer->rrclass, answer->rdlen,
   3228                                               answer->rdata, answer->ttl, query, true);
   3229             }
   3230             answer = next;
   3231         }
   3232         dp_question_cache_remove_queries(question);
   3233     }
   3234 }
   3235 
   3236 static void
   3237 dp_query_context_release(void *context)
   3238 {
   3239     dnssd_query_t *query = context;
   3240     RELEASE_HERE(query, dnssd_query);
   3241 }
   3242 
   3243 static bool
   3244 dp_query_start(dnssd_query_t *query, int *rcode, bool *hardwired, bool dns64)
   3245 {
   3246     bool local = false;
   3247     question_t *question = query->question;
   3248 
   3249     if (question->served_domain != NULL) {
   3250         if (dnssd_hardwired_response(query, dns_question_callback)) {
   3251             *rcode = dns_rcode_noerror; // indicate that we already sent the response
   3252             *hardwired = true;
   3253             INFO("[Q%d] hardwired response", SERIAL(query));
   3254             return true;
   3255         }
   3256         local = true;
   3257     }
   3258 
   3259     // If we get an SOA query for record that's under a zone cut we're authoritative for, which
   3260     // is the case of query->served_domain->interface != NULL, then answer with a negative response that includes
   3261     // our authority records, rather than waiting for the query to time out.
   3262     if (question->served_domain != NULL && question->served_domain->interface != NULL && !question->name[0]) {
   3263         // If this isn't a DNS Push query, we can signal that there is no data. Otherwise we just never send an answer since
   3264         // we will never have one.
   3265         if (query->dso == NULL) {
   3266             *hardwired = true;
   3267         }
   3268         return true;
   3269     }
   3270 
   3271     // Check if DNSServiceQueryRecord call needs to be made
   3272     if (question->txn == NULL) {
   3273         int ret = dp_start_question(question, dns64);
   3274         if (ret == kDNSServiceErr_Refused) {
   3275             *rcode = dns_rcode_servfail;
   3276             INFO("question was refused");
   3277         } else if (ret != kDNSServiceErr_NoError) {
   3278             *rcode = dns_rcode_servfail;
   3279             INFO("[Q%d] couldn't start question", SERIAL(query));
   3280             return false;
   3281         }
   3282     } else {
   3283         if (question->answers != NULL || question->no_data) {
   3284             INFO("[Q%d] answering immediately from cache", SERIAL(query));
   3285             *rcode = dns_rcode_noerror;
   3286             return true;
   3287         }
   3288     }
   3289 
   3290     // If this isn't a DNS Push subscription, we need to respond quickly with as much data as we have.  It
   3291     // turns out that dig gives us a second, but also that responses seem to come back in on the order of a
   3292     // millisecond, so we'll wait 100ms.
   3293     if (query->dso == NULL && local) {
   3294         // [DNS Discovery Proxy RFC, RFC 8766, Section 5.6, Answer Aggregation]
   3295 
   3296         // RFC8766 asks us to wait six seconds, but this is probably too long. Most likely we will have all
   3297         // our answers much sooner than that, and waiting this long means that we have to keep state for
   3298         // this long; when there are a lot of queries coming in, that can amount to too much state, causing
   3299         // us to drop requests we could easily have answered.
   3300         if (query->wakeup == NULL) {
   3301             query->wakeup = ioloop_wakeup_create();
   3302             if (query->wakeup == NULL) {
   3303                 *rcode = dns_rcode_servfail;
   3304                 return false;
   3305             }
   3306         }
   3307         ioloop_add_wake_event(query->wakeup, query, dp_query_wakeup, dp_query_context_release, RESPONSE_WINDOW_MSECS /* ms */);
   3308         RETAIN_HERE(query, dnssd_query);
   3309     }
   3310 
   3311     INFO("[Q%d] waiting for wakeup or response", SERIAL(query));
   3312     return true;
   3313 }
   3314 
   3315 static dnssd_query_t *
   3316 dp_query_create(dp_tracker_t *tracker, dns_rr_t *question, message_t *message, dso_state_t *dso, int *rcode)
   3317 {
   3318     char name[DNS_MAX_NAME_SIZE + 1];
   3319     served_domain_t *sdt = dp_served(question->name, name, sizeof name);
   3320     int xid = message == NULL ? 0 : ntohs(message->wire.id);
   3321 
   3322     dnssd_query_t *query = calloc(1,sizeof *query);
   3323     require_action_quiet(query != NULL, exit, *rcode = dns_rcode_servfail;
   3324                          ERROR("Unable to allocate memory for query on " PRI_S_SRP, name));
   3325     RETAIN_HERE(query, dnssd_query); // for the caller
   3326     query->serial = ++cur_query_serial;
   3327 
   3328     // If it's a query for a name served by the local discovery proxy, do an mDNS lookup.
   3329     if (sdt != NULL) {
   3330         INFO("[Q%d][QID%x] msg %p " PUB_S_SRP " question: type %d class %d " PRI_S_SRP "." PRI_S_SRP " -> "
   3331              PRI_S_SRP DOT_LOCAL, SERIAL(query), xid, message, dso != NULL ? "push" : " dns",
   3332              question->type, question->qclass, name, sdt->domain, name);
   3333     } else {
   3334         dns_name_print(question->name, name, sizeof name);
   3335         INFO("[Q%d][QID%x] msg %p " PUB_S_SRP " question: type %d class %d " PRI_S_SRP, SERIAL(query), xid,
   3336              message, dso != NULL ? "push" : " dns", question->type, question->qclass, name);
   3337     }
   3338 
   3339     query->response = malloc(sizeof *query->response);
   3340     require_action_quiet(query->response != NULL, exit, *rcode = dns_rcode_servfail;
   3341                          ERROR("[Q%d] Unable to allocate memory for query response on " PRI_S_SRP,
   3342                                SERIAL(query), name));
   3343 
   3344     query->data_size = DNS_DATA_SIZE;
   3345 
   3346     // Zero out the DNS header, but not the data.
   3347     memset(query->response, 0, DNS_HEADER_SIZE);
   3348 
   3349     // Name now contains the name we want mDNSResponder to look up.
   3350 
   3351     // The only thing holding a reference to query is its tracker.
   3352     query->tracker = tracker;
   3353     RETAIN_HERE(query->tracker, dp_tracker);
   3354 
   3355     // Remember whether this is a long-lived query.
   3356     query->dso = dso;
   3357 
   3358     // Retain the question, as we will need it to send a response.
   3359     if (message != NULL) {
   3360         query->message = message;
   3361         ioloop_message_retain(query->message);
   3362     }
   3363 
   3364     // Start writing the response
   3365     dp_query_towire_reset(query);
   3366 
   3367     bool new_entry;
   3368     query->question = dp_query_question_cache_copy(question, &new_entry);
   3369     require_action_quiet(query->question != NULL, exit, *rcode = dns_rcode_servfail);
   3370 
   3371     // add the query to the list of queries that are asking this question.
   3372     dnssd_query_t **qr = &(query->question->queries);
   3373     while (*qr != NULL) {
   3374         qr = &(*qr)->question_next;
   3375     }
   3376     *qr = query;
   3377     // Question query list holds a reference to the query.
   3378     RETAIN_HERE(*qr, dnssd_query);
   3379     INFO("[Q%d][QID%x] msg %p " PUB_S_SRP " cache entry for question: type %d class %d " PRI_S_SRP, SERIAL(query),
   3380          xid, query->message, new_entry ? "new" : " existing", question->type, question->qclass, name);
   3381     *rcode = dns_rcode_noerror;
   3382     dp_num_outstanding_queries++;
   3383 
   3384 exit:
   3385     if (*rcode != dns_rcode_noerror && query != NULL) {
   3386         RELEASE_HERE(query, dnssd_query);
   3387         query = NULL;
   3388     }
   3389     return query;
   3390 }
   3391 
   3392 
   3393 static void
   3394 dns_push_query_answer_process(DNSServiceFlags flags, DNSServiceErrorType errorCode,
   3395                               const char *fullname, uint16_t rrtype, uint16_t rrclass,
   3396                               uint16_t rdlen, const void *rdata, uint32_t ttl, dnssd_query_t *query, bool send)
   3397 {
   3398     uint8_t *revert = query->towire.p;
   3399 
   3400     VALIDATE_TRACKER_CONNECTION_NON_NULL();
   3401 
   3402     // From DNSSD-Hybrid, for mDNS queries:
   3403     // If we have cached answers, respond immediately, because we probably have all the answers.
   3404     // If we don't have cached answers, respond as soon as we get an answer (presumably more-coming will be false).
   3405 
   3406     // The spec says to not query if we have cached answers.   We trust the DNSServiceQueryRecord call to handle this.
   3407 
   3408     // If we switch to using a single connection to mDNSResponder, we could have !more-coming trigger a flush of
   3409     // all outstanding queries that aren't waiting on a time trigger.   This is because more-coming isn't
   3410     // query-specific
   3411 
   3412     INFO("[Q%d] PUSH " PRI_S_SRP " %d %d %x %d %p", SERIAL(query), fullname, rrtype, rrclass, rdlen, errorCode, query);
   3413 
   3414     // query_state_waiting means that we're answering a regular DNS question
   3415     if (errorCode == kDNSServiceErr_NoError) {
   3416         if (send) {
   3417             const void *rdata_to_send;
   3418             uint32_t ttl_to_send;
   3419             // If kDNSServiceFlagsAdd is set, it's an add, otherwise a delete.
   3420         re_add:
   3421             if (flags & kDNSServiceFlagsAdd) {
   3422                 rdata_to_send = rdata;
   3423                 ttl_to_send = ttl;
   3424                 INFO("[Q%d] DNS Push adding record - "
   3425                      "name: " PRI_S_SRP ", rrtype: " PUB_S_SRP ", rrclass: " PUB_S_SRP ", rdlen: %u, ttl: %u.",
   3426                      SERIAL(query), fullname, dns_rrtype_to_string(rrtype), dns_qclass_to_string(rrclass), rdlen, ttl_to_send);
   3427             } else {
   3428                 // See <https://tools.ietf.org/html/rfc8765#section-6.3.1>.
   3429 #define TTL_TO_REMOVE_INDIVIDUAL_RECORDS    0xFFFFFFFF
   3430 #define TTL_TO_REMOVE_MULTIPLE_RECORDS      0xFFFFFFFE
   3431                 if (rdlen == 0) {
   3432                     // Remove specified RRset from a name in given class:
   3433                     // TTL = 0xFFFFFFFE, RDLEN = 0,
   3434                     // CLASS and TYPE specify the RRset being removed.
   3435                     rdata_to_send = NULL;
   3436                     ttl_to_send = TTL_TO_REMOVE_MULTIPLE_RECORDS;
   3437                 } else {
   3438                     // Remove an individual RR from a name:
   3439                     // TTL = 0xFFFFFFFF,
   3440                     // CLASS, TYPE, RDLEN, and RDATA specify the RR being removed.
   3441                     rdata_to_send = rdata;
   3442                     ttl_to_send = TTL_TO_REMOVE_INDIVIDUAL_RECORDS;
   3443                 }
   3444                 INFO("[Q%d] DNS Push removing record - "
   3445                      "name: " PRI_S_SRP ", rrtype: " PUB_S_SRP ", rrclass: " PUB_S_SRP ", rdlen: %u, ttl: 0x%X.",
   3446                      SERIAL(query), fullname, dns_rrtype_to_string(rrtype), dns_qclass_to_string(rrclass), rdlen, ttl_to_send);
   3447             }
   3448 
   3449             // Do the update.
   3450             dp_query_add_data_to_response(query, fullname, rrtype, rrclass, rdlen, rdata_to_send,
   3451                                           ttl_to_send, false, false, NULL);
   3452 
   3453             if (query->towire.truncated) {
   3454                 query->towire.truncated = false;
   3455                 query->towire.p = revert;
   3456                 query->towire.error = 0;
   3457                 dp_push_response(query, NULL);
   3458                 dns_push_start(query);
   3459                 goto re_add;
   3460             }
   3461         }
   3462         // If there isn't more coming, send a DNS Push notification now.
   3463         // XXX If enough comes to fill the response, send the message.
   3464         if (!(flags & kDNSServiceFlagsMoreComing)) {
   3465             dp_push_response(query, NULL);
   3466         }
   3467     } else if (errorCode != kDNSServiceErr_NoSuchRecord) { // Do nothing if kDNSServiceErr_NoSuchRecord is received.
   3468         ERROR("[Q%d] unexpected error code %d", SERIAL(query), errorCode);
   3469         dnssd_query_cancel(query);
   3470     }
   3471 }
   3472 
   3473 static void
   3474 dns_push_subscribe(dp_tracker_t *tracker, const dns_wire_t *header, dso_state_t *dso, dns_rr_t *question,
   3475                    const char *activity_name, const char * UNUSED opcode_name)
   3476 {
   3477     int rcode;
   3478     dnssd_query_t *query = dp_query_create(tracker, question, NULL, dso, &rcode);
   3479 
   3480     if (!query) {
   3481         dso_simple_response(tracker->connection, NULL, header, rcode);
   3482         return;
   3483     }
   3484 
   3485     dso_activity_t *activity = dso_add_activity(dso, activity_name, push_subscription_activity_type, query,
   3486                                                 dns_push_cancel);
   3487     RETAIN_HERE(query, dnssd_query); // The activity holds a reference to the query.
   3488     query->activity = activity;
   3489     bool dns64 = false;
   3490 #if SRP_FEATURE_NAT64
   3491     if (srp_servers->srp_nat64_enabled) {
   3492         dns64 = nat64_is_active();
   3493     }
   3494 #endif
   3495     bool hardwired = false;
   3496     if (!dp_query_start(query, &rcode, &hardwired, dns64)) {
   3497         dso_simple_response(tracker->connection, NULL, header, rcode);
   3498         dp_question_cache_remove_queries(query->question);
   3499         dnssd_query_cancel(query);
   3500     } else {
   3501         char nbuf[DNS_MAX_NAME_SIZE + 1];
   3502         dns_name_print(question->name, nbuf, sizeof(nbuf));
   3503         // The push subscribe can be considered a success at this point.
   3504         dso_simple_response(tracker->connection, NULL, header, dns_rcode_noerror);
   3505         if (hardwired) {
   3506             INFO("[DSO%d][Q%d] hardwired response for " PRI_S_SRP " %d %d",
   3507                  SERIAL(dso), SERIAL(query), nbuf, question->type, question->qclass);
   3508             dp_push_response(query, question);
   3509         } else if (query->question != NULL) {
   3510             INFO("[DSO%d][Q%d][QU%d] replying from cache for " PRI_S_SRP " %d %d",
   3511                  SERIAL(dso), SERIAL(query), SERIAL(query->question), nbuf, question->type, question->qclass);
   3512             dp_query_reply_from_cache(query->question, query, false);
   3513         }
   3514     }
   3515 
   3516     // dp_query_create() returned the query retained; when we added the query to the activity, we retained it again;
   3517     // if something went wrong, the second retain was released, but whether or not something went wrong, we can now
   3518     // safely release the initial retain.
   3519     RELEASE_HERE(query, dnssd_query);
   3520 }
   3521 
   3522 static void
   3523 dns_push_reconfirm(comm_t *comm, const dns_wire_t *header, dso_state_t *dso)
   3524 {
   3525     dns_rr_t question;
   3526     char name[DNS_MAX_NAME_SIZE + 1];
   3527     uint16_t rdlen;
   3528     memset(&question, 0, sizeof(question));
   3529 
   3530     // The TLV offset should always be pointing into the message.
   3531     unsigned offp = (unsigned)(dso->primary.payload - &header->data[0]);
   3532     unsigned len = offp + dso->primary.length;
   3533     dp_tracker_t *tracker = comm->context;
   3534 
   3535     // Parse the name, rrtype and class.   We say there's no rdata even though there is
   3536     // because there's no ttl and also we want the raw rdata, not parsed rdata.
   3537     if (!dns_rr_parse(&question, header->data, len, &offp, false, false) ||
   3538         !dns_u16_parse(header->data, len, &offp, &rdlen))
   3539     {
   3540         dso_simple_response(comm, NULL, header, dns_rcode_formerr);
   3541         ERROR("[DSO%d][C%d][TRK%d] RR parse from %s failed",
   3542               SERIAL(dso), SERIAL(comm), SERIAL(tracker), dso->remote_name);
   3543         goto out;
   3544     }
   3545     if (rdlen + offp != len) {
   3546         dso_simple_response(comm, NULL, header, dns_rcode_formerr);
   3547         ERROR("[DSO%d][C%d][TRK%d] RRdata parse from %s failed: length mismatch (%d != %d)",
   3548               SERIAL(dso), SERIAL(comm), SERIAL(tracker), dso->remote_name, rdlen + offp, len);
   3549         goto out;
   3550     }
   3551 
   3552     if ((dp_served(question.name, name, sizeof name))) {
   3553         size_t name_len = strlen(name);
   3554         if (name_len + sizeof local_suffix > sizeof name) {
   3555             dso_simple_response(comm, NULL, header, dns_rcode_formerr);
   3556             ERROR("[DSO%d][C%d][TRK%d] name is too long for .local suffix: %s", SERIAL(dso), SERIAL(comm), SERIAL(tracker), name);
   3557             goto out;
   3558         }
   3559         memcpy(&name[name_len], local_suffix, sizeof local_suffix);
   3560     } else {
   3561         dns_name_print(question.name, &name[8], sizeof name - 8);
   3562     }
   3563     // transmogrify name.
   3564     DNSServiceReconfirmRecord(0, kDNSServiceInterfaceIndexAny, name,
   3565                               question.type, question.qclass, rdlen, &header->data[offp]);
   3566     dso_simple_response(comm, NULL, header, dns_rcode_noerror);
   3567 out:
   3568     dns_rrdata_free(&question);
   3569     dns_name_free(question.name);
   3570 }
   3571 
   3572 static void
   3573 dns_push_unsubscribe(dso_activity_t *activity)
   3574 {
   3575     dnssd_query_t *query = activity->context;
   3576     dnssd_query_cancel(query);
   3577     // No response, unsubscribe is unidirectional.
   3578 }
   3579 
   3580 static void
   3581 dns_push_subscription_change(const char *opcode_name, dp_tracker_t *tracker, const dns_wire_t *header, dso_state_t *dso)
   3582 {
   3583     // type-in-hex/class-in-hex/name-to-subscribe
   3584     char activity_name[5];
   3585     dso_activity_t *activity;
   3586 
   3587     // The TLV offset should always be pointing into the message.
   3588     unsigned offp = (unsigned)(dso->primary.payload - &header->data[0]);
   3589     unsigned len = offp + dso->primary.length;
   3590     // Get the question
   3591     dns_rr_t question;
   3592     uint16_t subscribe_xid = ntohs(header->id);
   3593     char nbuf[DNS_MAX_NAME_SIZE + 1];
   3594 
   3595     memset(&question, 0, sizeof(question));
   3596     if (dso->primary.opcode == kDSOType_DNSPushSubscribe) {
   3597         if (!dns_rr_parse(&question, header->data, offp + dso->primary.length, &offp, false, false)) {
   3598             dso_simple_response(tracker->connection, NULL, header, dns_rcode_formerr);
   3599             ERROR("[DSO%d][TRK%d] RR parse for %s from %s failed", SERIAL(dso), SERIAL(tracker), dso->remote_name, opcode_name);
   3600             goto out;
   3601         }
   3602         dns_name_print(question.name, nbuf, sizeof(nbuf));
   3603     } else {
   3604         // Unsubscribes are unidirectional, so no response can be sent
   3605         if (!dns_u16_parse(header->data, offp + dso->primary.length, &offp, &subscribe_xid)) {
   3606             ERROR("unable to get subscribe xid from primary");
   3607             goto out;
   3608         }
   3609         const char none[] = "none";
   3610         memcpy(nbuf, none, sizeof(none));
   3611     }
   3612     if (offp != len) {
   3613         if (dso->primary.opcode == kDSOType_DNSPushSubscribe) {
   3614             dso_simple_response(tracker->connection, NULL, header, dns_rcode_formerr);
   3615         }
   3616         ERROR("DNS push " PUB_S_SRP " parse from %s failed: length mismatch (%d != %d)",
   3617               dso->primary.opcode == kDSOType_DNSPushSubscribe ? "subscribe" : "unsubscribe",
   3618               dso->remote_name, offp, len);
   3619         goto out;
   3620     }
   3621 
   3622     // Concoct an activity name. The subscribe transaction ID is required to be unique and is used by the
   3623     // protocol to identify the subscription, so we can just use that.
   3624     snprintf(activity_name, sizeof(activity_name), "%04x", subscribe_xid);
   3625 
   3626     activity = dso_find_activity(dso, activity_name, push_subscription_activity_type, NULL);
   3627     if (activity == NULL) {
   3628         // Unsubscribe with no activity means no work to do; just return noerror.
   3629         if (dso->primary.opcode != kDSOType_DNSPushSubscribe) {
   3630             ERROR("[DSO%d][TRK%d] " PUB_S_SRP " for " PRI_S_SRP " (" PUB_S_SRP ") when no subscription exists.",
   3631                   SERIAL(dso), SERIAL(tracker), opcode_name, nbuf, activity_name);
   3632         } else {
   3633             INFO("[DSO%d][TRK%d] " PUB_S_SRP " for " PRI_S_SRP " (" PUB_S_SRP ") type %d.",
   3634                  SERIAL(dso), SERIAL(tracker), opcode_name, nbuf, activity_name, question.type);
   3635             // In this case we have a push subscribe for which no subscription exists, which means we can do it.
   3636             dns_push_subscribe(tracker, header, dso, &question, activity_name, opcode_name);
   3637         }
   3638     } else {
   3639         // We should never get two subscribes with the same transaction id.
   3640         if (dso->primary.opcode == kDSOType_DNSPushSubscribe) {
   3641             ERROR("[DSO%d][TRK%d] " PUB_S_SRP " for " PRI_S_SRP " (" PUB_S_SRP ") "
   3642                   "xid %d when subscription already exists.", SERIAL(dso), SERIAL(tracker),
   3643                   opcode_name, nbuf, activity_name, subscribe_xid);
   3644             dso_simple_response(tracker->connection, NULL, header, dns_rcode_refused);
   3645         }
   3646         // Otherwise cancel the subscription.
   3647         else {
   3648             dnssd_query_t *query = activity->context;
   3649             char *question_name = query->question != NULL ? query->question->name : nbuf;
   3650             INFO("[DSO%d][TRK%d] " PUB_S_SRP " for " PRI_S_SRP " (" PUB_S_SRP ") type %d.",
   3651                  SERIAL(dso), SERIAL(tracker), opcode_name, question_name, activity_name, question.type);
   3652             dns_push_unsubscribe(activity);
   3653         }
   3654     }
   3655 out:
   3656     dns_rrdata_free(&question);
   3657     dns_name_free(question.name);
   3658 }
   3659 
   3660 static bool
   3661 dso_limit(dp_tracker_t *tracker, message_t *message, dp_tracker_session_type_t session_type)
   3662 {
   3663     if (num_push_sessions == MAX_DSO_CONNECTIONS) {
   3664         // We are too busy. Return a retry-delay response.
   3665         INFO("[TRK%d] no more DNS Push connections allowed--sending retry-delay: %d", SERIAL(tracker), num_push_sessions);
   3666         dso_retry_delay_response(tracker->connection, message, &message->wire, dns_rcode_servfail, BUSY_RETRY_DELAY_MS);
   3667 
   3668         num_push_sessions_dropped_for_load++;
   3669         // Cancel the connection after five seconds
   3670         dp_tracker_idle_after(tracker, 5, NULL);
   3671         return true;
   3672     }
   3673 
   3674     // Count this as a DSO connection.
   3675     (num_push_sessions)++;
   3676     INFO("[TRK%d] new DNS Push connection, count is now %d", SERIAL(tracker), num_push_sessions);
   3677 
   3678     tracker->session_type = session_type;
   3679     return false;
   3680 }
   3681 
   3682 static void dso_message(dp_tracker_t *tracker, message_t *message, dso_state_t *dso)
   3683 {
   3684     // For the first DSO message we get on a connection, see if we already have too many connections of
   3685     // the same type. We track SRP replication and DNS Push separately, because we don't want a surfeit of
   3686     // DNS Push messages to prevent replication from working. A surfeit of SRP Replication connections is
   3687     // less likely, and less problematic.
   3688     if (tracker->session_type == dp_tracker_session_none) {
   3689         if (dso->primary.opcode != kDSOType_SRPLSession) {
   3690             if (dso_limit(tracker, message, dp_tracker_session_push)) {
   3691                 return;
   3692             }
   3693         }
   3694     }
   3695 
   3696     switch(dso->primary.opcode) {
   3697     case kDSOType_DNSPushSubscribe:
   3698         dns_push_subscription_change("DNS Push Subscribe", tracker, &message->wire, dso);
   3699         break;
   3700     case kDSOType_DNSPushUnsubscribe:
   3701         dns_push_subscription_change("DNS Push Unsubscribe", tracker, &message->wire, dso);
   3702         break;
   3703 
   3704     case kDSOType_DNSPushReconfirm:
   3705         dns_push_reconfirm(tracker->connection, &message->wire, dso);
   3706         break;
   3707 
   3708     case kDSOType_DNSPushUpdate:
   3709         INFO("[DSO%d][TRK%d] bogus push update message %d", SERIAL(dso), SERIAL(tracker), dso->primary.opcode);
   3710         dso_state_cancel(dso);
   3711         break;
   3712 
   3713 #if SRP_FEATURE_REPLICATION
   3714     case kDSOType_SRPLSession:
   3715         if (dso->activities != NULL) {
   3716             dso_state_cancel(dso);
   3717             ERROR("[DSO%d][TRK%d][C%d] " PRI_S_SRP ": SRP Replication session start received on a connection that is already doing DNS Push.",
   3718                   SERIAL(dso), SERIAL(tracker), SERIAL(tracker->connection), tracker->connection->name);
   3719             return;
   3720         }
   3721 #ifdef SRP_TEST_SERVER
   3722         srpl_dso_server_message(tracker->connection, message, dso, (srp_server_t*)tracker->connection->srp_server);
   3723 #else
   3724         srpl_dso_server_message(tracker->connection, message, dso, srp_servers);
   3725 #endif
   3726         break;
   3727 #endif
   3728 
   3729     default:
   3730         INFO("[DSO%d][TRK%d] unexpected primary TLV %d", SERIAL(dso), SERIAL(tracker), dso->primary.opcode);
   3731         dso_simple_response(tracker->connection, NULL, &message->wire, dns_rcode_dsotypeni);
   3732         break;
   3733     }
   3734     // XXX free the message if we didn't consume it.
   3735 #ifdef SRP_TEST_SERVER
   3736     if (srp_test_dso_message_finished != NULL) {
   3737         srp_test_dso_message_finished(srp_test_tls_listener_context, message, dso);
   3738     }
   3739 #endif
   3740 }
   3741 
   3742 static void
   3743 dp_keepalive_response_send(dso_keepalive_context_t *keepalive_event, dso_state_t *dso)
   3744 {
   3745     uint8_t dsobuf[SRPL_KEEPALIVE_MESSAGE_LENGTH];
   3746     dns_towire_state_t towire;
   3747     struct iovec iov;
   3748     uint16_t *p_dso_length;
   3749     dso_message_t state;
   3750 
   3751     if (dso->transport == NULL) {
   3752         ERROR("dso state " PRI_S_SRP " has no transport", dso->remote_name);
   3753         return;
   3754     }
   3755 
   3756     memset(&towire, 0, sizeof(towire));
   3757     towire.p = &dsobuf[DNS_HEADER_SIZE];
   3758     towire.lim = towire.p + (sizeof(dsobuf) - DNS_HEADER_SIZE);
   3759     towire.message = (dns_wire_t *)dsobuf;
   3760     towire.p_rdlength = NULL;
   3761     towire.p_opt = NULL;
   3762     p_dso_length = NULL;
   3763 
   3764     dso_make_message(&state, dsobuf, sizeof(dsobuf), dso, false /* unidirectional */, true /* response */,
   3765                      keepalive_event->xid, dns_rcode_noerror, dso->transport);
   3766     dns_u16_to_wire(&towire, kDSOType_Keepalive);
   3767     dns_rdlength_begin(&towire);
   3768     dns_u32_to_wire(&towire, keepalive_event->inactivity_timeout); // Idle timeout (we are never idle)
   3769     dns_u32_to_wire(&towire, keepalive_event->keepalive_interval); // Keepalive timeout
   3770     dns_rdlength_end(&towire);
   3771     if (towire.error) {
   3772         ERROR("ran out of message space at " PUB_S_SRP ", :%d", __FILE__, towire.line);
   3773         return;
   3774     }
   3775     memset(&iov, 0, sizeof(iov));
   3776     iov.iov_len = towire.p - dsobuf;
   3777     iov.iov_base = dsobuf;
   3778     if (!ioloop_send_message(dso->transport, NULL, &iov, 1)) {
   3779         INFO("send failed");
   3780         return;
   3781     }
   3782 
   3783     INFO("sent %zd byte response Keepalive, xid %02x%02x (was %04x), to " PRI_S_SRP,
   3784          iov.iov_len, dsobuf[0], dsobuf[1], keepalive_event->xid, dso->transport->name);
   3785 }
   3786 
   3787 static void
   3788 dns_push_callback(void *context, void *event_context, dso_state_t *dso, dso_event_type_t eventType)
   3789 {
   3790     dso_keepalive_context_t *keepalive_context;
   3791     message_t *message;
   3792     switch(eventType)
   3793     {
   3794     case kDSOEventType_DNSMessage:
   3795         // We shouldn't get here because we already handled any DNS messages
   3796         message = event_context;
   3797         INFO("[DSO%d] DNS Message (opcode=%d) received from " PRI_S_SRP, SERIAL(dso), dns_opcode_get(&message->wire),
   3798              dso->remote_name);
   3799         break;
   3800     case kDSOEventType_DNSResponse:
   3801         // We shouldn't get here because we already handled any DNS messages
   3802         message = event_context;
   3803         INFO("[DSO%d] DNS Response (opcode=%d) received from " PRI_S_SRP, SERIAL(dso), dns_opcode_get(&message->wire),
   3804              dso->remote_name);
   3805         break;
   3806     case kDSOEventType_DSOMessage:
   3807         INFO("[DSO%d] DSO Message (Primary TLV=%d) received from " PRI_S_SRP,
   3808              SERIAL(dso), dso->primary.opcode, dso->remote_name);
   3809         message = event_context;
   3810         dso_message((dp_tracker_t *)context, message, dso);
   3811         break;
   3812     case kDSOEventType_DSOResponse:
   3813         INFO("[DSO%d] DSO Response (Primary TLV=%d) received from " PRI_S_SRP,
   3814              SERIAL(dso), dso->primary.opcode, dso->remote_name);
   3815         break;
   3816 
   3817     case kDSOEventType_Finalize:
   3818         INFO("[DSO%d] Finalize", SERIAL(dso));
   3819         break;
   3820 
   3821     case kDSOEventType_Connected:
   3822         INFO("[DSO%d] Connected to " PRI_S_SRP, SERIAL(dso), dso->remote_name);
   3823         break;
   3824 
   3825     case kDSOEventType_ConnectFailed:
   3826         INFO("[DSO%d] Connection to " PRI_S_SRP " failed", SERIAL(dso), dso->remote_name);
   3827         break;
   3828 
   3829     case kDSOEventType_Disconnected:
   3830         INFO("[DSO%d] Connection to " PRI_S_SRP " disconnected", SERIAL(dso), dso->remote_name);
   3831         break;
   3832     case kDSOEventType_ShouldReconnect:
   3833         INFO("[DSO%d] Connection to " PRI_S_SRP " should reconnect (not for a server)", SERIAL(dso), dso->remote_name);
   3834         break;
   3835     case kDSOEventType_Inactive:
   3836         INFO("[DSO%d] Inactivity timer went off, closing connection.", SERIAL(dso));
   3837         break;
   3838     case kDSOEventType_Keepalive:
   3839         INFO("[DSO%d] should send a keepalive now.", SERIAL(dso));
   3840         break;
   3841     case kDSOEventType_KeepaliveRcvd:
   3842         keepalive_context = event_context;
   3843         keepalive_context->send_response = false;
   3844         INFO("[DSO%d] " PRI_S_SRP ": keepalive received, xid %04x.", SERIAL(dso), dso->transport->name, keepalive_context->xid);
   3845 
   3846         // If we are the server, we have to send a response to the keepalive.
   3847         if (dso->is_server) {
   3848             dp_keepalive_response_send(keepalive_context, dso);
   3849         }
   3850         break;
   3851     case kDSOEventType_RetryDelay:
   3852         INFO("[DSO%d] keepalive received.", SERIAL(dso));
   3853         break;
   3854     }
   3855 }
   3856 
   3857 static bool
   3858 dp_dns_query(dp_tracker_t *tracker, message_t *message, dns_rr_t *question, int num_questions)
   3859 {
   3860     int rcode;
   3861 
   3862     // Limit outstanding queries if we don't have shared connection support
   3863     if (dp_num_outstanding_queries >= 256) {
   3864         num_queries_dropped_for_load++;
   3865         dso_simple_response(tracker->connection, message, &message->wire, dns_rcode_servfail);
   3866         ERROR("[TRK%d][QID %x] dropping query because there are too many", SERIAL(tracker), ntohs(message->wire.id));
   3867         return false;
   3868     }
   3869 
   3870 
   3871     dnssd_query_t *query = dp_query_create(tracker, question, message, NULL, &rcode);
   3872     const char *failnote = NULL;
   3873     if (!query) {
   3874         ERROR("[TRK%d][QID %x] query create failed", SERIAL(tracker), ntohs(message->wire.id));
   3875         dso_simple_response(tracker->connection, message, &message->wire, rcode);
   3876         return false;
   3877     }
   3878     query->num_questions = num_questions;
   3879 
   3880     dns_rcode_set(query->response, dns_rcode_noerror);
   3881 
   3882     // For DNS queries, we need to return the question.
   3883     query->response->qdcount = htons(1);
   3884     if (query->question->served_domain != NULL) {
   3885         TOWIRE_CHECK("name", &query->towire, dns_name_to_wire(NULL, &query->towire, query->question->name));
   3886         TOWIRE_CHECK("enclosing_domain", &query->towire,
   3887                      dns_full_name_to_wire(&query->enclosing_domain_pointer,
   3888                                            &query->towire, query->question->served_domain->domain));
   3889     } else {
   3890         TOWIRE_CHECK("full name", &query->towire, dns_full_name_to_wire(NULL, &query->towire, query->question->name));
   3891     }
   3892     TOWIRE_CHECK("TYPE", &query->towire, dns_u16_to_wire(&query->towire, question->type));    // TYPE
   3893     TOWIRE_CHECK("CLASS", &query->towire, dns_u16_to_wire(&query->towire, question->qclass));  // CLASS
   3894     if (failnote != NULL) {
   3895         ERROR("[TRK%d][QID %x] failure encoding question: " PUB_S_SRP, SERIAL(tracker), ntohs(message->wire.id), failnote);
   3896         goto fail;
   3897     }
   3898 
   3899     // Set message ID.
   3900     query->towire.message->id = message->wire.id;
   3901 
   3902     // We should check for OPT RR, but for now assume it's there.
   3903     query->is_edns0 = true;
   3904 
   3905     bool dns64 = false;
   3906 #if SRP_FEATURE_NAT64
   3907     if (srp_servers->srp_nat64_enabled) {
   3908         dns64 = nat64_is_active();
   3909     }
   3910 #endif
   3911     dp_query_track(tracker, query);
   3912     bool hardwired = false;
   3913     if (dp_query_start(query, &rcode, &hardwired, dns64)) {
   3914         // If query->question isn't NULL, we need to reply from cache
   3915         if (hardwired) {
   3916             INFO("[Q%d][TRK%d] hardwired reply", SERIAL(query), SERIAL(tracker));
   3917             dp_query_send_dns_response(query, "hardwired");
   3918             dp_question_cache_remove_queries(query->question);
   3919             RELEASE_HERE(query->question, question);
   3920             query->question = NULL;
   3921         } else if (query->question != NULL) {
   3922             INFO("[Q%d][TRK%d] replying from cache", SERIAL(query), SERIAL(tracker));
   3923             dp_query_reply_from_cache(query->question, query, false);
   3924             dp_question_cache_remove_queries(query->question);
   3925         } else {
   3926             INFO("[Q%d][TRK%d] not replying from cache", SERIAL(query), SERIAL(tracker));
   3927         }
   3928     } else {
   3929         INFO("[Q%d][TRK%d][QID %x] query start failed", SERIAL(query), SERIAL(tracker), ntohs(message->wire.id));
   3930     fail:
   3931         dso_simple_response(tracker->connection, message, &message->wire, rcode);
   3932         query->satisfied = true;
   3933         dp_question_cache_remove_queries(query->question);
   3934         dnssd_query_cancel(query);
   3935         RELEASE_HERE(query, dnssd_query);
   3936         return false;
   3937     }
   3938     // Query is returned retained, and dp_query_track retains it, so we always need to release the reference here.
   3939     RELEASE_HERE(query, dnssd_query);
   3940     return true;
   3941 }
   3942 
   3943 static void
   3944 dp_tracker_dso_cleanup(void *UNUSED context)
   3945 {
   3946     dso_cleanup(false);
   3947 }
   3948 
   3949 static bool
   3950 dp_tracker_dso_state_change(const dso_life_cycle_t cycle, void *const context, dso_state_t *const dso)
   3951 {
   3952     if (cycle == dso_life_cycle_cancel) {
   3953         dp_tracker_t *tracker = context;
   3954         if (tracker->dso != NULL) {
   3955             tracker->dso = NULL;
   3956             if (tracker->connection != NULL) {
   3957                 tracker->connection->dso = NULL;
   3958                 ioloop_comm_cancel(tracker->connection);
   3959             }
   3960             for (dnssd_query_t *query = tracker->dns_queries; query != NULL; query = query->next) {
   3961                 if (query->dso == dso) {
   3962                     query->dso = NULL;
   3963                 }
   3964                 if (query->activity != NULL) {
   3965                     query->activity = NULL;
   3966                     // Release the activity's reference to the query.
   3967                     RELEASE_HERE(query, dnssd_query);
   3968                 }
   3969             }
   3970         }
   3971         ioloop_run_async(dp_tracker_dso_cleanup, NULL);
   3972         return true;
   3973     }
   3974     return false;
   3975 }
   3976 
   3977 static void
   3978 dnssd_proxy_dns_evaluate(comm_t *comm, message_t *message, dp_tracker_t *tracker)
   3979 {
   3980     dns_rr_t question;
   3981     unsigned offset = 0;
   3982 
   3983     if (tracker == NULL) {
   3984         tracker = calloc(1, sizeof(*tracker));
   3985         if (tracker == NULL) {
   3986             ERROR("[C%d] " PRI_S_SRP ": no memory for a connection tracker object!", SERIAL(comm), comm->name);
   3987             goto fail;
   3988         }
   3989         tracker->connection = comm;
   3990         tracker->serial = ++cur_tracker_serial;
   3991         ioloop_comm_retain(tracker->connection);
   3992         if (comm->tcp_stream) {
   3993             ioloop_comm_context_set(comm, tracker, dp_tracker_context_release);
   3994             RETAIN_HERE(tracker, dp_tracker); // connection has a reference.
   3995         }
   3996         if (!comm->is_listener) {
   3997             ioloop_comm_disconnect_callback_set(comm, dp_tracker_disconnected);
   3998         }
   3999     }
   4000     RETAIN_HERE(tracker, dp_tracker); // For the function.
   4001 
   4002     // Drop incoming responses--we're a server, so we only accept queries.
   4003     if (dns_qr_get(&message->wire) == dns_qr_response) {
   4004         INFO("[TRK%d][C%d] " PRI_S_SRP ": dropping unexpected response", SERIAL(tracker), SERIAL(comm), comm->name);
   4005         goto fail;
   4006     }
   4007 
   4008     // If this is a DSO message, see if we have a session yet.
   4009     switch(dns_opcode_get(&message->wire)) {
   4010     case dns_opcode_dso:
   4011         if (!comm->tcp_stream) {
   4012             ERROR("[TRK%d][C%d] " PRI_S_SRP ": DSO message received on non-tcp socket.", SERIAL(tracker), SERIAL(comm), comm->name);
   4013             dso_simple_response(comm, message, &message->wire, dns_rcode_notimp);
   4014             goto fail;
   4015         }
   4016 
   4017         if (!tracker->dso) {
   4018             tracker->dso = dso_state_create(true, 2, comm->name, dns_push_callback, tracker,
   4019                                             dp_tracker_dso_state_change, comm);
   4020             if (!tracker->dso) {
   4021                 ERROR("[TRK%d][C%d] " PRI_S_SRP ": Unable to create a dso context.", SERIAL(tracker), SERIAL(comm), comm->name);
   4022                 dso_simple_response(comm, message, &message->wire, dns_rcode_servfail);
   4023                 goto fail;
   4024             }
   4025             comm->dso = tracker->dso;
   4026         }
   4027         dp_tracker_not_idle(tracker);
   4028         dso_message_received(comm->dso, (uint8_t *)&message->wire, message->length, message);
   4029         break;
   4030 
   4031     case dns_opcode_query: {
   4032         int num_questions = ntohs(message->wire.qdcount);
   4033 
   4034         // Some Matter accessories will send queries with more than one question, and if we don't answer these
   4035         // queries, automations fail. So even though this is a bit weird, we need to answer the queries.
   4036         for (int i = 0; i < num_questions; i++) {
   4037             memset(&question, 0, sizeof(question));
   4038             if (!dns_rr_parse(&question, message->wire.data, message->length - DNS_HEADER_SIZE, &offset, false, false)) {
   4039                 ERROR("[TRK%d][C%d] " PRI_S_SRP ": rr parse failed.", SERIAL(tracker), SERIAL(comm), comm->name);
   4040                 dso_simple_response(comm, message, &message->wire, dns_rcode_formerr);
   4041                 goto fail;
   4042             }
   4043             bool success = dp_dns_query(tracker, message, &question, num_questions);
   4044             dns_rrdata_free(&question);
   4045             dns_name_free(question.name);
   4046             if (!success) {
   4047                 dnssd_query_t *next = NULL, *match = NULL;
   4048                 for (dnssd_query_t *query = tracker->dns_queries; query != NULL; query = next) {
   4049                     next = query->next;
   4050                     if (dp_same_message(query->message, message)) {
   4051                         query->satisfied = true;
   4052                         dp_question_cache_remove_queries(query->question);
   4053                         if (match == NULL) {
   4054                             match = query;
   4055                             RETAIN_HERE(match, dnssd_query);
   4056                         }
   4057                     }
   4058                 }
   4059                 if (match != NULL) {
   4060                     dnssd_query_cancel(match);
   4061                     RELEASE_HERE(match, dnssd_query);
   4062                 }
   4063                 goto out;
   4064             }
   4065         }
   4066         dp_tracker_not_idle(tracker);
   4067         break;
   4068     }
   4069         // No support for other opcodes yet.
   4070     default:
   4071         dso_simple_response(comm, message, &message->wire, dns_rcode_notimp);
   4072         break;
   4073     }
   4074     goto out;
   4075 fail:
   4076     // For connected connections, if we exit unexpectedly, we need to cancel the connection.
   4077     if (comm->tcp_stream) {
   4078         ioloop_comm_cancel(tracker->connection);
   4079     }
   4080 out:
   4081     if (tracker != NULL) {
   4082         RELEASE_HERE(tracker, dp_tracker); // For the function.
   4083     }
   4084 }
   4085 
   4086 void
   4087 dns_proxy_input_for_server(comm_t *comm, srp_server_t *server_state, message_t *message, void *context)
   4088 {
   4089     char buf[INET6_ADDRSTRLEN];
   4090     const char *remote_name = buf;
   4091     if (comm->tcp_stream) {
   4092         remote_name = comm->name;
   4093     } else {
   4094         IOLOOP_NTOP(&message->src, buf);
   4095     }
   4096     dp_tracker_t *tracker = comm->context;
   4097     INFO("[C%d][TRK%d][QID %x] Received a new DNS message - src: " PRI_S_SRP ", message length: %u bytes.",
   4098          SERIAL(comm), SERIAL(tracker), ntohs(message->wire.id), remote_name, message->length);
   4099 
   4100 
   4101     dnssd_proxy_dns_evaluate(comm, message, context);
   4102 }
   4103 
   4104 static void
   4105 dns_proxy_input(comm_t *comm, message_t *message, void *context)
   4106 {
   4107     dns_proxy_input_for_server(comm, srp_servers, message, context);
   4108 }
   4109 
   4110 // usage is only called when we are building standalone dnssd-proxy, not the combined one.
   4111 #if (!SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY)
   4112 static int
   4113 usage(const char *progname)
   4114 {
   4115     ERROR("usage: %s", progname);
   4116     ERROR("ex: dnssd-proxy");
   4117     return 1;
   4118 }
   4119 #endif // #if (!SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY)
   4120 
   4121 // Called whenever we get a connection.
   4122 static void UNUSED
   4123 connected(comm_t *comm)
   4124 {
   4125     INFO("[C%d] connection from " PRI_S_SRP, SERIAL(comm), comm->name);
   4126     return;
   4127 }
   4128 
   4129 static served_domain_t *NULLABLE
   4130 new_served_domain(dp_interface_t *const NULLABLE interface, const char *const NONNULL domain)
   4131 {
   4132     served_domain_t *sdt = calloc(1, sizeof *sdt);
   4133     if (sdt == NULL) {
   4134         ERROR("Unable to allocate served domain %s", domain);
   4135         return NULL;
   4136     }
   4137     size_t domain_len = strlen(domain);
   4138     sdt->domain_ld = malloc(domain_len + 2);
   4139     if (sdt->domain_ld == NULL) {
   4140         ERROR("Unable to allocate served domain name %s", domain);
   4141         free(sdt);
   4142         return NULL;
   4143     }
   4144     sdt->domain_ld[0] = '.';
   4145     sdt->domain = sdt->domain_ld + 1;
   4146     memcpy(sdt->domain, domain, domain_len + 1);
   4147     sdt->domain_name = dns_pres_name_parse(sdt->domain);
   4148     sdt->interface = interface;
   4149     if (sdt->domain_name == NULL) {
   4150         if (interface != NULL) {
   4151             ERROR("invalid domain name for interface %s: %s", interface->name, sdt->domain);
   4152         } else {
   4153             ERROR("invalid domain name: %s", sdt->domain);
   4154         }
   4155         free(sdt);
   4156         return NULL;
   4157     }
   4158     sdt->next = served_domains;
   4159     served_domains = sdt;
   4160 
   4161     INFO("new served domain created - domain name: " PRI_S_SRP, sdt->domain);
   4162     return sdt;
   4163 }
   4164 
   4165 #if STUB_ROUTER
   4166 static served_domain_t *NULLABLE
   4167 find_served_domain(const char *const NONNULL domain)
   4168 {
   4169     served_domain_t *current;
   4170     for (current = served_domains; current != NULL; current = current->next) {
   4171         if (strcasecmp(domain, current->domain) == 0) {
   4172             break;
   4173         }
   4174     }
   4175 
   4176     return current;
   4177 }
   4178 #endif
   4179 
   4180 // served domain can only go away when combined with srp-mdns-proxy and interface going up and down.
   4181 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
   4182 static void
   4183 served_domain_free(served_domain_t *const served_domain)
   4184 {
   4185     INFO("served domain removed - domain name: " PRI_S_SRP, served_domain->domain);
   4186 
   4187    // free struct interface *NULLABLE interface
   4188     if (served_domain->interface != NULL) {
   4189         interface_addr_t *current = served_domain->interface->addresses;
   4190         interface_addr_t *next;
   4191         for (;current != NULL; current = next) {
   4192             next = current->next;
   4193             free(current);
   4194         }
   4195         if (served_domain->interface->name != NULL) {
   4196             free(served_domain->interface->name);
   4197         }
   4198         free(served_domain->interface);
   4199     }
   4200 
   4201     // free hardwired_t *NULLABLE hardwired_responses
   4202     if (served_domain->hardwired_responses != NULL) {
   4203         hardwired_t *current = served_domain->hardwired_responses;
   4204         hardwired_t *next;
   4205         for (; current != NULL; current = next) {
   4206             next = current->next;
   4207             free(current);
   4208         }
   4209     }
   4210 
   4211     // free dns_name_t *NONNULL domain_name;
   4212     if (served_domain->domain_name != NULL) {
   4213         dns_name_free(served_domain->domain_name);
   4214     }
   4215 
   4216     // free char *NONNULL domain_ld;
   4217     free(served_domain->domain_ld);
   4218 
   4219 #ifdef SRP_TEST_SERVER
   4220     last_freed_domain = served_domain;
   4221 #endif
   4222 
   4223     // free served_domain_t *
   4224     free(served_domain);
   4225 }
   4226 
   4227 static void
   4228 delete_served_domain(served_domain_t *const served_domain)
   4229 {
   4230     if (served_domain->questions == NULL) {
   4231         served_domain_free(served_domain);
   4232     }
   4233 }
   4234 
   4235 #if STUB_ROUTER
   4236 served_domain_t *
   4237 delete_served_domain_by_interface_name(const char *const NONNULL interface_name)
   4238 {
   4239     served_domain_t *current;
   4240     served_domain_t *prev = NULL;
   4241     for(current= served_domains; current != NULL; prev = current, current = current->next) {
   4242         if (current->interface == NULL) {
   4243             continue;
   4244         }
   4245         if (strcmp(interface_name, current->interface->name) != 0) {
   4246             continue;
   4247         }
   4248 
   4249         INFO("served domain deleted with interface - "
   4250             "domain: " PRI_S_SRP ", interface name: " PUB_S_SRP, current->domain, interface_name);
   4251 
   4252         // Since we are removing the entire served domain and the interface, the addresses that are associated with
   4253         // this interface will also be removed. Therefore, any hardwired response that contains these addresses should
   4254         // also be removed.
   4255         for (interface_addr_t *address = current->interface->addresses; address != NULL; address = address->next) {
   4256             dnssd_hardwired_process_addr_change(&address->addr, &address->mask, false);
   4257         }
   4258 
   4259         if (prev == NULL) {
   4260             served_domains = current->next;
   4261         } else {
   4262             prev->next = current->next;
   4263         }
   4264 
   4265         delete_served_domain(current);
   4266         break;
   4267     }
   4268 
   4269     return current;
   4270 }
   4271 #endif // STUB_ROUTER
   4272 #endif // SRP_FEATURE_DYNAMIC_CONFIGURATION
   4273 
   4274 // Dynamic interface detection...
   4275 // This is called whenever a new interface address is encountered.
   4276 
   4277 void
   4278 dnssd_proxy_ifaddr_callback(srp_server_t *UNUSED server_state, void *UNUSED context, const char *name,
   4279                             const addr_t *address, const addr_t *mask, uint32_t UNUSED flags,
   4280                             enum interface_address_change event_type)
   4281 {
   4282 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
   4283     bool is_new_interface = true;
   4284 #endif
   4285     bool succeeded;
   4286     const char *const action = (event_type == interface_address_added ? "Adding" : "Removing");
   4287 
   4288     if (event_type == interface_address_unchanged) {
   4289         goto exit;
   4290     }
   4291 
   4292     int interface_index = if_nametoindex(name);
   4293     if (address->sa.sa_family == AF_INET) {
   4294         IPv4_ADDR_GEN_SRP((const uint8_t *)&address->sin.sin_addr, addr_buf);
   4295         IPv4_ADDR_GEN_SRP((const uint8_t *)&mask->sin.sin_addr, mask_buf);
   4296         INFO("Interface " PUB_S_SRP " address " PRI_IPv4_ADDR_SRP " mask " PRI_IPv4_ADDR_SRP " index %d " PUB_S_SRP,
   4297              name, IPv4_ADDR_PARAM_SRP((const uint8_t *)&address->sin.sin_addr, addr_buf),
   4298              IPv4_ADDR_PARAM_SRP((const uint8_t *)&mask->sin.sin_addr, mask_buf), interface_index,
   4299              event_type == interface_address_added ? "added" : "removed");
   4300     } else if (address->sa.sa_family == AF_INET6) {
   4301         IPv6_ADDR_GEN_SRP((const uint8_t *)&address->sin6.sin6_addr, addr_buf);
   4302         IPv6_ADDR_GEN_SRP((const uint8_t *)&mask->sin6.sin6_addr, mask_buf);
   4303         INFO("Interface " PUB_S_SRP " address " PRI_IPv6_ADDR_SRP " mask " PRI_IPv6_ADDR_SRP " index %d " PUB_S_SRP,
   4304              name, IPv6_ADDR_PARAM_SRP((const uint8_t *)&address->sin6.sin6_addr, addr_buf),
   4305              IPv6_ADDR_PARAM_SRP((const uint8_t *)&mask->sin6.sin6_addr, mask_buf), interface_index,
   4306              event_type == interface_address_added ? "added" : "removed");
   4307     } else {
   4308         INFO("Interface " PUB_S_SRP " address type %d index %d " PUB_S_SRP, name, address->sa.sa_family, interface_index,
   4309              event_type == interface_address_added ? "added" : "removed");
   4310         INFO("ignoring non IP address");
   4311         goto exit;
   4312     }
   4313 
   4314 #if THREAD_BORDER_ROUTER && SRP_FEATURE_COMBINED_DNSSD_PROXY
   4315     // Ignore Thread interface
   4316     bool is_valid_address = thread_interface_name == NULL || strcmp(thread_interface_name, name) != 0;
   4317     if (!is_valid_address) {
   4318         INFO("skipping thread interface address");
   4319         goto exit;
   4320     }
   4321 #endif
   4322 
   4323     // Add/remove the address from the corresponding served domain.
   4324     served_domain_t **sp = &served_domains;
   4325     while (*sp != NULL) {
   4326         served_domain_t *current = *sp;
   4327         // Only change the served domain that owns the current interface and address.
   4328         if (current->interface == NULL || current->interface->ifindex == 0 ||
   4329             strcmp(current->interface->name, name) != 0) {
   4330             goto again;
   4331         }
   4332 
   4333         INFO(PUB_S_SRP " address from the served domain - domain: " PRI_S_SRP, action, current->domain);
   4334         succeeded = interface_process_addr_change(current->interface, address, mask, event_type);
   4335         require_action_quiet(succeeded, exit, ERROR("failed to " PUB_S_SRP " new interface address", action));
   4336 
   4337 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
   4338         is_new_interface = false;
   4339 
   4340         // if interface loses all usable IP addresses, the interface has gone, remove this interface and the
   4341         // corresponding served domain.
   4342         if (event_type == interface_address_deleted) {
   4343             if (current->interface->addresses == NULL) {
   4344                 INFO("Removing served domain with 0 address - domain: " PRI_S_SRP ", interface name: " PUB_S_SRP,
   4345                     current->domain, current->interface->name);
   4346                 *sp = current->next;
   4347                 delete_served_domain(current);
   4348                 continue;
   4349             }
   4350         }
   4351 #else // SRP_FEATURE_DYNAMIC_CONFIGURATION
   4352         if (current->interface->addresses == NULL) {
   4353             current->interface->ifindex = 0;
   4354         }
   4355 #endif // SRP_FEATURE_DYNAMIC_CONFIGURATION
   4356     again:
   4357         sp = &(*sp)->next;
   4358     }
   4359 
   4360     // We will only create new served domain from dnssd_proxy_ifaddr_callback if the callback gets called from
   4361     // srp-mdns-proxy.
   4362 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
   4363     if (event_type == interface_address_added && is_new_interface) {
   4364         served_domain_t *const new_served_domain = add_new_served_domain_with_interface(name, address, mask);
   4365         require_action_quiet(new_served_domain != NULL, exit,
   4366             ERROR("failed to add new served domain ""- interface name: " PUB_S_SRP, name));
   4367 
   4368         bool hardwired_set = dnssd_hardwired_setup_for_served_domain(new_served_domain);
   4369         if (!hardwired_set) {
   4370             ERROR("failed to setup hardwired response for newly created served domain - domain: " PRI_S_SRP, name);
   4371             delete_served_domain(new_served_domain);
   4372         }
   4373         INFO("New served domain created and hardwired response created - domain: " PRI_S_SRP,
   4374             new_served_domain->domain);
   4375     }
   4376 #endif // SRP_FEATURE_DYNAMIC_CONFIGURATION
   4377 
   4378 #if STUB_ROUTER
   4379     // Added or removed address will possibly need hardwired response to be updated.
   4380     dnssd_hardwired_process_addr_change(address, mask, event_type == interface_address_added);
   4381 #endif
   4382 
   4383 exit:
   4384     return;
   4385 }
   4386 
   4387 #if !SRP_FEATURE_DYNAMIC_CONFIGURATION
   4388 // Config file parsing...
   4389 static bool
   4390 interface_handler(void * UNUSED context, const char * UNUSED filename, char **hunks, int UNUSED num_hunks,
   4391                   int UNUSED lineno)
   4392 {
   4393     dp_interface_t *interface = calloc(1, sizeof *interface);
   4394     if (interface == NULL) {
   4395         ERROR("Unable to allocate interface %s", hunks[1]);
   4396         return false;
   4397     }
   4398 
   4399     interface->name = strdup(hunks[1]);
   4400     if (interface->name == NULL) {
   4401         ERROR("Unable to allocate interface name %s", hunks[1]);
   4402         free(interface);
   4403         return false;
   4404     }
   4405 
   4406     if (!strcmp(hunks[0], "nopush")) {
   4407         interface->no_push = true;
   4408     }
   4409 
   4410     if (new_served_domain(interface, hunks[2]) == NULL) {
   4411         free(interface->name);
   4412         free(interface);
   4413         return false;
   4414     }
   4415     return true;
   4416 }
   4417 
   4418 static bool
   4419 port_handler(void * UNUSED context, const char * UNUSED filename, char **hunks, int UNUSED num_hunks, int UNUSED lineno)
   4420 {
   4421     char *ep = NULL;
   4422     long port = strtol(hunks[1], &ep, 10);
   4423     if (port < 0 || port > 65535 || *ep != 0) {
   4424         ERROR("Invalid port number: %s", hunks[1]);
   4425         return false;
   4426     }
   4427     if (!strcmp(hunks[0], "udp-port")) {
   4428         dnssd_proxy_udp_port = port;
   4429     } else if (!strcmp(hunks[0], "tcp-port")) {
   4430         dnssd_proxy_tcp_port = port;
   4431     } else if (!strcmp(hunks[0], "tls-port")) {
   4432         dnssd_proxy_tls_port = port;
   4433     }
   4434     return true;
   4435 }
   4436 
   4437 static bool
   4438 config_string_handler(char **ret, const char * UNUSED filename, const char *string, int UNUSED lineno, bool tdot,
   4439                                   bool ldot)
   4440 {
   4441     char *s;
   4442     int add_trailing_dot = 0;
   4443     int add_leading_dot = ldot ? 1 : 0;
   4444     size_t len = strlen(string);
   4445 
   4446     // Space for NUL and leading dot.
   4447     if (tdot && len > 0 && string[len - 1] != '.') {
   4448         add_trailing_dot = 1;
   4449     }
   4450     s = malloc(strlen(string) + add_leading_dot + add_trailing_dot + 1);
   4451     if (s == NULL) {
   4452         ERROR("Unable to allocate domain name %s", string);
   4453         return false;
   4454     }
   4455     *ret = s;
   4456     if (ldot) {
   4457         *s++ = '.';
   4458     }
   4459     memcpy(s, string, len + add_leading_dot + add_trailing_dot + 1);
   4460     if (add_trailing_dot) {
   4461         s[len] = '.';
   4462         s[len + 1] = 0;
   4463     }
   4464     return true;
   4465 }
   4466 
   4467 static bool
   4468 my_name_handler(void * UNUSED context, const char *filename, char **hunks, int UNUSED num_hunks, int lineno)
   4469 {
   4470     static char *new_name = NULL;
   4471     if (new_name != NULL) {
   4472         free(new_name);
   4473         my_name = NULL;
   4474         new_name = NULL;
   4475     }
   4476     if (!config_string_handler(&new_name, filename, hunks[1], lineno, false, false)) {
   4477         return false;
   4478     }
   4479     my_name = new_name;
   4480     size_t len = strlen(my_name);
   4481     size_t bigger = sizeof(DOT_HOME_NET_DOMAIN) > sizeof(DOT_LOCAL) ? sizeof(DOT_HOME_NET_DOMAIN) : sizeof(DOT_LOCAL);
   4482     if (len >= sizeof(local_host_name) - bigger) {
   4483         ERROR("truncating local hostname %s", my_name);
   4484         return false;
   4485     }
   4486 
   4487     // Set up existing local host name with .local. suffix
   4488     snprintf(local_host_name_dot_local, sizeof(local_host_name_dot_local), "%s" DOT_LOCAL, my_name);
   4489 
   4490     // Set up existing local host name with .home.net. suffix
   4491     snprintf(local_host_name, sizeof(local_host_name), "%s" DOT_HOME_NET_DOMAIN, my_name);
   4492     return true;
   4493 }
   4494 
   4495 static bool
   4496 listen_addr_handler(void * UNUSED context, const char *filename, char **hunks, int UNUSED num_hunks, int lineno)
   4497 {
   4498     if (num_listen_addrs == MAX_ADDRS) {
   4499         ERROR("Only %d IPv4 listen addresses can be configured.", MAX_ADDRS);
   4500         return false;
   4501     }
   4502     return config_string_handler(&listen_addrs[num_listen_addrs++], filename, hunks[1], lineno, false, false);
   4503 }
   4504 
   4505 static bool
   4506 publish_addr_handler(void * UNUSED context, const char *filename, char **hunks, int UNUSED num_hunks, int lineno)
   4507 {
   4508     if (num_publish_addrs == MAX_ADDRS) {
   4509         ERROR("Only %d addresses can be published.", MAX_ADDRS);
   4510         return false;
   4511     }
   4512     return config_string_handler(&publish_addrs[num_publish_addrs++], filename, hunks[1], lineno, false, false);
   4513 }
   4514 
   4515 static bool
   4516 tls_key_handler(void * UNUSED context, const char *filename, char **hunks, int UNUSED num_hunks, int lineno)
   4517 {
   4518     return config_string_handler(&tls_key_filename, filename, hunks[1], lineno, false, false);
   4519 }
   4520 
   4521 static bool
   4522 tls_cert_handler(void * UNUSED context, const char *filename, char **hunks, int UNUSED num_hunks, int lineno)
   4523 {
   4524     return config_string_handler(&tls_cert_filename, filename, hunks[1], lineno, false, false);
   4525 }
   4526 
   4527 static bool
   4528 tls_cacert_handler(void * UNUSED context, const char *filename, char **hunks, int UNUSED num_hunks, int lineno)
   4529 {
   4530     return config_string_handler(&tls_cacert_filename, filename, hunks[1], lineno, false, false);
   4531 }
   4532 
   4533 config_file_verb_t dp_verbs[] = {
   4534     { "interface",    3, 3, interface_handler },    // interface <name> <domain>
   4535     { "nopush",       3, 3, interface_handler },    // nopush <name> <domain>
   4536     { "udp-port",     2, 2, port_handler },         // udp-port <number>
   4537     { "tcp-port",     2, 2, port_handler },         // tcp-port <number>
   4538     { "tls-port",     2, 2, port_handler },         // tls-port <number>
   4539     { "my-name",      2, 2, my_name_handler },      // my-name <domain name>
   4540     { "tls-key",      2, 2, tls_key_handler },      // tls-key <filename>
   4541     { "tls-cert",     2, 2, tls_cert_handler },     // tls-cert <filename>
   4542     { "tls-cacert",   2, 2, tls_cacert_handler },   // tls-cacert <filename>
   4543     { "listen-addr",  2, 2, listen_addr_handler },  // listen-addr <IP address>
   4544     { "publish-addr", 2, 2, publish_addr_handler }  // publish-addr <IP address>
   4545 };
   4546 #define NUMCFVERBS ((sizeof dp_verbs) / sizeof (config_file_verb_t))
   4547 #endif // !SRP_FEATURE_DYNAMIC_CONFIGURATION
   4548 
   4549 static wakeup_t *tls_listener_wakeup;
   4550 static int tls_listener_index;
   4551 static void dnssd_tls_listener_restart(comm_t *NONNULL listener, void *NULLABLE context);
   4552 
   4553 static void dnssd_tls_key_change_notification_send(void)
   4554 {
   4555     static int dnssd_tls_change_notification_token = NOTIFY_TOKEN_INVALID;
   4556 
   4557     if (dnssd_tls_change_notification_token == NOTIFY_TOKEN_INVALID) {
   4558         uint32_t notifyStatus = notify_register_check(kDNSSDAdvertisingProxyTLSKeyUpdateNotification,
   4559                                                       &dnssd_tls_change_notification_token);
   4560         if (notifyStatus != NOTIFY_STATUS_OK) {
   4561             dnssd_tls_change_notification_token = NOTIFY_TOKEN_INVALID;
   4562             ERROR("notify_register_check(%s) failed with %u", kDNSSDAdvertisingProxyTLSKeyUpdateNotification, notifyStatus);
   4563             return;
   4564         }
   4565     }
   4566 
   4567     if (dnssd_tls_change_notification_token != NOTIFY_TOKEN_INVALID) {
   4568         uint32_t notifyStatus = notify_post(kDNSSDAdvertisingProxyTLSKeyUpdateNotification);
   4569         if (notifyStatus != NOTIFY_STATUS_OK) {
   4570             ERROR("notify_post(%s) %u", kDNSSDAdvertisingProxyTLSKeyUpdateNotification, notifyStatus);
   4571             notify_cancel(dnssd_tls_change_notification_token);
   4572             dnssd_tls_change_notification_token = NOTIFY_TOKEN_INVALID;
   4573         }
   4574     }
   4575 }
   4576 
   4577 static void
   4578 dnssd_tls_listener_ready(void *UNUSED context, uint16_t port)
   4579 {
   4580 #ifdef SRP_TEST_SERVER
   4581     if (srp_test_dnssd_tls_listener_ready != NULL) {
   4582         srp_test_dnssd_tls_listener_ready(srp_test_tls_listener_context, port);
   4583     }
   4584 #else
   4585     (void)context;
   4586     (void)port;
   4587 #endif
   4588 }
   4589 
   4590 static void dnssd_tls_listener_listen(void *context, bool init_daemon)
   4591 {
   4592     addr_t addr;
   4593     INFO("starting DoT listener");
   4594     memset(&addr, 0, sizeof(addr));
   4595     addr.sa.sa_family = AF_UNSPEC;
   4596 #ifndef NOT_HAVE_SA_LEN
   4597     addr.sa.sa_len = sizeof(addr.sin6);
   4598 #endif
   4599     addr.sin6.sin6_port = htons(dnssd_proxy_tls_port);
   4600 #ifndef EXCLUDE_TLS
   4601     dnssd_proxy_listeners[tls_listener_index] =
   4602             ioloop_listener_create(true, true, init_daemon, NULL, 0, &addr, NULL, "DNS over TLS",
   4603                                    dns_proxy_input, NULL, dnssd_tls_listener_restart, dnssd_tls_listener_ready,
   4604                                    NULL, srp_tls_configure, 0, context);
   4605 #else
   4606     dnssd_proxy_listeners[tls_listener_index] =
   4607         ioloop_listener_create(true, true, init_daemon, NULL, 0, &addr, NULL, "DNS over TLS",
   4608                                dns_proxy_input, NULL, dnssd_tls_listener_restart, dnssd_tls_listener_ready,
   4609                                NULL, NULL, 0, context);
   4610 #endif
   4611     if (dnssd_proxy_listeners[tls_listener_index] == NULL) {
   4612         ERROR("DNS Push listener: fail.");
   4613         goto exit;
   4614     }
   4615 
   4616     // Notify about intial key update
   4617     dnssd_tls_key_change_notification_send();
   4618 
   4619     // Schedule a wake up timer to rotate the expired TLS certificate.
   4620     schedule_tls_certificate_rotation(&tls_listener_wakeup, dnssd_proxy_listeners[tls_listener_index]);
   4621 exit:
   4622     return;
   4623 }
   4624 
   4625 static void dnssd_tls_listener_relisten(void *context)
   4626 {
   4627     dnssd_tls_listener_listen(context, false);
   4628 }
   4629 
   4630 static void
   4631 dnssd_tls_listener_restart(comm_t *UNUSED in_listener, void *context)
   4632 {
   4633     const bool doing_rotation = dnssd_proxy_listeners[tls_listener_index]->tls_rotation_ready;
   4634     ioloop_listener_release(dnssd_proxy_listeners[tls_listener_index]);
   4635     dnssd_proxy_listeners[tls_listener_index] = NULL;
   4636 
   4637     if (doing_rotation) {
   4638         const bool succeeded = srp_tls_init();
   4639         if (!succeeded) {
   4640             FAULT("srp_tls_init failed.");
   4641             return;
   4642         }
   4643 
   4644         // Send TLS key update notification
   4645         dnssd_tls_key_change_notification_send();
   4646         dnssd_tls_listener_listen(NULL, false);
   4647     } else {
   4648         INFO("Creation of TLS listener failed; reattempting in 10s.");
   4649 
   4650         if (tls_listener_wakeup == NULL) {
   4651             tls_listener_wakeup = ioloop_wakeup_create();
   4652             if (tls_listener_wakeup == NULL) {
   4653                 ERROR("Unable to allocate wakeup in order to re-attempt TLS listener creation.");
   4654                 return;
   4655             }
   4656         }
   4657         ioloop_add_wake_event(tls_listener_wakeup, context, dnssd_tls_listener_relisten, NULL, 10 * MSEC_PER_SEC);
   4658     }
   4659 }
   4660 
   4661 static void
   4662 dnssd_push_setup(void)
   4663 {
   4664     tls_listener_index = dnssd_proxy_num_listeners++;
   4665     dnssd_tls_listener_listen(NULL, true);
   4666 
   4667     // Only set hardwired response when dynamic configuration is enabled.  Dynamic configuration
   4668     // sets up hardwired response when new address of the interface is added.
   4669 #if SRP_FEATURE_DYNAMIC_CONFIGURATION // not set hardwired response for now
   4670     dnssd_hardwired_push_setup();
   4671 #endif // !SRP_FEATURE_DYNAMIC_CONFIGURATION
   4672 }
   4673 
   4674 #if (!SRP_FEATURE_CAN_GENERATE_TLS_CERT)
   4675 
   4676 // Start a key generation or cert signing program.   Arguments are key=value pairs.
   4677 // Arguments that can be constant should be <"key=value", NULL>.   Arguments that
   4678 // have a variable component should be <"key", value">.  References to arguments
   4679 // will be held, except that if the rhs of the pair is variable, memory is allocated
   4680 // to store the key=value pair, so the neither the key nor the value is retained.
   4681 // The callback is called when the program exits.
   4682 
   4683 static void
   4684 keyprogram_start(const char *program, subproc_callback_t callback, ...)
   4685 {
   4686 #define MAX_SUBPROC_VARS 3
   4687     size_t lens[MAX_SUBPROC_VARS];
   4688     char *vars[MAX_SUBPROC_VARS];
   4689     int num_vars = 0;
   4690     char *argv[MAX_SUBPROC_ARGS + 1];
   4691     int argc = 0;
   4692     va_list vl;
   4693     int i;
   4694     subproc_t *subproc = NULL;
   4695 
   4696     va_start(vl, callback);
   4697     while (true) {
   4698         char *vname, *value;
   4699         char *arg;
   4700 
   4701         vname = va_arg(vl, char *);
   4702         if (vname == NULL) {
   4703             break;
   4704         }
   4705         value = va_arg(vl, char *);
   4706 
   4707         if (argc >= MAX_SUBPROC_ARGS) {
   4708             ERROR("keyprogram_start: too many arguments.");
   4709         }
   4710 
   4711         if (value == NULL) {
   4712             arg = vname;
   4713         } else {
   4714             if (num_vars >= MAX_SUBPROC_VARS) {
   4715                 ERROR("Too many variable args: %s %s", vname, value);
   4716                 goto out;
   4717             }
   4718             lens[num_vars] = strlen(vname) + strlen(value) + 2;
   4719             vars[num_vars] = malloc(lens[num_vars]);
   4720             if (vars[num_vars] == NULL) {
   4721                 ERROR("No memory for variable key=value %s %s", vname, value);
   4722                 goto out;
   4723             }
   4724             snprintf(vars[num_vars], lens[num_vars], "%s=%s", vname, value);
   4725             arg = vars[num_vars];
   4726             num_vars++;
   4727         }
   4728         argv[argc++] = arg;
   4729     }
   4730     argv[argc] = NULL;
   4731     subproc = ioloop_subproc(program, argv, argc, callback, NULL, NULL);
   4732     if (subproc != NULL) {
   4733         ioloop_subproc_run_sync(subproc);
   4734         ioloop_subproc_release(subproc);
   4735     }
   4736 out:
   4737     for (i = 0; i < num_vars; i++) {
   4738         free(vars[i]);
   4739     }
   4740 }
   4741 
   4742 static bool
   4743 finished_okay(const char *context, int status, const char *error)
   4744 {
   4745     // If we get an error, something failed before the program had been successfully started.
   4746     if (error != NULL) {
   4747         ERROR("%s failed on startup: %s", context, error);
   4748     }
   4749 
   4750     // The key file generation process completed
   4751     else if (WIFEXITED(status)) {
   4752         if (WEXITSTATUS(status) != 0) {
   4753             ERROR("%s program exited with status %d", context, status);
   4754             // And that means we don't have DNS Push--sorry!
   4755         } else {
   4756             return true;
   4757         }
   4758     } else if (WIFSIGNALED(status)) {
   4759         ERROR("%s program exited on signal %d", context, WTERMSIG(status));
   4760         // And that means we don't have DNS Push--sorry!
   4761     } else if (WIFSTOPPED(status)) {
   4762         ERROR("%s program stopped on signal %d", context, WSTOPSIG(status));
   4763         // And that means we don't have DNS Push--sorry!
   4764     } else {
   4765         ERROR("%s program exit status unknown: %d", context, status);
   4766         // And that means we don't have DNS Push--sorry!
   4767     }
   4768     return false;
   4769 }
   4770 
   4771 // Called after the cert has been generated.
   4772 static void
   4773 certfile_finished_callback(void *NULLABLE context, int status, const char *error)
   4774 {
   4775     (void)context;
   4776 
   4777     // If we were able to generate a cert, we can start DNS Push service and start advertising it.
   4778     if (finished_okay("Certificate signing", status, error)) {
   4779         int i = dnssd_proxy_num_listeners;
   4780 
   4781         dnssd_push_setup();
   4782 
   4783         for (; i < dnssd_proxy_num_listeners; i++) {
   4784             INFO("Started " PUB_S_SRP, dnssd_proxy_listeners[i]->name);
   4785         }
   4786     }
   4787 }
   4788 
   4789 // Called after the key has been generated.
   4790 static void
   4791 keyfile_finished_callback(void *context, int status, const char *error)
   4792 {
   4793     (void)context;
   4794     if (finished_okay("Keyfile generation", status, error)) {
   4795         INFO("Keyfile generation completed.");
   4796 
   4797     // XXX dates need to not be constant!!!
   4798     keyprogram_start(CERTWRITE_PROGRAM, certfile_finished_callback,
   4799                      "selfsign=1", NULL, "issuer_key", tls_key_filename, "issuer_name=CN", my_name,
   4800                      "not_before=20210825000000", NULL, "not_after=20230824235959", NULL, "is_ca=1", NULL,
   4801                      "max_pathlen=0", NULL, "output_file", tls_cert_filename, NULL);
   4802     }
   4803 
   4804 }
   4805 #endif // #if (SRP_FEATURE_CAN_GENERATE_TLS_CERT)
   4806 
   4807 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
   4808 static served_domain_t *NONNULL
   4809 add_new_served_domain_with_interface(const char *const NONNULL name,
   4810                                      const addr_t *const NULLABLE address, const addr_t *const NULLABLE mask)
   4811 {
   4812     dp_interface_t *new_interface = NULL;
   4813     served_domain_t *served_domain = NULL;
   4814     bool local_only_interface = !strcmp(LOCAL_ONLY_PSEUDO_INTERFACE, name);
   4815     bool locally_served_interface = !local_only_interface && !strcmp(ALL_LOCALS_PSEUDO_INTERFACE, name);
   4816 #if SRP_FEATURE_LOCAL_DISCOVERY
   4817     bool infrastructure_interface = !locally_served_interface && !strcmp(INFRASTRUCTURE_PSEUDO_INTERFACE, name);
   4818 #endif
   4819     bool succeeded;
   4820 
   4821     new_interface = calloc(1, sizeof(*new_interface));
   4822     require_action_quiet(new_interface != NULL, exit, succeeded = false;
   4823         ERROR("calloc failed - name: " PRI_S_SRP ", allocate size: %lu", name, sizeof(*new_interface)));
   4824 
   4825     new_interface->name = strdup(name);
   4826     require_action_quiet(new_interface->name != NULL, exit, succeeded = false;
   4827         ERROR("strdup failed to copy interface name - interface name: " PRI_S_SRP, name));
   4828 
   4829     if (local_only_interface) {
   4830         new_interface->ifindex = kDNSServiceInterfaceIndexLocalOnly;
   4831     } else if (locally_served_interface) {
   4832         new_interface->ifindex = kDNSServiceInterfaceIndexAny;
   4833 #if SRP_FEATURE_LOCAL_DISCOVERY
   4834     } else if (infrastructure_interface) {
   4835         new_interface->ifindex = kDNSServiceInterfaceIndexInfra;
   4836 #endif
   4837     } else {
   4838         new_interface->ifindex = if_nametoindex(name);
   4839     }
   4840 
   4841     // Enable DNS push by default.
   4842     new_interface->no_push = false;
   4843 
   4844     if (address != NULL) {
   4845         require_action_quiet(mask != NULL, exit, succeeded = false);
   4846 
   4847         new_interface->addresses = calloc(1, sizeof(*new_interface->addresses));
   4848         require_action_quiet(new_interface->addresses != NULL, exit, succeeded = false;
   4849             ERROR("calloc failed - allocated size: %lu", sizeof(*new_interface->addresses)));
   4850         new_interface->addresses->addr = *address;
   4851         new_interface->addresses->mask = *mask;
   4852     }
   4853 
   4854     char *per_interface_served_domain;
   4855 #if STUB_ROUTER
   4856     char served_domain_buffer[DNS_MAX_NAME_SIZE];
   4857 #endif
   4858     if (local_only_interface) {
   4859         // All queries sent to <Thread ID>.thread.home.arpa. will only be proxied to local only interface.
   4860         per_interface_served_domain = THREAD_DOMAIN_WITH_ID;
   4861     } else if (locally_served_interface) {
   4862         per_interface_served_domain = DEFAULT_SERVICE_ARPA_DOMAIN;
   4863 #if SRP_FEATURE_LOCAL_DISCOVERY
   4864     } else if (infrastructure_interface) {
   4865         per_interface_served_domain = DOT_LOCAL_DOMAIN;
   4866 #endif
   4867     } else {
   4868 #if STUB_ROUTER
   4869         int bytes_written = snprintf(served_domain_buffer, sizeof(served_domain_buffer),
   4870             "%s-%s." HOME_NET_DOMAIN, local_host_name, name);
   4871         require_action_quiet(bytes_written > 0 && (size_t)bytes_written < sizeof(served_domain_buffer), exit,
   4872             succeeded = false;
   4873             ERROR("snprintf failed - local host name: " PRI_S_SRP ", interface name: " PUB_S_SRP
   4874                 ", name buffer size: %lu", my_name, name, sizeof(served_domain_buffer))
   4875         );
   4876         per_interface_served_domain = served_domain_buffer;
   4877 #else
   4878         ERROR("unexpected served domain " PRI_S_SRP, name);
   4879         succeeded = false;
   4880         goto exit;
   4881 #endif
   4882     }
   4883 
   4884     served_domain = new_served_domain(new_interface, per_interface_served_domain);
   4885     require_action_quiet(served_domain != NULL, exit, succeeded = false;
   4886         ERROR("new_served_domain failed - interface name: " PUB_S_SRP ", served domain: " PRI_S_SRP,
   4887             name, per_interface_served_domain)
   4888     );
   4889 
   4890     succeeded = true;
   4891     INFO("new served domain added with interface - served domain: " PUB_S_SRP ", interface name: " PUB_S_SRP,
   4892         per_interface_served_domain, name);
   4893 exit:
   4894     if (!succeeded) {
   4895         if (new_interface != NULL) {
   4896             if (new_interface->addresses != NULL) {
   4897                 verify_action(new_interface->addresses->next == NULL,
   4898                     ERROR("multiple addresses added for this new interface"));
   4899                 free(new_interface->addresses);
   4900             }
   4901             if (new_interface->name != NULL) {
   4902                 free(new_interface->name);
   4903             }
   4904             free(new_interface);
   4905         }
   4906     }
   4907 
   4908     return served_domain;
   4909 }
   4910 #endif // !SRP_FEATURE_DYNAMIC_CONFIGURATION
   4911 
   4912 static bool
   4913 interface_addr_t_equal(const interface_addr_t *const NONNULL a, const interface_addr_t *const NONNULL b)
   4914 {
   4915     bool equal;
   4916     const addr_t *const a_addr = &a->addr;
   4917     const addr_t *const a_mask = &a->mask;
   4918     const addr_t *const b_addr = &b->addr;
   4919     const addr_t *const b_mask = &b->mask;
   4920 
   4921     if (a_addr->sa.sa_family != b_addr->sa.sa_family) {
   4922         equal = false;
   4923         goto exit;
   4924     }
   4925 
   4926     require_action_quiet(a_addr->sa.sa_family == a_mask->sa.sa_family, exit, equal = false;
   4927         ERROR("A address and mask are not in the same sa_family - address family: %d, mask family: %d",
   4928             a_addr->sa.sa_family, a_mask->sa.sa_family)
   4929     );
   4930 
   4931     require_action_quiet(b_addr->sa.sa_family == b_mask->sa.sa_family, exit, equal = false;
   4932         ERROR("B address and mask are no in the same sa_family - address family: %d, mask family: %d",
   4933             b_addr->sa.sa_family, b_mask->sa.sa_family)
   4934     );
   4935 
   4936     if (a_addr->sa.sa_family == AF_INET) {
   4937         if (a_addr->sin.sin_addr.s_addr != b_addr->sin.sin_addr.s_addr) {
   4938             equal = false;
   4939             goto exit;
   4940         }
   4941 
   4942         if (a_mask->sin.sin_addr.s_addr != b_mask->sin.sin_addr.s_addr) {
   4943             equal = false;
   4944             goto exit;
   4945         }
   4946     } else { // a_addr->sa.sa_family == AF_INET6
   4947         if (memcmp(&a_addr->sin6.sin6_addr, &b_addr->sin6.sin6_addr, sizeof(a_addr->sin6.sin6_addr)) != 0) {
   4948             equal = false;
   4949             goto exit;
   4950         }
   4951 
   4952         if (memcmp(&a_mask->sin6.sin6_addr, &b_mask->sin6.sin6_addr, sizeof(a_mask->sin6.sin6_addr)) != 0) {
   4953             equal = false;
   4954             goto exit;
   4955         }
   4956     }
   4957 
   4958     equal = true;
   4959 exit:
   4960     return equal;
   4961 }
   4962 
   4963 static bool
   4964 interface_add_new_address(dp_interface_t *const NONNULL interface, const addr_t *const NONNULL address,
   4965                           const addr_t *const NONNULL mask)
   4966 {
   4967     bool succeeded;
   4968 
   4969     interface_addr_t *new_if_addr = calloc(1, sizeof(*new_if_addr));
   4970     require_action_quiet(new_if_addr != NULL, exit, succeeded = false;
   4971         ERROR("calloc failed - allocated size: %zu", sizeof(*new_if_addr)));
   4972     new_if_addr->addr = *address;
   4973     new_if_addr->mask = *mask;
   4974     new_if_addr->next = NULL;
   4975 
   4976     interface_addr_t **ap;
   4977 
   4978     for (ap = &interface->addresses; *ap != NULL; ap = &(*ap)->next)
   4979         ;
   4980 
   4981     *ap = new_if_addr;
   4982     succeeded = true;;
   4983 exit:
   4984     return succeeded;
   4985 }
   4986 
   4987 static bool
   4988 interface_remove_old_address(dp_interface_t *const NONNULL interface, const addr_t *const NONNULL address,
   4989                              const addr_t *const NONNULL mask)
   4990 {
   4991     bool succeeded;
   4992     interface_addr_t addr_to_remove = {NULL, *address, *mask};
   4993     interface_addr_t **ap;
   4994     interface_addr_t *current;
   4995 
   4996     for (ap = &interface->addresses; *ap != NULL; ap = &(*ap)->next) {
   4997         if (interface_addr_t_equal(*ap, &addr_to_remove)) {
   4998             break;
   4999         }
   5000     }
   5001     if (*ap == NULL) {
   5002         INFO("address not found in the interface address list - interface name: " PUB_S_SRP, interface->name);
   5003         succeeded = false;
   5004         goto exit;
   5005     }
   5006     current = *ap;
   5007     *ap = current->next;
   5008     free(current);
   5009 
   5010     succeeded = true;
   5011 exit:
   5012     return succeeded;
   5013 }
   5014 
   5015 static bool
   5016 interface_process_addr_change(dp_interface_t *const NONNULL interface, const addr_t *const NONNULL address,
   5017                               const addr_t *const NONNULL mask, const enum interface_address_change event_type)
   5018 {
   5019     bool succeeded;
   5020 
   5021     require_action_quiet(event_type != interface_address_unchanged, exit, succeeded = false;
   5022         INFO("no address change event happens"));
   5023 
   5024     if (event_type == interface_address_added) {
   5025         succeeded = interface_add_new_address(interface, address, mask);
   5026     } else { // event_type == interface_address_removed
   5027         succeeded = interface_remove_old_address(interface, address, mask);
   5028     }
   5029 
   5030     INFO("address added/removed successfully - event: " PUB_S_SRP,
   5031         event_type == interface_address_added ? "added" : "removed");
   5032 
   5033 exit:
   5034     return succeeded;
   5035 }
   5036 
   5037 static void
   5038 towire_init(dns_wire_t * const NONNULL wire_ptr, dns_towire_state_t * const NONNULL towire_ptr)
   5039 {
   5040     memset(wire_ptr, 0, sizeof(*wire_ptr));
   5041     memset(towire_ptr, 0, sizeof(*towire_ptr));
   5042     towire_ptr->message = wire_ptr;
   5043     towire_ptr->lim = &wire_ptr->data[DNS_DATA_SIZE];
   5044     towire_ptr->p = wire_ptr->data;
   5045 }
   5046 
   5047 #if STUB_ROUTER
   5048 static bool
   5049 string_ends_with(const char *const NONNULL str, const char *const NONNULL suffix)
   5050 {
   5051     size_t str_len = strlen(str);
   5052     size_t suffix_len = strlen(suffix);
   5053     bool ret;
   5054 
   5055     if (str_len < suffix_len) {
   5056         ret = false;
   5057         goto exit;
   5058     }
   5059 
   5060     if (strcmp(str + (str_len-suffix_len), suffix) != 0) {
   5061         ret = false;
   5062         goto exit;
   5063     }
   5064 
   5065     ret = true;
   5066 exit:
   5067     return ret;
   5068 }
   5069 #endif
   5070 
   5071 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
   5072 #if STUB_ROUTER
   5073 static bool
   5074 served_domain_change_domain_name(void)
   5075 {
   5076     bool succeeded = true;
   5077 
   5078     served_domain_t *next;
   5079     for (served_domain_t *current = served_domains; current != NULL; current = next) {
   5080         next = current->next;
   5081         if (!string_ends_with(current->domain, HOME_NET_DOMAIN)) {
   5082             continue;
   5083         }
   5084         // Skip local only interface because only served domain <Thread ID>.thread.home.arpa. does not contain domain
   5085         // string.
   5086         if (current->interface != NULL && strcmp(LOCAL_ONLY_PSEUDO_INTERFACE, current->interface->name) == 0) {
   5087             continue;
   5088         }
   5089 
   5090         // Constructs new served domain name.
   5091         char *new_served_domain_name;
   5092         char new_served_domain_buff[DNS_MAX_NAME_SIZE];
   5093 
   5094         if (0) {
   5095         } else if (current->interface != NULL) { // <local host name>-<interface name>.home.arpa.
   5096             const dp_interface_t *const interface = current->interface;
   5097             int bytes_written = snprintf(new_served_domain_buff, sizeof(new_served_domain_buff),
   5098                 "%s-%s." HOME_NET_DOMAIN, local_host_name, interface->name);
   5099             require_action_quiet(bytes_written > 0 && (size_t)bytes_written < sizeof(new_served_domain_buff), exit,
   5100                 succeeded = false; ERROR("snprintf failed"));
   5101             new_served_domain_name = new_served_domain_buff;
   5102         } else { // <local host name>.home.arpa.
   5103             int bytes_written = snprintf(new_served_domain_buff, sizeof(new_served_domain_buff),
   5104                 "%s." HOME_NET_DOMAIN, local_host_name);
   5105             require_action_quiet(bytes_written > 0 && (size_t)bytes_written < sizeof(new_served_domain_buff), exit,
   5106                 succeeded = false; ERROR("snprintf failed"));
   5107             new_served_domain_name = new_served_domain_buff;
   5108         }
   5109 
   5110         INFO("Updating served domain from " PRI_S_SRP " to " PRI_S_SRP, current->domain, new_served_domain_name);
   5111 
   5112         // Free the old served domain name.
   5113         free(current->domain_ld);
   5114         dns_name_free(current->domain_name);
   5115 
   5116         // Set the new served domain name.
   5117         size_t domain_len = strlen(new_served_domain_name);
   5118         current->domain_ld = malloc(domain_len + 2);
   5119         require_action_quiet(current->domain_ld != NULL, for_loop_exit, succeeded = false;
   5120             ERROR("malloc failed - allocated length: %zu", domain_len + 2));
   5121         current->domain_ld[0] = '.';
   5122         current->domain = current->domain_ld + 1;
   5123         memcpy(current->domain, new_served_domain_name, domain_len);
   5124         current->domain[domain_len] = '\0';
   5125 
   5126         current->domain_name = dns_pres_name_parse(current->domain);
   5127         require_action_quiet(current->domain_name != NULL, for_loop_exit, succeeded = false;
   5128             ERROR("failed to create parsed DNS name - domain name to be parsed: " PRI_S_SRP, current->domain)
   5129         );
   5130 
   5131     for_loop_exit:
   5132         if (!succeeded) {
   5133             delete_served_domain(current);
   5134         }
   5135     }
   5136 
   5137 exit:
   5138     return succeeded;
   5139 }
   5140 #endif // STUB_ROUTER
   5141 
   5142 static bool
   5143 served_domain_process_name_change(void)
   5144 {
   5145     bool succeeded;
   5146 
   5147     // Deletes all hardwired response set in the served domain.
   5148     dnssd_hardwired_clear();
   5149 
   5150 #if STUB_ROUTER
   5151     // Since local host name changes, we need to reflect the change in the served domain name.
   5152     succeeded = served_domain_change_domain_name();
   5153     require_action_quiet(succeeded, exit, ERROR("served_domain_change_domain_name failed"));
   5154 #endif
   5155 
   5156     // Re-set the hardwired response
   5157     dnssd_hardwired_setup();
   5158 
   5159     // Re-set the DNS push hardwired response
   5160     dnssd_hardwired_push_setup();
   5161 
   5162     succeeded = true;
   5163 #if STUB_ROUTER
   5164 exit:
   5165 #endif
   5166     return succeeded;
   5167 }
   5168 
   5169 static bool
   5170 initialize_uuid_name(srp_server_t *UNUSED server_state)
   5171 {
   5172     char *s;
   5173     uint64_t uuid = srp_random64();
   5174     static const char letters[] = "0123456789abcdefghijklmnopqrstuvwxyz";
   5175     static int letlen = sizeof(letters) - 1;
   5176     s = uuid_name;
   5177     *s++ = 'u'; // So that it always starts with a letter.
   5178     while (s < uuid_name + sizeof(uuid_name) - 1 && uuid != 0) {
   5179         *s++ = letters[uuid % letlen];
   5180         uuid /= letlen;
   5181     }
   5182     *s++ = 0;
   5183     return true;
   5184 }
   5185 
   5186 static bool
   5187 update_my_name(CFStringRef local_host_name_cfstr)
   5188 {
   5189     bool succeeded;
   5190     size_t name_length;
   5191 
   5192     if (local_host_name_cfstr == NULL) {
   5193         // If we are a thread device and not a stub router, make up a hostname for the remote server in case we need it.
   5194         char localhost[] = "localhost.";
   5195         name_length = sizeof(localhost);
   5196         memcpy(local_host_name, localhost, name_length);
   5197         memcpy(local_host_name_dot_local, localhost, name_length);
   5198         memcpy(my_name_buf, localhost, name_length);
   5199     } else {
   5200         // local host name to c string.
   5201         succeeded = CFStringGetCString(local_host_name_cfstr, local_host_name, sizeof(local_host_name),
   5202                                        kCFStringEncodingUTF8);
   5203         require_action_quiet(succeeded, exit, succeeded = false;
   5204                              ERROR("CFStringGetCString failed - local host name: " PRI_S_SRP,
   5205                                    CFStringGetCStringPtr(local_host_name_cfstr, kCFStringEncodingUTF8))
   5206             );
   5207         name_length = strlen(local_host_name);
   5208 
   5209         // Validate the local host name.
   5210         for (size_t i = 0; i < name_length; i++) {
   5211             char ch = local_host_name[i];
   5212             bool is_valid_char = isalnum(ch) || (ch == '-');
   5213             require_action_quiet(is_valid_char, exit, succeeded = false;
   5214                                  ERROR("invalid DNS name - name: " PUB_S_SRP, local_host_name));
   5215         }
   5216 
   5217         require_action_quiet(name_length + sizeof(DOT_HOME_NET_DOMAIN) <= sizeof(my_name_buf),
   5218                              exit,
   5219                              succeeded = false;
   5220                              ERROR("generated name too long: " PUB_S_SRP DOT_HOME_NET_DOMAIN, local_host_name));
   5221 
   5222         // Update existing local host name in my_name.
   5223         memcpy(my_name_buf, local_host_name, name_length);
   5224         memcpy(my_name_buf + name_length, DOT_HOME_NET_DOMAIN, sizeof(DOT_HOME_NET_DOMAIN));
   5225 
   5226         // Update existing local host name with .local suffix.
   5227         int bytes_written = snprintf(local_host_name_dot_local, sizeof(local_host_name_dot_local), "%s" DOT_LOCAL, local_host_name);
   5228         if (bytes_written < 0 || (size_t) bytes_written > sizeof(local_host_name_dot_local)) {
   5229            ERROR("snprintf failed - name length: %lu, max: %lu", strlen(local_host_name) + sizeof(DOT_LOCAL),
   5230                  sizeof(local_host_name_dot_local));
   5231            succeeded = false;
   5232            goto exit;
   5233         }
   5234     }
   5235     my_name = my_name_buf;
   5236 
   5237     succeeded = true;
   5238     INFO(PUB_S_SRP " my_name: " PRI_S_SRP ", local host name: " PRI_S_SRP, my_name == NULL ? "initialized" : "updated",
   5239          my_name, local_host_name_dot_local);
   5240 
   5241 exit:
   5242     return succeeded;
   5243 }
   5244 
   5245 // Gets called when name change event happens
   5246 static void
   5247 monitor_name_changes_callback(SCDynamicStoreRef store, CFArrayRef changed_keys, void *context)
   5248 {
   5249     bool succeeded;
   5250     CFStringRef local_host_name_cfstring = NULL;
   5251     dnssd_proxy_advertisements_t *advertisements = context;
   5252 
   5253     // Check if name changes.
   5254     CFRange range = {0, CFArrayGetCount(changed_keys)};
   5255     const bool host_name_changed = CFArrayContainsValue(changed_keys, range, sc_dynamic_store_key_host_name);
   5256     if (!host_name_changed) {
   5257         goto exit;
   5258     }
   5259 
   5260     // Get the new local host name.
   5261     local_host_name_cfstring = SCDynamicStoreCopyLocalHostName(store);
   5262     require_action_quiet(local_host_name_cfstring != NULL, exit, ERROR("failed to get updated local host name"));
   5263 
   5264     // Update the old my_name
   5265     succeeded = update_my_name(local_host_name_cfstring);
   5266     require_action_quiet(succeeded, exit, ERROR("failed to update my name"));
   5267 
   5268     // With the new local host name, update the served domains and hardwired response.
   5269     succeeded = served_domain_process_name_change();
   5270     require_action_quiet(succeeded, exit, ERROR("failed to process name change for served domains"));
   5271 
   5272     if (advertisements->txn != NULL) {
   5273         dns_wire_t wire;
   5274         dns_towire_state_t towire;
   5275         towire_init(&wire, &towire);
   5276         dns_full_name_to_wire(NULL, &towire, local_host_name_dot_local);
   5277 
   5278         DNSServiceErrorType err = DNSServiceUpdateRecord(advertisements->service_ref, advertisements->ns_record_ref, 0,
   5279             towire.p - wire.data, wire.data, 0);
   5280         if (err != kDNSServiceErr_NoError) {
   5281             ERROR("DNSServiceUpdateRecord failed to update NS record to new name - name: " PRI_S_SRP,
   5282                 local_host_name_dot_local);
   5283         }
   5284 
   5285         INFO("Updating record - new NS record rdata: " PRI_S_SRP, local_host_name_dot_local);
   5286     }
   5287 
   5288 exit:
   5289     if (local_host_name_cfstring != NULL) {
   5290         CFRelease(local_host_name_cfstring);
   5291     }
   5292     return;
   5293 }
   5294 
   5295 static bool
   5296 monitor_name_changes(dnssd_proxy_advertisements_t *advertisements)
   5297 {
   5298     bool succeeded;
   5299     SCDynamicStoreRef store = NULL;
   5300     const void *monitored_keys[1];
   5301     CFArrayRef monitored_keys_array = NULL;
   5302 
   5303     // Set the callback function for name change event.
   5304     store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("dnssd-proxy:watch for name change events"),
   5305                                  monitor_name_changes_callback, &advertisements->sc_context);
   5306     require_action_quiet(store != NULL, exit, succeeded = false; ERROR("failed to create SCDynamicStoreRef"));
   5307 
   5308     // Set the key to be monitored, which is host name
   5309     sc_dynamic_store_key_host_name = SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault);
   5310     require_action_quiet(sc_dynamic_store_key_host_name != NULL, exit, succeeded = false;
   5311         ERROR("failed to create SCDynamicStoreKey for host name"));
   5312 
   5313     monitored_keys[0] = sc_dynamic_store_key_host_name;
   5314     monitored_keys_array = CFArrayCreate(kCFAllocatorDefault, monitored_keys, countof(monitored_keys),
   5315         &kCFTypeArrayCallBacks);
   5316     require_action_quiet(monitored_keys_array != NULL, exit, succeeded = false;
   5317         ERROR("failed to create CFArrayRef for monitored keys"));
   5318 
   5319     succeeded = SCDynamicStoreSetNotificationKeys(store, monitored_keys_array, NULL);
   5320     require_action_quiet(succeeded, exit, ERROR("SCDynamicStoreSetNotificationKeys failed"));
   5321 
   5322     succeeded = SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue());
   5323     require_action_quiet(succeeded, exit, ERROR("SCDynamicStoreSetDispatchQueue failed"));
   5324 
   5325     succeeded = true;
   5326     INFO("Start to monitor local host name changes");
   5327 exit:
   5328     if (!succeeded) {
   5329         if (store != NULL) {
   5330             CFRelease(store);
   5331         }
   5332     }
   5333     if (monitored_keys_array != NULL) {
   5334         CFRelease(monitored_keys_array);
   5335     }
   5336     return succeeded;
   5337 }
   5338 
   5339 static bool
   5340 initialize_my_name_and_monitoring(srp_server_t *server_state)
   5341 {
   5342     bool succeeded;
   5343     CFStringRef local_host_name_cfstring = NULL;
   5344 
   5345     // Set notification from configd.
   5346     succeeded = monitor_name_changes(server_state->dnssd_proxy_advertisements);
   5347     require_action_quiet(succeeded, exit, ERROR("failed to monitor name changes"));
   5348 
   5349     // Get the initial local host name
   5350     local_host_name_cfstring = SCDynamicStoreCopyLocalHostName(NULL);
   5351     require_action_quiet(local_host_name != NULL, exit, succeeded = false; ERROR("failed to get local host name"));
   5352 
   5353     succeeded = update_my_name(local_host_name_cfstring);
   5354     require_action_quiet(succeeded, exit, ERROR("failed to update myname"));
   5355 
   5356 exit:
   5357     if (local_host_name_cfstring != NULL) {
   5358         CFRelease(local_host_name_cfstring);
   5359     }
   5360     return succeeded;
   5361 }
   5362 
   5363 #ifndef SRP_TEST_SERVER
   5364 static bool
   5365 configure_dnssd_proxy(void)
   5366 {
   5367     dnssd_proxy_udp_port= 53;
   5368     dnssd_proxy_tcp_port = 53;
   5369     dnssd_proxy_tls_port = 853;
   5370     return true;
   5371 }
   5372 #endif // SRP_TEST_SERVER
   5373 #endif // SRP_FEATURE_DYNAMIC_CONFIGURATION
   5374 
   5375 static bool
   5376 start_dnssd_proxy_listener(void)
   5377 {
   5378     bool succeeded;
   5379 
   5380 #if STUB_ROUTER
   5381 #ifndef NOT_HAVE_SA_LEN
   5382 #  define SA_LEN_INIT addr.sa.sa_len = sizeof(addr.sin6)
   5383 #else
   5384 #  define SA_LEN_INIT
   5385 #endif // NOT_HAVE_SA_LEN
   5386 #define INIT_ADDR_T(PORT)                       \
   5387         do {                                    \
   5388             memset(&addr, 0, sizeof(addr));     \
   5389             addr.sa.sa_family = AF_UNSPEC;      \
   5390             addr.sin6.sin6_port = htons(PORT);  \
   5391             SA_LEN_INIT;                        \
   5392         } while (false)
   5393 
   5394     addr_t addr;
   5395 
   5396     INIT_ADDR_T(dnssd_proxy_udp_port);
   5397     dnssd_proxy_listeners[dnssd_proxy_num_listeners] =
   5398         ioloop_listener_create(false, false, true, NULL, 0, &addr, NULL, "DNS over UDP", dns_proxy_input,
   5399                                NULL, NULL, NULL, NULL, NULL, 0, NULL);
   5400     require_action_quiet(dnssd_proxy_listeners[dnssd_proxy_num_listeners] != NULL, exit, succeeded = false;
   5401         ERROR("failed to start UDP listener - listener index: %d", dnssd_proxy_num_listeners));
   5402     dnssd_proxy_num_listeners++;
   5403 
   5404     INIT_ADDR_T(dnssd_proxy_tcp_port);
   5405     dnssd_proxy_listeners[dnssd_proxy_num_listeners] =
   5406         ioloop_listener_create(true, false, true, NULL, 0, &addr, NULL, "DNS over TCP", dns_proxy_input,
   5407                                NULL, NULL, NULL, NULL, NULL, 0, NULL);
   5408     require_action_quiet(dnssd_proxy_listeners[dnssd_proxy_num_listeners] != NULL, exit, succeeded = false;
   5409         ERROR("failed to start TCP listener - listener index: %d", dnssd_proxy_num_listeners));
   5410     dnssd_proxy_num_listeners++;
   5411 #endif // STUB_ROUTER
   5412 
   5413     dnssd_push_setup();
   5414 
   5415     for (int i = 0; i < dnssd_proxy_num_listeners; i++) {
   5416         INFO("listener started - name: " PUB_S_SRP, dnssd_proxy_listeners[i]->name);
   5417     }
   5418 
   5419     succeeded = true;
   5420     goto exit;
   5421 
   5422 exit:
   5423     return succeeded;
   5424 }
   5425 
   5426 #define ADVERTISEMENT_RETRY_TIMER 10 * MSEC_PER_SEC
   5427 
   5428 #if STUB_ROUTER
   5429 static void
   5430 advertisements_finalize(void *context)
   5431 {
   5432     dnssd_proxy_advertisements_t *advertisements_context = context;
   5433     advertisements_context->txn = NULL;
   5434 }
   5435 
   5436 static void
   5437 advertisements_failed(void *UNUSED context, int status)
   5438 {
   5439     ERROR("%d", status);
   5440 }
   5441 
   5442 static void
   5443 advertisements_callback(DNSServiceRef sd_ref, DNSRecordRef record_ref, DNSServiceFlags UNUSED flags,
   5444                         DNSServiceErrorType error, void *context)
   5445 {
   5446     dnssd_proxy_advertisements_t *advertisements_context = context;
   5447 
   5448     if (error == kDNSServiceErr_NoError) {
   5449         const char * const description = record_ref == advertisements_context->ns_record_ref ? "NS" : "PTR";
   5450         INFO("record registered successfully - registered: " PUB_S_SRP, description);
   5451     } else if (error == kDNSServiceErr_ServiceNotRunning) {
   5452         // The record is not being advertised because mDNSResponder stopped running for some reason (like crashes),
   5453         // in which case, we will stop the previous DNSService operation and start a new one 10s later.
   5454 
   5455         // Release the previous DNSServiceRef.
   5456         if (advertisements_context->service_ref != sd_ref) {
   5457             ERROR("Invalid DNSServiceRef - context->service_ref: %p, sd_ref: %p", advertisements_context->service_ref,
   5458                 sd_ref);
   5459         }
   5460         if (advertisements_context->txn != NULL) {
   5461             ioloop_dnssd_txn_cancel(advertisements_context->txn);
   5462             ioloop_dnssd_txn_release(advertisements_context->txn);
   5463             advertisements_context->txn = NULL;
   5464         }
   5465         advertisements_context->service_ref = NULL;
   5466 
   5467         // Restart the advertisement.
   5468         bool succeeded = start_timer_to_advertise(advertisements_context, NULL, ADVERTISEMENT_RETRY_TIMER);
   5469         if (!succeeded) {
   5470             ERROR("start_timer_to_advertise failed");
   5471         } else {
   5472             INFO("mDNSResponder stopped running, preparing to re-advertise the PTR and NS records");
   5473         }
   5474     } else {
   5475         ERROR("record not registered - error: %d", error);
   5476     }
   5477 }
   5478 
   5479 static void
   5480 advertise_dnssd_proxy_callback(void *NONNULL context)
   5481 {
   5482     DNSServiceErrorType err;
   5483     bool succeeded;
   5484     bool dns_service_initialized = false;
   5485     dns_wire_t wire;
   5486     dns_towire_state_t towire;
   5487     dnssd_proxy_advertisements_t *advertisement_context = context;
   5488     srp_server_t *server_state = advertisement_context->server_state;
   5489     const char *const domain_to_advertise = advertisement_context->domain_to_advertise;
   5490 
   5491     INFO("Start advertising lb._dns-sd._udp.local. PTR and openthread.thread.home.arpa.local NS records");
   5492 
   5493     // Create DNSServiceRef
   5494     err = DNSServiceCreateConnection(&advertisement_context->service_ref);
   5495     if (err != kDNSServiceErr_NoError) {
   5496         ERROR("DNSServiceCreateConnection failed");
   5497         succeeded = false;
   5498         goto exit;
   5499     }
   5500     dns_service_initialized = true;
   5501 
   5502     // Setup lb._dns-sd._udp.local. PTR openthread.thread.home.arpa.
   5503     towire_init(&wire, &towire);
   5504     dns_full_name_to_wire(NULL, &towire, domain_to_advertise);
   5505 
   5506     err = DNSServiceRegisterRecord(advertisement_context->service_ref, &advertisement_context->ptr_record_ref,
   5507                                    kDNSServiceFlagsShared, server_state->advertise_interface, AUTOMATIC_BROWSING_DOMAIN,
   5508                                    kDNSServiceType_PTR, kDNSServiceClass_IN, towire.p - wire.data, wire.data, 0,
   5509                                    advertisements_callback, advertisement_context);
   5510     if (err != kDNSServiceErr_NoError) {
   5511         ERROR("DNSServiceRegisterRecord failed - record: " PUB_S_SRP " PTR " PRI_S_SRP, AUTOMATIC_BROWSING_DOMAIN,
   5512               domain_to_advertise);
   5513         succeeded = false;
   5514         goto exit;
   5515     }
   5516 
   5517     // Setup openthread.thread.home.arpa. NS <local host name>.local.
   5518     towire_init(&wire, &towire);
   5519     dns_full_name_to_wire(NULL, &towire, local_host_name_dot_local);
   5520 
   5521     err = DNSServiceRegisterRecord(advertisement_context->service_ref, &advertisement_context->ns_record_ref,
   5522                                    kDNSServiceFlagsShared | kDNSServiceFlagsForceMulticast,
   5523                                    server_state->advertise_interface, domain_to_advertise, kDNSServiceType_NS,
   5524                                    kDNSServiceClass_IN, towire.p - wire.data, wire.data, 0,
   5525                                    advertisements_callback, advertisement_context);
   5526     if (err != kDNSServiceErr_NoError) {
   5527         ERROR("DNSServiceRegisterRecord failed - record: " PUB_S_SRP " NS " PRI_S_SRP, domain_to_advertise,
   5528             local_host_name_dot_local);
   5529         succeeded = false;
   5530         goto exit;
   5531     }
   5532 
   5533     // Start the running loop
   5534     advertisement_context->txn = ioloop_dnssd_txn_add(advertisement_context->service_ref, advertisement_context,
   5535                                                       advertisements_finalize, advertisements_failed);
   5536     if (advertisement_context->txn == NULL) {
   5537         ERROR("ioloop_dnssd_txn_add failed");
   5538         succeeded = false;
   5539         goto exit;
   5540     }
   5541 
   5542     INFO("Advertising records - " PUB_S_SRP " PTR " PRI_S_SRP ", " PRI_S_SRP " NS " PRI_S_SRP,
   5543          AUTOMATIC_BROWSING_DOMAIN, domain_to_advertise, domain_to_advertise, local_host_name_dot_local);
   5544     succeeded = true;
   5545 exit:
   5546     if (!succeeded) {
   5547         if (dns_service_initialized) {
   5548             DNSServiceRefDeallocate(advertisement_context->service_ref);
   5549             advertisement_context->service_ref = NULL;
   5550         }
   5551         if (err == kDNSServiceErr_ServiceNotRunning) {
   5552             ERROR("mDNSResponder is not running yet when trying to advertise PTR and NS records, try again 10s later");
   5553             // advertise_dnssd_proxy_callback will be called again 10s later, since we did not cancel the timer.
   5554         } else {
   5555             // Other kDNSServiceErr, should be impossible. If it happens, give up advertising the records.
   5556             ioloop_cancel_wake_event(advertisement_context->wakeup_timer);
   5557         }
   5558     } else {
   5559         // Since we registered successfully, there is no need to trigger another timer to set the records.
   5560         // Stop the timer.
   5561         ioloop_cancel_wake_event(advertisement_context->wakeup_timer);
   5562     }
   5563 }
   5564 
   5565 static bool
   5566 start_timer_to_advertise(dnssd_proxy_advertisements_t *NONNULL context,
   5567     const char *const NULLABLE domain_to_advertise, const uint32_t interval)
   5568 {
   5569     bool succeeded;
   5570 
   5571     // Only create timer once.
   5572     if (context->wakeup_timer == NULL) {
   5573         context->wakeup_timer = ioloop_wakeup_create();
   5574         if (context->wakeup_timer == NULL) {
   5575             succeeded = false;
   5576             goto exit;
   5577         }
   5578     }
   5579 
   5580     // Only copy advertised domain once.
   5581     if (context->domain_to_advertise == NULL) {
   5582         if (domain_to_advertise == NULL) {
   5583             succeeded = false;
   5584             goto exit;
   5585         }
   5586 
   5587         context->domain_to_advertise = strdup(domain_to_advertise);
   5588         if (context->domain_to_advertise == NULL) {
   5589             succeeded = false;
   5590             goto exit;
   5591         }
   5592     }
   5593 
   5594     // Start the timer, finalize callback is not necessary here because the context should always be available.
   5595     succeeded = ioloop_add_wake_event(context->wakeup_timer, context, advertise_dnssd_proxy_callback, NULL, interval);
   5596     if (!succeeded) {
   5597         goto exit;
   5598     }
   5599 
   5600     succeeded = true;
   5601 exit:
   5602     if (!succeeded) {
   5603         if (context->domain_to_advertise != NULL) {
   5604             free(context->domain_to_advertise);
   5605             context->domain_to_advertise = NULL;
   5606         }
   5607         if (context->wakeup_timer != NULL) {
   5608             ioloop_wakeup_release(context->wakeup_timer);
   5609             context->wakeup_timer = NULL;
   5610         }
   5611     }
   5612     return succeeded;
   5613 }
   5614 
   5615 #if SRP_FEATURE_DISCOVERY_PROXY_SERVER
   5616 
   5617 static bool
   5618 start_timer_to_advertise_dnssd_dp_proxy(dnssd_dp_proxy_advertisements_t *context, uint32_t interval);
   5619 
   5620 static void
   5621 dp_advertisements_finalize(void *const context)
   5622 {
   5623     dnssd_dp_proxy_advertisements_t *advertisements_context = context;
   5624     advertisements_context->txn = NULL;
   5625 }
   5626 
   5627 static void
   5628 dp_advertisements_failed(void *const UNUSED context, const int status)
   5629 {
   5630     ERROR("push service advertisement failed  -- error: %d", status);
   5631 }
   5632 
   5633 static void
   5634 dp_advertisements_callback(const DNSServiceRef UNUSED sd_ref, const DNSServiceFlags UNUSED flags,
   5635                            const DNSServiceErrorType error, const char *const name, const char *const reg_type,
   5636                            const char *const domain, void *const context)
   5637 {
   5638     dnssd_dp_proxy_advertisements_t *const ads_ctx = context;
   5639     if (error == kDNSServiceErr_NoError) {
   5640         INFO("Push service registered successfully -- %s.%s%s", name, reg_type, domain);
   5641     } else if (error == kDNSServiceErr_ServiceNotRunning) {
   5642         if (ads_ctx->txn != NULL) {
   5643             ioloop_dnssd_txn_cancel(ads_ctx->txn);
   5644             ioloop_dnssd_txn_forget(&ads_ctx->txn);
   5645         }
   5646         ads_ctx->service_ref = NULL;
   5647 
   5648         const bool succeeded = start_timer_to_advertise_dnssd_dp_proxy(ads_ctx, ADVERTISEMENT_RETRY_TIMER);
   5649         if (!succeeded) {
   5650             ERROR("start_timer_to_advertise_dnssd_dp_proxy failed");
   5651         } else {
   5652             INFO("mDNSResponder stopped running, preparing to re-advertise DNS push service");
   5653         }
   5654     } else {
   5655         ERROR("Push service not registered -- error: %d", error);
   5656     }
   5657 }
   5658 
   5659 static void
   5660 advertise_dnssd_dp_proxy_callback(void *const context)
   5661 {
   5662     DNSServiceRef service_ref = NULL;
   5663     dnssd_txn_t *txn = NULL;
   5664     dnssd_dp_proxy_advertisements_t *const advertisement_context = context;
   5665     srp_server_t *const server_state = advertisement_context->server_state;
   5666     int bytes_written = 0;
   5667 
   5668     // Construct ,_local,_openthread#thread#home#arpa
   5669     const char *domains_support_push[] = {
   5670         DOT_LOCAL_DOMAIN,
   5671         THREAD_BROWSING_DOMAIN,
   5672     };
   5673     char subtype_domains[256];
   5674     size_t current_len = 0;
   5675     for (size_t i = 0; i < countof(domains_support_push); i++) {
   5676         const char *const domain_supports_push = domains_support_push[i];
   5677         const size_t len = strlen(domain_supports_push);
   5678         char subtype_domain[128];
   5679         // Convert domain name like `_openthread.thread.home.arpa` to `_openthread#thread#home#arpa`.
   5680         require_quiet(len < sizeof(subtype_domain), exit);
   5681         for (size_t j = 0; j < len + 1; j++) {
   5682             if (domain_supports_push[j] == '.') {
   5683                 subtype_domain[j] = '#';
   5684             } else {
   5685                 subtype_domain[j] = domain_supports_push[j];
   5686             }
   5687         }
   5688         // Remove the trailing '#'.
   5689         if (subtype_domain[len - 1] == '#') {
   5690             subtype_domain[len - 1] = '\0';
   5691         }
   5692 
   5693         bytes_written = snprintf(subtype_domains + current_len, sizeof(subtype_domains) - current_len, ",_%s",
   5694                                  subtype_domain);
   5695         require_quiet((bytes_written > 0) && ((size_t)bytes_written < (sizeof(subtype_domains) - current_len)), exit);
   5696         current_len += bytes_written;
   5697     }
   5698 
   5699     // Construct _dnssd-dp._tcp,_local,_openthread#thread#home#arpa with subtype.
   5700     char reg_type[128];
   5701     bytes_written = snprintf(reg_type, sizeof(reg_type), "_dnssd-dp._tcp%s", subtype_domains);
   5702     require_quiet((bytes_written > 0) && ((size_t)bytes_written < sizeof(reg_type)), exit);
   5703 
   5704     // Construct service instance name like: p128-undulw2d1vktd1
   5705     const uint8_t priority = 128;
   5706     const char * const random_identifier = uuid_name;
   5707     char name[128];
   5708     bytes_written = snprintf(name, sizeof(name), "p%03d-%s", priority, random_identifier);
   5709     require_quiet((bytes_written > 0) && ((size_t)bytes_written < sizeof(name)), exit);
   5710 
   5711     const uint16_t dp_port = dnssd_proxy_tls_port;
   5712 
   5713     // The registered PTRs will be like:
   5714     // _openthread#thread#home#arpa._sub._dnssd-dp._tcp.local   PTR p128-undulw2d1vktd1._dnssd-dp._tcp.local
   5715     // _local._sub._dnssd-dp._tcp.local                         PTR p128-undulw2d1vktd1._dnssd-dp._tcp.local
   5716     const DNSServiceErrorType dnsssd_err = DNSServiceRegister(&service_ref, 0, server_state->advertise_interface, name,
   5717         reg_type, DOT_LOCAL_DOMAIN, NULL, htons(dp_port), 0, NULL, dp_advertisements_callback, context);
   5718     require_action_quiet(dnsssd_err == kDNSServiceErr_NoError, exit,
   5719         ERROR("DNSServiceRegisterRecord failed -- error: %d", dnsssd_err));
   5720 
   5721     txn = ioloop_dnssd_txn_add(service_ref, advertisement_context, dp_advertisements_finalize,
   5722                                dp_advertisements_failed);
   5723     require_quiet(txn != NULL, exit);
   5724 
   5725     advertisement_context->service_ref = service_ref;
   5726     service_ref = NULL;
   5727     advertisement_context->txn = txn;
   5728     txn = NULL;
   5729     INFO("Advertising push discovery service -- reg_type: %s.%s, service instance name: %s._dnssd-dp._tcp.%s",
   5730          reg_type, DOT_LOCAL_DOMAIN, name, DOT_LOCAL_DOMAIN);
   5731 
   5732 exit:
   5733     DNSServiceRefSourceForget(&service_ref);
   5734     if (txn != NULL) {
   5735         ioloop_dnssd_txn_cancel(txn);
   5736         ioloop_dnssd_txn_forget(&txn);
   5737     }
   5738 }
   5739 
   5740 static bool
   5741 start_timer_to_advertise_dnssd_dp_proxy(dnssd_dp_proxy_advertisements_t *const context, const uint32_t interval)
   5742 {
   5743     bool succeeded;
   5744     wakeup_t *wakeup_timer = context->wakeup_timer;
   5745 
   5746     if (wakeup_timer == NULL) {
   5747         wakeup_timer = ioloop_wakeup_create();
   5748     } else {
   5749         ioloop_wakeup_retain(wakeup_timer);
   5750     }
   5751     require_action_quiet(wakeup_timer != NULL, exit, succeeded = false);
   5752 
   5753     succeeded = ioloop_add_wake_event(wakeup_timer, context, advertise_dnssd_dp_proxy_callback, NULL, interval);
   5754     require_quiet(succeeded, exit);
   5755 
   5756     if (context->wakeup_timer == NULL) {
   5757         context->wakeup_timer = wakeup_timer;
   5758         wakeup_timer = NULL;
   5759     }
   5760 
   5761 exit:
   5762     ioloop_wakeup_forget(&wakeup_timer);
   5763     return succeeded;
   5764 }
   5765 
   5766 static bool
   5767 advertise_dnssd_dp_proxy(srp_server_t *const server_state)
   5768 {
   5769     return start_timer_to_advertise_dnssd_dp_proxy(server_state->dnssd_dp_proxy_advertisements,
   5770         ADVERTISEMENT_RETRY_TIMER);
   5771 }
   5772 
   5773 static bool
   5774 is_eligible_to_provide_push_discovery_service(void)
   5775 {
   5776     return true;
   5777 }
   5778 
   5779 #endif // SRP_FEATURE_DISCOVERY_PROXY_SERVER
   5780 
   5781 #endif // STUB_ROUTER
   5782 
   5783 #if SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY
   5784 #  if SRP_FEATURE_DYNAMIC_CONFIGURATION
   5785 static bool
   5786 served_domain_init(srp_server_t *server_state)
   5787 {
   5788     bool succeeded;
   5789     served_domain_t *my_name_served_domain = NULL;
   5790     served_domain_t *ipv6 = NULL;
   5791     served_domain_t *ipv4 = NULL;
   5792     served_domain_t *thread_served_domain = NULL;
   5793     served_domain_t *default_service_arpa_domain = NULL;
   5794 #if SRP_FEATURE_LOCAL_DISCOVERY
   5795     served_domain_t *dot_local_domain = NULL;
   5796 #endif
   5797 
   5798     // <local host name>.home.arpa.
   5799     my_name_served_domain = new_served_domain(NULL, my_name);
   5800     require_action_quiet(my_name_served_domain != NULL, exit, succeeded = false;
   5801         ERROR("failed to create new served domain - domain name: " PUB_S_SRP, my_name));
   5802 
   5803 #if STUB_ROUTER
   5804     if (server_state->stub_router_enabled) {
   5805         // ip6.arpa.
   5806         // in-addr.arpa.
   5807         ipv6 = new_served_domain(NULL, IPV6_REVERSE_LOOKUP_DOMAIN);
   5808         ipv4 = new_served_domain(NULL, IPV4_REVERSE_LOOKUP_DOMAIN);
   5809         require_action_quiet(ipv6 != NULL && ipv4 != NULL, exit, succeeded = false;
   5810                              ERROR("failed to create new served domain for reverse look up -  domain name: " PUB_S_SRP ", " PUB_S_SRP,
   5811                                    IPV6_REVERSE_LOOKUP_DOMAIN, IPV4_REVERSE_LOOKUP_DOMAIN)
   5812             );
   5813     }
   5814 #else
   5815     (void)server_state;
   5816 #endif
   5817 
   5818     // THREAD_BROWSING_DOMAIN
   5819     // It will be served by kDNSServiceInterfaceIndexLocalOnly, which is a pseudo interface.
   5820     thread_served_domain = add_new_served_domain_with_interface(LOCAL_ONLY_PSEUDO_INTERFACE, NULL, NULL);
   5821     require_action_quiet(thread_served_domain != NULL, exit, succeeded = false);
   5822     bool hardwired_set = dnssd_hardwired_setup_for_served_domain(thread_served_domain);
   5823     require_action_quiet(hardwired_set, exit, succeeded = false);
   5824 
   5825     // default.service.arpa
   5826     // For Thread 1.3.0, default.service.arpa has to return all locally-discoverable services
   5827     default_service_arpa_domain = add_new_served_domain_with_interface(ALL_LOCALS_PSEUDO_INTERFACE, NULL, NULL);
   5828     require_action_quiet(default_service_arpa_domain != NULL, exit, succeeded = false);
   5829     hardwired_set = dnssd_hardwired_setup_for_served_domain(default_service_arpa_domain);
   5830     require_action_quiet(hardwired_set, exit, succeeded = false);
   5831 
   5832 #if SRP_FEATURE_LOCAL_DISCOVERY
   5833     // local
   5834     // discovery proxy for the infrastructure interface
   5835     dot_local_domain = add_new_served_domain_with_interface(INFRASTRUCTURE_PSEUDO_INTERFACE, NULL, NULL);
   5836     require_action_quiet(dot_local_domain != NULL, exit, succeeded = false);
   5837     hardwired_set = dnssd_hardwired_setup_for_served_domain(dot_local_domain);
   5838     require_action_quiet(hardwired_set, exit, succeeded = false);
   5839 #endif
   5840 
   5841     succeeded = true;
   5842 exit:
   5843     if (!succeeded) {
   5844         if (thread_served_domain != NULL) {
   5845             delete_served_domain(thread_served_domain);
   5846         }
   5847         if (default_service_arpa_domain != NULL) {
   5848             delete_served_domain(default_service_arpa_domain);
   5849         }
   5850 #if SRP_FEATURE_LOCAL_DISCOVERY
   5851         if (dot_local_domain != NULL) {
   5852             delete_served_domain(dot_local_domain);
   5853         }
   5854 #endif
   5855         if (ipv4 != NULL) {
   5856             delete_served_domain(ipv4);
   5857         }
   5858         if (ipv6 != NULL) {
   5859             delete_served_domain(ipv6);
   5860         }
   5861         if (my_name_served_domain != NULL) {
   5862             delete_served_domain(my_name_served_domain);
   5863         }
   5864     }
   5865     return succeeded;
   5866 }
   5867 #  endif // SRP_FEATURE_DYNAMIC_CONFIGURATION
   5868 #endif // SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY
   5869 
   5870 bool
   5871 init_dnssd_proxy(srp_server_t *server_state)
   5872 {
   5873     bool succeeded;
   5874     dnssd_proxy_advertisements_t *advertisements = server_state->dnssd_proxy_advertisements;
   5875     if (advertisements == NULL) {
   5876         advertisements = calloc(1, sizeof(*advertisements));
   5877         require_action_quiet(advertisements != NULL, exit,
   5878                              succeeded = false;
   5879                              ERROR("no memory for advertisements"));
   5880         server_state->dnssd_proxy_advertisements = advertisements;
   5881         advertisements->server_state = server_state;
   5882         advertisements->sc_context.info = advertisements;
   5883     }
   5884 
   5885 #if STUB_ROUTER
   5886 #if SRP_FEATURE_DISCOVERY_PROXY_SERVER
   5887     if (is_eligible_to_provide_push_discovery_service()) {
   5888         dnssd_dp_proxy_advertisements_t *dp_ads = server_state->dnssd_dp_proxy_advertisements;
   5889         if (dp_ads == NULL) {
   5890             dp_ads = calloc(1, sizeof(*dp_ads));
   5891             require_action_quiet(dp_ads != NULL, exit,
   5892                                  succeeded = false; ERROR("no memory for push discovery service advertisements"));
   5893             server_state->dnssd_dp_proxy_advertisements = dp_ads;
   5894             dp_ads->server_state = server_state;
   5895         }
   5896     }
   5897 #endif // SRP_FEATURE_DISCOVERY_PROXY_SERVER
   5898 #endif // STUB_ROUTER
   5899 
   5900 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
   5901     succeeded = configure_dnssd_proxy();
   5902     require_action_quiet(succeeded, exit, ERROR("configure_dnssd_proxy failed"));
   5903 
   5904 
   5905     succeeded = initialize_my_name_and_monitoring(server_state);
   5906 
   5907     require_action_quiet(succeeded, exit, ERROR("initialize_my_name_and_monitoring failed"));
   5908     succeeded = initialize_uuid_name(server_state);
   5909     require_action_quiet(succeeded, exit, ERROR("initialize_uuid_name failed"));
   5910 #if STUB_ROUTER
   5911     if (!server_state->stub_router_enabled) {
   5912         served_domain_process_name_change();
   5913     }
   5914 #endif
   5915 
   5916 #else // SRP_FEATURE_DYNAMIC_CONFIGURATION
   5917     // Read the config file
   5918     succeeded = config_parse(NULL, "/etc/dnssd-proxy.cf", dp_verbs, NUMCFVERBS);
   5919     require_action_quiet(succeeded,
   5920                          exit,);
   5921 
   5922     // Insist that we have at least one address we're listening on.
   5923     succeeded = !(num_listen_addrs == 0 && num_publish_addrs == 0);
   5924     require_action_quiet(succeeded,
   5925                          exit,
   5926                          ERROR("Please configure at least one my-ipv4-addr and/or one my-ipv6-addr."));
   5927 
   5928     ioloop_map_interface_addresses(server_state, NULL, &served_domains, dnssd_proxy_ifaddr_callback);
   5929 
   5930     // Set up hardwired answers
   5931     dnssd_hardwired_setup();
   5932 #endif // SRP_FEATURE_DYNAMIC_CONFIGURATION
   5933 
   5934     succeeded = srp_tls_init();
   5935     require_action_quiet(succeeded, exit, ERROR("srp_tls_init failed."));
   5936 
   5937 #if !SRP_FEATURE_CAN_GENERATE_TLS_CERT
   5938     // The tls_fail flag allows us to run the proxy in such a way that TLS connections will fail.
   5939     // This is never what you want in production, but is useful for testing.
   5940     if (!tls_fail) {
   5941         if (access(tls_key_filename, R_OK) < 0) {
   5942             keyprogram_start(GENKEY_PROGRAM, keyfile_finished_callback,
   5943                              "type=rsa", NULL, "rsa_keysize=4096", NULL, "filename", tls_key_filename, NULL);
   5944         } else if (access(tls_cert_filename, R_OK) < 0) {
   5945             keyfile_finished_callback(NULL, 0, NULL);
   5946         }
   5947         require_action_quiet(access(tls_key_filename, R_OK) >= 0, exit, ERROR("failed to create tls listener key."));
   5948         require_action_quiet(access(tls_cert_filename, R_OK) >= 0, exit, ERROR("failed to create tls listener cert."));
   5949 
   5950         require_action_quiet(srp_tls_server_init(NULL, tls_cert_filename, tls_key_filename),
   5951                              exit, ERROR("srp_tls_server_init failed."));
   5952         require_action_quiet(srp_tls_client_init(), exit, ERROR("srp_tls_client_init failed."));
   5953     }
   5954 #endif
   5955 
   5956     succeeded = start_dnssd_proxy_listener();
   5957     require_action_quiet(succeeded, exit, ERROR("start_dnssd_proxy_listener failed"));
   5958 
   5959 #if STUB_ROUTER
   5960     if (server_state->stub_router_enabled) {
   5961     #if SRP_FEATURE_DISCOVERY_PROXY_SERVER
   5962         if (server_state->dnssd_dp_proxy_advertisements != NULL) {
   5963             succeeded = advertise_dnssd_dp_proxy(server_state);
   5964             require_action_quiet(succeeded, exit, ERROR("advertise_dnssd_dp_proxy failed"));
   5965         }
   5966     #endif
   5967     }
   5968 #endif
   5969 
   5970 #if SRP_FEATURE_DYNAMIC_CONFIGURATION
   5971     succeeded = served_domain_init(server_state);
   5972 #endif
   5973 
   5974 exit:
   5975     return succeeded;
   5976 }
   5977 
   5978 #if !SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY
   5979 int
   5980 main(int argc, char **argv)
   5981 {
   5982     int i;
   5983     bool log_stderr = false;
   5984 
   5985     dnssd_proxy_udp_port = dnssd_proxy_tcp_port = 53;
   5986     dnssd_proxy_tls_port = 853;
   5987 
   5988     // Parse command line arguments
   5989     for (i = 1; i < argc; i++) {
   5990         if (!strcmp(argv[i], "--tls-fail")) {
   5991             tls_fail = true;
   5992         } else if (!strcmp(argv[i], "--log-stderr")) {
   5993             log_stderr = true;
   5994         } else {
   5995             return usage(argv[0]);
   5996         }
   5997     }
   5998 
   5999     OPENLOG("dnssd-proxy", log_stderr);
   6000 
   6001     if (!ioloop_init()) {
   6002         return 1;
   6003     }
   6004 
   6005     init_dnssd_proxy();
   6006 
   6007     ioloop();
   6008 }
   6009 #endif // #if !SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY
   6010 
   6011 #endif // (SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY) || (!defined(BUILD_SRP_MDNS_PROXY) || (BUILD_SRP_MDNS_PROXY == 0))
   6012 
   6013 // Local Variables:
   6014 // mode: C
   6015 // tab-width: 4
   6016 // c-file-style: "bsd"
   6017 // c-basic-offset: 4
   6018 // fill-column: 108
   6019 // indent-tabs-mode: nil
   6020 // End:
   6021