1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2012 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 <dispatch/dispatch.h>
21#include "dns_services_mdns.h"
22
23//*************************************************************************************************************
24// Globals:
25//*************************************************************************************************************
26
27static const char kFilePathSep   =  '/';
28static DNSXConnRef ClientRef     =  NULL;
29
30//*************************************************************************************************************
31// Utility Funcs:
32//*************************************************************************************************************
33
34static void printtimestamp(void)
35{
36    struct tm tm;
37    int ms;
38    static char date[16];
39    static char new_date[16];
40    struct timeval tv;
41    gettimeofday(&tv, NULL);
42    localtime_r((time_t*)&tv.tv_sec, &tm);
43    ms = tv.tv_usec/1000;
44    strftime(new_date, sizeof(new_date), "%a %d %b %Y", &tm);
45    //display date only if it has changed
46    if (strncmp(date, new_date, sizeof(new_date)))
47    {
48        printf("DATE: ---%s---\n", new_date);
49        strncpy(date, new_date, sizeof(date));
50    }
51    printf("%2d:%02d:%02d.%03d  ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms);
52}
53
54static void print_usage(const char *arg0)
55{
56    fprintf(stderr, "%s USAGE:                                                                  \n", arg0);
57    fprintf(stderr, "%s -DP Enable DNS Proxy with Default Parameters                            \n", arg0);
58    fprintf(stderr, "%s -DP [-o <output interface>] [-i <input interface(s)>] Enable DNS Proxy  \n", arg0);
59}
60
61//*************************************************************************************************************
62// CallBack Funcs:
63//*************************************************************************************************************
64
65// DNSXEnableProxy Callback from the Daemon
66static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode)
67{
68    (void) connRef;
69    printtimestamp();
70    switch (errCode)
71    {
72        case kDNSX_NoError          :  printf("  SUCCESS   \n");     break;
73        case kDNSX_DictError        :  printf(" DICT ERROR \n");     break;
74        case kDNSX_DaemonNotRunning :  printf(" NO DAEMON  \n");
75                                       DNSXRefDeAlloc(ClientRef);    break;
76        case kDNSX_Engaged          :  printf(" ENGAGED    \n");
77                                       DNSXRefDeAlloc(ClientRef);    break;
78        case kDNSX_UnknownErr       :
79        default                     :  printf("UNKNOWN ERR \n");
80                                       DNSXRefDeAlloc(ClientRef);    break;
81    }
82    fflush(NULL);
83
84}
85
86//*************************************************************************************************************
87
88int main(int argc, char **argv)
89{
90    DNSXErrorType err;
91
92    // Default i/p intf is lo0 and o/p intf is primary interface
93    IfIndex Ipintfs[MaxInputIf] =  {1, 0, 0, 0, 0};
94    IfIndex Opintf = kDNSIfindexAny;
95
96    // Extract program name from argv[0], which by convention contains the path to this executable
97    const char *a0 = strrchr(argv[0], kFilePathSep) + 1;
98    if (a0 == (const char *)1)
99        a0 = argv[0];
100
101    // Must run as root
102    if (0 != geteuid())
103    {
104        fprintf(stderr, "%s MUST run as root!!\n", a0);
105        exit(-1);
106    }
107    if ((sizeof(argv) == 8))
108        printf("dnsctl running in 64-bit mode\n");
109    else if ((sizeof(argv) == 4))
110        printf("dnsctl running in 32-bit mode\n");
111
112    // expects atleast one argument
113    if (argc < 2)
114        goto Usage;
115
116    if ( !strcmp(argv[1], "-DP") || !strcmp(argv[1], "-dp") )
117    {
118        if (argc == 2)
119        {
120            printtimestamp();
121            printf("Proceeding to Enable DNSProxy on mDNSResponder with Default Parameters\n");
122            dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
123            err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
124        }
125        else if (argc > 2)
126        {
127            argc--;
128            argv++;
129            if (!strcmp(argv[1], "-o"))
130            {
131                Opintf = if_nametoindex(argv[2]);
132                if (!Opintf)
133                    Opintf = atoi(argv[2]);
134                if (!Opintf)
135                {
136                    fprintf(stderr, "Could not parse o/p interface [%s]: Passing default primary \n", argv[2]);
137                    Opintf = kDNSIfindexAny;
138                }
139                argc -= 2;
140                argv += 2;
141            }
142            if (argc > 2 && !strcmp(argv[1], "-i"))
143            {
144                int i;
145                argc--;
146                argv++;
147                for (i = 0; i < MaxInputIf && argc > 1; i++)
148                {
149                    Ipintfs[i] = if_nametoindex(argv[1]);
150                    if (!Ipintfs[i])
151                        Ipintfs[i] = atoi(argv[1]);
152                    if (!Ipintfs[i])
153                    {
154                        fprintf(stderr, "Could not parse i/p interface [%s]: Passing default lo0 \n", argv[2]);
155                        Ipintfs[i] = 1;
156                    }
157                    argc--;
158                    argv++;
159                }
160            }
161            printtimestamp();
162            printf("Proceeding to Enable DNSProxy on mDNSResponder \n");
163            dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
164            err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
165        }
166    }
167    else
168    {
169        goto Usage;
170    }
171
172    dispatch_main();
173
174Usage:
175    print_usage(a0);
176    return 0;
177}
178
179