1 /*
2  * Copyright (c) 2003-2019 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  * This file defines a simple shim layer between a client calling the "/usr/include/dns_sd.h" APIs
17  * and an implementation of mDNSCore ("mDNSEmbeddedAPI.h" APIs) in the same address space.
18  * When the client calls a dns_sd.h function, the shim calls the corresponding mDNSEmbeddedAPI.h
19  * function, and when mDNSCore calls the shim's callback, we call through to the client's callback.
20  * The shim is responsible for two main things:
21  * - converting string parameters between C string format and native DNS format,
22  * - and for allocating and freeing memory.
23  */
24 
25 #include "dns_sd.h"             // Defines the interface to the client layer above
26 #include "mDNSEmbeddedAPI.h"        // The interface we're building on top of
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 extern mDNS mDNSStorage;        // We need to pass the address of this storage to the lower-layer functions
30 
31 #if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
32 #pragma export on
33 #endif
34 
35 //*************************************************************************************************************
36 // General Utility Functions
37 
38 // All mDNS_DirectOP structures start with the pointer to the type-specific disposal function.
39 // Optional type-specific data follows these three fields
40 // When the client starts an operation, we return the address of the corresponding mDNS_DirectOP
41 // as the DNSServiceRef for the operation
42 // We stash the value in core context fields so we can get it back to recover our state in our callbacks,
43 // and pass it though to the client for it to recover its state
44 
45 typedef struct mDNS_DirectOP_struct mDNS_DirectOP;
46 typedef void mDNS_DirectOP_Dispose (mDNS_DirectOP *op);
47 struct mDNS_DirectOP_struct
48 {
49     mDNS_DirectOP_Dispose  *disposefn;
50 };
51 
52 typedef struct
53 {
54     mDNS_DirectOP_Dispose  *disposefn;
55     DNSServiceRegisterReply callback;
56     void                   *context;
57     mDNSBool autoname;                      // Set if this name is tied to the Computer Name
58     mDNSBool autorename;                    // Set if we just got a name conflict and now need to automatically pick a new name
59     domainlabel name;
60     domainname host;
61     ServiceRecordSet s;
62 } mDNS_DirectOP_Register;
63 
64 typedef struct
65 {
66     mDNS_DirectOP_Dispose  *disposefn;
67     DNSServiceBrowseReply callback;
68     void                   *context;
69     DNSQuestion q;
70 } mDNS_DirectOP_Browse;
71 
72 typedef struct
73 {
74     mDNS_DirectOP_Dispose  *disposefn;
75     DNSServiceResolveReply callback;
76     void                   *context;
77     const ResourceRecord   *SRV;
78     const ResourceRecord   *TXT;
79     DNSQuestion qSRV;
80     DNSQuestion qTXT;
81 } mDNS_DirectOP_Resolve;
82 
83 typedef struct
84 {
85     mDNS_DirectOP_Dispose      *disposefn;
86     DNSServiceQueryRecordReply callback;
87     void                       *context;
88     DNSQuestion q;
89 } mDNS_DirectOP_QueryRecord;
90 
91 typedef struct
92 {
93     mDNS_DirectOP_Dispose     *disposefn;
94     DNSServiceGetAddrInfoReply callback;
95     void                      *context;
96     mDNSu32                    interfaceIndex;
97     DNSQuestion                a;
98     DNSQuestion                aaaa;
99 } mDNS_DirectOP_GetAddrInfo;
100 
DNSServiceRefSockFD(DNSServiceRef sdRef)101 dnssd_sock_t DNSServiceRefSockFD(DNSServiceRef sdRef)
102 {
103     (void)sdRef;    // Unused
104     return(0);
105 }
106 
DNSServiceProcessResult(DNSServiceRef sdRef)107 DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
108 {
109     (void)sdRef;    // Unused
110     return(kDNSServiceErr_NoError);
111 }
112 
DNSServiceRefDeallocate(DNSServiceRef sdRef)113 void DNSServiceRefDeallocate(DNSServiceRef sdRef)
114 {
115     mDNS_DirectOP *op = (mDNS_DirectOP *)sdRef;
116     //LogMsg("DNSServiceRefDeallocate");
117     op->disposefn(op);
118 }
119 
DNSServiceInterfaceIndexToID(mDNSu32 interfaceIndex,DNSServiceFlags * flags)120 static mDNSInterfaceID DNSServiceInterfaceIndexToID(mDNSu32 interfaceIndex, DNSServiceFlags *flags)
121 {
122     // Map kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
123     // flag set so that the resolve will run over P2P interfaces that are not yet created.
124     if (interfaceIndex == kDNSServiceInterfaceIndexP2P)
125     {
126         LogOperation("handle_resolve_request: mapping kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny + kDNSServiceFlagsIncludeP2P");
127         if (flags != mDNSNULL) *flags |= kDNSServiceFlagsIncludeP2P;
128         interfaceIndex = kDNSServiceInterfaceIndexAny;
129     }
130     return mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
131 }
132 
133 //*************************************************************************************************************
134 // Domain Enumeration
135 
136 // Not yet implemented, so don't include in stub library
137 // We DO include it in the actual Extension, so that if a later client compiled to use this
138 // is run against this Extension, it will get a reasonable error code instead of just
139 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
140 #if !MDNS_BUILDINGSTUBLIBRARY
DNSServiceEnumerateDomains(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceDomainEnumReply callback,void * context)141 DNSServiceErrorType DNSServiceEnumerateDomains
142 (
143     DNSServiceRef                       *sdRef,
144     DNSServiceFlags flags,
145     uint32_t interfaceIndex,
146     DNSServiceDomainEnumReply callback,
147     void                                *context  /* may be NULL */
148 )
149 {
150     (void)sdRef;            // Unused
151     (void)flags;            // Unused
152     (void)interfaceIndex;   // Unused
153     (void)callback;         // Unused
154     (void)context;          // Unused
155     return(kDNSServiceErr_Unsupported);
156 }
157 #endif
158 
159 //*************************************************************************************************************
160 // Register Service
161 
FreeDNSServiceRegistration(mDNS_DirectOP_Register * x)162 mDNSlocal void FreeDNSServiceRegistration(mDNS_DirectOP_Register *x)
163 {
164     while (x->s.Extras)
165     {
166         ExtraResourceRecord *extras = x->s.Extras;
167         x->s.Extras = x->s.Extras->next;
168         if (extras->r.resrec.rdata != &extras->r.rdatastorage)
169             mDNSPlatformMemFree(extras->r.resrec.rdata);
170         mDNSPlatformMemFree(extras);
171     }
172 
173     if (x->s.RR_TXT.resrec.rdata != &x->s.RR_TXT.rdatastorage)
174         mDNSPlatformMemFree(x->s.RR_TXT.resrec.rdata);
175 
176     if (x->s.SubTypes) mDNSPlatformMemFree(x->s.SubTypes);
177 
178     mDNSPlatformMemFree(x);
179 }
180 
DNSServiceRegisterDispose(mDNS_DirectOP * op)181 static void DNSServiceRegisterDispose(mDNS_DirectOP *op)
182 {
183     mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)op;
184     x->autorename = mDNSfalse;
185     // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
186     // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
187     // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
188     // the list, so we should go ahead and free the memory right now
189     if (mDNS_DeregisterService(&mDNSStorage, &x->s) != mStatus_NoError)
190         FreeDNSServiceRegistration(x);
191 }
192 
RegCallback(mDNS * const m,ServiceRecordSet * const sr,mStatus result)193 mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
194 {
195     mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)sr->ServiceContext;
196 
197     domainlabel name;
198     domainname type, dom;
199     char namestr[MAX_DOMAIN_LABEL+1];       // Unescaped name: up to 63 bytes plus C-string terminating NULL.
200     char typestr[MAX_ESCAPED_DOMAIN_NAME];
201     char domstr [MAX_ESCAPED_DOMAIN_NAME];
202     if (!DeconstructServiceName(sr->RR_SRV.resrec.name, &name, &type, &dom)) return;
203     if (!ConvertDomainLabelToCString_unescaped(&name, namestr)) return;
204     if (!ConvertDomainNameToCString(&type, typestr)) return;
205     if (!ConvertDomainNameToCString(&dom, domstr)) return;
206 
207     if (result == mStatus_NoError)
208     {
209         if (x->callback)
210             x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context);
211     }
212     else if (result == mStatus_NameConflict)
213     {
214         if (x->autoname) mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
215         else if (x->callback)
216             x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context);
217     }
218     else if (result == mStatus_MemFree)
219     {
220         if (x->autorename)
221         {
222             x->autorename = mDNSfalse;
223             x->name = mDNSStorage.nicelabel;
224             mDNS_RenameAndReregisterService(m, &x->s, &x->name);
225         }
226         else
227             FreeDNSServiceRegistration(x);
228     }
229 }
230 
DNSServiceRegister(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,const char * host,uint16_t notAnIntPort,uint16_t txtLen,const void * txtRecord,DNSServiceRegisterReply callback,void * context)231 DNSServiceErrorType DNSServiceRegister
232 (
233     DNSServiceRef                       *sdRef,
234     DNSServiceFlags flags,
235     uint32_t interfaceIndex,
236     const char                          *name,         /* may be NULL */
237     const char                          *regtype,
238     const char                          *domain,       /* may be NULL */
239     const char                          *host,         /* may be NULL */
240     uint16_t notAnIntPort,
241     uint16_t txtLen,
242     const void                          *txtRecord,    /* may be NULL */
243     DNSServiceRegisterReply callback,                  /* may be NULL */
244     void                                *context       /* may be NULL */
245 )
246 {
247     mStatus err = mStatus_NoError;
248     const char *errormsg = "Unknown";
249     domainlabel n;
250     domainname t, d, h, srv;
251     mDNSIPPort port;
252     unsigned int size = sizeof(RDataBody);
253     AuthRecord *SubTypes = mDNSNULL;
254     mDNSu32 NumSubTypes = 0;
255     mDNS_DirectOP_Register *x;
256     (void)flags;            // Unused
257     (void)interfaceIndex;   // Unused
258 
259     // Check parameters
260     if (!name) name = "";
261     if (!name[0]) n = mDNSStorage.nicelabel;
262     else if (!MakeDomainLabelFromLiteralString(&n, name))                              { errormsg = "Bad Instance Name"; goto badparam; }
263     if (!regtype || !*regtype || !MakeDomainNameFromDNSNameString(&t, regtype))        { errormsg = "Bad Service Type";  goto badparam; }
264     if (!MakeDomainNameFromDNSNameString(&d, (domain && *domain) ? domain : "local.")) { errormsg = "Bad Domain";        goto badparam; }
265     if (!MakeDomainNameFromDNSNameString(&h, (host   && *host  ) ? host   : ""))       { errormsg = "Bad Target Host";   goto badparam; }
266     if (!ConstructServiceName(&srv, &n, &t, &d))                                       { errormsg = "Bad Name";          goto badparam; }
267     port.NotAnInteger = notAnIntPort;
268 
269     // Allocate memory, and handle failure
270     if (size < txtLen)
271         size = txtLen;
272     x = (mDNS_DirectOP_Register *) mDNSPlatformMemAllocateClear(sizeof(*x) - sizeof(RDataBody) + size);
273     if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
274 
275     // Set up object
276     x->disposefn = DNSServiceRegisterDispose;
277     x->callback  = callback;
278     x->context   = context;
279     x->autoname = (!name[0]);
280     x->autorename = mDNSfalse;
281     x->name = n;
282     x->host = h;
283 
284     // Do the operation
285     err = mDNS_RegisterService(&mDNSStorage, &x->s,
286                                &x->name, &t, &d, // Name, type, domain
287                                &x->host, port, // Host and port
288 							   mDNSNULL,
289                                txtRecord, txtLen, // TXT data, length
290                                SubTypes, NumSubTypes, // Subtypes
291                                mDNSInterface_Any, // Interface ID
292                                RegCallback, x, 0); // Callback, context, flags
293     if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_RegisterService"; goto fail; }
294 
295     // Succeeded: Wrap up and return
296     *sdRef = (DNSServiceRef)x;
297     return(mStatus_NoError);
298 
299 badparam:
300     err = mStatus_BadParamErr;
301 fail:
302     LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
303     return(err);
304 }
305 
306 //*************************************************************************************************************
307 // Add / Update / Remove records from existing Registration
308 
309 // Not yet implemented, so don't include in stub library
310 // We DO include it in the actual Extension, so that if a later client compiled to use this
311 // is run against this Extension, it will get a reasonable error code instead of just
312 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
313 #if !MDNS_BUILDINGSTUBLIBRARY
DNSServiceAddRecord(DNSServiceRef sdRef,DNSRecordRef * RecordRef,DNSServiceFlags flags,uint16_t rrtype,uint16_t rdlen,const void * rdata,uint32_t ttl)314 DNSServiceErrorType DNSServiceAddRecord
315 (
316     DNSServiceRef sdRef,
317     DNSRecordRef                        *RecordRef,
318     DNSServiceFlags flags,
319     uint16_t rrtype,
320     uint16_t rdlen,
321     const void                          *rdata,
322     uint32_t ttl
323 )
324 {
325     (void)sdRef;        // Unused
326     (void)RecordRef;    // Unused
327     (void)flags;        // Unused
328     (void)rrtype;       // Unused
329     (void)rdlen;        // Unused
330     (void)rdata;        // Unused
331     (void)ttl;          // Unused
332     return(kDNSServiceErr_Unsupported);
333 }
334 
DNSServiceUpdateRecord(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags,uint16_t rdlen,const void * rdata,uint32_t ttl)335 DNSServiceErrorType DNSServiceUpdateRecord
336 (
337     DNSServiceRef sdRef,
338     DNSRecordRef RecordRef,                            /* may be NULL */
339     DNSServiceFlags flags,
340     uint16_t rdlen,
341     const void                          *rdata,
342     uint32_t ttl
343 )
344 {
345     (void)sdRef;        // Unused
346     (void)RecordRef;    // Unused
347     (void)flags;        // Unused
348     (void)rdlen;        // Unused
349     (void)rdata;        // Unused
350     (void)ttl;          // Unused
351     return(kDNSServiceErr_Unsupported);
352 }
353 
DNSServiceRemoveRecord(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags)354 DNSServiceErrorType DNSServiceRemoveRecord
355 (
356     DNSServiceRef sdRef,
357     DNSRecordRef RecordRef,
358     DNSServiceFlags flags
359 )
360 {
361     (void)sdRef;        // Unused
362     (void)RecordRef;    // Unused
363     (void)flags;        // Unused
364     return(kDNSServiceErr_Unsupported);
365 }
366 #endif
367 
368 //*************************************************************************************************************
369 // Browse for services
370 
DNSServiceBrowseDispose(mDNS_DirectOP * op)371 static void DNSServiceBrowseDispose(mDNS_DirectOP *op)
372 {
373     mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)op;
374     //LogMsg("DNSServiceBrowseDispose");
375     mDNS_StopBrowse(&mDNSStorage, &x->q);
376     mDNSPlatformMemFree(x);
377 }
378 
FoundInstance(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)379 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
380 {
381     DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0;
382     domainlabel name;
383     domainname type, domain;
384     char cname[MAX_DOMAIN_LABEL+1];         // Unescaped name: up to 63 bytes plus C-string terminating NULL.
385     char ctype[MAX_ESCAPED_DOMAIN_NAME];
386     char cdom [MAX_ESCAPED_DOMAIN_NAME];
387     mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)question->QuestionContext;
388     (void)m;        // Unused
389 
390     if (answer->rrtype != kDNSType_PTR)
391     { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; }
392 
393     if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
394     {
395         LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
396                answer->name->c, answer->rdata->u.name.c);
397         return;
398     }
399 
400     ConvertDomainLabelToCString_unescaped(&name, cname);
401     ConvertDomainNameToCString(&type, ctype);
402     ConvertDomainNameToCString(&domain, cdom);
403     if (x->callback)
404         x->callback((DNSServiceRef)x, flags, 0, 0, cname, ctype, cdom, x->context);
405 }
406 
DNSServiceBrowse(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * regtype,const char * domain,DNSServiceBrowseReply callback,void * context)407 DNSServiceErrorType DNSServiceBrowse
408 (
409     DNSServiceRef                       *sdRef,
410     DNSServiceFlags flags,
411     uint32_t interfaceIndex,
412     const char                          *regtype,
413     const char                          *domain,    /* may be NULL */
414     DNSServiceBrowseReply callback,
415     void                                *context    /* may be NULL */
416 )
417 {
418     mStatus err = mStatus_NoError;
419     const char *errormsg = "Unknown";
420     domainname t, d;
421     mDNS_DirectOP_Browse *x;
422     (void)flags;            // Unused
423     (void)interfaceIndex;   // Unused
424 
425     // Check parameters
426     if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype))      { errormsg = "Illegal regtype"; goto badparam; }
427     if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Illegal domain";  goto badparam; }
428 
429     // Allocate memory, and handle failure
430     x = (mDNS_DirectOP_Browse *) mDNSPlatformMemAllocateClear(sizeof(*x));
431     if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
432 
433     // Set up object
434     x->disposefn = DNSServiceBrowseDispose;
435     x->callback  = callback;
436     x->context   = context;
437     x->q.QuestionContext = x;
438 
439     // Do the operation
440     err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, flags, (flags & kDNSServiceFlagsForceMulticast) != 0, (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0, FoundInstance, x);
441     if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_StartBrowse"; goto fail; }
442 
443     // Succeeded: Wrap up and return
444     *sdRef = (DNSServiceRef)x;
445     return(mStatus_NoError);
446 
447 badparam:
448     err = mStatus_BadParamErr;
449 fail:
450     LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
451     return(err);
452 }
453 
454 //*************************************************************************************************************
455 // Resolve Service Info
456 
DNSServiceResolveDispose(mDNS_DirectOP * op)457 static void DNSServiceResolveDispose(mDNS_DirectOP *op)
458 {
459     mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)op;
460     if (x->qSRV.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qSRV);
461     if (x->qTXT.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qTXT);
462     mDNSPlatformMemFree(x);
463 }
464 
FoundServiceInfo(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)465 mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
466 {
467     mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)question->QuestionContext;
468     (void)m;    // Unused
469     if (!AddRecord)
470     {
471         if (answer->rrtype == kDNSType_SRV && x->SRV == answer) x->SRV = mDNSNULL;
472         if (answer->rrtype == kDNSType_TXT && x->TXT == answer) x->TXT = mDNSNULL;
473     }
474     else
475     {
476         if (answer->rrtype == kDNSType_SRV) x->SRV = answer;
477         if (answer->rrtype == kDNSType_TXT) x->TXT = answer;
478         if (x->SRV && x->TXT && x->callback)
479         {
480             char fullname[MAX_ESCAPED_DOMAIN_NAME], targethost[MAX_ESCAPED_DOMAIN_NAME];
481             ConvertDomainNameToCString(answer->name, fullname);
482             ConvertDomainNameToCString(&x->SRV->rdata->u.srv.target, targethost);
483             x->callback((DNSServiceRef)x, 0, 0, kDNSServiceErr_NoError, fullname, targethost,
484                         x->SRV->rdata->u.srv.port.NotAnInteger, x->TXT->rdlength, (unsigned char*)x->TXT->rdata->u.txt.c, x->context);
485         }
486     }
487 }
488 
DNSServiceResolve(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,DNSServiceResolveReply callback,void * context)489 DNSServiceErrorType DNSServiceResolve
490 (
491     DNSServiceRef                       *sdRef,
492     DNSServiceFlags flags,
493     uint32_t interfaceIndex,
494     const char                          *name,
495     const char                          *regtype,
496     const char                          *domain,
497     DNSServiceResolveReply callback,
498     void                                *context  /* may be NULL */
499 )
500 {
501     mStatus err = mStatus_NoError;
502     const char *errormsg = "Unknown";
503     domainlabel n;
504     domainname t, d, srv;
505     mDNS_DirectOP_Resolve *x;
506 
507     // Check parameters
508     if (!name[0]    || !MakeDomainLabelFromLiteralString(&n, name  )) { errormsg = "Bad Instance Name"; goto badparam; }
509     if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type";  goto badparam; }
510     if (!domain[0]  || !MakeDomainNameFromDNSNameString(&d, domain )) { errormsg = "Bad Domain";        goto badparam; }
511     if (!ConstructServiceName(&srv, &n, &t, &d))                      { errormsg = "Bad Name";          goto badparam; }
512 
513     // Allocate memory, and handle failure
514     x = (mDNS_DirectOP_Resolve *) mDNSPlatformMemAllocateClear(sizeof(*x));
515     if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
516 
517     // Set up object
518     x->disposefn = DNSServiceResolveDispose;
519     x->callback  = callback;
520     x->context   = context;
521     x->SRV       = mDNSNULL;
522     x->TXT       = mDNSNULL;
523 
524     x->qSRV.ThisQInterval       = -1;       // So that DNSServiceResolveDispose() knows whether to cancel this question
525     x->qSRV.InterfaceID         = DNSServiceInterfaceIndexToID(interfaceIndex, &flags);
526     x->qSRV.flags               = flags;
527     AssignDomainName(&x->qSRV.qname, &srv);
528     x->qSRV.qtype               = kDNSType_SRV;
529     x->qSRV.qclass              = kDNSClass_IN;
530     x->qSRV.LongLived           = mDNSfalse;
531     x->qSRV.ExpectUnique        = mDNStrue;
532     x->qSRV.ForceMCast          = mDNSfalse;
533     x->qSRV.ReturnIntermed      = mDNSfalse;
534     x->qSRV.SuppressUnusable    = mDNSfalse;
535     x->qSRV.AppendSearchDomains = 0;
536     x->qSRV.TimeoutQuestion     = 0;
537     x->qSRV.WakeOnResolve       = 0;
538     x->qSRV.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
539     x->qSRV.ProxyQuestion       = 0;
540     x->qSRV.pid                 = mDNSPlatformGetPID();
541     x->qSRV.QuestionCallback    = FoundServiceInfo;
542     x->qSRV.QuestionContext     = x;
543 
544     x->qTXT.ThisQInterval       = -1;       // So that DNSServiceResolveDispose() knows whether to cancel this question
545     x->qTXT.InterfaceID         = DNSServiceInterfaceIndexToID(interfaceIndex, mDNSNULL);
546     x->qTXT.flags               = flags;
547     AssignDomainName(&x->qTXT.qname, &srv);
548     x->qTXT.qtype               = kDNSType_TXT;
549     x->qTXT.qclass              = kDNSClass_IN;
550     x->qTXT.LongLived           = mDNSfalse;
551     x->qTXT.ExpectUnique        = mDNStrue;
552     x->qTXT.ForceMCast          = mDNSfalse;
553     x->qTXT.ReturnIntermed      = mDNSfalse;
554     x->qTXT.SuppressUnusable    = mDNSfalse;
555     x->qTXT.AppendSearchDomains = 0;
556     x->qTXT.TimeoutQuestion     = 0;
557     x->qTXT.WakeOnResolve       = 0;
558     x->qTXT.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
559     x->qTXT.ProxyQuestion       = 0;
560     x->qTXT.pid                 = mDNSPlatformGetPID();
561     x->qTXT.QuestionCallback    = FoundServiceInfo;
562     x->qTXT.QuestionContext     = x;
563 
564     err = mDNS_StartQuery(&mDNSStorage, &x->qSRV);
565     if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qSRV"; goto fail; }
566     err = mDNS_StartQuery(&mDNSStorage, &x->qTXT);
567     if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qTXT"; goto fail; }
568 
569     // Succeeded: Wrap up and return
570     *sdRef = (DNSServiceRef)x;
571     return(mStatus_NoError);
572 
573 badparam:
574     err = mStatus_BadParamErr;
575 fail:
576     LogMsg("DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", name, regtype, domain, errormsg, err);
577     return(err);
578 }
579 
580 //*************************************************************************************************************
581 // Connection-oriented calls
582 
583 // Not yet implemented, so don't include in stub library
584 // We DO include it in the actual Extension, so that if a later client compiled to use this
585 // is run against this Extension, it will get a reasonable error code instead of just
586 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
587 #if !MDNS_BUILDINGSTUBLIBRARY
DNSServiceCreateConnection(DNSServiceRef * sdRef)588 DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
589 {
590     (void)sdRef;    // Unused
591     return(kDNSServiceErr_Unsupported);
592 }
593 
DNSServiceRegisterRecord(DNSServiceRef sdRef,DNSRecordRef * RecordRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,DNSServiceRegisterRecordReply callback,void * context)594 DNSServiceErrorType DNSServiceRegisterRecord
595 (
596     DNSServiceRef sdRef,
597     DNSRecordRef                        *RecordRef,
598     DNSServiceFlags flags,
599     uint32_t interfaceIndex,
600     const char                          *fullname,
601     uint16_t rrtype,
602     uint16_t rrclass,
603     uint16_t rdlen,
604     const void                          *rdata,
605     uint32_t ttl,
606     DNSServiceRegisterRecordReply callback,
607     void                                *context    /* may be NULL */
608 )
609 {
610     (void)sdRef;            // Unused
611     (void)RecordRef;        // Unused
612     (void)flags;            // Unused
613     (void)interfaceIndex;   // Unused
614     (void)fullname;         // Unused
615     (void)rrtype;           // Unused
616     (void)rrclass;          // Unused
617     (void)rdlen;            // Unused
618     (void)rdata;            // Unused
619     (void)ttl;              // Unused
620     (void)callback;         // Unused
621     (void)context;          // Unused
622     return(kDNSServiceErr_Unsupported);
623 }
624 #endif
625 
626 //*************************************************************************************************************
627 // DNSServiceQueryRecord
628 
DNSServiceQueryRecordDispose(mDNS_DirectOP * op)629 static void DNSServiceQueryRecordDispose(mDNS_DirectOP *op)
630 {
631     mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)op;
632     if (x->q.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->q);
633     mDNSPlatformMemFree(x);
634 }
635 
DNSServiceQueryRecordResponse(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)636 mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
637 {
638     mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)question->QuestionContext;
639     char fullname[MAX_ESCAPED_DOMAIN_NAME];
640     (void)m;    // Unused
641     ConvertDomainNameToCString(answer->name, fullname);
642     x->callback((DNSServiceRef)x, AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, 0, kDNSServiceErr_NoError,
643                 fullname, answer->rrtype, answer->rrclass, answer->rdlength, answer->rdata->u.data, answer->rroriginalttl, x->context);
644 }
645 
DNSServiceQueryRecord(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,DNSServiceQueryRecordReply callback,void * context)646 DNSServiceErrorType DNSServiceQueryRecord
647 (
648     DNSServiceRef             *sdRef,
649     DNSServiceFlags            flags,
650     uint32_t                   interfaceIndex,
651     const char                *fullname,
652     uint16_t                   rrtype,
653     uint16_t                   rrclass,
654     DNSServiceQueryRecordReply callback,
655     void                      *context  /* may be NULL */
656 )
657 {
658     mStatus err = mStatus_NoError;
659     const char *errormsg = "Unknown";
660     mDNS_DirectOP_QueryRecord *x;
661 
662     // Allocate memory, and handle failure
663     x = (mDNS_DirectOP_QueryRecord *) mDNSPlatformMemAllocateClear(sizeof(*x));
664     if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
665 
666     // Set up object
667     x->disposefn = DNSServiceQueryRecordDispose;
668     x->callback  = callback;
669     x->context   = context;
670 
671     x->q.ThisQInterval        = -1;      // So that DNSServiceResolveDispose() knows whether to cancel this question
672     x->q.InterfaceID          = DNSServiceInterfaceIndexToID(interfaceIndex, &flags);
673     x->q.flags                = flags;
674     MakeDomainNameFromDNSNameString(&x->q.qname, fullname);
675     x->q.qtype                = rrtype;
676     x->q.qclass               = rrclass;
677     x->q.LongLived            = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
678     x->q.ExpectUnique         = mDNSfalse;
679     x->q.ForceMCast           = (flags & kDNSServiceFlagsForceMulticast) != 0;
680     x->q.ReturnIntermed       = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
681     x->q.SuppressUnusable     = (flags & kDNSServiceFlagsSuppressUnusable) != 0;
682     x->q.AppendSearchDomains  = 0;
683     x->q.TimeoutQuestion      = 0;
684     x->q.WakeOnResolve        = 0;
685     x->q.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
686     x->q.ProxyQuestion        = 0;
687     x->q.pid                  = mDNSPlatformGetPID();
688     x->q.QuestionCallback     = DNSServiceQueryRecordResponse;
689     x->q.QuestionContext      = x;
690 
691     err = mDNS_StartQuery(&mDNSStorage, &x->q);
692     if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
693 
694     // Succeeded: Wrap up and return
695     *sdRef = (DNSServiceRef)x;
696     return(mStatus_NoError);
697 
698 fail:
699     LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err);
700     return(err);
701 }
702 
703 //*************************************************************************************************************
704 // DNSServiceGetAddrInfo
705 //
706 
DNSServiceGetAddrInfoDispose(mDNS_DirectOP * op)707 static void DNSServiceGetAddrInfoDispose(mDNS_DirectOP *op)
708 {
709     mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)op;
710     if (x->a.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->a);
711     if (x->aaaa.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->aaaa);
712     mDNSPlatformMemFree(x);
713 }
714 
DNSServiceGetAddrInfoResponse(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result addRecord)715 mDNSlocal void DNSServiceGetAddrInfoResponse(mDNS *const m, DNSQuestion *question,
716                                              const ResourceRecord *const answer, QC_result addRecord)
717 {
718     mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)question->QuestionContext;
719     char fullname[MAX_ESCAPED_DOMAIN_NAME];
720 
721     struct sockaddr_storage sas;
722 	struct sockaddr_in *sin = (struct sockaddr_in *)&sas;
723 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sas;
724     void *sa_ap = mDNSNULL;
725     int sa_as = 0;
726     mStatus err = mStatus_NoError;
727 
728     (void)m;    // Unused
729 
730 	mDNSPlatformMemZero(&sas, sizeof sas);
731 
732     ConvertDomainNameToCString(answer->name, fullname);
733 
734     if (addRecord == QC_suppressed || answer->RecordType == kDNSRecordTypePacketNegative)
735     {
736         err = mStatus_NoSuchRecord;
737     }
738 
739     // There are three checks here for bad data: class != IN, RRTYPE not in {A,AAAA} and wrong length.
740     // None of these should be possible, because the cache code wouldn't cache malformed data and wouldn't
741     // return records we didn't ask for, but it doesn't hurt to check.
742     if (answer->rrclass != kDNSServiceClass_IN)
743     {
744         LogMsg("DNSServiceGetAddrInfoResponse: response of class %d received, which is bogus", answer->rrclass);
745     totally_invalid:
746         if (x->a.ThisQInterval >= 0)
747         {
748             sin->sin_family = AF_INET;
749 #ifndef NOT_HAVE_SA_LEN
750             sin->sin_len = sizeof *sin;
751 #endif
752             x->callback((DNSServiceRef)x, 0, x->interfaceIndex, kDNSServiceErr_Invalid, fullname,
753                         (const struct sockaddr *)&sas, 0, x->context);
754         }
755         if (x->aaaa.ThisQInterval >= 0)
756         {
757             sin6->sin6_family = AF_INET6;
758 #ifndef NOT_HAVE_SA_LEN
759             sin6->sin6_len = sizeof *sin6;
760 #endif
761             x->callback((DNSServiceRef)x, 0, x->interfaceIndex, kDNSServiceErr_Invalid, fullname,
762                         (const struct sockaddr *)&sas, 0, x->context);
763         }
764         return;
765     }
766     else if (answer->rrtype == kDNSServiceType_A)
767     {
768         sin->sin_family = AF_INET;
769 #ifndef NOT_HAVE_SA_LEN
770         sin->sin_len = sizeof *sin;
771 #endif
772         sa_ap = &sin->sin_addr;
773         sa_as = sizeof sin->sin_addr.s_addr;
774     }
775     else if (answer->rrtype == kDNSServiceType_AAAA)
776     {
777         sin6->sin6_family = AF_INET6;
778 #ifndef NOT_HAVE_SA_LEN
779         sin6->sin6_len = sizeof *sin6;
780 #endif
781         sa_ap = &sin6->sin6_addr;
782         sa_as = sizeof sin6->sin6_addr.s6_addr;
783     }
784     else
785     {
786         LogMsg("DNSServiceGetAddrInfoResponse: response of type %d received, which is bogus", answer->rrtype);
787         goto totally_invalid;
788     }
789 
790     if (err == kDNSServiceErr_NoError && sa_ap != mDNSNULL)
791     {
792         if (err == mStatus_NoError)
793         {
794             if (answer->rdlength == sa_as)
795             {
796                 mDNSPlatformMemCopy(sa_ap, answer->rdata->u.data, answer->rdlength);
797             }
798             else
799             {
800                 LogMsg("DNSServiceGetAddrInfoResponse: %s rrtype with length %d received",
801                        answer->rrtype == kDNSServiceType_A ? "A" : "AAAA", answer->rdlength);
802                 goto totally_invalid;
803             }
804         }
805     }
806 
807     x->callback((DNSServiceRef)x, addRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, x->interfaceIndex, err,
808                 fullname, (const struct sockaddr *)&sas, answer->rroriginalttl, x->context);
809 }
810 
DNSServiceGetAddrInfo(DNSServiceRef * outRef,DNSServiceFlags inFlags,uint32_t inInterfaceIndex,DNSServiceProtocol inProtocol,const char * inHostName,DNSServiceGetAddrInfoReply inCallback,void * inContext)811 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo(
812     DNSServiceRef             *outRef,
813     DNSServiceFlags            inFlags,
814     uint32_t                   inInterfaceIndex,
815     DNSServiceProtocol         inProtocol,
816     const char                *inHostName,
817     DNSServiceGetAddrInfoReply inCallback,
818     void                      *inContext )
819 {
820     const char                *errormsg = "Unknown";
821     DNSServiceErrorType        err;
822     mDNS_DirectOP_GetAddrInfo *x;
823 
824     // Allocate memory, and handle failure
825     x = (mDNS_DirectOP_GetAddrInfo *) mDNSPlatformMemAllocateClear(sizeof(*x));
826     if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
827 
828     // Set up object
829     x->disposefn      = DNSServiceGetAddrInfoDispose;
830     x->callback       = inCallback;
831     x->context        = inContext;
832     x->interfaceIndex = inInterfaceIndex;
833 
834     // Validate and default the protocols.
835     if ((inProtocol & ~(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6)) != 0)
836     {
837         err = mStatus_BadParamErr;
838         errormsg = "Unsupported protocol";
839         goto fail;
840     }
841     // In theory this API checks to see if we have a routable IPv6 address, but
842     if ((inProtocol & (kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6)) == 0)
843     {
844         inProtocol = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6;
845         inFlags |= kDNSServiceFlagsSuppressUnusable;
846     }
847 
848     x->a.ThisQInterval        = -1;      // So we know whether to cancel this question
849     x->a.InterfaceID          = DNSServiceInterfaceIndexToID(inInterfaceIndex, &inFlags);
850     x->a.flags                = inFlags;
851     MakeDomainNameFromDNSNameString(&x->a.qname, inHostName);
852     x->a.qtype                = kDNSType_A;
853     x->a.qclass               = kDNSClass_IN;
854     x->a.LongLived            = (inFlags & kDNSServiceFlagsLongLivedQuery) != 0;
855     x->a.ExpectUnique         = mDNSfalse;
856     x->a.ForceMCast           = (inFlags & kDNSServiceFlagsForceMulticast) != 0;
857     x->a.ReturnIntermed       = (inFlags & kDNSServiceFlagsReturnIntermediates) != 0;
858     x->a.SuppressUnusable     = (inFlags & kDNSServiceFlagsSuppressUnusable) != 0;
859     x->a.AppendSearchDomains  = 0;
860     x->a.TimeoutQuestion      = 0;
861     x->a.WakeOnResolve        = 0;
862     x->a.UseBackgroundTraffic = (inFlags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
863     x->a.ProxyQuestion        = 0;
864     x->a.pid                  = mDNSPlatformGetPID();
865     x->a.QuestionCallback     = DNSServiceGetAddrInfoResponse;
866     x->a.QuestionContext      = x;
867 
868 	x->aaaa = x->a;
869 	x->aaaa.qtype = kDNSType_AAAA;
870 
871     if (inProtocol & kDNSServiceProtocol_IPv4)
872     {
873         err = mDNS_StartQuery(&mDNSStorage, &x->a);
874         if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
875     }
876     if (inProtocol & kDNSServiceProtocol_IPv6)
877     {
878         err = mDNS_StartQuery(&mDNSStorage, &x->aaaa);
879         if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
880     }
881 
882     *outRef = (DNSServiceRef)x;
883     return(mStatus_NoError);
884 
885 fail:
886     LogMsg("DNSServiceGetAddrInfo(\"%s\", %d) failed: %s (%ld)", inHostName, inProtocol, errormsg, err);
887     return(err);
888 }
889 
890 //*************************************************************************************************************
891 // DNSServiceReconfirmRecord
892 
893 // Not yet implemented, so don't include in stub library
894 // We DO include it in the actual Extension, so that if a later client compiled to use this
895 // is run against this Extension, it will get a reasonable error code instead of just
896 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
897 #if !MDNS_BUILDINGSTUBLIBRARY
DNSServiceReconfirmRecord(DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata)898 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
899 (
900     DNSServiceFlags flags,
901     uint32_t interfaceIndex,
902     const char                         *fullname,
903     uint16_t rrtype,
904     uint16_t rrclass,
905     uint16_t rdlen,
906     const void                         *rdata
907 )
908 {
909     (void)flags;            // Unused
910     (void)interfaceIndex;   // Unused
911     (void)fullname;         // Unused
912     (void)rrtype;           // Unused
913     (void)rrclass;          // Unused
914     (void)rdlen;            // Unused
915     (void)rdata;            // Unused
916     return(kDNSServiceErr_Unsupported);
917 }
918 
919 #endif // !MDNS_BUILDINGSTUBLIBRARY
920 
921 // Local Variables:
922 // mode: C
923 // tab-width: 4
924 // c-file-style: "bsd"
925 // c-basic-offset: 4
926 // fill-column: 108
927 // indent-tabs-mode: nil
928 // End:
929