2 * Copyright (c) 2002-2019 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"
26 D2DStatus
D2DInitialize(CFRunLoopRef runLoop
, D2DServiceCallback serviceCallback
, void* userData
) __attribute__((weak_import
));
27 D2DStatus
D2DRetain(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
28 D2DStatus
D2DStopAdvertisingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
29 D2DStatus
D2DRelease(D2DServiceInstance instanceHandle
, D2DTransportType transportType
) __attribute__((weak_import
));
30 D2DStatus
D2DStartAdvertisingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
31 D2DStatus
D2DStartBrowsingForKeyOnTransport(const Byte
*key
, const size_t keySize
, D2DTransportType transport
) __attribute__((weak_import
));
32 D2DStatus
D2DStopBrowsingForKeyOnTransport(const Byte
*key
, const size_t keySize
, D2DTransportType transport
) __attribute__((weak_import
));
33 void D2DStartResolvingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
34 void D2DStopResolvingPairOnTransport(const Byte
*key
, const size_t keySize
, const Byte
*value
, const size_t valueSize
, D2DTransportType transport
) __attribute__((weak_import
));
35 D2DStatus
D2DTerminate(void) __attribute__((weak_import
));
37 #pragma mark - D2D Support
39 mDNSexport
void D2D_start_advertising_interface(NetworkInterfaceInfo
*interface
)
41 // AWDL wants the address and reverse address PTR record communicated
42 // via the D2D interface layer.
43 if (interface
->InterfaceID
== AWDLInterfaceID
)
45 // only log if we have a valid record to start advertising
46 if (interface
->RR_A
.resrec
.RecordType
|| interface
->RR_PTR
.resrec
.RecordType
)
47 LogInfo("D2D_start_advertising_interface: %s", interface
->ifname
);
49 if (interface
->RR_A
.resrec
.RecordType
)
50 external_start_advertising_service(&interface
->RR_A
.resrec
, 0);
51 if (interface
->RR_PTR
.resrec
.RecordType
)
52 external_start_advertising_service(&interface
->RR_PTR
.resrec
, 0);
56 mDNSexport
void D2D_stop_advertising_interface(NetworkInterfaceInfo
*interface
)
58 if (interface
->InterfaceID
== AWDLInterfaceID
)
60 // only log if we have a valid record to stop advertising
61 if (interface
->RR_A
.resrec
.RecordType
|| interface
->RR_PTR
.resrec
.RecordType
)
62 LogInfo("D2D_stop_advertising_interface: %s", interface
->ifname
);
64 if (interface
->RR_A
.resrec
.RecordType
)
65 external_stop_advertising_service(&interface
->RR_A
.resrec
, 0);
66 if (interface
->RR_PTR
.resrec
.RecordType
)
67 external_stop_advertising_service(&interface
->RR_PTR
.resrec
, 0);
71 // If record would have been advertised to the D2D plugin layer, stop that advertisement.
72 mDNSexport
void D2D_stop_advertising_record(AuthRecord
*ar
)
74 DNSServiceFlags flags
= deriveD2DFlagsFromAuthRecType(ar
->ARType
);
75 if (callExternalHelpers(ar
->resrec
.InterfaceID
, ar
->resrec
.name
, flags
))
77 external_stop_advertising_service(&ar
->resrec
, flags
);
81 // If record should be advertised to the D2D plugin layer, start that advertisement.
82 mDNSexport
void D2D_start_advertising_record(AuthRecord
*ar
)
84 DNSServiceFlags flags
= deriveD2DFlagsFromAuthRecType(ar
->ARType
);
85 if (callExternalHelpers(ar
->resrec
.InterfaceID
, ar
->resrec
.name
, flags
))
87 external_start_advertising_service(&ar
->resrec
, flags
);
91 // Name compression items for fake packet version number 1
92 static const mDNSu8 compression_packet_v1
= 0x01;
94 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" };
95 static mDNSu8
*const compression_limit
= (mDNSu8
*) &compression_base_msg
+ sizeof(DNSMessage
);
96 static mDNSu8
*const compression_lhs
= (mDNSu8
*const) compression_base_msg
.data
+ 27;
98 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
100 typedef struct D2DRecordListElem
102 struct D2DRecordListElem
*next
;
103 D2DServiceInstance instanceHandle
;
104 D2DTransportType transportType
;
105 AuthRecord ar
; // must be last in the structure to accomodate extra space
106 // allocated for large records.
109 static D2DRecordListElem
*D2DRecords
= NULL
; // List of records returned with D2DServiceFound events
111 typedef struct D2DBrowseListElem
113 struct D2DBrowseListElem
*next
;
116 unsigned int refCount
;
119 D2DBrowseListElem
* D2DBrowseList
= NULL
;
121 mDNSlocal mDNSu8
*putVal16(mDNSu8
*ptr
, mDNSu16 val
)
123 ptr
[0] = (mDNSu8
)((val
>> 8 ) & 0xFF);
124 ptr
[1] = (mDNSu8
)((val
) & 0xFF);
125 return ptr
+ sizeof(mDNSu16
);
128 mDNSlocal mDNSu8
*putVal32(mDNSu8
*ptr
, mDNSu32 val
)
130 ptr
[0] = (mDNSu8
)((val
>> 24) & 0xFF);
131 ptr
[1] = (mDNSu8
)((val
>> 16) & 0xFF);
132 ptr
[2] = (mDNSu8
)((val
>> 8) & 0xFF);
133 ptr
[3] = (mDNSu8
)((val
) & 0xFF);
134 return ptr
+ sizeof(mDNSu32
);
137 mDNSlocal
void DomainnameToLower(const domainname
* const in
, domainname
* const out
)
139 const mDNSu8
* const start
= (const mDNSu8
* const)in
;
140 mDNSu8
*ptr
= (mDNSu8
*)start
;
144 out
->c
[ptr
-start
] = *ptr
;
146 for (; c
; c
--,ptr
++) out
->c
[ptr
-start
] = mDNSIsUpperCase(*ptr
) ? (*ptr
- 'A' + 'a') : *ptr
;
148 out
->c
[ptr
-start
] = *ptr
;
151 mDNSlocal mDNSu8
* DNSNameCompressionBuildLHS(const domainname
* typeDomain
, DNS_TypeValues qtype
)
153 mDNSu8
*ptr
= putDomainNameAsLabels(&compression_base_msg
, compression_lhs
, compression_limit
, typeDomain
);
154 if (!ptr
) return ptr
;
155 *ptr
= (qtype
>> 8) & 0xff;
159 *ptr
= compression_packet_v1
;
163 mDNSlocal mDNSu8
* DNSNameCompressionBuildRHS(mDNSu8
*start
, const ResourceRecord
*const resourceRecord
)
165 return putRData(&compression_base_msg
, start
, compression_limit
, resourceRecord
);
168 mDNSlocal
void PrintHelper(const char *const tag
, mDNSu8
*lhs
, mDNSu16 lhs_len
, mDNSu8
*rhs
, mDNSu16 rhs_len
)
170 if (mDNS_LoggingEnabled
)
172 LogDebug("%s: LHS: (%d bytes) %.*H", tag
, lhs_len
, lhs_len
, lhs
);
173 if (rhs
) LogDebug("%s: RHS: (%d bytes) %.*H", tag
, rhs_len
, rhs_len
, rhs
);
177 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
180 if (result
== mStatus_MemFree
)
182 D2DRecordListElem
**ptr
= &D2DRecords
;
183 D2DRecordListElem
*tmp
;
184 while (*ptr
&& &(*ptr
)->ar
!= rr
) ptr
= &(*ptr
)->next
;
185 if (!*ptr
) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m
, rr
)); return; }
186 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m
, rr
));
189 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
190 mDNSPlatformMemFree(tmp
);
194 mDNSexport
void external_connection_release(const domainname
*instance
)
197 D2DRecordListElem
*ptr
= D2DRecords
;
199 for ( ; ptr
; ptr
= ptr
->next
)
201 if ((ptr
->ar
.resrec
.rrtype
== kDNSServiceType_PTR
) &&
202 SameDomainName(&ptr
->ar
.rdatastorage
.u
.name
, instance
))
204 LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d",
205 ptr
->instanceHandle
, ptr
->transportType
);
206 if (D2DRelease
) D2DRelease(ptr
->instanceHandle
, ptr
->transportType
);
211 mDNSlocal
void xD2DClearCache(const domainname
*regType
, DNS_TypeValues qtype
)
213 D2DRecordListElem
*ptr
= D2DRecords
;
214 for ( ; ptr
; ptr
= ptr
->next
)
216 if ((ptr
->ar
.resrec
.rrtype
== qtype
) && SameDomainName(&ptr
->ar
.namestorage
, regType
))
218 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage
, &ptr
->ar
));
219 mDNS_Deregister(&mDNSStorage
, &ptr
->ar
);
224 mDNSlocal D2DBrowseListElem
** D2DFindInBrowseList(const domainname
*const name
, mDNSu16 type
)
226 D2DBrowseListElem
**ptr
= &D2DBrowseList
;
228 for ( ; *ptr
; ptr
= &(*ptr
)->next
)
229 if ((*ptr
)->type
== type
&& SameDomainName(&(*ptr
)->name
, name
))
235 mDNSlocal
unsigned int D2DBrowseListRefCount(const domainname
*const name
, mDNSu16 type
)
237 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
238 return *ptr
? (*ptr
)->refCount
: 0;
241 mDNSlocal
void D2DBrowseListRetain(const domainname
*const name
, mDNSu16 type
)
243 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
247 *ptr
= (D2DBrowseListElem
*) mDNSPlatformMemAllocateClear(sizeof(**ptr
));
249 AssignDomainName(&(*ptr
)->name
, name
);
251 (*ptr
)->refCount
+= 1;
253 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
256 // Returns true if found in list, false otherwise
257 mDNSlocal
bool D2DBrowseListRelease(const domainname
*const name
, mDNSu16 type
)
259 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
261 if (!*ptr
) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name
->c
, DNSTypeName(type
)); return false; }
263 (*ptr
)->refCount
-= 1;
265 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
267 if (!(*ptr
)->refCount
)
269 D2DBrowseListElem
*tmp
= *ptr
;
271 mDNSPlatformMemFree(tmp
);
276 mDNSlocal mStatus
xD2DParse(const mDNSu8
* const lhs
, const mDNSu16 lhs_len
, const mDNSu8
* const rhs
, const mDNSu16 rhs_len
, D2DRecordListElem
**D2DListp
)
278 mDNS
*const m
= &mDNSStorage
;
280 // Sanity check that key array (lhs) has one domain name, followed by the record type and single byte D2D
281 // plugin protocol version number.
282 // Note, we don't have a DNSMessage pointer at this point, so just pass in the lhs value as the lower bound
283 // of the input bytes we are processing. skipDomainName() does not try to follow name compression pointers,
284 // so it is safe to pass it the key byte array since it will stop parsing the DNS name and return a pointer
285 // to the byte after the first name compression pointer it encounters.
286 const mDNSu8
*keyp
= skipDomainName((const DNSMessage
*const) lhs
, lhs
, lhs
+ lhs_len
);
288 // There should be 3 bytes remaining in a valid key,
289 // two for the DNS record type, and one for the D2D protocol version number.
290 if (keyp
== NULL
|| (keyp
+ 3 != (lhs
+ lhs_len
)))
292 LogInfo("xD2DParse: Could not parse DNS name in key");
293 return mStatus_Incompatible
;
295 keyp
+= 2; // point to D2D compression packet format version byte
296 if (*keyp
!= compression_packet_v1
)
298 LogInfo("xD2DParse: Invalid D2D packet version: %d", *keyp
);
299 return mStatus_Incompatible
;
302 if (mDNS_LoggingEnabled
)
304 const int len
= (int)(compression_lhs
- (mDNSu8
*)&compression_base_msg
);
305 LogInfo("xD2DParse: Static Bytes: (%d bytes) %.*H", len
, len
, &compression_base_msg
);
308 mDNSu8
*ptr
= compression_lhs
; // pointer to the end of our fake packet
310 // Check to make sure we're not going to go past the end of the DNSMessage data
311 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
312 if (ptr
+ lhs_len
- 7 + rhs_len
>= compression_limit
) return mStatus_NoMemoryErr
;
314 // Copy the LHS onto our fake wire packet
315 mDNSPlatformMemCopy(ptr
, lhs
, lhs_len
);
318 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
319 if (*ptr
!= compression_packet_v1
) return mStatus_Incompatible
;
321 // two bytes of CLASS
322 ptr
= putVal16(ptr
, kDNSClass_IN
| kDNSClass_UniqueRRSet
);
325 ptr
= putVal32(ptr
, 120);
327 // Copy the RHS length into the RDLENGTH of our fake wire packet
328 ptr
= putVal16(ptr
, rhs_len
);
330 // Copy the RHS onto our fake wire packet
331 mDNSPlatformMemCopy(ptr
, rhs
, rhs_len
);
334 if (mDNS_LoggingEnabled
)
336 const int len
= (int)(ptr
- compression_lhs
);
337 LogInfo("xD2DParse: Our Bytes (%d bytes): %.*H", len
, len
, compression_lhs
);
340 ptr
= (mDNSu8
*) GetLargeResourceRecord(m
, &compression_base_msg
, compression_lhs
, ptr
, mDNSInterface_Any
, kDNSRecordTypePacketAns
, &m
->rec
);
341 if (!ptr
|| m
->rec
.r
.resrec
.RecordType
== kDNSRecordTypePacketNegative
)
343 LogMsg("xD2DParse: failed to get large RR");
344 m
->rec
.r
.resrec
.RecordType
= 0;
345 return mStatus_UnknownErr
;
349 LogInfo("xD2DParse: got rr: %s", CRDisplayString(m
, &m
->rec
.r
));
352 *D2DListp
= (D2DRecordListElem
*) mDNSPlatformMemAllocateClear(sizeof(D2DRecordListElem
) + (m
->rec
.r
.resrec
.rdlength
<= sizeof(RDataBody
) ? 0 : m
->rec
.r
.resrec
.rdlength
- sizeof(RDataBody
)));
353 if (!*D2DListp
) return mStatus_NoMemoryErr
;
355 AuthRecord
*rr
= &(*D2DListp
)->ar
;
356 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_P2P
, m
->rec
.r
.resrec
.rrtype
, 7200, kDNSRecordTypeShared
, AuthRecordP2P
, FreeD2DARElemCallback
, NULL
);
357 AssignDomainName(&rr
->namestorage
, &m
->rec
.namestorage
);
358 rr
->resrec
.rdlength
= m
->rec
.r
.resrec
.rdlength
;
359 rr
->resrec
.rdata
->MaxRDLength
= m
->rec
.r
.resrec
.rdlength
;
360 mDNSPlatformMemCopy(rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
);
361 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
362 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
364 m
->rec
.r
.resrec
.RecordType
= 0; // Mark m->rec as no longer in use
366 return mStatus_NoError
;
369 mDNSexport
void xD2DAddToCache(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
371 mDNS
*const m
= &mDNSStorage
;
372 if (result
== kD2DSuccess
)
374 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
377 D2DRecordListElem
*ptr
= NULL
;
379 err
= xD2DParse((const mDNSu8
* const)key
, (const mDNSu16
)keySize
, (const mDNSu8
* const)value
, (const mDNSu16
)valueSize
, &ptr
);
382 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err
);
383 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
385 mDNSPlatformMemFree(ptr
);
389 #if ENABLE_BLE_TRIGGERED_BONJOUR
390 // If the record was created based on a BLE beacon, update the interface index to indicate
391 // this and thus match BLE specific queries.
392 if (transportType
== D2DBLETransport
)
393 ptr
->ar
.resrec
.InterfaceID
= mDNSInterface_BLE
;
394 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
396 err
= mDNS_Register(m
, &ptr
->ar
);
399 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err
, ARDisplayString(m
, &ptr
->ar
));
400 mDNSPlatformMemFree(ptr
);
404 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m
, &ptr
->ar
));
405 ptr
->instanceHandle
= instanceHandle
;
406 ptr
->transportType
= transportType
;
407 ptr
->next
= D2DRecords
;
411 LogMsg("xD2DAddToCache: Unexpected result %d", result
);
414 mDNSlocal D2DRecordListElem
* xD2DFindInList(const Byte
*const key
, const size_t keySize
, const Byte
*const value
, const size_t valueSize
)
416 D2DRecordListElem
*ptr
= D2DRecords
;
417 D2DRecordListElem
*arptr
= NULL
;
419 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL
; }
421 mStatus err
= xD2DParse((const mDNSu8
*const)key
, (const mDNSu16
)keySize
, (const mDNSu8
*const)value
, (const mDNSu16
)valueSize
, &arptr
);
424 LogMsg("xD2DFindInList: xD2DParse returned error: %d", err
);
425 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
427 mDNSPlatformMemFree(arptr
);
433 if (IdenticalResourceRecord(&arptr
->ar
.resrec
, &ptr
->ar
.resrec
)) break;
437 if (!ptr
) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(&mDNSStorage
, &arptr
->ar
));
438 mDNSPlatformMemFree(arptr
);
442 mDNSexport
void xD2DRemoveFromCache(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
444 (void)transportType
; // We don't care about this, yet.
445 (void)instanceHandle
; // We don't care about this, yet.
447 if (result
== kD2DSuccess
)
449 D2DRecordListElem
*ptr
= xD2DFindInList(key
, keySize
, value
, valueSize
);
452 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(&mDNSStorage
, &ptr
->ar
));
453 mDNS_Deregister(&mDNSStorage
, &ptr
->ar
);
457 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result
);
460 mDNSlocal
void xD2DServiceResolved(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
467 if (result
== kD2DSuccess
)
469 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle
);
470 if (D2DRetain
) D2DRetain(instanceHandle
, transportType
);
472 else LogMsg("xD2DServiceResolved: Unexpected result %d", result
);
475 mDNSlocal
void xD2DRetainHappened(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
477 (void)instanceHandle
;
484 if (result
== kD2DSuccess
) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle
);
485 else LogMsg("xD2DRetainHappened: Unexpected result %d", result
);
488 mDNSlocal
void xD2DReleaseHappened(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
490 (void)instanceHandle
;
497 if (result
== kD2DSuccess
) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle
);
498 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result
);
501 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
)
503 const char *eventString
= "unknown";
507 if (keySize
> 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize
);
508 if (valueSize
> 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize
);
512 case D2DServiceFound
:
513 eventString
= "D2DServiceFound";
516 eventString
= "D2DServiceLost";
518 case D2DServiceResolved
:
519 eventString
= "D2DServiceResolved";
521 case D2DServiceRetained
:
522 eventString
= "D2DServiceRetained";
524 case D2DServiceReleased
:
525 eventString
= "D2DServiceReleased";
531 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
);
532 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
536 case D2DServiceFound
:
537 xD2DAddToCache(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
540 xD2DRemoveFromCache(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
542 case D2DServiceResolved
:
543 xD2DServiceResolved(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
545 case D2DServiceRetained
:
546 xD2DRetainHappened(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
548 case D2DServiceReleased
:
549 xD2DReleaseHappened(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
555 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
556 KQueueUnlock("xD2DServiceCallback");
559 // Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
561 // When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
562 // will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
563 // If the return value is not D2DTransportMax, excludedTransportType is undefined.
565 mDNSlocal D2DTransportType
xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID
, DNSServiceFlags flags
, D2DTransportType
* excludedTransportType
)
567 NetworkInterfaceInfoOSX
*info
;
569 // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
570 *excludedTransportType
= D2DAWDLTransport
;
572 // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
573 if ((flags
& kDNSServiceFlagsIncludeP2P
) && (flags
& kDNSServiceFlagsIncludeAWDL
))
575 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
576 *excludedTransportType
= D2DTransportMax
;
577 return D2DTransportMax
;
579 // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
580 else if (flags
& kDNSServiceFlagsIncludeP2P
)
582 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
583 return D2DTransportMax
;
585 // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
586 else if (flags
& kDNSServiceFlagsIncludeAWDL
)
588 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
589 return D2DAWDLTransport
;
592 if (InterfaceID
== mDNSInterface_P2P
)
594 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
595 return D2DTransportMax
;
598 // Compare to cached AWDL interface ID.
599 if (AWDLInterfaceID
&& (InterfaceID
== AWDLInterfaceID
))
601 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID
);
602 return D2DAWDLTransport
;
605 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
608 LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID
);
609 return D2DTransportMax
;
612 // Recognize AirDrop specific p2p* interface based on interface name.
613 if (strncmp(info
->ifinfo
.ifname
, "p2p", 3) == 0)
615 LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID
);
616 return D2DWifiPeerToPeerTransport
;
619 // Currently there is no way to identify Bluetooth interface by name,
620 // since they use "en*" based name strings.
622 LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID
);
623 return D2DTransportMax
;
626 mDNSexport
void external_start_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
628 #if ENABLE_BLE_TRIGGERED_BONJOUR
629 // BLE support currently not handled by a D2D plugin
630 if (applyToBLE(InterfaceID
, flags
))
634 DomainnameToLower(typeDomain
, &lower
);
635 // pass in the key and keySize
636 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
637 start_BLE_browse(InterfaceID
, &lower
, qtype
, flags
, compression_lhs
, end
- compression_lhs
);
640 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
641 internal_start_browsing_for_service(InterfaceID
, typeDomain
, qtype
, flags
);
644 mDNSexport
void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
648 DomainnameToLower(typeDomain
, &lower
);
650 if (!D2DBrowseListRefCount(&lower
, qtype
))
652 D2DTransportType transportType
, excludedTransport
;
654 LogInfo("%s: Starting browse for: %##s %s", __func__
, lower
.c
, DNSTypeName(qtype
));
655 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
656 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
658 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
659 if (transportType
== D2DTransportMax
)
662 for (i
= 0; i
< D2DTransportMax
; i
++)
664 if (i
== excludedTransport
) continue;
665 if (D2DStartBrowsingForKeyOnTransport
) D2DStartBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, i
);
670 if (D2DStartBrowsingForKeyOnTransport
) D2DStartBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, transportType
);
673 D2DBrowseListRetain(&lower
, qtype
);
676 mDNSexport
void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
678 #if ENABLE_BLE_TRIGGERED_BONJOUR
679 // BLE support currently not handled by a D2D plugin
680 if (applyToBLE(InterfaceID
, flags
))
684 // If this is the last instance of this browse, clear any cached records recieved for it.
685 // We are not guaranteed to get a D2DServiceLost event for all key, value pairs cached over BLE.
686 DomainnameToLower(typeDomain
, &lower
);
687 if (stop_BLE_browse(InterfaceID
, &lower
, qtype
, flags
))
688 xD2DClearCache(&lower
, qtype
);
691 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
692 internal_stop_browsing_for_service(InterfaceID
, typeDomain
, qtype
, flags
);
695 mDNSexport
void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
699 DomainnameToLower(typeDomain
, &lower
);
701 // If found in list and this is the last reference to this browse, remove the key from the D2D plugins.
702 if (D2DBrowseListRelease(&lower
, qtype
) && !D2DBrowseListRefCount(&lower
, qtype
))
704 D2DTransportType transportType
, excludedTransport
;
706 LogInfo("%s: Stopping browse for: %##s %s", __func__
, lower
.c
, DNSTypeName(qtype
));
707 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
708 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
710 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
711 if (transportType
== D2DTransportMax
)
714 for (i
= 0; i
< D2DTransportMax
; i
++)
716 if (i
== excludedTransport
) continue;
717 if (D2DStopBrowsingForKeyOnTransport
) D2DStopBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, i
);
722 if (D2DStopBrowsingForKeyOnTransport
) D2DStopBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, transportType
);
725 // The D2D driver may not generate the D2DServiceLost event for this key after
726 // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
728 xD2DClearCache(&lower
, qtype
);
732 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
734 #if ENABLE_BLE_TRIGGERED_BONJOUR
735 if (applyToBLE(resourceRecord
->InterfaceID
, flags
))
739 DomainnameToLower(resourceRecord
->name
, &lower
);
740 start_BLE_advertise(resourceRecord
, &lower
, resourceRecord
->rrtype
, flags
);
743 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
744 internal_start_advertising_service(resourceRecord
, flags
);
747 mDNSexport
void internal_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
752 D2DTransportType transportType
, excludedTransport
;
753 DomainnameToLower(resourceRecord
->name
, &lower
);
755 LogInfo("%s: %s", __func__
, RRDisplayString(&mDNSStorage
, resourceRecord
));
757 // For SRV records, update packet filter if p2p interface already exists, otherwise,
758 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
759 if (resourceRecord
->rrtype
== kDNSType_SRV
)
760 mDNSUpdatePacketFilter(NULL
);
762 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
763 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
764 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
766 transportType
= xD2DInterfaceToTransportType(resourceRecord
->InterfaceID
, flags
, & excludedTransport
);
767 if (transportType
== D2DTransportMax
)
770 for (i
= 0; i
< D2DTransportMax
; i
++)
772 if (i
== excludedTransport
) continue;
773 if (D2DStartAdvertisingPairOnTransport
) D2DStartAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
778 if (D2DStartAdvertisingPairOnTransport
) D2DStartAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
782 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
784 #if ENABLE_BLE_TRIGGERED_BONJOUR
785 // BLE support currently not handled by a D2D plugin
786 if (applyToBLE(resourceRecord
->InterfaceID
, flags
))
790 DomainnameToLower(resourceRecord
->name
, &lower
);
791 stop_BLE_advertise(&lower
, resourceRecord
->rrtype
, flags
);
794 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
795 internal_stop_advertising_service(resourceRecord
, flags
);
798 mDNSexport
void internal_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
803 D2DTransportType transportType
, excludedTransport
;
804 DomainnameToLower(resourceRecord
->name
, &lower
);
806 LogInfo("%s: %s", __func__
, RRDisplayString(&mDNSStorage
, resourceRecord
));
808 // For SRV records, update packet filter if p2p interface already exists, otherwise,
809 // For SRV records, update packet filter to to remove this port from list
810 if (resourceRecord
->rrtype
== kDNSType_SRV
)
811 mDNSUpdatePacketFilter(resourceRecord
);
813 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
814 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
815 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
817 transportType
= xD2DInterfaceToTransportType(resourceRecord
->InterfaceID
, flags
, & excludedTransport
);
818 if (transportType
== D2DTransportMax
)
821 for (i
= 0; i
< D2DTransportMax
; i
++)
823 if (i
== excludedTransport
) continue;
824 if (D2DStopAdvertisingPairOnTransport
) D2DStopAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
829 if (D2DStopAdvertisingPairOnTransport
) D2DStopAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
833 mDNSexport
void external_start_resolving_service(mDNSInterfaceID InterfaceID
, const domainname
*const fqdn
, DNSServiceFlags flags
)
838 mDNSBool AWDL_used
= false; // whether AWDL was used for this resolve
839 D2DTransportType transportType
, excludedTransport
;
840 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
842 LogInfo("external_start_resolving_service: %##s", fqdn
->c
);
843 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
844 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
845 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
847 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
848 if (transportType
== D2DTransportMax
)
850 // Resolving over all the transports, except for excludedTransport if set.
852 for (i
= 0; i
< D2DTransportMax
; i
++)
854 if (i
== excludedTransport
) continue;
855 if (D2DStartResolvingPairOnTransport
) D2DStartResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
857 if (i
== D2DAWDLTransport
)
863 // Resolving over one specific transport.
864 if (D2DStartResolvingPairOnTransport
) D2DStartResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
866 if (transportType
== D2DAWDLTransport
)
870 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
871 // We only want these records going to AWDL, so use AWDLInterfaceID as the
872 // interface and don't set any other flags.
873 if (AWDL_used
&& AWDLInterfaceID
)
875 LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
876 external_start_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_TXT
, 0);
877 external_start_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_SRV
, 0);
881 mDNSexport
void external_stop_resolving_service(mDNSInterfaceID InterfaceID
, const domainname
*const fqdn
, DNSServiceFlags flags
)
886 mDNSBool AWDL_used
= false; // whether AWDL was used for this resolve
887 D2DTransportType transportType
, excludedTransport
;
888 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
890 LogInfo("external_stop_resolving_service: %##s", fqdn
->c
);
891 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
892 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
893 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
895 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
896 if (transportType
== D2DTransportMax
)
899 for (i
= 0; i
< D2DTransportMax
; i
++)
901 if (i
== excludedTransport
) continue;
902 if (D2DStopResolvingPairOnTransport
) D2DStopResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
904 if (i
== D2DAWDLTransport
)
910 if (D2DStopResolvingPairOnTransport
) D2DStopResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
912 if (transportType
== D2DAWDLTransport
)
916 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
917 // We only want these records going to AWDL, so use AWDLInterfaceID as the
918 // interface and don't set any other flags.
919 if (AWDL_used
&& AWDLInterfaceID
)
921 LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
922 external_stop_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_TXT
, 0);
923 external_stop_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_SRV
, 0);
927 mDNSexport mDNSBool
callExternalHelpers(mDNSInterfaceID InterfaceID
, const domainname
*const domain
, DNSServiceFlags flags
)
929 // Only call D2D layer routines if request applies to a D2D interface and the domain is "local".
930 if ( (((InterfaceID
== mDNSInterface_Any
) && (flags
& (kDNSServiceFlagsIncludeP2P
| kDNSServiceFlagsIncludeAWDL
| kDNSServiceFlagsAutoTrigger
)))
931 || mDNSPlatformInterfaceIsD2D(InterfaceID
) || (InterfaceID
== mDNSInterface_BLE
))
932 && IsLocalDomain(domain
))
940 // Used to derive the original D2D specific flags specified by the client in the registration
941 // when we don't have access to the original flag (kDNSServiceFlags*) values.
942 mDNSexport mDNSu32
deriveD2DFlagsFromAuthRecType(AuthRecType authRecType
)
945 if ((authRecType
== AuthRecordAnyIncludeP2P
) || (authRecType
== AuthRecordAnyIncludeAWDLandP2P
))
946 flags
|= kDNSServiceFlagsIncludeP2P
;
947 else if ((authRecType
== AuthRecordAnyIncludeAWDL
) || (authRecType
== AuthRecordAnyIncludeAWDLandP2P
))
948 flags
|= kDNSServiceFlagsIncludeAWDL
;
952 void initializeD2DPlugins(mDNS
*const m
)
954 // We only initialize if mDNSCore successfully initialized.
957 D2DStatus ds
= D2DInitialize(CFRunLoopGetMain(), xD2DServiceCallback
, m
);
958 if (ds
!= kD2DSuccess
)
959 LogMsg("D2DInitialiize failed: %d", ds
);
961 LogMsg("D2DInitialize succeeded");
965 void terminateD2DPlugins(void)
969 D2DStatus ds
= D2DTerminate();
970 if (ds
!= kD2DSuccess
)
971 LogMsg("D2DTerminate failed: %d", ds
);
973 LogMsg("D2DTerminate succeeded");
978 #pragma mark - Unit test support routines
980 // These unit test support routines are called from unittests/ framework
981 // and are not compiled for the mDNSResponder runtime code paths.
983 void D2D_unitTest(void)