1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2018 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
);
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
= mDNSPlatformMemAllocate(sizeof(**ptr
));
249 mDNSPlatformMemZero(*ptr
, sizeof(**ptr
));
251 AssignDomainName(&(*ptr
)->name
, name
);
253 (*ptr
)->refCount
+= 1;
255 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
258 // Returns true if found in list, false otherwise
259 mDNSlocal
bool D2DBrowseListRelease(const domainname
*const name
, mDNSu16 type
)
261 D2DBrowseListElem
**ptr
= D2DFindInBrowseList(name
, type
);
263 if (!*ptr
) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name
->c
, DNSTypeName(type
)); return false; }
265 (*ptr
)->refCount
-= 1;
267 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
269 if (!(*ptr
)->refCount
)
271 D2DBrowseListElem
*tmp
= *ptr
;
273 mDNSPlatformMemFree(tmp
);
278 mDNSlocal mStatus
xD2DParse(const mDNSu8
* const lhs
, const mDNSu16 lhs_len
, const mDNSu8
* const rhs
, const mDNSu16 rhs_len
, D2DRecordListElem
**D2DListp
)
280 mDNS
*const m
= &mDNSStorage
;
282 // Sanity check that key array (lhs) has one domain name, followed by the record type and single byte D2D
283 // plugin protocol version number.
284 // Note, we don't have a DNSMessage pointer at this point, so just pass in the lhs value as the lower bound
285 // of the input bytes we are processing. skipDomainName() does not try to follow name compression pointers,
286 // so it is safe to pass it the key byte array since it will stop parsing the DNS name and return a pointer
287 // to the byte after the first name compression pointer it encounters.
288 const mDNSu8
*keyp
= skipDomainName((const DNSMessage
*const) lhs
, lhs
, lhs
+ lhs_len
);
290 // There should be 3 bytes remaining in a valid key,
291 // two for the DNS record type, and one for the D2D protocol version number.
292 if (keyp
== NULL
|| (keyp
+ 3 != (lhs
+ lhs_len
)))
294 LogInfo("xD2DParse: Could not parse DNS name in key");
295 return mStatus_Incompatible
;
297 keyp
+= 2; // point to D2D compression packet format version byte
298 if (*keyp
!= compression_packet_v1
)
300 LogInfo("xD2DParse: Invalid D2D packet version: %d", *keyp
);
301 return mStatus_Incompatible
;
304 if (mDNS_LoggingEnabled
)
306 const int len
= (int)(compression_lhs
- (mDNSu8
*)&compression_base_msg
);
307 LogInfo("xD2DParse: Static Bytes: (%d bytes) %.*H", len
, len
, &compression_base_msg
);
310 mDNSu8
*ptr
= compression_lhs
; // pointer to the end of our fake packet
312 // Check to make sure we're not going to go past the end of the DNSMessage data
313 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
314 if (ptr
+ lhs_len
- 7 + rhs_len
>= compression_limit
) return mStatus_NoMemoryErr
;
316 // Copy the LHS onto our fake wire packet
317 mDNSPlatformMemCopy(ptr
, lhs
, lhs_len
);
320 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
321 if (*ptr
!= compression_packet_v1
) return mStatus_Incompatible
;
323 // two bytes of CLASS
324 ptr
= putVal16(ptr
, kDNSClass_IN
| kDNSClass_UniqueRRSet
);
327 ptr
= putVal32(ptr
, 120);
329 // Copy the RHS length into the RDLENGTH of our fake wire packet
330 ptr
= putVal16(ptr
, rhs_len
);
332 // Copy the RHS onto our fake wire packet
333 mDNSPlatformMemCopy(ptr
, rhs
, rhs_len
);
336 if (mDNS_LoggingEnabled
)
338 const int len
= (int)(ptr
- compression_lhs
);
339 LogInfo("xD2DParse: Our Bytes (%d bytes): %.*H", len
, len
, compression_lhs
);
342 ptr
= (mDNSu8
*) GetLargeResourceRecord(m
, &compression_base_msg
, compression_lhs
, ptr
, mDNSInterface_Any
, kDNSRecordTypePacketAns
, &m
->rec
);
343 if (!ptr
|| m
->rec
.r
.resrec
.RecordType
== kDNSRecordTypePacketNegative
)
345 LogMsg("xD2DParse: failed to get large RR");
346 m
->rec
.r
.resrec
.RecordType
= 0;
347 return mStatus_UnknownErr
;
351 LogInfo("xD2DParse: got rr: %s", CRDisplayString(m
, &m
->rec
.r
));
354 *D2DListp
= mDNSPlatformMemAllocate(sizeof(D2DRecordListElem
) + (m
->rec
.r
.resrec
.rdlength
<= sizeof(RDataBody
) ? 0 : m
->rec
.r
.resrec
.rdlength
- sizeof(RDataBody
)));
355 if (!*D2DListp
) return mStatus_NoMemoryErr
;
357 AuthRecord
*rr
= &(*D2DListp
)->ar
;
358 mDNS_SetupResourceRecord(rr
, mDNSNULL
, mDNSInterface_P2P
, m
->rec
.r
.resrec
.rrtype
, 7200, kDNSRecordTypeShared
, AuthRecordP2P
, FreeD2DARElemCallback
, NULL
);
359 AssignDomainName(&rr
->namestorage
, &m
->rec
.namestorage
);
360 rr
->resrec
.rdlength
= m
->rec
.r
.resrec
.rdlength
;
361 rr
->resrec
.rdata
->MaxRDLength
= m
->rec
.r
.resrec
.rdlength
;
362 mDNSPlatformMemCopy(rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
);
363 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
364 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Sets rr->rdatahash for us
366 m
->rec
.r
.resrec
.RecordType
= 0; // Mark m->rec as no longer in use
368 return mStatus_NoError
;
371 mDNSexport
void xD2DAddToCache(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
373 mDNS
*const m
= &mDNSStorage
;
374 if (result
== kD2DSuccess
)
376 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
379 D2DRecordListElem
*ptr
= NULL
;
381 err
= xD2DParse((const mDNSu8
* const)key
, (const mDNSu16
)keySize
, (const mDNSu8
* const)value
, (const mDNSu16
)valueSize
, &ptr
);
384 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err
);
385 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
387 mDNSPlatformMemFree(ptr
);
391 #if ENABLE_BLE_TRIGGERED_BONJOUR
392 // If the record was created based on a BLE beacon, update the interface index to indicate
393 // this and thus match BLE specific queries.
394 if (transportType
== D2DBLETransport
)
395 ptr
->ar
.resrec
.InterfaceID
= mDNSInterface_BLE
;
396 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
398 err
= mDNS_Register(m
, &ptr
->ar
);
401 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err
, ARDisplayString(m
, &ptr
->ar
));
402 mDNSPlatformMemFree(ptr
);
406 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m
, &ptr
->ar
));
407 ptr
->instanceHandle
= instanceHandle
;
408 ptr
->transportType
= transportType
;
409 ptr
->next
= D2DRecords
;
413 LogMsg("xD2DAddToCache: Unexpected result %d", result
);
416 mDNSlocal D2DRecordListElem
* xD2DFindInList(const Byte
*const key
, const size_t keySize
, const Byte
*const value
, const size_t valueSize
)
418 D2DRecordListElem
*ptr
= D2DRecords
;
419 D2DRecordListElem
*arptr
= NULL
;
421 if ( key
== NULL
|| value
== NULL
|| keySize
== 0 || valueSize
== 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL
; }
423 mStatus err
= xD2DParse((const mDNSu8
*const)key
, (const mDNSu16
)keySize
, (const mDNSu8
*const)value
, (const mDNSu16
)valueSize
, &arptr
);
426 LogMsg("xD2DFindInList: xD2DParse returned error: %d", err
);
427 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
429 mDNSPlatformMemFree(arptr
);
435 if (IdenticalResourceRecord(&arptr
->ar
.resrec
, &ptr
->ar
.resrec
)) break;
439 if (!ptr
) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(&mDNSStorage
, &arptr
->ar
));
440 mDNSPlatformMemFree(arptr
);
444 mDNSexport
void xD2DRemoveFromCache(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
446 (void)transportType
; // We don't care about this, yet.
447 (void)instanceHandle
; // We don't care about this, yet.
449 if (result
== kD2DSuccess
)
451 D2DRecordListElem
*ptr
= xD2DFindInList(key
, keySize
, value
, valueSize
);
454 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(&mDNSStorage
, &ptr
->ar
));
455 mDNS_Deregister(&mDNSStorage
, &ptr
->ar
);
459 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result
);
462 mDNSlocal
void xD2DServiceResolved(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
469 if (result
== kD2DSuccess
)
471 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle
);
472 if (D2DRetain
) D2DRetain(instanceHandle
, transportType
);
474 else LogMsg("xD2DServiceResolved: Unexpected result %d", result
);
477 mDNSlocal
void xD2DRetainHappened(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
479 (void)instanceHandle
;
486 if (result
== kD2DSuccess
) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle
);
487 else LogMsg("xD2DRetainHappened: Unexpected result %d", result
);
490 mDNSlocal
void xD2DReleaseHappened(D2DStatus result
, D2DServiceInstance instanceHandle
, D2DTransportType transportType
, const Byte
*key
, size_t keySize
, const Byte
*value
, size_t valueSize
)
492 (void)instanceHandle
;
499 if (result
== kD2DSuccess
) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle
);
500 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result
);
503 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
)
505 const char *eventString
= "unknown";
509 if (keySize
> 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize
);
510 if (valueSize
> 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize
);
514 case D2DServiceFound
:
515 eventString
= "D2DServiceFound";
518 eventString
= "D2DServiceLost";
520 case D2DServiceResolved
:
521 eventString
= "D2DServiceResolved";
523 case D2DServiceRetained
:
524 eventString
= "D2DServiceRetained";
526 case D2DServiceReleased
:
527 eventString
= "D2DServiceReleased";
533 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
);
534 PrintHelper(__func__
, (mDNSu8
*)key
, (mDNSu16
)keySize
, (mDNSu8
*)value
, (mDNSu16
)valueSize
);
538 case D2DServiceFound
:
539 xD2DAddToCache(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
542 xD2DRemoveFromCache(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
544 case D2DServiceResolved
:
545 xD2DServiceResolved(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
547 case D2DServiceRetained
:
548 xD2DRetainHappened(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
550 case D2DServiceReleased
:
551 xD2DReleaseHappened(result
, instanceHandle
, transportType
, key
, keySize
, value
, valueSize
);
557 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
558 KQueueUnlock("xD2DServiceCallback");
561 // Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
563 // When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
564 // will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
565 // If the return value is not D2DTransportMax, excludedTransportType is undefined.
567 mDNSlocal D2DTransportType
xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID
, DNSServiceFlags flags
, D2DTransportType
* excludedTransportType
)
569 NetworkInterfaceInfoOSX
*info
;
571 // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
572 *excludedTransportType
= D2DAWDLTransport
;
574 // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
575 if ((flags
& kDNSServiceFlagsIncludeP2P
) && (flags
& kDNSServiceFlagsIncludeAWDL
))
577 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
578 *excludedTransportType
= D2DTransportMax
;
579 return D2DTransportMax
;
581 // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
582 else if (flags
& kDNSServiceFlagsIncludeP2P
)
584 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
585 return D2DTransportMax
;
587 // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
588 else if (flags
& kDNSServiceFlagsIncludeAWDL
)
590 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
591 return D2DAWDLTransport
;
594 if (InterfaceID
== mDNSInterface_P2P
)
596 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
597 return D2DTransportMax
;
600 // Compare to cached AWDL interface ID.
601 if (AWDLInterfaceID
&& (InterfaceID
== AWDLInterfaceID
))
603 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID
);
604 return D2DAWDLTransport
;
607 info
= IfindexToInterfaceInfoOSX(InterfaceID
);
610 LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID
);
611 return D2DTransportMax
;
614 // Recognize AirDrop specific p2p* interface based on interface name.
615 if (strncmp(info
->ifinfo
.ifname
, "p2p", 3) == 0)
617 LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID
);
618 return D2DWifiPeerToPeerTransport
;
621 // Currently there is no way to identify Bluetooth interface by name,
622 // since they use "en*" based name strings.
624 LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID
);
625 return D2DTransportMax
;
628 mDNSexport
void external_start_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
630 #if ENABLE_BLE_TRIGGERED_BONJOUR
631 // BLE support currently not handled by a D2D plugin
632 if (applyToBLE(InterfaceID
, flags
))
636 DomainnameToLower(typeDomain
, &lower
);
637 // pass in the key and keySize
638 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
639 start_BLE_browse(InterfaceID
, &lower
, qtype
, flags
, compression_lhs
, end
- compression_lhs
);
642 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
643 internal_start_browsing_for_service(InterfaceID
, typeDomain
, qtype
, flags
);
646 mDNSexport
void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
650 DomainnameToLower(typeDomain
, &lower
);
652 if (!D2DBrowseListRefCount(&lower
, qtype
))
654 D2DTransportType transportType
, excludedTransport
;
656 LogInfo("%s: Starting browse for: %##s %s", __func__
, lower
.c
, DNSTypeName(qtype
));
657 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
658 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
660 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
661 if (transportType
== D2DTransportMax
)
664 for (i
= 0; i
< D2DTransportMax
; i
++)
666 if (i
== excludedTransport
) continue;
667 if (D2DStartBrowsingForKeyOnTransport
) D2DStartBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, i
);
672 if (D2DStartBrowsingForKeyOnTransport
) D2DStartBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, transportType
);
675 D2DBrowseListRetain(&lower
, qtype
);
678 mDNSexport
void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
680 #if ENABLE_BLE_TRIGGERED_BONJOUR
681 // BLE support currently not handled by a D2D plugin
682 if (applyToBLE(InterfaceID
, flags
))
686 // If this is the last instance of this browse, clear any cached records recieved for it.
687 // We are not guaranteed to get a D2DServiceLost event for all key, value pairs cached over BLE.
688 DomainnameToLower(typeDomain
, &lower
);
689 if (stop_BLE_browse(InterfaceID
, &lower
, qtype
, flags
))
690 xD2DClearCache(&lower
, qtype
);
693 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
694 internal_stop_browsing_for_service(InterfaceID
, typeDomain
, qtype
, flags
);
697 mDNSexport
void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID
, const domainname
*const typeDomain
, DNS_TypeValues qtype
, DNSServiceFlags flags
)
701 DomainnameToLower(typeDomain
, &lower
);
703 // If found in list and this is the last reference to this browse, remove the key from the D2D plugins.
704 if (D2DBrowseListRelease(&lower
, qtype
) && !D2DBrowseListRefCount(&lower
, qtype
))
706 D2DTransportType transportType
, excludedTransport
;
708 LogInfo("%s: Stopping browse for: %##s %s", __func__
, lower
.c
, DNSTypeName(qtype
));
709 mDNSu8
*end
= DNSNameCompressionBuildLHS(&lower
, qtype
);
710 PrintHelper(__func__
, compression_lhs
, end
- compression_lhs
, mDNSNULL
, 0);
712 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
713 if (transportType
== D2DTransportMax
)
716 for (i
= 0; i
< D2DTransportMax
; i
++)
718 if (i
== excludedTransport
) continue;
719 if (D2DStopBrowsingForKeyOnTransport
) D2DStopBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, i
);
724 if (D2DStopBrowsingForKeyOnTransport
) D2DStopBrowsingForKeyOnTransport(compression_lhs
, end
- compression_lhs
, transportType
);
727 // The D2D driver may not generate the D2DServiceLost event for this key after
728 // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
730 xD2DClearCache(&lower
, qtype
);
734 mDNSexport
void external_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
736 #if ENABLE_BLE_TRIGGERED_BONJOUR
737 if (applyToBLE(resourceRecord
->InterfaceID
, flags
))
741 DomainnameToLower(resourceRecord
->name
, &lower
);
742 start_BLE_advertise(resourceRecord
, &lower
, resourceRecord
->rrtype
, flags
);
745 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
746 internal_start_advertising_service(resourceRecord
, flags
);
749 mDNSexport
void internal_start_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
754 D2DTransportType transportType
, excludedTransport
;
755 DomainnameToLower(resourceRecord
->name
, &lower
);
757 LogInfo("%s: %s", __func__
, RRDisplayString(&mDNSStorage
, resourceRecord
));
759 // For SRV records, update packet filter if p2p interface already exists, otherwise,
760 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
761 if (resourceRecord
->rrtype
== kDNSType_SRV
)
762 mDNSUpdatePacketFilter(NULL
);
764 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
765 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
766 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
768 transportType
= xD2DInterfaceToTransportType(resourceRecord
->InterfaceID
, flags
, & excludedTransport
);
769 if (transportType
== D2DTransportMax
)
772 for (i
= 0; i
< D2DTransportMax
; i
++)
774 if (i
== excludedTransport
) continue;
775 if (D2DStartAdvertisingPairOnTransport
) D2DStartAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
780 if (D2DStartAdvertisingPairOnTransport
) D2DStartAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
784 mDNSexport
void external_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
786 #if ENABLE_BLE_TRIGGERED_BONJOUR
787 // BLE support currently not handled by a D2D plugin
788 if (applyToBLE(resourceRecord
->InterfaceID
, flags
))
792 DomainnameToLower(resourceRecord
->name
, &lower
);
793 stop_BLE_advertise(&lower
, resourceRecord
->rrtype
, flags
);
796 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
797 internal_stop_advertising_service(resourceRecord
, flags
);
800 mDNSexport
void internal_stop_advertising_service(const ResourceRecord
*const resourceRecord
, DNSServiceFlags flags
)
805 D2DTransportType transportType
, excludedTransport
;
806 DomainnameToLower(resourceRecord
->name
, &lower
);
808 LogInfo("%s: %s", __func__
, RRDisplayString(&mDNSStorage
, resourceRecord
));
810 // For SRV records, update packet filter if p2p interface already exists, otherwise,
811 // For SRV records, update packet filter to to remove this port from list
812 if (resourceRecord
->rrtype
== kDNSType_SRV
)
813 mDNSUpdatePacketFilter(resourceRecord
);
815 rhs
= DNSNameCompressionBuildLHS(&lower
, resourceRecord
->rrtype
);
816 end
= DNSNameCompressionBuildRHS(rhs
, resourceRecord
);
817 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
819 transportType
= xD2DInterfaceToTransportType(resourceRecord
->InterfaceID
, flags
, & excludedTransport
);
820 if (transportType
== D2DTransportMax
)
823 for (i
= 0; i
< D2DTransportMax
; i
++)
825 if (i
== excludedTransport
) continue;
826 if (D2DStopAdvertisingPairOnTransport
) D2DStopAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
831 if (D2DStopAdvertisingPairOnTransport
) D2DStopAdvertisingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
835 mDNSexport
void external_start_resolving_service(mDNSInterfaceID InterfaceID
, const domainname
*const fqdn
, DNSServiceFlags flags
)
840 mDNSBool AWDL_used
= false; // whether AWDL was used for this resolve
841 D2DTransportType transportType
, excludedTransport
;
842 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
844 LogInfo("external_start_resolving_service: %##s", fqdn
->c
);
845 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
846 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
847 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
849 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
850 if (transportType
== D2DTransportMax
)
852 // Resolving over all the transports, except for excludedTransport if set.
854 for (i
= 0; i
< D2DTransportMax
; i
++)
856 if (i
== excludedTransport
) continue;
857 if (D2DStartResolvingPairOnTransport
) D2DStartResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
859 if (i
== D2DAWDLTransport
)
865 // Resolving over one specific transport.
866 if (D2DStartResolvingPairOnTransport
) D2DStartResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
868 if (transportType
== D2DAWDLTransport
)
872 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
873 // We only want these records going to AWDL, so use AWDLInterfaceID as the
874 // interface and don't set any other flags.
875 if (AWDL_used
&& AWDLInterfaceID
)
877 LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
878 external_start_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_TXT
, 0);
879 external_start_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_SRV
, 0);
883 mDNSexport
void external_stop_resolving_service(mDNSInterfaceID InterfaceID
, const domainname
*const fqdn
, DNSServiceFlags flags
)
888 mDNSBool AWDL_used
= false; // whether AWDL was used for this resolve
889 D2DTransportType transportType
, excludedTransport
;
890 DomainnameToLower(SkipLeadingLabels(fqdn
, 1), &lower
);
892 LogInfo("external_stop_resolving_service: %##s", fqdn
->c
);
893 rhs
= DNSNameCompressionBuildLHS(&lower
, kDNSType_PTR
);
894 end
= putDomainNameAsLabels(&compression_base_msg
, rhs
, compression_limit
, fqdn
);
895 PrintHelper(__func__
, compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
);
897 transportType
= xD2DInterfaceToTransportType(InterfaceID
, flags
, & excludedTransport
);
898 if (transportType
== D2DTransportMax
)
901 for (i
= 0; i
< D2DTransportMax
; i
++)
903 if (i
== excludedTransport
) continue;
904 if (D2DStopResolvingPairOnTransport
) D2DStopResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, i
);
906 if (i
== D2DAWDLTransport
)
912 if (D2DStopResolvingPairOnTransport
) D2DStopResolvingPairOnTransport(compression_lhs
, rhs
- compression_lhs
, rhs
, end
- rhs
, transportType
);
914 if (transportType
== D2DAWDLTransport
)
918 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
919 // We only want these records going to AWDL, so use AWDLInterfaceID as the
920 // interface and don't set any other flags.
921 if (AWDL_used
&& AWDLInterfaceID
)
923 LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
924 external_stop_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_TXT
, 0);
925 external_stop_browsing_for_service(AWDLInterfaceID
, fqdn
, kDNSType_SRV
, 0);
929 void initializeD2DPlugins(mDNS
*const m
)
931 // We only initialize if mDNSCore successfully initialized.
934 D2DStatus ds
= D2DInitialize(CFRunLoopGetMain(), xD2DServiceCallback
, m
);
935 if (ds
!= kD2DSuccess
)
936 LogMsg("D2DInitialiize failed: %d", ds
);
938 LogMsg("D2DInitialize succeeded");
942 void terminateD2DPlugins(void)
946 D2DStatus ds
= D2DTerminate();
947 if (ds
!= kD2DSuccess
)
948 LogMsg("D2DTerminate failed: %d", ds
);
950 LogMsg("D2DTerminate succeeded");
955 #pragma mark - Unit test support routines
957 // These unit test support routines are called from unittests/ framework
958 // and are not compiled for the mDNSResponder runtime code paths.
960 void D2D_unitTest(void)