mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-06-05 17:00:21 +08:00

The sources can be obtained via: https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-765.1.2.tar.gz Move mDNS_StartResolveService() and mDNS_StopResolveService() to an RTEMS-specific file (rtemsbsd/mdns/mDNSResolveService.c) using the v576.30.4 implementation. Apple removed these functions without explanation. Update #3522.
672 lines
23 KiB
C
672 lines
23 KiB
C
/* -*- Mode: C; tab-width: 4 -*-
|
|
*
|
|
* Copyright (c) 2007-2012 Apple Inc. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define _FORTIFY_SOURCE 2
|
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
#include <sys/cdefs.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <mach/mach.h>
|
|
#include <mach/mach_error.h>
|
|
#include <servers/bootstrap.h>
|
|
#include <launch.h>
|
|
#include <pwd.h>
|
|
#include <pthread.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <Security/Security.h>
|
|
#include "helper.h"
|
|
#include "helper-server.h"
|
|
#include <xpc/private.h>
|
|
|
|
#if TARGET_OS_EMBEDDED
|
|
#define NO_SECURITYFRAMEWORK 1
|
|
#endif
|
|
|
|
#ifndef LAUNCH_JOBKEY_MACHSERVICES
|
|
#define LAUNCH_JOBKEY_MACHSERVICES "MachServices"
|
|
#define LAUNCH_DATA_MACHPORT 10
|
|
#define launch_data_get_machport launch_data_get_fd
|
|
#endif
|
|
|
|
|
|
int mDNSHelperLogEnabled = 0;
|
|
os_log_t log_handle = NULL;
|
|
|
|
static dispatch_queue_t xpc_queue = NULL;
|
|
static int opt_debug;
|
|
static pthread_t idletimer_thread;
|
|
|
|
unsigned long maxidle = 15;
|
|
unsigned long actualidle = 3600;
|
|
|
|
CFRunLoopRef gRunLoop = NULL;
|
|
CFRunLoopTimerRef gTimer = NULL;
|
|
|
|
|
|
static void handle_sigterm(int sig)
|
|
{
|
|
// os_log_debug(log_handle,"entry sig=%d", sig); Can't use syslog from within a signal handler
|
|
assert(sig == SIGTERM);
|
|
helper_exit();
|
|
}
|
|
|
|
static void initialize_logging(void)
|
|
{
|
|
log_handle = os_log_create("com.apple.mDNSResponderHelper", "INFO");
|
|
|
|
if (!log_handle)
|
|
{
|
|
// OS_LOG_DEFAULT is the default logging object, if you are not creating a custom subsystem/category
|
|
os_log_error(OS_LOG_DEFAULT, "Could NOT create log handle in mDNSResponderHelper");
|
|
}
|
|
|
|
}
|
|
|
|
static void initialize_id(void)
|
|
{
|
|
static char login[] = "_mdnsresponder";
|
|
struct passwd hardcode;
|
|
struct passwd *pwd = &hardcode; // getpwnam(login);
|
|
hardcode.pw_uid = 65;
|
|
hardcode.pw_gid = 65;
|
|
|
|
if (!pwd)
|
|
{
|
|
os_log(log_handle, "Could not find account name `%s'. I will only help root.", login);
|
|
return;
|
|
}
|
|
mDNSResponderUID = pwd->pw_uid;
|
|
mDNSResponderGID = pwd->pw_gid;
|
|
}
|
|
|
|
static void diediedie(CFRunLoopTimerRef timer, void *context)
|
|
{
|
|
os_log_info(log_handle, "entry %p %p %lu", timer, context, actualidle);
|
|
|
|
assert(gTimer == timer);
|
|
os_log_info(log_handle, "mDNSResponderHelper exiting after [%lu] seconds", actualidle);
|
|
|
|
if (actualidle)
|
|
helper_exit();
|
|
}
|
|
|
|
void pause_idle_timer(void)
|
|
{
|
|
os_log_debug(log_handle,"entry");
|
|
assert(gTimer);
|
|
assert(gRunLoop);
|
|
CFRunLoopRemoveTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode);
|
|
}
|
|
|
|
void unpause_idle_timer(void)
|
|
{
|
|
os_log_debug(log_handle,"entry");
|
|
assert(gRunLoop);
|
|
assert(gTimer);
|
|
CFRunLoopAddTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode);
|
|
}
|
|
|
|
void update_idle_timer(void)
|
|
{
|
|
os_log_debug(log_handle,"entry");
|
|
assert(gTimer);
|
|
CFRunLoopTimerSetNextFireDate(gTimer, CFAbsoluteTimeGetCurrent() + actualidle);
|
|
}
|
|
|
|
static void *idletimer(void *context)
|
|
{
|
|
os_log_debug(log_handle,"entry context=%p", context);
|
|
gRunLoop = CFRunLoopGetMain();
|
|
|
|
unpause_idle_timer();
|
|
|
|
for (;;)
|
|
{
|
|
// os_log_debug(log_handle,"Running CFRunLoop");
|
|
CFRunLoopRun();
|
|
sleep(1);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int initialize_timer()
|
|
{
|
|
gTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + actualidle, actualidle, 0, 0, diediedie, NULL);
|
|
int err = 0;
|
|
os_log_info(log_handle, "mDNSResponderHelper initialize_timer() started");
|
|
|
|
if (0 != (err = pthread_create(&idletimer_thread, NULL, idletimer, NULL)))
|
|
os_log(log_handle, "Could not start idletimer thread: %s", strerror(err));
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
Reads the user's program arguments for mDNSResponderHelper
|
|
For now we have only one option: mDNSHelperDebugLogging which is used to turn on mDNSResponderHelperLogging
|
|
|
|
To turn ON mDNSResponderHelper Verbose Logging,
|
|
1] sudo defaults write /Library/Preferences/com.apple.mDNSResponderHelper.plist mDNSHelperDebugLogging -bool YES
|
|
2] sudo reboot
|
|
|
|
To turn OFF mDNSResponderHelper Logging,
|
|
1] sudo defaults delete /Library/Preferences/com.apple.mDNSResponderHelper.plist
|
|
|
|
To view the current options set,
|
|
1] plutil -p /Library/Preferences/com.apple.mDNSResponderHelper.plist
|
|
OR
|
|
1] sudo defaults read /Library/Preferences/com.apple.mDNSResponderHelper.plist
|
|
*/
|
|
|
|
static mDNSBool HelperPrefsGetValueBool(CFStringRef key, mDNSBool defaultVal)
|
|
{
|
|
CFBooleanRef boolean;
|
|
mDNSBool result = defaultVal;
|
|
|
|
boolean = CFPreferencesCopyAppValue(key, kmDNSHelperProgramArgs);
|
|
if (boolean)
|
|
{
|
|
if (CFGetTypeID(boolean) == CFBooleanGetTypeID())
|
|
result = CFBooleanGetValue(boolean) ? mDNStrue : mDNSfalse;
|
|
CFRelease(boolean);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
// Verify Client's Entitlement
|
|
static mDNSBool check_entitlement(xpc_connection_t conn, const char *password)
|
|
{
|
|
mDNSBool entitled = mDNSfalse;
|
|
xpc_object_t ent = xpc_connection_copy_entitlement_value(conn, password);
|
|
|
|
if (ent)
|
|
{
|
|
if (xpc_get_type(ent) == XPC_TYPE_BOOL && xpc_bool_get_value(ent))
|
|
{
|
|
entitled = mDNStrue;
|
|
}
|
|
xpc_release(ent);
|
|
}
|
|
else
|
|
{
|
|
os_log(log_handle, "client entitlement is NULL");
|
|
}
|
|
|
|
if (!entitled)
|
|
os_log(log_handle, "entitlement check failed -> client is missing entitlement!");
|
|
|
|
return entitled;
|
|
}
|
|
|
|
|
|
static void handle_request(xpc_object_t req)
|
|
{
|
|
mDNSu32 helper_mode = 0;
|
|
int error_code = 0;
|
|
|
|
xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req);
|
|
xpc_object_t response = xpc_dictionary_create_reply(req);
|
|
|
|
// switch here based on dictionary to handle different requests from mDNSResponder
|
|
if ((xpc_dictionary_get_uint64(req, kHelperMode)))
|
|
{
|
|
os_log_info(log_handle, "Getting mDNSResponder request mode");
|
|
helper_mode = (mDNSu32)(xpc_dictionary_get_uint64(req, kHelperMode));
|
|
}
|
|
|
|
switch (helper_mode)
|
|
{
|
|
case bpf_request:
|
|
{
|
|
os_log_info(log_handle, "Calling new RequestBPF()");
|
|
RequestBPF();
|
|
break;
|
|
}
|
|
|
|
case set_name:
|
|
{
|
|
const char *old_name;
|
|
const char *new_name;
|
|
int pref_key = 0;
|
|
|
|
pref_key = (int)(xpc_dictionary_get_uint64(req, kPrefsNameKey));
|
|
old_name = xpc_dictionary_get_string(req, kPrefsOldName);
|
|
new_name = xpc_dictionary_get_string(req, kPrefsNewName);
|
|
|
|
os_log_info(log_handle, "Calling new SetName() oldname: %s newname: %s key:%d", old_name, new_name, pref_key);
|
|
PreferencesSetName(pref_key, old_name, new_name);
|
|
break;
|
|
}
|
|
|
|
case p2p_packetfilter:
|
|
{
|
|
pfArray_t pfports;
|
|
pfArray_t pfprotocols;
|
|
const char *if_name;
|
|
uint32_t cmd;
|
|
uint32_t count;
|
|
|
|
cmd = xpc_dictionary_get_uint64(req, "pf_opcode");
|
|
if_name = xpc_dictionary_get_string(req, "pf_ifname");
|
|
count = xpc_dictionary_get_uint64(req, "pf_count");
|
|
|
|
pfports[0] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port0");
|
|
pfports[1] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port1");
|
|
pfports[2] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port2");
|
|
pfports[3] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port3");
|
|
|
|
pfprotocols[0] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol0");
|
|
pfprotocols[1] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol1");
|
|
pfprotocols[2] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol2");
|
|
pfprotocols[3] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol3");
|
|
|
|
os_log_info(log_handle,"Calling new PacketFilterControl()");
|
|
PacketFilterControl(cmd, if_name, count, pfports, pfprotocols);
|
|
break;
|
|
}
|
|
|
|
case user_notify:
|
|
{
|
|
const char *title;
|
|
const char *msg;
|
|
title = xpc_dictionary_get_string(req, "notify_title");
|
|
msg = xpc_dictionary_get_string(req, "notify_msg");
|
|
|
|
os_log_info(log_handle,"Calling new UserNotify() title:%s msg:%s", title, msg);
|
|
UserNotify(title, msg);
|
|
break;
|
|
}
|
|
|
|
case power_req:
|
|
{
|
|
int key, interval;
|
|
key = xpc_dictionary_get_uint64(req, "powerreq_key");
|
|
interval = xpc_dictionary_get_uint64(req, "powerreq_interval");
|
|
|
|
os_log_info(log_handle,"Calling new PowerRequest() key[%d] interval[%d]", key, interval);
|
|
PowerRequest(key, interval, &error_code);
|
|
break;
|
|
}
|
|
|
|
case send_wakepkt:
|
|
{
|
|
const char *ether_addr;
|
|
const char *ip_addr;
|
|
int iteration;
|
|
unsigned int if_id;
|
|
|
|
if_id = (unsigned int)xpc_dictionary_get_uint64(req, "interface_index");
|
|
ether_addr = xpc_dictionary_get_string(req, "ethernet_address");
|
|
ip_addr = xpc_dictionary_get_string(req, "ip_address");
|
|
iteration = (int)xpc_dictionary_get_uint64(req, "swp_iteration");
|
|
|
|
os_log_info(log_handle, "Calling new SendWakeupPacket() ether_addr[%s] ip_addr[%s] if_id[%d] iteration[%d]",
|
|
ether_addr, ip_addr, if_id, iteration);
|
|
SendWakeupPacket(if_id, ether_addr, ip_addr, iteration);
|
|
break;
|
|
}
|
|
|
|
case set_localaddr_cacheentry:
|
|
{
|
|
int if_index, family;
|
|
|
|
if_index = xpc_dictionary_get_uint64(req, "slace_ifindex");
|
|
family = xpc_dictionary_get_uint64(req, "slace_family");
|
|
|
|
const uint8_t* ip = xpc_dictionary_get_data(req, "slace_ip", NULL);
|
|
const uint8_t* eth = xpc_dictionary_get_data(req, "slace_eth", NULL);
|
|
|
|
os_log_info(log_handle, "Calling new SetLocalAddressCacheEntry() if_index[%d] family[%d] ", if_index, family);
|
|
|
|
SetLocalAddressCacheEntry(if_index, family, ip, eth, &error_code);
|
|
|
|
/*
|
|
static int v6addr_to_string(const v6addr_t addr, char *buf, size_t buflen)
|
|
{
|
|
if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
|
|
{
|
|
os_log(log_handle, "inet_ntop failed: %s", strerror(errno));
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ethaddr_t eth = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } ;
|
|
const uint8_t* slace_ip = NULL;
|
|
v6addr_t addr_ipv6;
|
|
size_t ip_len;
|
|
slace_ip = xpc_dictionary_get_data(req, "slace_ip", &ip_len);
|
|
if (slace_ip && (ip_len == sizeof(v6addr_t)))
|
|
{
|
|
os_log(log_handle, "mDNSResponderHelper: doing memcpy()");
|
|
memcpy(&addr_ipv6, slace_ip, ip_len);
|
|
}
|
|
char test_ipv6_str[46];
|
|
v6addr_to_string(addr_ipv6, test_ipv6_str, sizeof(test_ipv6_str));
|
|
os_log(log_handle, "mDNSResponderHelper: handle_request: set_localaddr_cacheentry: test_ipv6_str is %s", test_ipv6_str);
|
|
*/
|
|
|
|
break;
|
|
}
|
|
|
|
case send_keepalive:
|
|
{
|
|
uint16_t lport, rport, win;
|
|
uint32_t seq, ack;
|
|
|
|
lport = xpc_dictionary_get_uint64(req, "send_keepalive_lport");
|
|
rport = xpc_dictionary_get_uint64(req, "send_keepalive_rport");
|
|
seq = xpc_dictionary_get_uint64(req, "send_keepalive_seq");
|
|
ack = xpc_dictionary_get_uint64(req, "send_keepalive_ack");
|
|
win = xpc_dictionary_get_uint64(req, "send_keepalive_win");
|
|
|
|
const uint8_t* sadd6 = xpc_dictionary_get_data(req, "send_keepalive_sadd", NULL);
|
|
const uint8_t* dadd6 = xpc_dictionary_get_data(req, "send_keepalive_dadd", NULL);
|
|
|
|
os_log_info(log_handle, "helper-main: handle_request: send_keepalive: lport is[%d] rport is[%d] seq is[%d] ack is[%d] win is[%d]",
|
|
lport, rport, seq, ack, win);
|
|
|
|
SendKeepalive(sadd6, dadd6, lport, rport, seq, ack, win);
|
|
break;
|
|
}
|
|
|
|
case retreive_tcpinfo:
|
|
{
|
|
uint16_t lport, rport;
|
|
int family;
|
|
uint32_t seq, ack;
|
|
uint16_t win;
|
|
int32_t intfid;
|
|
|
|
lport = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_lport");
|
|
rport = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_rport");
|
|
family = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_family");
|
|
|
|
const uint8_t* laddr = xpc_dictionary_get_data(req, "retreive_tcpinfo_laddr", NULL);
|
|
const uint8_t* raddr = xpc_dictionary_get_data(req, "retreive_tcpinfo_raddr", NULL);
|
|
|
|
os_log_info(log_handle, "helper-main: handle_request: retreive_tcpinfo: lport is[%d] rport is[%d] family is [%d]",
|
|
lport, rport, family);
|
|
|
|
RetrieveTCPInfo(family, laddr, lport, raddr, rport, &seq, &ack, &win, &intfid, &error_code);
|
|
|
|
if (response)
|
|
{
|
|
xpc_dictionary_set_uint64(response, "retreive_tcpinfo_seq", seq);
|
|
xpc_dictionary_set_uint64(response, "retreive_tcpinfo_ack", ack);
|
|
xpc_dictionary_set_uint64(response, "retreive_tcpinfo_win", win);
|
|
xpc_dictionary_set_uint64(response, "retreive_tcpinfo_ifid", intfid);
|
|
}
|
|
|
|
os_log_info(log_handle, "helper-main: handle_request: retreive_tcpinfo: seq is[%d] ack is[%d] win is [%d] intfid is [%d]",
|
|
seq, ack, win, intfid);
|
|
|
|
break;
|
|
}
|
|
|
|
case autotunnel_setkeys:
|
|
{
|
|
uint16_t lport, rport;
|
|
int replace_del;
|
|
const char *fqdnstr;
|
|
|
|
lport = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_lport");
|
|
rport = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_rport");
|
|
replace_del = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_repdel");
|
|
|
|
const uint8_t* local_inner = xpc_dictionary_get_data(req, "autotunnelsetkeys_localinner", NULL);
|
|
const uint8_t* local_outer = xpc_dictionary_get_data(req, "autotunnelsetkeys_localouter", NULL);
|
|
const uint8_t* remote_inner = xpc_dictionary_get_data(req, "autotunnelsetkeys_remoteinner", NULL);
|
|
const uint8_t* remote_outer = xpc_dictionary_get_data(req, "autotunnelsetkeys_remoteouter", NULL);
|
|
|
|
fqdnstr = xpc_dictionary_get_string(req, "autotunnelsetkeys_fqdnStr");
|
|
|
|
os_log_info(log_handle, "helper-main: handle_request: autotunnel_setkeys: lport is[%d] rport is[%d] replace_del is [%d]",
|
|
lport, rport, replace_del);
|
|
|
|
|
|
HelperAutoTunnelSetKeys(replace_del, local_inner, local_outer, lport, remote_inner, remote_outer, rport, fqdnstr, &error_code);
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case keychain_getsecrets:
|
|
{
|
|
unsigned int num_sec = 0;
|
|
unsigned long secrets = 0;
|
|
unsigned int sec_cnt = 0;
|
|
|
|
os_log_info(log_handle,"Calling new KeyChainGetSecrets()");
|
|
|
|
KeychainGetSecrets(&num_sec, &secrets, &sec_cnt, &error_code);
|
|
|
|
if (response)
|
|
{
|
|
xpc_dictionary_set_uint64(response, "keychain_num_secrets", num_sec);
|
|
xpc_dictionary_set_data(response, "keychain_secrets", (void *)secrets, sec_cnt);
|
|
xpc_dictionary_set_uint64(response, "keychain_secrets_count", sec_cnt);
|
|
}
|
|
|
|
os_log_info(log_handle,"helper-main: handle_request: keychain_getsecrets: num_secrets is %d, secrets is %lu, secrets_Cnt is %d",
|
|
num_sec, secrets, sec_cnt);
|
|
|
|
if (secrets)
|
|
vm_deallocate(mach_task_self(), secrets, sec_cnt);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
os_log(log_handle, "handle_request: Unrecognized mode!");
|
|
error_code = kHelperErr_UndefinedMode;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return Response Status back to the client (essentially ACKing the request)
|
|
if (response)
|
|
{
|
|
xpc_dictionary_set_uint64(response, kHelperReplyStatus, kHelperReply_ACK);
|
|
xpc_dictionary_set_int64(response, kHelperErrCode, error_code);
|
|
xpc_connection_send_message(remote_conn, response);
|
|
xpc_release(response);
|
|
}
|
|
else
|
|
{
|
|
os_log(log_handle, "handle_requests: Response Dictionary could not be created!");
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
static void accept_client(xpc_connection_t conn)
|
|
{
|
|
int c_pid = xpc_connection_get_pid(conn);
|
|
|
|
if (!(check_entitlement(conn, kHelperService)))
|
|
{
|
|
os_log(log_handle, "accept_client: Helper Client PID[%d] is missing Entitlement. Cancelling connection", c_pid);
|
|
xpc_connection_cancel(conn);
|
|
return;
|
|
}
|
|
|
|
xpc_retain(conn);
|
|
xpc_connection_set_target_queue(conn, xpc_queue);
|
|
xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg)
|
|
{
|
|
xpc_type_t type = xpc_get_type(req_msg);
|
|
|
|
if (type == XPC_TYPE_DICTIONARY)
|
|
{
|
|
os_log_info(log_handle,"accept_client:conn:[%p] client[%d](mDNSResponder) requesting service", (void *) conn, c_pid);
|
|
handle_request(req_msg);
|
|
}
|
|
else // We hit this case ONLY if Client Terminated Connection OR Crashed
|
|
{
|
|
os_log(log_handle, "accept_client:conn:[%p] client[%d](mDNSResponder) teared down the connection (OR Crashed)", (void *) conn, c_pid);
|
|
// handle_termination();
|
|
xpc_release(conn);
|
|
}
|
|
});
|
|
|
|
xpc_connection_resume(conn);
|
|
}
|
|
|
|
|
|
static void init_helper_service(const char *service_name)
|
|
{
|
|
|
|
xpc_connection_t xpc_listener = xpc_connection_create_mach_service(service_name, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
|
|
if (!xpc_listener || xpc_get_type(xpc_listener) != XPC_TYPE_CONNECTION)
|
|
{
|
|
os_log(log_handle, "init_helper_service: Error Creating XPC Listener for mDNSResponderHelperService !!");
|
|
return;
|
|
}
|
|
|
|
os_log_info(log_handle,"init_helper_service: XPC Listener for mDNSResponderHelperService Listening");
|
|
|
|
xpc_queue = dispatch_queue_create("com.apple.mDNSHelper.service_queue", NULL);
|
|
|
|
xpc_connection_set_event_handler(xpc_listener, ^(xpc_object_t eventmsg)
|
|
{
|
|
xpc_type_t type = xpc_get_type(eventmsg);
|
|
|
|
if (type == XPC_TYPE_CONNECTION)
|
|
{
|
|
os_log_info(log_handle,"init_helper_service: new mDNSResponderHelper Client %p", eventmsg);
|
|
accept_client(eventmsg);
|
|
}
|
|
else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases below
|
|
{
|
|
os_log(log_handle, "init_helper_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
os_log(log_handle, "init_helper_service: Unknown EventMsg type");
|
|
return;
|
|
}
|
|
});
|
|
|
|
xpc_connection_resume(xpc_listener);
|
|
}
|
|
|
|
|
|
int main(int ac, char *av[])
|
|
{
|
|
char *p = NULL;
|
|
long n;
|
|
int ch;
|
|
|
|
while ((ch = getopt(ac, av, "dt:")) != -1)
|
|
{
|
|
switch (ch)
|
|
{
|
|
case 'd':
|
|
opt_debug = 1;
|
|
break;
|
|
case 't':
|
|
n = strtol(optarg, &p, 0);
|
|
if ('\0' == optarg[0] || '\0' != *p || n > LONG_MAX || n < 0)
|
|
{
|
|
fprintf(stderr, "Invalid idle timeout: %s\n", optarg);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
maxidle = n;
|
|
break;
|
|
case '?':
|
|
default:
|
|
fprintf(stderr, "Usage: mDNSResponderHelper [-d] [-t maxidle]\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
ac -= optind;
|
|
av += optind;
|
|
(void)ac; // Unused
|
|
(void)av; // Unused
|
|
|
|
initialize_logging();
|
|
initialize_id();
|
|
|
|
mDNSHelperLogEnabled = HelperPrefsGetValueBool(kPreferencesKey_mDNSHelperLog, mDNSHelperLogEnabled);
|
|
|
|
// Currently on Fuji/Whitetail releases we are keeping the logging always enabled.
|
|
// Hence mDNSHelperLogEnabled is set to true below by default.
|
|
mDNSHelperLogEnabled = 1;
|
|
|
|
os_log_info(log_handle,"mDNSResponderHelper Starting to run");
|
|
|
|
#ifndef NO_SECURITYFRAMEWORK
|
|
// We should normally be running as a system daemon. However, that might not be the case in some scenarios (e.g. debugging).
|
|
// Explicitly ensure that our Keychain operations utilize the system domain.
|
|
if (opt_debug)
|
|
SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
|
|
#endif
|
|
|
|
if (maxidle)
|
|
actualidle = maxidle;
|
|
|
|
signal(SIGTERM, handle_sigterm);
|
|
|
|
if (initialize_timer())
|
|
exit(EXIT_FAILURE);
|
|
for (n=0; n<100000; n++)
|
|
if (!gRunLoop)
|
|
usleep(100);
|
|
|
|
if (!gRunLoop)
|
|
{
|
|
os_log(log_handle, "gRunLoop not set after waiting");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
init_helper_service(kHelperService);
|
|
os_log_info(log_handle,"mDNSResponderHelper is now running");
|
|
dispatch_main();
|
|
|
|
}
|
|
|
|
// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
|
|
// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
|
|
// To expand "version" to its value before making the string, use STRINGIFY(version) instead
|
|
#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s
|
|
#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
|
|
|
|
// For convenience when using the "strings" command, this is the last thing in the file
|
|
// The "@(#) " pattern is a special prefix the "what" command looks for
|
|
const char VersionString_SCCS[] = "@(#) mDNSResponderHelper " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
|
|
|
|
#if _BUILDING_XCODE_PROJECT_
|
|
// If the process crashes, then this string will be magically included in the automatically-generated crash log
|
|
const char *__crashreporter_info__ = VersionString_SCCS + 5;
|
|
asm (".desc ___crashreporter_info__, 0x10");
|
|
#endif
|