]> git.saurik.com Git - apple/mdnsresponder.git/blob - Clients/srputil/srputil.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / Clients / srputil / srputil.c
1 /* srputil.c
2 *
3 * Copyright (c) 2020 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * SRP Advertising Proxy utility program, allows:
18 * start/stop advertising proxy
19 * get/track list of service types
20 * get/track list of services of a particular type
21 * get/track list of hosts
22 * get/track information about a particular host
23 */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <fcntl.h>
34 #include <sys/time.h>
35 #include <dns_sd.h>
36 #include <net/if.h>
37 #include <os/log.h>
38
39 #include "srp.h"
40 #include "advertising_proxy_services.h"
41
42 dispatch_queue_t main_queue;
43
44 static void
45 started_callback(advertising_proxy_conn_ref cref, xpc_object_t response, advertising_proxy_error_type err)
46 {
47 INFO("started: cref %p response %p err %d.", cref, response, err);
48 if (err != kDNSSDAdvertisingProxyStatus_NoError) {
49 exit(1);
50 }
51 }
52
53 static void
54 flushed_callback(advertising_proxy_conn_ref cref, xpc_object_t response, advertising_proxy_error_type err)
55 {
56 INFO("flushed: cref %p response %p err %d.", cref, response, err);
57 if (err != kDNSSDAdvertisingProxyStatus_NoError) {
58 exit(1);
59 }
60 // We don't need to wait around after flushing.
61 exit(0);
62 }
63
64 static void
65 block_callback(advertising_proxy_conn_ref cref, xpc_object_t response, advertising_proxy_error_type err)
66 {
67 INFO("blocked: cref %p response %p err %d.", cref, response, err);
68 if (err != kDNSSDAdvertisingProxyStatus_NoError) {
69 exit(1);
70 }
71 // We don't need to wait around after blocking.
72 exit(0);
73 }
74
75 static void
76 unblock_callback(advertising_proxy_conn_ref cref, xpc_object_t response, advertising_proxy_error_type err)
77 {
78 INFO("unblocked: cref %p response %p err %d.", cref, response, err);
79 if (err != kDNSSDAdvertisingProxyStatus_NoError) {
80 exit(1);
81 }
82 // We don't need to wait around after unblocking.
83 exit(0);
84 }
85
86 static void
87 regenerate_callback(advertising_proxy_conn_ref cref, xpc_object_t response, advertising_proxy_error_type err)
88 {
89 INFO("regenerated ula: cref %p response %p err %d.", cref, response, err);
90 if (err != kDNSSDAdvertisingProxyStatus_NoError) {
91 exit(1);
92 }
93 // We don't need to wait around after unblocking.
94 exit(0);
95 }
96
97 static void
98 services_callback(advertising_proxy_conn_ref cref, xpc_object_t response, advertising_proxy_error_type err)
99 {
100 size_t i, num;
101 int64_t lease, hours, minutes, seconds;
102 INFO("services: cref %p response %p err %d.", cref, response, err);
103 if (err != kDNSSDAdvertisingProxyStatus_NoError) {
104 exit(1);
105 }
106 xpc_object_t services = xpc_dictionary_get_value(response, "instances");
107 if (services == NULL) {
108 INFO("Non-error response doesn't contain an instances key");
109 exit(1);
110 }
111 if (xpc_get_type(services) != XPC_TYPE_ARRAY) {
112 INFO("Non-error response instances value is not an array");
113 exit(1);
114 }
115 num = xpc_array_get_count(services);
116 if (num == 0) {
117 INFO("No registered services.");
118 }
119 for (i = 0; i < num; i++) {
120 xpc_object_t dict = xpc_array_get_value(services, i);
121 if (dict == NULL || xpc_get_type(dict) != XPC_TYPE_DICTIONARY) {
122 INFO("services array[%d] is not a dictionary", i);
123 exit(1);
124 }
125 const char *hostname, *instance_name, *service_type, *port, *address, *regname;
126 regname = xpc_dictionary_get_string(dict, "regname");
127 hostname = xpc_dictionary_get_string(dict, "hostname");
128 instance_name = xpc_dictionary_get_string(dict, "name");
129 if (instance_name == NULL) {
130 instance_name = "<no instances>";
131 service_type = "";
132 port = "";
133 } else {
134 service_type = xpc_dictionary_get_string(dict, "type");
135 port = xpc_dictionary_get_string(dict, "port");
136 }
137 address = xpc_dictionary_get_string(dict, "address");
138 lease = xpc_dictionary_get_int64(dict, "lease");
139 hours = lease / 3600 / 1000;
140 lease -= hours * 3600 * 1000;
141 minutes = lease / 60 / 1000;
142 lease -= minutes * 60 * 1000;
143 seconds = lease / 1000;
144 lease -= seconds * 1000;
145
146 printf("\"%s\" \"%s\" %s %s %s %qd:%qd:%qd.%qd \"%s\"\n", regname, instance_name, service_type, port,
147 address == NULL ? "" : address, hours, minutes, seconds, lease, hostname);
148 }
149 exit(0);
150 }
151
152 static void
153 usage(void)
154 {
155 ERROR("srputil start -- start the SRP MDNS Proxy through launchd");
156 ERROR(" services -- get the list of services currently being advertised");
157 ERROR(" block -- block the SRP listener");
158 ERROR(" unblock -- unblock the SRP listener");
159 ERROR(" regenerate-ula -- generate a new ULA and restart the network");
160 #ifdef NOTYET
161 ERROR(" flush -- flush all entries from the SRP proxy (for testing only)");
162 #endif
163 }
164
165 int
166 main(int argc, char **argv)
167 {
168 int i;
169 bool start_proxy = false;
170 bool flush_entries = false;
171 bool list_services = false;
172 bool block = false;
173 bool unblock = false;
174 bool regenerate_ula = false;
175 #ifdef NOTYET
176 bool watch = false;
177 bool get = false;
178 #endif
179
180 for (i = 1; i < argc; i++) {
181 if (!strcmp(argv[i], "start")) {
182 start_proxy = true;
183 } else if (!strcmp(argv[i], "flush")) {
184 flush_entries = true;
185 } else if (!strcmp(argv[i], "services")) {
186 list_services = true;
187 } else if (!strcmp(argv[i], "block")) {
188 block = true;
189 } else if (!strcmp(argv[i], "unblock")) {
190 unblock = true;
191 } else if (!strcmp(argv[i], "regenerate-ula")) {
192 regenerate_ula = true;
193 #ifdef NOTYET
194 } else if (!strcmp(argv[i], "watch")) {
195 ERROR("Watching not implemented yet.");
196 exit(1);
197 } else if (!strcmp(argv[i], "get")) {
198 ERROR("Getting not implemented yet.");
199 exit(1);
200 #endif
201 } else {
202 usage();
203 }
204 }
205
206 main_queue = dispatch_get_main_queue();
207 dispatch_retain(main_queue);
208
209 // Start the queue, //then// do the work
210 dispatch_async(main_queue, ^{
211 advertising_proxy_error_type err = kDNSSDAdvertisingProxyStatus_NoError;;
212 advertising_proxy_conn_ref cref = NULL;
213
214 if (start_proxy) {
215 err = advertising_proxy_enable(&cref, main_queue, started_callback);
216 }
217 if (err == kDNSSDAdvertisingProxyStatus_NoError && flush_entries) {
218 err = advertising_proxy_flush_entries(&cref, main_queue, flushed_callback);
219 }
220 if (err == kDNSSDAdvertisingProxyStatus_NoError && list_services) {
221 err = advertising_proxy_get_service_list(&cref, main_queue, services_callback);
222 }
223 if (err == kDNSSDAdvertisingProxyStatus_NoError && block) {
224 err = advertising_proxy_block_service(&cref, main_queue, block_callback);
225 }
226 if (err == kDNSSDAdvertisingProxyStatus_NoError && unblock) {
227 err = advertising_proxy_unblock_service(&cref, main_queue, unblock_callback);
228 }
229 if (err == kDNSSDAdvertisingProxyStatus_NoError && regenerate_ula) {
230 err = advertising_proxy_regenerate_ula(&cref, main_queue, regenerate_callback);
231 }
232 if (err != kDNSSDAdvertisingProxyStatus_NoError) {
233 exit(1);
234 }
235 });
236 dispatch_main();
237 }
238
239 // Local Variables:
240 // mode: C
241 // tab-width: 4
242 // c-file-style: "bsd"
243 // c-basic-offset: 4
244 // fill-column: 108
245 // indent-tabs-mode: nil
246 // End: