srputil.c revision 1.1 1 1.1 christos /* srputil.c
2 1.1 christos *
3 1.1 christos * Copyright (c) 2020-2024 Apple Inc. All rights reserved.
4 1.1 christos *
5 1.1 christos * Licensed under the Apache License, Version 2.0 (the "License");
6 1.1 christos * you may not use this file except in compliance with the License.
7 1.1 christos * You may obtain a copy of the License at
8 1.1 christos *
9 1.1 christos * https://www.apache.org/licenses/LICENSE-2.0
10 1.1 christos *
11 1.1 christos * Unless required by applicable law or agreed to in writing, software
12 1.1 christos * distributed under the License is distributed on an "AS IS" BASIS,
13 1.1 christos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 1.1 christos * See the License for the specific language governing permissions and
15 1.1 christos * limitations under the License.
16 1.1 christos *
17 1.1 christos * SRP Advertising Proxy utility program, allows:
18 1.1 christos * start/stop advertising proxy
19 1.1 christos * get/track list of service types
20 1.1 christos * get/track list of services of a particular type
21 1.1 christos * get/track list of hosts
22 1.1 christos * get/track information about a particular host
23 1.1 christos */
24 1.1 christos
25 1.1 christos #include <stdlib.h>
26 1.1 christos #include <string.h>
27 1.1 christos #include <stdio.h>
28 1.1 christos #include <unistd.h>
29 1.1 christos #include <errno.h>
30 1.1 christos #include <sys/socket.h>
31 1.1 christos #include <netinet/in.h>
32 1.1 christos #include <arpa/inet.h>
33 1.1 christos #include <fcntl.h>
34 1.1 christos #include <time.h>
35 1.1 christos #include <dns_sd.h>
36 1.1 christos #include <net/if.h>
37 1.1 christos #include <inttypes.h>
38 1.1 christos
39 1.1 christos void *main_queue = NULL;
40 1.1 christos
41 1.1 christos #include "srp.h"
42 1.1 christos #include "dns-msg.h"
43 1.1 christos #include "ioloop.h"
44 1.1 christos #include "advertising_proxy_services.h"
45 1.1 christos #include "route-tracker.h"
46 1.1 christos #include "state-machine.h"
47 1.1 christos #include "thread-service.h"
48 1.1 christos #include "service-tracker.h"
49 1.1 christos #include "probe-srp.h"
50 1.1 christos #include "cti-services.h"
51 1.1 christos #include "adv-ctl-server.h"
52 1.1 christos
53 1.1 christos
54 1.1 christos static void
55 1.1 christos flushed_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
56 1.1 christos {
57 1.1 christos INFO("flushed: cref %p response %p err %d.", cref, result, err);
58 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
59 1.1 christos exit(1);
60 1.1 christos }
61 1.1 christos // We don't need to wait around after flushing.
62 1.1 christos exit(0);
63 1.1 christos }
64 1.1 christos
65 1.1 christos static void
66 1.1 christos block_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
67 1.1 christos {
68 1.1 christos INFO("blocked: cref %p response %p err %d.", cref, result, err);
69 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
70 1.1 christos exit(1);
71 1.1 christos }
72 1.1 christos // We don't need to wait around after blocking.
73 1.1 christos exit(0);
74 1.1 christos }
75 1.1 christos
76 1.1 christos static void
77 1.1 christos unblock_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
78 1.1 christos {
79 1.1 christos INFO("unblocked: cref %p response %p err %d.", cref, result, err);
80 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
81 1.1 christos exit(1);
82 1.1 christos }
83 1.1 christos // We don't need to wait around after unblocking.
84 1.1 christos exit(0);
85 1.1 christos }
86 1.1 christos
87 1.1 christos static void
88 1.1 christos regenerate_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
89 1.1 christos {
90 1.1 christos INFO("regenerated ula: cref %p response %p err %d.", cref, result, err);
91 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
92 1.1 christos exit(1);
93 1.1 christos }
94 1.1 christos // We don't need to wait around after unblocking.
95 1.1 christos exit(0);
96 1.1 christos }
97 1.1 christos
98 1.1 christos static void
99 1.1 christos prefix_advertise_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
100 1.1 christos {
101 1.1 christos INFO("advertise prefix: cref %p response %p err %d.", cref, result, err);
102 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
103 1.1 christos exit(1);
104 1.1 christos }
105 1.1 christos // We don't need to wait around after advertising prefix.
106 1.1 christos exit(0);
107 1.1 christos }
108 1.1 christos
109 1.1 christos static void
110 1.1 christos add_prefix_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
111 1.1 christos {
112 1.1 christos INFO("add prefix: cref %p response %p err %d.", cref, result, err);
113 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
114 1.1 christos exit(1);
115 1.1 christos }
116 1.1 christos // We don't need to wait around after advertising prefix.
117 1.1 christos exit(0);
118 1.1 christos }
119 1.1 christos
120 1.1 christos static void
121 1.1 christos remove_prefix_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
122 1.1 christos {
123 1.1 christos INFO("remove prefix: cref %p response %p err %d.", cref, result, err);
124 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
125 1.1 christos exit(1);
126 1.1 christos }
127 1.1 christos // We don't need to wait around after advertising prefix.
128 1.1 christos exit(0);
129 1.1 christos }
130 1.1 christos
131 1.1 christos static void
132 1.1 christos add_nat64_prefix_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
133 1.1 christos {
134 1.1 christos INFO("add nat64 prefix: cref %p response %p err %d.", cref, result, err);
135 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
136 1.1 christos exit(1);
137 1.1 christos }
138 1.1 christos exit(0);
139 1.1 christos }
140 1.1 christos
141 1.1 christos static void
142 1.1 christos remove_nat64_prefix_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
143 1.1 christos {
144 1.1 christos INFO("remove nat64 prefix: cref %p response %p err %d.", cref, result, err);
145 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
146 1.1 christos exit(1);
147 1.1 christos }
148 1.1 christos exit(0);
149 1.1 christos }
150 1.1 christos
151 1.1 christos static void
152 1.1 christos stop_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
153 1.1 christos {
154 1.1 christos INFO("stopped: cref %p response %p err %d.", cref, result, err);
155 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
156 1.1 christos exit(1);
157 1.1 christos }
158 1.1 christos // We don't need to wait around after stopping.
159 1.1 christos exit(0);
160 1.1 christos }
161 1.1 christos
162 1.1 christos static const char *
163 1.1 christos print_address(advertising_proxy_host_address_t *address, char *addrbuf, size_t addrbuf_size)
164 1.1 christos {
165 1.1 christos if (address->rrtype == 0) {
166 1.1 christos return (char *)address->rdata;
167 1.1 christos } else if (address->rrtype == dns_rrtype_a && address->rdlen == 4) {
168 1.1 christos inet_ntop(AF_INET, address->rdata, addrbuf, (socklen_t)addrbuf_size);
169 1.1 christos return addrbuf;
170 1.1 christos } else if (address->rrtype == dns_rrtype_aaaa && address->rdlen == 16) {
171 1.1 christos inet_ntop(AF_INET6, address->rdata, addrbuf, (socklen_t)addrbuf_size);
172 1.1 christos return addrbuf;
173 1.1 christos } else {
174 1.1 christos sprintf(addrbuf, "Family-%d", address->rrtype);
175 1.1 christos return addrbuf;
176 1.1 christos }
177 1.1 christos }
178 1.1 christos
179 1.1 christos static void
180 1.1 christos services_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
181 1.1 christos {
182 1.1 christos int i;
183 1.1 christos int64_t lease, hours, minutes, seconds;
184 1.1 christos advertising_proxy_host_t *host = result;
185 1.1 christos const char *address = "<no address>";
186 1.1 christos char *addrbuf = NULL;
187 1.1 christos size_t addrbuflen;
188 1.1 christos uint64_t ula;
189 1.1 christos
190 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
191 1.1 christos INFO("services: cref %p response %p err %d.", cref, result, err);
192 1.1 christos exit(1);
193 1.1 christos }
194 1.1 christos if (result == NULL) {
195 1.1 christos INFO("services: cref %p response %p err %d.", cref, result, err);
196 1.1 christos exit(0);
197 1.1 christos }
198 1.1 christos
199 1.1 christos if (host->num_instances == 0) {
200 1.1 christos i = -1;
201 1.1 christos } else {
202 1.1 christos i = 0;
203 1.1 christos }
204 1.1 christos for (; i < host->num_instances; i++) {
205 1.1 christos const char *instance_name, *service_type, *reg_type;
206 1.1 christos char port[6]; // uint16_t as ascii
207 1.1 christos
208 1.1 christos if (i == -1 || host->instances[i].instance_name == NULL) {
209 1.1 christos instance_name = "<no instances>";
210 1.1 christos service_type = "";
211 1.1 christos port[0] = 0;
212 1.1 christos reg_type = "";
213 1.1 christos } else {
214 1.1 christos instance_name = host->instances[i].instance_name;
215 1.1 christos service_type = host->instances[i].service_type;
216 1.1 christos snprintf(port, sizeof(port), "%u", host->instances[i].port);
217 1.1 christos reg_type = host->instances[i].reg_type;
218 1.1 christos }
219 1.1 christos
220 1.1 christos if (host->num_addresses > 0) {
221 1.1 christos addrbuflen = host->num_addresses * (INET6_ADDRSTRLEN + 1);
222 1.1 christos addrbuf = malloc(addrbuflen);
223 1.1 christos if (addrbuf == NULL) {
224 1.1 christos address = "<no memory for address buffer>";
225 1.1 christos } else {
226 1.1 christos char *ap = addrbuf;
227 1.1 christos for (int j = 0; j < host->num_addresses; j++) {
228 1.1 christos *ap++ = ' ';
229 1.1 christos address = print_address(&host->addresses[j], ap, addrbuflen - (ap - addrbuf));
230 1.1 christos size_t len = strlen(address);
231 1.1 christos if (address != ap) {
232 1.1 christos if (len + ap + 1 > addrbuf + addrbuflen) {
233 1.1 christos len = addrbuflen - (ap - addrbuf) - 1;
234 1.1 christos }
235 1.1 christos memcpy(ap, address, len + 1); // Includes NUL
236 1.1 christos }
237 1.1 christos ap += len;
238 1.1 christos }
239 1.1 christos address = addrbuf;
240 1.1 christos }
241 1.1 christos }
242 1.1 christos lease = host->lease_time;
243 1.1 christos hours = lease / 3600 / 1000;
244 1.1 christos lease -= hours * 3600 * 1000;
245 1.1 christos minutes = lease / 60 / 1000;
246 1.1 christos lease -= minutes * 60 * 1000;
247 1.1 christos seconds = lease / 1000;
248 1.1 christos lease -= seconds * 1000;
249 1.1 christos
250 1.1 christos // Our implementation of the stable server ID uses the server ULA, so just copy out those 48 bits,
251 1.1 christos // which are in network byte order.
252 1.1 christos ula = 0;
253 1.1 christos for (int j = 1; j < 6; j++) {
254 1.1 christos ula = ula << 8 | (((uint8_t *)&host->server_id)[j]);
255 1.1 christos }
256 1.1 christos printf("\"%s\" \"%s\" %s %s %s %" PRIu64 ":%" PRIu64 ":%" PRIu64 ".%" PRIu64 " \"%s\" \"%s\" %s %" PRIx64 "\n",
257 1.1 christos host->regname, instance_name, service_type, port,
258 1.1 christos address == NULL ? "" : address, hours, minutes, seconds, lease, host->hostname,
259 1.1 christos reg_type, host->removed ? "invalid" : "valid", ula);
260 1.1 christos if (addrbuf != NULL) {
261 1.1 christos free(addrbuf);
262 1.1 christos }
263 1.1 christos }
264 1.1 christos }
265 1.1 christos
266 1.1 christos static void
267 1.1 christos ula_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
268 1.1 christos {
269 1.1 christos INFO("get_ula: cref %p response %p err %d.", cref, result, err);
270 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
271 1.1 christos fprintf(stderr, "ULA get failed: %d\n", err);
272 1.1 christos exit(1);
273 1.1 christos }
274 1.1 christos uint64_t ula = *((uint64_t *)result);
275 1.1 christos printf("ULA: %" PRIx64 "\n", ula);
276 1.1 christos exit(0);
277 1.1 christos }
278 1.1 christos
279 1.1 christos static void
280 1.1 christos disable_srp_replication_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
281 1.1 christos {
282 1.1 christos INFO("disable_srp_replication: cref %p response %p err %d.", cref, result, err);
283 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
284 1.1 christos exit(1);
285 1.1 christos }
286 1.1 christos // We don't need to wait around after SRP replication disabled.
287 1.1 christos exit(0);
288 1.1 christos }
289 1.1 christos
290 1.1 christos static void
291 1.1 christos drop_srpl_connection_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
292 1.1 christos {
293 1.1 christos INFO("drop_srpl_connection: cref %p response %p err %d.", cref, result, err);
294 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
295 1.1 christos exit(1);
296 1.1 christos }
297 1.1 christos exit(0);
298 1.1 christos }
299 1.1 christos
300 1.1 christos static void
301 1.1 christos undrop_srpl_connection_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
302 1.1 christos {
303 1.1 christos INFO("undrop_srpl_connection: cref %p response %p err %d.", cref, result, err);
304 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
305 1.1 christos exit(1);
306 1.1 christos }
307 1.1 christos exit(0);
308 1.1 christos }
309 1.1 christos
310 1.1 christos static void
311 1.1 christos drop_srpl_advertisement_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
312 1.1 christos {
313 1.1 christos INFO("drop_srpl_advertisement: cref %p response %p err %d.", cref, result, err);
314 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
315 1.1 christos exit(1);
316 1.1 christos }
317 1.1 christos exit(0);
318 1.1 christos }
319 1.1 christos
320 1.1 christos static void
321 1.1 christos undrop_srpl_advertisement_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
322 1.1 christos {
323 1.1 christos INFO("undrop_srpl_advertisement: cref %p response %p err %d.", cref, result, err);
324 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
325 1.1 christos exit(1);
326 1.1 christos }
327 1.1 christos exit(0);
328 1.1 christos }
329 1.1 christos
330 1.1 christos static void
331 1.1 christos start_dropping_push_connections_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
332 1.1 christos {
333 1.1 christos INFO("start_dropping_push_connections: cref %p response %p err %d.", cref, result, err);
334 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
335 1.1 christos exit(1);
336 1.1 christos }
337 1.1 christos exit(0);
338 1.1 christos }
339 1.1 christos
340 1.1 christos static void
341 1.1 christos start_breaking_time_validation_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
342 1.1 christos {
343 1.1 christos INFO("start_breaking_time_validation: cref %p response %p err %d.", cref, result, err);
344 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
345 1.1 christos exit(1);
346 1.1 christos }
347 1.1 christos exit(0);
348 1.1 christos }
349 1.1 christos
350 1.1 christos static void
351 1.1 christos block_anycast_service_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
352 1.1 christos {
353 1.1 christos INFO("block_anycast_service: cref %p response %p err %d.", cref, result, err);
354 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
355 1.1 christos exit(1);
356 1.1 christos }
357 1.1 christos exit(0);
358 1.1 christos }
359 1.1 christos
360 1.1 christos static void
361 1.1 christos unblock_anycast_service_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
362 1.1 christos {
363 1.1 christos INFO("unblock_anycast_service: cref %p response %p err %d.", cref, result, err);
364 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
365 1.1 christos exit(1);
366 1.1 christos }
367 1.1 christos exit(0);
368 1.1 christos }
369 1.1 christos
370 1.1 christos static void
371 1.1 christos start_thread_shutdown_callback(advertising_proxy_conn_ref cref, void *result, advertising_proxy_error_type err)
372 1.1 christos {
373 1.1 christos INFO("cref %p response %p err %d.", cref, result, err);
374 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
375 1.1 christos exit(1);
376 1.1 christos }
377 1.1 christos exit(0);
378 1.1 christos }
379 1.1 christos
380 1.1 christos typedef struct variable variable_t;
381 1.1 christos struct variable {
382 1.1 christos variable_t *next;
383 1.1 christos const char *name, *value;
384 1.1 christos };
385 1.1 christos
386 1.1 christos static void
387 1.1 christos set_variable_callback(advertising_proxy_conn_ref cref, void *context, void *result, advertising_proxy_error_type err)
388 1.1 christos {
389 1.1 christos variable_t *variable = context;
390 1.1 christos INFO("set_variable: cref %p response %p err %d, variable name %s, value %s.",
391 1.1 christos cref, result, err, variable->name, variable->value);
392 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
393 1.1 christos if (variable->next == NULL) {
394 1.1 christos exit(1);
395 1.1 christos }
396 1.1 christos }
397 1.1 christos if (variable->next == NULL) {
398 1.1 christos exit(0);
399 1.1 christos }
400 1.1 christos }
401 1.1 christos
402 1.1 christos static comm_t *tcp_connection;
403 1.1 christos bool do_tcp_zero_test = false;
404 1.1 christos bool do_tcp_fin_length = false;
405 1.1 christos bool do_tcp_fin_payload = false;
406 1.1 christos
407 1.1 christos service_tracker_t *tracker;
408 1.1 christos
409 1.1 christos // Dummy functions required to use service tracker here
410 1.1 christos void
411 1.1 christos adv_ctl_thread_shutdown_status_check(srp_server_t *UNUSED server_state) {
412 1.1 christos }
413 1.1 christos
414 1.1 christos static void
415 1.1 christos service_done_callback(void *context, cti_status_t status)
416 1.1 christos {
417 1.1 christos const char *action = context;
418 1.1 christos if (status != kCTIStatus_NoError) {
419 1.1 christos fprintf(stderr, PUB_S_SRP " failed, status %d", action, status);
420 1.1 christos exit(1);
421 1.1 christos } else {
422 1.1 christos fprintf(stderr, PUB_S_SRP " done", action);
423 1.1 christos exit(0);
424 1.1 christos }
425 1.1 christos }
426 1.1 christos
427 1.1 christos static void
428 1.1 christos service_set_changed(bool unicast)
429 1.1 christos {
430 1.1 christos thread_service_t *winner = NULL;
431 1.1 christos for (thread_service_t *service = service_tracker_services_get(tracker); service != NULL; service = service->next) {
432 1.1 christos if (service->ignore) {
433 1.1 christos continue;
434 1.1 christos }
435 1.1 christos if (unicast && service->service_type == unicast_service) {
436 1.1 christos if (winner == NULL || in6addr_compare(&service->u.unicast.address, &winner->u.unicast.address) < 0) {
437 1.1 christos winner = service;
438 1.1 christos }
439 1.1 christos }
440 1.1 christos }
441 1.1 christos if (winner == NULL) {
442 1.1 christos fprintf(stderr, "no services present!");
443 1.1 christos exit(1);
444 1.1 christos }
445 1.1 christos winner->u.unicast.address.s6_addr[15] = 0;
446 1.1 christos uint8_t service_data[1] = { THREAD_SRP_SERVER_OPTION };
447 1.1 christos uint8_t server_data[18];
448 1.1 christos memcpy(server_data, &winner->u.unicast.address, 15);
449 1.1 christos server_data[15] = 0;
450 1.1 christos server_data[16] = winner->u.unicast.port[0];
451 1.1 christos server_data[17] = winner->u.unicast.port[1];
452 1.1 christos int ret = cti_add_service(NULL, "add", service_done_callback, NULL,
453 1.1 christos THREAD_ENTERPRISE_NUMBER, service_data, 1, server_data, 18);
454 1.1 christos if (ret != kCTIStatus_NoError) {
455 1.1 christos fprintf(stderr, "add_service failed: %d", ret);
456 1.1 christos exit(1);
457 1.1 christos }
458 1.1 christos }
459 1.1 christos
460 1.1 christos static void
461 1.1 christos unicast_service_set_changed(void *UNUSED context)
462 1.1 christos {
463 1.1 christos service_set_changed(true);
464 1.1 christos }
465 1.1 christos
466 1.1 christos static void
467 1.1 christos start_advertising_winning_unicast_service(void)
468 1.1 christos {
469 1.1 christos tracker = service_tracker_create(NULL);
470 1.1 christos if (tracker != NULL) {
471 1.1 christos service_tracker_callback_add(tracker, unicast_service_set_changed, NULL, NULL);
472 1.1 christos service_tracker_start(tracker);
473 1.1 christos } else {
474 1.1 christos fprintf(stderr, "unable to allocate tracker");
475 1.1 christos exit(1);
476 1.1 christos }
477 1.1 christos }
478 1.1 christos
479 1.1 christos static void
480 1.1 christos start_removing_unicast_service(void)
481 1.1 christos {
482 1.1 christos uint8_t service_data[1] = { THREAD_SRP_SERVER_OPTION };
483 1.1 christos int ret = cti_remove_service(NULL, "remove", service_done_callback, NULL, THREAD_ENTERPRISE_NUMBER, service_data, 1);
484 1.1 christos if (ret != kCTIStatus_NoError) {
485 1.1 christos fprintf(stderr, "remove_service failed: %d", ret);
486 1.1 christos exit(1);
487 1.1 christos }
488 1.1 christos }
489 1.1 christos
490 1.1 christos static void
491 1.1 christos tcp_datagram_callback(comm_t *NONNULL comm, message_t *NONNULL message, void *NULLABLE context)
492 1.1 christos {
493 1.1 christos (void)comm;
494 1.1 christos (void)context;
495 1.1 christos fprintf(stderr, "tcp datagram received, length %d", message->length);
496 1.1 christos }
497 1.1 christos
498 1.1 christos static void
499 1.1 christos tcp_connect_callback(comm_t *NONNULL connection, void *NULLABLE context)
500 1.1 christos {
501 1.1 christos fprintf(stderr, "tcp connection succeeded...\n");
502 1.1 christos uint8_t length[2];
503 1.1 christos struct iovec iov[2];
504 1.1 christos char databuf[128];
505 1.1 christos memset(databuf, 0, sizeof(databuf));
506 1.1 christos memset(iov, 0, sizeof(iov));
507 1.1 christos
508 1.1 christos (void)context;
509 1.1 christos
510 1.1 christos if (do_tcp_zero_test) {
511 1.1 christos memset(length, 0, sizeof(length));
512 1.1 christos iov[0].iov_len = 2;
513 1.1 christos iov[0].iov_base = length;
514 1.1 christos ioloop_send_data(connection, NULL, iov, 1);
515 1.1 christos } else if (do_tcp_fin_length) {
516 1.1 christos memset(length, 0, sizeof(length));
517 1.1 christos iov[0].iov_len = 1;
518 1.1 christos iov[0].iov_base = &length;
519 1.1 christos ioloop_send_final_data(connection, NULL, iov, 1);
520 1.1 christos } else if (do_tcp_fin_payload) {
521 1.1 christos length[0] = 0;
522 1.1 christos length[1] = 255;
523 1.1 christos iov[0].iov_len = 2;
524 1.1 christos iov[0].iov_base = length;
525 1.1 christos iov[1].iov_len = 128;
526 1.1 christos iov[1].iov_base = databuf;
527 1.1 christos ioloop_send_final_data(connection, NULL, iov, 2);
528 1.1 christos }
529 1.1 christos }
530 1.1 christos
531 1.1 christos static void
532 1.1 christos tcp_disconnect_callback(comm_t *NONNULL comm, void *NULLABLE context, int error)
533 1.1 christos {
534 1.1 christos (void)comm;
535 1.1 christos (void)context;
536 1.1 christos (void)error;
537 1.1 christos fprintf(stderr, "tcp remote close.\n");
538 1.1 christos exit(0);
539 1.1 christos }
540 1.1 christos
541 1.1 christos static int
542 1.1 christos start_tcp_test(void)
543 1.1 christos {
544 1.1 christos addr_t address;
545 1.1 christos memset(&address, 0, sizeof(address));
546 1.1 christos address.sa.sa_family = AF_INET;
547 1.1 christos address.sin.sin_addr.s_addr = htonl(0x7f000001);
548 1.1 christos address.sin.sin_port = htons(53);
549 1.1 christos #ifndef NOT_HAVE_SA_LEN
550 1.1 christos address.sin.sin_len = sizeof(address.sin);
551 1.1 christos #endif
552 1.1 christos tcp_connection = ioloop_connection_create(&address, false, true, false, false, tcp_datagram_callback,
553 1.1 christos tcp_connect_callback, tcp_disconnect_callback, NULL, NULL);
554 1.1 christos if (tcp_connection == NULL) {
555 1.1 christos return kDNSSDAdvertisingProxyStatus_NoMemory;
556 1.1 christos }
557 1.1 christos return kDNSSDAdvertisingProxyStatus_NoError;
558 1.1 christos }
559 1.1 christos
560 1.1 christos const char *need_name, *need_service;
561 1.1 christos bool needed_flag;
562 1.1 christos
563 1.1 christos advertising_proxy_conn_ref service_sub;
564 1.1 christos
565 1.1 christos static void
566 1.1 christos service_callback(advertising_proxy_conn_ref UNUSED sub, void *UNUSED context, advertising_proxy_error_type error)
567 1.1 christos {
568 1.1 christos fprintf(stderr, "service callback: %d\n", error);
569 1.1 christos exit(0);
570 1.1 christos }
571 1.1 christos
572 1.1 christos static void
573 1.1 christos start_needing_service(void)
574 1.1 christos {
575 1.1 christos advertising_proxy_error_type ret = advertising_proxy_set_service_needed(&service_sub, dispatch_get_main_queue(),
576 1.1 christos service_callback, NULL, NULL, need_service,
577 1.1 christos needed_flag);
578 1.1 christos if (ret != kDNSSDAdvertisingProxyStatus_NoError) {
579 1.1 christos fprintf(stderr, "advertising_proxy_service_create failed: %d\n", ret);
580 1.1 christos exit(1);
581 1.1 christos }
582 1.1 christos }
583 1.1 christos
584 1.1 christos advertising_proxy_conn_ref instance_sub;
585 1.1 christos
586 1.1 christos static void
587 1.1 christos instance_callback(advertising_proxy_conn_ref UNUSED sub, void *UNUSED context, advertising_proxy_error_type error)
588 1.1 christos {
589 1.1 christos fprintf(stderr, "instance callback: %d\n", error);
590 1.1 christos exit(0);
591 1.1 christos }
592 1.1 christos
593 1.1 christos static void
594 1.1 christos start_needing_instance(void)
595 1.1 christos {
596 1.1 christos advertising_proxy_error_type ret = advertising_proxy_set_service_needed(&instance_sub, dispatch_get_main_queue(),
597 1.1 christos instance_callback, NULL, need_name,
598 1.1 christos need_service, needed_flag);
599 1.1 christos if (ret != kDNSSDAdvertisingProxyStatus_NoError) {
600 1.1 christos fprintf(stderr, "advertising_proxy_set_service_needed failed: %d\n", ret);
601 1.1 christos exit(1);
602 1.1 christos }
603 1.1 christos }
604 1.1 christos
605 1.1 christos const char *browse_service, *resolve_name, *resolve_service;
606 1.1 christos
607 1.1 christos advertising_proxy_subscription_t *browse_sub;
608 1.1 christos
609 1.1 christos static void
610 1.1 christos browse_callback(advertising_proxy_subscription_t *UNUSED sub, advertising_proxy_error_type error, uint32_t interface_index,
611 1.1 christos bool add, const char *instance_name, const char *service_type, void *UNUSED context)
612 1.1 christos {
613 1.1 christos if (error != kDNSSDAdvertisingProxyStatus_NoError) {
614 1.1 christos fprintf(stderr, "browse_callback: %d\n", error);
615 1.1 christos exit(1);
616 1.1 christos }
617 1.1 christos
618 1.1 christos fprintf(stderr, "browse: %d %s %s %s\n", interface_index, add ? "add" : "rmv", instance_name, service_type);
619 1.1 christos }
620 1.1 christos
621 1.1 christos static void
622 1.1 christos start_browsing_service(void)
623 1.1 christos {
624 1.1 christos advertising_proxy_error_type ret = advertising_proxy_browse_create(&browse_sub, dispatch_get_main_queue(),
625 1.1 christos browse_service, browse_callback, NULL);
626 1.1 christos if (ret != kDNSSDAdvertisingProxyStatus_NoError) {
627 1.1 christos fprintf(stderr, "advertising_proxy_browse_create failed: %d\n", ret);
628 1.1 christos exit(1);
629 1.1 christos }
630 1.1 christos }
631 1.1 christos
632 1.1 christos advertising_proxy_subscription_t *resolve_sub;
633 1.1 christos
634 1.1 christos static void
635 1.1 christos resolve_callback(advertising_proxy_subscription_t *UNUSED sub, advertising_proxy_error_type error,
636 1.1 christos uint32_t interface_index, bool add, const char *fullname, const char *hostname, uint16_t port,
637 1.1 christos uint16_t txt_length, const uint8_t *UNUSED txt_record, void *UNUSED context)
638 1.1 christos {
639 1.1 christos if (error != kDNSSDAdvertisingProxyStatus_NoError) {
640 1.1 christos fprintf(stderr, "resolve_create callback: %d\n", error);
641 1.1 christos exit(1);
642 1.1 christos }
643 1.1 christos
644 1.1 christos fprintf(stderr, "resolved: %d %s %s %s %d %d\n", interface_index, add ? "add" : "rmv",
645 1.1 christos fullname, hostname, port, txt_length);
646 1.1 christos }
647 1.1 christos
648 1.1 christos static void
649 1.1 christos start_resolving_service(void)
650 1.1 christos {
651 1.1 christos advertising_proxy_error_type ret = advertising_proxy_resolve_create(&resolve_sub, dispatch_get_main_queue(),
652 1.1 christos resolve_name, resolve_service, NULL,
653 1.1 christos resolve_callback, NULL);
654 1.1 christos if (ret != kDNSSDAdvertisingProxyStatus_NoError) {
655 1.1 christos fprintf(stderr, "advertising_proxy_resolve_create failed: %d\n", ret);
656 1.1 christos exit(1);
657 1.1 christos }
658 1.1 christos }
659 1.1 christos
660 1.1 christos advertising_proxy_subscription_t *registrar_sub;
661 1.1 christos
662 1.1 christos static void
663 1.1 christos registrar_callback(advertising_proxy_subscription_t *UNUSED sub,
664 1.1 christos advertising_proxy_error_type error, void *UNUSED context)
665 1.1 christos {
666 1.1 christos if (error != kDNSSDAdvertisingProxyStatus_NoError) {
667 1.1 christos fprintf(stderr, "registrar_callback: %d\n", error);
668 1.1 christos exit(1);
669 1.1 christos }
670 1.1 christos
671 1.1 christos INFO("SRP registrar is enabled.");
672 1.1 christos }
673 1.1 christos
674 1.1 christos static void
675 1.1 christos start_registrar(void)
676 1.1 christos {
677 1.1 christos advertising_proxy_error_type ret = advertising_proxy_registrar_create(®istrar_sub, dispatch_get_main_queue(),
678 1.1 christos registrar_callback, NULL);
679 1.1 christos if (ret != kDNSSDAdvertisingProxyStatus_NoError) {
680 1.1 christos fprintf(stderr, "advertising_proxy_registrar_create failed: %d", ret);
681 1.1 christos exit(1);
682 1.1 christos }
683 1.1 christos }
684 1.1 christos
685 1.1 christos
686 1.1 christos static void
687 1.1 christos usage(void)
688 1.1 christos {
689 1.1 christos fprintf(stderr, "srputil start [if1 .. ifN -] -- start the SRP MDNS Proxy through launchd\n");
690 1.1 christos fprintf(stderr, " tcp-zero -- connect to port 53, send a DNS message that's got a zero-length payload\n");
691 1.1 christos fprintf(stderr, " tcp-fin-length -- connect to port 53, send a DNS message that ends before length is complete\n");
692 1.1 christos fprintf(stderr, " tcp-fin-payload -- connect to port 53, send a DNS message that ends before payload is complete\n");
693 1.1 christos fprintf(stderr, " services -- get the list of services currently being advertised\n");
694 1.1 christos fprintf(stderr, " block -- block the SRP listener\n");
695 1.1 christos fprintf(stderr, " unblock -- unblock the SRP listener\n");
696 1.1 christos fprintf(stderr, " regenerate-ula -- generate a new ULA and restart the network\n");
697 1.1 christos fprintf(stderr, " adv-prefix-high -- advertise high-priority prefix to thread network\n");
698 1.1 christos fprintf(stderr, " adv-prefix -- advertise prefix to thread network\n");
699 1.1 christos fprintf(stderr, " stop -- stop advertising as SRP server\n");
700 1.1 christos fprintf(stderr, " get-ula -- fetch the current ULA prefix configured on the SRP server\n");
701 1.1 christos fprintf(stderr, " disable-srpl -- disable SRP replication\n");
702 1.1 christos fprintf(stderr, " add-prefix <ipv6 prefix> -- add an OMR prefix\n");
703 1.1 christos fprintf(stderr, " remove-prefix <ipv6 prefix -- remove an OMR prefix\n");
704 1.1 christos fprintf(stderr, " add-nat64-prefix <nat64 prefix> -- add an nat64 prefix\n");
705 1.1 christos fprintf(stderr, " remove-nat64-prefix <nat64 prefix> -- remove an nat64 prefix\n");
706 1.1 christos fprintf(stderr, " drop-srpl-connection -- drop existing srp replication connections\n");
707 1.1 christos fprintf(stderr, " undrop-srpl-connection -- restart srp replication connections that were dropped \n");
708 1.1 christos fprintf(stderr, " drop-srpl-advertisement -- stop advertising srpl service (but keep it around)\n");
709 1.1 christos fprintf(stderr, " undrop-srpl-advertisement -- resume advertising srpl service\n");
710 1.1 christos fprintf(stderr, " start-dropping-push -- start repeatedly dropping any active push connections after 90 seconds\n");
711 1.1 christos fprintf(stderr, " start-breaking-time -- start breaking time validation on replicated SRP registrations\n");
712 1.1 christos fprintf(stderr, " set [variable] [value] -- set the value of variable to value (e.g. set min-lease-time 100)\n");
713 1.1 christos fprintf(stderr, " block-anycast-service -- block advertising anycast service\n");
714 1.1 christos fprintf(stderr, " unblock-anycast-service -- unblock advertising anycast service\n");
715 1.1 christos fprintf(stderr, " start-thread-shutdown -- start thread network shutdown\n");
716 1.1 christos fprintf(stderr, " advertise-winning-unicast-service -- advertise a unicast service that wins over the current service\n");
717 1.1 christos fprintf(stderr, " browse <service> -- start an advertising_proxy_browse on the specified service\n");
718 1.1 christos fprintf(stderr, " resolve <name> <service> -- start an advertising_proxy_resolve on the specified service instance\n");
719 1.1 christos fprintf(stderr, " need-service <service> <flag> -- signal to srp-mdns-proxy that we need to discover a service\n");
720 1.1 christos fprintf(stderr, " need-instance <name> <service> <flag> -- signal to srp-mdns-proxy that we need to discover a service\n");
721 1.1 christos fprintf(stderr, " start-srp -- on thread device, enable srp registration\n");
722 1.1 christos #ifdef NOTYET
723 1.1 christos fprintf(stderr, " flush -- flush all entries from the SRP proxy (for testing only)\n");
724 1.1 christos #endif
725 1.1 christos }
726 1.1 christos
727 1.1 christos bool start_proxy = false;
728 1.1 christos bool flush_entries = false;
729 1.1 christos bool list_services = false;
730 1.1 christos bool block = false;
731 1.1 christos bool unblock = false;
732 1.1 christos bool regenerate_ula = false;
733 1.1 christos bool adv_prefix = false;
734 1.1 christos bool adv_prefix_high = false;
735 1.1 christos bool stop_proxy = false;
736 1.1 christos bool dump_stdin = false;
737 1.1 christos bool get_ula = false;
738 1.1 christos bool disable_srp_replication = false;
739 1.1 christos bool dso_test = false;
740 1.1 christos bool drop_srpl_connection;
741 1.1 christos bool undrop_srpl_connection;
742 1.1 christos bool drop_srpl_advertisement;
743 1.1 christos bool undrop_srpl_advertisement;
744 1.1 christos bool start_dropping_push_connections;
745 1.1 christos bool add_thread_prefix = false;
746 1.1 christos bool remove_thread_prefix = false;
747 1.1 christos bool add_nat64_prefix = false;
748 1.1 christos bool remove_nat64_prefix = false;
749 1.1 christos bool start_breaking_time_validation = false;
750 1.1 christos bool test_route_tracker = false;
751 1.1 christos bool block_anycast_service = false;
752 1.1 christos bool unblock_anycast_service = false;
753 1.1 christos bool start_thread_shutdown = false;
754 1.1 christos bool advertise_winning_unicast_service = false;
755 1.1 christos bool remove_unicast_service = false;
756 1.1 christos bool start_srp = false;
757 1.1 christos uint8_t prefix_buf[16];
758 1.1 christos #ifdef NOTYET
759 1.1 christos bool watch = false;
760 1.1 christos bool get = false;
761 1.1 christos #endif
762 1.1 christos variable_t *variables;
763 1.1 christos int num_permitted_interfaces;
764 1.1 christos char **permitted_interfaces;
765 1.1 christos
766 1.1 christos static void
767 1.1 christos start_activities(void *context)
768 1.1 christos {
769 1.1 christos advertising_proxy_error_type err = kDNSSDAdvertisingProxyStatus_NoError;;
770 1.1 christos advertising_proxy_conn_ref cref = NULL;
771 1.1 christos (void)context;
772 1.1 christos
773 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && flush_entries) {
774 1.1 christos err = advertising_proxy_flush_entries(&cref, main_queue, flushed_callback);
775 1.1 christos }
776 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && (do_tcp_zero_test ||
777 1.1 christos do_tcp_fin_length || do_tcp_fin_payload)) {
778 1.1 christos err = start_tcp_test();
779 1.1 christos }
780 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && list_services) {
781 1.1 christos err = advertising_proxy_get_service_list(&cref, main_queue, services_callback);
782 1.1 christos }
783 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && block) {
784 1.1 christos err = advertising_proxy_block_service(&cref, main_queue, block_callback);
785 1.1 christos }
786 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && unblock) {
787 1.1 christos err = advertising_proxy_unblock_service(&cref, main_queue, unblock_callback);
788 1.1 christos }
789 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && regenerate_ula) {
790 1.1 christos err = advertising_proxy_regenerate_ula(&cref, main_queue, regenerate_callback);
791 1.1 christos }
792 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && adv_prefix) {
793 1.1 christos err = advertising_proxy_advertise_prefix(&cref, adv_prefix_high, main_queue, prefix_advertise_callback);
794 1.1 christos }
795 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && stop_proxy) {
796 1.1 christos err = advertising_proxy_stop(&cref, main_queue, stop_callback);
797 1.1 christos }
798 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && get_ula) {
799 1.1 christos err = advertising_proxy_get_ula(&cref, main_queue, ula_callback);
800 1.1 christos }
801 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && disable_srp_replication) {
802 1.1 christos err = advertising_proxy_disable_srp_replication(&cref, main_queue, disable_srp_replication_callback);
803 1.1 christos }
804 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && add_thread_prefix) {
805 1.1 christos err = advertising_proxy_add_prefix(&cref, main_queue, add_prefix_callback, prefix_buf, sizeof(prefix_buf));
806 1.1 christos }
807 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && remove_thread_prefix) {
808 1.1 christos err = advertising_proxy_remove_prefix(&cref, main_queue, remove_prefix_callback, prefix_buf, sizeof(prefix_buf));
809 1.1 christos }
810 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && add_nat64_prefix) {
811 1.1 christos err = advertising_proxy_add_nat64_prefix(&cref, main_queue, add_nat64_prefix_callback, prefix_buf, sizeof(prefix_buf));
812 1.1 christos }
813 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && remove_nat64_prefix) {
814 1.1 christos err = advertising_proxy_remove_nat64_prefix(&cref, main_queue, remove_nat64_prefix_callback, prefix_buf, sizeof(prefix_buf));
815 1.1 christos }
816 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && drop_srpl_connection) {
817 1.1 christos err = advertising_proxy_drop_srpl_connection(&cref, main_queue, drop_srpl_connection_callback);
818 1.1 christos }
819 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && undrop_srpl_connection) {
820 1.1 christos err = advertising_proxy_undrop_srpl_connection(&cref, main_queue, undrop_srpl_connection_callback);
821 1.1 christos }
822 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && drop_srpl_advertisement) {
823 1.1 christos err = advertising_proxy_drop_srpl_advertisement(&cref, main_queue, drop_srpl_advertisement_callback);
824 1.1 christos }
825 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && undrop_srpl_advertisement) {
826 1.1 christos err = advertising_proxy_undrop_srpl_advertisement(&cref, main_queue, undrop_srpl_advertisement_callback);
827 1.1 christos }
828 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && start_dropping_push_connections) {
829 1.1 christos err = advertising_proxy_start_dropping_push_connections(&cref, main_queue, start_dropping_push_connections_callback);
830 1.1 christos }
831 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && start_breaking_time_validation) {
832 1.1 christos err = advertising_proxy_start_breaking_time_validation(&cref, main_queue, start_breaking_time_validation_callback);
833 1.1 christos }
834 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && block_anycast_service) {
835 1.1 christos err = advertising_proxy_block_anycast_service(&cref, main_queue, block_anycast_service_callback);
836 1.1 christos }
837 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && unblock_anycast_service) {
838 1.1 christos err = advertising_proxy_unblock_anycast_service(&cref, main_queue, unblock_anycast_service_callback);
839 1.1 christos }
840 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && start_thread_shutdown) {
841 1.1 christos err = advertising_proxy_start_thread_shutdown(&cref, main_queue, start_thread_shutdown_callback);
842 1.1 christos }
843 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && test_route_tracker) {
844 1.1 christos route_tracker_test_start(1000);
845 1.1 christos }
846 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && advertise_winning_unicast_service) {
847 1.1 christos start_advertising_winning_unicast_service();
848 1.1 christos }
849 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && remove_unicast_service) {
850 1.1 christos start_removing_unicast_service();
851 1.1 christos }
852 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && advertise_winning_unicast_service) {
853 1.1 christos start_advertising_winning_unicast_service();
854 1.1 christos }
855 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && browse_service != NULL) {
856 1.1 christos start_browsing_service();
857 1.1 christos }
858 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && resolve_service != NULL) {
859 1.1 christos start_resolving_service();
860 1.1 christos }
861 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && need_service != NULL && need_name == NULL) {
862 1.1 christos start_needing_service();
863 1.1 christos }
864 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && need_service != NULL && need_name != NULL) {
865 1.1 christos start_needing_instance();
866 1.1 christos }
867 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && start_srp) {
868 1.1 christos start_registrar();
869 1.1 christos }
870 1.1 christos if (err == kDNSSDAdvertisingProxyStatus_NoError && variables != NULL) {
871 1.1 christos for (variable_t *variable = variables; variable != NULL; variable = variable->next) {
872 1.1 christos err = advertising_proxy_set_variable(&cref, main_queue, set_variable_callback, variable, variable->name, variable->value);
873 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
874 1.1 christos break;
875 1.1 christos }
876 1.1 christos }
877 1.1 christos }
878 1.1 christos if (err != kDNSSDAdvertisingProxyStatus_NoError) {
879 1.1 christos exit(1);
880 1.1 christos }
881 1.1 christos }
882 1.1 christos
883 1.1 christos static void
884 1.1 christos dump_packet(void)
885 1.1 christos {
886 1.1 christos ssize_t len;
887 1.1 christos dns_message_t *message = NULL;
888 1.1 christos dns_wire_t wire;
889 1.1 christos
890 1.1 christos len = read(0, &wire, sizeof(wire));
891 1.1 christos if (len < 0) {
892 1.1 christos ERROR("stdin: %s", strerror(errno));
893 1.1 christos return;
894 1.1 christos }
895 1.1 christos if (len < DNS_HEADER_SIZE) {
896 1.1 christos ERROR("stdin: too short: %zd bytes", len);
897 1.1 christos return;
898 1.1 christos }
899 1.1 christos if (!dns_wire_parse(&message, &wire, (unsigned)len, true)) {
900 1.1 christos fprintf(stderr, "DNS message parse failed\n");
901 1.1 christos return;
902 1.1 christos }
903 1.1 christos }
904 1.1 christos
905 1.1 christos int
906 1.1 christos main(int argc, char **argv)
907 1.1 christos {
908 1.1 christos int i;
909 1.1 christos bool something = false;
910 1.1 christos bool log_stderr = false;
911 1.1 christos
912 1.1 christos for (i = 1; i < argc; i++) {
913 1.1 christos if (!strcmp(argv[i], "start")) {
914 1.1 christos start_proxy = true;
915 1.1 christos something = true;
916 1.1 christos int j;
917 1.1 christos for (j = i + 1; j < argc; j++) {
918 1.1 christos if (!strcmp(argv[j], "-")) {
919 1.1 christos break;
920 1.1 christos }
921 1.1 christos }
922 1.1 christos num_permitted_interfaces = j - i - 1;
923 1.1 christos permitted_interfaces = argv + i + 1;
924 1.1 christos i = j;
925 1.1 christos } else if (!strcmp(argv[i], "tcp-zero")) {
926 1.1 christos do_tcp_zero_test = true;
927 1.1 christos something = true;
928 1.1 christos } else if (!strcmp(argv[i], "tcp-fin-length")) {
929 1.1 christos do_tcp_fin_length = true;
930 1.1 christos something = true;
931 1.1 christos } else if (!strcmp(argv[i], "tcp-fin-payload")) {
932 1.1 christos do_tcp_fin_payload = true;
933 1.1 christos something = true;
934 1.1 christos } else if (!strcmp(argv[i], "flush")) {
935 1.1 christos flush_entries = true;
936 1.1 christos something = true;
937 1.1 christos } else if (!strcmp(argv[i], "services")) {
938 1.1 christos list_services = true;
939 1.1 christos something = true;
940 1.1 christos } else if (!strcmp(argv[i], "block")) {
941 1.1 christos block = true;
942 1.1 christos something = true;
943 1.1 christos } else if (!strcmp(argv[i], "unblock")) {
944 1.1 christos unblock = true;
945 1.1 christos something = true;
946 1.1 christos } else if (!strcmp(argv[i], "regenerate-ula")) {
947 1.1 christos regenerate_ula = true;
948 1.1 christos something = true;
949 1.1 christos } else if (!strcmp(argv[i], "adv-prefix")) {
950 1.1 christos adv_prefix = true;
951 1.1 christos something = true;
952 1.1 christos } else if (!strcmp(argv[i], "adv-prefix-high")) {
953 1.1 christos adv_prefix = true;
954 1.1 christos adv_prefix_high = true;
955 1.1 christos something = true;
956 1.1 christos } else if (!strcmp(argv[i], "stop")) {
957 1.1 christos stop_proxy = true;
958 1.1 christos something = true;
959 1.1 christos } else if (!strcmp(argv[i], "dump")) {
960 1.1 christos dump_packet();
961 1.1 christos exit(0);
962 1.1 christos } else if (!strcmp(argv[i], "get-ula")) {
963 1.1 christos get_ula = true;
964 1.1 christos something = true;
965 1.1 christos } else if (!strcmp(argv[i], "disable-srpl")) {
966 1.1 christos disable_srp_replication = true;
967 1.1 christos something = true;
968 1.1 christos } else if (!strcmp(argv[i], "add-prefix")) {
969 1.1 christos if (i + 1 >= argc) {
970 1.1 christos usage();
971 1.1 christos }
972 1.1 christos if (inet_pton(AF_INET6, argv[i + 1], prefix_buf) < 1) {
973 1.1 christos fprintf(stderr, "Invalid ipv6 prefix %s.\n", argv[i + 1]);
974 1.1 christos usage();
975 1.1 christos } else {
976 1.1 christos add_thread_prefix = true;
977 1.1 christos something = true;
978 1.1 christos i++;
979 1.1 christos }
980 1.1 christos } else if (!strcmp(argv[i], "remove-prefix")) {
981 1.1 christos if (i + 1 >= argc) {
982 1.1 christos usage();
983 1.1 christos }
984 1.1 christos if (inet_pton(AF_INET6, argv[i + 1], prefix_buf) < 1) {
985 1.1 christos fprintf(stderr, "Invalid ipv6 prefix %s.\n", argv[i + 1]);
986 1.1 christos usage();
987 1.1 christos } else {
988 1.1 christos remove_thread_prefix = true;
989 1.1 christos something = true;
990 1.1 christos i++;
991 1.1 christos }
992 1.1 christos } else if (!strcmp(argv[i], "add-nat64-prefix")) {
993 1.1 christos if (i + 1 >= argc) {
994 1.1 christos usage();
995 1.1 christos }
996 1.1 christos if (inet_pton(AF_INET6, argv[i + 1], prefix_buf) < 1) {
997 1.1 christos fprintf(stderr, "Invalid ipv6 prefix %s.\n", argv[i + 1]);
998 1.1 christos usage();
999 1.1 christos } else {
1000 1.1 christos add_nat64_prefix = true;
1001 1.1 christos something = true;
1002 1.1 christos i++;
1003 1.1 christos }
1004 1.1 christos } else if (!strcmp(argv[i], "remove-nat64-prefix")) {
1005 1.1 christos if (i + 1 >= argc) {
1006 1.1 christos usage();
1007 1.1 christos }
1008 1.1 christos if (inet_pton(AF_INET6, argv[i + 1], prefix_buf) < 1) {
1009 1.1 christos fprintf(stderr, "Invalid ipv6 prefix %s.\n", argv[i + 1]);
1010 1.1 christos usage();
1011 1.1 christos } else {
1012 1.1 christos remove_nat64_prefix = true;
1013 1.1 christos something = true;
1014 1.1 christos i++;
1015 1.1 christos }
1016 1.1 christos } else if (!strcmp(argv[i], "browse")) {
1017 1.1 christos if (i + 1 >= argc) {
1018 1.1 christos usage();
1019 1.1 christos }
1020 1.1 christos browse_service = argv[i + 1];
1021 1.1 christos i++;
1022 1.1 christos something = true;
1023 1.1 christos } else if (!strcmp(argv[i], "resolve")) {
1024 1.1 christos if (i + 2 >= argc) {
1025 1.1 christos usage();
1026 1.1 christos }
1027 1.1 christos resolve_name = argv[i + 1];
1028 1.1 christos resolve_service = argv[i + 2];
1029 1.1 christos i += 2;
1030 1.1 christos something = true;
1031 1.1 christos } else if (!strcmp(argv[i], "need-service")) {
1032 1.1 christos if (i + 2 >= argc) {
1033 1.1 christos usage();
1034 1.1 christos }
1035 1.1 christos need_service = argv[i + 1];
1036 1.1 christos if (!strcmp(argv[i + 2], "true")) {
1037 1.1 christos needed_flag = true;
1038 1.1 christos } else {
1039 1.1 christos needed_flag = false;
1040 1.1 christos }
1041 1.1 christos i += 2;
1042 1.1 christos something = true;
1043 1.1 christos } else if (!strcmp(argv[i], "need-instance")) {
1044 1.1 christos if (i + 3 >= argc) {
1045 1.1 christos usage();
1046 1.1 christos }
1047 1.1 christos need_name = argv[i + 1];
1048 1.1 christos need_service = argv[i + 2];
1049 1.1 christos if (!strcmp(argv[i + 3], "true")) {
1050 1.1 christos needed_flag = true;
1051 1.1 christos } else {
1052 1.1 christos needed_flag = false;
1053 1.1 christos }
1054 1.1 christos i += 3;
1055 1.1 christos something = true;
1056 1.1 christos } else if (!strcmp(argv[i], "start-srp")) {
1057 1.1 christos start_srp = true;
1058 1.1 christos something = true;
1059 1.1 christos } else if (!strcmp(argv[i], "drop-srpl-connection")) {
1060 1.1 christos drop_srpl_connection = true;
1061 1.1 christos something = true;
1062 1.1 christos } else if (!strcmp(argv[i], "undrop-srpl-connection")) {
1063 1.1 christos undrop_srpl_connection = true;
1064 1.1 christos something = true;
1065 1.1 christos } else if (!strcmp(argv[i], "drop-srpl-advertisement")) {
1066 1.1 christos drop_srpl_advertisement = true;
1067 1.1 christos something = true;
1068 1.1 christos } else if (!strcmp(argv[i], "undrop-srpl-advertisement")) {
1069 1.1 christos undrop_srpl_advertisement = true;
1070 1.1 christos something = true;
1071 1.1 christos } else if (!strcmp(argv[i], "start-dropping-push")) {
1072 1.1 christos start_dropping_push_connections = true;
1073 1.1 christos something = true;
1074 1.1 christos } else if (!strcmp(argv[i], "start-breaking-time")) {
1075 1.1 christos start_breaking_time_validation = true;
1076 1.1 christos something = true;
1077 1.1 christos } else if (!strcmp(argv[i], "block-anycast-service")) {
1078 1.1 christos block_anycast_service = true;
1079 1.1 christos something = true;
1080 1.1 christos } else if (!strcmp(argv[i], "unblock-anycast-service")) {
1081 1.1 christos unblock_anycast_service = true;
1082 1.1 christos something = true;
1083 1.1 christos } else if (!strcmp(argv[i], "test-route-tracker")) {
1084 1.1 christos test_route_tracker = true;
1085 1.1 christos something = true;
1086 1.1 christos } else if (!strcmp(argv[i], "start-thread-shutdown")) {
1087 1.1 christos start_thread_shutdown = true;
1088 1.1 christos something = true;
1089 1.1 christos } else if (!strcmp(argv[i], "advertise-winning-unicast-service")) {
1090 1.1 christos advertise_winning_unicast_service = true;
1091 1.1 christos something = true;
1092 1.1 christos } else if (!strcmp(argv[i], "remove-unicast-service")) {
1093 1.1 christos remove_unicast_service = true;
1094 1.1 christos something = true;
1095 1.1 christos } else if (!strcmp(argv[i], "set")) {
1096 1.1 christos if (i + 2 >= argc) {
1097 1.1 christos usage();
1098 1.1 christos }
1099 1.1 christos variable_t *variable = calloc(1, sizeof(*variable));
1100 1.1 christos if (variable == NULL) {
1101 1.1 christos fprintf(stderr, "no memory for variable %s", argv[i + 1]);
1102 1.1 christos exit(1);
1103 1.1 christos }
1104 1.1 christos variable->name = argv[i + 1];
1105 1.1 christos variable->value = argv[i + 2];
1106 1.1 christos variable->next = variables;
1107 1.1 christos variables = variable;
1108 1.1 christos i += 2;
1109 1.1 christos something = true;
1110 1.1 christos #ifdef NOTYET
1111 1.1 christos } else if (!strcmp(argv[i], "watch")) {
1112 1.1 christos fprintf(stderr, "Watching not implemented yet.\n");
1113 1.1 christos exit(1);
1114 1.1 christos } else if (!strcmp(argv[i], "get")) {
1115 1.1 christos fprintf(stderr, "Getting not implemented yet.\n");
1116 1.1 christos exit(1);
1117 1.1 christos #endif
1118 1.1 christos } else if (!strcmp(argv[i], "--debug")) {
1119 1.1 christos OPENLOG("srputil", true);
1120 1.1 christos log_stderr = true;
1121 1.1 christos } else {
1122 1.1 christos usage();
1123 1.1 christos exit(1);
1124 1.1 christos }
1125 1.1 christos }
1126 1.1 christos
1127 1.1 christos if (!something) {
1128 1.1 christos usage();
1129 1.1 christos exit(1);
1130 1.1 christos }
1131 1.1 christos
1132 1.1 christos if (log_stderr == false) {
1133 1.1 christos OPENLOG("srputil", log_stderr);
1134 1.1 christos }
1135 1.1 christos
1136 1.1 christos ioloop_init();
1137 1.1 christos // Start the queue, //then// do the work
1138 1.1 christos ioloop_run_async(start_activities, NULL);
1139 1.1 christos ioloop();
1140 1.1 christos }
1141 1.1 christos
1142 1.1 christos // Local Variables:
1143 1.1 christos // mode: C
1144 1.1 christos // tab-width: 4
1145 1.1 christos // c-file-style: "bsd"
1146 1.1 christos // c-basic-offset: 4
1147 1.1 christos // fill-column: 108
1148 1.1 christos // indent-tabs-mode: nil
1149 1.1 christos // End:
1150