1 /*
2  * Copyright (c) 2003-2020 Apple Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #if defined(_WIN32)
18 #include <process.h>
19 #define usleep(X) Sleep(((X)+999)/1000)
20 #else
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
25 #include <sys/time.h>
26 #include <sys/resource.h>
27 #endif
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 
32 #include "mDNSEmbeddedAPI.h"
33 #include "DNSCommon.h"
34 #include "uDNS.h"
35 #include "uds_daemon.h"
36 #include "dns_sd_internal.h"
37 
38 // Apple-specific functionality, not required for other platforms
39 #if APPLE_OSX_mDNSResponder
40 #include <os/log.h>
41 #include <sys/ucred.h>
42 #ifndef PID_FILE
43 #define NO_PID_FILE // We need to signal that this platform has no PID file, and not just that we are taking the default
44 #endif
45 #endif
46 
47 #ifdef LOCAL_PEEREPID
48 #include <sys/un.h>         // for LOCAL_PEEREPID
49 #include <sys/socket.h>     // for getsockopt
50 #include <sys/proc_info.h>  // for struct proc_bsdshortinfo
51 #include <libproc.h>        // for proc_pidinfo()
52 #endif //LOCAL_PEEREPID
53 
54 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
55 #include "D2D.h"
56 #endif
57 
58 #if APPLE_OSX_mDNSResponder
59 #include "BLE.h"
60 #endif
61 
62 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
63 #include "mDNSMacOSX.h"
64 #include <os/feature_private.h>
65 #endif
66 
67 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
68 #include <bsm/libbsm.h>
69 #endif
70 
71 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
72 #include "QuerierSupport.h"
73 #endif
74 
75 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) && MDNSRESPONDER_SUPPORTS(APPLE, IPC_TLV)
76 #include "mdns_tlv.h"
77 #endif
78 
79 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
80 #include "dnssec_v2.h"
81 #endif
82 
83 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
84 #include "dnssd_server.h"
85 #endif
86 
87 // User IDs 0-500 are system-wide processes, not actual users in the usual sense
88 // User IDs for real user accounts start at 501 and count up from there
89 #define SystemUID(X) ((X) <= 500)
90 
91 // ***************************************************************************
92 #if COMPILER_LIKES_PRAGMA_MARK
93 #pragma mark -
94 #pragma mark - Globals
95 #endif
96 
97 // globals
98 mDNSexport mDNS mDNSStorage;
99 mDNSexport const char ProgramName[] = "mDNSResponder";
100 
101 #if defined(USE_TCP_LOOPBACK)
102 static char* boundPath = NULL;
103 #else
104 static char* boundPath = MDNS_UDS_SERVERPATH;
105 #endif
106 #if DEBUG
107 #define MDNS_UDS_SERVERPATH_DEBUG "/var/tmp/mDNSResponder"
108 #endif
109 static dnssd_sock_t listenfd = dnssd_InvalidSocket;
110 static request_state *all_requests = NULL;
111 #ifdef LOCAL_PEEREPID
112 struct proc_bsdshortinfo proc;
113 #endif //LOCAL_PEEREPID
114 mDNSlocal void set_peer_pid(request_state *request);
115 mDNSlocal void LogMcastClientInfo(request_state *req);
116 mDNSlocal void GetMcastClients(request_state *req);
117 static mDNSu32 mcount;     // tracks the current active mcast operations for McastLogging
118 static mDNSu32 i_mcount;   // sets mcount when McastLogging is enabled(PROF signal is sent)
119 static mDNSu32 n_mrecords; // tracks the current active mcast records for McastLogging
120 static mDNSu32 n_mquests;  // tracks the current active mcast questions for McastLogging
121 
122 
123 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
124 mDNSu32 curr_num_regservices = 0;
125 mDNSu32 max_num_regservices = 0;
126 #endif
127 
128 // Note asymmetry here between registration and browsing.
129 // For service registrations we only automatically register in domains that explicitly appear in local configuration data
130 // (so AutoRegistrationDomains could equally well be called SCPrefRegDomains)
131 // For service browsing we also learn automatic browsing domains from the network, so for that case we have:
132 // 1. SCPrefBrowseDomains (local configuration data)
133 // 2. LocalDomainEnumRecords (locally-generated local-only PTR records -- equivalent to slElem->AuthRecs in uDNS.c)
134 // 3. AutoBrowseDomains, which is populated by tracking add/rmv events in AutomaticBrowseDomainChange, the callback function for our mDNS_GetDomains call.
135 // By creating and removing our own LocalDomainEnumRecords, we trigger AutomaticBrowseDomainChange callbacks just like domains learned from the network would.
136 
137 mDNSexport DNameListElem *AutoRegistrationDomains;  // Domains where we automatically register for empty-string registrations
138 
139 static DNameListElem *SCPrefBrowseDomains;          // List of automatic browsing domains read from SCPreferences for "empty string" browsing
140 static ARListElem    *LocalDomainEnumRecords;       // List of locally-generated PTR records to augment those we learn from the network
141 mDNSexport DNameListElem *AutoBrowseDomains;        // List created from those local-only PTR records plus records we get from the network
142 
143 #define MSG_PAD_BYTES 5     // pad message buffer (read from client) with n zero'd bytes to guarantee
144                             // n get_string() calls w/o buffer overrun
145 // initialization, setup/teardown functions
146 
147 // If a platform specifies its own PID file name, we use that
148 #ifndef PID_FILE
149 #define PID_FILE "/var/run/mDNSResponder.pid"
150 #endif
151 
152 // ***************************************************************************
153 #if COMPILER_LIKES_PRAGMA_MARK
154 #pragma mark -
155 #pragma mark - General Utility Functions
156 #endif
157 
GetNewRequestID(void)158 mDNSlocal mDNSu32 GetNewRequestID(void)
159 {
160 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
161     return dnssd_server_get_new_request_id();
162 #else
163     static mDNSu32 s_last_id = 0;
164     return ++s_last_id;
165 #endif
166 }
167 
FatalError(char * errmsg)168 mDNSlocal void FatalError(char *errmsg)
169 {
170     LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno));
171     abort();
172 }
173 
dnssd_htonl(mDNSu32 l)174 mDNSlocal mDNSu32 dnssd_htonl(mDNSu32 l)
175 {
176     mDNSu32 ret;
177     char *data = (char*) &ret;
178     put_uint32(l, &data);
179     return ret;
180 }
181 
182 // hack to search-replace perror's to LogMsg's
my_perror(char * errmsg)183 mDNSlocal void my_perror(char *errmsg)
184 {
185     LogMsg("%s: %d (%s)", errmsg, dnssd_errno, dnssd_strerror(dnssd_errno));
186 }
187 
188 // Throttled version of my_perror: Logs once every 250 msgs
my_throttled_perror(char * err_msg)189 mDNSlocal void my_throttled_perror(char *err_msg)
190 {
191     static int uds_throttle_count = 0;
192     if ((uds_throttle_count++ % 250) == 0)
193         my_perror(err_msg);
194 }
195 
196 // LogMcastQuestion/LogMcastQ should be called after the DNSQuestion struct is initialized(especially for q->TargetQID)
197 // Hence all calls are made after mDNS_StartQuery()/mDNS_StopQuery()/mDNS_StopBrowse() is called.
LogMcastQuestion(const DNSQuestion * const q,request_state * req,q_state status)198 mDNSlocal void LogMcastQuestion(const DNSQuestion *const q, request_state *req, q_state status)
199 {
200     if (mDNSOpaque16IsZero(q->TargetQID)) // Check for Mcast Query
201     {
202         mDNSBool mflag = mDNSfalse;
203         if (status == q_start)
204         {
205             if (++mcount == 1)
206                 mflag = mDNStrue;
207         }
208         else
209         {
210             mcount--;
211         }
212         LogMcast("%s: %##s  (%s) (%s)  Client(%d)[%s]", status ? "+Question" : "-Question", q->qname.c, DNSTypeName(q->qtype),
213                  q->InterfaceID == mDNSInterface_LocalOnly ? "lo" :
214                  q->InterfaceID == mDNSInterface_P2P ? "p2p" :
215                  q->InterfaceID == mDNSInterface_BLE ? "BLE" :
216                  q->InterfaceID == mDNSInterface_Any ? "any" : InterfaceNameForID(&mDNSStorage, q->InterfaceID),
217                  req->process_id, req->pid_name);
218         LogMcastStateInfo(mflag, mDNSfalse, mDNSfalse);
219     }
220     return;
221 }
222 
223 // LogMcastService/LogMcastS should be called after the AuthRecord struct is initialized
224 // Hence all calls are made after mDNS_Register()/ just before mDNS_Deregister()
LogMcastService(const AuthRecord * const ar,request_state * req,reg_state status)225 mDNSlocal void LogMcastService(const AuthRecord *const ar, request_state *req, reg_state status)
226 {
227     if (!AuthRecord_uDNS(ar)) // Check for Mcast Service
228     {
229         mDNSBool mflag = mDNSfalse;
230         if (status == reg_start)
231         {
232             if (++mcount == 1)
233                 mflag = mDNStrue;
234         }
235         else
236         {
237             mcount--;
238         }
239         LogMcast("%s: %##s  (%s)  (%s)  Client(%d)[%s]", status ? "+Service" : "-Service", ar->resrec.name->c, DNSTypeName(ar->resrec.rrtype),
240                  ar->resrec.InterfaceID == mDNSInterface_LocalOnly ? "lo" :
241                  ar->resrec.InterfaceID == mDNSInterface_P2P ? "p2p" :
242                  ar->resrec.InterfaceID == mDNSInterface_BLE ? "BLE" :
243                  ar->resrec.InterfaceID == mDNSInterface_Any ? "all" : InterfaceNameForID(&mDNSStorage, ar->resrec.InterfaceID),
244                  req->process_id, req->pid_name);
245         LogMcastStateInfo(mflag, mDNSfalse, mDNSfalse);
246     }
247     return;
248 }
249 
250 // For complete Mcast State Log, pass mDNStrue to mstatelog in LogMcastStateInfo()
LogMcastStateInfo(mDNSBool mflag,mDNSBool start,mDNSBool mstatelog)251 mDNSexport void LogMcastStateInfo(mDNSBool mflag, mDNSBool start, mDNSBool mstatelog)
252 {
253     mDNS *const m = &mDNSStorage;
254     if (!mstatelog)
255     {
256         if (!all_requests)
257         {
258             LogMcastNoIdent("<None>");
259         }
260         else
261         {
262             request_state *req, *r;
263             for (req = all_requests; req; req=req->next)
264             {
265                 if (req->primary) // If this is a subbordinate operation, check that the parent is in the list
266                 {
267                     for (r = all_requests; r && r != req; r=r->next)
268                         if (r == req->primary)
269                             goto foundpar;
270                 }
271                 // For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
272                 GetMcastClients(req);
273     foundpar:;
274             }
275             LogMcastNoIdent("--- MCAST RECORDS COUNT[%d] MCAST QUESTIONS COUNT[%d] ---", n_mrecords, n_mquests);
276             n_mrecords = n_mquests = 0; // Reset the values
277         }
278     }
279     else
280     {
281         static mDNSu32 i_mpktnum;
282         i_mcount = 0;
283         if (start)
284             mcount = 0;
285         // mcount is initialized to 0 when the PROF signal is sent since mcount could have
286         // wrong value if MulticastLogging is disabled and then re-enabled
287         LogMcastNoIdent("--- START MCAST STATE LOG ---");
288         if (!all_requests)
289         {
290             mcount = 0;
291             LogMcastNoIdent("<None>");
292         }
293         else
294         {
295             request_state *req, *r;
296             for (req = all_requests; req; req=req->next)
297             {
298                 if (req->primary) // If this is a subbordinate operation, check that the parent is in the list
299                 {
300                     for (r = all_requests; r && r != req; r=r->next)
301                         if (r == req->primary)
302                             goto foundparent;
303                     LogMcastNoIdent("%3d: Orphan operation; parent not found in request list", req->sd);
304                 }
305                 // For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
306                 LogMcastClientInfo(req);
307     foundparent:;
308             }
309             if(!mcount) // To initially set mcount
310                 mcount = i_mcount;
311         }
312         if (mcount == 0)
313         {
314             i_mpktnum = m->MPktNum;
315             LogMcastNoIdent("--- MCOUNT[%d]: IMPKTNUM[%d] ---", mcount, i_mpktnum);
316         }
317         if (mflag)
318             LogMcastNoIdent("--- MCOUNT[%d]: CMPKTNUM[%d] - IMPKTNUM[%d] = [%d]PKTS ---", mcount, m->MPktNum, i_mpktnum, (m->MPktNum - i_mpktnum));
319         LogMcastNoIdent("--- END MCAST STATE LOG ---");
320     }
321 }
322 
abort_request(request_state * req)323 mDNSlocal void abort_request(request_state *req)
324 {
325     if (req->terminate == (req_termination_fn) ~0)
326     {
327         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
328                   "[R%d] abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req->request_id, req, req->terminate);
329         return;
330     }
331 
332     // First stop whatever mDNSCore operation we were doing
333     // If this is actually a shared connection operation, then its req->terminate function will scan
334     // the all_requests list and terminate any subbordinate operations sharing this file descriptor
335     if (req->terminate) req->terminate(req);
336 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
337     if (req->custom_service_id != 0)
338     {
339         Querier_DeregisterCustomDNSService(req->custom_service_id);
340         req->custom_service_id = 0;
341     }
342 #endif
343 
344     if (!dnssd_SocketValid(req->sd))
345     {
346         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
347                   "[R%d] abort_request: ERROR: Attempt to abort operation %p with invalid fd %d", req->request_id, req, req->sd);
348         return;
349     }
350 
351     // Now, if this request_state is not subordinate to some other primary, close file descriptor and discard replies
352     if (!req->primary)
353     {
354         if (req->errsd != req->sd)
355         {
356             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
357                       "[R%d] Removing FD %d and closing errsd %d", req->request_id, req->sd, req->errsd);
358         }
359         else
360         {
361             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
362                       "[R%d] Removing FD %d", req->request_id, req->sd);
363         }
364         udsSupportRemoveFDFromEventLoop(req->sd, req->platform_data);       // Note: This also closes file descriptor req->sd for us
365         if (req->errsd != req->sd) { dnssd_close(req->errsd); req->errsd = req->sd; }
366 
367         while (req->replies)    // free pending replies
368         {
369             reply_state *ptr = req->replies;
370             req->replies = req->replies->next;
371             freeL("reply_state (abort)", ptr);
372         }
373     }
374 
375     // Set req->sd to something invalid, so that udsserver_idle knows to unlink and free this structure
376 #if MDNS_MALLOC_DEBUGGING
377     // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MDNS_MALLOC_DEBUGGING uses
378     // for detecting when the memory for an object is inadvertently freed while the object is still on some list
379 #ifdef WIN32
380 #error This will not work on Windows, look at IsValidSocket in mDNSShared/CommonServices.h to see why
381 #endif
382     req->sd = req->errsd = -2;
383 #else
384     req->sd = req->errsd = dnssd_InvalidSocket;
385 #endif
386     // We also set req->terminate to a bogus value so we know if abort_request() gets called again for this request
387     req->terminate = (req_termination_fn) ~0;
388 }
389 
390 #if DEBUG
SetDebugBoundPath(void)391 mDNSexport void SetDebugBoundPath(void)
392 {
393 #if !defined(USE_TCP_LOOPBACK)
394     boundPath = MDNS_UDS_SERVERPATH_DEBUG;
395 #endif
396 }
397 
IsDebugSocketInUse(void)398 mDNSexport int IsDebugSocketInUse(void)
399 {
400 #if !defined(USE_TCP_LOOPBACK)
401     return !strcmp(boundPath, MDNS_UDS_SERVERPATH_DEBUG);
402 #else
403     return mDNSfalse;
404 #endif
405 }
406 #endif
407 
AbortUnlinkAndFree(request_state * req)408 mDNSlocal void AbortUnlinkAndFree(request_state *req)
409 {
410     request_state **p = &all_requests;
411     abort_request(req);
412     while (*p && *p != req) p=&(*p)->next;
413     if (*p)
414     {
415         *p = req->next;
416 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
417         if (req->trust)
418         {
419             void * context = mdns_trust_get_context(req->trust);
420             mdns_trust_set_context(req->trust, NULL);
421             if (context) freeL("context/AbortUnlinkAndFree", context);
422             mdns_trust_forget(&req->trust);
423         }
424 #endif
425         freeL("request_state/AbortUnlinkAndFree", req);
426     }
427     else LogMsg("AbortUnlinkAndFree: ERROR: Attempt to abort operation %p not in list", req);
428 }
429 
create_reply(const reply_op_t op,const size_t datalen,request_state * const request)430 mDNSlocal reply_state *create_reply(const reply_op_t op, const size_t datalen, request_state *const request)
431 {
432     reply_state *reply;
433 
434     if ((unsigned)datalen < sizeof(reply_hdr))
435     {
436         LogMsg("ERROR: create_reply - data length less than length of required fields");
437         return NULL;
438     }
439 
440     reply = (reply_state *) callocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr));
441     if (!reply) FatalError("ERROR: calloc");
442 
443     reply->next     = mDNSNULL;
444     reply->totallen = (mDNSu32)datalen + sizeof(ipc_msg_hdr);
445     reply->nwriten  = 0;
446 
447     reply->mhdr->version        = VERSION;
448     reply->mhdr->datalen        = (mDNSu32)datalen;
449     reply->mhdr->ipc_flags      = 0;
450     reply->mhdr->op             = op;
451     reply->mhdr->client_context = request->hdr.client_context;
452     reply->mhdr->reg_index      = 0;
453 
454     return reply;
455 }
456 
457 // Append a reply to the list in a request object
458 // If our request is sharing a connection, then we append our reply_state onto the primary's list
459 // If the request does not want asynchronous replies, then the reply is freed instead of being appended to any list.
append_reply(request_state * req,reply_state * rep)460 mDNSlocal void append_reply(request_state *req, reply_state *rep)
461 {
462     request_state *r;
463     reply_state **ptr;
464 
465     if (req->no_reply)
466     {
467         freeL("reply_state/append_reply", rep);
468         return;
469     }
470 
471     r = req->primary ? req->primary : req;
472     ptr = &r->replies;
473     while (*ptr) ptr = &(*ptr)->next;
474     *ptr = rep;
475     rep->next = NULL;
476 }
477 
478 // Generates a response message giving name, type, domain, plus interface index,
479 // suitable for a browse result or service registration result.
480 // On successful completion rep is set to point to a malloc'd reply_state struct
GenerateNTDResponse(const domainname * const servicename,const mDNSInterfaceID id,request_state * const request,reply_state ** const rep,reply_op_t op,DNSServiceFlags flags,mStatus err)481 mDNSlocal mStatus GenerateNTDResponse(const domainname *const servicename, const mDNSInterfaceID id,
482                                       request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err)
483 {
484     domainlabel name;
485     domainname type, dom;
486     *rep = NULL;
487     if (servicename && !DeconstructServiceName(servicename, &name, &type, &dom))
488         return kDNSServiceErr_Invalid;
489     else
490     {
491         char namestr[MAX_DOMAIN_LABEL+1];
492         char typestr[MAX_ESCAPED_DOMAIN_NAME];
493         char domstr [MAX_ESCAPED_DOMAIN_NAME];
494         int len;
495         char *data;
496 
497         if (servicename)
498         {
499             ConvertDomainLabelToCString_unescaped(&name, namestr);
500             ConvertDomainNameToCString(&type, typestr);
501             ConvertDomainNameToCString(&dom, domstr);
502         }
503         else
504         {
505             namestr[0] = 0;
506             typestr[0] = 0;
507             domstr[0] = 0;
508         }
509 
510         // Calculate reply data length
511         len = sizeof(DNSServiceFlags);
512         len += sizeof(mDNSu32);  // if index
513         len += sizeof(DNSServiceErrorType);
514         len += (int) (strlen(namestr) + 1);
515         len += (int) (strlen(typestr) + 1);
516         len += (int) (strlen(domstr) + 1);
517 
518         // Build reply header
519         *rep = create_reply(op, len, request);
520         (*rep)->rhdr->flags = dnssd_htonl(flags);
521         (*rep)->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id, mDNSfalse));
522         (*rep)->rhdr->error = dnssd_htonl(err);
523 
524         // Build reply body
525         data = (char *)&(*rep)->rhdr[1];
526         put_string(namestr, &data);
527         put_string(typestr, &data);
528         put_string(domstr, &data);
529 
530         return mStatus_NoError;
531     }
532 }
533 
GenerateBrowseReply(const domainname * const servicename,const mDNSInterfaceID id,request_state * const request,reply_state ** const rep,reply_op_t op,DNSServiceFlags flags,mStatus err)534 mDNSlocal void GenerateBrowseReply(const domainname *const servicename, const mDNSInterfaceID id,
535                                               request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err)
536 {
537     char namestr[MAX_DOMAIN_LABEL+1];
538     char typestr[MAX_ESCAPED_DOMAIN_NAME];
539     static const char domstr[] = ".";
540     int len;
541     char *data;
542 
543     *rep = NULL;
544 
545     if (servicename)
546     {
547         // 1. Put first label in namestr
548         ConvertDomainLabelToCString_unescaped((const domainlabel *)servicename, namestr);
549 
550         // 2. Put second label and "local" into typestr
551         mDNS_snprintf(typestr, sizeof(typestr), "%#s.local.", SecondLabel(servicename));
552     }
553     else
554     {
555         namestr[0] = 0;
556         typestr[0] = 0;
557     }
558 
559     // Calculate reply data length
560     len = sizeof(DNSServiceFlags);
561     len += sizeof(mDNSu32);  // if index
562     len += sizeof(DNSServiceErrorType);
563     len += (int) (strlen(namestr) + 1);
564     len += (int) (strlen(typestr) + 1);
565     len += (int) (strlen(domstr) + 1);
566 
567     // Build reply header
568     *rep = create_reply(op, len, request);
569     (*rep)->rhdr->flags = dnssd_htonl(flags);
570     (*rep)->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id, mDNSfalse));
571     (*rep)->rhdr->error = dnssd_htonl(err);
572 
573     // Build reply body
574     data = (char *)&(*rep)->rhdr[1];
575     put_string(namestr, &data);
576     put_string(typestr, &data);
577     put_string(domstr, &data);
578 }
579 
580 // Returns a resource record (allocated w/ malloc) containing the data found in an IPC message
581 // Data must be in the following format: flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional) ttl
582 // (ttl only extracted/set if ttl argument is non-zero). Returns NULL for a bad-parameter error
read_rr_from_ipc_msg(request_state * request,int GetTTL,int validate_flags)583 mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, int validate_flags)
584 {
585     DNSServiceFlags flags  = get_flags(&request->msgptr, request->msgend);
586     mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
587     char name[MAX_ESCAPED_DOMAIN_NAME];
588     int str_err = get_string(&request->msgptr, request->msgend, name, sizeof(name));
589     mDNSu16 type    = get_uint16(&request->msgptr, request->msgend);
590     mDNSu16     class   = get_uint16(&request->msgptr, request->msgend);
591     mDNSu16 rdlen   = get_uint16(&request->msgptr, request->msgend);
592     const mDNSu8 *const rdata = (const mDNSu8 *)get_rdata (&request->msgptr, request->msgend, rdlen);
593     mDNSu32 ttl   = GetTTL ? get_uint32(&request->msgptr, request->msgend) : 0;
594     size_t rdcapacity;
595     AuthRecord *rr;
596     mDNSInterfaceID InterfaceID;
597     AuthRecType artype;
598     mDNSu8 recordType;
599 
600     request->flags = flags;
601     request->interfaceIndex = interfaceIndex;
602 
603     if (str_err) { LogMsg("ERROR: read_rr_from_ipc_msg - get_string"); return NULL; }
604 
605     if (!request->msgptr) { LogMsg("Error reading Resource Record from client"); return NULL; }
606 
607     if (validate_flags &&
608         !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
609         !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique) &&
610         !((flags & kDNSServiceFlagsKnownUnique) == kDNSServiceFlagsKnownUnique))
611     {
612         LogMsg("ERROR: Bad resource record flags (must be one of either kDNSServiceFlagsShared, kDNSServiceFlagsUnique or kDNSServiceFlagsKnownUnique)");
613         return NULL;
614     }
615     InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
616 
617     // The registration is scoped to a specific interface index, but the interface is not currently on our list.
618     if ((InterfaceID == mDNSInterface_Any) && (interfaceIndex != kDNSServiceInterfaceIndexAny))
619     {
620         // On Apple platforms, an interface's mDNSInterfaceID is equal to its index. Using an interface index that isn't
621         // currently valid will cause the registration to take place as soon as it becomes valid. On other platforms,
622         // mDNSInterfaceID is actually a pointer to a platform-specific interface object, but we don't know what the pointer
623         // for the interface index will be ahead of time. For now, just return NULL to indicate an error condition since the
624         // interface index is invalid. Otherwise, the registration would be performed on all interfaces.
625 #if APPLE_OSX_mDNSResponder
626         InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
627 #else
628         return NULL;
629 #endif
630     }
631     rdcapacity = (rdlen > sizeof(RDataBody2)) ? rdlen : sizeof(RDataBody2);
632     rr = (AuthRecord *) callocL("AuthRecord/read_rr_from_ipc_msg", sizeof(*rr) - sizeof(RDataBody) + rdcapacity);
633     if (!rr) FatalError("ERROR: calloc");
634 
635     if (InterfaceID == mDNSInterface_LocalOnly)
636         artype = AuthRecordLocalOnly;
637     else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE)
638         artype = AuthRecordP2P;
639     else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeP2P)
640             && (flags & kDNSServiceFlagsIncludeAWDL))
641         artype = AuthRecordAnyIncludeAWDLandP2P;
642     else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeP2P))
643         artype = AuthRecordAnyIncludeP2P;
644     else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeAWDL))
645         artype = AuthRecordAnyIncludeAWDL;
646     else
647         artype = AuthRecordAny;
648 
649     if (flags & kDNSServiceFlagsShared)
650         recordType = (mDNSu8) kDNSRecordTypeShared;
651     else if (flags & kDNSServiceFlagsKnownUnique)
652         recordType = (mDNSu8) kDNSRecordTypeKnownUnique;
653     else
654         recordType = (mDNSu8) kDNSRecordTypeUnique;
655 
656     mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, type, 0, recordType, artype, mDNSNULL, mDNSNULL);
657 
658     if (!MakeDomainNameFromDNSNameString(&rr->namestorage, name))
659     {
660         LogMsg("ERROR: bad name: %s", name);
661         freeL("AuthRecord/read_rr_from_ipc_msg", rr);
662         return NULL;
663     }
664 
665     if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
666     rr->resrec.rrclass = class;
667     rr->resrec.rdlength = rdlen;
668     rr->resrec.rdata->MaxRDLength = (mDNSu16)rdcapacity;
669     if (!SetRData(mDNSNULL, rdata, rdata + rdlen, &rr->resrec, rdlen))
670     {
671         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
672             "[R%u] read_rr_from_ipc_msg: SetRData failed for " PRI_DM_NAME " (" PUB_S ")",
673             request->request_id, DM_NAME_PARAM(rr->resrec.name), DNSTypeName(type));
674         freeL("AuthRecord/read_rr_from_ipc_msg", rr);
675         return NULL;
676     }
677     if (GetTTL) rr->resrec.rroriginalttl = ttl;
678     rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
679     SetNewRData(&rr->resrec, mDNSNULL, 0);  // Sets rr->rdatahash for us
680     return rr;
681 }
682 
build_domainname_from_strings(domainname * srv,char * name,char * regtype,char * domain)683 mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
684 {
685     domainlabel n;
686     domainname d, t;
687 
688     if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
689     if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
690     if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
691     if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
692     return 0;
693 }
694 
send_all(dnssd_sock_t s,const char * ptr,int len)695 mDNSlocal void send_all(dnssd_sock_t s, const char *ptr, int len)
696 {
697     const ssize_t n = send(s, ptr, len, 0);
698     // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a small write for us
699     // (four bytes for a typical error code return, 12 bytes for DNSServiceGetProperty(DaemonVersion)).
700     // If it does fail, we don't attempt to handle this failure, but we do log it so we know something is wrong.
701     if (n < len)
702     {
703         LogMsg("ERROR: send_all(%d) wrote %ld of %d errno %d (%s)",
704             s, (long)n, len, dnssd_errno, dnssd_strerror(dnssd_errno));
705     }
706 }
707 
708 #if 0
709 mDNSlocal mDNSBool AuthorizedDomain(const request_state * const request, const domainname * const d, const DNameListElem * const doms)
710 {
711     const DNameListElem   *delem = mDNSNULL;
712     int bestDelta   = -1;                           // the delta of the best match, lower is better
713     int dLabels     = 0;
714     mDNSBool allow       = mDNSfalse;
715 
716     if (SystemUID(request->uid)) return mDNStrue;
717 
718     dLabels = CountLabels(d);
719     for (delem = doms; delem; delem = delem->next)
720     {
721         if (delem->uid)
722         {
723             int delemLabels = CountLabels(&delem->name);
724             int delta       = dLabels - delemLabels;
725             if ((bestDelta == -1 || delta <= bestDelta) && SameDomainName(&delem->name, SkipLeadingLabels(d, delta)))
726             {
727                 bestDelta = delta;
728                 allow = (allow || (delem->uid == request->uid));
729             }
730         }
731     }
732 
733     return bestDelta == -1 ? mDNStrue : allow;
734 }
735 #endif
736 
737 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
SetupAuditTokenForRequest(request_state * request)738 mDNSlocal void SetupAuditTokenForRequest(request_state *request)
739 {
740 
741     pid_t audit_pid = audit_token_to_pid(request->audit_token);
742     if (audit_pid == 0)
743     {
744 #if !defined(LOCAL_PEERTOKEN)
745 #define LOCAL_PEERTOKEN         0x006           /* retrieve peer audit token */
746 #endif
747         socklen_t len = sizeof(audit_token_t);
748         int ret = getsockopt(request->sd, SOL_LOCAL, LOCAL_PEERTOKEN, &request->audit_token, &len);
749         if (ret != 0)
750         {
751             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
752                       "SetupAuditTokenForRequest: No audit_token using LOCAL_PEERTOKEN (%s PID %d) for op %d ret(%d)",
753                       request->pid_name, request->process_id, request->hdr.op, ret);
754         }
755     }
756 }
757 #endif
758 
759 // ***************************************************************************
760 #if COMPILER_LIKES_PRAGMA_MARK
761 #pragma mark -
762 #pragma mark - external helpers
763 #endif
764 
765 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_start_advertising_helper(service_instance * const instance)766 mDNSlocal void external_start_advertising_helper(service_instance *const instance)
767 {
768     AuthRecord *st = instance->subtypes;
769     ExtraResourceRecord *e;
770     int i;
771     const pid_t requestPID = instance->request->process_id;
772 
773     if (mDNSIPPortIsZero(instance->request->u.servicereg.port))
774     {
775         LogInfo("external_start_advertising_helper: Not registering service with port number zero");
776         return;
777     }
778 
779     if (instance->external_advertise) LogMsg("external_start_advertising_helper: external_advertise already set!");
780 
781     for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
782         external_start_advertising_service(&st[i].resrec, instance->request->flags, requestPID);
783 
784     external_start_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags, requestPID);
785     external_start_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags, requestPID);
786     external_start_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags, requestPID);
787 
788     for (e = instance->srs.Extras; e; e = e->next)
789         external_start_advertising_service(&e->r.resrec, instance->request->flags, requestPID);
790 
791     instance->external_advertise = mDNStrue;
792 }
793 
external_stop_advertising_helper(service_instance * const instance)794 mDNSlocal void external_stop_advertising_helper(service_instance *const instance)
795 {
796     AuthRecord *st = instance->subtypes;
797     ExtraResourceRecord *e;
798     int i;
799 
800     if (!instance->external_advertise) return;
801 
802     LogInfo("external_stop_advertising_helper: calling external_stop_advertising_service");
803 
804     if (instance->request)
805     {
806         const pid_t requestPID = instance->request->process_id;
807         for (i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
808         {
809             external_stop_advertising_service(&st[i].resrec, instance->request->flags, requestPID);
810         }
811 
812         external_stop_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags, requestPID);
813         external_stop_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags, requestPID);
814         external_stop_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags, requestPID);
815 
816         for (e = instance->srs.Extras; e; e = e->next)
817         {
818             external_stop_advertising_service(&e->r.resrec, instance->request->flags, requestPID);
819         }
820     }
821 
822     instance->external_advertise = mDNSfalse;
823 }
824 #endif  // MDNSRESPONDER_SUPPORTS(APPLE, D2D)
825 
826 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
_get_trust_results_dispatch_queue(void)827 mDNSlocal dispatch_queue_t _get_trust_results_dispatch_queue(void)
828 {
829     static dispatch_once_t  once    = 0;
830     static dispatch_queue_t queue   = NULL;
831 
832     dispatch_once(&once, ^{
833         dispatch_queue_attr_t const attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
834         queue = dispatch_queue_create("com.apple.mDNSResponder.trust_results-queue", attr);
835     });
836     return queue;
837 }
838 #endif
839 
840 // ***************************************************************************
841 #if COMPILER_LIKES_PRAGMA_MARK
842 #pragma mark -
843 #pragma mark - DNSServiceRegister
844 #endif
845 
FreeExtraRR(mDNS * const m,AuthRecord * const rr,mStatus result)846 mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
847 {
848     ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
849     (void)m;  // Unused
850 
851     if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
852 
853     LogInfo("     FreeExtraRR %s", RRDisplayString(m, &rr->resrec));
854 
855     if (rr->resrec.rdata != &rr->rdatastorage)
856         freeL("Extra RData", rr->resrec.rdata);
857     freeL("ExtraResourceRecord/FreeExtraRR", extra);
858 }
859 
unlink_and_free_service_instance(service_instance * srv)860 mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
861 {
862     ExtraResourceRecord *e = srv->srs.Extras, *tmp;
863 
864 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
865     external_stop_advertising_helper(srv);
866 #endif
867 
868     // clear pointers from parent struct
869     if (srv->request)
870     {
871         service_instance **p = &srv->request->u.servicereg.instances;
872         while (*p)
873         {
874             if (*p == srv) { *p = (*p)->next; break; }
875             p = &(*p)->next;
876         }
877     }
878 
879     while (e)
880     {
881         e->r.RecordContext = e;
882         tmp = e;
883         e = e->next;
884         FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree);
885     }
886 
887     if (srv->srs.RR_TXT.resrec.rdata != &srv->srs.RR_TXT.rdatastorage)
888         freeL("TXT RData", srv->srs.RR_TXT.resrec.rdata);
889 
890     if (srv->subtypes)
891     {
892         freeL("ServiceSubTypes", srv->subtypes);
893         srv->subtypes = NULL;
894     }
895     freeL("service_instance", srv);
896 }
897 
898 // Count how many other service records we have locally with the same name, but different rdata.
899 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
900 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
CountPeerRegistrations(ServiceRecordSet * const srs)901 mDNSexport int CountPeerRegistrations(ServiceRecordSet *const srs)
902 {
903     int count = 0;
904     ResourceRecord *r = &srs->RR_SRV.resrec;
905     AuthRecord *rr;
906 
907     for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
908         if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !IdenticalSameNameRecord(&rr->resrec, r))
909             count++;
910 
911     verbosedebugf("%d peer registrations for %##s", count, r->name->c);
912     return(count);
913 }
914 
CountExistingRegistrations(domainname * srv,mDNSIPPort port)915 mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
916 {
917     int count = 0;
918     AuthRecord *rr;
919     for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
920         if (rr->resrec.rrtype == kDNSType_SRV &&
921             mDNSSameIPPort(rr->resrec.rdata->u.srv.port, port) &&
922             SameDomainName(rr->resrec.name, srv))
923             count++;
924     return(count);
925 }
926 
SendServiceRemovalNotification(ServiceRecordSet * const srs)927 mDNSlocal void SendServiceRemovalNotification(ServiceRecordSet *const srs)
928 {
929     reply_state *rep;
930     service_instance *instance = srs->ServiceContext;
931     if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, 0, mStatus_NoError) != mStatus_NoError)
932         LogMsg("%3d: SendServiceRemovalNotification: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
933     else { append_reply(instance->request, rep); instance->clientnotified = mDNSfalse; }
934 }
935 
936 // service registration callback performs three duties - frees memory for deregistered services,
937 // handles name conflicts, and delivers completed registration information to the client
regservice_callback(mDNS * const m,ServiceRecordSet * const srs,mStatus result)938 mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
939 {
940     mStatus err;
941     mDNSBool SuppressError = mDNSfalse;
942     service_instance *instance;
943     reply_state         *rep;
944     (void)m; // Unused
945 
946     if (!srs)
947     {
948         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: srs is NULL %d", result);
949         return;
950     }
951 
952     instance = srs->ServiceContext;
953     if (!instance)
954     {
955         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: srs->ServiceContext is NULL %d", result);
956         return;
957     }
958 
959     // don't send errors up to client for wide-area, empty-string registrations
960     if (instance->request &&
961         instance->request->u.servicereg.default_domain &&
962         !instance->default_local)
963         SuppressError = mDNStrue;
964 
965     if (mDNS_LoggingEnabled)
966     {
967         const char *result_description;
968         char description[32]; // 32-byte is enough for holding "suppressed error -2147483648\0"
969         mDNSu32 request_id = instance->request ? instance->request->request_id : 0;
970         switch (result) {
971             case mStatus_NoError:
972                 result_description = "REGISTERED";
973                 break;
974             case mStatus_MemFree:
975                 result_description = "DEREGISTERED";
976                 break;
977             case mStatus_NameConflict:
978                 result_description = "NAME CONFLICT";
979                 break;
980             default:
981                 mDNS_snprintf(description, sizeof(description), "%s %d", SuppressError ? "suppressed error" : "CALLBACK", result);
982                 result_description = description;
983                 break;
984         }
985         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] DNSServiceRegister(" PRI_DM_NAME ", %u) %s",
986                   request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name), mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result_description);
987     }
988 
989     if (!instance->request && result != mStatus_MemFree)
990     {
991         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: instance->request is NULL %d", result);
992         return;
993     }
994 
995     if (result == mStatus_NoError)
996     {
997         if (instance->request->u.servicereg.allowremotequery)
998         {
999             ExtraResourceRecord *e;
1000             srs->RR_ADV.AllowRemoteQuery = mDNStrue;
1001             srs->RR_PTR.AllowRemoteQuery = mDNStrue;
1002             srs->RR_SRV.AllowRemoteQuery = mDNStrue;
1003             srs->RR_TXT.AllowRemoteQuery = mDNStrue;
1004             for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
1005         }
1006 
1007         if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
1008             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name));
1009         else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
1010 
1011 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1012         if (callExternalHelpers(instance->request->u.servicereg.InterfaceID, &instance->domain, instance->request->flags))
1013         {
1014             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] regservice_callback: calling external_start_advertising_helper()", instance->request->request_id);
1015             external_start_advertising_helper(instance);
1016         }
1017 #endif
1018         if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
1019             RecordUpdatedNiceLabel(0);   // Successfully got new name, tell user immediately
1020     }
1021     else if (result == mStatus_MemFree)
1022     {
1023 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
1024         curr_num_regservices--;
1025 #endif
1026         if (instance->request && instance->renameonmemfree)
1027         {
1028 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1029             external_stop_advertising_helper(instance);
1030 #endif
1031             instance->renameonmemfree = 0;
1032             err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
1033             if (err)
1034                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] ERROR: regservice_callback - RenameAndReregisterService returned %d", instance->request->request_id, err);
1035             // error should never happen - safest to log and continue
1036         }
1037         else
1038             unlink_and_free_service_instance(instance);
1039     }
1040     else if (result == mStatus_NameConflict)
1041     {
1042         if (instance->request->u.servicereg.autorename)
1043         {
1044 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1045             external_stop_advertising_helper(instance);
1046 #endif
1047             if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
1048             {
1049                 // On conflict for an autoname service, rename and reregister *all* autoname services
1050                 IncrementLabelSuffix(&m->nicelabel, mDNStrue);
1051                 mDNS_ConfigChanged(m);  // Will call back into udsserver_handle_configchange()
1052             }
1053             else    // On conflict for a non-autoname service, rename and reregister just that one service
1054             {
1055                 if (instance->clientnotified) SendServiceRemovalNotification(srs);
1056                 mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
1057             }
1058         }
1059         else
1060         {
1061             if (!SuppressError)
1062             {
1063                 if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
1064                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name));
1065                 else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
1066             }
1067             unlink_and_free_service_instance(instance);
1068         }
1069     }
1070     else        // Not mStatus_NoError, mStatus_MemFree, or mStatus_NameConflict
1071     {
1072         if (!SuppressError)
1073         {
1074             if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
1075                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name));
1076             else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
1077         }
1078     }
1079 }
1080 
regrecord_callback(mDNS * const m,AuthRecord * rr,mStatus result)1081 mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
1082 {
1083     (void)m; // Unused
1084     if (!rr->RecordContext)     // parent struct already freed by termination callback
1085     {
1086         if (result == mStatus_NoError)
1087             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Error: regrecord_callback: successful registration of orphaned record " PRI_S, ARDisplayString(m, rr));
1088         else
1089         {
1090             if (result != mStatus_MemFree)
1091                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regrecord_callback: error %d received after parent termination", result);
1092 
1093             // We come here when the record is being deregistered either from DNSServiceRemoveRecord or connection_termination.
1094             // If the record has been updated, we need to free the rdata. Every time we call mDNS_Update, it calls update_callback
1095             // with the old rdata (so that we can free it) and stores the new rdata in "rr->resrec.rdata". This means, we need
1096             // to free the latest rdata for which the update_callback was never called with.
1097             if (rr->resrec.rdata != &rr->rdatastorage) freeL("RData/regrecord_callback", rr->resrec.rdata);
1098             freeL("AuthRecord/regrecord_callback", rr);
1099         }
1100     }
1101     else
1102     {
1103         registered_record_entry *re = rr->RecordContext;
1104         request_state *request = re->request;
1105 
1106         if (mDNS_LoggingEnabled)
1107         {
1108             const char *result_description;
1109             char description[16]; // 16-byte is enough for holding -2147483648\0
1110             switch (result) {
1111                 case mStatus_NoError:
1112                     result_description = "REGISTERED";
1113                     break;
1114                 case mStatus_MemFree:
1115                     result_description = "DEREGISTERED";
1116                     break;
1117                 case mStatus_NameConflict:
1118                     result_description = "NAME CONFLICT";
1119                     break;
1120                 default:
1121                     mDNS_snprintf(description, sizeof(description), "%d", result);
1122                     result_description = description;
1123                     break;
1124             }
1125 
1126             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] DNSServiceRegisterRecord(%u " PRI_S ")" PUB_S,
1127                       request->request_id, re->key, RRDisplayString(m, &rr->resrec), result_description);
1128         }
1129 
1130         if (result != mStatus_MemFree)
1131         {
1132             int len = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + sizeof(DNSServiceErrorType);
1133             reply_state *reply = create_reply(reg_record_reply_op, len, request);
1134             reply->mhdr->client_context = re->regrec_client_context;
1135             reply->rhdr->flags = dnssd_htonl(0);
1136             reply->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, rr->resrec.InterfaceID, mDNSfalse));
1137             reply->rhdr->error = dnssd_htonl(result);
1138             append_reply(request, reply);
1139         }
1140 
1141         if (result)
1142         {
1143             // If this is a callback to a keepalive record, do not free it.
1144             if (result == mStatus_BadStateErr)
1145             {
1146                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1147                           "[R%u] regrecord_callback: Callback with error code mStatus_BadStateErr - not freeing the record.", request->request_id);
1148             }
1149             else
1150             {
1151                 // unlink from list, free memory
1152                 registered_record_entry **ptr = &request->u.reg_recs;
1153                 while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
1154                 if (!*ptr)
1155                 {
1156                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1157                               "[R%u] regrecord_callback - record not in list!", request->request_id);
1158                     return;
1159                 }
1160                 *ptr = (*ptr)->next;
1161                 freeL("registered_record_entry AuthRecord regrecord_callback", re->rr);
1162                 freeL("registered_record_entry regrecord_callback", re);
1163              }
1164         }
1165         else
1166         {
1167             if (re->external_advertise)
1168             {
1169                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1170                           "[R%u] regrecord_callback: external_advertise already set!", request->request_id);
1171             }
1172 
1173 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1174             if (callExternalHelpers(re->origInterfaceID, &rr->namestorage, request->flags))
1175             {
1176                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1177                           "[R%u] regrecord_callback: calling external_start_advertising_service", request->request_id);
1178                 external_start_advertising_service(&rr->resrec, request->flags, request->process_id);
1179                 re->external_advertise = mDNStrue;
1180             }
1181 #endif
1182         }
1183     }
1184 }
1185 
1186 // set_peer_pid() is called after mem is allocated for each new request in NewRequest()
1187 // This accounts for 2 places (connect_callback, request_callback)
set_peer_pid(request_state * request)1188 mDNSlocal void set_peer_pid(request_state *request)
1189 {
1190     request->pid_name[0] = '\0';
1191     request->process_id  = -1;
1192 #ifdef LOCAL_PEEREPID
1193     pid_t           p    = (pid_t) -1;
1194     socklen_t       len  = sizeof(p);
1195     if (request->sd < 0)
1196         return;
1197     // to extract the effective pid value
1198     if (getsockopt(request->sd, SOL_LOCAL, LOCAL_PEEREPID, &p, &len) != 0)
1199         return;
1200     // to extract the process name from the pid value
1201     if (proc_pidinfo(p, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0)
1202         return;
1203     mDNSPlatformStrLCopy(request->pid_name, proc.pbsi_comm, sizeof(request->pid_name));
1204     request->process_id = p;
1205     debugf("set_peer_pid: Client PEEREPID is %d %s", p, request->pid_name);
1206 #else   // !LOCAL_PEEREPID
1207     LogInfo("set_peer_pid: Not Supported on this version of OS");
1208     if (request->sd < 0)
1209         return;
1210 #endif  // LOCAL_PEEREPID
1211 }
1212 
connection_termination(request_state * request)1213 mDNSlocal void connection_termination(request_state *request)
1214 {
1215     // When terminating a shared connection, we need to scan the all_requests list
1216     // and terminate any subbordinate operations sharing this file descriptor
1217     request_state **req = &all_requests;
1218 
1219     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1220            "[R%d] DNSServiceCreateConnection STOP PID[%d](" PUB_S ")",
1221            request->request_id, request->process_id, request->pid_name);
1222 
1223     while (*req)
1224     {
1225         if ((*req)->primary == request)
1226         {
1227             // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
1228             request_state *tmp = *req;
1229             if (tmp->primary == tmp) LogMsg("connection_termination ERROR (*req)->primary == *req for %p %d",                  tmp, tmp->sd);
1230             if (tmp->replies) LogMsg("connection_termination ERROR How can subordinate req %p %d have replies queued?", tmp, tmp->sd);
1231             abort_request(tmp);
1232             *req = tmp->next;
1233 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
1234             if (tmp->trust)
1235             {
1236                 void * context = mdns_trust_get_context(tmp->trust);
1237                 mdns_trust_set_context(tmp->trust, NULL);
1238                 if (context) freeL("context/connection_termination", context);
1239                 mdns_trust_forget(&tmp->trust);
1240             }
1241 #endif
1242             freeL("request_state/connection_termination", tmp);
1243         }
1244         else
1245             req = &(*req)->next;
1246     }
1247 
1248     while (request->u.reg_recs)
1249     {
1250         registered_record_entry *ptr = request->u.reg_recs;
1251         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1252                "[R%d] DNSServiceRegisterRecord(0x%X, %d, " PRI_S ") STOP PID[%d](" PUB_S ")",
1253                request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &ptr->rr->resrec), request->process_id,
1254                request->pid_name);
1255         request->u.reg_recs = request->u.reg_recs->next;
1256         ptr->rr->RecordContext = NULL;
1257         if (ptr->external_advertise)
1258         {
1259             ptr->external_advertise = mDNSfalse;
1260 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1261             external_stop_advertising_service(&ptr->rr->resrec, request->flags, request->process_id);
1262 #endif
1263         }
1264         LogMcastS(ptr->rr, request, reg_stop);
1265         mDNS_Deregister(&mDNSStorage, ptr->rr);     // Will free ptr->rr for us
1266         freeL("registered_record_entry/connection_termination", ptr);
1267     }
1268 }
1269 
handle_cancel_request(request_state * request)1270 mDNSlocal void handle_cancel_request(request_state *request)
1271 {
1272     request_state **req = &all_requests;
1273     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "[R%d] Cancel %08X %08X",
1274            request->request_id, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
1275     while (*req)
1276     {
1277         if ((*req)->primary == request &&
1278             (*req)->hdr.client_context.u32[0] == request->hdr.client_context.u32[0] &&
1279             (*req)->hdr.client_context.u32[1] == request->hdr.client_context.u32[1])
1280         {
1281             // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
1282             request_state *tmp = *req;
1283             abort_request(tmp);
1284             *req = tmp->next;
1285 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
1286             if (tmp->trust)
1287             {
1288                 void * context = mdns_trust_get_context(tmp->trust);
1289                 mdns_trust_set_context(tmp->trust, NULL);
1290                 if (context) freeL("context/handle_cancel_request", context);
1291                 mdns_trust_forget(&tmp->trust);
1292             }
1293 #endif
1294             freeL("request_state/handle_cancel_request", tmp);
1295         }
1296         else
1297             req = &(*req)->next;
1298     }
1299 }
1300 
_handle_regrecord_request_start(request_state * request,AuthRecord * rr)1301 mDNSlocal mStatus _handle_regrecord_request_start(request_state *request, AuthRecord * rr)
1302 {
1303     mStatus err;
1304     registered_record_entry *re;
1305     // Don't allow non-local domains to be regsitered as LocalOnly. Allowing this would permit
1306     // clients to register records such as www.bigbank.com A w.x.y.z to redirect Safari.
1307     if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly && !IsLocalDomain(rr->resrec.name) &&
1308         rr->resrec.rrclass == kDNSClass_IN && (rr->resrec.rrtype == kDNSType_A || rr->resrec.rrtype == kDNSType_AAAA ||
1309                                                rr->resrec.rrtype == kDNSType_CNAME))
1310     {
1311         freeL("AuthRecord/handle_regrecord_request", rr);
1312         return (mStatus_BadParamErr);
1313     }
1314     // allocate registration entry, link into list
1315     re = (registered_record_entry *) callocL("registered_record_entry", sizeof(*re));
1316     if (!re) FatalError("ERROR: calloc");
1317     re->key                   = request->hdr.reg_index;
1318     re->rr                    = rr;
1319     re->regrec_client_context = request->hdr.client_context;
1320     re->request               = request;
1321     re->external_advertise    = mDNSfalse;
1322     rr->RecordContext         = re;
1323     rr->RecordCallback        = regrecord_callback;
1324 
1325     re->origInterfaceID = rr->resrec.InterfaceID;
1326     if (rr->resrec.InterfaceID == mDNSInterface_P2P)
1327         rr->resrec.InterfaceID = mDNSInterface_Any;
1328 #if 0
1329     if (!AuthorizedDomain(request, rr->resrec.name, AutoRegistrationDomains)) return (mStatus_NoError);
1330 #endif
1331     if (rr->resrec.rroriginalttl == 0)
1332         rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
1333 
1334     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1335            "[R%d] DNSServiceRegisterRecord(0x%X, %d, " PRI_S ") START PID[%d](" PUB_S ")",
1336            request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &rr->resrec), request->process_id,
1337            request->pid_name);
1338 
1339     err = mDNS_Register(&mDNSStorage, rr);
1340     if (err)
1341     {
1342         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1343                "[R%d] DNSServiceRegisterRecord(0x%X, %d," PRI_S ") ERROR (%d)",
1344                request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &rr->resrec), err);
1345         freeL("registered_record_entry", re);
1346         freeL("registered_record_entry/AuthRecord", rr);
1347     }
1348     else
1349     {
1350         LogMcastS(rr, request, reg_start);
1351         re->next = request->u.reg_recs;
1352         request->u.reg_recs = re;
1353     }
1354     return err;
1355 }
1356 
1357 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
1358 
_return_regrecord_request_error(request_state * request,mStatus error)1359 mDNSlocal void _return_regrecord_request_error(request_state *request, mStatus error)
1360 {
1361     reply_state *rep;
1362     if (GenerateNTDResponse(NULL, 0, request, &rep, reg_record_reply_op, 0, error) != mStatus_NoError)
1363     {
1364         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] DNSServiceRegisterRecord _return_regrecord_request_error: error(%d)", request->request_id, error);
1365     }
1366     else
1367     {
1368         append_reply(request, rep);
1369     }
1370 }
1371 
_handle_regrecord_request_with_trust(request_state * request,AuthRecord * rr)1372 mDNSlocal mStatus _handle_regrecord_request_with_trust(request_state *request, AuthRecord * rr)
1373 {
1374     mStatus err;
1375     if (audit_token_to_pid(request->audit_token) == 0)
1376     {
1377         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_regrecord_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
1378         err = _handle_regrecord_request_start(request, rr);
1379     }
1380     else
1381     {
1382         const char *service_ptr = NULL;
1383         char type_str[MAX_ESCAPED_DOMAIN_NAME] = "";
1384         domainlabel name;
1385         domainname type, domain;
1386         bool good = DeconstructServiceName(rr->resrec.name, &name, &type, &domain);
1387         if (good)
1388         {
1389             ConvertDomainNameToCString(&type, type_str);
1390             service_ptr = type_str;
1391         }
1392 
1393         mdns_trust_flags_t flags = mdns_trust_flags_none;
1394         mdns_trust_status_t status = mdns_trust_check_bonjour(request->audit_token, service_ptr, &flags);
1395         switch (status)
1396         {
1397             case mdns_trust_status_denied:
1398             case mdns_trust_status_pending:
1399             {
1400                 mdns_trust_t trust = mdns_trust_create(request->audit_token, service_ptr, flags);
1401                 if (!trust)
1402                 {
1403                     freeL("AuthRecord/_handle_regrecord_request_with_trust", rr);
1404                     err = mStatus_NoMemoryErr;
1405                     goto exit;
1406                 }
1407                 mdns_trust_set_context(trust, rr);
1408                 mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
1409                 mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
1410                 {
1411                     if (event == mdns_trust_event_result)
1412                     {
1413                         mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
1414                         KQueueLock();
1415                         AuthRecord * _rr =  mdns_trust_get_context(trust);
1416                         if (_rr)
1417                         {
1418                             if (!error)
1419                             {
1420                                 mdns_trust_set_context(trust, NULL); // _handle_regrecord_request_start handles free
1421                                 error = _handle_regrecord_request_start(request, _rr);
1422                                 // No context means the request was canceled before we got here
1423                             }
1424                             if (error) // (not else if) Always check for error result
1425                             {
1426                                 _return_regrecord_request_error(request, error);
1427                             }
1428                         }
1429                         KQueueUnlock("_handle_regrecord_request_with_trust");
1430                     }
1431                 });
1432                 request->trust = trust;
1433                 mdns_trust_activate(trust);
1434                 err = mStatus_NoError;
1435                 break;
1436             }
1437 
1438             case mdns_trust_status_no_entitlement:
1439                 err = mStatus_NoAuth;
1440                 break;
1441 
1442             case mdns_trust_status_granted:
1443                 err = _handle_regrecord_request_start(request, rr);
1444                 break;
1445 
1446             default:
1447                 err = mStatus_UnknownErr;
1448                 break;
1449         }
1450      }
1451 exit:
1452     return err;
1453 }
1454 #endif // TRUST_ENFORCEMENT
1455 
handle_regrecord_request(request_state * request)1456 mDNSlocal mStatus handle_regrecord_request(request_state *request)
1457 {
1458     mStatus err = mStatus_BadParamErr;
1459     AuthRecord *rr;
1460 
1461     if (request->terminate != connection_termination)
1462     { LogMsg("%3d: DNSServiceRegisterRecord(not a shared connection ref)", request->sd); return(err); }
1463 
1464     rr = read_rr_from_ipc_msg(request, 1, 1);
1465     if (rr)
1466     {
1467 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
1468         if (os_feature_enabled(mDNSResponder, bonjour_privacy) &&
1469             IsLocalDomain(rr->resrec.name))
1470         {
1471             err = _handle_regrecord_request_with_trust(request, rr);
1472         }
1473         else
1474         {
1475             err = _handle_regrecord_request_start(request, rr);
1476         }
1477 #else
1478         err = _handle_regrecord_request_start(request, rr);
1479 #endif
1480     }
1481     return(err);
1482 }
1483 
1484 mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m);
1485 
regservice_termination_callback(request_state * request)1486 mDNSlocal void regservice_termination_callback(request_state *request)
1487 {
1488     if (!request)
1489     {
1490         LogMsg("regservice_termination_callback context is NULL");
1491         return;
1492     }
1493     while (request->u.servicereg.instances)
1494     {
1495         service_instance *p = request->u.servicereg.instances;
1496         request->u.servicereg.instances = request->u.servicereg.instances->next;
1497         // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
1498         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceRegister(" PRI_DM_NAME ", %u) STOP PID[%d](" PUB_S ")",
1499                request->request_id, DM_NAME_PARAM(p->srs.RR_SRV.resrec.name),
1500                mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port), request->process_id, request->pid_name);
1501 
1502 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1503         external_stop_advertising_helper(p);
1504 #endif
1505 
1506         // Clear backpointer *before* calling mDNS_DeregisterService/unlink_and_free_service_instance
1507         // We don't need unlink_and_free_service_instance to cut its element from the list, because we're already advancing
1508         // request->u.servicereg.instances as we work our way through the list, implicitly cutting one element at a time
1509         // We can't clear p->request *after* the calling mDNS_DeregisterService/unlink_and_free_service_instance
1510         // because by then we might have already freed p
1511         p->request = NULL;
1512         LogMcastS(&p->srs.RR_SRV, request, reg_stop);
1513         if (mDNS_DeregisterService(&mDNSStorage, &p->srs))
1514         {
1515             unlink_and_free_service_instance(p);
1516             // Don't touch service_instance *p after this -- it's likely to have been freed already
1517         }
1518     }
1519     if (request->u.servicereg.txtdata)
1520     {
1521         freeL("service_info txtdata", request->u.servicereg.txtdata);
1522         request->u.servicereg.txtdata = NULL;
1523     }
1524     if (request->u.servicereg.autoname)
1525     {
1526         // Clear autoname before calling UpdateDeviceInfoRecord() so it doesn't mistakenly include this in its count of active autoname registrations
1527         request->u.servicereg.autoname = mDNSfalse;
1528         UpdateDeviceInfoRecord(&mDNSStorage);
1529     }
1530 }
1531 
LocateSubordinateRequest(request_state * request)1532 mDNSlocal request_state *LocateSubordinateRequest(request_state *request)
1533 {
1534     request_state *req;
1535     for (req = all_requests; req; req = req->next)
1536         if (req->primary == request &&
1537             req->hdr.client_context.u32[0] == request->hdr.client_context.u32[0] &&
1538             req->hdr.client_context.u32[1] == request->hdr.client_context.u32[1]) return(req);
1539     return(request);
1540 }
1541 
add_record_to_service(request_state * request,service_instance * instance,mDNSu16 rrtype,mDNSu16 rdlen,const mDNSu8 * const rdata,mDNSu32 ttl)1542 mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen,
1543     const mDNSu8 *const rdata, mDNSu32 ttl)
1544 {
1545     ServiceRecordSet *srs = &instance->srs;
1546     mStatus result;
1547     const size_t rdcapacity = (rdlen > sizeof(RDataBody2)) ? rdlen : sizeof(RDataBody2);
1548     ExtraResourceRecord *extra = (ExtraResourceRecord *)callocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + rdcapacity);
1549     if (!extra) { my_perror("ERROR: calloc"); return mStatus_NoMemoryErr; }
1550 
1551     extra->r.resrec.rrtype = rrtype;
1552     extra->r.resrec.rdata = &extra->r.rdatastorage;
1553     extra->r.resrec.rdata->MaxRDLength = (mDNSu16)rdcapacity;
1554     extra->r.resrec.rdlength = rdlen;
1555     if (!SetRData(mDNSNULL, rdata, rdata + rdlen, &extra->r.resrec, rdlen))
1556     {
1557         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
1558             "[R%u] read_rr_from_ipc_msg: SetRData failed for " PRI_DM_NAME " (" PUB_S ")",
1559             request->request_id, DM_NAME_PARAM(request->u.servicereg.instances ?
1560             request->u.servicereg.instances->srs.RR_SRV.resrec.name : mDNSNULL), DNSTypeName(rrtype));
1561         freeL("ExtraResourceRecord/add_record_to_service", extra);
1562         return mStatus_BadParamErr;
1563     }
1564     SetNewRData(&extra->r.resrec, mDNSNULL, 0);  // Sets rr->rdatahash for us
1565     // use InterfaceID value from DNSServiceRegister() call that created the original service
1566     extra->r.resrec.InterfaceID = request->u.servicereg.InterfaceID;
1567 
1568     result = mDNS_AddRecordToService(&mDNSStorage, srs, extra, &extra->r.rdatastorage, ttl, request->flags);
1569     if (result)
1570     {
1571         freeL("ExtraResourceRecord/add_record_to_service", extra);
1572         return result;
1573     }
1574     LogMcastS(&srs->RR_PTR, request, reg_start);
1575 
1576     extra->ClientID = request->hdr.reg_index;
1577 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1578     if (   instance->external_advertise
1579            && callExternalHelpers(request->u.servicereg.InterfaceID, &instance->domain, request->flags))
1580     {
1581         LogInfo("add_record_to_service: calling external_start_advertising_service");
1582         external_start_advertising_service(&extra->r.resrec, request->flags, request->process_id);
1583     }
1584 #endif
1585     return result;
1586 }
1587 
handle_add_request(request_state * request)1588 mDNSlocal mStatus handle_add_request(request_state *request)
1589 {
1590     service_instance *i;
1591     mStatus result = mStatus_UnknownErr;
1592     DNSServiceFlags flags  = get_flags (&request->msgptr, request->msgend);
1593     mDNSu16 rrtype = get_uint16(&request->msgptr, request->msgend);
1594     mDNSu16 rdlen  = get_uint16(&request->msgptr, request->msgend);
1595     const mDNSu8 *const rdata = (const mDNSu8 *)get_rdata(&request->msgptr, request->msgend, rdlen);
1596     mDNSu32 ttl    = get_uint32(&request->msgptr, request->msgend);
1597     if (!ttl) ttl = DefaultTTLforRRType(rrtype);
1598     (void)flags; // Unused
1599 
1600     if (!request->msgptr)
1601     {
1602         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1603                "[R%d] DNSServiceAddRecord(unreadable parameters)", request->request_id);
1604         return(mStatus_BadParamErr);
1605     }
1606 
1607     // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
1608     if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
1609 
1610     if (request->terminate != regservice_termination_callback)
1611     {
1612         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1613                "[R%d] DNSServiceAddRecord(not a registered service ref)", request->request_id);
1614         return(mStatus_BadParamErr);
1615     }
1616 
1617     // For a service registered with zero port, don't allow adding records. This mostly happens due to a bug
1618     // in the application. See radar://9165807.
1619     if (mDNSIPPortIsZero(request->u.servicereg.port))
1620     {
1621         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1622                "[R%d] DNSServiceAddRecord: adding record to a service registered with zero port", request->request_id);
1623         return(mStatus_BadParamErr);
1624     }
1625     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
1626            "[R%d] DNSServiceAddRecord(%X, " PRI_DM_NAME ", " PUB_S ", %d) PID[%d](" PUB_S ")",
1627            request->request_id, flags,
1628            DM_NAME_PARAM((request->u.servicereg.instances) ? (request->u.servicereg.instances->srs.RR_SRV.resrec.name) : mDNSNULL),
1629            DNSTypeName(rrtype), rdlen, request->process_id, request->pid_name);
1630 
1631     for (i = request->u.servicereg.instances; i; i = i->next)
1632     {
1633         result = add_record_to_service(request, i, rrtype, rdlen, rdata, ttl);
1634         if (result && i->default_local) break;
1635         else result = mStatus_NoError;  // suppress non-local default errors
1636     }
1637 
1638     return(result);
1639 }
1640 
update_callback(mDNS * const m,AuthRecord * const rr,RData * oldrd,mDNSu16 oldrdlen)1641 mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd, mDNSu16 oldrdlen)
1642 {
1643     mDNSBool external_advertise = (rr->UpdateContext) ? *((mDNSBool *)rr->UpdateContext) : mDNSfalse;
1644     (void)m; // Unused
1645 
1646     // There are three cases.
1647     //
1648     // 1. We have updated the primary TXT record of the service
1649     // 2. We have updated the TXT record that was added to the service using DNSServiceAddRecord
1650     // 3. We have updated the TXT record that was registered using DNSServiceRegisterRecord
1651     //
1652     // external_advertise is set if we have advertised at least once during the initial addition
1653     // of the record in all of the three cases above. We should have checked for InterfaceID/LocalDomain
1654     // checks during the first time and hence we don't do any checks here
1655     if (external_advertise)
1656     {
1657         ResourceRecord ext = rr->resrec;
1658 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1659         DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(rr->ARType);
1660 #endif
1661 
1662         if (ext.rdlength == oldrdlen && mDNSPlatformMemSame(&ext.rdata->u, &oldrd->u, oldrdlen)) goto exit;
1663         SetNewRData(&ext, oldrd, oldrdlen);
1664 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1665         external_stop_advertising_service(&ext, flags, 0);
1666         LogInfo("update_callback: calling external_start_advertising_service");
1667         external_start_advertising_service(&rr->resrec, flags, 0);
1668 #endif
1669     }
1670 exit:
1671     if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
1672 }
1673 
update_record(AuthRecord * ar,mDNSu16 rdlen,const mDNSu8 * const rdata,mDNSu32 ttl,const mDNSBool * const external_advertise,const mDNSu32 request_id)1674 mDNSlocal mStatus update_record(AuthRecord *ar, mDNSu16 rdlen, const mDNSu8 *const rdata, mDNSu32 ttl,
1675     const mDNSBool *const external_advertise, const mDNSu32 request_id)
1676 {
1677     ResourceRecord rr;
1678     mStatus result;
1679     const size_t rdcapacity = (rdlen > sizeof(RDataBody2)) ? rdlen : sizeof(RDataBody2);
1680     RData *newrd = (RData *) callocL("RData/update_record", sizeof(*newrd) - sizeof(RDataBody) + rdcapacity);
1681     if (!newrd) FatalError("ERROR: calloc");
1682     mDNSPlatformMemZero(&rr, (mDNSu32)sizeof(rr));
1683     rr.name     = ar->resrec.name;
1684     rr.rrtype   = ar->resrec.rrtype;
1685     rr.rrclass  = ar->resrec.rrclass;
1686     rr.rdata    = newrd;
1687     rr.rdata->MaxRDLength = (mDNSu16)rdcapacity;
1688     rr.rdlength = rdlen;
1689     if (!SetRData(mDNSNULL, rdata, rdata + rdlen, &rr, rdlen))
1690     {
1691         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
1692             "[R%u] update_record: SetRData failed for " PRI_DM_NAME " (" PUB_S ")",
1693             request_id, DM_NAME_PARAM(rr.name), DNSTypeName(rr.rrtype));
1694         freeL("RData/update_record", newrd);
1695         return mStatus_BadParamErr;
1696     }
1697     rdlen = GetRDLength(&rr, mDNSfalse);
1698     // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1699     // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1700     // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1701     if (ar->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
1702 
1703     if (external_advertise) ar->UpdateContext = (void *)external_advertise;
1704 
1705     result = mDNS_Update(&mDNSStorage, ar, ttl, rdlen, newrd, update_callback);
1706     if (result) { LogMsg("update_record: Error %d for %s", (int)result, ARDisplayString(&mDNSStorage, ar)); freeL("RData/update_record", newrd); }
1707     return result;
1708 }
1709 
handle_update_request(request_state * request)1710 mDNSlocal mStatus handle_update_request(request_state *request)
1711 {
1712     const ipc_msg_hdr *const hdr = &request->hdr;
1713     mStatus result = mStatus_BadReferenceErr;
1714     service_instance *i;
1715     AuthRecord *rr = NULL;
1716 
1717     // get the message data
1718     DNSServiceFlags flags = get_flags (&request->msgptr, request->msgend);  // flags unused
1719     mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
1720     const mDNSu8 *const rdata = (const mDNSu8 *)get_rdata(&request->msgptr, request->msgend, rdlen);
1721     mDNSu32 ttl   = get_uint32(&request->msgptr, request->msgend);
1722     (void)flags; // Unused
1723 
1724     if (!request->msgptr)
1725     {
1726         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1727                "[R%d] DNSServiceUpdateRecord(unreadable parameters)", request->request_id);
1728         return(mStatus_BadParamErr);
1729     }
1730 
1731     // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
1732     if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
1733 
1734     if (request->terminate == connection_termination)
1735     {
1736         // update an individually registered record
1737         registered_record_entry *reptr;
1738         for (reptr = request->u.reg_recs; reptr; reptr = reptr->next)
1739         {
1740             if (reptr->key == hdr->reg_index)
1741             {
1742                 result = update_record(reptr->rr, rdlen, rdata, ttl, &reptr->external_advertise, request->request_id);
1743                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1744                        "[R%d] DNSServiceUpdateRecord(" PRI_DM_NAME ", " PUB_S ") PID[%d](" PUB_S ")",
1745                        request->request_id, DM_NAME_PARAM(reptr->rr->resrec.name),
1746                        reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>",
1747                        request->process_id, request->pid_name);
1748                 goto end;
1749             }
1750         }
1751         result = mStatus_BadReferenceErr;
1752         goto end;
1753     }
1754 
1755     if (request->terminate != regservice_termination_callback)
1756     {
1757         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1758                "[R%d] DNSServiceUpdateRecord(not a registered service ref)", request->request_id);
1759         return(mStatus_BadParamErr);
1760     }
1761 
1762     // For a service registered with zero port, only SRV record is initialized. Don't allow any updates.
1763     if (mDNSIPPortIsZero(request->u.servicereg.port))
1764     {
1765         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1766                "[R%d] DNSServiceUpdateRecord: updating the record of a service registered with zero port", request->request_id);
1767         return(mStatus_BadParamErr);
1768     }
1769 
1770     // update the saved off TXT data for the service
1771     if (hdr->reg_index == TXT_RECORD_INDEX)
1772     {
1773         if (request->u.servicereg.txtdata)
1774         { freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; }
1775         if (rdlen > 0)
1776         {
1777             request->u.servicereg.txtdata = mallocL("service_info txtdata", rdlen);
1778             if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_update_request - malloc");
1779             mDNSPlatformMemCopy(request->u.servicereg.txtdata, rdata, rdlen);
1780         }
1781         request->u.servicereg.txtlen = rdlen;
1782     }
1783 
1784     // update a record from a service record set
1785     for (i = request->u.servicereg.instances; i; i = i->next)
1786     {
1787         if (hdr->reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
1788         else
1789         {
1790             ExtraResourceRecord *e;
1791             for (e = i->srs.Extras; e; e = e->next)
1792                 if (e->ClientID == hdr->reg_index) { rr = &e->r; break; }
1793         }
1794 
1795         if (!rr) { result = mStatus_BadReferenceErr; goto end; }
1796         result = update_record(rr, rdlen, rdata, ttl, &i->external_advertise, request->request_id);
1797         if (result && i->default_local) goto end;
1798         else result = mStatus_NoError;  // suppress non-local default errors
1799     }
1800 
1801 end:
1802     if (request->terminate == regservice_termination_callback)
1803         LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)  PID[%d](%s)", request->sd,
1804                      (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
1805                      rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>",
1806                      request->process_id, request->pid_name);
1807 
1808     return(result);
1809 }
1810 
1811 // remove a resource record registered via DNSServiceRegisterRecord()
remove_record(request_state * request)1812 mDNSlocal mStatus remove_record(request_state *request)
1813 {
1814     mStatus err = mStatus_UnknownErr;
1815     registered_record_entry *e, **ptr = &request->u.reg_recs;
1816 
1817     while (*ptr && (*ptr)->key != request->hdr.reg_index) ptr = &(*ptr)->next;
1818     if (!*ptr) { LogMsg("%3d: DNSServiceRemoveRecord(%u) not found", request->sd, request->hdr.reg_index); return mStatus_BadReferenceErr; }
1819     e = *ptr;
1820     *ptr = e->next; // unlink
1821 
1822     LogOperation("%3d: DNSServiceRemoveRecord(%u %s)  PID[%d](%s)",
1823                 request->sd, e->key, RRDisplayString(&mDNSStorage, &e->rr->resrec), request->process_id, request->pid_name);
1824     e->rr->RecordContext = NULL;
1825     if (e->external_advertise)
1826     {
1827 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1828         external_stop_advertising_service(&e->rr->resrec, request->flags, request->process_id);
1829 #endif
1830         e->external_advertise = mDNSfalse;
1831     }
1832     LogMcastS(e->rr, request, reg_stop);
1833     err = mDNS_Deregister(&mDNSStorage, e->rr);     // Will free e->rr for us; we're responsible for freeing e
1834     if (err)
1835     {
1836         LogMsg("ERROR: remove_record, mDNS_Deregister: %d", err);
1837         freeL("registered_record_entry AuthRecord remove_record", e->rr);
1838     }
1839     freeL("registered_record_entry remove_record", e);
1840     return err;
1841 }
1842 
remove_extra(const request_state * const request,service_instance * const serv,mDNSu16 * const rrtype)1843 mDNSlocal mStatus remove_extra(const request_state *const request, service_instance *const serv, mDNSu16 *const rrtype)
1844 {
1845     mStatus err = mStatus_BadReferenceErr;
1846     ExtraResourceRecord *ptr;
1847 
1848     for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
1849     {
1850         if (ptr->ClientID == request->hdr.reg_index) // found match
1851         {
1852             *rrtype = ptr->r.resrec.rrtype;
1853 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
1854             if (serv->external_advertise)
1855             {
1856                 external_stop_advertising_service(&ptr->r.resrec, request->flags, request->process_id);
1857             }
1858 #endif
1859             err = mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
1860             break;
1861         }
1862     }
1863     return err;
1864 }
1865 
handle_removerecord_request(request_state * request)1866 mDNSlocal mStatus handle_removerecord_request(request_state *request)
1867 {
1868     mStatus err = mStatus_BadReferenceErr;
1869     get_flags(&request->msgptr, request->msgend);   // flags unused
1870 
1871     if (!request->msgptr)
1872     {
1873         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1874                "[R%d] DNSServiceRemoveRecord(unreadable parameters)", request->request_id);
1875         return(mStatus_BadParamErr);
1876     }
1877 
1878     // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
1879     if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
1880 
1881     if (request->terminate == connection_termination)
1882         err = remove_record(request);  // remove individually registered record
1883     else if (request->terminate != regservice_termination_callback)
1884     {
1885         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
1886                "[R%d] DNSServiceRemoveRecord(not a registered service ref)", request->request_id);
1887         return(mStatus_BadParamErr);
1888     }
1889     else
1890     {
1891         service_instance *i;
1892         mDNSu16 rrtype = 0;
1893         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceRemoveRecord(" PRI_DM_NAME ", " PUB_S ") PID[%d](" PUB_S ")",
1894                request->request_id,
1895                DM_NAME_PARAM((request->u.servicereg.instances) ? (request->u.servicereg.instances->srs.RR_SRV.resrec.name) : mDNSNULL),
1896                rrtype ? DNSTypeName(rrtype) : "<NONE>", request->process_id, request->pid_name);
1897         for (i = request->u.servicereg.instances; i; i = i->next)
1898         {
1899             err = remove_extra(request, i, &rrtype);
1900             if (err && i->default_local) break;
1901             else err = mStatus_NoError;  // suppress non-local default errors
1902         }
1903     }
1904 
1905     return(err);
1906 }
1907 
1908 // If there's a comma followed by another character,
1909 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1910 // Otherwise, it returns a pointer to the final nul at the end of the string
FindFirstSubType(char * p)1911 mDNSlocal char *FindFirstSubType(char *p)
1912 {
1913     while (*p)
1914     {
1915         if (p[0] == '\\' && p[1])
1916         {
1917              p += 2;
1918         }
1919         else if (p[0] == ',' && p[1])
1920         {
1921             *p++ = 0;
1922             return(p);
1923         }
1924         else
1925         {
1926             p++;
1927         }
1928     }
1929     return(p);
1930 }
1931 
1932 // If there's a comma followed by another character,
1933 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1934 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1935 // Otherwise, it returns a pointer to the final nul at the end of the string
FindNextSubType(char * p)1936 mDNSlocal char *FindNextSubType(char *p)
1937 {
1938     while (*p)
1939     {
1940         if (p[0] == '\\' && p[1])       // If escape character
1941             p += 2;                     // ignore following character
1942         else if (p[0] == ',')           // If we found a comma
1943         {
1944             if (p[1]) *p++ = 0;
1945             return(p);
1946         }
1947         else if (p[0] == '.')
1948             return(mDNSNULL);
1949         else p++;
1950     }
1951     return(p);
1952 }
1953 
1954 // Returns -1 if illegal subtype found
ChopSubTypes(char * regtype)1955 mDNSlocal mDNSs32 ChopSubTypes(char *regtype)
1956 {
1957     mDNSs32 NumSubTypes = 0;
1958     char *stp = FindFirstSubType(regtype);
1959     while (stp && *stp)                 // If we found a comma...
1960     {
1961         if (*stp == ',') return(-1);
1962         NumSubTypes++;
1963         stp = FindNextSubType(stp);
1964     }
1965     if (!stp) return(-1);
1966     return(NumSubTypes);
1967 }
1968 
AllocateSubTypes(mDNSs32 NumSubTypes,char * p)1969 mDNSlocal AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
1970 {
1971     AuthRecord *st = mDNSNULL;
1972     if (NumSubTypes)
1973     {
1974         mDNSs32 i;
1975         st = (AuthRecord *) callocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
1976         if (!st) return(mDNSNULL);
1977         for (i = 0; i < NumSubTypes; i++)
1978         {
1979             mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL);
1980             while (*p) p++;
1981             p++;
1982             if (!MakeDomainNameFromDNSNameString(&st[i].namestorage, p))
1983             {
1984                 freeL("ServiceSubTypes", st);
1985                 return(mDNSNULL);
1986             }
1987         }
1988     }
1989     return(st);
1990 }
1991 
register_service_instance(request_state * request,const domainname * domain)1992 mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
1993 {
1994     service_instance **ptr, *instance;
1995     size_t extra_size = (request->u.servicereg.txtlen > sizeof(RDataBody)) ? (request->u.servicereg.txtlen - sizeof(RDataBody)) : 0;
1996     const mDNSBool DomainIsLocal = SameDomainName(domain, &localdomain);
1997     mStatus result;
1998     mDNSInterfaceID interfaceID = request->u.servicereg.InterfaceID;
1999 
2000     // If the client specified an interface, but no domain, then we honor the specified interface for the "local" (mDNS)
2001     // registration but for the wide-area registrations we don't (currently) have any concept of a wide-area unicast
2002     // registrations scoped to a specific interface, so for the automatic domains we add we must *not* specify an interface.
2003     // (Specifying an interface with an apparently wide-area domain (i.e. something other than "local")
2004     // currently forces the registration to use mDNS multicast despite the apparently wide-area domain.)
2005     if (request->u.servicereg.default_domain && !DomainIsLocal) interfaceID = mDNSInterface_Any;
2006 
2007     for (ptr = &request->u.servicereg.instances; *ptr; ptr = &(*ptr)->next)
2008     {
2009         if (SameDomainName(&(*ptr)->domain, domain))
2010         {
2011             LogMsg("register_service_instance: domain %##s already registered for %#s.%##s",
2012                    domain->c, &request->u.servicereg.name, &request->u.servicereg.type);
2013             return mStatus_AlreadyRegistered;
2014         }
2015     }
2016 
2017     instance = (service_instance *) callocL("service_instance", sizeof(*instance) + extra_size);
2018     if (!instance) { my_perror("ERROR: calloc"); return mStatus_NoMemoryErr; }
2019 
2020     instance->next                          = mDNSNULL;
2021     instance->request                       = request;
2022     instance->renameonmemfree               = 0;
2023     instance->clientnotified                = mDNSfalse;
2024     instance->default_local                 = (request->u.servicereg.default_domain && DomainIsLocal);
2025     instance->external_advertise            = mDNSfalse;
2026     AssignDomainName(&instance->domain, domain);
2027 
2028     instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
2029 
2030     if (request->u.servicereg.num_subtypes && !instance->subtypes)
2031     {
2032         unlink_and_free_service_instance(instance);
2033         instance = NULL;
2034         FatalError("ERROR: malloc");
2035     }
2036 
2037     result = mDNS_RegisterService(&mDNSStorage, &instance->srs,
2038                                   &request->u.servicereg.name, &request->u.servicereg.type, domain,
2039                                   request->u.servicereg.host.c[0] ? &request->u.servicereg.host : NULL,
2040                                   request->u.servicereg.port,
2041                                   mDNSNULL, request->u.servicereg.txtdata, request->u.servicereg.txtlen,
2042                                   instance->subtypes, request->u.servicereg.num_subtypes,
2043                                   interfaceID, regservice_callback, instance, request->flags);
2044 
2045     if (!result)
2046     {
2047         *ptr = instance;        // Append this to the end of our request->u.servicereg.instances list
2048         LogOperation("%3d: DNSServiceRegister(%##s, %u) ADDED", instance->request->sd,
2049                      instance->srs.RR_SRV.resrec.name->c, mDNSVal16(request->u.servicereg.port));
2050         LogMcastS(&instance->srs.RR_SRV, request, reg_start);
2051     }
2052     else
2053     {
2054         LogMsg("register_service_instance %#s.%##s%##s error %d",
2055                &request->u.servicereg.name, &request->u.servicereg.type, domain->c, result);
2056         unlink_and_free_service_instance(instance);
2057     }
2058 
2059     return result;
2060 }
2061 
udsserver_default_reg_domain_changed(const DNameListElem * const d,const mDNSBool add)2062 mDNSlocal void udsserver_default_reg_domain_changed(const DNameListElem *const d, const mDNSBool add)
2063 {
2064     request_state *request;
2065 
2066     LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->name.c);
2067     for (request = all_requests; request; request = request->next)
2068     {
2069         if (request->terminate != regservice_termination_callback) continue;
2070         if (!request->u.servicereg.default_domain) continue;
2071         if (!d->uid || SystemUID(request->uid) || request->uid == d->uid)
2072         {
2073             service_instance **ptr = &request->u.servicereg.instances;
2074             while (*ptr && !SameDomainName(&(*ptr)->domain, &d->name)) ptr = &(*ptr)->next;
2075             if (add)
2076             {
2077                 // If we don't already have this domain in our list for this registration, add it now
2078                 if (!*ptr) register_service_instance(request, &d->name);
2079                 else debugf("udsserver_default_reg_domain_changed %##s already in list, not re-adding", &d->name);
2080             }
2081             else
2082             {
2083                 // Normally we should not fail to find the specified instance
2084                 // One case where this can happen is if a uDNS update fails for some reason,
2085                 // and regservice_callback then calls unlink_and_free_service_instance and disposes of that instance.
2086                 if (!*ptr)
2087                     LogMsg("udsserver_default_reg_domain_changed domain %##s not found for service %#s type %s",
2088                            &d->name, request->u.servicereg.name.c, request->u.servicereg.type_as_string);
2089                 else
2090                 {
2091                     DNameListElem *p;
2092                     for (p = AutoRegistrationDomains; p; p=p->next)
2093                         if (!p->uid || SystemUID(request->uid) || request->uid == p->uid)
2094                             if (SameDomainName(&d->name, &p->name)) break;
2095                     if (p) debugf("udsserver_default_reg_domain_changed %##s still in list, not removing", &d->name);
2096                     else
2097                     {
2098                         mStatus err;
2099                         service_instance *si = *ptr;
2100                         *ptr = si->next;
2101                         if (si->clientnotified) SendServiceRemovalNotification(&si->srs); // Do this *before* clearing si->request backpointer
2102                         // Now that we've cut this service_instance from the list, we MUST clear the si->request backpointer.
2103                         // Otherwise what can happen is this: While our mDNS_DeregisterService is in the
2104                         // process of completing asynchronously, the client cancels the entire operation, so
2105                         // regservice_termination_callback then runs through the whole list deregistering each
2106                         // instance, clearing the backpointers, and then disposing the parent request_state object.
2107                         // However, because this service_instance isn't in the list any more, regservice_termination_callback
2108                         // has no way to find it and clear its backpointer, and then when our mDNS_DeregisterService finally
2109                         // completes later with a mStatus_MemFree message, it calls unlink_and_free_service_instance() with
2110                         // a service_instance with a stale si->request backpointer pointing to memory that's already been freed.
2111                         si->request = NULL;
2112                         err = mDNS_DeregisterService(&mDNSStorage, &si->srs);
2113                         if (err) { LogMsg("udsserver_default_reg_domain_changed err %d", err); unlink_and_free_service_instance(si); }
2114                     }
2115                 }
2116             }
2117         }
2118     }
2119 }
2120 
2121 // Returns true if the interfaceIndex value matches one of the pre-defined
2122 // special values listed in the switch statement below.
PreDefinedInterfaceIndex(mDNSu32 interfaceIndex)2123 mDNSlocal mDNSBool PreDefinedInterfaceIndex(mDNSu32 interfaceIndex)
2124 {
2125     switch(interfaceIndex)
2126     {
2127         case kDNSServiceInterfaceIndexAny:
2128         case kDNSServiceInterfaceIndexLocalOnly:
2129         case kDNSServiceInterfaceIndexUnicast:
2130         case kDNSServiceInterfaceIndexP2P:
2131         case kDNSServiceInterfaceIndexBLE:
2132             return mDNStrue;
2133         default:
2134             return mDNSfalse;
2135     }
2136 }
2137 
_handle_regservice_request_start(request_state * request,const domainname * const d)2138 mDNSlocal mStatus _handle_regservice_request_start(request_state *request, const domainname * const d)
2139 {
2140     mStatus err;
2141 
2142     request->terminate = regservice_termination_callback;
2143     err = register_service_instance(request, d);
2144 
2145 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
2146     ++curr_num_regservices;
2147     if (curr_num_regservices > max_num_regservices)
2148         max_num_regservices = curr_num_regservices;
2149 #endif
2150 
2151 #if 0
2152     err = AuthorizedDomain(request, d, AutoRegistrationDomains) ? register_service_instance(request, d) : mStatus_NoError;
2153 #endif
2154     if (!err)
2155     {
2156         if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage);
2157 
2158         if (request->u.servicereg.default_domain)
2159         {
2160             DNameListElem *ptr;
2161             // Note that we don't report errors for non-local, non-explicit domains
2162             for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
2163                 if (!ptr->uid || SystemUID(request->uid) || request->uid == ptr->uid)
2164                     register_service_instance(request, &ptr->name);
2165         }
2166     }
2167     return err;
2168 }
2169 
2170 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
2171 
_return_regservice_request_error(request_state * request,mStatus error)2172 mDNSlocal void _return_regservice_request_error(request_state *request, mStatus error)
2173 {
2174     if (request->u.servicereg.txtdata)
2175     {
2176         freeL("service_info txtdata", request->u.servicereg.txtdata);
2177         request->u.servicereg.txtdata = NULL;
2178     }
2179 
2180     reply_state *rep;
2181     if (GenerateNTDResponse(NULL, 0, request, &rep, reg_service_reply_op, 0, error) != mStatus_NoError)
2182     {
2183         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] DNSServiceRegister _return_regservice_request_error: error(%d)", request->request_id, error);
2184     }
2185     else
2186     {
2187         append_reply(request, rep);
2188     }
2189 }
2190 
_handle_regservice_request_with_trust(request_state * request,const domainname * const d)2191 mDNSlocal mStatus _handle_regservice_request_with_trust(request_state *request, const domainname * const d)
2192 {
2193     mStatus err;
2194     if (audit_token_to_pid(request->audit_token) == 0)
2195     {
2196         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_regservice_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
2197         err = _handle_regservice_request_start(request, d);
2198     }
2199     else
2200     {
2201         mdns_trust_flags_t flags = mdns_trust_flags_none;
2202         mdns_trust_status_t status = mdns_trust_check_register_service(request->audit_token, request->u.servicereg.type_as_string, &flags);
2203         switch (status) {
2204             case mdns_trust_status_denied:
2205             case mdns_trust_status_pending:
2206             {
2207                 mdns_trust_t trust = mdns_trust_create(request->audit_token, request->u.servicereg.type_as_string, flags);
2208                 if (!trust)
2209                 {
2210                     err = mStatus_NoMemoryErr;
2211                     goto exit;
2212                 }
2213                 void * context = mallocL("context/_handle_regservice_request_with_trust", sizeof(domainname));
2214                 if (!context)
2215                 {
2216                     my_perror("ERROR: mallocL context/_handle_regservice_request_with_trust");
2217                     mdns_release(trust);
2218                     err = mStatus_NoMemoryErr;
2219                     goto exit;
2220                 }
2221                 memcpy(context, d, sizeof(domainname));
2222                 mdns_trust_set_context(trust, context);
2223 
2224                 mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
2225                 mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
2226                 {
2227                     if (event == mdns_trust_event_result)
2228                     {
2229                         mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
2230                         KQueueLock();
2231                         const domainname * _d = mdns_trust_get_context(trust);
2232                         if (_d)
2233                         {
2234                             if (!error)
2235                             {
2236                                 error = _handle_regservice_request_start(request, _d);
2237                                 // No context means the request was canceled before we got here
2238                             }
2239                             if (error) // (not else if) Always check for error result
2240                             {
2241                                 _return_regservice_request_error(request, error);
2242                             }
2243                         }
2244                         KQueueUnlock("_register_service_instance_with_trust");
2245                     }
2246                 });
2247                 request->trust = trust;
2248                 mdns_trust_activate(trust);
2249                 err = mStatus_NoError;
2250                 break;
2251             }
2252 
2253             case mdns_trust_status_no_entitlement:
2254                 err = mStatus_NoAuth;
2255                 break;
2256 
2257             case mdns_trust_status_granted:
2258                 err = _handle_regservice_request_start(request, d);
2259                 break;
2260 
2261             default:
2262                 err = mStatus_UnknownErr;
2263                 break;
2264         }
2265     }
2266 exit:
2267     return err;
2268 }
2269 #endif // TRUST_ENFORCEMENT
2270 
handle_regservice_request(request_state * request)2271 mDNSlocal mStatus handle_regservice_request(request_state *request)
2272 {
2273     char name[256]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
2274     char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
2275     char type_as_string[MAX_ESCAPED_DOMAIN_NAME];  // Note that this service type may include a trailing list of subtypes
2276     domainname d, srv;
2277     mStatus err;
2278     const char *msgTXTData;
2279 
2280     DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
2281     mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
2282     mDNSInterfaceID InterfaceID;
2283 
2284     // Map kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny with the
2285     // kDNSServiceFlagsIncludeP2P flag set.
2286     if (interfaceIndex == kDNSServiceInterfaceIndexP2P)
2287     {
2288         LogOperation("handle_regservice_request: mapping kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny + kDNSServiceFlagsIncludeP2P");
2289         flags |= kDNSServiceFlagsIncludeP2P;
2290         interfaceIndex = kDNSServiceInterfaceIndexAny;
2291     }
2292 
2293     InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
2294 
2295     // The registration is scoped to a specific interface index, but the
2296     // interface is not currently in our list.
2297     if (interfaceIndex && !InterfaceID)
2298     {
2299         // If it's one of the specially defined inteface index values, just return an error.
2300         if (PreDefinedInterfaceIndex(interfaceIndex))
2301         {
2302             LogInfo("handle_regservice_request: bad interfaceIndex %d", interfaceIndex);
2303             return(mStatus_BadParamErr);
2304         }
2305 
2306         // Otherwise, use the specified interface index value and the registration will
2307         // be applied to that interface when it comes up.
2308         InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
2309         LogInfo("handle_regservice_request: registration pending for interface index %d", interfaceIndex);
2310     }
2311 
2312     if (get_string(&request->msgptr, request->msgend, name,           sizeof(name          )) < 0 ||
2313         get_string(&request->msgptr, request->msgend, type_as_string, sizeof(type_as_string)) < 0 ||
2314         get_string(&request->msgptr, request->msgend, domain,         sizeof(domain        )) < 0 ||
2315         get_string(&request->msgptr, request->msgend, host,           sizeof(host          )) < 0)
2316     { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
2317 
2318     request->flags = flags;
2319     request->interfaceIndex = interfaceIndex;
2320     request->u.servicereg.InterfaceID = InterfaceID;
2321     request->u.servicereg.instances = NULL;
2322     request->u.servicereg.txtlen  = 0;
2323     request->u.servicereg.txtdata = NULL;
2324     mDNSPlatformStrLCopy(request->u.servicereg.type_as_string, type_as_string, sizeof(request->u.servicereg.type_as_string));
2325 
2326     if (request->msgptr + 2 > request->msgend) request->msgptr = NULL;
2327     else
2328     {
2329         request->u.servicereg.port.b[0] = *request->msgptr++;
2330         request->u.servicereg.port.b[1] = *request->msgptr++;
2331     }
2332 
2333     request->u.servicereg.txtlen = get_uint16(&request->msgptr, request->msgend);
2334     msgTXTData = get_rdata(&request->msgptr, request->msgend, request->u.servicereg.txtlen);
2335 
2336     if (!request->msgptr) { LogMsg("%3d: DNSServiceRegister(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
2337 
2338     if (request->u.servicereg.txtlen)
2339     {
2340         request->u.servicereg.txtdata = mallocL("service_info txtdata", request->u.servicereg.txtlen);
2341         if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_regservice_request - malloc");
2342         mDNSPlatformMemCopy(request->u.servicereg.txtdata, msgTXTData, request->u.servicereg.txtlen);
2343     }
2344 
2345     // Check for sub-types after the service type
2346     request->u.servicereg.num_subtypes = ChopSubTypes(request->u.servicereg.type_as_string);    // Note: Modifies regtype string to remove trailing subtypes
2347     if (request->u.servicereg.num_subtypes < 0)
2348     {
2349         LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", request->u.servicereg.type_as_string);
2350         goto bad_param;
2351     }
2352 
2353     // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
2354     if (!*request->u.servicereg.type_as_string || !MakeDomainNameFromDNSNameString(&request->u.servicereg.type, request->u.servicereg.type_as_string))
2355     { LogMsg("ERROR: handle_regservice_request - type_as_string bad %s", request->u.servicereg.type_as_string); goto bad_param; }
2356 
2357     if (!name[0])
2358     {
2359         request->u.servicereg.name = mDNSStorage.nicelabel;
2360         request->u.servicereg.autoname = mDNStrue;
2361     }
2362     else
2363     {
2364         // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
2365         if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
2366         {
2367             int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
2368             name[newlen] = 0;
2369         }
2370         if (!MakeDomainLabelFromLiteralString(&request->u.servicereg.name, name))
2371         { LogMsg("ERROR: handle_regservice_request - name bad %s", name); goto bad_param; }
2372         request->u.servicereg.autoname = mDNSfalse;
2373     }
2374 
2375     if (*domain)
2376     {
2377         request->u.servicereg.default_domain = mDNSfalse;
2378         if (!MakeDomainNameFromDNSNameString(&d, domain))
2379         { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); goto bad_param; }
2380     }
2381     else
2382     {
2383         request->u.servicereg.default_domain = mDNStrue;
2384         MakeDomainNameFromDNSNameString(&d, "local.");
2385     }
2386 
2387     if (!ConstructServiceName(&srv, &request->u.servicereg.name, &request->u.servicereg.type, &d))
2388     {
2389         LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”",
2390                request->u.servicereg.name.c, request->u.servicereg.type.c, d.c); goto bad_param;
2391     }
2392 
2393     if (!MakeDomainNameFromDNSNameString(&request->u.servicereg.host, host))
2394     { LogMsg("ERROR: handle_regservice_request - host bad %s", host); goto bad_param; }
2395     request->u.servicereg.autorename       = (flags & kDNSServiceFlagsNoAutoRename    ) == 0;
2396     request->u.servicereg.allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
2397 
2398     // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
2399     // a port number of zero. When two instances of the protected client are allowed to run on one
2400     // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
2401     if (!mDNSIPPortIsZero(request->u.servicereg.port))
2402     {
2403         int count = CountExistingRegistrations(&srv, request->u.servicereg.port);
2404         if (count)
2405             LogMsg("Client application[%d](%s) registered %d identical instances of service %##s port %u.", request->process_id,
2406                    request->pid_name, count+1, srv.c, mDNSVal16(request->u.servicereg.port));
2407     }
2408 
2409 #if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
2410     // Determine if this request should be promoted to use BLE triggered feature.
2411     if (shouldUseBLE(InterfaceID, 0, &request->u.servicereg.type, &d))
2412     {
2413         request->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
2414         LogInfo("handle_regservice_request: registration promoted to use kDNSServiceFlagsAutoTrigger");
2415     }
2416 #endif  // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
2417 
2418     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
2419            "[R%d] DNSServiceRegister(%X, %d, \"" PRI_S "\", \"" PRI_S "\", \"" PRI_S "\", \"" PRI_S "\", %u) START PID[%d](" PUB_S ")",
2420            request->request_id, request->flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host,
2421            mDNSVal16(request->u.servicereg.port), request->process_id, request->pid_name);
2422 
2423     // We need to unconditionally set request->terminate, because even if we didn't successfully
2424     // start any registrations right now, subsequent configuration changes may cause successful
2425     // registrations to be added, and we'll need to cancel them before freeing this memory.
2426     // We also need to set request->terminate first, before adding additional service instances,
2427     // because the udsserver_validatelists uses the request->terminate function pointer to determine
2428     // what kind of request this is, and therefore what kind of list validation is required.
2429     request->terminate = NULL;
2430 
2431 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
2432     if (os_feature_enabled(mDNSResponder, bonjour_privacy) &&
2433         (request->u.servicereg.default_domain || IsLocalDomain(&d)))
2434     {
2435         err = _handle_regservice_request_with_trust(request, &d);
2436         if (err == mStatus_NoAuth && request->u.servicereg.txtdata)
2437         {
2438             freeL("service_info txtdata", request->u.servicereg.txtdata);
2439             request->u.servicereg.txtdata = NULL;
2440         }
2441     }
2442     else
2443     {
2444         err = _handle_regservice_request_start(request, &d);
2445     }
2446 #else
2447     err = _handle_regservice_request_start(request, &d);
2448 #endif
2449 
2450     return(err);
2451 
2452 bad_param:
2453     freeL("handle_regservice_request (txtdata)", request->u.servicereg.txtdata);
2454     request->u.servicereg.txtdata = NULL;
2455     return mStatus_BadParamErr;
2456 }
2457 
2458 // ***************************************************************************
2459 #if COMPILER_LIKES_PRAGMA_MARK
2460 #pragma mark -
2461 #pragma mark - DNSServiceBrowse
2462 #endif
2463 
FoundInstance(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)2464 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
2465 {
2466     DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : 0;
2467     request_state *req = question->QuestionContext;
2468     reply_state *rep;
2469     (void)m; // Unused
2470 
2471     if (answer->rrtype != kDNSType_PTR)
2472     { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
2473 
2474     if (mDNSOpaque16IsZero(question->TargetQID) && (question->BrowseThreshold > 0) && (question->CurrentAnswers >= question->BrowseThreshold))
2475     {
2476         flags |= kDNSServiceFlagsThresholdReached;
2477     }
2478 
2479     // if returning a negative answer, then use question's name in reply
2480     if (answer->RecordType == kDNSRecordTypePacketNegative)
2481     {
2482         GenerateBrowseReply(&question->qname, answer->InterfaceID, req, &rep, browse_reply_op, flags, kDNSServiceErr_NoSuchRecord);
2483         goto validReply;
2484     }
2485 
2486     if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError) != mStatus_NoError)
2487     {
2488         if (SameDomainName(&req->u.browser.regtype, (const domainname*)"\x09_services\x07_dns-sd\x04_udp"))
2489         {
2490             // Special support to enable the DNSServiceBrowse call made by Bonjour Browser
2491             // Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
2492             GenerateBrowseReply(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError);
2493             goto validReply;
2494         }
2495 
2496         LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
2497                req->sd, answer->name->c, answer->rdata->u.name.c);
2498         return;
2499     }
2500 
2501 validReply:
2502 
2503     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
2504            "[R%d->Q%d] DNSServiceBrowse(" PRI_DM_NAME ", " PUB_S ") RESULT " PUB_S " interface %d: " PRI_S,
2505            req->request_id, mDNSVal16(question->TargetQID), DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype),
2506            AddRecord ? "ADD" : "RMV", mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse),
2507            RRDisplayString(m, answer));
2508 
2509     append_reply(req, rep);
2510 }
2511 
SetQuestionPolicy(DNSQuestion * q,request_state * req)2512 mDNSlocal void SetQuestionPolicy(DNSQuestion *q, request_state *req)
2513 {
2514     q->euid = req->uid;
2515     // The policy is either based on pid or UUID. Pass a zero pid
2516     // to the "core" if the UUID is valid. If we always pass the pid,
2517     // then the "core" needs to determine whether the uuid is valid
2518     // by examining all the 16 bytes at the time of the policy
2519     // check and also when setting the delegate socket option. Also, it
2520     // requires that we zero out the uuid wherever the question is
2521     // initialized to make sure that it is not interpreted as valid.
2522     // To prevent these intrusive changes, just pass a zero pid to indicate
2523     // that pid is not valid when uuid is valid. In future if we need the
2524     // pid in the question, we will reevaluate this strategy.
2525     if (req->validUUID)
2526     {
2527         mDNSPlatformMemCopy(q->uuid, req->uuid, UUID_SIZE);
2528         q->pid = 0;
2529     }
2530     else
2531     {
2532         q->pid = req->process_id;
2533     }
2534 
2535     //debugf("SetQuestionPolicy: q->euid[%d] q->pid[%d] uuid is valid : %s", q->euid, q->pid, req->validUUID ? "true" : "false");
2536 }
2537 
add_domain_to_browser(request_state * info,const domainname * d)2538 mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d)
2539 {
2540     browser_t *b, *p;
2541     mStatus err;
2542 
2543     for (p = info->u.browser.browsers; p; p = p->next)
2544     {
2545         if (SameDomainName(&p->domain, d))
2546         { debugf("add_domain_to_browser %##s already in list", d->c); return mStatus_AlreadyRegistered; }
2547     }
2548 
2549     b = (browser_t *) callocL("browser_t", sizeof(*b));
2550     if (!b) return mStatus_NoMemoryErr;
2551     AssignDomainName(&b->domain, d);
2552     SetQuestionPolicy(&b->q, info);
2553     err = mDNS_StartBrowse(&mDNSStorage, &b->q, &info->u.browser.regtype, d, info->u.browser.interface_id, info->flags,
2554                             info->u.browser.ForceMCast, (info->flags & kDNSServiceFlagsBackgroundTrafficClass) != 0, FoundInstance, info);
2555     if (err)
2556     {
2557         LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->u.browser.regtype.c, d->c);
2558         freeL("browser_t/add_domain_to_browser", b);
2559     }
2560     else
2561     {
2562         b->next = info->u.browser.browsers;
2563         info->u.browser.browsers = b;
2564 
2565 #if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
2566         // Determine if this request should be promoted to use BLE triggered discovery.
2567         if (shouldUseBLE(info->u.browser.interface_id, 0, &info->u.browser.regtype, (domainname *) d))
2568         {
2569             info->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
2570             b->q.flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
2571             LogInfo("add_domain_to_browser: request promoted to use kDNSServiceFlagsAutoTrigger");
2572         }
2573 #endif  // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
2574 
2575         LogMcastQ(&b->q, info, q_start);
2576 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
2577         if (callExternalHelpers(info->u.browser.interface_id, &b->domain, info->flags))
2578         {
2579             domainname tmp;
2580             ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &b->domain);
2581             LogDebug("add_domain_to_browser: calling external_start_browsing_for_service()");
2582             external_start_browsing_for_service(info->u.browser.interface_id, &tmp, kDNSType_PTR, info->flags, info->process_id);
2583         }
2584 #endif
2585     }
2586     return err;
2587 }
2588 
browse_termination_callback(request_state * info)2589 mDNSlocal void browse_termination_callback(request_state *info)
2590 {
2591     if (info->u.browser.default_domain)
2592     {
2593         // Stop the domain enumeration queries to discover the WAB legacy browse domains
2594         LogInfo("%3d: DNSServiceBrowse Cancel WAB PID[%d](%s)", info->sd, info->process_id, info->pid_name);
2595         uDNS_StopWABQueries(&mDNSStorage, UDNS_WAB_LBROWSE_QUERY);
2596     }
2597     while (info->u.browser.browsers)
2598     {
2599         browser_t *ptr = info->u.browser.browsers;
2600 
2601 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
2602         if (callExternalHelpers(ptr->q.InterfaceID, &ptr->domain, ptr->q.flags))
2603         {
2604             domainname tmp;
2605             ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &ptr->domain);
2606             LogInfo("browse_termination_callback: calling external_stop_browsing_for_service()");
2607             external_stop_browsing_for_service(ptr->q.InterfaceID, &tmp, kDNSType_PTR, ptr->q.flags, info->process_id);
2608         }
2609 #endif
2610         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
2611                "[R%d] DNSServiceBrowse(%X, %d, \"" PRI_DM_NAME "\") STOP PID[%d](" PUB_S ")",
2612                info->request_id, info->flags, info->interfaceIndex, DM_NAME_PARAM(&ptr->q.qname),
2613                info->process_id, info->pid_name);
2614 
2615         info->u.browser.browsers = ptr->next;
2616         mDNS_StopBrowse(&mDNSStorage, &ptr->q);  // no need to error-check result
2617         LogMcastQ(&ptr->q, info, q_stop);
2618         freeL("browser_t/browse_termination_callback", ptr);
2619     }
2620 }
2621 
udsserver_automatic_browse_domain_changed(const DNameListElem * const d,const mDNSBool add)2622 mDNSlocal void udsserver_automatic_browse_domain_changed(const DNameListElem *const d, const mDNSBool add)
2623 {
2624     request_state *request;
2625     debugf("udsserver_automatic_browse_domain_changed: %s default browse domain %##s", add ? "Adding" : "Removing", d->name.c);
2626 
2627     for (request = all_requests; request; request = request->next)
2628     {
2629         if (request->terminate != browse_termination_callback) continue;    // Not a browse operation
2630         if (!request->u.browser.default_domain) continue;                   // Not an auto-browse operation
2631         if (!d->uid || SystemUID(request->uid) || request->uid == d->uid)
2632         {
2633             browser_t **ptr = &request->u.browser.browsers;
2634             while (*ptr && !SameDomainName(&(*ptr)->domain, &d->name)) ptr = &(*ptr)->next;
2635             if (add)
2636             {
2637                 // If we don't already have this domain in our list for this browse operation, add it now
2638                 if (!*ptr) add_domain_to_browser(request, &d->name);
2639                 else debugf("udsserver_automatic_browse_domain_changed %##s already in list, not re-adding", &d->name);
2640             }
2641             else
2642             {
2643                 if (!*ptr) LogMsg("udsserver_automatic_browse_domain_changed ERROR %##s not found", &d->name);
2644                 else
2645                 {
2646                     DNameListElem *p;
2647                     for (p = AutoBrowseDomains; p; p=p->next)
2648                         if (!p->uid || SystemUID(request->uid) || request->uid == p->uid)
2649                             if (SameDomainName(&d->name, &p->name)) break;
2650                     if (p) debugf("udsserver_automatic_browse_domain_changed %##s still in list, not removing", &d->name);
2651                     else
2652                     {
2653                         browser_t *rem = *ptr;
2654                         *ptr = (*ptr)->next;
2655                         mDNS_StopQueryWithRemoves(&mDNSStorage, &rem->q);
2656                         freeL("browser_t/udsserver_automatic_browse_domain_changed", rem);
2657                     }
2658                 }
2659             }
2660         }
2661     }
2662 }
2663 
FreeARElemCallback(mDNS * const m,AuthRecord * const rr,mStatus result)2664 mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
2665 {
2666     (void)m;  // unused
2667     if (result == mStatus_MemFree)
2668     {
2669         // On shutdown, mDNS_Close automatically deregisters all records
2670         // Since in this case no one has called DeregisterLocalOnlyDomainEnumPTR to cut the record
2671         // from the LocalDomainEnumRecords list, we do this here before we free the memory.
2672         // (This should actually no longer be necessary, now that we do the proper cleanup in
2673         // udsserver_exit. To confirm this, we'll log an error message if we do find a record that
2674         // hasn't been cut from the list yet. If these messages don't appear, we can delete this code.)
2675         ARListElem **ptr = &LocalDomainEnumRecords;
2676         while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
2677         if (*ptr) { *ptr = (*ptr)->next; LogMsg("FreeARElemCallback: Have to cut %s", ARDisplayString(m, rr)); }
2678         mDNSPlatformMemFree(rr->RecordContext);
2679     }
2680 }
2681 
2682 // RegisterLocalOnlyDomainEnumPTR and DeregisterLocalOnlyDomainEnumPTR largely duplicate code in
2683 // "FoundDomain" in uDNS.c for creating and destroying these special mDNSInterface_LocalOnly records.
2684 // We may want to turn the common code into a subroutine.
2685 
RegisterLocalOnlyDomainEnumPTR(mDNS * m,const domainname * d,int type)2686 mDNSlocal void RegisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
2687 {
2688     // allocate/register legacy and non-legacy _browse PTR record
2689     mStatus err;
2690     ARListElem *ptr = (ARListElem *) mDNSPlatformMemAllocateClear(sizeof(*ptr));
2691 
2692     debugf("Incrementing %s refcount for %##s",
2693            (type == mDNS_DomainTypeBrowse         ) ? "browse domain   " :
2694            (type == mDNS_DomainTypeRegistration   ) ? "registration dom" :
2695            (type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
2696 
2697     mDNS_SetupResourceRecord(&ptr->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, AuthRecordLocalOnly, FreeARElemCallback, ptr);
2698     MakeDomainNameFromDNSNameString(&ptr->ar.namestorage, mDNS_DomainTypeNames[type]);
2699     AppendDNSNameString            (&ptr->ar.namestorage, "local");
2700     AssignDomainName(&ptr->ar.resrec.rdata->u.name, d);
2701     err = mDNS_Register(m, &ptr->ar);
2702     if (err)
2703     {
2704         LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
2705         mDNSPlatformMemFree(ptr);
2706     }
2707     else
2708     {
2709         ptr->next = LocalDomainEnumRecords;
2710         LocalDomainEnumRecords = ptr;
2711     }
2712 }
2713 
DeregisterLocalOnlyDomainEnumPTR(mDNS * m,const domainname * d,int type)2714 mDNSlocal void DeregisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
2715 {
2716     ARListElem **ptr = &LocalDomainEnumRecords;
2717     domainname lhs; // left-hand side of PTR, for comparison
2718 
2719     debugf("Decrementing %s refcount for %##s",
2720            (type == mDNS_DomainTypeBrowse         ) ? "browse domain   " :
2721            (type == mDNS_DomainTypeRegistration   ) ? "registration dom" :
2722            (type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
2723 
2724     MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
2725     AppendDNSNameString            (&lhs, "local");
2726 
2727     while (*ptr)
2728     {
2729         if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
2730         {
2731             ARListElem *rem = *ptr;
2732             *ptr = (*ptr)->next;
2733             mDNS_Deregister(m, &rem->ar);
2734             return;
2735         }
2736         else ptr = &(*ptr)->next;
2737     }
2738 }
2739 
AddAutoBrowseDomain(const mDNSu32 uid,const domainname * const name)2740 mDNSlocal void AddAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
2741 {
2742     DNameListElem *new = (DNameListElem *) mDNSPlatformMemAllocateClear(sizeof(*new));
2743     if (!new) { LogMsg("ERROR: malloc"); return; }
2744     AssignDomainName(&new->name, name);
2745     new->uid = uid;
2746     new->next = AutoBrowseDomains;
2747     AutoBrowseDomains = new;
2748     udsserver_automatic_browse_domain_changed(new, mDNStrue);
2749 }
2750 
RmvAutoBrowseDomain(const mDNSu32 uid,const domainname * const name)2751 mDNSlocal void RmvAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
2752 {
2753     DNameListElem **p = &AutoBrowseDomains;
2754     while (*p && (!SameDomainName(&(*p)->name, name) || (*p)->uid != uid)) p = &(*p)->next;
2755     if (!*p) LogMsg("RmvAutoBrowseDomain: Got remove event for domain %##s not in list", name->c);
2756     else
2757     {
2758         DNameListElem *ptr = *p;
2759         *p = ptr->next;
2760         udsserver_automatic_browse_domain_changed(ptr, mDNSfalse);
2761         mDNSPlatformMemFree(ptr);
2762     }
2763 }
2764 
SetPrefsBrowseDomains(mDNS * m,DNameListElem * browseDomains,mDNSBool add)2765 mDNSlocal void SetPrefsBrowseDomains(mDNS *m, DNameListElem *browseDomains, mDNSBool add)
2766 {
2767     DNameListElem *d;
2768     for (d = browseDomains; d; d = d->next)
2769     {
2770         if (add)
2771         {
2772             RegisterLocalOnlyDomainEnumPTR(m, &d->name, mDNS_DomainTypeBrowse);
2773             AddAutoBrowseDomain(d->uid, &d->name);
2774         }
2775         else
2776         {
2777             DeregisterLocalOnlyDomainEnumPTR(m, &d->name, mDNS_DomainTypeBrowse);
2778             RmvAutoBrowseDomain(d->uid, &d->name);
2779         }
2780     }
2781 }
2782 
2783 #if APPLE_OSX_mDNSResponder
2784 
UpdateDeviceInfoRecord(mDNS * const m)2785 mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m)
2786 {
2787     int num_autoname = 0;
2788     request_state *req;
2789 
2790     // Don't need to register the device info record for kDNSServiceInterfaceIndexLocalOnly registrations.
2791     for (req = all_requests; req; req = req->next)
2792     {
2793         if (req->terminate == regservice_termination_callback && req->u.servicereg.autoname && req->interfaceIndex != kDNSServiceInterfaceIndexLocalOnly)
2794             num_autoname++;
2795     }
2796 
2797     // If DeviceInfo record is currently registered, see if we need to deregister it
2798     if (m->DeviceInfo.resrec.RecordType != kDNSRecordTypeUnregistered)
2799         if (num_autoname == 0 || !SameDomainLabelCS(m->DeviceInfo.resrec.name->c, m->nicelabel.c))
2800         {
2801             LogOperation("UpdateDeviceInfoRecord Deregister %##s", m->DeviceInfo.resrec.name);
2802             mDNS_Deregister(m, &m->DeviceInfo);
2803         }
2804 
2805     // If DeviceInfo record is not currently registered, see if we need to register it
2806     if (m->DeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
2807         if (num_autoname > 0)
2808         {
2809             mDNS_SetupResourceRecord(&m->DeviceInfo, mDNSNULL, mDNSNULL, kDNSType_TXT, kStandardTTL, kDNSRecordTypeAdvisory, AuthRecordAny, mDNSNULL, mDNSNULL);
2810             ConstructServiceName(&m->DeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &localdomain);
2811             m->DeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, m->DeviceInfo.resrec.rdata->u.data);
2812             LogOperation("UpdateDeviceInfoRecord   Register %##s", m->DeviceInfo.resrec.name);
2813             mDNS_Register(m, &m->DeviceInfo);
2814         }
2815 }
2816 #else   // APPLE_OSX_mDNSResponder
UpdateDeviceInfoRecord(mDNS * const m)2817 mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m)
2818 {
2819     (void)m; // unused
2820 }
2821 #endif  // APPLE_OSX_mDNSResponder
2822 
udsserver_handle_configchange(mDNS * const m)2823 mDNSexport void udsserver_handle_configchange(mDNS *const m)
2824 {
2825     request_state *req;
2826     service_instance *ptr;
2827     DNameListElem *RegDomains = NULL;
2828     DNameListElem *BrowseDomains = NULL;
2829     DNameListElem *p;
2830 
2831     UpdateDeviceInfoRecord(m);
2832 
2833     // For autoname services, see if the default service name has changed, necessitating an automatic update
2834     for (req = all_requests; req; req = req->next)
2835         if (req->terminate == regservice_termination_callback)
2836             if (req->u.servicereg.autoname && !SameDomainLabelCS(req->u.servicereg.name.c, m->nicelabel.c))
2837             {
2838                 req->u.servicereg.name = m->nicelabel;
2839                 for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
2840                 {
2841                     ptr->renameonmemfree = 1;
2842                     if (ptr->clientnotified) SendServiceRemovalNotification(&ptr->srs);
2843                     LogInfo("udsserver_handle_configchange: Calling deregister for Service %##s", ptr->srs.RR_PTR.resrec.name->c);
2844                     if (mDNS_DeregisterService_drt(m, &ptr->srs, mDNS_Dereg_rapid))
2845                         regservice_callback(m, &ptr->srs, mStatus_MemFree); // If service deregistered already, we can re-register immediately
2846                 }
2847             }
2848 
2849     // Let the platform layer get the current DNS information
2850     mDNS_Lock(m);
2851     mDNSPlatformSetDNSConfig(mDNSfalse, mDNSfalse, mDNSNULL, &RegDomains, &BrowseDomains, mDNSfalse);
2852     mDNS_Unlock(m);
2853 
2854     // Any automatic registration domains are also implicitly automatic browsing domains
2855     if (RegDomains) SetPrefsBrowseDomains(m, RegDomains, mDNStrue);                             // Add the new list first
2856     if (AutoRegistrationDomains) SetPrefsBrowseDomains(m, AutoRegistrationDomains, mDNSfalse);  // Then clear the old list
2857 
2858     // Add any new domains not already in our AutoRegistrationDomains list
2859     for (p=RegDomains; p; p=p->next)
2860     {
2861         DNameListElem **pp = &AutoRegistrationDomains;
2862         while (*pp && ((*pp)->uid != p->uid || !SameDomainName(&(*pp)->name, &p->name))) pp = &(*pp)->next;
2863         if (!*pp)       // If not found in our existing list, this is a new default registration domain
2864         {
2865             RegisterLocalOnlyDomainEnumPTR(m, &p->name, mDNS_DomainTypeRegistration);
2866             udsserver_default_reg_domain_changed(p, mDNStrue);
2867         }
2868         else            // else found same domainname in both old and new lists, so no change, just delete old copy
2869         {
2870             DNameListElem *del = *pp;
2871             *pp = (*pp)->next;
2872             mDNSPlatformMemFree(del);
2873         }
2874     }
2875 
2876     // Delete any domains in our old AutoRegistrationDomains list that are now gone
2877     while (AutoRegistrationDomains)
2878     {
2879         DNameListElem *del = AutoRegistrationDomains;
2880         AutoRegistrationDomains = AutoRegistrationDomains->next;        // Cut record from list FIRST,
2881         DeregisterLocalOnlyDomainEnumPTR(m, &del->name, mDNS_DomainTypeRegistration);
2882         udsserver_default_reg_domain_changed(del, mDNSfalse);           // before calling udsserver_default_reg_domain_changed()
2883         mDNSPlatformMemFree(del);
2884     }
2885 
2886     // Now we have our new updated automatic registration domain list
2887     AutoRegistrationDomains = RegDomains;
2888 
2889     // Add new browse domains to internal list
2890     if (BrowseDomains) SetPrefsBrowseDomains(m, BrowseDomains, mDNStrue);
2891 
2892     // Remove old browse domains from internal list
2893     if (SCPrefBrowseDomains)
2894     {
2895         SetPrefsBrowseDomains(m, SCPrefBrowseDomains, mDNSfalse);
2896         while (SCPrefBrowseDomains)
2897         {
2898             DNameListElem *fptr = SCPrefBrowseDomains;
2899             SCPrefBrowseDomains = SCPrefBrowseDomains->next;
2900             mDNSPlatformMemFree(fptr);
2901         }
2902     }
2903 
2904     // Replace the old browse domains array with the new array
2905     SCPrefBrowseDomains = BrowseDomains;
2906 }
2907 
AutomaticBrowseDomainChange(mDNS * const m,DNSQuestion * q,const ResourceRecord * const answer,QC_result AddRecord)2908 mDNSlocal void AutomaticBrowseDomainChange(mDNS *const m, DNSQuestion *q, const ResourceRecord *const answer, QC_result AddRecord)
2909 {
2910     (void)m; // unused;
2911     (void)q; // unused
2912 
2913     LogOperation("AutomaticBrowseDomainChange: %s automatic browse domain %##s",
2914                  AddRecord ? "Adding" : "Removing", answer->rdata->u.name.c);
2915 
2916     if (AddRecord) AddAutoBrowseDomain(0, &answer->rdata->u.name);
2917     else RmvAutoBrowseDomain(0, &answer->rdata->u.name);
2918 }
2919 
_handle_browse_request_start(request_state * request,const char * domain)2920 mDNSlocal mStatus _handle_browse_request_start(request_state *request, const char * domain)
2921 {
2922     domainname d;
2923     mStatus err = mStatus_NoError;
2924 
2925     request->terminate = browse_termination_callback;
2926 
2927     if (domain[0])
2928     {
2929         if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
2930         err = add_domain_to_browser(request, &d);
2931     }
2932     else
2933     {
2934         DNameListElem *sdom;
2935         for (sdom = AutoBrowseDomains; sdom; sdom = sdom->next)
2936             if (!sdom->uid || SystemUID(request->uid) || request->uid == sdom->uid)
2937             {
2938                 err = add_domain_to_browser(request, &sdom->name);
2939                 if (err)
2940                 {
2941                     if (SameDomainName(&sdom->name, &localdomain)) break;
2942                     else err = mStatus_NoError;  // suppress errors for non-local "default" domains
2943                 }
2944             }
2945     }
2946 
2947     return(err);
2948 }
2949 
2950 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
2951 
_return_browse_request_error(request_state * request,mStatus error)2952 mDNSlocal void _return_browse_request_error(request_state *request, mStatus error)
2953 {
2954     reply_state *rep;
2955 
2956     GenerateBrowseReply(NULL, 0, request, &rep, browse_reply_op, 0, error);
2957 
2958     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
2959            "[R%d] DNSServiceBrowse _return_browse_request_error: error (%d)", request->request_id, error);
2960 
2961     append_reply(request, rep);
2962 }
2963 
_handle_browse_request_with_trust(request_state * request,const char * domain)2964 mDNSlocal mStatus _handle_browse_request_with_trust(request_state *request, const char * domain)
2965 {
2966     mStatus err;
2967     if (audit_token_to_pid(request->audit_token) == 0)
2968     {
2969         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_browse_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
2970         err = _handle_browse_request_start(request, domain);
2971     }
2972     else
2973     {
2974         char typestr[MAX_ESCAPED_DOMAIN_NAME];
2975         typestr[0] = 0;
2976         (void)ConvertDomainNameToCString(&request->u.browser.regtype, typestr);
2977         mdns_trust_flags_t flags = mdns_trust_flags_none;
2978         mdns_trust_status_t status = mdns_trust_check_bonjour(request->audit_token, typestr, &flags);
2979         switch (status)
2980         {
2981             case mdns_trust_status_denied:
2982             case mdns_trust_status_pending:
2983             {
2984                 mdns_trust_t trust = mdns_trust_create(request->audit_token, typestr, flags);
2985                 if (!trust )
2986                 {
2987                     err = mStatus_NoMemoryErr;
2988                     goto exit;
2989                 }
2990 
2991                 size_t len = strlen(domain) + 1;
2992                 void * context = mallocL("context/_handle_browse_request_with_trust", len);
2993                 if (!context)
2994                 {
2995                     my_perror("ERROR: mallocL context/_handle_browse_request_with_trust");
2996                     mdns_release(trust);
2997                     err = mStatus_NoMemoryErr;
2998                     goto exit;
2999                 }
3000                 memcpy(context, domain, len);
3001                 mdns_trust_set_context(trust, context);
3002 
3003                 mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
3004                 mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
3005                 {
3006                     if (event == mdns_trust_event_result)
3007                     {
3008                         mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
3009                         KQueueLock();
3010                         const char * _domain = mdns_trust_get_context(trust);
3011                         if (_domain)
3012                         {
3013                             if (!error)
3014                             {
3015                                 error = _handle_browse_request_start(request, _domain);
3016                                 // No context means the request was canceled before we got here
3017                             }
3018                             if (error) // (not else if) Always check for error result
3019                             {
3020                                 _return_browse_request_error(request, error);
3021                             }
3022                         }
3023                         KQueueUnlock("_handle_browse_request_with_trust");
3024                     }
3025                 });
3026                 request->trust = trust;
3027                 mdns_trust_activate(trust);
3028                 err = mStatus_NoError;
3029                 break;
3030             }
3031 
3032             case mdns_trust_status_no_entitlement:
3033                 err = mStatus_NoAuth;
3034                 break;
3035 
3036             case mdns_trust_status_granted:
3037                 err = _handle_browse_request_start(request, domain);
3038                 break;
3039 
3040             default:
3041                 err = mStatus_UnknownErr;
3042                 break;
3043         }
3044     }
3045 exit:
3046     return err;
3047 }
3048 #endif // TRUST_ENFORCEMENT
3049 
handle_browse_request(request_state * request)3050 mDNSlocal mStatus handle_browse_request(request_state *request)
3051 {
3052     // Note that regtype may include a trailing subtype
3053     char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
3054     domainname typedn, temp;
3055     mDNSs32 NumSubTypes;
3056     mStatus err = mStatus_NoError;
3057 
3058     DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
3059     mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
3060     mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
3061 
3062     // The browse is scoped to a specific interface index, but the
3063     // interface is not currently in our list.
3064     if (interfaceIndex && !InterfaceID)
3065     {
3066         // If it's one of the specially defined inteface index values, just return an error.
3067         if (PreDefinedInterfaceIndex(interfaceIndex))
3068         {
3069             LogInfo("handle_browse_request: bad interfaceIndex %d", interfaceIndex);
3070             return(mStatus_BadParamErr);
3071         }
3072 
3073         // Otherwise, use the specified interface index value and the browse will
3074         // be applied to that interface when it comes up.
3075         InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
3076         LogInfo("handle_browse_request: browse pending for interface index %d", interfaceIndex);
3077     }
3078 
3079     if (get_string(&request->msgptr, request->msgend, regtype, sizeof(regtype)) < 0 ||
3080         get_string(&request->msgptr, request->msgend, domain,  sizeof(domain )) < 0) return(mStatus_BadParamErr);
3081 
3082     if (!request->msgptr) { LogMsg("%3d: DNSServiceBrowse(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
3083 
3084     request->flags = flags;
3085     request->interfaceIndex = interfaceIndex;
3086     typedn.c[0] = 0;
3087     NumSubTypes = ChopSubTypes(regtype);    // Note: Modifies regtype string to remove trailing subtypes
3088     if (NumSubTypes < 0 || NumSubTypes > 1)
3089         return(mStatus_BadParamErr);
3090     if (NumSubTypes == 1)
3091     {
3092         if (!AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
3093             return(mStatus_BadParamErr);
3094     }
3095 
3096     if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) return(mStatus_BadParamErr);
3097 
3098     if (!MakeDomainNameFromDNSNameString(&temp, regtype)) return(mStatus_BadParamErr);
3099     // For over-long service types, we only allow domain "local"
3100     if (temp.c[0] > 15 && domain[0] == 0) mDNSPlatformStrLCopy(domain, "local.", sizeof(domain));
3101 
3102     // Set up browser info
3103     request->u.browser.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
3104     request->u.browser.interface_id = InterfaceID;
3105     AssignDomainName(&request->u.browser.regtype, &typedn);
3106     request->u.browser.default_domain = !domain[0];
3107     request->u.browser.browsers = NULL;
3108 
3109     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceBrowse(%X, %d, \"" PRI_DM_NAME "\", \"" PRI_S "\") START PID[%d](" PUB_S ")",
3110            request->request_id, request->flags, interfaceIndex, DM_NAME_PARAM(&request->u.browser.regtype), domain,
3111            request->process_id, request->pid_name);
3112 
3113     if (request->u.browser.default_domain)
3114     {
3115         // Start the domain enumeration queries to discover the WAB browse domains
3116         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
3117                "[R%d] DNSServiceBrowse Start WAB PID[%d](" PUB_S ")",
3118                request->request_id, request->process_id, request->pid_name);
3119         uDNS_StartWABQueries(&mDNSStorage, UDNS_WAB_LBROWSE_QUERY);
3120     }
3121     // We need to unconditionally set request->terminate, because even if we didn't successfully
3122     // start any browses right now, subsequent configuration changes may cause successful
3123     // browses to be added, and we'll need to cancel them before freeing this memory.
3124     request->terminate = NULL;
3125 
3126 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
3127     domainname d;
3128     if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
3129 
3130     if (os_feature_enabled(mDNSResponder, bonjour_privacy) &&
3131         (request->u.browser.default_domain || IsLocalDomain(&d) || request->u.browser.ForceMCast))
3132     {
3133         err = _handle_browse_request_with_trust(request, domain);
3134     }
3135     else
3136     {
3137         err = _handle_browse_request_start(request, domain);
3138     }
3139 #else
3140     err = _handle_browse_request_start(request, domain);
3141 #endif
3142 
3143     return(err);
3144 }
3145 
3146 // ***************************************************************************
3147 #if COMPILER_LIKES_PRAGMA_MARK
3148 #pragma mark -
3149 #pragma mark - DNSServiceResolve
3150 #endif
3151 
resolve_termination_callback(request_state * request)3152 mDNSlocal void resolve_termination_callback(request_state *request)
3153 {
3154     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
3155            "[R%d] DNSServiceResolve(%X, %d, \"" PRI_DM_NAME "\") STOP PID[%d](" PUB_S ")",
3156            request->request_id, request->flags, request->interfaceIndex, DM_NAME_PARAM(&request->u.resolve.qtxt.qname),
3157            request->process_id, request->pid_name);
3158     mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
3159     mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
3160     LogMcastQ(&request->u.resolve.qsrv, request, q_stop);
3161 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
3162     if (request->u.resolve.external_advertise)
3163     {
3164         external_stop_resolving_service(request->u.resolve.qsrv.InterfaceID, &request->u.resolve.qsrv.qname, request->flags, request->process_id);
3165     }
3166 #endif
3167 }
3168 
3169 typedef struct {
3170     char            regtype[MAX_ESCAPED_DOMAIN_NAME];
3171     domainname      fqdn;
3172     mDNSInterfaceID InterfaceID;
3173 } _resolve_start_params_t;
3174 
_handle_resolve_request_start(request_state * request,const _resolve_start_params_t * const params)3175 mDNSlocal mStatus _handle_resolve_request_start(request_state *request, const _resolve_start_params_t * const params)
3176 {
3177     mStatus err;
3178 
3179     err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
3180 
3181     if (!err)
3182     {
3183         err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt);
3184         if (err)
3185         {
3186             mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
3187         }
3188         else
3189         {
3190             request->terminate = resolve_termination_callback;
3191             LogMcastQ(&request->u.resolve.qsrv, request, q_start);
3192 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
3193             if (callExternalHelpers(params->InterfaceID, &params->fqdn, request->flags))
3194             {
3195                 request->u.resolve.external_advertise    = mDNStrue;
3196                 LogInfo("handle_resolve_request: calling external_start_resolving_service()");
3197                 external_start_resolving_service(params->InterfaceID, &params->fqdn, request->flags, request->process_id);
3198             }
3199 #else
3200             (void)params;
3201 #endif
3202         }
3203     }
3204     return err;
3205 }
3206 
resolve_result_callback(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)3207 mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
3208 {
3209     size_t len = 0;
3210     char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME] = "0";
3211     char *data;
3212     reply_state *rep;
3213     request_state *req = question->QuestionContext;
3214     const DNSServiceErrorType error =
3215         (answer->RecordType == kDNSRecordTypePacketNegative) ? kDNSServiceErr_NoSuchRecord : kDNSServiceErr_NoError;
3216     (void)m; // Unused
3217 
3218     LogOperation("%3d: DNSServiceResolve(%##s) %s interface %d: %s",
3219         req->sd, question->qname.c, AddRecord ? "ADD" : "RMV",
3220         mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse), RRDisplayString(m, answer));
3221 
3222     if (!AddRecord)
3223     {
3224         if (req->u.resolve.srv == answer) req->u.resolve.srv = mDNSNULL;
3225         if (req->u.resolve.txt == answer) req->u.resolve.txt = mDNSNULL;
3226         return;
3227     }
3228 
3229     if (answer->rrtype == kDNSType_SRV) req->u.resolve.srv = answer;
3230     if (answer->rrtype == kDNSType_TXT) req->u.resolve.txt = answer;
3231 
3232     if (!req->u.resolve.txt || !req->u.resolve.srv) return;     // only deliver result to client if we have both answers
3233 
3234     ConvertDomainNameToCString(answer->name, fullname);
3235 
3236     if (answer->RecordType != kDNSRecordTypePacketNegative)
3237         ConvertDomainNameToCString(&req->u.resolve.srv->rdata->u.srv.target, target);
3238 
3239     // calculate reply length
3240     len += sizeof(DNSServiceFlags);
3241     len += sizeof(mDNSu32);  // interface index
3242     len += sizeof(DNSServiceErrorType);
3243     len += strlen(fullname) + 1;
3244     len += strlen(target) + 1;
3245     len += 2 * sizeof(mDNSu16);  // port, txtLen
3246     len += req->u.resolve.txt->rdlength;
3247 
3248     // allocate/init reply header
3249     rep = create_reply(resolve_reply_op, len, req);
3250     rep->rhdr->flags = dnssd_htonl(0);
3251     rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse));
3252     rep->rhdr->error = dnssd_htonl(error);
3253 
3254     data = (char *)&rep->rhdr[1];
3255 
3256     // write reply data to message
3257     put_string(fullname, &data);
3258     put_string(target, &data);
3259     *data++ =  req->u.resolve.srv->rdata->u.srv.port.b[0];
3260     *data++ =  req->u.resolve.srv->rdata->u.srv.port.b[1];
3261     put_uint16(req->u.resolve.txt->rdlength, &data);
3262     put_rdata (req->u.resolve.txt->rdlength, req->u.resolve.txt->rdata->u.data, &data);
3263 
3264     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d->Q%d] DNSServiceResolve(" PRI_S ") RESULT   " PRI_S ":%d",
3265            req->request_id, mDNSVal16(question->TargetQID), fullname, target,
3266            mDNSVal16(req->u.resolve.srv->rdata->u.srv.port));
3267     append_reply(req, rep);
3268 }
3269 
3270 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
3271 
_return_resolve_request_error(request_state * request,mStatus error)3272 mDNSlocal void _return_resolve_request_error(request_state * request, mStatus error)
3273 {
3274     size_t len;
3275     char * emptystr = "\0";
3276     char * data;
3277     reply_state *rep;
3278 
3279     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
3280        "[R%u] DNSServiceResolve _return_resolve_request_error: error(%d)", request->request_id, error);
3281 
3282     // calculate reply length
3283     len = sizeof(DNSServiceFlags);
3284     len += sizeof(mDNSu32);  // interface index
3285     len += sizeof(DNSServiceErrorType);
3286     len += 2; // name, target
3287     len += 2 * sizeof(mDNSu16);  // port, txtLen
3288     len += 0; //req->u.resolve.txt->rdlength;
3289 
3290     rep = create_reply(resolve_reply_op, len, request);
3291 
3292     rep->rhdr->flags = 0;
3293     rep->rhdr->ifi   = 0;
3294     rep->rhdr->error = dnssd_htonl(error);
3295 
3296     data = (char *)&rep->rhdr[1];
3297 
3298     // write reply data to message
3299     put_string(emptystr, &data); // name
3300     put_string(emptystr, &data); // target
3301     put_uint16(0,        &data); // port
3302     put_uint16(0,        &data); // txtLen
3303 
3304     append_reply(request, rep);
3305 }
3306 
_handle_resolve_request_with_trust(request_state * request,const _resolve_start_params_t * const params)3307 mDNSlocal mStatus _handle_resolve_request_with_trust(request_state *request, const _resolve_start_params_t * const params)
3308 {
3309     mStatus err;
3310     if (audit_token_to_pid(request->audit_token) == 0)
3311     {
3312         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_resolve_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
3313         err = _handle_resolve_request_start(request, params);
3314     }
3315     else
3316     {
3317         mdns_trust_flags_t flags = mdns_trust_flags_none;
3318         mdns_trust_status_t status = mdns_trust_check_bonjour(request->audit_token, params->regtype, &flags);
3319         switch (status)
3320         {
3321             case mdns_trust_status_denied:
3322             case mdns_trust_status_pending:
3323             {
3324                 mdns_trust_t trust = mdns_trust_create(request->audit_token, params->regtype, flags);
3325                 if (!trust )
3326                 {
3327                     err = mStatus_NoMemoryErr;
3328                     goto exit;
3329                 }
3330 
3331                 void * context = mallocL("context/_handle_resolve_request_with_trust", sizeof(_resolve_start_params_t));
3332                 if (!context)
3333                 {
3334                     my_perror("ERROR: mallocL context/_handle_resolve_request_with_trust");
3335                     mdns_release(trust);
3336                     err = mStatus_NoMemoryErr;
3337                     goto exit;
3338                 }
3339                 memcpy(context, params, sizeof(_resolve_start_params_t));
3340                 mdns_trust_set_context(trust, context);
3341                 mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
3342                 mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
3343                 {
3344                     if (event == mdns_trust_event_result)
3345                     {
3346                         mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
3347                         KQueueLock();
3348                         _resolve_start_params_t * _params =  mdns_trust_get_context(trust);
3349                         if (_params)
3350                         {
3351                             if (!error)
3352                             {
3353                                 error = _handle_resolve_request_start(request, _params);
3354                                 // No context means the request was canceled before we got here
3355                             }
3356                             if (error) // (not else if) Always check for error result
3357                             {
3358                                 _return_resolve_request_error(request, error);
3359                             }
3360                         }
3361                         KQueueUnlock("_handle_resolve_request_with_trust");
3362                     }
3363                 });
3364                 request->trust = trust;
3365                 mdns_trust_activate(trust);
3366                 err = mStatus_NoError;
3367                 break;
3368             }
3369 
3370             case mdns_trust_status_no_entitlement:
3371                 err = mStatus_NoAuth;
3372                 break;
3373 
3374             case mdns_trust_status_granted:
3375                 err = _handle_resolve_request_start(request, params);
3376                 break;
3377 
3378             default:
3379                 err = mStatus_UnknownErr;
3380                 break;
3381         }
3382     }
3383 exit:
3384     return err;
3385 }
3386 #endif // TRUST_ENFORCEMENT
3387 
handle_resolve_request(request_state * request)3388 mDNSlocal mStatus handle_resolve_request(request_state *request)
3389 {
3390     char name[256], domain[MAX_ESCAPED_DOMAIN_NAME];
3391     _resolve_start_params_t params;
3392     mStatus err;
3393 
3394     // extract the data from the message
3395     DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
3396     mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
3397 
3398     // Map kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
3399     // flag set so that the resolve will run over P2P interfaces that are not yet created.
3400     if (interfaceIndex == kDNSServiceInterfaceIndexP2P)
3401     {
3402         LogOperation("handle_resolve_request: mapping kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny + kDNSServiceFlagsIncludeP2P");
3403         flags |= kDNSServiceFlagsIncludeP2P;
3404         interfaceIndex = kDNSServiceInterfaceIndexAny;
3405     }
3406 
3407     params.InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
3408 
3409     // The operation is scoped to a specific interface index, but the
3410     // interface is not currently in our list.
3411     if (interfaceIndex && !params.InterfaceID)
3412     {
3413         // If it's one of the specially defined inteface index values, just return an error.
3414         if (PreDefinedInterfaceIndex(interfaceIndex))
3415         {
3416             LogInfo("handle_resolve_request: bad interfaceIndex %d", interfaceIndex);
3417             return(mStatus_BadParamErr);
3418         }
3419 
3420         // Otherwise, use the specified interface index value and the operation will
3421         // be applied to that interface when it comes up.
3422         params.InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
3423         LogInfo("handle_resolve_request: resolve pending for interface index %d", interfaceIndex);
3424     }
3425 
3426     if (get_string(&request->msgptr, request->msgend, name,           sizeof(name   )) < 0 ||
3427         get_string(&request->msgptr, request->msgend, params.regtype, sizeof(params.regtype)) < 0 ||
3428         get_string(&request->msgptr, request->msgend, domain,         sizeof(domain )) < 0)
3429     { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
3430 
3431     if (!request->msgptr) { LogMsg("%3d: DNSServiceResolve(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
3432 
3433     if (build_domainname_from_strings(&params.fqdn, name, params.regtype, domain) < 0)
3434     { LogMsg("ERROR: handle_resolve_request bad “%s” “%s” “%s”", name, params.regtype, domain); return(mStatus_BadParamErr); }
3435 
3436     mDNSPlatformMemZero(&request->u.resolve, sizeof(request->u.resolve));
3437 
3438 #if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
3439     // Determine if this request should be promoted to use BLE triggered discovery.
3440     if (shouldUseBLE(InterfaceID, 0, (domainname *)SkipLeadingLabels(&fqdn, 1), &fqdn))
3441     {
3442         flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
3443         LogInfo("handle_resolve_request: request promoted to use kDNSServiceFlagsAutoTrigger");
3444     }
3445 #endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
3446 
3447     request->flags = flags;
3448     request->interfaceIndex = interfaceIndex;
3449 
3450     // format questions
3451     request->u.resolve.qsrv.InterfaceID      = params.InterfaceID;
3452     request->u.resolve.qsrv.flags            = flags;
3453     AssignDomainName(&request->u.resolve.qsrv.qname, &params.fqdn);
3454     request->u.resolve.qsrv.qtype            = kDNSType_SRV;
3455     request->u.resolve.qsrv.qclass           = kDNSClass_IN;
3456     request->u.resolve.qsrv.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
3457     request->u.resolve.qsrv.ExpectUnique     = mDNStrue;
3458     request->u.resolve.qsrv.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
3459     request->u.resolve.qsrv.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
3460     request->u.resolve.qsrv.SuppressUnusable = mDNSfalse;
3461     request->u.resolve.qsrv.AppendSearchDomains = 0;
3462     request->u.resolve.qsrv.TimeoutQuestion  = 0;
3463     request->u.resolve.qsrv.WakeOnResolve    = (flags & kDNSServiceFlagsWakeOnResolve) != 0;
3464     request->u.resolve.qsrv.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
3465     request->u.resolve.qsrv.ProxyQuestion    = 0;
3466     request->u.resolve.qsrv.pid              = request->process_id;
3467     request->u.resolve.qsrv.euid             = request->uid;
3468     request->u.resolve.qsrv.QuestionCallback = resolve_result_callback;
3469     request->u.resolve.qsrv.QuestionContext  = request;
3470 
3471     request->u.resolve.qtxt.InterfaceID      = params.InterfaceID;
3472     request->u.resolve.qtxt.flags            = flags;
3473     AssignDomainName(&request->u.resolve.qtxt.qname, &params.fqdn);
3474     request->u.resolve.qtxt.qtype            = kDNSType_TXT;
3475     request->u.resolve.qtxt.qclass           = kDNSClass_IN;
3476     request->u.resolve.qtxt.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
3477     request->u.resolve.qtxt.ExpectUnique     = mDNStrue;
3478     request->u.resolve.qtxt.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
3479     request->u.resolve.qtxt.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
3480     request->u.resolve.qtxt.SuppressUnusable = mDNSfalse;
3481     request->u.resolve.qtxt.AppendSearchDomains = 0;
3482     request->u.resolve.qtxt.TimeoutQuestion  = 0;
3483     request->u.resolve.qtxt.WakeOnResolve    = 0;
3484     request->u.resolve.qtxt.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
3485     request->u.resolve.qtxt.ProxyQuestion    = 0;
3486     request->u.resolve.qtxt.pid              = request->process_id;
3487     request->u.resolve.qtxt.euid             = request->uid;
3488     request->u.resolve.qtxt.QuestionCallback = resolve_result_callback;
3489     request->u.resolve.qtxt.QuestionContext  = request;
3490 
3491     request->u.resolve.ReportTime            = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond);
3492 
3493     request->u.resolve.external_advertise    = mDNSfalse;
3494 
3495 #if 0
3496     if (!AuthorizedDomain(request, &fqdn, AutoBrowseDomains)) return(mStatus_NoError);
3497 #endif
3498 
3499     // ask the questions
3500     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
3501            "[R%d] DNSServiceResolve(%X, %d, \"" PRI_DM_NAME "\") START PID[%d](" PUB_S ")",
3502            request->request_id, flags, interfaceIndex, DM_NAME_PARAM(&request->u.resolve.qsrv.qname),
3503            request->process_id, request->pid_name);
3504 
3505     request->terminate = NULL;
3506 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
3507     domainname d;
3508     if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
3509 
3510     if (os_feature_enabled(mDNSResponder, bonjour_privacy) &&
3511         (IsLocalDomain(&d) || request->u.resolve.qsrv.ForceMCast))
3512     {
3513         err = _handle_resolve_request_with_trust(request, &params);
3514     }
3515     else
3516     {
3517         err = _handle_resolve_request_start(request, &params);
3518     }
3519 #else
3520     err = _handle_resolve_request_start(request, &params);
3521 #endif
3522 
3523     return(err);
3524 }
3525 
3526 // ***************************************************************************
3527 #if COMPILER_LIKES_PRAGMA_MARK
3528 #pragma mark -
3529 #pragma mark - DNSServiceQueryRecord
3530 #endif
3531 
queryrecord_result_reply(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord,DNSServiceErrorType error,void * context)3532 mDNSlocal void queryrecord_result_reply(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord, DNSServiceErrorType error, void *context)
3533 {
3534     char name[MAX_ESCAPED_DOMAIN_NAME];
3535     size_t len;
3536     DNSServiceFlags flags = 0;
3537     reply_state *rep;
3538     char *data;
3539     request_state *req = (request_state *)context;
3540     const char *dnssec_result_description = "";
3541 
3542     ConvertDomainNameToCString(answer->name, name);
3543 
3544 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
3545     if (question->DNSSECStatus.enable_dnssec) {
3546         if (answer->dnssec_result == dnssec_secure)
3547         {
3548             flags |= kDNSServiceFlagsSecure;
3549             dnssec_result_description = ", DNSSEC_Secure";
3550         }
3551         else if (answer->dnssec_result == dnssec_insecure)
3552         {
3553             flags |= kDNSServiceFlagsInsecure;
3554             dnssec_result_description = ", DNSSEC_Insecure";
3555         }
3556         else if (answer->dnssec_result == dnssec_bogus)
3557         {
3558             flags |= kDNSServiceFlagsBogus;
3559             dnssec_result_description = ", DNSSEC_Bogus";
3560         }
3561         else if (answer->dnssec_result == dnssec_indeterminate)
3562         {
3563             flags |= kDNSServiceFlagsIndeterminate;
3564             dnssec_result_description = ", DNSSEC_Indeterminate";
3565         }
3566     } else if (question->DNSSECStatus.tried_dnssec_but_unsigned) {
3567         // handle the case where we restart the question without the DNSSEC while the user requires DNSSEC result, for
3568         // some reason we failed to get DNSSEC records. In which case, even if we go back to normal query, we should pass
3569         // the DNSSEC result
3570         flags |= kDNSServiceFlagsInsecure;
3571         dnssec_result_description = ", DNSSEC_Insecure";
3572     }
3573 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
3574 
3575     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
3576        "[R%u->Q%u] DNSService" PUB_S "(" PRI_DM_NAME ", " PUB_S ") RESULT " PUB_S " interface %d: (" PUB_S PUB_S ")" PRI_S,
3577        req->request_id, mDNSVal16(question->TargetQID), req->hdr.op == query_request ? "QueryRecord" : "GetAddrInfo",
3578        DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
3579        mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse),
3580        MortalityDisplayString(answer->mortality), dnssec_result_description, RRDisplayString(m, answer));
3581 
3582     len = sizeof(DNSServiceFlags);  // calculate reply data length
3583     len += sizeof(mDNSu32);     // interface index
3584     len += sizeof(DNSServiceErrorType);
3585     len += strlen(name) + 1;
3586     len += 3 * sizeof(mDNSu16); // type, class, rdlen
3587     len += answer->rdlength;
3588     len += sizeof(mDNSu32);     // TTL
3589 
3590     rep = create_reply(req->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, req);
3591 
3592     if (AddRecord)
3593         flags |= kDNSServiceFlagsAdd;
3594     if (answer->mortality == Mortality_Ghost)
3595         flags |= kDNSServiceFlagsExpiredAnswer;
3596     if (!question->InitialCacheMiss)
3597         flags |= kDNSServiceFlagAnsweredFromCache;
3598 
3599     rep->rhdr->flags = dnssd_htonl(flags);
3600     // Call mDNSPlatformInterfaceIndexfromInterfaceID, but suppressNetworkChange (last argument). Otherwise, if the
3601     // InterfaceID is not valid, then it simulates a "NetworkChanged" which in turn makes questions
3602     // to be stopped and started including  *this* one. Normally the InterfaceID is valid. But when we
3603     // are using the /etc/hosts entries to answer a question, the InterfaceID may not be known to the
3604     // mDNS core . Eventually, we should remove the calls to "NetworkChanged" in
3605     // mDNSPlatformInterfaceIndexfromInterfaceID when it can't find InterfaceID as ResourceRecords
3606     // should not have existed to answer this question if the corresponding interface is not valid.
3607     rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNStrue));
3608     rep->rhdr->error = dnssd_htonl(error);
3609 
3610     data = (char *)&rep->rhdr[1];
3611 
3612     put_string(name,             &data);
3613     put_uint16(answer->rrtype,   &data);
3614     put_uint16(answer->rrclass,  &data);
3615     put_uint16(answer->rdlength, &data);
3616     // We need to use putRData here instead of the crude put_rdata function, because the crude put_rdata
3617     // function just does a blind memory copy without regard to structures that may have holes in them.
3618     if (answer->rdlength)
3619         if (!putRData(mDNSNULL, (mDNSu8 *)data, (mDNSu8 *)rep->rhdr + len, answer))
3620             LogMsg("queryrecord_result_reply putRData failed %d", (mDNSu8 *)rep->rhdr + len - (mDNSu8 *)data);
3621     data += answer->rdlength;
3622     put_uint32(AddRecord ? answer->rroriginalttl : 0, &data);
3623 
3624     append_reply(req, rep);
3625 }
3626 
queryrecord_termination_callback(request_state * request)3627 mDNSlocal void queryrecord_termination_callback(request_state *request)
3628 {
3629     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
3630            "[R%u] DNSServiceQueryRecord(%X, %d, " PRI_DM_NAME ", " PUB_S ") STOP PID[%d](" PUB_S ")",
3631            request->request_id, request->flags, request->interfaceIndex,
3632            DM_NAME_PARAM(QueryRecordClientRequestGetQName(&request->u.queryrecord)),
3633            DNSTypeName(QueryRecordClientRequestGetType(&request->u.queryrecord)), request->process_id, request->pid_name);
3634 
3635     QueryRecordClientRequestStop(&request->u.queryrecord);
3636 }
3637 
3638 typedef struct {
3639     char            qname[MAX_ESCAPED_DOMAIN_NAME];
3640     mDNSu32         interfaceIndex;
3641     DNSServiceFlags flags;
3642     mDNSu16         qtype;
3643     mDNSu16         qclass;
3644 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
3645     mDNSBool        require_privacy;
3646 #endif
3647 } _queryrecord_start_params_t;
3648 
3649 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) && MDNSRESPONDER_SUPPORTS(APPLE, IPC_TLV)
ipc_tlv_get_resolver_config_plist_data(const mDNSu8 * const start,const mDNSu8 * const end,size_t * outLen)3650 mDNSlocal const mDNSu8 * ipc_tlv_get_resolver_config_plist_data(const mDNSu8 *const start, const mDNSu8 *const end,
3651     size_t *outLen)
3652 {
3653     size_t len = 0;
3654     const mDNSu8 *value = NULL;
3655     mdns_tlv16_get_value(start, end, IPC_TLV_TYPE_RESOLVER_CONFIG_PLIST_DATA, &len, &value, NULL);
3656     if (outLen)
3657     {
3658         *outLen = len;
3659     }
3660     return value;
3661 }
3662 
ipc_tlv_get_require_privacy(const mDNSu8 * const start,const mDNSu8 * const end)3663 mDNSlocal mDNSBool ipc_tlv_get_require_privacy(const mDNSu8 *const start, const mDNSu8 *const end)
3664 {
3665     size_t len = 0;
3666     const mDNSu8 *value = NULL;
3667     mdns_tlv16_get_value(start, end, IPC_TLV_TYPE_REQUIRE_PRIVACY, &len, &value, NULL);
3668     return ((len == 1) && (*value != 0)) ? mDNStrue : mDNSfalse;
3669 }
3670 #endif
3671 
_handle_queryrecord_request_start(request_state * request,const _queryrecord_start_params_t * const params)3672 mDNSlocal mStatus _handle_queryrecord_request_start(request_state *request, const _queryrecord_start_params_t * const params)
3673 {
3674     mStatus err;
3675 
3676     request->terminate = queryrecord_termination_callback;
3677 
3678     QueryRecordClientRequestParams queryParams;
3679     QueryRecordClientRequestParamsInit(&queryParams);
3680     queryParams.requestID      = request->request_id;
3681     queryParams.qnameStr       = params->qname;
3682     queryParams.interfaceIndex = params->interfaceIndex;
3683     queryParams.flags          = params->flags;
3684     queryParams.qtype          = params->qtype;
3685     queryParams.qclass         = params->qclass;
3686     queryParams.effectivePID   = request->validUUID ? 0 : request->process_id;
3687     queryParams.effectiveUUID  = request->validUUID ? request->uuid : mDNSNULL;
3688     queryParams.peerUID        = request->uid;
3689 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
3690     queryParams.needEncryption = params->require_privacy ? mDNStrue : mDNSfalse;
3691     queryParams.customID       = request->custom_service_id;
3692 #endif
3693 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
3694     queryParams.peerAuditToken = &request->audit_token;
3695 #endif
3696     err = QueryRecordClientRequestStart(&request->u.queryrecord, &queryParams, queryrecord_result_reply, request);
3697     return err;
3698 }
3699 
3700 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
3701 
_return_queryrecord_request_error(request_state * request,mStatus error)3702 mDNSlocal void _return_queryrecord_request_error(request_state * request, mStatus error)
3703 {
3704     size_t len;
3705     char * emptystr = "\0";
3706     char * data;
3707     reply_state *rep;
3708 
3709     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
3710        "[R%u] DNSService" PUB_S " _return_queryrecord_request_error: error(%d)",
3711        request->request_id, request->hdr.op == query_request ? "QueryRecord" : "GetAddrInfo", error);
3712 
3713     len = sizeof(DNSServiceFlags);  // calculate reply data length
3714     len += sizeof(mDNSu32);     // interface index
3715     len += sizeof(DNSServiceErrorType);
3716     len += strlen(emptystr) + 1;
3717     len += 3 * sizeof(mDNSu16); // type, class, rdlen
3718     len += 0;//answer->rdlength;
3719     len += sizeof(mDNSu32);     // TTL
3720 
3721     rep = create_reply(request->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, request);
3722 
3723     rep->rhdr->flags = 0;
3724     rep->rhdr->ifi   = 0;
3725     rep->rhdr->error = dnssd_htonl(error);
3726 
3727     data = (char *)&rep->rhdr[1];
3728 
3729     put_string(emptystr,    &data);
3730     put_uint16(0,           &data);
3731     put_uint16(0,           &data);
3732     put_uint16(0,           &data);
3733     data += 0;
3734     put_uint32(0,           &data);
3735 
3736     append_reply(request, rep);
3737 }
3738 
_handle_queryrecord_request_with_trust(request_state * request,const _queryrecord_start_params_t * const params)3739 mDNSlocal mStatus _handle_queryrecord_request_with_trust(request_state *request, const _queryrecord_start_params_t * const params)
3740 {
3741     mStatus err;
3742     if (audit_token_to_pid(request->audit_token) == 0)
3743     {
3744         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_queryrecord_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
3745         err = _handle_queryrecord_request_start(request, params);
3746     }
3747     else
3748     {
3749         const char *service_ptr = NULL;
3750         char type_str[MAX_ESCAPED_DOMAIN_NAME] = "";
3751         domainname query_name;
3752         if (MakeDomainNameFromDNSNameString(&query_name, params->qname))
3753         {
3754             domainlabel name;
3755             domainname type, domain;
3756             bool good = DeconstructServiceName(&query_name, &name, &type, &domain);
3757             if (good)
3758             {
3759                 ConvertDomainNameToCString(&type, type_str);
3760                 service_ptr = type_str;
3761             }
3762         }
3763 
3764         mdns_trust_flags_t flags = mdns_trust_flags_none;
3765         mdns_trust_status_t status = mdns_trust_check_query(request->audit_token, params->qname, service_ptr, params->qtype, (params->flags & kDNSServiceFlagsForceMulticast) != 0, &flags);
3766         switch (status)
3767         {
3768             case mdns_trust_status_denied:
3769             case mdns_trust_status_pending:
3770             {
3771                 mdns_trust_t trust = mdns_trust_create(request->audit_token, service_ptr, flags);
3772                 if (!trust )
3773                 {
3774                     err = mStatus_NoMemoryErr;
3775                     goto exit;
3776                 }
3777 
3778                 void * context = mallocL("context/_handle_queryrecord_request_with_trust", sizeof(_queryrecord_start_params_t));
3779                 if (!context)
3780                 {
3781                     my_perror("ERROR: mallocL context/_handle_queryrecord_request_with_trust");
3782                     mdns_release(trust);
3783                     err = mStatus_NoMemoryErr;
3784                     goto exit;
3785                 }
3786                 memcpy(context, params, sizeof(_queryrecord_start_params_t));
3787                 mdns_trust_set_context(trust, context);
3788                 mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
3789                 mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
3790                 {
3791                     if (event == mdns_trust_event_result)
3792                     {
3793                         mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
3794                         KQueueLock();
3795                         _queryrecord_start_params_t * _params =  mdns_trust_get_context(trust);
3796                         if (_params)
3797                         {
3798                             if (!error)
3799                             {
3800                                 error = _handle_queryrecord_request_start(request, _params);
3801                                 // No context means the request was canceled before we got here
3802                             }
3803                             if (error) // (not else if) Always check for error result
3804                             {
3805                                 _return_queryrecord_request_error(request, error);
3806                             }
3807                         }
3808                         KQueueUnlock("_handle_queryrecord_request_with_trust");
3809                     }
3810                 });
3811                 request->trust = trust;
3812                 mdns_trust_activate(trust);
3813                 err = mStatus_NoError;
3814                 break;
3815             }
3816 
3817             case mdns_trust_status_no_entitlement:
3818                 err = mStatus_NoAuth;
3819                 break;
3820 
3821             case mdns_trust_status_granted:
3822                 err = _handle_queryrecord_request_start(request, params);
3823                 break;
3824 
3825             default:
3826                 err = mStatus_UnknownErr;
3827                 break;
3828         }
3829     }
3830 exit:
3831     return err;
3832 }
3833 #endif // TRUST_ENFORCEMENT
3834 
handle_queryrecord_request(request_state * request)3835 mDNSlocal mStatus handle_queryrecord_request(request_state *request)
3836 {
3837     mStatus err;
3838     _queryrecord_start_params_t params;
3839 
3840     params.flags           = get_flags(&request->msgptr, request->msgend);
3841     params.interfaceIndex  = get_uint32(&request->msgptr, request->msgend);
3842     if (get_string(&request->msgptr, request->msgend, params.qname, sizeof(params.qname)) < 0)
3843     {
3844         err = mStatus_BadParamErr;
3845         goto exit;
3846     }
3847     params.qtype           = get_uint16(&request->msgptr, request->msgend);
3848     params.qclass          = get_uint16(&request->msgptr, request->msgend);
3849 
3850     if (!request->msgptr)
3851     {
3852         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
3853                "[R%d] DNSServiceQueryRecord(unreadable parameters)", request->request_id);
3854         err = mStatus_BadParamErr;
3855         goto exit;
3856     }
3857 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
3858     params.require_privacy = mDNSfalse;
3859 #endif
3860 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) && MDNSRESPONDER_SUPPORTS(APPLE, IPC_TLV)
3861     if (request->msgptr && (request->hdr.ipc_flags & IPC_FLAGS_TRAILING_TLVS))
3862     {
3863         size_t len;
3864         const mDNSu8 *const start = (const mDNSu8 *)request->msgptr;
3865         const mDNSu8 *const end = (const mDNSu8 *)request->msgend;
3866         const mDNSu8 *const data = ipc_tlv_get_resolver_config_plist_data(start, end, &len);
3867         if (data)
3868         {
3869             request->custom_service_id = Querier_RegisterCustomDNSServiceWithPListData(data, len);
3870         }
3871         params.require_privacy = ipc_tlv_get_require_privacy(start, end);
3872     }
3873 #endif
3874     request->flags          = params.flags;
3875     request->interfaceIndex = params.interfaceIndex;
3876 
3877     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
3878            "[R%d] DNSServiceQueryRecord(%X, %d, " PRI_S ", " PUB_S ") START PID[%d](" PUB_S ")",
3879            request->request_id, request->flags, request->interfaceIndex, params.qname, DNSTypeName(params.qtype), request->process_id,
3880            request->pid_name);
3881 
3882     mDNSPlatformMemZero(&request->u.queryrecord, (mDNSu32)sizeof(request->u.queryrecord));
3883     request->terminate = NULL;
3884 
3885 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
3886     if (os_feature_enabled(mDNSResponder, bonjour_privacy))
3887     {
3888         err = _handle_queryrecord_request_with_trust(request, &params);
3889     }
3890     else
3891     {
3892         err = _handle_queryrecord_request_start(request, &params);
3893     }
3894 #else
3895     err = _handle_queryrecord_request_start(request, &params);
3896 #endif
3897 
3898 exit:
3899     return(err);
3900 }
3901 
3902 // ***************************************************************************
3903 #if COMPILER_LIKES_PRAGMA_MARK
3904 #pragma mark -
3905 #pragma mark - DNSServiceEnumerateDomains
3906 #endif
3907 
format_enumeration_reply(request_state * request,const char * domain,DNSServiceFlags flags,mDNSu32 ifi,DNSServiceErrorType err)3908 mDNSlocal reply_state *format_enumeration_reply(request_state *request,
3909                                                 const char *domain, DNSServiceFlags flags, mDNSu32 ifi, DNSServiceErrorType err)
3910 {
3911     size_t len;
3912     reply_state *reply;
3913     char *data;
3914 
3915     len = sizeof(DNSServiceFlags);
3916     len += sizeof(mDNSu32);
3917     len += sizeof(DNSServiceErrorType);
3918     len += strlen(domain) + 1;
3919 
3920     reply = create_reply(enumeration_reply_op, len, request);
3921     reply->rhdr->flags = dnssd_htonl(flags);
3922     reply->rhdr->ifi   = dnssd_htonl(ifi);
3923     reply->rhdr->error = dnssd_htonl(err);
3924     data = (char *)&reply->rhdr[1];
3925     put_string(domain, &data);
3926     return reply;
3927 }
3928 
enum_termination_callback(request_state * request)3929 mDNSlocal void enum_termination_callback(request_state *request)
3930 {
3931     // Stop the domain enumeration queries to discover the WAB Browse/Registration domains
3932     if (request->u.enumeration.flags & kDNSServiceFlagsRegistrationDomains)
3933     {
3934         LogInfo("%3d: DNSServiceEnumeration Cancel WAB Registration PID[%d](%s)", request->sd, request->process_id, request->pid_name);
3935         uDNS_StopWABQueries(&mDNSStorage, UDNS_WAB_REG_QUERY);
3936     }
3937     else
3938     {
3939         LogInfo("%3d: DNSServiceEnumeration Cancel WAB Browse PID[%d](%s)", request->sd, request->process_id, request->pid_name);
3940         uDNS_StopWABQueries(&mDNSStorage, UDNS_WAB_BROWSE_QUERY | UDNS_WAB_LBROWSE_QUERY);
3941         mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_autoall);
3942     }
3943     mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all);
3944     mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_default);
3945 }
3946 
enum_result_callback(mDNS * const m,DNSQuestion * const question,const ResourceRecord * const answer,QC_result AddRecord)3947 mDNSlocal void enum_result_callback(mDNS *const m,
3948                                     DNSQuestion *const question, const ResourceRecord *const answer, QC_result AddRecord)
3949 {
3950     char domain[MAX_ESCAPED_DOMAIN_NAME];
3951     request_state *request = question->QuestionContext;
3952     DNSServiceFlags flags = 0;
3953     reply_state *reply;
3954     (void)m; // Unused
3955 
3956     if (answer->rrtype != kDNSType_PTR) return;
3957 
3958 #if 0
3959     if (!AuthorizedDomain(request, &answer->rdata->u.name, request->u.enumeration.flags ? AutoRegistrationDomains : AutoBrowseDomains)) return;
3960 #endif
3961 
3962     // We only return add/remove events for the browse and registration lists
3963     // For the default browse and registration answers, we only give an "ADD" event
3964     if (question == &request->u.enumeration.q_default && !AddRecord) return;
3965 
3966     if (AddRecord)
3967     {
3968         flags |= kDNSServiceFlagsAdd;
3969         if (question == &request->u.enumeration.q_default) flags |= kDNSServiceFlagsDefault;
3970     }
3971 
3972     ConvertDomainNameToCString(&answer->rdata->u.name, domain);
3973     // Note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
3974     // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
3975     // network, so we just pass kDNSServiceInterfaceIndexAny
3976     reply = format_enumeration_reply(request, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
3977     if (!reply) { LogMsg("ERROR: enum_result_callback, format_enumeration_reply"); return; }
3978 
3979     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
3980            "[R%d->Q%d] DNSServiceEnumerateDomains(%2.*s) RESULT " PUB_S ": " PRI_S,
3981            request->request_id, mDNSVal16(question->TargetQID), question->qname.c[0], &question->qname.c[1],
3982            AddRecord ? "ADD" : "RMV", domain);
3983 
3984     append_reply(request, reply);
3985 }
3986 
handle_enum_request(request_state * request)3987 mDNSlocal mStatus handle_enum_request(request_state *request)
3988 {
3989     mStatus err;
3990     DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
3991     DNSServiceFlags reg = flags & kDNSServiceFlagsRegistrationDomains;
3992     mDNS_DomainType t_all     = reg ? mDNS_DomainTypeRegistration        : mDNS_DomainTypeBrowse;
3993     mDNS_DomainType t_default = reg ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault;
3994     mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
3995     mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
3996     if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
3997 
3998     if (!request->msgptr)
3999     { LogMsg("%3d: DNSServiceEnumerateDomains(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
4000 
4001     request->flags = flags;
4002     request->interfaceIndex = interfaceIndex;
4003 
4004     // mark which kind of enumeration we're doing so that we know what domain enumeration queries to stop
4005     request->u.enumeration.flags = reg;
4006 
4007     // enumeration requires multiple questions, so we must link all the context pointers so that
4008     // necessary context can be reached from the callbacks
4009     request->u.enumeration.q_all.QuestionContext = request;
4010     request->u.enumeration.q_default.QuestionContext = request;
4011     if (!reg) request->u.enumeration.q_autoall.QuestionContext = request;
4012 
4013     // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
4014     if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
4015 
4016     // make the calls
4017     LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", request->sd, flags,
4018                  (flags & kDNSServiceFlagsBrowseDomains      ) ? "kDNSServiceFlagsBrowseDomains" :
4019                  (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
4020     err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_all, t_all, NULL, InterfaceID, enum_result_callback, request);
4021     if (!err)
4022     {
4023         err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_default, t_default, NULL, InterfaceID, enum_result_callback, request);
4024         if (err) mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all);
4025         else if (!reg)
4026         {
4027             err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_autoall, mDNS_DomainTypeBrowseAutomatic, NULL, InterfaceID, enum_result_callback, request);
4028             if (err)
4029             {
4030                 mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all);
4031                 mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_default);
4032             }
4033         }
4034         if (!err) request->terminate = enum_termination_callback;
4035     }
4036     if (!err)
4037     {
4038         // Start the domain enumeration queries to discover the WAB Browse/Registration domains
4039         if (reg)
4040         {
4041             LogInfo("%3d: DNSServiceEnumerateDomains Start WAB Registration PID[%d](%s)", request->sd, request->process_id, request->pid_name);
4042             uDNS_StartWABQueries(&mDNSStorage, UDNS_WAB_REG_QUERY);
4043         }
4044         else
4045         {
4046             LogInfo("%3d: DNSServiceEnumerateDomains Start WAB Browse PID[%d](%s)", request->sd, request->process_id, request->pid_name);
4047             uDNS_StartWABQueries(&mDNSStorage, UDNS_WAB_BROWSE_QUERY | UDNS_WAB_LBROWSE_QUERY);
4048         }
4049     }
4050 
4051     return(err);
4052 }
4053 
4054 // ***************************************************************************
4055 #if COMPILER_LIKES_PRAGMA_MARK
4056 #pragma mark -
4057 #pragma mark - DNSServiceReconfirmRecord & Misc
4058 #endif
4059 
handle_reconfirm_request(request_state * request)4060 mDNSlocal mStatus handle_reconfirm_request(request_state *request)
4061 {
4062     mStatus status = mStatus_BadParamErr;
4063     AuthRecord *rr = read_rr_from_ipc_msg(request, 0, 0);
4064     if (rr)
4065     {
4066         status = mDNS_ReconfirmByValue(&mDNSStorage, &rr->resrec);
4067         LogOperation(
4068             (status == mStatus_NoError) ?
4069             "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated PID[%d](%s)" :
4070             "%3d: DNSServiceReconfirmRecord(%s) interface %d failed PID[%d](%s) status %d",
4071             request->sd, RRDisplayString(&mDNSStorage, &rr->resrec),
4072             mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, rr->resrec.InterfaceID, mDNSfalse),
4073             request->process_id, request->pid_name, status);
4074         freeL("AuthRecord/handle_reconfirm_request", rr);
4075     }
4076     return(status);
4077 }
4078 
4079 #if APPLE_OSX_mDNSResponder
4080 
handle_release_request(request_state * request)4081 mDNSlocal mStatus handle_release_request(request_state *request)
4082 {
4083     mStatus err = 0;
4084     char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
4085     domainname instance;
4086 
4087     // extract the data from the message
4088     DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
4089 
4090     if (get_string(&request->msgptr, request->msgend, name,    sizeof(name   )) < 0 ||
4091         get_string(&request->msgptr, request->msgend, regtype, sizeof(regtype)) < 0 ||
4092         get_string(&request->msgptr, request->msgend, domain,  sizeof(domain )) < 0)
4093     {
4094         LogMsg("ERROR: handle_release_request - Couldn't read name/regtype/domain");
4095         return(mStatus_BadParamErr);
4096     }
4097 
4098     if (!request->msgptr)
4099     {
4100         LogMsg("%3d: PeerConnectionRelease(unreadable parameters)", request->sd);
4101         return(mStatus_BadParamErr);
4102     }
4103 
4104     if (build_domainname_from_strings(&instance, name, regtype, domain) < 0)
4105     {
4106         LogMsg("ERROR: handle_release_request bad “%s” “%s” “%s”", name, regtype, domain);
4107         return(mStatus_BadParamErr);
4108     }
4109 
4110     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
4111            "[R%d] PeerConnectionRelease(%X " PRI_DM_NAME ") START PID[%d](" PUB_S ")",
4112            request->request_id, flags, DM_NAME_PARAM(&instance), request->process_id, request->pid_name);
4113 
4114 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
4115     external_connection_release(&instance);
4116 #endif
4117     return(err);
4118 }
4119 
4120 #else   // APPLE_OSX_mDNSResponder
4121 
handle_release_request(request_state * request)4122 mDNSlocal mStatus handle_release_request(request_state *request)
4123 {
4124     (void) request;
4125     return mStatus_UnsupportedErr;
4126 }
4127 
4128 #endif  // APPLE_OSX_mDNSResponder
4129 
handle_setdomain_request(request_state * request)4130 mDNSlocal mStatus handle_setdomain_request(request_state *request)
4131 {
4132     char domainstr[MAX_ESCAPED_DOMAIN_NAME];
4133     domainname domain;
4134     DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
4135     (void)flags; // Unused
4136     if (get_string(&request->msgptr, request->msgend, domainstr, sizeof(domainstr)) < 0 ||
4137         !MakeDomainNameFromDNSNameString(&domain, domainstr))
4138     { LogMsg("%3d: DNSServiceSetDefaultDomainForUser(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
4139 
4140     LogOperation("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
4141     return(mStatus_NoError);
4142 }
4143 
4144 typedef packedstruct
4145 {
4146     mStatus err;
4147     mDNSu32 len;
4148     mDNSu32 vers;
4149 } DaemonVersionReply;
4150 
handle_getproperty_request(request_state * request)4151 mDNSlocal void handle_getproperty_request(request_state *request)
4152 {
4153     const mStatus BadParamErr = dnssd_htonl((mDNSu32)mStatus_BadParamErr);
4154     char prop[256];
4155     if (get_string(&request->msgptr, request->msgend, prop, sizeof(prop)) >= 0)
4156     {
4157         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
4158                "[R%d] DNSServiceGetProperty(" PUB_S ")", request->request_id, prop);
4159         if (!strcmp(prop, kDNSServiceProperty_DaemonVersion))
4160         {
4161             DaemonVersionReply x = { 0, dnssd_htonl(4), dnssd_htonl(_DNS_SD_H) };
4162             send_all(request->sd, (const char *)&x, sizeof(x));
4163             return;
4164         }
4165     }
4166 
4167     // If we didn't recogize the requested property name, return BadParamErr
4168     send_all(request->sd, (const char *)&BadParamErr, sizeof(BadParamErr));
4169 }
4170 
4171 #ifdef APPLE_OSX_mDNSResponder
4172 // The caller can specify either the pid or the uuid. If the pid is not specified,
4173 // update the effective uuid. Don't overwrite the pid which is used for debugging
4174 // purposes and initialized when the socket is opened.
handle_connection_delegate_request(request_state * request)4175 mDNSlocal void handle_connection_delegate_request(request_state *request)
4176 {
4177     mDNSs32 pid;
4178     socklen_t len;
4179 
4180     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
4181            "[R%d] DNSServiceCreateDelegateConnection START PID[%d](" PUB_S  ")",
4182            request->request_id, request->process_id, request->pid_name);
4183     request->terminate = connection_termination;
4184 
4185     len = 0;
4186     pid = get_uint32(&request->msgptr, request->msgend);
4187 #ifdef LOCAL_PEEREPID
4188     if (pid)
4189     {
4190         len = sizeof(pid);
4191         if (getsockopt(request->sd, SOL_LOCAL, LOCAL_PEEREPID, &request->process_id, &len) != 0)
4192         {
4193             LogMsg("handle_connection_delegate_request: getsockopt for LOCAL_PEEREPID failed errno:%d / %s", errno, strerror(errno));
4194             return;
4195         }
4196         // to extract the process name from the pid value
4197         if (proc_pidinfo(request->process_id, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0)
4198             return;
4199         mDNSPlatformStrLCopy(request->pid_name, proc.pbsi_comm, sizeof(request->pid_name));
4200         debugf("handle_connection_delegate_request: process id %d, name %s", request->process_id, request->pid_name);
4201     }
4202 #endif
4203 #ifdef LOCAL_PEEREUUID
4204     if (!pid)
4205     {
4206         len = UUID_SIZE;
4207         if (getsockopt(request->sd, SOL_LOCAL, LOCAL_PEEREUUID, request->uuid, &len) != 0)
4208         {
4209             LogMsg("handle_connection_delegate_request: getsockopt for LOCAL_PEEREUUID failed errno:%d / %s", errno, strerror(errno));
4210             return;
4211         }
4212         request->validUUID = mDNStrue;
4213     }
4214 #endif
4215 }
4216 #else
handle_connection_delegate_request(request_state * request)4217 mDNSlocal void handle_connection_delegate_request(request_state *request)
4218 {
4219     (void) request;
4220 }
4221 #endif
4222 
4223 typedef packedstruct
4224 {
4225     mStatus err;
4226     mDNSs32 pid;
4227 } PIDInfo;
4228 
4229 // ***************************************************************************
4230 #if COMPILER_LIKES_PRAGMA_MARK
4231 #pragma mark -
4232 #pragma mark - DNSServiceNATPortMappingCreate
4233 #endif
4234 
4235 #define DNSServiceProtocol(X) ((X) == NATOp_AddrRequest ? 0 : (X) == NATOp_MapUDP ? kDNSServiceProtocol_UDP : kDNSServiceProtocol_TCP)
4236 
port_mapping_termination_callback(request_state * request)4237 mDNSlocal void port_mapping_termination_callback(request_state *request)
4238 {
4239     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP PID[%d](" PUB_S ")",
4240            request->request_id, DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
4241            mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
4242            request->process_id, request->pid_name);
4243 
4244     mDNS_StopNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
4245 }
4246 
4247 // Called via function pointer when we get a NAT Traversal (address request or port mapping) response
port_mapping_create_request_callback(mDNS * m,NATTraversalInfo * n)4248 mDNSlocal void port_mapping_create_request_callback(mDNS *m, NATTraversalInfo *n)
4249 {
4250     request_state *request = (request_state *)n->clientContext;
4251     reply_state *rep;
4252     int replyLen;
4253     char *data;
4254 
4255     if (!request) { LogMsg("port_mapping_create_request_callback called with unknown request_state object"); return; }
4256 
4257     // calculate reply data length
4258     replyLen = sizeof(DNSServiceFlags);
4259     replyLen += 3 * sizeof(mDNSu32);  // if index + addr + ttl
4260     replyLen += sizeof(DNSServiceErrorType);
4261     replyLen += 2 * sizeof(mDNSu16);  // Internal Port + External Port
4262     replyLen += sizeof(mDNSu8);       // protocol
4263 
4264     rep = create_reply(port_mapping_reply_op, replyLen, request);
4265 
4266     rep->rhdr->flags = dnssd_htonl(0);
4267     rep->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, n->InterfaceID, mDNSfalse));
4268     rep->rhdr->error = dnssd_htonl(n->Result);
4269 
4270     data = (char *)&rep->rhdr[1];
4271 
4272     *data++ = request->u.pm.NATinfo.ExternalAddress.b[0];
4273     *data++ = request->u.pm.NATinfo.ExternalAddress.b[1];
4274     *data++ = request->u.pm.NATinfo.ExternalAddress.b[2];
4275     *data++ = request->u.pm.NATinfo.ExternalAddress.b[3];
4276     *data++ = DNSServiceProtocol(request->u.pm.NATinfo.Protocol);
4277     *data++ = request->u.pm.NATinfo.IntPort.b[0];
4278     *data++ = request->u.pm.NATinfo.IntPort.b[1];
4279     *data++ = request->u.pm.NATinfo.ExternalPort.b[0];
4280     *data++ = request->u.pm.NATinfo.ExternalPort.b[1];
4281     put_uint32(request->u.pm.NATinfo.Lifetime, &data);
4282 
4283     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
4284            "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) RESULT " PRI_IPv4_ADDR ":%u TTL %u",
4285            request->request_id, DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
4286            mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
4287            &request->u.pm.NATinfo.ExternalAddress, mDNSVal16(request->u.pm.NATinfo.ExternalPort),
4288            request->u.pm.NATinfo.Lifetime);
4289 
4290     append_reply(request, rep);
4291 }
4292 
handle_port_mapping_request(request_state * request)4293 mDNSlocal mStatus handle_port_mapping_request(request_state *request)
4294 {
4295     mDNSu32 ttl = 0;
4296     mStatus err = mStatus_NoError;
4297 
4298     DNSServiceFlags flags          = get_flags(&request->msgptr, request->msgend);
4299     mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
4300     mDNSInterfaceID InterfaceID    = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
4301     mDNSu8 protocol       = (mDNSu8)get_uint32(&request->msgptr, request->msgend);
4302     (void)flags; // Unused
4303     if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
4304     if (request->msgptr + 8 > request->msgend) request->msgptr = NULL;
4305     else
4306     {
4307         request->u.pm.NATinfo.IntPort.b[0] = *request->msgptr++;
4308         request->u.pm.NATinfo.IntPort.b[1] = *request->msgptr++;
4309         request->u.pm.ReqExt.b[0]          = *request->msgptr++;
4310         request->u.pm.ReqExt.b[1]          = *request->msgptr++;
4311         ttl = get_uint32(&request->msgptr, request->msgend);
4312     }
4313 
4314     if (!request->msgptr)
4315     {
4316         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
4317                "[R%d] DNSServiceNATPortMappingCreate(unreadable parameters)", request->request_id);
4318         return(mStatus_BadParamErr);
4319     }
4320 
4321     if (protocol == 0)  // If protocol == 0 (i.e. just request public address) then IntPort, ExtPort, ttl must be zero too
4322     {
4323         if (!mDNSIPPortIsZero(request->u.pm.NATinfo.IntPort) || !mDNSIPPortIsZero(request->u.pm.ReqExt) || ttl) return(mStatus_BadParamErr);
4324     }
4325     else
4326     {
4327         if (mDNSIPPortIsZero(request->u.pm.NATinfo.IntPort)) return(mStatus_BadParamErr);
4328         if (!(protocol & (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP))) return(mStatus_BadParamErr);
4329     }
4330 
4331     request->flags                       = flags;
4332     request->interfaceIndex              = interfaceIndex;
4333     request->u.pm.NATinfo.Protocol       = !protocol ? NATOp_AddrRequest : (protocol == kDNSServiceProtocol_UDP) ? NATOp_MapUDP : NATOp_MapTCP;
4334     //       u.pm.NATinfo.IntPort        = already set above
4335     request->u.pm.NATinfo.RequestedPort  = request->u.pm.ReqExt;
4336     request->u.pm.NATinfo.NATLease       = ttl;
4337     request->u.pm.NATinfo.clientCallback = port_mapping_create_request_callback;
4338     request->u.pm.NATinfo.clientContext  = request;
4339 
4340     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
4341            "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START PID[%d](" PUB_S ")",
4342            request->request_id, protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt),
4343            request->u.pm.NATinfo.NATLease, request->process_id, request->pid_name);
4344     err = mDNS_StartNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
4345     if (err) LogMsg("ERROR: mDNS_StartNATOperation: %d", (int)err);
4346     else request->terminate = port_mapping_termination_callback;
4347 
4348     return(err);
4349 }
4350 
4351 // ***************************************************************************
4352 #if COMPILER_LIKES_PRAGMA_MARK
4353 #pragma mark -
4354 #pragma mark - DNSServiceGetAddrInfo
4355 #endif
4356 
addrinfo_termination_callback(request_state * request)4357 mDNSlocal void addrinfo_termination_callback(request_state *request)
4358 {
4359     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
4360            "[R%u] DNSServiceGetAddrInfo(" PRI_DM_NAME ") STOP PID[%d](" PUB_S ")",
4361            request->request_id, DM_NAME_PARAM(GetAddrInfoClientRequestGetQName(&request->u.addrinfo)),
4362            request->process_id, request->pid_name);
4363 
4364     GetAddrInfoClientRequestStop(&request->u.addrinfo);
4365 }
4366 
4367 typedef struct {
4368     mDNSu32     protocols;
4369     char        hostname[MAX_ESCAPED_DOMAIN_NAME];
4370 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
4371     mDNSBool    require_privacy;
4372 #endif
4373 } _addrinfo_start_params_t;
4374 
_handle_addrinfo_request_start(request_state * request,const _addrinfo_start_params_t * const params)4375 mDNSlocal mStatus _handle_addrinfo_request_start(request_state *request, const _addrinfo_start_params_t * const params)
4376 {
4377     mStatus err;
4378 
4379     request->terminate = addrinfo_termination_callback;
4380 
4381     GetAddrInfoClientRequestParams gaiParams;
4382     GetAddrInfoClientRequestParamsInit(&gaiParams);
4383     gaiParams.requestID      = request->request_id;
4384     gaiParams.hostnameStr    = params->hostname;
4385     gaiParams.interfaceIndex = request->interfaceIndex;
4386     gaiParams.flags          = request->flags;
4387     gaiParams.protocols      = params->protocols;
4388     gaiParams.effectivePID   = request->validUUID ? 0 : request->process_id;
4389     gaiParams.effectiveUUID  = request->validUUID ? request->uuid : mDNSNULL;
4390     gaiParams.peerUID        = request->uid;
4391 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
4392     gaiParams.needEncryption = params->require_privacy ? mDNStrue : mDNSfalse;
4393     gaiParams.customID       = request->custom_service_id;
4394 #endif
4395 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
4396     gaiParams.peerAuditToken = &request->audit_token;
4397 #endif
4398     err = GetAddrInfoClientRequestStart(&request->u.addrinfo, &gaiParams, queryrecord_result_reply, request);
4399 
4400     return err;
4401 }
4402 
4403 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
4404 
_return_addrinfo_request_error(request_state * request,mStatus error)4405 mDNSlocal void _return_addrinfo_request_error(request_state * request, mStatus error)
4406 {
4407     _return_queryrecord_request_error(request, error);
4408 }
4409 
_handle_addrinfo_request_with_trust(request_state * request,const _addrinfo_start_params_t * const params)4410 mDNSlocal mStatus _handle_addrinfo_request_with_trust(request_state *request, const _addrinfo_start_params_t * const params)
4411 {
4412     mStatus err;
4413     if (audit_token_to_pid(request->audit_token) == 0)
4414     {
4415         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_addrinfo_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
4416         err = _handle_addrinfo_request_start(request, params);
4417     }
4418     else
4419     {
4420         mdns_trust_flags_t flags = mdns_trust_flags_none;
4421         mdns_trust_status_t status = mdns_trust_check_getaddrinfo(request->audit_token, params->hostname, &flags);
4422         switch (status)
4423         {
4424             case mdns_trust_status_denied:
4425             case mdns_trust_status_pending:
4426             {
4427                 mdns_trust_t trust = mdns_trust_create(request->audit_token, NULL, flags);
4428                 if (!trust )
4429                 {
4430                     err = mStatus_NoMemoryErr;
4431                     goto exit;
4432                 }
4433 
4434                 void * context = mallocL("context/_handle_addrinfo_request_with_trust", sizeof(_addrinfo_start_params_t));
4435                 if (!context)
4436                 {
4437                     my_perror("ERROR: mallocL context/_handle_addrinfo_request_with_trust");
4438                     mdns_release(trust);
4439                     err = mStatus_NoMemoryErr;
4440                     goto exit;
4441                 }
4442                 memcpy(context, params, sizeof(_addrinfo_start_params_t));
4443                 mdns_trust_set_context(trust, context);
4444                 mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
4445                 mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
4446                 {
4447                     if (event == mdns_trust_event_result)
4448                     {
4449                         mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
4450                         KQueueLock();
4451                         _addrinfo_start_params_t * _params =  mdns_trust_get_context(trust);
4452                         if (_params)
4453                         {
4454                             if (!error)
4455                             {
4456                                 error = _handle_addrinfo_request_start(request, _params);
4457                                 // No context means the request was canceled before we got here
4458                             }
4459                             if (error) // (not else if) Always check for error result
4460                             {
4461                                 _return_addrinfo_request_error(request, error);
4462                             }
4463                         }
4464                         KQueueUnlock("_handle_addrinfo_request_with_trust");
4465                     }
4466                 });
4467                 request->trust = trust;
4468                 mdns_trust_activate(trust);
4469                 err = mStatus_NoError;
4470                 break;
4471             }
4472 
4473             case mdns_trust_status_no_entitlement:
4474                 err = mStatus_NoAuth;
4475                 break;
4476 
4477             case mdns_trust_status_granted:
4478                 err = _handle_addrinfo_request_start(request, params);
4479                 break;
4480 
4481             default:
4482                 err = mStatus_UnknownErr;
4483                 break;
4484         }
4485     }
4486 exit:
4487     return err;
4488 }
4489 #endif // TRUST_ENFORCEMENT
4490 
handle_addrinfo_request(request_state * request)4491 mDNSlocal mStatus handle_addrinfo_request(request_state *request)
4492 {
4493     mStatus             err;
4494     DNSServiceFlags     flags;
4495     mDNSu32             interfaceIndex;
4496     _addrinfo_start_params_t params;
4497 
4498     flags               = get_flags(&request->msgptr, request->msgend);
4499     interfaceIndex      = get_uint32(&request->msgptr, request->msgend);
4500     params.protocols    = get_uint32(&request->msgptr, request->msgend);
4501     if (get_string(&request->msgptr, request->msgend, params.hostname, sizeof(params.hostname)) < 0)
4502     {
4503         err = mStatus_BadParamErr;
4504         goto exit;
4505     }
4506     if (!request->msgptr)
4507     {
4508         LogMsg("%3d: DNSServiceGetAddrInfo(unreadable parameters)", request->sd);
4509         err = mStatus_BadParamErr;
4510         goto exit;
4511     }
4512 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
4513     params.require_privacy = mDNSfalse;
4514 #endif
4515 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) && MDNSRESPONDER_SUPPORTS(APPLE, IPC_TLV)
4516     if (request->msgptr && (request->hdr.ipc_flags & IPC_FLAGS_TRAILING_TLVS))
4517     {
4518         size_t len;
4519         const mDNSu8 *const start = (const mDNSu8 *)request->msgptr;
4520         const mDNSu8 *const end = (const mDNSu8 *)request->msgend;
4521         const mDNSu8 *const data = ipc_tlv_get_resolver_config_plist_data(start, end, &len);
4522         if (data)
4523         {
4524             request->custom_service_id = Querier_RegisterCustomDNSServiceWithPListData(data, len);
4525         }
4526         params.require_privacy = ipc_tlv_get_require_privacy(start, end);
4527     }
4528 #endif
4529     request->flags          = flags;
4530     request->interfaceIndex = interfaceIndex;
4531 
4532     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
4533            "[R%u] DNSServiceGetAddrInfo(%X, %d, %u, " PRI_S ") START PID[%d](" PUB_S ")",
4534            request->request_id, request->flags, request->interfaceIndex, params.protocols, params.hostname, request->process_id,
4535            request->pid_name);
4536 
4537     mDNSPlatformMemZero(&request->u.addrinfo, (mDNSu32)sizeof(request->u.addrinfo));
4538     request->terminate = NULL;
4539 
4540 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
4541     if (os_feature_enabled(mDNSResponder, bonjour_privacy))
4542     {
4543         err = _handle_addrinfo_request_with_trust(request, &params);
4544     }
4545     else
4546     {
4547         err = _handle_addrinfo_request_start(request, &params);
4548     }
4549 #else
4550     err = _handle_addrinfo_request_start(request, &params);
4551 #endif
4552 
4553 exit:
4554     return(err);
4555 }
4556 
4557 // ***************************************************************************
4558 #if COMPILER_LIKES_PRAGMA_MARK
4559 #pragma mark -
4560 #pragma mark - Main Request Handler etc.
4561 #endif
4562 
NewRequest(void)4563 mDNSlocal request_state *NewRequest(void)
4564 {
4565     request_state *request;
4566     request_state **p = &all_requests;
4567     request = (request_state *) callocL("request_state", sizeof(*request));
4568     if (!request) FatalError("ERROR: calloc");
4569     while (*p) p = &(*p)->next;
4570     *p = request;
4571     return(request);
4572 }
4573 
4574 // read_msg may be called any time when the transfer state (req->ts) is t_morecoming.
4575 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
read_msg(request_state * req)4576 mDNSlocal void read_msg(request_state *req)
4577 {
4578     if (req->ts == t_terminated || req->ts == t_error)
4579     {
4580         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4581                   "[R%u] ERROR: read_msg called with transfer state terminated or error", req->request_id);
4582         req->ts = t_error;
4583         return;
4584     }
4585 
4586     if (req->ts == t_complete)  // this must be death or something is wrong
4587     {
4588         char buf[4];    // dummy for death notification
4589         int nread = udsSupportReadFD(req->sd, buf, 4, 0, req->platform_data);
4590         if (!nread) { req->ts = t_terminated; return; }
4591         if (nread < 0) goto rerror;
4592         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4593                   "[R%u] ERROR: read data from a completed request", req->request_id);
4594         req->ts = t_error;
4595         return;
4596     }
4597 
4598     if (req->ts != t_morecoming)
4599     {
4600         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4601                   "[R%u] ERROR: read_msg called with invalid transfer state (%d)", req->request_id, req->ts);
4602         req->ts = t_error;
4603         return;
4604     }
4605 
4606     if (req->hdr_bytes < sizeof(ipc_msg_hdr))
4607     {
4608         mDNSu32 nleft = sizeof(ipc_msg_hdr) - req->hdr_bytes;
4609         int nread = udsSupportReadFD(req->sd, (char *)&req->hdr + req->hdr_bytes, nleft, 0, req->platform_data);
4610         if (nread == 0) { req->ts = t_terminated; return; }
4611         if (nread < 0) goto rerror;
4612         req->hdr_bytes += nread;
4613         if (req->hdr_bytes > sizeof(ipc_msg_hdr))
4614         {
4615             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4616                       "[R%u] ERROR: read_msg - read too many header bytes", req->request_id);
4617             req->ts = t_error;
4618             return;
4619         }
4620 
4621         // only read data if header is complete
4622         if (req->hdr_bytes == sizeof(ipc_msg_hdr))
4623         {
4624             ConvertHeaderBytes(&req->hdr);
4625             if (req->hdr.version != VERSION)
4626             {
4627                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4628                           "[R%u] ERROR: client version 0x%08X daemon version 0x%08X", req->request_id, req->hdr.version, VERSION);
4629                 req->ts = t_error;
4630                 return;
4631             }
4632 
4633             // Largest conceivable single request is a DNSServiceRegisterRecord() or DNSServiceAddRecord()
4634             // with 64kB of rdata. Adding 1009 byte for a maximal domain name, plus a safety margin
4635             // for other overhead, this means any message above 70kB is definitely bogus.
4636             if (req->hdr.datalen > 70000)
4637             {
4638                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4639                           "[R%u] ERROR: read_msg: hdr.datalen %u (0x%X) > 70000", req->request_id, req->hdr.datalen, req->hdr.datalen);
4640                 req->ts = t_error;
4641                 return;
4642             }
4643             req->msgbuf = (char *) callocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
4644             if (!req->msgbuf) { my_perror("ERROR: calloc"); req->ts = t_error; return; }
4645             req->msgptr = req->msgbuf;
4646             req->msgend = req->msgbuf + req->hdr.datalen;
4647         }
4648     }
4649 
4650     // If our header is complete, but we're still needing more body data, then try to read it now
4651     // Note: For cancel_request req->hdr.datalen == 0, but there's no error return socket for cancel_request
4652     // Any time we need to get the error return socket we know we'll have at least one data byte
4653     // (even if only the one-byte empty C string placeholder for the old ctrl_path parameter)
4654     if (req->hdr_bytes == sizeof(ipc_msg_hdr) && req->data_bytes < req->hdr.datalen)
4655     {
4656         mDNSu32 nleft = req->hdr.datalen - req->data_bytes;
4657         ssize_t nread;
4658 #if !defined(_WIN32)
4659         struct iovec vec = { req->msgbuf + req->data_bytes, nleft };    // Tell recvmsg where we want the bytes put
4660         struct msghdr msg;
4661         struct cmsghdr *cmsg;
4662         char cbuf[CMSG_SPACE(4 * sizeof(dnssd_sock_t))];
4663         msg.msg_name       = 0;
4664         msg.msg_namelen    = 0;
4665         msg.msg_iov        = &vec;
4666         msg.msg_iovlen     = 1;
4667         msg.msg_control    = cbuf;
4668         msg.msg_controllen = sizeof(cbuf);
4669         msg.msg_flags      = 0;
4670         nread = recvmsg(req->sd, &msg, 0);
4671 #else
4672         nread = udsSupportReadFD(req->sd, (char *)req->msgbuf + req->data_bytes, nleft, 0, req->platform_data);
4673 #endif
4674         if (nread == 0) { req->ts = t_terminated; return; }
4675         if (nread < 0) goto rerror;
4676         req->data_bytes += nread;
4677         if (req->data_bytes > req->hdr.datalen)
4678         {
4679             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4680                       "[R%u] ERROR: read_msg - read too many data bytes", req->request_id);
4681             req->ts = t_error;
4682             return;
4683         }
4684 #if !defined(_WIN32)
4685         cmsg = CMSG_FIRSTHDR(&msg);
4686 #if DEBUG_64BIT_SCM_RIGHTS
4687         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
4688                   "[R%u] Expecting %d %d %d %d", req->request_id, sizeof(cbuf), sizeof(cbuf), SOL_SOCKET, SCM_RIGHTS);
4689         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
4690                   "[R%u] Got       %d %d %d %d", req->request_id, msg.msg_controllen, cmsg ? cmsg->cmsg_len : -1, cmsg ? cmsg->cmsg_level : -1, cmsg ? cmsg->cmsg_type : -1);
4691 #endif // DEBUG_64BIT_SCM_RIGHTS
4692         if (cmsg && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
4693         {
4694 #if APPLE_OSX_mDNSResponder
4695             // Strictly speaking BPF_fd belongs solely in the platform support layer, but because
4696             // of privilege separation on Mac OS X we need to get BPF_fd from mDNSResponderHelper,
4697             // and it's convenient to repurpose the existing fd-passing code here for that task
4698             if (req->hdr.op == send_bpf)
4699             {
4700                 dnssd_sock_t x = *(dnssd_sock_t *)CMSG_DATA(cmsg);
4701                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
4702                           "[R%u] Got len %d, BPF %d", req->request_id, cmsg->cmsg_len, x);
4703                 mDNSPlatformReceiveBPF_fd(x);
4704             }
4705             else
4706 #endif // APPLE_OSX_mDNSResponder
4707             req->errsd = *(dnssd_sock_t *)CMSG_DATA(cmsg);
4708 #if DEBUG_64BIT_SCM_RIGHTS
4709             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
4710                       "[R%u] read req->errsd %d", req->request_id, req->errsd);
4711 #endif // DEBUG_64BIT_SCM_RIGHTS
4712             if (req->data_bytes < req->hdr.datalen)
4713             {
4714                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
4715                           "[R%u] Client(PID [%d](" PUB_S ")) sent result code socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d",
4716                           req->request_id, req->process_id, req->pid_name, req->errsd, req->data_bytes, req->hdr.datalen);
4717                 req->ts = t_error;
4718                 return;
4719             }
4720         }
4721 #endif
4722     }
4723 
4724     // If our header and data are both complete, see if we need to make our separate error return socket
4725     if (req->hdr_bytes == sizeof(ipc_msg_hdr) && req->data_bytes == req->hdr.datalen)
4726     {
4727         if (req->terminate && req->hdr.op != cancel_request)
4728         {
4729             dnssd_sockaddr_t cliaddr;
4730 #if defined(USE_TCP_LOOPBACK)
4731             mDNSOpaque16 port;
4732             u_long opt = 1;
4733             port.b[0] = req->msgptr[0];
4734             port.b[1] = req->msgptr[1];
4735             req->msgptr += 2;
4736             cliaddr.sin_family      = AF_INET;
4737             cliaddr.sin_port        = port.NotAnInteger;
4738             cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
4739 #else
4740             char ctrl_path[MAX_CTLPATH];
4741             get_string(&req->msgptr, req->msgend, ctrl_path, MAX_CTLPATH);  // path is first element in message buffer
4742             mDNSPlatformMemZero(&cliaddr, sizeof(cliaddr));
4743             cliaddr.sun_family = AF_LOCAL;
4744             mDNSPlatformStrLCopy(cliaddr.sun_path, ctrl_path, sizeof(cliaddr.sun_path));
4745             // If the error return path UDS name is empty string, that tells us
4746             // that this is a new version of the library that's going to pass us
4747             // the error return path socket via sendmsg/recvmsg
4748             if (ctrl_path[0] == 0)
4749             {
4750                 if (req->errsd == req->sd)
4751                 {
4752                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4753                               "[R%u] read_msg: ERROR failed to get errsd via SCM_RIGHTS", req->request_id);
4754                     req->ts = t_error;
4755                     return;
4756                 }
4757                 goto got_errfd;
4758             }
4759 #endif
4760 
4761             req->errsd = socket(AF_DNSSD, SOCK_STREAM, 0);
4762             if (!dnssd_SocketValid(req->errsd))
4763             {
4764                 my_throttled_perror("ERROR: socket");
4765                 req->ts = t_error;
4766                 return;
4767             }
4768 
4769             if (connect(req->errsd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
4770             {
4771 #if !defined(USE_TCP_LOOPBACK)
4772                 struct stat sb;
4773                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4774                           "[R%u] read_msg: Couldn't connect to error return path socket " PUB_S " errno %d (" PUB_S ")",
4775                           req->request_id, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
4776                 if (stat(cliaddr.sun_path, &sb) < 0)
4777                 {
4778                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4779                               "[R%u] read_msg: stat failed " PUB_S " errno %d (" PUB_S ")",
4780                               req->request_id, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
4781                 }
4782                 else
4783                 {
4784                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4785                               "[R%u] read_msg: file " PUB_S " mode %o (octal) uid %d gid %d",
4786                               req->request_id, cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid);
4787                 }
4788 #endif
4789                 req->ts = t_error;
4790                 return;
4791             }
4792 
4793 #if !defined(USE_TCP_LOOPBACK)
4794 got_errfd:
4795 #endif
4796 
4797 #if defined(_WIN32)
4798             if (ioctlsocket(req->errsd, FIONBIO, &opt) != 0)
4799 #else
4800             if (fcntl(req->errsd, F_SETFL, fcntl(req->errsd, F_GETFL, 0) | O_NONBLOCK) != 0)
4801 #endif
4802             {
4803                 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4804                           "[R%u] ERROR: could not set control socket to non-blocking mode errno %d (" PUB_S ")",
4805                           req->request_id, dnssd_errno, dnssd_strerror(dnssd_errno));
4806                 req->ts = t_error;
4807                 return;
4808             }
4809         }
4810 
4811         req->ts = t_complete;
4812     }
4813 
4814     return;
4815 
4816 rerror:
4817     if (dnssd_errno == dnssd_EWOULDBLOCK || dnssd_errno == dnssd_EINTR) return;
4818     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
4819               "[R%u] ERROR: read_msg errno %d (" PUB_S ")", req->request_id, dnssd_errno, dnssd_strerror(dnssd_errno));
4820     req->ts = t_error;
4821 }
4822 
handle_client_request(request_state * req)4823 mDNSlocal mStatus handle_client_request(request_state *req)
4824 {
4825     mStatus err = mStatus_NoError;
4826 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
4827     SetupAuditTokenForRequest(req);
4828 #endif
4829     switch(req->hdr.op)
4830     {
4831             // These are all operations that have their own first-class request_state object
4832         case connection_request:
4833             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
4834                    "[R%d] DNSServiceCreateConnection START PID[%d](" PUB_S ")",
4835                    req->request_id, req->process_id, req->pid_name);
4836             req->terminate = connection_termination;
4837             break;
4838         case connection_delegate_request:
4839             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
4840                    "[R%d] DNSServiceCreateDelegateConnection START PID[%d](" PRI_S ")",
4841                    req->request_id, req->process_id, req->pid_name);
4842             req->terminate = connection_termination;
4843             handle_connection_delegate_request(req);
4844             break;
4845         case resolve_request:              err = handle_resolve_request     (req);  break;
4846         case query_request:                err = handle_queryrecord_request (req);  break;
4847         case browse_request:               err = handle_browse_request      (req);  break;
4848         case reg_service_request:          err = handle_regservice_request  (req);  break;
4849         case enumeration_request:          err = handle_enum_request        (req);  break;
4850         case reconfirm_record_request:     err = handle_reconfirm_request   (req);  break;
4851         case setdomain_request:            err = handle_setdomain_request   (req);  break;
4852         case getproperty_request:                handle_getproperty_request (req);  break;
4853         case port_mapping_request:         err = handle_port_mapping_request(req);  break;
4854         case addrinfo_request:             err = handle_addrinfo_request    (req);  break;
4855         case send_bpf:                     /* Do nothing for send_bpf */            break;
4856 
4857             // These are all operations that work with an existing request_state object
4858         case reg_record_request:           err = handle_regrecord_request   (req);  break;
4859         case add_record_request:           err = handle_add_request         (req);  break;
4860         case update_record_request:        err = handle_update_request      (req);  break;
4861         case remove_record_request:        err = handle_removerecord_request(req);  break;
4862         case cancel_request:                     handle_cancel_request      (req);  break;
4863         case release_request:              err = handle_release_request     (req);  break;
4864         default: LogMsg("request_callback: %3d:ERROR: Unsupported UDS req:%d PID[%d][%s]",
4865                         req->sd, req->hdr.op, req->process_id, req->pid_name);
4866             err = mStatus_BadParamErr;
4867             break;
4868     }
4869 
4870     return err;
4871 }
4872 
4873 #define RecordOrientedOp(X) \
4874     ((X) == reg_record_request || (X) == add_record_request || (X) == update_record_request || (X) == remove_record_request)
4875 
4876 // The lightweight operations are the ones that don't need a dedicated request_state structure allocated for them
4877 #define LightweightOp(X) (RecordOrientedOp(X) || (X) == cancel_request)
4878 
request_callback(int fd,void * info)4879 mDNSlocal void request_callback(int fd, void *info)
4880 {
4881     mStatus err = 0;
4882     request_state *req = info;
4883     mDNSs32 min_size = sizeof(DNSServiceFlags);
4884     (void)fd; // Unused
4885 
4886     for (;;)
4887     {
4888         read_msg(req);
4889         if (req->ts == t_morecoming)
4890             return;
4891         if (req->ts == t_terminated || req->ts == t_error)
4892         {
4893             AbortUnlinkAndFree(req);
4894             return;
4895         }
4896         if (req->ts != t_complete)
4897         {
4898             LogMsg("request_callback: req->ts %d != t_complete PID[%d][%s]", req->ts, req->process_id, req->pid_name);
4899             AbortUnlinkAndFree(req);
4900             return;
4901         }
4902 
4903         switch(req->hdr.op)            //          Interface       + other data
4904         {
4905             case connection_request:       min_size = 0;                                                                           break;
4906             case connection_delegate_request: min_size = 4; /* pid */                                                              break;
4907             case reg_service_request:      min_size += sizeof(mDNSu32) + 4 /* name, type, domain, host */ + 4 /* port, textlen */; break;
4908             case add_record_request:       min_size +=                   4 /* type, rdlen */              + 4 /* ttl */;           break;
4909             case update_record_request:    min_size +=                   2 /* rdlen */                    + 4 /* ttl */;           break;
4910             case remove_record_request:                                                                                            break;
4911             case browse_request:           min_size += sizeof(mDNSu32) + 2 /* type, domain */;                                     break;
4912             case resolve_request:          min_size += sizeof(mDNSu32) + 3 /* type, type, domain */;                               break;
4913             case query_request:            min_size += sizeof(mDNSu32) + 1 /* name */                     + 4 /* type, class*/;    break;
4914             case enumeration_request:      min_size += sizeof(mDNSu32);                                                            break;
4915             case reg_record_request:       min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */ + 4 /* ttl */;  break;
4916             case reconfirm_record_request: min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */;                break;
4917             case setdomain_request:        min_size +=                   1 /* domain */;                                           break;
4918             case getproperty_request:      min_size = 2;                                                                           break;
4919             case port_mapping_request:     min_size += sizeof(mDNSu32) + 4 /* udp/tcp */ + 4 /* int/ext port */    + 4 /* ttl */;  break;
4920             case addrinfo_request:         min_size += sizeof(mDNSu32) + 4 /* v4/v6 */   + 1 /* hostname */;                       break;
4921             case send_bpf:                 // Same as cancel_request below
4922             case cancel_request:           min_size = 0;                                                                           break;
4923             case release_request:          min_size += sizeof(mDNSu32) + 3 /* type, type, domain */;                               break;
4924             default: LogMsg("request_callback: ERROR: validate_message - unsupported req type: %d PID[%d][%s]",
4925                             req->hdr.op, req->process_id, req->pid_name);
4926                      min_size = -1;                                                                                                break;
4927         }
4928 
4929         if ((mDNSs32)req->data_bytes < min_size)
4930         {
4931             LogMsg("request_callback: Invalid message %d bytes; min for %d is %d PID[%d][%s]",
4932                     req->data_bytes, req->hdr.op, min_size, req->process_id, req->pid_name);
4933             AbortUnlinkAndFree(req);
4934             return;
4935         }
4936         if (LightweightOp(req->hdr.op) && !req->terminate)
4937         {
4938             LogMsg("request_callback: Reg/Add/Update/Remove %d require existing connection PID[%d][%s]",
4939                     req->hdr.op, req->process_id, req->pid_name);
4940             AbortUnlinkAndFree(req);
4941             return;
4942         }
4943 
4944         // If req->terminate is already set, this means this operation is sharing an existing connection
4945         if (req->terminate && !LightweightOp(req->hdr.op))
4946         {
4947             request_state *newreq = NewRequest();
4948             newreq->primary = req;
4949             newreq->sd      = req->sd;
4950             newreq->errsd   = req->errsd;
4951             newreq->uid     = req->uid;
4952             newreq->hdr     = req->hdr;
4953             newreq->msgbuf  = req->msgbuf;
4954             newreq->msgptr  = req->msgptr;
4955             newreq->msgend  = req->msgend;
4956             newreq->request_id = GetNewRequestID();
4957 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
4958             newreq->audit_token = req->audit_token;
4959 #endif
4960             // if the parent request is a delegate connection, copy the
4961             // relevant bits
4962             if (req->validUUID)
4963             {
4964                 newreq->validUUID = mDNStrue;
4965                 mDNSPlatformMemCopy(newreq->uuid, req->uuid, UUID_SIZE);
4966             }
4967             else
4968             {
4969                 if (req->process_id)
4970                 {
4971                     newreq->process_id = req->process_id;
4972                     mDNSPlatformStrLCopy(newreq->pid_name, req->pid_name, (mDNSu32)sizeof(newreq->pid_name));
4973                 }
4974                 else
4975                 {
4976                     set_peer_pid(newreq);
4977                 }
4978             }
4979             req = newreq;
4980         }
4981 
4982         // Check if the request wants no asynchronous replies.
4983         if (req->hdr.ipc_flags & IPC_FLAGS_NOREPLY) req->no_reply = 1;
4984 
4985         // If we're shutting down, don't allow new client requests
4986         // We do allow "cancel" and "getproperty" during shutdown
4987         if (mDNSStorage.ShutdownTime && req->hdr.op != cancel_request && req->hdr.op != getproperty_request)
4988             err = mStatus_ServiceNotRunning;
4989         else
4990             err = handle_client_request(req);
4991 
4992         // req->msgbuf may be NULL, e.g. for connection_request or remove_record_request
4993         if (req->msgbuf) freeL("request_state msgbuf", req->msgbuf);
4994 
4995         // There's no return data for a cancel request (DNSServiceRefDeallocate returns no result)
4996         // For a DNSServiceGetProperty call, the handler already generated the response, so no need to do it again here
4997         if (req->hdr.op != cancel_request && req->hdr.op != getproperty_request && req->hdr.op != send_bpf && req->hdr.op != getpid_request)
4998         {
4999             const mStatus err_netorder = dnssd_htonl(err);
5000             send_all(req->errsd, (const char *)&err_netorder, sizeof(err_netorder));
5001             if (req->errsd != req->sd)
5002             {
5003                 dnssd_close(req->errsd);
5004                 req->errsd = req->sd;
5005                 // Also need to reset the parent's errsd, if this is a subordinate operation
5006                 if (req->primary) req->primary->errsd = req->primary->sd;
5007             }
5008         }
5009 
5010         // Reset ready to accept the next req on this pipe
5011         if (req->primary) req = req->primary;
5012         req->ts         = t_morecoming;
5013         req->hdr_bytes  = 0;
5014         req->data_bytes = 0;
5015         req->msgbuf     = mDNSNULL;
5016         req->msgptr     = mDNSNULL;
5017         req->msgend     = 0;
5018     }
5019 }
5020 
connect_callback(int fd,void * info)5021 mDNSlocal void connect_callback(int fd, void *info)
5022 {
5023     dnssd_sockaddr_t cliaddr;
5024     dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr);
5025     dnssd_sock_t sd = accept(fd, (struct sockaddr*) &cliaddr, &len);
5026 #if defined(SO_NOSIGPIPE) || defined(_WIN32)
5027     unsigned long optval = 1;
5028 #endif
5029 
5030     (void)info; // Unused
5031 
5032     if (!dnssd_SocketValid(sd))
5033     {
5034         if (dnssd_errno != dnssd_EWOULDBLOCK)
5035             my_throttled_perror("ERROR: accept");
5036         return;
5037     }
5038 
5039 #ifdef SO_NOSIGPIPE
5040     // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
5041     if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
5042         LogMsg("%3d: WARNING: setsockopt - SO_NOSIGPIPE %d (%s)", sd, dnssd_errno, dnssd_strerror(dnssd_errno));
5043 #endif
5044 
5045 #if defined(_WIN32)
5046     if (ioctlsocket(sd, FIONBIO, &optval) != 0)
5047 #else
5048     if (fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK) != 0)
5049 #endif
5050     {
5051         my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
5052         dnssd_close(sd);
5053         return;
5054     }
5055     else
5056     {
5057         request_state *request = NewRequest();
5058         request->ts    = t_morecoming;
5059         request->sd    = sd;
5060         request->errsd = sd;
5061         request->request_id = GetNewRequestID();
5062         set_peer_pid(request);
5063 #if APPLE_OSX_mDNSResponder
5064         struct xucred x;
5065         socklen_t xucredlen = sizeof(x);
5066         if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 && x.cr_version == XUCRED_VERSION)
5067             request->uid = x.cr_uid; // save the effective userid of the client
5068         else
5069             my_perror("ERROR: getsockopt, LOCAL_PEERCRED");
5070         debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups);
5071 #endif // APPLE_OSX_mDNSResponder
5072         LogDebug("%3d: connect_callback: Adding FD for uid %u", request->sd, request->uid);
5073         udsSupportAddFDToEventLoop(sd, request_callback, request, &request->platform_data);
5074     }
5075 }
5076 
uds_socket_setup(dnssd_sock_t skt)5077 mDNSlocal mDNSBool uds_socket_setup(dnssd_sock_t skt)
5078 {
5079 #if defined(SO_NP_EXTENSIONS)
5080     struct      so_np_extensions sonpx;
5081     socklen_t optlen = sizeof(struct so_np_extensions);
5082     sonpx.npx_flags = SONPX_SETOPTSHUT;
5083     sonpx.npx_mask  = SONPX_SETOPTSHUT;
5084     if (setsockopt(skt, SOL_SOCKET, SO_NP_EXTENSIONS, &sonpx, optlen) < 0)
5085         my_perror("WARNING: could not set sockopt - SO_NP_EXTENSIONS");
5086 #endif
5087 #if defined(_WIN32)
5088     // SEH: do we even need to do this on windows?
5089     // This socket will be given to WSAEventSelect which will automatically set it to non-blocking
5090     u_long opt = 1;
5091     if (ioctlsocket(skt, FIONBIO, &opt) != 0)
5092 #else
5093     if (fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK) != 0)
5094 #endif
5095     {
5096         my_perror("ERROR: could not set listen socket to non-blocking mode");
5097         return mDNSfalse;
5098     }
5099 
5100     if (listen(skt, LISTENQ) != 0)
5101     {
5102         my_perror("ERROR: could not listen on listen socket");
5103         return mDNSfalse;
5104     }
5105 
5106     if (mStatus_NoError != udsSupportAddFDToEventLoop(skt, connect_callback, (void *) NULL, (void **) NULL))
5107     {
5108         my_perror("ERROR: could not add listen socket to event loop");
5109         return mDNSfalse;
5110     }
5111     else
5112     {
5113         LogOperation("%3d: Listening for incoming Unix Domain Socket client requests", skt);
5114         mDNSStorage.uds_listener_skt = skt;
5115     }
5116     return mDNStrue;
5117 }
5118 
5119 #if MDNS_MALLOC_DEBUGGING
5120 mDNSlocal void udsserver_validatelists(void *context);
5121 #endif
5122 
udsserver_init(dnssd_sock_t skts[],const size_t count)5123 mDNSexport int udsserver_init(dnssd_sock_t skts[], const size_t count)
5124 {
5125     dnssd_sockaddr_t laddr;
5126     int ret;
5127 
5128 #ifndef NO_PID_FILE
5129     FILE *fp = fopen(PID_FILE, "w");
5130     if (fp != NULL)
5131     {
5132         fprintf(fp, "%d\n", getpid());
5133         fclose(fp);
5134     }
5135 #endif
5136 
5137 #if MDNS_MALLOC_DEBUGGING
5138 	static mDNSListValidator validator;
5139 	mDNSPlatformAddListValidator(&validator, udsserver_validatelists, "udsserver_validatelists", NULL);
5140 #endif
5141 
5142     if (skts)
5143     {
5144         size_t i;
5145         for (i = 0; i < count; i++)
5146             if (dnssd_SocketValid(skts[i]) && !uds_socket_setup(skts[i]))
5147                 goto error;
5148     }
5149     else
5150     {
5151         listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
5152         if (!dnssd_SocketValid(listenfd))
5153         {
5154             my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
5155             goto error;
5156         }
5157 
5158         mDNSPlatformMemZero(&laddr, sizeof(laddr));
5159 
5160         #if defined(USE_TCP_LOOPBACK)
5161         {
5162             laddr.sin_family = AF_INET;
5163             laddr.sin_port = htons(MDNS_TCP_SERVERPORT);
5164             laddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
5165             ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
5166             if (ret < 0)
5167             {
5168                 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
5169                 goto error;
5170             }
5171         }
5172         #else
5173         {
5174             mode_t mask = umask(0);
5175             unlink(boundPath);  // OK if this fails
5176             laddr.sun_family = AF_LOCAL;
5177             #ifndef NOT_HAVE_SA_LEN
5178             // According to Stevens (section 3.2), there is no portable way to
5179             // determine whether sa_len is defined on a particular platform.
5180             laddr.sun_len = sizeof(struct sockaddr_un);
5181             #endif
5182             if (strlen(boundPath) >= sizeof(laddr.sun_path))
5183             {
5184                 LogMsg("ERROR: MDNS_UDS_SERVERPATH must be < %d characters", (int)sizeof(laddr.sun_path));
5185                 goto error;
5186             }
5187             mDNSPlatformStrLCopy(laddr.sun_path, boundPath, sizeof(laddr.sun_path));
5188             ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
5189             umask(mask);
5190             if (ret < 0)
5191             {
5192                 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
5193                 goto error;
5194             }
5195         }
5196         #endif
5197 
5198         if (!uds_socket_setup(listenfd)) goto error;
5199     }
5200 
5201 #if !defined(PLATFORM_NO_RLIMIT)
5202     {
5203         // Set maximum number of open file descriptors
5204     #define MIN_OPENFILES 10240
5205         struct rlimit maxfds, newfds;
5206 
5207         // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
5208         // you have to get and set rlimits once before getrlimit will return sensible values
5209         if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
5210         if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
5211 
5212         if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
5213         newfds.rlim_max = (maxfds.rlim_max > MIN_OPENFILES) ? maxfds.rlim_max : MIN_OPENFILES;
5214         newfds.rlim_cur = (maxfds.rlim_cur > MIN_OPENFILES) ? maxfds.rlim_cur : MIN_OPENFILES;
5215         if (newfds.rlim_max != maxfds.rlim_max || newfds.rlim_cur != maxfds.rlim_cur)
5216             if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
5217 
5218         if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
5219         debugf("maxfds.rlim_max %d", (long)maxfds.rlim_max);
5220         debugf("maxfds.rlim_cur %d", (long)maxfds.rlim_cur);
5221     }
5222 #endif
5223 
5224     // We start a "LocalOnly" query looking for Automatic Browse Domain records.
5225     // When Domain Enumeration in uDNS.c finds an "lb" record from the network, its "FoundDomain" routine
5226     // creates a "LocalOnly" record, which results in our AutomaticBrowseDomainChange callback being invoked
5227     mDNS_GetDomains(&mDNSStorage, &mDNSStorage.AutomaticBrowseDomainQ, mDNS_DomainTypeBrowseAutomatic,
5228                     mDNSNULL, mDNSInterface_LocalOnly, AutomaticBrowseDomainChange, mDNSNULL);
5229 
5230     // Add "local" as recommended registration domain ("dns-sd -E"), recommended browsing domain ("dns-sd -F"), and automatic browsing domain
5231     RegisterLocalOnlyDomainEnumPTR(&mDNSStorage, &localdomain, mDNS_DomainTypeRegistration);
5232     RegisterLocalOnlyDomainEnumPTR(&mDNSStorage, &localdomain, mDNS_DomainTypeBrowse);
5233     AddAutoBrowseDomain(0, &localdomain);
5234 
5235     udsserver_handle_configchange(&mDNSStorage);
5236     return 0;
5237 
5238 error:
5239 
5240     my_perror("ERROR: udsserver_init");
5241     return -1;
5242 }
5243 
udsserver_exit(void)5244 mDNSexport int udsserver_exit(void)
5245 {
5246     // Cancel all outstanding client requests
5247     while (all_requests) AbortUnlinkAndFree(all_requests);
5248 
5249     // Clean up any special mDNSInterface_LocalOnly records we created, both the entries for "local" we
5250     // created in udsserver_init, and others we created as a result of reading local configuration data
5251     while (LocalDomainEnumRecords)
5252     {
5253         ARListElem *rem = LocalDomainEnumRecords;
5254         LocalDomainEnumRecords = LocalDomainEnumRecords->next;
5255         mDNS_Deregister(&mDNSStorage, &rem->ar);
5256     }
5257 
5258     // If the launching environment created no listening socket,
5259     // that means we created it ourselves, so we should clean it up on exit
5260     if (dnssd_SocketValid(listenfd))
5261     {
5262         dnssd_close(listenfd);
5263 #if !defined(USE_TCP_LOOPBACK)
5264         // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
5265         // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
5266         // It would be nice if we could find a solution to this problem
5267         if (unlink(boundPath))
5268             debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
5269 #endif
5270     }
5271 
5272 #ifndef NO_PID_FILE
5273     unlink(PID_FILE);
5274 #endif
5275 
5276     return 0;
5277 }
5278 
LogClientInfoToFD(int fd,request_state * req)5279 mDNSlocal void LogClientInfoToFD(int fd, request_state *req)
5280 {
5281     char reqIDStr[14];
5282     char prefix[18];
5283 
5284     mDNS_snprintf(reqIDStr, sizeof(reqIDStr), "[R%u]", req->request_id);
5285 
5286     mDNS_snprintf(prefix, sizeof(prefix), "%-6s %2s", reqIDStr, req->primary ? "->" : "");
5287 
5288     if (!req->terminate)
5289         LogToFD(fd, "%s No operation yet on this socket", prefix);
5290     else if (req->terminate == connection_termination)
5291     {
5292         int num_records = 0, num_ops = 0;
5293         const registered_record_entry *p;
5294         request_state *r;
5295         for (p = req->u.reg_recs; p; p=p->next) num_records++;
5296         for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++;
5297         LogToFD(fd, "%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s PID[%d](%s)",
5298                   prefix, num_records, num_records != 1 ? "s" : "", num_ops,     num_ops     != 1 ? "s" : "",
5299                   req->process_id, req->pid_name);
5300         for (p = req->u.reg_recs; p; p=p->next)
5301             LogToFD(fd, " ->  DNSServiceRegisterRecord   0x%08X %2d %3d %s PID[%d](%s)",
5302                       req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
5303         for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfoToFD(fd, r);
5304     }
5305     else if (req->terminate == regservice_termination_callback)
5306     {
5307         service_instance *ptr;
5308         for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
5309             LogToFD(fd, "%-9s DNSServiceRegister         0x%08X %2d %##s %u/%u PID[%d](%s)",
5310                       (ptr == req->u.servicereg.instances) ? prefix : "", req->flags, req->interfaceIndex, ptr->srs.RR_SRV.resrec.name->c,
5311                       mDNSVal16(req->u.servicereg.port),
5312                       SRS_PORT(&ptr->srs), req->process_id, req->pid_name);
5313     }
5314     else if (req->terminate == browse_termination_callback)
5315     {
5316         browser_t *blist;
5317         for (blist = req->u.browser.browsers; blist; blist = blist->next)
5318             LogToFD(fd, "%-9s DNSServiceBrowse           0x%08X %2d %##s PID[%d](%s)",
5319                       (blist == req->u.browser.browsers) ? prefix : "", req->flags, req->interfaceIndex, blist->q.qname.c,
5320                       req->process_id, req->pid_name);
5321     }
5322     else if (req->terminate == resolve_termination_callback)
5323         LogToFD(fd, "%s DNSServiceResolve          0x%08X %2d %##s PID[%d](%s)",
5324                   prefix, req->flags, req->interfaceIndex, req->u.resolve.qsrv.qname.c, req->process_id, req->pid_name);
5325     else if (req->terminate == queryrecord_termination_callback)
5326         LogToFD(fd, "%s DNSServiceQueryRecord      0x%08X %2d %##s (%s) PID[%d](%s)",
5327                   prefix, req->flags, req->interfaceIndex, QueryRecordClientRequestGetQName(&req->u.queryrecord), DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)), req->process_id, req->pid_name);
5328     else if (req->terminate == enum_termination_callback)
5329         LogToFD(fd, "%s DNSServiceEnumerateDomains 0x%08X %2d %##s PID[%d](%s)",
5330                   prefix, req->flags, req->interfaceIndex, req->u.enumeration.q_all.qname.c, req->process_id, req->pid_name);
5331     else if (req->terminate == port_mapping_termination_callback)
5332         LogToFD(fd, "%s DNSServiceNATPortMapping   0x%08X %2d %s%s Int %5d Req %5d Ext %.4a:%5d Req TTL %5d Granted TTL %5d PID[%d](%s)",
5333                   prefix,
5334                   req->flags,
5335                   req->interfaceIndex,
5336                   req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : "   ",
5337                   req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : "   ",
5338                   mDNSVal16(req->u.pm.NATinfo.IntPort),
5339                   mDNSVal16(req->u.pm.ReqExt),
5340                   &req->u.pm.NATinfo.ExternalAddress,
5341                   mDNSVal16(req->u.pm.NATinfo.ExternalPort),
5342                   req->u.pm.NATinfo.NATLease,
5343                   req->u.pm.NATinfo.Lifetime,
5344                   req->process_id, req->pid_name);
5345     else if (req->terminate == addrinfo_termination_callback)
5346         LogToFD(fd, "%s DNSServiceGetAddrInfo      0x%08X %2d %s%s %##s PID[%d](%s)",
5347                   prefix, req->flags, req->interfaceIndex,
5348                   req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : "  ",
5349                   req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : "  ",
5350                   GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name);
5351     else
5352         LogToFD(fd, "%s Unrecognized operation %p", prefix, req->terminate);
5353 }
5354 
LogClientInfo(request_state * req)5355 mDNSlocal void LogClientInfo(request_state *req)
5356 {
5357     char reqIDStr[14];
5358     char prefix[18];
5359 
5360     mDNS_snprintf(reqIDStr, sizeof(reqIDStr), "[R%u]", req->request_id);
5361 
5362     mDNS_snprintf(prefix, sizeof(prefix), "%-6s %2s", reqIDStr, req->primary ? "->" : "");
5363 
5364     if (!req->terminate)
5365     LogMsgNoIdent("%s No operation yet on this socket", prefix);
5366     else if (req->terminate == connection_termination)
5367     {
5368         int num_records = 0, num_ops = 0;
5369         const registered_record_entry *p;
5370         request_state *r;
5371         for (p = req->u.reg_recs; p; p=p->next) num_records++;
5372         for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++;
5373         LogMsgNoIdent("%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s PID[%d](%s)",
5374                       prefix, num_records, num_records != 1 ? "s" : "", num_ops,     num_ops     != 1 ? "s" : "",
5375                       req->process_id, req->pid_name);
5376         for (p = req->u.reg_recs; p; p=p->next)
5377         LogMsgNoIdent(" ->  DNSServiceRegisterRecord   0x%08X %2d %3d %s PID[%d](%s)",
5378                       req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
5379         for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfo(r);
5380     }
5381     else if (req->terminate == regservice_termination_callback)
5382     {
5383         service_instance *ptr;
5384         for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
5385         LogMsgNoIdent("%-9s DNSServiceRegister         0x%08X %2d %##s %u/%u PID[%d](%s)",
5386                       (ptr == req->u.servicereg.instances) ? prefix : "", req->flags, req->interfaceIndex, ptr->srs.RR_SRV.resrec.name->c,
5387                       mDNSVal16(req->u.servicereg.port),
5388                       SRS_PORT(&ptr->srs), req->process_id, req->pid_name);
5389     }
5390     else if (req->terminate == browse_termination_callback)
5391     {
5392         browser_t *blist;
5393         for (blist = req->u.browser.browsers; blist; blist = blist->next)
5394         LogMsgNoIdent("%-9s DNSServiceBrowse           0x%08X %2d %##s PID[%d](%s)",
5395                       (blist == req->u.browser.browsers) ? prefix : "", req->flags, req->interfaceIndex, blist->q.qname.c,
5396                       req->process_id, req->pid_name);
5397     }
5398     else if (req->terminate == resolve_termination_callback)
5399     LogMsgNoIdent("%s DNSServiceResolve          0x%08X %2d %##s PID[%d](%s)",
5400                   prefix, req->flags, req->interfaceIndex, req->u.resolve.qsrv.qname.c, req->process_id, req->pid_name);
5401     else if (req->terminate == queryrecord_termination_callback)
5402     LogMsgNoIdent("%s DNSServiceQueryRecord      0x%08X %2d %##s (%s) PID[%d](%s)",
5403                   prefix, req->flags, req->interfaceIndex, QueryRecordClientRequestGetQName(&req->u.queryrecord), DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)), req->process_id, req->pid_name);
5404     else if (req->terminate == enum_termination_callback)
5405     LogMsgNoIdent("%s DNSServiceEnumerateDomains 0x%08X %2d %##s PID[%d](%s)",
5406                   prefix, req->flags, req->interfaceIndex, req->u.enumeration.q_all.qname.c, req->process_id, req->pid_name);
5407     else if (req->terminate == port_mapping_termination_callback)
5408     LogMsgNoIdent("%s DNSServiceNATPortMapping   0x%08X %2d %s%s Int %5d Req %5d Ext %.4a:%5d Req TTL %5d Granted TTL %5d PID[%d](%s)",
5409                   prefix,
5410                   req->flags,
5411                   req->interfaceIndex,
5412                   req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : "   ",
5413                   req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : "   ",
5414                   mDNSVal16(req->u.pm.NATinfo.IntPort),
5415                   mDNSVal16(req->u.pm.ReqExt),
5416                   &req->u.pm.NATinfo.ExternalAddress,
5417                   mDNSVal16(req->u.pm.NATinfo.ExternalPort),
5418                   req->u.pm.NATinfo.NATLease,
5419                   req->u.pm.NATinfo.Lifetime,
5420                   req->process_id, req->pid_name);
5421     else if (req->terminate == addrinfo_termination_callback)
5422     LogMsgNoIdent("%s DNSServiceGetAddrInfo      0x%08X %2d %s%s %##s PID[%d](%s)",
5423                   prefix, req->flags, req->interfaceIndex,
5424                   req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : "  ",
5425                   req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : "  ",
5426                   GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name);
5427     else
5428     LogMsgNoIdent("%s Unrecognized operation %p", prefix, req->terminate);
5429 }
5430 
GetMcastClients(request_state * req)5431 mDNSlocal void GetMcastClients(request_state *req)
5432 {
5433     if (req->terminate == connection_termination)
5434     {
5435         int num_records = 0, num_ops = 0;
5436         const registered_record_entry *p;
5437         request_state *r;
5438         for (p = req->u.reg_recs; p; p=p->next)
5439             num_records++;
5440         for (r = req->next; r; r=r->next)
5441             if (r->primary == req)
5442                 num_ops++;
5443         for (p = req->u.reg_recs; p; p=p->next)
5444         {
5445             if (!AuthRecord_uDNS(p->rr))
5446                 n_mrecords++;
5447         }
5448         for (r = req->next; r; r=r->next)
5449             if (r->primary == req)
5450                 GetMcastClients(r);
5451     }
5452     else if (req->terminate == regservice_termination_callback)
5453     {
5454         service_instance *ptr;
5455         for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
5456         {
5457             if (!AuthRecord_uDNS(&ptr->srs.RR_SRV))
5458                 n_mrecords++;
5459         }
5460     }
5461     else if (req->terminate == browse_termination_callback)
5462     {
5463         browser_t *blist;
5464         for (blist = req->u.browser.browsers; blist; blist = blist->next)
5465         {
5466             if (mDNSOpaque16IsZero(blist->q.TargetQID))
5467                 n_mquests++;
5468         }
5469     }
5470     else if (req->terminate == resolve_termination_callback)
5471     {
5472         if ((mDNSOpaque16IsZero(req->u.resolve.qsrv.TargetQID)) && (req->u.resolve.qsrv.ThisQInterval > 0))
5473             n_mquests++;
5474     }
5475     else if (req->terminate == queryrecord_termination_callback)
5476     {
5477         if (QueryRecordClientRequestIsMulticast(&req->u.queryrecord))
5478             n_mquests++;
5479     }
5480     else if (req->terminate == addrinfo_termination_callback)
5481     {
5482         if (GetAddrInfoClientRequestIsMulticast(&req->u.addrinfo))
5483             n_mquests++;
5484     }
5485     else
5486     {
5487         return;
5488     }
5489 }
5490 
5491 
LogMcastClientInfo(request_state * req)5492 mDNSlocal void LogMcastClientInfo(request_state *req)
5493 {
5494     if (!req->terminate)
5495         LogMcastNoIdent("No operation yet on this socket");
5496     else if (req->terminate == connection_termination)
5497     {
5498         int num_records = 0, num_ops = 0;
5499         const registered_record_entry *p;
5500         request_state *r;
5501         for (p = req->u.reg_recs; p; p=p->next)
5502             num_records++;
5503         for (r = req->next; r; r=r->next)
5504             if (r->primary == req)
5505                 num_ops++;
5506         for (p = req->u.reg_recs; p; p=p->next)
5507         {
5508             if (!AuthRecord_uDNS(p->rr))
5509                 LogMcastNoIdent("R: ->  DNSServiceRegisterRecord:  %##s %s PID[%d](%s)", p->rr->resrec.name->c,
5510                                 DNSTypeName(p->rr->resrec.rrtype), req->process_id, req->pid_name, i_mcount++);
5511         }
5512         for (r = req->next; r; r=r->next)
5513             if (r->primary == req)
5514                 LogMcastClientInfo(r);
5515     }
5516     else if (req->terminate == regservice_termination_callback)
5517     {
5518         service_instance *ptr;
5519         for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
5520         {
5521             if (!AuthRecord_uDNS(&ptr->srs.RR_SRV))
5522                 LogMcastNoIdent("R: DNSServiceRegister:  %##s %u/%u PID[%d](%s)", ptr->srs.RR_SRV.resrec.name->c, mDNSVal16(req->u.servicereg.port),
5523                                 SRS_PORT(&ptr->srs), req->process_id, req->pid_name, i_mcount++);
5524         }
5525     }
5526     else if (req->terminate == browse_termination_callback)
5527     {
5528         browser_t *blist;
5529         for (blist = req->u.browser.browsers; blist; blist = blist->next)
5530         {
5531             if (mDNSOpaque16IsZero(blist->q.TargetQID))
5532                 LogMcastNoIdent("Q: DNSServiceBrowse  %##s %s PID[%d](%s)", blist->q.qname.c, DNSTypeName(blist->q.qtype),
5533                                 req->process_id, req->pid_name, i_mcount++);
5534         }
5535     }
5536     else if (req->terminate == resolve_termination_callback)
5537     {
5538         if ((mDNSOpaque16IsZero(req->u.resolve.qsrv.TargetQID)) && (req->u.resolve.qsrv.ThisQInterval > 0))
5539             LogMcastNoIdent("Q: DNSServiceResolve  %##s %s PID[%d](%s)", req->u.resolve.qsrv.qname.c, DNSTypeName(req->u.resolve.qsrv.qtype),
5540                             req->process_id, req->pid_name, i_mcount++);
5541     }
5542     else if (req->terminate == queryrecord_termination_callback)
5543     {
5544         if (QueryRecordClientRequestIsMulticast(&req->u.queryrecord))
5545         {
5546             LogMcastNoIdent("Q: DNSServiceQueryRecord  %##s %s PID[%d](%s)",
5547                           QueryRecordClientRequestGetQName(&req->u.queryrecord),
5548                           DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)),
5549                           req->process_id, req->pid_name, i_mcount++);
5550         }
5551     }
5552     else if (req->terminate == addrinfo_termination_callback)
5553     {
5554         if (GetAddrInfoClientRequestIsMulticast(&req->u.addrinfo))
5555         {
5556             LogMcastNoIdent("Q: DNSServiceGetAddrInfo  %s%s %##s PID[%d](%s)",
5557                           req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : "  ",
5558                           req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : "  ",
5559                           GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name, i_mcount++);
5560         }
5561     }
5562 }
5563 
RecordTypeName(mDNSu8 rtype)5564 mDNSlocal char *RecordTypeName(mDNSu8 rtype)
5565 {
5566     switch (rtype)
5567     {
5568     case kDNSRecordTypeUnregistered:  return ("Unregistered ");
5569     case kDNSRecordTypeDeregistering: return ("Deregistering");
5570     case kDNSRecordTypeUnique:        return ("Unique       ");
5571     case kDNSRecordTypeAdvisory:      return ("Advisory     ");
5572     case kDNSRecordTypeShared:        return ("Shared       ");
5573     case kDNSRecordTypeVerified:      return ("Verified     ");
5574     case kDNSRecordTypeKnownUnique:   return ("KnownUnique  ");
5575     default: return("Unknown");
5576     }
5577 }
5578 
LogEtcHostsToFD(int fd,mDNS * const m)5579 mDNSlocal int LogEtcHostsToFD(int fd, mDNS *const m)
5580 {
5581     mDNSBool showheader = mDNStrue;
5582     const AuthRecord *ar;
5583     mDNSu32 slot;
5584     AuthGroup *ag;
5585     int count = 0;
5586     int authslot = 0;
5587     mDNSBool truncated = 0;
5588 
5589     for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
5590     {
5591         if (m->rrauth.rrauth_hash[slot]) authslot++;
5592         for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
5593             for (ar = ag->members; ar; ar = ar->next)
5594             {
5595                 if (ar->RecordCallback != FreeEtcHosts) continue;
5596                 if (showheader) { showheader = mDNSfalse; LogToFD(fd, "  State       Interface"); }
5597 
5598                 // Print a maximum of 50 records
5599                 if (count++ >= 50) { truncated = mDNStrue; continue; }
5600                 if (ar->ARType == AuthRecordLocalOnly)
5601                 {
5602                     if (ar->resrec.InterfaceID == mDNSInterface_LocalOnly)
5603                         LogToFD(fd, " %s   LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
5604                     else
5605                     {
5606                         mDNSu32 scopeid  = (mDNSu32)(uintptr_t)ar->resrec.InterfaceID;
5607                         LogToFD(fd, " %s   %u  %s", RecordTypeName(ar->resrec.RecordType), scopeid, ARDisplayString(m, ar));
5608                     }
5609                 }
5610             }
5611     }
5612 
5613     if (showheader) LogToFD(fd, "<None>");
5614     else if (truncated) LogToFD(fd, "<Truncated: to 50 records, Total records %d, Total Auth Groups %d, Auth Slots %d>", count, m->rrauth.rrauth_totalused, authslot);
5615     return count;
5616 }
5617 
LogLocalOnlyAuthRecordsToFD(int fd,mDNS * const m)5618 mDNSlocal void LogLocalOnlyAuthRecordsToFD(int fd, mDNS *const m)
5619 {
5620     mDNSBool showheader = mDNStrue;
5621     const AuthRecord *ar;
5622     mDNSu32 slot;
5623     AuthGroup *ag;
5624 
5625     for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
5626     {
5627         for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
5628             for (ar = ag->members; ar; ar = ar->next)
5629             {
5630                 if (ar->RecordCallback == FreeEtcHosts) continue;
5631                 if (showheader) { showheader = mDNSfalse; LogToFD(fd, "  State       Interface"); }
5632 
5633                 // Print a maximum of 400 records
5634                 if (ar->ARType == AuthRecordLocalOnly)
5635                     LogToFD(fd, " %s   LO  %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
5636                 else if (ar->ARType == AuthRecordP2P)
5637                 {
5638                     if (ar->resrec.InterfaceID == mDNSInterface_BLE)
5639                         LogToFD(fd, " %s   BLE %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
5640                     else
5641                         LogToFD(fd, " %s   PP  %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
5642                 }
5643             }
5644     }
5645 
5646     if (showheader) LogToFD(fd, "<None>");
5647 }
5648 
LogOneAuthRecordToFD(int fd,const AuthRecord * ar,mDNSs32 now,const char * ifname)5649 mDNSlocal void LogOneAuthRecordToFD(int fd, const AuthRecord *ar, mDNSs32 now, const char *ifname)
5650 {
5651     if (AuthRecord_uDNS(ar))
5652     {
5653         LogToFD(fd, "%7d %7d %7d %-7s %4d %s %s",
5654                   ar->ThisAPInterval / mDNSPlatformOneSecond,
5655                   (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
5656                   ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
5657                   "-U-",
5658                   ar->state,
5659                   ar->AllowRemoteQuery ? "☠" : " ",
5660                   ARDisplayString(&mDNSStorage, ar));
5661     }
5662     else
5663     {
5664         LogToFD(fd, "%7d %7d %7d %-7s 0x%02X %s %s",
5665                   ar->ThisAPInterval / mDNSPlatformOneSecond,
5666                   ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
5667                   ar->TimeExpire    ? (ar->TimeExpire                      - now) / mDNSPlatformOneSecond : 0,
5668                   ifname ? ifname : "ALL",
5669                   ar->resrec.RecordType,
5670                   ar->AllowRemoteQuery ? "☠" : " ",
5671                   ARDisplayString(&mDNSStorage, ar));
5672     }
5673 }
5674 
LogAuthRecordsToFD(int fd,const mDNSs32 now,AuthRecord * ResourceRecords,int * proxy)5675 mDNSlocal void LogAuthRecordsToFD(int fd,
5676                                     const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
5677 {
5678     mDNSBool showheader = mDNStrue;
5679     const AuthRecord *ar;
5680     OwnerOptData owner = zeroOwner;
5681     for (ar = ResourceRecords; ar; ar=ar->next)
5682     {
5683         const char *const ifname = InterfaceNameForID(&mDNSStorage, ar->resrec.InterfaceID);
5684         if ((ar->WakeUp.HMAC.l[0] != 0) == (proxy != mDNSNULL))
5685         {
5686             if (showheader) { showheader = mDNSfalse; LogToFD(fd, "    Int    Next  Expire if     State"); }
5687             if (proxy) (*proxy)++;
5688             if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)))
5689             {
5690                 owner = ar->WakeUp;
5691                 if (owner.password.l[0])
5692                     LogToFD(fd, "Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
5693                 else if (!mDNSSameEthAddress(&owner.HMAC, &owner.IMAC))
5694                     LogToFD(fd, "Proxying for H-MAC %.6a I-MAC %.6a seq %d",               &owner.HMAC, &owner.IMAC,                  owner.seq);
5695                 else
5696                     LogToFD(fd, "Proxying for %.6a seq %d",                                &owner.HMAC,                               owner.seq);
5697             }
5698             if (AuthRecord_uDNS(ar))
5699             {
5700                 LogOneAuthRecordToFD(fd, ar, now, ifname);
5701             }
5702             else if (ar->ARType == AuthRecordLocalOnly)
5703             {
5704                 LogToFD(fd, "                             LO %s", ARDisplayString(&mDNSStorage, ar));
5705             }
5706             else if (ar->ARType == AuthRecordP2P)
5707             {
5708                 if (ar->resrec.InterfaceID == mDNSInterface_BLE)
5709                     LogToFD(fd, "                             BLE %s", ARDisplayString(&mDNSStorage, ar));
5710                 else
5711                     LogToFD(fd, "                             PP %s", ARDisplayString(&mDNSStorage, ar));
5712             }
5713             else
5714             {
5715                 LogOneAuthRecordToFD(fd, ar, now, ifname);
5716             }
5717         }
5718     }
5719     if (showheader) LogToFD(fd, "<None>");
5720 }
5721 
PrintOneCacheRecordToFD(int fd,const CacheRecord * cr,mDNSu32 slot,const mDNSu32 remain,const char * ifname,mDNSu32 * CacheUsed)5722 mDNSlocal void PrintOneCacheRecordToFD(int fd, const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
5723 {
5724     LogToFD(fd, "%3d %s%8d %-7s%s %-6s%s",
5725               slot,
5726               cr->CRActiveQuestion ? "*" : " ",
5727               remain,
5728               ifname ? ifname : "-U-",
5729               (cr->resrec.RecordType == kDNSRecordTypePacketNegative)  ? "-" :
5730               (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
5731               DNSTypeName(cr->resrec.rrtype),
5732               CRDisplayString(&mDNSStorage, cr));
5733     (*CacheUsed)++;
5734 }
5735 
PrintCachedRecordsToFD(int fd,const CacheRecord * cr,mDNSu32 slot,const mDNSu32 remain,const char * ifname,mDNSu32 * CacheUsed)5736 mDNSlocal void PrintCachedRecordsToFD(int fd, const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
5737 {
5738     CacheRecord *soa;
5739 
5740     soa = cr->soa;
5741     if (soa)
5742     {
5743         PrintOneCacheRecordToFD(fd, soa, slot, remain, ifname, CacheUsed);
5744     }
5745 }
5746 
LogMDNSStatisticsToFD(int fd,mDNS * const m)5747 mDNSexport void LogMDNSStatisticsToFD(int fd, mDNS *const m)
5748 {
5749     LogToFD(fd, "--- MDNS Statistics ---");
5750 
5751     LogToFD(fd, "Name Conflicts                 %u", m->mDNSStats.NameConflicts);
5752     LogToFD(fd, "KnownUnique Name Conflicts     %u", m->mDNSStats.KnownUniqueNameConflicts);
5753     LogToFD(fd, "Duplicate Query Suppressions   %u", m->mDNSStats.DupQuerySuppressions);
5754     LogToFD(fd, "KA Suppressions                %u", m->mDNSStats.KnownAnswerSuppressions);
5755     LogToFD(fd, "KA Multiple Packets            %u", m->mDNSStats.KnownAnswerMultiplePkts);
5756     LogToFD(fd, "Poof Cache Deletions           %u", m->mDNSStats.PoofCacheDeletions);
5757     LogToFD(fd, "--------------------------------");
5758 
5759     LogToFD(fd, "Multicast packets Sent         %u", m->MulticastPacketsSent);
5760     LogToFD(fd, "Multicast packets Received     %u", m->MPktNum);
5761     LogToFD(fd, "Remote Subnet packets          %u", m->RemoteSubnet);
5762     LogToFD(fd, "QU questions  received         %u", m->mDNSStats.UnicastBitInQueries);
5763     LogToFD(fd, "Normal multicast questions     %u", m->mDNSStats.NormalQueries);
5764     LogToFD(fd, "Answers for questions          %u", m->mDNSStats.MatchingAnswersForQueries);
5765     LogToFD(fd, "Unicast responses              %u", m->mDNSStats.UnicastResponses);
5766     LogToFD(fd, "Multicast responses            %u", m->mDNSStats.MulticastResponses);
5767     LogToFD(fd, "Unicast response Demotions     %u", m->mDNSStats.UnicastDemotedToMulticast);
5768     LogToFD(fd, "--------------------------------");
5769 
5770     LogToFD(fd, "Sleeps                         %u", m->mDNSStats.Sleeps);
5771     LogToFD(fd, "Wakeups                        %u", m->mDNSStats.Wakes);
5772     LogToFD(fd, "Interface UP events            %u", m->mDNSStats.InterfaceUp);
5773     LogToFD(fd, "Interface UP Flap events       %u", m->mDNSStats.InterfaceUpFlap);
5774     LogToFD(fd, "Interface Down events          %u", m->mDNSStats.InterfaceDown);
5775     LogToFD(fd, "Interface DownFlap events      %u", m->mDNSStats.InterfaceDownFlap);
5776     LogToFD(fd, "Cache refresh queries          %u", m->mDNSStats.CacheRefreshQueries);
5777     LogToFD(fd, "Cache refreshed                %u", m->mDNSStats.CacheRefreshed);
5778     LogToFD(fd, "Wakeup on Resolves             %u", m->mDNSStats.WakeOnResolves);
5779 }
5780 
udsserver_info_dump_to_fd(int fd)5781 mDNSexport void udsserver_info_dump_to_fd(int fd)
5782 {
5783     mDNS *const m = &mDNSStorage;
5784     const mDNSs32 now = mDNS_TimeNow(m);
5785     mDNSu32 CacheUsed = 0, CacheActive = 0, slot;
5786     int ProxyA = 0, ProxyD = 0;
5787     mDNSu32 groupCount = 0;
5788     mDNSu32 mcastRecordCount = 0;
5789     mDNSu32 ucastRecordCount = 0;
5790     const CacheGroup *cg;
5791     const CacheRecord *cr;
5792     const DNSQuestion *q;
5793     const DNameListElem *d;
5794     const SearchListElem *s;
5795 
5796     LogToFD(fd, "------------ Cache -------------");
5797     LogToFD(fd, "Slt Q     TTL if     U Type rdlen");
5798     for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
5799     {
5800         for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
5801         {
5802             groupCount++;   // Count one cache entity for the CacheGroup object
5803             for (cr = cg->members; cr; cr=cr->next)
5804             {
5805                 const mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
5806                 const char *ifname;
5807                 mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
5808                 mDNSu32 *const countPtr = InterfaceID ? &mcastRecordCount : &ucastRecordCount;
5809 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
5810                 if (!InterfaceID && cr->resrec.dnsservice &&
5811                     (mdns_dns_service_get_scope(cr->resrec.dnsservice) == mdns_dns_service_scope_interface))
5812                 {
5813                     InterfaceID = (mDNSInterfaceID)(uintptr_t)mdns_dns_service_get_interface_index(cr->resrec.dnsservice);
5814                 }
5815 #else
5816                 if (!InterfaceID && cr->resrec.rDNSServer && cr->resrec.rDNSServer->scopeType)
5817                     InterfaceID = cr->resrec.rDNSServer->interface;
5818 #endif
5819                 ifname = InterfaceNameForID(m, InterfaceID);
5820                 if (cr->CRActiveQuestion) CacheActive++;
5821                 PrintOneCacheRecordToFD(fd, cr, slot, remain, ifname, countPtr);
5822                 PrintCachedRecordsToFD(fd, cr, slot, remain, ifname, countPtr);
5823             }
5824         }
5825     }
5826 
5827     CacheUsed = groupCount + mcastRecordCount + ucastRecordCount;
5828     if (m->rrcache_totalused != CacheUsed)
5829         LogToFD(fd, "Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
5830     if (m->rrcache_active != CacheActive)
5831         LogToFD(fd, "Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
5832     LogToFD(fd, "Cache size %u entities; %u in use (%u group, %u multicast, %u unicast); %u referenced by active questions",
5833               m->rrcache_size, CacheUsed, groupCount, mcastRecordCount, ucastRecordCount, CacheActive);
5834 
5835     LogToFD(fd, "--------- Auth Records ---------");
5836     LogAuthRecordsToFD(fd, now, m->ResourceRecords, mDNSNULL);
5837 
5838     LogToFD(fd, "--------- LocalOnly, P2P Auth Records ---------");
5839     LogLocalOnlyAuthRecordsToFD(fd, m);
5840 
5841     LogToFD(fd, "--------- /etc/hosts ---------");
5842     LogEtcHostsToFD(fd, m);
5843 
5844     LogToFD(fd, "------ Duplicate Records -------");
5845     LogAuthRecordsToFD(fd, now, m->DuplicateRecords, mDNSNULL);
5846 
5847     LogToFD(fd, "----- Auth Records Proxied -----");
5848     LogAuthRecordsToFD(fd, now, m->ResourceRecords, &ProxyA);
5849 
5850     LogToFD(fd, "-- Duplicate Records Proxied ---");
5851     LogAuthRecordsToFD(fd, now, m->DuplicateRecords, &ProxyD);
5852 
5853     LogToFD(fd, "---------- Questions -----------");
5854     if (!m->Questions) LogToFD(fd, "<None>");
5855     else
5856     {
5857         CacheUsed = 0;
5858         CacheActive = 0;
5859         LogToFD(fd, "   Int  Next if     T NumAns VDNS                               Qptr               DupOf              SU SQ Type Name");
5860         for (q = m->Questions; q; q=q->next)
5861         {
5862             mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond;
5863             mDNSs32 n = (NextQSendTime(q) - now) / mDNSPlatformOneSecond;
5864             char *ifname = InterfaceNameForID(m, q->InterfaceID);
5865             CacheUsed++;
5866             if (q->ThisQInterval) CacheActive++;
5867 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
5868             LogToFD(fd, "%6d%6d %-7s%s %5d 0x%p 0x%p %1d %2d  %-5s%##s%s",
5869 #else
5870             LogToFD(fd, "%6d%6d %-7s%s %5d 0x%08x%08x%08x%08x 0x%p 0x%p %1d %2d  %-5s%##s%s",
5871 #endif
5872                       i, n,
5873                       ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
5874                       mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
5875                       q->CurrentAnswers,
5876 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
5877                       q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1], q->validDNSServers.l[0],
5878 #endif
5879                       q, q->DuplicateOf,
5880                       q->SuppressUnusable, q->Suppressed, DNSTypeName(q->qtype), q->qname.c,
5881                       q->DuplicateOf ? " (dup)" : "");
5882         }
5883         LogToFD(fd, "%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
5884     }
5885 
5886     LogToFD(fd, "----- LocalOnly, P2P Questions -----");
5887     if (!m->LocalOnlyQuestions) LogToFD(fd, "<None>");
5888     else for (q = m->LocalOnlyQuestions; q; q=q->next)
5889         LogToFD(fd, "                 %3s   %5d  %-6s%##s%s",
5890                   q->InterfaceID == mDNSInterface_LocalOnly ? "LO ": q->InterfaceID == mDNSInterface_BLE ? "BLE": "P2P",
5891                   q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
5892 
5893     LogToFD(fd, "---- Active UDS Client Requests ----");
5894     if (!all_requests) LogToFD(fd, "<None>");
5895     else
5896     {
5897         request_state *req, *r;
5898         for (req = all_requests; req; req=req->next)
5899         {
5900             if (req->primary)   // If this is a subbordinate operation, check that the parent is in the list
5901             {
5902                 for (r = all_requests; r && r != req; r=r->next) if (r == req->primary) goto foundparent;
5903                 LogToFD(fd, "%3d: Orhpan operation %p; parent %p not found in request list", req->sd);
5904             }
5905             // For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
5906             LogClientInfoToFD(fd, req);
5907         foundparent:;
5908         }
5909     }
5910 
5911     LogToFD(fd, "-------- NAT Traversals --------");
5912     LogToFD(fd, "ExtAddress %.4a Retry %d Interval %d",
5913               &m->ExtAddress,
5914               m->retryGetAddr ? (m->retryGetAddr - now) / mDNSPlatformOneSecond : 0,
5915               m->retryIntervalGetAddr / mDNSPlatformOneSecond);
5916     if (m->NATTraversals)
5917     {
5918         const NATTraversalInfo *nat;
5919         for (nat = m->NATTraversals; nat; nat=nat->next)
5920         {
5921             LogToFD(fd, "%p %s Int %5d %s Err %d Retry %5d Interval %5d Expire %5d Req %.4a:%d Ext %.4a:%d",
5922                       nat,
5923                       nat->Protocol ? (nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP") : "ADD",
5924                       mDNSVal16(nat->IntPort),
5925                       (nat->lastSuccessfulProtocol == NATTProtocolNone    ? "None    " :
5926                        nat->lastSuccessfulProtocol == NATTProtocolNATPMP  ? "NAT-PMP " :
5927                        nat->lastSuccessfulProtocol == NATTProtocolUPNPIGD ? "UPnP/IGD" :
5928                        nat->lastSuccessfulProtocol == NATTProtocolPCP     ? "PCP     " :
5929                        /* else */                                           "Unknown " ),
5930                       nat->Result,
5931                       nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
5932                       nat->retryInterval / mDNSPlatformOneSecond,
5933                       nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
5934                       &nat->NewAddress, mDNSVal16(nat->RequestedPort),
5935                       &nat->ExternalAddress, mDNSVal16(nat->ExternalPort));
5936         }
5937     }
5938 
5939     LogToFD(fd, "--------- AuthInfoList ---------");
5940     if (!m->AuthInfoList) LogToFD(fd, "<None>");
5941     else
5942     {
5943         const DomainAuthInfo *a;
5944         for (a = m->AuthInfoList; a; a = a->next)
5945         {
5946             LogToFD(fd, "%##s %##s %##s %d %d",
5947                       a->domain.c, a->keyname.c,
5948                       a->hostname.c, (a->port.b[0] << 8 | a->port.b[1]),
5949                       (a->deltime ? (a->deltime - now) : 0));
5950         }
5951     }
5952 
5953     LogToFD(fd, "---------- Misc State ----------");
5954 
5955     LogToFD(fd, "PrimaryMAC:   %.6a", &m->PrimaryMAC);
5956 
5957     LogToFD(fd, "m->SleepState %d (%s) seq %d",
5958               m->SleepState,
5959               m->SleepState == SleepState_Awake        ? "Awake"        :
5960               m->SleepState == SleepState_Transferring ? "Transferring" :
5961               m->SleepState == SleepState_Sleeping     ? "Sleeping"     : "?",
5962               m->SleepSeqNum);
5963 
5964     if (!m->SPSSocket) LogToFD(fd, "Not offering Sleep Proxy Service");
5965 #ifndef SPC_DISABLED
5966     else LogToFD(fd, "Offering Sleep Proxy Service: %#s", m->SPSRecords.RR_SRV.resrec.name->c);
5967 #endif
5968     if (m->ProxyRecords == ProxyA + ProxyD) LogToFD(fd, "ProxyRecords: %d + %d = %d", ProxyA, ProxyD, ProxyA + ProxyD);
5969     else LogToFD(fd, "ProxyRecords: MISMATCH %d + %d = %d ≠ %d", ProxyA, ProxyD, ProxyA + ProxyD, m->ProxyRecords);
5970 
5971     LogToFD(fd, "------ Auto Browse Domains -----");
5972     if (!AutoBrowseDomains) LogToFD(fd, "<None>");
5973     else for (d=AutoBrowseDomains; d; d=d->next) LogToFD(fd, "%##s", d->name.c);
5974 
5975     LogToFD(fd, "--- Auto Registration Domains --");
5976     if (!AutoRegistrationDomains) LogToFD(fd, "<None>");
5977     else for (d=AutoRegistrationDomains; d; d=d->next) LogToFD(fd, "%##s", d->name.c);
5978 
5979     LogToFD(fd, "--- Search Domains --");
5980     if (!SearchList) LogToFD(fd, "<None>");
5981     else
5982     {
5983         for (s=SearchList; s; s=s->next)
5984         {
5985             char *ifname = InterfaceNameForID(m, s->InterfaceID);
5986             LogToFD(fd, "%##s %s", s->domain.c, ifname ? ifname : "");
5987         }
5988     }
5989     LogMDNSStatisticsToFD(fd, m);
5990 
5991     LogToFD(fd, "---- Task Scheduling Timers ----");
5992 
5993 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
5994     LogToFD(fd, "BonjourEnabled %d", m->BonjourEnabled);
5995 #endif
5996 
5997 #if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
5998     LogToFD(fd, "EnableBLEBasedDiscovery %d", EnableBLEBasedDiscovery);
5999     LogToFD(fd, "DefaultToBLETriggered %d", DefaultToBLETriggered);
6000 #endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
6001 
6002     if (!m->NewQuestions)
6003         LogToFD(fd, "NewQuestion <NONE>");
6004     else
6005         LogToFD(fd, "NewQuestion DelayAnswering %d %d %##s (%s)",
6006                   m->NewQuestions->DelayAnswering, m->NewQuestions->DelayAnswering-now,
6007                   m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
6008 
6009     if (!m->NewLocalOnlyQuestions)
6010         LogToFD(fd, "NewLocalOnlyQuestions <NONE>");
6011     else
6012         LogToFD(fd, "NewLocalOnlyQuestions %##s (%s)",
6013                   m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
6014 
6015     if (!m->NewLocalRecords)
6016         LogToFD(fd, "NewLocalRecords <NONE>");
6017     else
6018         LogToFD(fd, "NewLocalRecords %02X %s", m->NewLocalRecords->resrec.RecordType, ARDisplayString(m, m->NewLocalRecords));
6019 
6020     LogToFD(fd, "SPSProxyListChanged%s", m->SPSProxyListChanged ? "" : " <NONE>");
6021     LogToFD(fd, "LocalRemoveEvents%s",   m->LocalRemoveEvents   ? "" : " <NONE>");
6022     LogToFD(fd, "m->WABBrowseQueriesCount %d", m->WABBrowseQueriesCount);
6023     LogToFD(fd, "m->WABLBrowseQueriesCount %d", m->WABLBrowseQueriesCount);
6024     LogToFD(fd, "m->WABRegQueriesCount %d", m->WABRegQueriesCount);
6025     LogToFD(fd, "m->AutoTargetServices %u", m->AutoTargetServices);
6026 #if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
6027     LogToFD(fd, "m->AutoTargetAWDLIncludedCount %u", m->AutoTargetAWDLIncludedCount);
6028     LogToFD(fd, "m->AutoTargetAWDLOnlyCount     %u", m->AutoTargetAWDLOnlyCount);
6029 #endif
6030 
6031     LogToFD(fd, "                         ABS (hex)  ABS (dec)  REL (hex)  REL (dec)");
6032     LogToFD(fd, "m->timenow               %08X %11d", now, now);
6033     LogToFD(fd, "m->timenow_adjust        %08X %11d", m->timenow_adjust, m->timenow_adjust);
6034     LogTimerToFD(fd, "m->NextScheduledEvent   ", m->NextScheduledEvent);
6035 
6036 #ifndef UNICAST_DISABLED
6037     LogTimerToFD(fd, "m->NextuDNSEvent        ", m->NextuDNSEvent);
6038     LogTimerToFD(fd, "m->NextSRVUpdate        ", m->NextSRVUpdate);
6039     LogTimerToFD(fd, "m->NextScheduledNATOp   ", m->NextScheduledNATOp);
6040     LogTimerToFD(fd, "m->retryGetAddr         ", m->retryGetAddr);
6041 #endif
6042 
6043     LogTimerToFD(fd, "m->NextCacheCheck       ", m->NextCacheCheck);
6044     LogTimerToFD(fd, "m->NextScheduledSPS     ", m->NextScheduledSPS);
6045     LogTimerToFD(fd, "m->NextScheduledKA      ", m->NextScheduledKA);
6046 
6047 #if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
6048     LogTimerToFD(fd, "m->NextBonjourDisableTime ", m->NextBonjourDisableTime);
6049 #endif
6050 
6051     LogTimerToFD(fd, "m->NextScheduledSPRetry ", m->NextScheduledSPRetry);
6052     LogTimerToFD(fd, "m->DelaySleep           ", m->DelaySleep);
6053 
6054     LogTimerToFD(fd, "m->NextScheduledQuery   ", m->NextScheduledQuery);
6055     LogTimerToFD(fd, "m->NextScheduledProbe   ", m->NextScheduledProbe);
6056     LogTimerToFD(fd, "m->NextScheduledResponse", m->NextScheduledResponse);
6057 
6058     LogTimerToFD(fd, "m->SuppressSending      ", m->SuppressSending);
6059     LogTimerToFD(fd, "m->SuppressProbes       ", m->SuppressProbes);
6060     LogTimerToFD(fd, "m->ProbeFailTime        ", m->ProbeFailTime);
6061     LogTimerToFD(fd, "m->DelaySleep           ", m->DelaySleep);
6062     LogTimerToFD(fd, "m->SleepLimit           ", m->SleepLimit);
6063     LogTimerToFD(fd, "m->NextScheduledStopTime ", m->NextScheduledStopTime);
6064 }
6065 
6066 #if MDNS_MALLOC_DEBUGGING
udsserver_validatelists(void * context)6067 mDNSlocal void udsserver_validatelists(void *context)
6068 {
6069     const request_state *req, *p;
6070 	(void)context; // unused
6071     for (req = all_requests; req; req=req->next)
6072     {
6073         if (req->next == (request_state *)~0 || (req->sd < 0 && req->sd != -2))
6074             LogMemCorruption("UDS request list: %p is garbage (%d)", req, req->sd);
6075 
6076         if (req->primary == req)
6077             LogMemCorruption("UDS request list: req->primary should not point to self %p/%d", req, req->sd);
6078 
6079         if (req->primary && req->replies)
6080             LogMemCorruption("UDS request list: Subordinate request %p/%d/%p should not have replies (%p)",
6081                              req, req->sd, req->primary && req->replies);
6082 
6083         p = req->primary;
6084         if ((long)p & 3)
6085             LogMemCorruption("UDS request list: req %p primary %p is misaligned (%d)", req, p, req->sd);
6086         else if (p && (p->next == (request_state *)~0 || (p->sd < 0 && p->sd != -2)))
6087             LogMemCorruption("UDS request list: req %p primary %p is garbage (%d)", req, p, p->sd);
6088 
6089         reply_state *rep;
6090         for (rep = req->replies; rep; rep=rep->next)
6091             if (rep->next == (reply_state *)~0)
6092                 LogMemCorruption("UDS req->replies: %p is garbage", rep);
6093 
6094         if (req->terminate == connection_termination)
6095         {
6096             registered_record_entry *r;
6097             for (r = req->u.reg_recs; r; r=r->next)
6098                 if (r->next == (registered_record_entry *)~0)
6099                     LogMemCorruption("UDS req->u.reg_recs: %p is garbage", r);
6100         }
6101         else if (req->terminate == regservice_termination_callback)
6102         {
6103             service_instance *s;
6104             for (s = req->u.servicereg.instances; s; s=s->next)
6105                 if (s->next == (service_instance *)~0)
6106                     LogMemCorruption("UDS req->u.servicereg.instances: %p is garbage", s);
6107         }
6108         else if (req->terminate == browse_termination_callback)
6109         {
6110             browser_t *b;
6111             for (b = req->u.browser.browsers; b; b=b->next)
6112                 if (b->next == (browser_t *)~0)
6113                     LogMemCorruption("UDS req->u.browser.browsers: %p is garbage", b);
6114         }
6115     }
6116 
6117     DNameListElem *d;
6118     for (d = SCPrefBrowseDomains; d; d=d->next)
6119         if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
6120             LogMemCorruption("SCPrefBrowseDomains: %p is garbage (%d)", d, d->name.c[0]);
6121 
6122     ARListElem *b;
6123     for (b = LocalDomainEnumRecords; b; b=b->next)
6124         if (b->next == (ARListElem *)~0 || b->ar.resrec.name->c[0] > 63)
6125             LogMemCorruption("LocalDomainEnumRecords: %p is garbage (%d)", b, b->ar.resrec.name->c[0]);
6126 
6127     for (d = AutoBrowseDomains; d; d=d->next)
6128         if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
6129             LogMemCorruption("AutoBrowseDomains: %p is garbage (%d)", d, d->name.c[0]);
6130 
6131     for (d = AutoRegistrationDomains; d; d=d->next)
6132         if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
6133             LogMemCorruption("AutoRegistrationDomains: %p is garbage (%d)", d, d->name.c[0]);
6134 }
6135 #endif // MDNS_MALLOC_DEBUGGING
6136 
send_msg(request_state * const req)6137 mDNSlocal int send_msg(request_state *const req)
6138 {
6139     reply_state *const rep = req->replies;      // Send the first waiting reply
6140     ssize_t nwriten;
6141 
6142     ConvertHeaderBytes(rep->mhdr);
6143     nwriten = send(req->sd, (char *)&rep->mhdr + rep->nwriten, rep->totallen - rep->nwriten, 0);
6144     ConvertHeaderBytes(rep->mhdr);
6145 
6146     if (nwriten < 0)
6147     {
6148         if (dnssd_errno == dnssd_EINTR || dnssd_errno == dnssd_EWOULDBLOCK) nwriten = 0;
6149         else
6150         {
6151 #if !defined(PLATFORM_NO_EPIPE)
6152             if (dnssd_errno == EPIPE)
6153                 return(req->ts = t_terminated);
6154             else
6155 #endif
6156             {
6157                 LogMsg("send_msg ERROR: failed to write %d of %d bytes to fd %d errno %d (%s)",
6158                        rep->totallen - rep->nwriten, rep->totallen, req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
6159                 return(t_error);
6160             }
6161         }
6162     }
6163     rep->nwriten += nwriten;
6164     return (rep->nwriten == rep->totallen) ? t_complete : t_morecoming;
6165 }
6166 
udsserver_idle(mDNSs32 nextevent)6167 mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
6168 {
6169     mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
6170     request_state **req = &all_requests;
6171 
6172     while (*req)
6173     {
6174         request_state *const r = *req;
6175 
6176         if (r->terminate == resolve_termination_callback)
6177             if (r->u.resolve.ReportTime && now - r->u.resolve.ReportTime >= 0)
6178             {
6179                 r->u.resolve.ReportTime = 0;
6180                 // if client received results and resolve still active
6181                 if (r->u.resolve.txt && r->u.resolve.srv)
6182                     LogMsgNoIdent("Client application PID[%d](%s) has received results for DNSServiceResolve(%##s) yet remains active over two minutes.", r->process_id, r->pid_name, r->u.resolve.qsrv.qname.c);
6183             }
6184 
6185         // Note: Only primary req's have reply lists, not subordinate req's.
6186         while (r->replies)      // Send queued replies
6187         {
6188             transfer_state result;
6189             if (r->replies->next)
6190                 r->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
6191             result = send_msg(r);   // Returns t_morecoming if buffer full because client is not reading
6192             if (result == t_complete)
6193             {
6194                 reply_state *fptr = r->replies;
6195                 r->replies = r->replies->next;
6196                 freeL("reply_state/udsserver_idle", fptr);
6197                 r->time_blocked = 0; // reset failure counter after successful send
6198                 r->unresponsiveness_reports = 0;
6199                 continue;
6200             }
6201             else if (result == t_terminated)
6202             {
6203                 LogInfo("%3d: Could not write data to client PID[%d](%s) because connection is terminated by the client", r->sd, r->process_id, r->pid_name);
6204                 abort_request(r);
6205             }
6206             else if (result == t_error)
6207             {
6208                 LogMsg("%3d: Could not write data to client PID[%d](%s) because of error - aborting connection", r->sd, r->process_id, r->pid_name);
6209                 LogClientInfo(r);
6210                 abort_request(r);
6211             }
6212             break;
6213         }
6214 
6215         if (r->replies)     // If we failed to send everything, check our time_blocked timer
6216         {
6217             if (nextevent - now > mDNSPlatformOneSecond)
6218                 nextevent = now + mDNSPlatformOneSecond;
6219 
6220             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
6221                "[R%u] Could not send all replies. Will try again in %d ticks.", r->request_id, nextevent - now);
6222             if (mDNSStorage.SleepState != SleepState_Awake)
6223                 r->time_blocked = 0;
6224             else if (!r->time_blocked)
6225                 r->time_blocked = NonZeroTime(now);
6226             else if (now - r->time_blocked >= 10 * mDNSPlatformOneSecond * (r->unresponsiveness_reports+1))
6227             {
6228                 int num = 0;
6229                 struct reply_state *x = r->replies;
6230                 while (x)
6231                 {
6232                     num++;
6233                     x=x->next;
6234                 }
6235                 LogMsg("%3d: Could not write data to client PID[%d](%s) after %ld seconds, %d repl%s waiting",
6236                        r->sd, r->process_id, r->pid_name, (now - r->time_blocked) / mDNSPlatformOneSecond, num, num == 1 ? "y" : "ies");
6237                 if (++r->unresponsiveness_reports >= 60)
6238                 {
6239                     LogMsg("%3d: Client PID[%d](%s) unresponsive; aborting connection", r->sd, r->process_id, r->pid_name);
6240                     LogClientInfo(r);
6241                     abort_request(r);
6242                 }
6243             }
6244         }
6245 
6246         if (!dnssd_SocketValid(r->sd)) // If this request is finished, unlink it from the list and free the memory
6247         {
6248             // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
6249             *req = r->next;
6250             freeL("request_state/udsserver_idle", r);
6251         }
6252         else
6253             req = &r->next;
6254     }
6255     return nextevent;
6256 }
6257 
6258 struct CompileTimeAssertionChecks_uds_daemon
6259 {
6260     // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
6261     // other overly-large structures instead of having a pointer to them, can inadvertently
6262     // cause structure sizes (and therefore memory usage) to balloon unreasonably.
6263     char sizecheck_request_state          [(sizeof(request_state)           <= 3880) ? 1 : -1];
6264     char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <=   60) ? 1 : -1];
6265     char sizecheck_service_instance       [(sizeof(service_instance)        <= 6552) ? 1 : -1];
6266     char sizecheck_browser_t              [(sizeof(browser_t)               <= 1480) ? 1 : -1];
6267     char sizecheck_reply_hdr              [(sizeof(reply_hdr)               <=   12) ? 1 : -1];
6268     char sizecheck_reply_state            [(sizeof(reply_state)             <=   64) ? 1 : -1];
6269 };
6270 
6271 #ifdef UNIT_TEST
6272 #include "../unittests/uds_daemon_ut.c"
6273 #endif  //  UNIT_TEST
6274