1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
6 * Command-line tool using libdns_services.dylib
8 * To build only this tool, copy and paste the following on the command line:
9 * On Apple 64bit Platforms ONLY OSX/iOS:
10 * clang -Wall dnsctl.c /usr/lib/libdns_services.dylib -o dnsctl
18 #include <net/if.h> // if_nametoindex()
20 #include "dns_services.h"
24 //*************************************************************************************************************
26 //*************************************************************************************************************
28 static const char kFilePathSep
= '/';
30 static DNSXConnRef ClientRef
= NULL
;
32 static xpc_connection_t dnsctl_conn
= NULL
;
34 //*************************************************************************************************************
36 //*************************************************************************************************************
38 static void printtimestamp(void)
43 static char new_date
[16];
45 gettimeofday(&tv
, NULL
);
46 localtime_r((time_t*)&tv
.tv_sec
, &tm
);
48 strftime(new_date
, sizeof(new_date
), "%a %d %b %Y", &tm
);
49 //display date only if it has changed
50 if (strncmp(date
, new_date
, sizeof(new_date
)))
52 printf("DATE: ---%s---\n", new_date
);
53 strlcpy(date
, new_date
, sizeof(date
));
55 printf("%2d:%02d:%02d.%03d ", tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, ms
);
58 static void print_usage(const char *arg0
)
60 fprintf(stderr
, "%s USAGE: \n", arg0
);
61 fprintf(stderr
, "%s -DP Enable DNS Proxy with Default Parameters \n", arg0
);
62 fprintf(stderr
, "%s -DP [-o <output interface>] [-i <input interface(s)>] Enable DNS Proxy \n", arg0
);
63 fprintf(stderr
, "%s -L [1/2/3/4] Change mDNSResponder Logging Level \n", arg0
);
64 fprintf(stderr
, "%s -I Print mDNSResponder STATE INFO \n", arg0
);
68 static bool DebugEnabled()
70 return true; // keep this true to debug the XPC msgs
73 static void DebugLog(const char *prefix
, xpc_object_t o
)
78 char *desc
= xpc_copy_description(o
);
79 printf("%s: %s \n", prefix
, desc
);
83 //*************************************************************************************************************
85 //*************************************************************************************************************
88 // DNSXEnableProxy Callback from the Daemon
89 static void dnsproxy_reply(DNSXConnRef connRef
, DNSXErrorType errCode
)
95 case kDNSX_NoError
: printf(" SUCCESS \n");
97 case kDNSX_DaemonNotRunning
: printf(" NO DAEMON \n");
98 DNSXRefDeAlloc(ClientRef
); break;
99 case kDNSX_BadParam
: printf(" BAD PARAMETER \n");
100 DNSXRefDeAlloc(ClientRef
); break;
101 case kDNSX_Busy
: printf(" BUSY \n");
102 DNSXRefDeAlloc(ClientRef
); break;
103 case kDNSX_UnknownErr
:
104 default : printf(" UNKNOWN ERR \n");
105 DNSXRefDeAlloc(ClientRef
); break;
111 //*************************************************************************************************************
113 //*************************************************************************************************************
115 static void Init_Connection(const char *servname
)
117 dnsctl_conn
= xpc_connection_create_mach_service(servname
, dispatch_get_main_queue(), XPC_CONNECTION_MACH_SERVICE_PRIVILEGED
);
119 xpc_connection_set_event_handler(dnsctl_conn
, ^(xpc_object_t event
)
121 printf("InitConnection: [%s] \n", xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
));
124 xpc_connection_resume(dnsctl_conn
);
127 static void SendDictToServer(xpc_object_t msg
)
130 DebugLog("SendDictToServer Sending msg to Daemon", msg
);
132 xpc_connection_send_message_with_reply(dnsctl_conn
, msg
, dispatch_get_main_queue(), ^(xpc_object_t recv_msg
)
134 xpc_type_t type
= xpc_get_type(recv_msg
);
136 if (type
== XPC_TYPE_DICTIONARY
)
138 DebugLog("SendDictToServer Received reply msg from Daemon", recv_msg
);
140 // If we ever want to do something based on the reply of the daemon
141 switch (daemon_status)
150 printf("SendDictToServer Received unexpected reply from daemon [%s]",
151 xpc_dictionary_get_string(recv_msg
, XPC_ERROR_KEY_DESCRIPTION
));
152 DebugLog("SendDictToServer Unexpected Reply contents", recv_msg
);
158 //*************************************************************************************************************
160 int main(int argc
, char **argv
)
162 // Extract program name from argv[0], which by convention contains the path to this executable
163 const char *a0
= strrchr(argv
[0], kFilePathSep
) + 1;
164 if (a0
== (const char *)1)
170 fprintf(stderr
, "%s MUST run as root!!\n", a0
);
173 if ((sizeof(argv
) == 8))
174 printf("dnsctl running in 64-bit mode\n");
175 else if ((sizeof(argv
) == 4))
176 printf("dnsctl running in 32-bit mode\n");
178 // expects atleast one argument
183 if (!strcasecmp(argv
[1], "-DP"))
186 // Default i/p intf is lo0 and o/p intf is primary interface
187 IfIndex Ipintfs
[MaxInputIf
] = {1, 0, 0, 0, 0};
188 IfIndex Opintf
= kDNSIfindexAny
;
192 dispatch_queue_t my_Q
= dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL
);
193 err
= DNSXEnableProxy(&ClientRef
, kDNSProxyEnable
, Ipintfs
, Opintf
, my_Q
, dnsproxy_reply
);
195 fprintf(stderr
, "DNSXEnableProxy returned %d\n", err
);
201 if (!strcmp(argv
[1], "-o"))
203 Opintf
= if_nametoindex(argv
[2]);
205 Opintf
= atoi(argv
[2]);
208 fprintf(stderr
, "Could not parse o/p interface [%s]: Passing default primary \n", argv
[2]);
209 Opintf
= kDNSIfindexAny
;
214 if (argc
> 2 && !strcmp(argv
[1], "-i"))
219 for (i
= 0; i
< MaxInputIf
&& argc
> 1; i
++)
221 Ipintfs
[i
] = if_nametoindex(argv
[1]);
223 Ipintfs
[i
] = atoi(argv
[1]);
226 fprintf(stderr
, "Could not parse i/p interface [%s]: Passing default lo0 \n", argv
[2]);
233 printf("Enabling DNSProxy on mDNSResponder \n");
234 dispatch_queue_t my_Q
= dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL
);
235 err
= DNSXEnableProxy(&ClientRef
, kDNSProxyEnable
, Ipintfs
, Opintf
, my_Q
, dnsproxy_reply
);
237 fprintf(stderr
, "DNSXEnableProxy returned %d\n", err
);
240 else if (!strcasecmp(argv
[1], "-l"))
242 printf("Changing loglevel of mDNSResponder \n");
243 Init_Connection(kDNSCTLService
);
245 // Create Dictionary To Send
246 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
250 xpc_dictionary_set_uint64(dict
, kDNSLogLevel
, log_level1
);
252 SendDictToServer(dict
);
260 switch (atoi(argv
[1]))
263 xpc_dictionary_set_uint64(dict
, kDNSLogLevel
, log_level1
);
267 xpc_dictionary_set_uint64(dict
, kDNSLogLevel
, log_level2
);
271 xpc_dictionary_set_uint64(dict
, kDNSLogLevel
, log_level3
);
275 xpc_dictionary_set_uint64(dict
, kDNSLogLevel
, log_level4
);
279 xpc_dictionary_set_uint64(dict
, kDNSLogLevel
, log_level1
);
282 SendDictToServer(dict
);
287 else if(!strcasecmp(argv
[1], "-i"))
289 printf("Get STATE INFO of mDNSResponder \n");
290 Init_Connection(kDNSCTLService
);
292 // Create Dictionary To Send
293 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
294 xpc_dictionary_set_uint64(dict
, kDNSStateInfo
, full_state
);
295 SendDictToServer(dict
);
299 else if(!strcasecmp(argv
[1], "-th"))
301 printf("Sending Test message to mDNSResponder to forward to mDNSResponderHelper\n");
302 Init_Connection(kDNSCTLService
);
304 // Create Dictionary To Send
305 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
306 xpc_dictionary_set_uint64(dict
, kmDNSResponderTests
, test_helper_ipc
);
307 SendDictToServer(dict
);
311 else if(!strcasecmp(argv
[1], "-tl"))
313 printf("Testing mDNSResponder Logging\n");
314 Init_Connection(kDNSCTLService
);
316 // Create Dictionary To Send
317 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
318 xpc_dictionary_set_uint64(dict
, kmDNSResponderTests
, test_mDNS_log
);
319 SendDictToServer(dict
);
339 static int operation;
341 static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptInd)
343 // Return the recognized option in optstr and the option index of the next arg.
344 int o = getopt(argc, (char *const *)argv, optstr);
350 operation = getfirstoption(argc, argv, "lLDdPp", &opindex);
362 printf("Change Verbosity Level of mDNSResponder\n");
364 Init_Connection(kDNSCTLService);
366 // Create Dictionary To Send
367 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
369 printf("could not create the Msg Dict To Send! \n");
370 xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level2);
372 SendDictToServer(dict);