blob: c025de7aa53aa1aa3978cf1c0e0f11c327030269 [file] [log] [blame] [edit]
/*
* Copyright (c) 2020-2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Apple Inc. ("Apple") nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "dnssd_clientstub_apple.h"
#include "dns_sd_private.h"
#include "dnssd_clientstub.h"
#include <CoreUtils/CommonServices.h>
#include <CoreUtils/DebugServices.h>
#include <os/lock.h>
#include "mdns_strict.h"
#define kDNSServiceDefaultsKey_RequirePrivacy "require_privacy"
#define kDNSServiceDefaultsKey_ResolverConfigPListData "resolver_config_plist_data"
static xpc_object_t g_defaults_dict = NULL;
static os_unfair_lock g_defaults_lock = OS_UNFAIR_LOCK_INIT;
DNSServiceErrorType DNSSD_API
DNSServiceSetResolverDefaults(const void * const plist_data_ptr, const size_t plist_data_len, bool require_privacy)
{
DNSServiceErrorType err;
require_action_quiet(plist_data_len <= (32 * CUBytesPerKibiByte), exit, err = kDNSServiceErr_Invalid);
const xpc_object_t new_dict = xpc_dictionary_create(NULL, NULL, 0);
require_action_quiet(new_dict, exit, err = kDNSServiceErr_NoMemory);
xpc_dictionary_set_bool(new_dict, kDNSServiceDefaultsKey_RequirePrivacy, require_privacy);
if (plist_data_ptr && (plist_data_len > 0)) {
xpc_dictionary_set_data(new_dict, kDNSServiceDefaultsKey_ResolverConfigPListData, plist_data_ptr,
plist_data_len);
}
os_unfair_lock_lock(&g_defaults_lock);
xpc_object_t old_dict = g_defaults_dict;
g_defaults_dict = new_dict;
os_unfair_lock_unlock(&g_defaults_lock);
xpc_forget(&old_dict);
err = kDNSServiceErr_NoError;
exit:
return err;
}
DNSServiceErrorType DNSSD_API
DNSServiceBrowseEx(DNSServiceRef *sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, const char *regtype, const char *domain, const DNSServiceAttribute * const attr,
DNSServiceBrowseReply callBack, void *context)
{
return DNSServiceBrowseInternal(sdRef, flags, interfaceIndex, regtype, domain, attr, callBack, context);
}
DNSServiceErrorType DNSSD_API
DNSServiceResolveEx(DNSServiceRef *sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, const char *name, const char *regtype, const char *domain,
const DNSServiceAttribute * const attr, DNSServiceResolveReply callBack, void *context)
{
return DNSServiceResolveInternal(sdRef, flags, interfaceIndex, name, regtype, domain, attr, callBack, context);
}
DNSServiceErrorType DNSSD_API
DNSServiceGetAddrInfoEx(DNSServiceRef *sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, DNSServiceProtocol protocol, const char *hostname, const DNSServiceAttribute * const attr,
DNSServiceGetAddrInfoReply callBack, void *context)
{
return DNSServiceGetAddrInfoInternal(sdRef, flags, interfaceIndex, protocol, hostname, attr, callBack, context);
}
DNSServiceErrorType DNSSD_API
DNSServiceQueryRecordEx(DNSServiceRef * const sdRef, const DNSServiceFlags flags, const uint32_t ifindex,
const char * const name, const uint16_t rrtype, const uint16_t rrclass, const DNSServiceAttribute * const attr,
const DNSServiceQueryRecordReply callback, void * const context)
{
return DNSServiceQueryRecordInternal(sdRef, flags, ifindex, name, rrtype, rrclass, attr, callback, context);
}
xpc_object_t
DNSServiceGetRetainedResolverDefaults(void)
{
os_unfair_lock_lock(&g_defaults_lock);
const xpc_object_t dict_copy = g_defaults_dict ? xpc_retain(g_defaults_dict) : NULL;
os_unfair_lock_unlock(&g_defaults_lock);
return dict_copy;
}
DNSServiceAttrRef
DNSServiceAttrCreate(void)
{
return DNSServiceAttributeCreate();
}
void
DNSServiceAttrFree(DNSServiceAttrRef attr)
{
DNSServiceAttributeDeallocate(attr);
}
size_t
get_required_tlv_length_for_defaults(const xpc_object_t defaults)
{
size_t len = 0;
size_t plist_len = 0;
// Add length for IPC_TLV_TYPE_RESOLVER_CONFIG_PLIST_DATA.
if (xpc_dictionary_get_data(defaults, kDNSServiceDefaultsKey_ResolverConfigPListData, &plist_len)) {
len += get_required_tlv_length((uint16_t)plist_len);
}
// Add length for IPC_TLV_TYPE_REQUIRE_PRIVACY.
len += get_required_tlv_uint8_length();
return len;
}
const uint8_t *
get_validation_data_from_tlvs(const uint8_t * const ptr, const uint8_t * const limit, size_t * const length)
{
size_t len = 0;
const uint8_t *const data = get_tlv(ptr, limit, IPC_TLV_TYPE_SERVICE_ATTR_VALIDATION_DATA, &len);
if (length)
{
*length = len;
}
return data;
}
const char *
get_tracker_hostname_from_tlvs(const uint8_t * const ptr, const uint8_t * const limit)
{
return get_tlv_string(ptr, limit, IPC_TLV_TYPE_SERVICE_ATTR_TRACKER_STR);
}
void
put_tlvs_for_defaults(const xpc_object_t defaults, ipc_msg_hdr * const hdr, uint8_t ** const ptr,
const uint8_t * const limit)
{
size_t len = 0;
const uint8_t * const data = xpc_dictionary_get_data(defaults, kDNSServiceDefaultsKey_ResolverConfigPListData,
&len);
if (data) {
put_tlv(IPC_TLV_TYPE_RESOLVER_CONFIG_PLIST_DATA, (uint16_t)len, data, ptr, limit);
}
const uint8_t require_privacy = xpc_dictionary_get_bool(defaults, kDNSServiceDefaultsKey_RequirePrivacy) ? 1 : 0;
put_tlv_uint8(IPC_TLV_TYPE_REQUIRE_PRIVACY, require_privacy, ptr, limit);
hdr->ipc_flags |= IPC_FLAGS_TRAILING_TLVS;
}