1/* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2012-2015 Apple Inc. All rights reserved. 4 * 5 * dnsctl.c 6 * Command-line tool using libdns_services.dylib 7 * 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 11 * 12 */ 13 14#include <stdio.h> 15#include <stdlib.h> 16#include <string.h> 17#include <sys/time.h> 18#include <net/if.h> // if_nametoindex() 19 20#include "dns_services.h" 21#include <xpc/xpc.h> 22#include "dns_xpc.h" 23 24//************************************************************************************************************* 25// Globals: 26//************************************************************************************************************* 27 28static const char kFilePathSep = '/'; 29 30static DNSXConnRef ClientRef = NULL; 31 32static xpc_connection_t dnsctl_conn = NULL; 33 34//************************************************************************************************************* 35// Utility Funcs: 36//************************************************************************************************************* 37 38static void printtimestamp(void) 39{ 40 struct tm tm; 41 int ms; 42 static char date[16]; 43 static char new_date[16]; 44 struct timeval tv; 45 gettimeofday(&tv, NULL); 46 localtime_r((time_t*)&tv.tv_sec, &tm); 47 ms = tv.tv_usec/1000; 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))) 51 { 52 printf("DATE: ---%s---\n", new_date); 53 strlcpy(date, new_date, sizeof(date)); 54 } 55 printf("%2d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms); 56} 57 58static void print_usage(const char *arg0) 59{ 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); 65} 66 67 68static bool DebugEnabled() 69{ 70 return true; // keep this true to debug the XPC msgs 71} 72 73static void DebugLog(const char *prefix, xpc_object_t o) 74{ 75 if (!DebugEnabled()) 76 return; 77 78 char *desc = xpc_copy_description(o); 79 printf("%s: %s \n", prefix, desc); 80 free(desc); 81} 82 83//************************************************************************************************************* 84// CallBack Funcs: 85//************************************************************************************************************* 86 87 88// DNSXEnableProxy Callback from the Daemon 89static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode) 90{ 91 (void) connRef; 92 printtimestamp(); 93 switch (errCode) 94 { 95 case kDNSX_NoError : printf(" SUCCESS \n"); 96 break; 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; 106 } 107 fflush(NULL); 108 109} 110 111//************************************************************************************************************* 112// XPC Funcs: 113//************************************************************************************************************* 114 115static void Init_Connection(const char *servname) 116{ 117 dnsctl_conn = xpc_connection_create_mach_service(servname, dispatch_get_main_queue(), XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); 118 119 xpc_connection_set_event_handler(dnsctl_conn, ^(xpc_object_t event) 120 { 121 printf("InitConnection: [%s] \n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION)); 122 }); 123 124 xpc_connection_resume(dnsctl_conn); 125} 126 127static void SendDictToServer(xpc_object_t msg) 128{ 129 130 DebugLog("SendDictToServer Sending msg to Daemon", msg); 131 132 xpc_connection_send_message_with_reply(dnsctl_conn, msg, dispatch_get_main_queue(), ^(xpc_object_t recv_msg) 133 { 134 xpc_type_t type = xpc_get_type(recv_msg); 135 136 if (type == XPC_TYPE_DICTIONARY) 137 { 138 DebugLog("SendDictToServer Received reply msg from Daemon", recv_msg); 139 /* 140 // If we ever want to do something based on the reply of the daemon 141 switch (daemon_status) 142 { 143 default: 144 break; 145 } 146 */ 147 } 148 else 149 { 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); 153 } 154 exit(1); 155 }); 156} 157 158//************************************************************************************************************* 159 160int main(int argc, char **argv) 161{ 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) 165 a0 = argv[0]; 166 167 // Must run as root 168 if (0 != geteuid()) 169 { 170 fprintf(stderr, "%s MUST run as root!!\n", a0); 171 exit(-1); 172 } 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"); 177 178 // expects atleast one argument 179 if (argc < 2) 180 goto Usage; 181 182 printtimestamp(); 183 if (!strcasecmp(argv[1], "-DP")) 184 { 185 DNSXErrorType err; 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; 189 190 if (argc == 2) 191 { 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); 194 if (err) 195 fprintf(stderr, "DNSXEnableProxy returned %d\n", err); 196 } 197 else if (argc > 2) 198 { 199 argc--; 200 argv++; 201 if (!strcmp(argv[1], "-o")) 202 { 203 Opintf = if_nametoindex(argv[2]); 204 if (!Opintf) 205 Opintf = atoi(argv[2]); 206 if (!Opintf) 207 { 208 fprintf(stderr, "Could not parse o/p interface [%s]: Passing default primary \n", argv[2]); 209 Opintf = kDNSIfindexAny; 210 } 211 argc -= 2; 212 argv += 2; 213 } 214 if (argc > 2 && !strcmp(argv[1], "-i")) 215 { 216 int i; 217 argc--; 218 argv++; 219 for (i = 0; i < MaxInputIf && argc > 1; i++) 220 { 221 Ipintfs[i] = if_nametoindex(argv[1]); 222 if (!Ipintfs[i]) 223 Ipintfs[i] = atoi(argv[1]); 224 if (!Ipintfs[i]) 225 { 226 fprintf(stderr, "Could not parse i/p interface [%s]: Passing default lo0 \n", argv[2]); 227 Ipintfs[i] = 1; 228 } 229 argc--; 230 argv++; 231 } 232 } 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); 236 if (err) 237 fprintf(stderr, "DNSXEnableProxy returned %d\n", err); 238 } 239 } 240 else if (!strcasecmp(argv[1], "-l")) 241 { 242 printf("Changing loglevel of mDNSResponder \n"); 243 Init_Connection(kDNSCTLService); 244 245 // Create Dictionary To Send 246 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); 247 248 if (argc == 2) 249 { 250 xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1); 251 252 SendDictToServer(dict); 253 xpc_release(dict); 254 dict = NULL; 255 } 256 else if (argc > 2) 257 { 258 argc--; 259 argv++; 260 switch (atoi(argv[1])) 261 { 262 case log_level1: 263 xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1); 264 break; 265 266 case log_level2: 267 xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level2); 268 break; 269 270 case log_level3: 271 xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level3); 272 break; 273 274 case log_level4: 275 xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level4); 276 break; 277 278 default: 279 xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1); 280 break; 281 } 282 SendDictToServer(dict); 283 xpc_release(dict); 284 dict = NULL; 285 } 286 } 287 else if(!strcasecmp(argv[1], "-i")) 288 { 289 printf("Get STATE INFO of mDNSResponder \n"); 290 Init_Connection(kDNSCTLService); 291 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); 296 xpc_release(dict); 297 dict = NULL; 298 } 299 else if(!strcasecmp(argv[1], "-th")) 300 { 301 printf("Sending Test message to mDNSResponder to forward to mDNSResponderHelper\n"); 302 Init_Connection(kDNSCTLService); 303 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); 308 xpc_release(dict); 309 dict = NULL; 310 } 311 else if(!strcasecmp(argv[1], "-tl")) 312 { 313 printf("Testing mDNSResponder Logging\n"); 314 Init_Connection(kDNSCTLService); 315 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); 320 xpc_release(dict); 321 dict = NULL; 322 } 323 else 324 { 325 goto Usage; 326 } 327 328 dispatch_main(); 329 330Usage: 331 print_usage(a0); 332 return 0; 333} 334 335/* 336 337#include <getopt.h> 338 339static int operation; 340 341static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptInd) 342{ 343 // Return the recognized option in optstr and the option index of the next arg. 344 int o = getopt(argc, (char *const *)argv, optstr); 345 *pOptInd = optind; 346 return o; 347} 348 349int opindex; 350operation = getfirstoption(argc, argv, "lLDdPp", &opindex); 351if (operation == -1) 352 goto Usage; 353 354 355 356switch (operation) 357{ 358 case 'L': 359 case 'l': 360 { 361 printtimestamp(); 362 printf("Change Verbosity Level of mDNSResponder\n"); 363 364 Init_Connection(kDNSCTLService); 365 366 // Create Dictionary To Send 367 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); 368 if (dict == NULL) 369 printf("could not create the Msg Dict To Send! \n"); 370 xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level2); 371 372 SendDictToServer(dict); 373 374 xpc_release(dict); 375 dict = NULL; 376 break; 377 } 378 // exit(1); 379 380} 381 382*/ 383 384