#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <dispatch/dispatch.h>
#include <mach/mach.h>
#ifdef VERBOSE_ACTIVITY_LOGGING
#include <os/activity.h>
#endif // VERBOSE_ACTIVITY_LOGGING
#include <xpc/xpc.h>
#ifndef SC_LOG_HANDLE
#include <os/log.h>
#define my_log(__level, __format, ...) os_log(OS_LOG_DEFAULT, __format, ## __VA_ARGS__)
#endif // SC_LOG_HANDLE
#include "libSystemConfiguration_client.h"
#include "dnsinfo.h"
#include "dnsinfo_private.h"
#include "dnsinfo_internal.h"
const char *
dns_configuration_notify_key()
{
const char *key;
key = "com.apple.system.SystemConfiguration.dns_configuration";
return key;
}
#pragma mark -
#pragma mark DNS configuration [dnsinfo] client support
static int dnsinfo_active = 0;
static libSC_info_client_t *dnsinfo_client = NULL;
#ifdef VERBOSE_ACTIVITY_LOGGING
static os_activity_t
__dns_configuration_activity()
{
static os_activity_t activity;
static dispatch_once_t once;
dispatch_once(&once, ^{
activity = os_activity_create("accessing DNS configuration",
OS_ACTIVITY_CURRENT,
OS_ACTIVITY_FLAG_DEFAULT);
});
return activity;
}
#endif // VERBOSE_ACTIVITY_LOGGING
static dispatch_queue_t
__dns_configuration_queue()
{
static dispatch_once_t once;
static dispatch_queue_t q;
dispatch_once(&once, ^{
q = dispatch_queue_create(DNSINFO_SERVICE_NAME, NULL);
});
return q;
}
dns_config_t *
dns_configuration_copy()
{
dns_config_t *dns_config = NULL;
_dns_config_buf_t *dns_config_buf = NULL;
static const char *proc_name = NULL;
xpc_object_t reqdict;
xpc_object_t reply;
if (!libSC_info_available()) {
os_log(OS_LOG_DEFAULT, "*** DNS configuration requested between fork() and exec()");
return NULL;
}
dispatch_sync(__dns_configuration_queue(), ^{
if ((dnsinfo_active++ == 0) || (dnsinfo_client == NULL)) {
static dispatch_once_t once;
static const char *service_name = DNSINFO_SERVICE_NAME;
dispatch_once(&once, ^{
#if DEBUG
const char *name;
name = getenv(service_name);
if (name != NULL) {
service_name = strdup(name);
}
#endif // DEBUG
proc_name = getprogname();
});
dnsinfo_client =
libSC_info_client_create(__dns_configuration_queue(), service_name, "DNS configuration"); if (dnsinfo_client == NULL) {
--dnsinfo_active;
}
}
});
if ((dnsinfo_client == NULL) || !dnsinfo_client->active) {
return NULL;
}
#ifdef VERBOSE_ACTIVITY_LOGGING
os_activity_scope(__dns_configuration_activity());
#endif // VERBOSE_ACTIVITY_LOGGING
reqdict = xpc_dictionary_create(NULL, NULL, 0);
if (proc_name != NULL) {
xpc_dictionary_set_string(reqdict, DNSINFO_PROC_NAME, proc_name);
}
xpc_dictionary_set_int64(reqdict, DNSINFO_REQUEST, DNSINFO_REQUEST_COPY);
reply = libSC_send_message_with_reply_sync(dnsinfo_client, reqdict);
xpc_release(reqdict);
if (reply != NULL) {
const void *dataRef;
size_t dataLen = 0;
dataRef = xpc_dictionary_get_data(reply, DNSINFO_CONFIGURATION, &dataLen);
if ((dataRef != NULL) &&
((dataLen >= sizeof(_dns_config_buf_t)) && (dataLen <= DNS_CONFIG_BUF_MAX))) {
dns_config_buf = _dns_configuration_buffer_create(dataRef, dataLen);
}
xpc_release(reply);
}
if (dns_config_buf != NULL) {
dns_config = _dns_configuration_buffer_expand(dns_config_buf);
if (dns_config == NULL) {
_dns_configuration_buffer_free(&dns_config_buf);
}
}
return dns_config;
}
void
dns_configuration_free(dns_config_t *config)
{
if (config == NULL) {
return; }
dispatch_sync(__dns_configuration_queue(), ^{
if (--dnsinfo_active == 0) {
libSC_info_client_release(dnsinfo_client);
dnsinfo_client = NULL;
}
});
free((void *)config);
return;
}
void
_dns_configuration_ack(dns_config_t *config, const char *bundle_id)
{
#pragma unused(bundle_id)
xpc_object_t reqdict;
if (config == NULL) {
return; }
if ((dnsinfo_client == NULL) || !dnsinfo_client->active) {
return;
}
dispatch_sync(__dns_configuration_queue(), ^{
dnsinfo_active++; });
reqdict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_int64(reqdict, DNSINFO_REQUEST, DNSINFO_REQUEST_ACKNOWLEDGE);
xpc_dictionary_set_uint64(reqdict, DNSINFO_GENERATION, config->generation);
xpc_connection_send_message(dnsinfo_client->connection, reqdict);
xpc_release(reqdict);
return;
}
#ifdef MAIN
int
main(int argc, char **argv)
{
dns_config_t *config;
config = dns_configuration_copy();
if (config != NULL) {
dns_configuration_free(config);
}
exit(0);
}
#endif