2 * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
19 #include "DNSCommon.h"
20 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
21 #include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
22 #include "dns_sd_internal.h"
23 #include "uds_daemon.h"
25 #include "mdns_powerlog.h"
27 D2DStatus
D2DInitialize(CFRunLoopRef runLoop
, D2DServiceCallback serviceCallback
, void* userData
) __attribute__((weak_import
));
28 D2DStatus
D2DRetain(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
29 D2DStatus
D2DStopAdvertisingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
30 D2DStatus
D2DRelease(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
31 D2DStatus
D2DStartAdvertisingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
32 D2DStatus
D2DStartBrowsingForKeyOnTransport(const Byte
*key
, const size_t keySize
, D2DTransportType transport
) __attribute__((weak_import
));
33 D2DStatus
D2DStopBrowsingForKeyOnTransport(const Byte
*key
, const size_t keySize
, D2DTransportType transport
) __attribute__((weak_import
));
34 void D2DStartResolvingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
35 void D2DStopResolvingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
36 D2DStatus
D2DTerminate(void) __attribute__((weak_import
));
38 #pragma mark - D2D Support
40 mDNSexport
void D2D_start_advertising_interface(NetworkInterfaceInfo
*interface
)
42 // AWDL wants the address and reverse address PTR record communicated
43 // via the D2D interface layer.
44 if (interface
->InterfaceID
== AWDLInterfaceID
)
46 // only log if we have a valid record to start advertising
47 if (interface
->RR_A
.resrec
.RecordType
|| interface
->RR_PTR
.resrec
.RecordType
)
48 LogInfo("D2D_start_advertising_interface: %s", interface
->ifname
);
50 if (interface
->RR_A
.resrec
.RecordType
)
51 external_start_advertising_service(&interface
->RR_A
.resrec
, 0, 0);
52 if (interface
->RR_PTR
.resrec
.RecordType
)
53 external_start_advertising_service(&interface
->RR_PTR
.resrec
, 0, 0);
57 mDNSexport
void D2D_stop_advertising_interface(NetworkInterfaceInfo
*interface
)
59 if (interface
->InterfaceID
== AWDLInterfaceID
)
61 // only log if we have a valid record to stop advertising
62 if (interface
->RR_A
.resrec
.RecordType
|| interface
->RR_PTR
.resrec
.RecordType
)
63 LogInfo("D2D_stop_advertising_interface: %s", interface
->ifname
);
65 if (interface
->RR_A
.resrec
.RecordType
)
66 external_stop_advertising_service(&interface
->RR_A
.resrec
, 0, 0);
67 if (interface
->RR_PTR
.resrec
.RecordType
)
68 external_stop_advertising_service(&interface
->RR_PTR
.resrec
, 0, 0);
72 // If record would have been advertised to the D2D plugin layer, stop that advertisement.
73 mDNSexport
void D2D_stop_advertising_record(AuthRecord
*ar
)
75 DNSServiceFlags flags
= deriveD2DFlagsFromAuthRecType(ar
->ARType
);
76 if (callExternalHelpers(ar
->resrec
.InterfaceID
, ar
->resrec
.name
, flags
))
78 external_stop_advertising_service(&ar
->resrec
, flags
, 0);
82 // If record should be advertised to the D2D plugin layer, start that advertisement.
83 mDNSexport
void D2D_start_advertising_record(AuthRecord
*ar
)
85 DNSServiceFlags flags
= deriveD2DFlagsFromAuthRecType(ar
->ARType
);
86 if (callExternalHelpers(ar
->resrec
.InterfaceID
, ar
->resrec
.name
, flags
))
88 external_start_advertising_service(&ar
->resrec
, flags
, 0);
92 // Name compression items for fake packet version number 1
93 static const mDNSu8 compression_packet_v1
= 0x01;
95 static DNSMessage compression_base_msg
= { { {{0}}, {{0}}, 2, 0, 0, 0 }, "\x04_tcp\x05local\x00\x00\x0C\x00\x01\x04_udp\xC0\x11\x00\x0C\x00\x01" };
96 static mDNSu8
*const compression_limit
= (mDNSu8
*) &compression_base_msg
+ sizeof(DNSMessage
);
97 static mDNSu8
*const compression_lhs
= (mDNSu8
*const) compression_base_msg
.data
+ 27;
99 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
101 typedef struct D2DRecordListElem
103 struct D2DRecordListElem
*next
;
104 D2DServiceInstance instanceHandle
;
105 D2DTransportType transportType
;
106 AuthRecord ar
; // must be last in the structure to accomodate extra space
107 // allocated for large records.
110 static D2DRecordListElem
*D2DRecords
= NULL
; // List of records returned with D2DServiceFound events
112 typedef struct D2DBrowseListElem
114 struct D2DBrowseListElem
*next
;
117 unsigned int refCount
;
120 D2DBrowseListElem
* D2DBrowseList
= NULL
;
122 mDNSlocal mDNSu8
*putVal16(mDNSu8
*ptr
, mDNSu16 val
)
124 ptr
[0] = (mDNSu8
)((val
>> 8 ) & 0xFF);
125 ptr
[1] = (mDNSu8
)((val
) & 0xFF);
126 return ptr
+ sizeof(mDNSu16
);
129 mDNSlocal mDNSu8
*putVal32(mDNSu8
*ptr
, mDNSu32 val
)
131 ptr
[0] = (mDNSu8
)((val
>> 24) & 0xFF);
132 ptr
[1] = (mDNSu8
)((val
>> 16) & 0xFF);
133 ptr
[2] = (mDNSu8
)((val
>> 8) & 0xFF);
134 ptr
[3] = (mDNSu8
)((val
) & 0xFF);
135 return ptr
+ sizeof(mDNSu32
);
138 mDNSlocal
void DomainnameToLower(const domainname
* const in
, domainname
* const out
)
140 const mDNSu8
* const start
= (const mDNSu8
* const)in
;
141 mDNSu8
*ptr
= (mDNSu8
*)start
;
145 out
->c
[ptr
-start
] = *ptr
;
147 for (; c
; c
--,ptr
++) out
->c
[ptr
-start
] = mDNSIsUpperCase(*ptr
) ? (*ptr
- 'A' + 'a') : *ptr
;
149 out
->c
[ptr
-start
] = *ptr
;
152 mDNSlocal mDNSu8
* DNSNameCompressionBuildLHS(const domainname
* typeDomain
, DNS_TypeValues qtype
)
154 mDNSu8
*ptr
= putDomainNameAsLabels(&compression_base_msg
, compression_lhs
, compression_limit
, typeDomain
);
155 if (!ptr
) return ptr
;
156 *ptr
= (qtype
>> 8) & 0xff;
160 *ptr
= compression_packet_v1
;
164 mDNSlocal mDNSu8
* DNSNameCompressionBuildRHS(mDNSu8
*start
, const ResourceRecord
*const resourceRecord
)
166 return putRData(&compression_base_msg
, start
, compression_limit
, resourceRecord
);
169 mDNSlocal
void PrintHelper(const char *const tag
, mDNSu8
*lhs
, mDNSu16 lhs_len
, mDNSu8
*rhs
, mDNSu16 rhs_len
)
171 if (mDNS_LoggingEnabled
)
173 LogDebug("%s: LHS: (%d bytes) %.*H", tag
, lhs_len
, lhs_len
, lhs
);
174 if (rhs
) LogDebug("%s: RHS: (%d bytes) %.*H", tag
, rhs_len
, rhs_len
, rhs
);
178 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
181 if (result
== mStatus_MemFree
)
183 D2DRecordListElem
**ptr
= &D2DRecords
;
184 D2DRecordListElem
*tmp
;
185 while (*ptr
&& &(*ptr
)->ar
!= rr
) ptr
= &(*ptr
)->next
;
186 if (!*ptr
) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m
, rr
)); return; }
187 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m
, rr
));
190 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
191 mDNSPlatformMemFree(tmp
);
195 mDNSexport
void external_connection_release(const domainname
*instance
)
198 D2DRecordListElem
*ptr
= D2DRecords
;
200 for ( ; ptr
; ptr
= ptr
->next
)
202 if ((ptr
->ar
.resrec
.rrtype
== kDNSServiceType_PTR
) &&
203 SameDomainName(&ptr
->ar
.rdatastorage
.u
.name
, instance
))
205 LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d",
206 ptr
->instanceHandle
, ptr
->transportType
);
207 if (D2DRelease
) D2DRelease(ptr
->instanceHandle
, ptr
->transportType
);
212 mDNSlocal
void xD2DClearCache(const domainname
*regType
, DNS_TypeValues qtype
)
214 D2DRecordListElem
*ptr
= D2DRecords
;
215 for ( ; ptr
; ptr
= ptr
->next
)
217 if ((ptr
->ar
.resrec
.rrtype
== qtype
) && SameDomainName(&ptr
->ar
.namestorage
, regType
))
219 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage
, &ptr
->ar
));
220 mDNS_Deregister(&mDNSStorage
, &ptr
->ar
);
225 mDNSlocal D2DBrowseListElem
** D2DFindInBrowseList(const domainname
*const name
, mDNSu16 type
)
227 D2DBrowseListElem
**ptr
= &D2DBrowseList
;
229 for ( ; *ptr
; ptr
= &(*ptr
)->next
)
230 if ((*ptr
)->type
== type
&& SameDomainName(&(*ptr
)->name
, name
))
236 mDNSlocal
unsigned int D2DBrowseListRefCount(const domainname
*const name
, mDNSu16 type
)
238 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
239 return *ptr
? (*ptr
)->refCount
: 0;
242 mDNSlocal
void D2DBrowseListRetain(const domainname
*const name
, mDNSu16 type
)
244 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
248 *ptr
= (D2DBrowseListElem
*) mDNSPlatformMemAllocateClear(sizeof(**ptr
));
250 AssignDomainName(&(*ptr
)->name
, name
);
252 (*ptr
)->refCount
+= 1;
254 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
257 // Returns true if found in list, false otherwise
258 mDNSlocal
bool D2DBrowseListRelease(const domainname
*const name
, mDNSu16 type
)
260 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
262 if (!*ptr
) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name
->c
, DNSTypeName(type
)); return false; }
264 (*ptr
)->refCount
-= 1;
266 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
268 if (!(*ptr
)->refCount
)
270 D2DBrowseListElem
*tmp
= *ptr
;
272 mDNSPlatformMemFree(tmp
);
277 mDNSlocal mStatus
xD2DParse(const mDNSu8
* const lhs
, const mDNSu16 lhs_len
, const mDNSu8
* const rhs
, const mDNSu16 rhs_len
, D2DRecordListElem
**D2DListp
)
279 mDNS
*const m
= &mDNSStorage
;
281 // Sanity check that key array (lhs) has one domain name, followed by the record type and single byte D2D
282 // plugin protocol version number.
283 // Note, we don't have a DNSMessage pointer at this point, so just pass in the lhs value as the lower bound
284 // of the input bytes we are processing. skipDomainName() does not try to follow name compression pointers,
285 // so it is safe to pass it the key byte array since it will stop parsing the DNS name and return a pointer
286 // to the byte after the first name compression pointer it encounters.
287 const mDNSu8
*keyp
= skipDomainName((const DNSMessage
*const) lhs
, lhs
, lhs
+ lhs_len
);
289 // There should be 3 bytes remaining in a valid key,
290 // two for the DNS record type, and one for the D2D protocol version number.
291 if (keyp
== NULL
|| (keyp
+ 3 != (lhs
+ lhs_len
)))
293 LogInfo("xD2DParse: Could not parse DNS name in key");
294 return mStatus_Incompatible
;
296 keyp
+= 2; // point to D2D compression packet format version byte
297 if (*keyp
!= compression_packet_v1
)
299 LogInfo("xD2DParse: Invalid D2D packet version: %d", *keyp
);
300 return mStatus_Incompatible
;
303 if (mDNS_LoggingEnabled
)
305 const int len
= (int)(compression_lhs
- (mDNSu8
*)&compression_base_msg
);
306 LogInfo("xD2DParse: Static Bytes: (%d bytes) %.*H", len
, len
, &compression_base_msg
);
309 mDNSu8
*ptr
= compression_lhs
; // pointer to the end of our fake packet
311 // Check to make sure we're not going to go past the end of the DNSMessage data
312 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
313 if (ptr
+ lhs_len
- 7 + rhs_len
>= compression_limit
) return mStatus_NoMemoryErr
;
315 // Copy the LHS onto our fake wire packet
316 mDNSPlatformMemCopy(ptr
, lhs
, lhs_len
);
319 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
320 if (*ptr
!= compression_packet_v1
) return mStatus_Incompatible
;
322 // two bytes of CLASS
323 ptr
= putVal16(ptr
, kDNSClass_IN
| kDNSClass_UniqueRRSet
);
326 ptr
= putVal32(ptr
, 120);
328 // Copy the RHS length into the RDLENGTH of our fake wire packet
329 ptr
= putVal16(ptr
, rhs_len
);
331 // Copy the RHS onto our fake wire packet
332 mDNSPlatformMemCopy(ptr
, rhs
, rhs_len
);
335 if (mDNS_LoggingEnabled
)
337 const int len
= (int)(ptr
- compression_lhs
);
338 LogInfo("xD2DParse: Our Bytes (%d bytes): %.*H", len
, len
, compression_lhs
);
341 ptr
= (mDNSu8
*) GetLargeResourceRecord(m
, &compression_base_msg
, compression_lhs
, ptr
, mDNSInterface_Any
, kDNSRecordTypePacketAns
, &m
->rec
);
342 if (!ptr
|| m
->rec
.r
.resrec
.RecordType
== kDNSRecordTypePacketNegative
)
344 LogMsg("xD2DParse: failed to get large RR");
345 m
->rec
.r
.resrec
.RecordType
= 0;
346 return mStatus_UnknownErr
;
350 LogInfo("xD2DParse: got rr: %s", CRDisplayString(m
, &m
->rec
.r
));
353 *D2DListp
= (D2DRecordListElem
*) mDNSPlatformMemAllocateClear(sizeof(D2DRecordListElem
) + (m
->rec
.r
.resrec
.rdlength
<= sizeof(RDataBody
) ? 0 : m
->rec
.r
.resrec
.rdlength
- sizeof(RDataBody
)));
354 if (!*D2DListp
) return mStatus_NoMemoryErr
;
356 AuthRecord
*rr
= &(*D2DListp
)->ar
;
357 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_P2P
, m
->rec
.r
.resrec
.rrtype
, 7200, kDNSRecordTypeShared
, AuthRecordP2P
, FreeD2DARElemCallback
, NULL
);
358 AssignDomainName(&rr
->namestorage
, &m
->rec
.namestorage
);
359 rr
->resrec
.rdlength
= m
->rec
.r
.resrec
.rdlength
;
360 rr
->resrec
.rdata
->MaxRDLength
= m
->rec
.r
.resrec
.rdlength
;
361 mDNSPlatformMemCopy(rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
);
362 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
363 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
365 m
->rec
.r
.resrec
.RecordType
= 0; // Mark m->rec as no longer in use
367 return mStatus_NoError
;
370 mDNSexport
void xD2DAddToCache(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
372 mDNS
*const m
= &mDNSStorage
;
373 if (result
== kD2DSuccess
)
375 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
378 D2DRecordListElem
*ptr
= NULL
;
380 err
= xD2DParse((const mDNSu8
* const)key
, (const mDNSu16
)keySize
, (const mDNSu8
* const)value
, (const mDNSu16
)valueSize
, &ptr
);
383 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err
);
384 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
386 mDNSPlatformMemFree(ptr
);
390 #if ENABLE_BLE_TRIGGERED_BONJOUR
391 // If the record was created based on a BLE beacon, update the interface index to indicate
392 // this and thus match BLE specific queries.
393 if (transportType
== D2DBLETransport
)
394 ptr
->ar
.resrec
.InterfaceID
= mDNSInterface_BLE
;
395 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
397 err
= mDNS_Register(m
, &ptr
->ar
);
400 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err
, ARDisplayString(m
, &ptr
->ar
));
401 mDNSPlatformMemFree(ptr
);
405 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m
, &ptr
->ar
));
406 ptr
->instanceHandle
= instanceHandle
;
407 ptr
->transportType
= transportType
;
408 ptr
->next
= D2DRecords
;
412 LogMsg("xD2DAddToCache: Unexpected result %d", result
);
415 mDNSlocal D2DRecordListElem
* xD2DFindInList(const Byte
*const key
, const size_t keySize
, const Byte
*const value
, const size_t valueSize
)
417 D2DRecordListElem
*ptr
= D2DRecords
;
418 D2DRecordListElem
*arptr
= NULL
;
420 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL
; }
422 mStatus err
= xD2DParse((const mDNSu8
*const)key
, (const mDNSu16
)keySize
, (const mDNSu8
*const)value
, (const mDNSu16
)valueSize
, &arptr
);
425 LogMsg("xD2DFindInList: xD2DParse returned error: %d", err
);
426 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
428 mDNSPlatformMemFree(arptr
);
434 if (IdenticalResourceRecord(&arptr
->ar
.resrec
, &ptr
->ar
.resrec
)) break;
438 if (!ptr
) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(&mDNSStorage
, &arptr
->ar
));
439 mDNSPlatformMemFree(arptr
);
443 mDNSexport
void xD2DRemoveFromCache(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
445 (void)transportType
; // We don't care about this, yet.
446 (void)instanceHandle
; // We don't care about this, yet.
448 if (result
== kD2DSuccess
)
450 D2DRecordListElem
*ptr
= xD2DFindInList(key
, keySize
, value
, valueSize
);
453 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(&mDNSStorage
, &ptr
->ar
));
454 mDNS_Deregister(&mDNSStorage
, &ptr
->ar
);
458 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result
);
461 mDNSlocal
void xD2DServiceResolved(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
468 if (result
== kD2DSuccess
)
470 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle
);
471 if (D2DRetain
) D2DRetain(instanceHandle
, transportType
);
473 else LogMsg("xD2DServiceResolved: Unexpected result %d", result
);
476 mDNSlocal
void xD2DRetainHappened(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
478 (void)instanceHandle
;
485 if (result
== kD2DSuccess
) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle
);
486 else LogMsg("xD2DRetainHappened: Unexpected result %d", result
);
489 mDNSlocal
void xD2DReleaseHappened(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
491 (void)instanceHandle
;
498 if (result
== kD2DSuccess
) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle
);
499 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result
);
502 mDNSlocal
void xD2DServiceCallback(D2DServiceEvent event
, D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
, void *userData
)
504 const char *eventString
= "unknown";
508 if (keySize
> 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize
);
509 if (valueSize
> 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize
);
513 case D2DServiceFound
:
514 eventString
= "D2DServiceFound";
517 eventString
= "D2DServiceLost";
519 case D2DServiceResolved
:
520 eventString
= "D2DServiceResolved";
522 case D2DServiceRetained
:
523 eventString
= "D2DServiceRetained";
525 case D2DServiceReleased
:
526 eventString
= "D2DServiceReleased";
532 LogInfo("xD2DServiceCallback: event=%s result=%d instanceHandle=%p transportType=%d LHS=%p (%u) RHS=%p (%u) userData=%p", eventString
, result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
, userData
);
533 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
537 case D2DServiceFound
:
538 xD2DAddToCache(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
541 xD2DRemoveFromCache(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
543 case D2DServiceResolved
:
544 xD2DServiceResolved(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
546 case D2DServiceRetained
:
547 xD2DRetainHappened(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
549 case D2DServiceReleased
:
550 xD2DReleaseHappened(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
556 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
557 KQueueUnlock("xD2DServiceCallback");
560 // Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
562 // When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
563 // will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
564 // If the return value is not D2DTransportMax, excludedTransportType is undefined.
566 mDNSlocal D2DTransportType
xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID
, DNSServiceFlags flags
, D2DTransportType
* excludedTransportType
)
568 NetworkInterfaceInfoOSX
*info
;
570 // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
571 *excludedTransportType
= D2DAWDLTransport
;
573 // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
574 if ((flags
& kDNSServiceFlagsIncludeP2P
) && (flags
& kDNSServiceFlagsIncludeAWDL
))
576 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
577 *excludedTransportType
= D2DTransportMax
;
578 return D2DTransportMax
;
580 // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
581 else if (flags
& kDNSServiceFlagsIncludeP2P
)
583 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
584 return D2DTransportMax
;
586 // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
587 else if (flags
& kDNSServiceFlagsIncludeAWDL
)
589 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
590 return D2DAWDLTransport
;
593 if (InterfaceID
== mDNSInterface_P2P
)
595 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
596 return D2DTransportMax
;
599 // Compare to cached AWDL interface ID.
600 if (AWDLInterfaceID
&& (InterfaceID
== AWDLInterfaceID
))
602 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID
);
603 return D2DAWDLTransport
;
606 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
609 LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID
);
610 return D2DTransportMax
;
613 // Recognize AirDrop specific p2p* interface based on interface name.
614 if (strncmp(info
->ifinfo
.ifname
, "p2p", 3) == 0)
616 LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID
);
617 return D2DWifiPeerToPeerTransport
;
620 // Currently there is no way to identify Bluetooth interface by name,
621 // since they use "en*" based name strings.
623 LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID
);
624 return D2DTransportMax
;
627 mDNSexport
void external_start_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
, pid_t clientPID
)
629 #if ENABLE_BLE_TRIGGERED_BONJOUR
630 // BLE support currently not handled by a D2D plugin
631 if (applyToBLE(InterfaceID
, flags
))
635 DomainnameToLower(typeDomain
, &lower
);
636 // pass in the key and keySize
637 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
638 start_BLE_browse(InterfaceID
, &lower
, qtype
, flags
, compression_lhs
, end
- compression_lhs
);
641 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
642 internal_start_browsing_for_service(InterfaceID
, typeDomain
, qtype
, flags
, clientPID
);
645 mDNSexport
void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
, pid_t clientPID
)
649 DomainnameToLower(typeDomain
, &lower
);
651 if (!D2DBrowseListRefCount(&lower
, qtype
))
653 D2DTransportType transportType
, excludedTransport
;
655 LogInfo("%s: Starting browse for: %##s %s", __func__
, lower
.c
, DNSTypeName(qtype
));
656 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
657 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
659 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
660 if (transportType
== D2DTransportMax
)
663 for (i
= 0; i
< D2DTransportMax
; i
++)
665 if (i
== excludedTransport
) continue;
666 if (D2DStartBrowsingForKeyOnTransport
)
668 if (i
== D2DAWDLTransport
)
670 mdns_powerlog_awdl_browse_start(typeDomain
->c
, qtype
, clientPID
);
672 D2DStartBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, i
);
678 if (D2DStartBrowsingForKeyOnTransport
)
680 if (transportType
== D2DAWDLTransport
)
682 mdns_powerlog_awdl_browse_start(typeDomain
->c
, qtype
, clientPID
);
684 D2DStartBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, transportType
);
688 D2DBrowseListRetain(&lower
, qtype
);
691 mDNSexport
void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
, pid_t clientPID
)
693 #if ENABLE_BLE_TRIGGERED_BONJOUR
694 // BLE support currently not handled by a D2D plugin
695 if (applyToBLE(InterfaceID
, flags
))
699 // If this is the last instance of this browse, clear any cached records recieved for it.
700 // We are not guaranteed to get a D2DServiceLost event for all key, value pairs cached over BLE.
701 DomainnameToLower(typeDomain
, &lower
);
702 if (stop_BLE_browse(InterfaceID
, &lower
, qtype
, flags
))
703 xD2DClearCache(&lower
, qtype
);
706 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
707 internal_stop_browsing_for_service(InterfaceID
, typeDomain
, qtype
, flags
, clientPID
);
710 mDNSexport
void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
, pid_t clientPID
)
714 DomainnameToLower(typeDomain
, &lower
);
716 // If found in list and this is the last reference to this browse, remove the key from the D2D plugins.
717 if (D2DBrowseListRelease(&lower
, qtype
) && !D2DBrowseListRefCount(&lower
, qtype
))
719 D2DTransportType transportType
, excludedTransport
;
721 LogInfo("%s: Stopping browse for: %##s %s", __func__
, lower
.c
, DNSTypeName(qtype
));
722 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
723 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
725 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
726 if (transportType
== D2DTransportMax
)
729 for (i
= 0; i
< D2DTransportMax
; i
++)
731 if (i
== excludedTransport
) continue;
732 if (D2DStopBrowsingForKeyOnTransport
)
734 D2DStopBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, i
);
735 if (i
== D2DAWDLTransport
)
737 mdns_powerlog_awdl_browse_stop(typeDomain
->c
, qtype
, clientPID
);
744 if (D2DStopBrowsingForKeyOnTransport
)
746 D2DStopBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, transportType
);
747 if (transportType
== D2DAWDLTransport
)
749 mdns_powerlog_awdl_browse_stop(typeDomain
->c
, qtype
, clientPID
);
754 // The D2D driver may not generate the D2DServiceLost event for this key after
755 // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
757 xD2DClearCache(&lower
, qtype
);
761 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
, pid_t clientPID
)
763 #if ENABLE_BLE_TRIGGERED_BONJOUR
764 if (applyToBLE(resourceRecord
->InterfaceID
, flags
))
768 DomainnameToLower(resourceRecord
->name
, &lower
);
769 start_BLE_advertise(resourceRecord
, &lower
, resourceRecord
->rrtype
, flags
);
772 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
773 internal_start_advertising_service(resourceRecord
, flags
, clientPID
);
776 mDNSexport
void internal_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
, pid_t clientPID
)
781 D2DTransportType transportType
, excludedTransport
;
782 DomainnameToLower(resourceRecord
->name
, &lower
);
784 LogInfo("%s: %s", __func__
, RRDisplayString(&mDNSStorage
, resourceRecord
));
786 // For SRV records, update packet filter if p2p interface already exists, otherwise,
787 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
788 if (resourceRecord
->rrtype
== kDNSType_SRV
)
789 mDNSUpdatePacketFilter(NULL
);
791 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
792 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
793 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
795 transportType
= xD2DInterfaceToTransportType(resourceRecord
->InterfaceID
, flags
, & excludedTransport
);
796 if (transportType
== D2DTransportMax
)
799 for (i
= 0; i
< D2DTransportMax
; i
++)
801 if (i
== excludedTransport
) continue;
802 if (D2DStartAdvertisingPairOnTransport
)
804 if (i
== D2DAWDLTransport
)
806 mdns_powerlog_awdl_advertise_start(lower
.c
, resourceRecord
->rrtype
, clientPID
);
808 D2DStartAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
814 if (D2DStartAdvertisingPairOnTransport
)
816 if (transportType
== D2DAWDLTransport
)
818 mdns_powerlog_awdl_advertise_start(lower
.c
, resourceRecord
->rrtype
, clientPID
);
820 D2DStartAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
825 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
, pid_t clientPID
)
827 #if ENABLE_BLE_TRIGGERED_BONJOUR
828 // BLE support currently not handled by a D2D plugin
829 if (applyToBLE(resourceRecord
->InterfaceID
, flags
))
833 DomainnameToLower(resourceRecord
->name
, &lower
);
834 stop_BLE_advertise(&lower
, resourceRecord
->rrtype
, flags
);
837 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
838 internal_stop_advertising_service(resourceRecord
, flags
, clientPID
);
841 mDNSexport
void internal_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
, pid_t clientPID
)
846 D2DTransportType transportType
, excludedTransport
;
847 DomainnameToLower(resourceRecord
->name
, &lower
);
849 LogInfo("%s: %s", __func__
, RRDisplayString(&mDNSStorage
, resourceRecord
));
851 // For SRV records, update packet filter if p2p interface already exists, otherwise,
852 // For SRV records, update packet filter to to remove this port from list
853 if (resourceRecord
->rrtype
== kDNSType_SRV
)
854 mDNSUpdatePacketFilter(resourceRecord
);
856 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
857 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
858 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
860 transportType
= xD2DInterfaceToTransportType(resourceRecord
->InterfaceID
, flags
, & excludedTransport
);
861 if (transportType
== D2DTransportMax
)
864 for (i
= 0; i
< D2DTransportMax
; i
++)
866 if (i
== excludedTransport
) continue;
867 if (D2DStopAdvertisingPairOnTransport
)
869 D2DStopAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
870 if (i
== D2DAWDLTransport
)
872 mdns_powerlog_awdl_advertise_stop(lower
.c
, resourceRecord
->rrtype
, clientPID
);
879 if (D2DStopAdvertisingPairOnTransport
)
881 D2DStopAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
882 if (transportType
== D2DAWDLTransport
)
884 mdns_powerlog_awdl_advertise_stop(lower
.c
, resourceRecord
->rrtype
, clientPID
);
890 mDNSexport
void external_start_resolving_service(mDNSInterfaceID InterfaceID
, const domainname
*const fqdn
, DNSServiceFlags flags
, pid_t clientPID
)
895 mDNSBool AWDL_used
= false; // whether AWDL was used for this resolve
896 D2DTransportType transportType
, excludedTransport
;
897 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
899 LogInfo("external_start_resolving_service: %##s", fqdn
->c
);
900 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
901 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
902 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
904 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
905 if (transportType
== D2DTransportMax
)
907 // Resolving over all the transports, except for excludedTransport if set.
909 for (i
= 0; i
< D2DTransportMax
; i
++)
911 if (i
== excludedTransport
) continue;
912 if (D2DStartResolvingPairOnTransport
)
914 if (i
== D2DAWDLTransport
)
916 mdns_powerlog_awdl_resolve_start(lower
.c
, kDNSType_PTR
, clientPID
);
918 D2DStartResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
920 if (i
== D2DAWDLTransport
)
926 // Resolving over one specific transport.
927 if (D2DStartResolvingPairOnTransport
)
929 if (transportType
== D2DAWDLTransport
)
931 mdns_powerlog_awdl_resolve_start(lower
.c
, kDNSType_PTR
, clientPID
);
933 D2DStartResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
935 if (transportType
== D2DAWDLTransport
)
939 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
940 // We only want these records going to AWDL, so use AWDLInterfaceID as the
941 // interface and don't set any other flags.
942 if (AWDL_used
&& AWDLInterfaceID
)
944 LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
945 external_start_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_TXT
, 0, clientPID
);
946 external_start_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_SRV
, 0, clientPID
);
950 mDNSexport
void external_stop_resolving_service(mDNSInterfaceID InterfaceID
, const domainname
*const fqdn
, DNSServiceFlags flags
, pid_t clientPID
)
955 mDNSBool AWDL_used
= false; // whether AWDL was used for this resolve
956 D2DTransportType transportType
, excludedTransport
;
957 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
959 LogInfo("external_stop_resolving_service: %##s", fqdn
->c
);
960 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
961 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
962 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
964 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
965 if (transportType
== D2DTransportMax
)
968 for (i
= 0; i
< D2DTransportMax
; i
++)
970 if (i
== excludedTransport
) continue;
971 if (D2DStopResolvingPairOnTransport
)
973 D2DStopResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
974 if (i
== D2DAWDLTransport
)
976 mdns_powerlog_awdl_resolve_stop(lower
.c
, kDNSType_PTR
, clientPID
);
979 if (i
== D2DAWDLTransport
)
985 if (D2DStopResolvingPairOnTransport
)
987 D2DStopResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
988 if (transportType
== D2DAWDLTransport
)
990 mdns_powerlog_awdl_resolve_stop(lower
.c
, kDNSType_PTR
, clientPID
);
993 if (transportType
== D2DAWDLTransport
)
997 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
998 // We only want these records going to AWDL, so use AWDLInterfaceID as the
999 // interface and don't set any other flags.
1000 if (AWDL_used
&& AWDLInterfaceID
)
1002 LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
1003 external_stop_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_TXT
, 0, clientPID
);
1004 external_stop_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_SRV
, 0, clientPID
);
1008 mDNSexport mDNSBool
callExternalHelpers(mDNSInterfaceID InterfaceID
, const domainname
*const domain
, DNSServiceFlags flags
)
1010 // Only call D2D layer routines if request applies to a D2D interface and the domain is "local".
1011 if ( (((InterfaceID
== mDNSInterface_Any
) && (flags
& (kDNSServiceFlagsIncludeP2P
| kDNSServiceFlagsIncludeAWDL
| kDNSServiceFlagsAutoTrigger
)))
1012 || mDNSPlatformInterfaceIsD2D(InterfaceID
) || (InterfaceID
== mDNSInterface_BLE
))
1013 && IsLocalDomain(domain
))
1021 // Used to derive the original D2D specific flags specified by the client in the registration
1022 // when we don't have access to the original flag (kDNSServiceFlags*) values.
1023 mDNSexport mDNSu32
deriveD2DFlagsFromAuthRecType(AuthRecType authRecType
)
1026 if ((authRecType
== AuthRecordAnyIncludeP2P
) || (authRecType
== AuthRecordAnyIncludeAWDLandP2P
))
1027 flags
|= kDNSServiceFlagsIncludeP2P
;
1028 else if ((authRecType
== AuthRecordAnyIncludeAWDL
) || (authRecType
== AuthRecordAnyIncludeAWDLandP2P
))
1029 flags
|= kDNSServiceFlagsIncludeAWDL
;
1033 void initializeD2DPlugins(mDNS
*const m
)
1035 // We only initialize if mDNSCore successfully initialized.
1038 D2DStatus ds
= D2DInitialize(CFRunLoopGetMain(), xD2DServiceCallback
, m
);
1039 if (ds
!= kD2DSuccess
)
1040 LogMsg("D2DInitialiize failed: %d", ds
);
1042 LogMsg("D2DInitialize succeeded");
1046 void terminateD2DPlugins(void)
1050 D2DStatus ds
= D2DTerminate();
1051 if (ds
!= kD2DSuccess
)
1052 LogMsg("D2DTerminate failed: %d", ds
);
1054 LogMsg("D2DTerminate succeeded");
1059 #pragma mark - Unit test support routines
1061 // These unit test support routines are called from unittests/ framework
1062 // and are not compiled for the mDNSResponder runtime code paths.
1064 void D2D_unitTest(void)