1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
20 #include "DNSCommon.h"
21 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
22 #include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
23 #include "dns_sd_internal.h"
24 #include "uds_daemon.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() __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);
52 if (interface
->RR_PTR
.resrec
.RecordType
)
53 external_start_advertising_service(&interface
->RR_PTR
.resrec
, 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);
67 if (interface
->RR_PTR
.resrec
.RecordType
)
68 external_stop_advertising_service(&interface
->RR_PTR
.resrec
, 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
);
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
);
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
);
100 mDNSlocal
void PrintHex(mDNSu8
*data
, mDNSu16 len
);
102 typedef struct D2DRecordListElem
104 struct D2DRecordListElem
*next
;
105 D2DServiceInstance instanceHandle
;
106 D2DTransportType transportType
;
107 AuthRecord ar
; // must be last in the structure to accomodate extra space
108 // allocated for large records.
111 static D2DRecordListElem
*D2DRecords
= NULL
; // List of records returned with D2DServiceFound events
113 typedef struct D2DBrowseListElem
115 struct D2DBrowseListElem
*next
;
118 unsigned int refCount
;
121 D2DBrowseListElem
* D2DBrowseList
= NULL
;
123 mDNSlocal mDNSu8
*putVal16(mDNSu8
*ptr
, mDNSu16 val
)
125 ptr
[0] = (mDNSu8
)((val
>> 8 ) & 0xFF);
126 ptr
[1] = (mDNSu8
)((val
) & 0xFF);
127 return ptr
+ sizeof(mDNSu16
);
130 mDNSlocal mDNSu8
*putVal32(mDNSu8
*ptr
, mDNSu32 val
)
132 ptr
[0] = (mDNSu8
)((val
>> 24) & 0xFF);
133 ptr
[1] = (mDNSu8
)((val
>> 16) & 0xFF);
134 ptr
[2] = (mDNSu8
)((val
>> 8) & 0xFF);
135 ptr
[3] = (mDNSu8
)((val
) & 0xFF);
136 return ptr
+ sizeof(mDNSu32
);
139 mDNSlocal
void DomainnameToLower(const domainname
* const in
, domainname
* const out
)
141 const mDNSu8
* const start
= (const mDNSu8
* const)in
;
142 mDNSu8
*ptr
= (mDNSu8
*)start
;
146 out
->c
[ptr
-start
] = *ptr
;
148 for (; c
; c
--,ptr
++) out
->c
[ptr
-start
] = mDNSIsUpperCase(*ptr
) ? (*ptr
- 'A' + 'a') : *ptr
;
150 out
->c
[ptr
-start
] = *ptr
;
153 mDNSlocal mDNSu8
* DNSNameCompressionBuildLHS(const domainname
* typeDomain
, DNS_TypeValues qtype
)
155 mDNSu8
*ptr
= putDomainNameAsLabels(&compression_base_msg
, compression_lhs
, compression_limit
, typeDomain
);
156 if (!ptr
) return ptr
;
157 *ptr
= (qtype
>> 8) & 0xff;
161 *ptr
= compression_packet_v1
;
165 mDNSlocal mDNSu8
* DNSNameCompressionBuildRHS(mDNSu8
*start
, const ResourceRecord
*const resourceRecord
)
167 return putRData(&compression_base_msg
, start
, compression_limit
, resourceRecord
);
170 #define PRINT_DEBUG_BYTES_LIMIT 64 // set limit on number of record bytes printed for debugging
172 mDNSlocal
void PrintHex(mDNSu8
*data
, mDNSu16 len
)
175 char buffer
[49] = {0};
176 char *bufend
= buffer
+ sizeof(buffer
);
178 if (len
> PRINT_DEBUG_BYTES_LIMIT
)
180 LogInfo(" (limiting debug output to %d bytes)", PRINT_DEBUG_BYTES_LIMIT
);
181 len
= PRINT_DEBUG_BYTES_LIMIT
;
188 for(; data
< end
&& ptr
< bufend
-1; ptr
+=3,data
++)
189 mDNS_snprintf(ptr
, bufend
- ptr
, "%02X ", *data
);
190 LogInfo(" %s", buffer
);
194 mDNSlocal
void PrintHelper(const char *const tag
, mDNSu8
*lhs
, mDNSu16 lhs_len
, mDNSu8
*rhs
, mDNSu16 rhs_len
)
196 if (!mDNS_LoggingEnabled
) return;
199 LogInfo(" LHS: (%d bytes)", lhs_len
);
200 PrintHex(lhs
, lhs_len
);
204 LogInfo(" RHS: (%d bytes)", rhs_len
);
205 PrintHex(rhs
, rhs_len
);
208 mDNSlocal
void FreeD2DARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
211 if (result
== mStatus_MemFree
)
213 D2DRecordListElem
**ptr
= &D2DRecords
;
214 D2DRecordListElem
*tmp
;
215 while (*ptr
&& &(*ptr
)->ar
!= rr
) ptr
= &(*ptr
)->next
;
216 if (!*ptr
) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m
, rr
)); return; }
217 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m
, rr
));
220 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
221 mDNSPlatformMemFree(tmp
);
225 mDNSexport
void external_connection_release(const domainname
*instance
)
228 D2DRecordListElem
*ptr
= D2DRecords
;
230 for ( ; ptr
; ptr
= ptr
->next
)
232 if ((ptr
->ar
.resrec
.rrtype
== kDNSServiceType_PTR
) &&
233 SameDomainName(&ptr
->ar
.rdatastorage
.u
.name
, instance
))
235 LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d",
236 ptr
->instanceHandle
, ptr
->transportType
);
237 if (D2DRelease
) D2DRelease(ptr
->instanceHandle
, ptr
->transportType
);
242 mDNSlocal
void xD2DClearCache(const domainname
*regType
, DNS_TypeValues qtype
)
244 D2DRecordListElem
*ptr
= D2DRecords
;
245 for ( ; ptr
; ptr
= ptr
->next
)
247 if ((ptr
->ar
.resrec
.rrtype
== qtype
) && SameDomainName(&ptr
->ar
.namestorage
, regType
))
249 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage
, &ptr
->ar
));
250 mDNS_Deregister(&mDNSStorage
, &ptr
->ar
);
255 mDNSlocal D2DBrowseListElem
** D2DFindInBrowseList(const domainname
*const name
, mDNSu16 type
)
257 D2DBrowseListElem
**ptr
= &D2DBrowseList
;
259 for ( ; *ptr
; ptr
= &(*ptr
)->next
)
260 if ((*ptr
)->type
== type
&& SameDomainName(&(*ptr
)->name
, name
))
266 mDNSlocal
unsigned int D2DBrowseListRefCount(const domainname
*const name
, mDNSu16 type
)
268 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
269 return *ptr
? (*ptr
)->refCount
: 0;
272 mDNSlocal
void D2DBrowseListRetain(const domainname
*const name
, mDNSu16 type
)
274 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
278 *ptr
= mDNSPlatformMemAllocate(sizeof(**ptr
));
279 mDNSPlatformMemZero(*ptr
, sizeof(**ptr
));
281 AssignDomainName(&(*ptr
)->name
, name
);
283 (*ptr
)->refCount
+= 1;
285 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
288 // Returns true if found in list, false otherwise
289 mDNSlocal
bool D2DBrowseListRelease(const domainname
*const name
, mDNSu16 type
)
291 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
293 if (!*ptr
) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name
->c
, DNSTypeName(type
)); return false; }
295 (*ptr
)->refCount
-= 1;
297 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
299 if (!(*ptr
)->refCount
)
301 D2DBrowseListElem
*tmp
= *ptr
;
303 mDNSPlatformMemFree(tmp
);
308 mDNSlocal mStatus
xD2DParse(const mDNSu8
* const lhs
, const mDNSu16 lhs_len
, const mDNSu8
* const rhs
, const mDNSu16 rhs_len
, D2DRecordListElem
**D2DListp
)
310 mDNS
*const m
= &mDNSStorage
;
312 // Sanity check that key array (lhs) has one domain name, followed by the record type and single byte D2D
313 // plugin protocol version number.
314 // Note, we don't have a DNSMessage pointer at this point, so just pass in the lhs value as the lower bound
315 // of the input bytes we are processing. skipDomainName() does not try to follow name compression pointers,
316 // so it is safe to pass it the key byte array since it will stop parsing the DNS name and return a pointer
317 // to the byte after the first name compression pointer it encounters.
318 const mDNSu8
*keyp
= skipDomainName((const DNSMessage
*const) lhs
, lhs
, lhs
+ lhs_len
);
320 // There should be 3 bytes remaining in a valid key,
321 // two for the DNS record type, and one for the D2D protocol version number.
322 if (keyp
== NULL
|| (keyp
+ 3 != (lhs
+ lhs_len
)))
324 LogInfo("xD2DParse: Could not parse DNS name in key");
325 return mStatus_Incompatible
;
327 keyp
+= 2; // point to D2D compression packet format version byte
328 if (*keyp
!= compression_packet_v1
)
330 LogInfo("xD2DParse: Invalid D2D packet version: %d", *keyp
);
331 return mStatus_Incompatible
;
334 if (mDNS_LoggingEnabled
)
336 LogInfo("%s", __func__
);
337 LogInfo(" Static Bytes: (%d bytes)", compression_lhs
- (mDNSu8
*)&compression_base_msg
);
338 PrintHex((mDNSu8
*)&compression_base_msg
, compression_lhs
- (mDNSu8
*)&compression_base_msg
);
341 mDNSu8
*ptr
= compression_lhs
; // pointer to the end of our fake packet
343 // Check to make sure we're not going to go past the end of the DNSMessage data
344 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
345 if (ptr
+ lhs_len
- 7 + rhs_len
>= compression_limit
) return mStatus_NoMemoryErr
;
347 // Copy the LHS onto our fake wire packet
348 mDNSPlatformMemCopy(ptr
, lhs
, lhs_len
);
351 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
352 if (*ptr
!= compression_packet_v1
) return mStatus_Incompatible
;
354 // two bytes of CLASS
355 ptr
= putVal16(ptr
, kDNSClass_IN
| kDNSClass_UniqueRRSet
);
358 ptr
= putVal32(ptr
, 120);
360 // Copy the RHS length into the RDLENGTH of our fake wire packet
361 ptr
= putVal16(ptr
, rhs_len
);
363 // Copy the RHS onto our fake wire packet
364 mDNSPlatformMemCopy(ptr
, rhs
, rhs_len
);
367 if (mDNS_LoggingEnabled
)
369 LogInfo(" Our Bytes (%d bytes): ", ptr
- compression_lhs
);
370 PrintHex(compression_lhs
, ptr
- compression_lhs
);
373 ptr
= (mDNSu8
*) GetLargeResourceRecord(m
, &compression_base_msg
, compression_lhs
, ptr
, mDNSInterface_Any
, kDNSRecordTypePacketAns
, &m
->rec
);
374 if (!ptr
|| m
->rec
.r
.resrec
.RecordType
== kDNSRecordTypePacketNegative
)
376 LogMsg("xD2DParse: failed to get large RR");
377 m
->rec
.r
.resrec
.RecordType
= 0;
378 return mStatus_UnknownErr
;
382 LogInfo("xD2DParse: got rr: %s", CRDisplayString(m
, &m
->rec
.r
));
385 *D2DListp
= mDNSPlatformMemAllocate(sizeof(D2DRecordListElem
) + (m
->rec
.r
.resrec
.rdlength
<= sizeof(RDataBody
) ? 0 : m
->rec
.r
.resrec
.rdlength
- sizeof(RDataBody
)));
386 if (!*D2DListp
) return mStatus_NoMemoryErr
;
388 AuthRecord
*rr
= &(*D2DListp
)->ar
;
389 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_P2P
, m
->rec
.r
.resrec
.rrtype
, 7200, kDNSRecordTypeShared
, AuthRecordP2P
, FreeD2DARElemCallback
, NULL
);
390 AssignDomainName(&rr
->namestorage
, &m
->rec
.namestorage
);
391 rr
->resrec
.rdlength
= m
->rec
.r
.resrec
.rdlength
;
392 rr
->resrec
.rdata
->MaxRDLength
= m
->rec
.r
.resrec
.rdlength
;
393 mDNSPlatformMemCopy(rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
);
394 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
395 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
397 m
->rec
.r
.resrec
.RecordType
= 0; // Mark m->rec as no longer in use
399 return mStatus_NoError
;
402 mDNSexport
void xD2DAddToCache(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
404 mDNS
*const m
= &mDNSStorage
;
405 if (result
== kD2DSuccess
)
407 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
410 D2DRecordListElem
*ptr
= NULL
;
412 err
= xD2DParse((const mDNSu8
* const)key
, (const mDNSu16
)keySize
, (const mDNSu8
* const)value
, (const mDNSu16
)valueSize
, &ptr
);
415 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err
);
416 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
418 mDNSPlatformMemFree(ptr
);
422 #if ENABLE_BLE_TRIGGERED_BONJOUR
423 // If the record was created based on a BLE beacon, update the interface index to indicate
424 // this and thus match BLE specific queries.
425 if (transportType
== D2DBLETransport
)
426 ptr
->ar
.resrec
.InterfaceID
= mDNSInterface_BLE
;
427 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
429 err
= mDNS_Register(m
, &ptr
->ar
);
432 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err
, ARDisplayString(m
, &ptr
->ar
));
433 mDNSPlatformMemFree(ptr
);
437 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m
, &ptr
->ar
));
438 ptr
->instanceHandle
= instanceHandle
;
439 ptr
->transportType
= transportType
;
440 ptr
->next
= D2DRecords
;
444 LogMsg("xD2DAddToCache: Unexpected result %d", result
);
447 mDNSlocal D2DRecordListElem
* xD2DFindInList(const Byte
*const key
, const size_t keySize
, const Byte
*const value
, const size_t valueSize
)
449 D2DRecordListElem
*ptr
= D2DRecords
;
450 D2DRecordListElem
*arptr
= NULL
;
452 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL
; }
454 mStatus err
= xD2DParse((const mDNSu8
*const)key
, (const mDNSu16
)keySize
, (const mDNSu8
*const)value
, (const mDNSu16
)valueSize
, &arptr
);
457 LogMsg("xD2DFindInList: xD2DParse returned error: %d", err
);
458 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
460 mDNSPlatformMemFree(arptr
);
466 if (IdenticalResourceRecord(&arptr
->ar
.resrec
, &ptr
->ar
.resrec
)) break;
470 if (!ptr
) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(&mDNSStorage
, &arptr
->ar
));
471 mDNSPlatformMemFree(arptr
);
475 mDNSexport
void xD2DRemoveFromCache(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
477 (void)transportType
; // We don't care about this, yet.
478 (void)instanceHandle
; // We don't care about this, yet.
480 if (result
== kD2DSuccess
)
482 D2DRecordListElem
*ptr
= xD2DFindInList(key
, keySize
, value
, valueSize
);
485 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(&mDNSStorage
, &ptr
->ar
));
486 mDNS_Deregister(&mDNSStorage
, &ptr
->ar
);
490 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result
);
493 mDNSlocal
void xD2DServiceResolved(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
500 if (result
== kD2DSuccess
)
502 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle
);
503 if (D2DRetain
) D2DRetain(instanceHandle
, transportType
);
505 else LogMsg("xD2DServiceResolved: Unexpected result %d", result
);
508 mDNSlocal
void xD2DRetainHappened(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
510 (void)instanceHandle
;
517 if (result
== kD2DSuccess
) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle
);
518 else LogMsg("xD2DRetainHappened: Unexpected result %d", result
);
521 mDNSlocal
void xD2DReleaseHappened(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
523 (void)instanceHandle
;
530 if (result
== kD2DSuccess
) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle
);
531 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result
);
534 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
)
536 const char *eventString
= "unknown";
540 if (keySize
> 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize
);
541 if (valueSize
> 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize
);
545 case D2DServiceFound
:
546 eventString
= "D2DServiceFound";
549 eventString
= "D2DServiceLost";
551 case D2DServiceResolved
:
552 eventString
= "D2DServiceResolved";
554 case D2DServiceRetained
:
555 eventString
= "D2DServiceRetained";
557 case D2DServiceReleased
:
558 eventString
= "D2DServiceReleased";
564 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
);
565 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
569 case D2DServiceFound
:
570 xD2DAddToCache(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
573 xD2DRemoveFromCache(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
575 case D2DServiceResolved
:
576 xD2DServiceResolved(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
578 case D2DServiceRetained
:
579 xD2DRetainHappened(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
581 case D2DServiceReleased
:
582 xD2DReleaseHappened(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
588 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
589 KQueueUnlock("xD2DServiceCallback");
592 // Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
594 // When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
595 // will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
596 // If the return value is not D2DTransportMax, excludedTransportType is undefined.
598 mDNSlocal D2DTransportType
xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID
, DNSServiceFlags flags
, D2DTransportType
* excludedTransportType
)
600 NetworkInterfaceInfoOSX
*info
;
602 // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
603 *excludedTransportType
= D2DAWDLTransport
;
605 // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
606 if ((flags
& kDNSServiceFlagsIncludeP2P
) && (flags
& kDNSServiceFlagsIncludeAWDL
))
608 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
609 *excludedTransportType
= D2DTransportMax
;
610 return D2DTransportMax
;
612 // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
613 else if (flags
& kDNSServiceFlagsIncludeP2P
)
615 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
616 return D2DTransportMax
;
618 // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
619 else if (flags
& kDNSServiceFlagsIncludeAWDL
)
621 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
622 return D2DAWDLTransport
;
625 if (InterfaceID
== mDNSInterface_P2P
)
627 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
628 return D2DTransportMax
;
631 // Compare to cached AWDL interface ID.
632 if (AWDLInterfaceID
&& (InterfaceID
== AWDLInterfaceID
))
634 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID
);
635 return D2DAWDLTransport
;
638 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
641 LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID
);
642 return D2DTransportMax
;
645 // Recognize AirDrop specific p2p* interface based on interface name.
646 if (strncmp(info
->ifinfo
.ifname
, "p2p", 3) == 0)
648 LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID
);
649 return D2DWifiPeerToPeerTransport
;
652 // Currently there is no way to identify Bluetooth interface by name,
653 // since they use "en*" based name strings.
655 LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID
);
656 return D2DTransportMax
;
659 mDNSexport
void external_start_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
661 #if ENABLE_BLE_TRIGGERED_BONJOUR
662 // BLE support currently not handled by a D2D plugin
663 if (applyToBLE(InterfaceID
, flags
))
667 DomainnameToLower(typeDomain
, &lower
);
668 // pass in the key and keySize
669 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
670 start_BLE_browse(InterfaceID
, &lower
, qtype
, flags
, compression_lhs
, end
- compression_lhs
);
673 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
674 internal_start_browsing_for_service(InterfaceID
, typeDomain
, qtype
, flags
);
677 mDNSexport
void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
681 DomainnameToLower(typeDomain
, &lower
);
683 if (!D2DBrowseListRefCount(&lower
, qtype
))
685 D2DTransportType transportType
, excludedTransport
;
687 LogInfo("%s: Starting browse for: %##s %s", __func__
, lower
.c
, DNSTypeName(qtype
));
688 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
689 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
691 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
692 if (transportType
== D2DTransportMax
)
695 for (i
= 0; i
< D2DTransportMax
; i
++)
697 if (i
== excludedTransport
) continue;
698 if (D2DStartBrowsingForKeyOnTransport
) D2DStartBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, i
);
703 if (D2DStartBrowsingForKeyOnTransport
) D2DStartBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, transportType
);
706 D2DBrowseListRetain(&lower
, qtype
);
709 mDNSexport
void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
711 #if ENABLE_BLE_TRIGGERED_BONJOUR
712 // BLE support currently not handled by a D2D plugin
713 if (applyToBLE(InterfaceID
, flags
))
717 // If this is the last instance of this browse, clear any cached records recieved for it.
718 // We are not guaranteed to get a D2DServiceLost event for all key, value pairs cached over BLE.
719 DomainnameToLower(typeDomain
, &lower
);
720 if (stop_BLE_browse(InterfaceID
, &lower
, qtype
, flags
))
721 xD2DClearCache(&lower
, qtype
);
724 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
725 internal_stop_browsing_for_service(InterfaceID
, typeDomain
, qtype
, flags
);
728 mDNSexport
void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
732 DomainnameToLower(typeDomain
, &lower
);
734 // If found in list and this is the last reference to this browse, remove the key from the D2D plugins.
735 if (D2DBrowseListRelease(&lower
, qtype
) && !D2DBrowseListRefCount(&lower
, qtype
))
737 D2DTransportType transportType
, excludedTransport
;
739 LogInfo("%s: Stopping browse for: %##s %s", __func__
, lower
.c
, DNSTypeName(qtype
));
740 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
741 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
743 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
744 if (transportType
== D2DTransportMax
)
747 for (i
= 0; i
< D2DTransportMax
; i
++)
749 if (i
== excludedTransport
) continue;
750 if (D2DStopBrowsingForKeyOnTransport
) D2DStopBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, i
);
755 if (D2DStopBrowsingForKeyOnTransport
) D2DStopBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, transportType
);
758 // The D2D driver may not generate the D2DServiceLost event for this key after
759 // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
761 xD2DClearCache(&lower
, qtype
);
765 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
767 #if ENABLE_BLE_TRIGGERED_BONJOUR
768 if (applyToBLE(resourceRecord
->InterfaceID
, flags
))
772 DomainnameToLower(resourceRecord
->name
, &lower
);
773 start_BLE_advertise(resourceRecord
, &lower
, resourceRecord
->rrtype
, flags
);
776 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
777 internal_start_advertising_service(resourceRecord
, flags
);
780 mDNSexport
void internal_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
785 D2DTransportType transportType
, excludedTransport
;
786 DomainnameToLower(resourceRecord
->name
, &lower
);
788 LogInfo("%s: %s", __func__
, RRDisplayString(&mDNSStorage
, resourceRecord
));
790 // For SRV records, update packet filter if p2p interface already exists, otherwise,
791 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
792 if (resourceRecord
->rrtype
== kDNSType_SRV
)
793 mDNSUpdatePacketFilter(NULL
);
795 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
796 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
797 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
799 transportType
= xD2DInterfaceToTransportType(resourceRecord
->InterfaceID
, flags
, & excludedTransport
);
800 if (transportType
== D2DTransportMax
)
803 for (i
= 0; i
< D2DTransportMax
; i
++)
805 if (i
== excludedTransport
) continue;
806 if (D2DStartAdvertisingPairOnTransport
) D2DStartAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
811 if (D2DStartAdvertisingPairOnTransport
) D2DStartAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
815 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
817 #if ENABLE_BLE_TRIGGERED_BONJOUR
818 // BLE support currently not handled by a D2D plugin
819 if (applyToBLE(resourceRecord
->InterfaceID
, flags
))
823 DomainnameToLower(resourceRecord
->name
, &lower
);
824 stop_BLE_advertise(&lower
, resourceRecord
->rrtype
, flags
);
827 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
828 internal_stop_advertising_service(resourceRecord
, flags
);
831 mDNSexport
void internal_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
836 D2DTransportType transportType
, excludedTransport
;
837 DomainnameToLower(resourceRecord
->name
, &lower
);
839 LogInfo("%s: %s", __func__
, RRDisplayString(&mDNSStorage
, resourceRecord
));
841 // For SRV records, update packet filter if p2p interface already exists, otherwise,
842 // For SRV records, update packet filter to to remove this port from list
843 if (resourceRecord
->rrtype
== kDNSType_SRV
)
844 mDNSUpdatePacketFilter(resourceRecord
);
846 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
847 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
848 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
850 transportType
= xD2DInterfaceToTransportType(resourceRecord
->InterfaceID
, flags
, & excludedTransport
);
851 if (transportType
== D2DTransportMax
)
854 for (i
= 0; i
< D2DTransportMax
; i
++)
856 if (i
== excludedTransport
) continue;
857 if (D2DStopAdvertisingPairOnTransport
) D2DStopAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
862 if (D2DStopAdvertisingPairOnTransport
) D2DStopAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
866 mDNSexport
void external_start_resolving_service(mDNSInterfaceID InterfaceID
, const domainname
*const fqdn
, DNSServiceFlags flags
)
871 mDNSBool AWDL_used
= false; // whether AWDL was used for this resolve
872 D2DTransportType transportType
, excludedTransport
;
873 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
875 LogInfo("external_start_resolving_service: %##s", fqdn
->c
);
876 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
877 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
878 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
880 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
881 if (transportType
== D2DTransportMax
)
883 // Resolving over all the transports, except for excludedTransport if set.
885 for (i
= 0; i
< D2DTransportMax
; i
++)
887 if (i
== excludedTransport
) continue;
888 if (D2DStartResolvingPairOnTransport
) D2DStartResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
890 if (i
== D2DAWDLTransport
)
896 // Resolving over one specific transport.
897 if (D2DStartResolvingPairOnTransport
) D2DStartResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
899 if (transportType
== D2DAWDLTransport
)
903 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
904 // We only want these records going to AWDL, so use AWDLInterfaceID as the
905 // interface and don't set any other flags.
906 if (AWDL_used
&& AWDLInterfaceID
)
908 LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
909 external_start_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_TXT
, 0);
910 external_start_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_SRV
, 0);
914 mDNSexport
void external_stop_resolving_service(mDNSInterfaceID InterfaceID
, const domainname
*const fqdn
, DNSServiceFlags flags
)
919 mDNSBool AWDL_used
= false; // whether AWDL was used for this resolve
920 D2DTransportType transportType
, excludedTransport
;
921 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
923 LogInfo("external_stop_resolving_service: %##s", fqdn
->c
);
924 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
925 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
926 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
928 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
929 if (transportType
== D2DTransportMax
)
932 for (i
= 0; i
< D2DTransportMax
; i
++)
934 if (i
== excludedTransport
) continue;
935 if (D2DStopResolvingPairOnTransport
) D2DStopResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
937 if (i
== D2DAWDLTransport
)
943 if (D2DStopResolvingPairOnTransport
) D2DStopResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
945 if (transportType
== D2DAWDLTransport
)
949 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
950 // We only want these records going to AWDL, so use AWDLInterfaceID as the
951 // interface and don't set any other flags.
952 if (AWDL_used
&& AWDLInterfaceID
)
954 LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
955 external_stop_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_TXT
, 0);
956 external_stop_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_SRV
, 0);
960 void initializeD2DPlugins(mDNS
*const m
)
962 // We only initialize if mDNSCore successfully initialized.
965 D2DStatus ds
= D2DInitialize(CFRunLoopGetMain(), xD2DServiceCallback
, m
);
966 if (ds
!= kD2DSuccess
)
967 LogMsg("D2DInitialiize failed: %d", ds
);
969 LogMsg("D2DInitialize succeeded");
973 void terminateD2DPlugins(void)
977 D2DStatus ds
= D2DTerminate();
978 if (ds
!= kD2DSuccess
)
979 LogMsg("D2DTerminate failed: %d", ds
);
981 LogMsg("D2DTerminate succeeded");
986 #pragma mark - Unit test support routines
988 // These unit test support routines are called from unittests/ framework
989 // and are not compiled for the mDNSResponder runtime code paths.
991 void D2D_unitTest(void)