]> git.saurik.com Git - apple/configd.git/blame - dnsinfo/dnsinfo_server.c
configd-699.1.5.tar.gz
[apple/configd.git] / dnsinfo / dnsinfo_server.c
CommitLineData
dbf6a266 1/*
78403150 2 * Copyright (c) 2004-2008, 2011-2014 Apple Inc. All rights reserved.
dbf6a266
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * Modification History
26 *
27 * March 9, 2004 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31#include <notify.h>
32#include <sysexits.h>
33#include <syslog.h>
34#include <unistd.h>
35#include <sys/types.h>
36#include <servers/bootstrap.h>
37#include <mach/mach.h>
38#include <mach/mach_error.h>
edebe297 39#include <bsm/libbsm.h>
5e9ce69e
A
40#include <dispatch/dispatch.h>
41#include <xpc/xpc.h>
edebe297 42
dbf6a266
A
43#include <CoreFoundation/CoreFoundation.h>
44#include <SystemConfiguration/SCPrivate.h>
45
5e9ce69e
A
46#include "libSystemConfiguration_client.h"
47#include "libSystemConfiguration_server.h"
48
49#include "dnsinfo_create.h"
dbf6a266
A
50#include "dnsinfo_server.h"
51#include "dnsinfo_private.h"
52
5e9ce69e
A
53#pragma mark -
54#pragma mark Globals
dbf6a266 55
dbf6a266 56
5e9ce69e
A
57/*
58 * S_dns_info
59 *
60 * Note: all accesses should be made while running on the _dns_server_queue()
61 */
62static libSC_info_server_t S_dns_info;
63
17d3ee29 64
5e9ce69e
A
65/*
66 * S_debug
67 * A boolean that enables additional logging.
68 */
78403150
A
69static Boolean S_debug_s;
70static Boolean * S_debug = &S_debug_s;
5e9ce69e
A
71static SCLoggerRef S_logger = NULL;
72
73
74/*
75 * S_sync_handler
76 * ACK (in-sync or not-in-sync) updates should be posted using
77 * this handler
78 *
79 * Note: all accesses should be made while running on the _dns_server_queue()
80 */
81static _dns_sync_handler_t S_sync_handler = NULL;
82
83
84#pragma mark -
85#pragma mark Support functions
86
87
88#ifdef NOT_YET_NEEDED
89static void
90log_xpc_object(const char *msg, xpc_object_t obj)
91{
92 char *desc;
93
94 desc = xpc_copy_description(obj);
95 if (*S_debug) {
78403150 96 SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("%s = %s"), msg, desc);
dbf6a266 97 }
5e9ce69e
A
98 free(desc);
99}
100#endif
101
102
103#pragma mark -
104#pragma mark DNS configuration server
dbf6a266 105
5e9ce69e
A
106
107static dispatch_queue_t
108_dnsinfo_server_queue()
109{
110 static dispatch_once_t once;
111 static dispatch_queue_t q;
112
113 dispatch_once(&once, ^{
114 q = dispatch_queue_create(DNSINFO_SERVICE_NAME ".server", NULL);
115 });
116
117 return q;
dbf6a266
A
118}
119
120
5e9ce69e
A
121/*
122 * _dnsinfo_copy
123 *
124 * Called when a client wants a copy of the current
125 * DNS configuration
126 *
127 * - caller must be running on the _dns_server_queue()
128 */
129static void
130_dnsinfo_copy(xpc_connection_t connection, xpc_object_t request)
dbf6a266 131{
5e9ce69e
A
132 CFDataRef data;
133 uint64_t generation;
134 xpc_connection_t remote;
135 xpc_object_t reply;
136
137 remote = xpc_dictionary_get_remote_connection(request);
138 reply = xpc_dictionary_create_reply(request);
139 if (reply == NULL) {
140 SCLoggerLog(S_logger, LOG_ERR,
141 CFSTR("<%p> _dnsinfo_copy: xpc_dictionary_create_reply: failed"),
142 connection);
143 return;
144 }
dbf6a266 145
5e9ce69e
A
146 // extract data and generation #
147 data = _libSC_info_server_get_data(&S_dns_info,
148 connection,
149 &generation);
150
151 if (*S_debug) {
152 const char *proc_name;
153
154 // extract process name
155 proc_name = xpc_dictionary_get_string(request, DNSINFO_PROC_NAME);
156 if (proc_name == NULL) {
157 proc_name = "???";
dbf6a266 158 }
5e9ce69e 159
78403150 160 SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("<%p:%s[%d]> DNS configuration copy: %llu"),
5e9ce69e
A
161 connection,
162 proc_name,
163 xpc_connection_get_pid(connection),
164 generation);
dbf6a266
A
165 }
166
5e9ce69e
A
167 // return the DNS configuration (if available)
168 if (data != NULL) {
169 xpc_dictionary_set_data(reply,
170 DNSINFO_CONFIGURATION,
171 CFDataGetBytePtr(data),
172 CFDataGetLength(data));
dbf6a266
A
173 }
174
5e9ce69e
A
175 // reply
176 xpc_connection_send_message(remote, reply);
177 xpc_release(reply);
178
179 return;
180}
181
182
183/*
184 * _dnsinfo_acknowledge
185 *
186 * Called when a client wants to acknowledge processing
187 * of the DNS configuration
188 *
189 * - caller must be running on the _dns_server_queue()
190 */
191static void
192_dnsinfo_acknowledge(xpc_connection_t connection, xpc_object_t request)
193{
194 uint64_t generation;
195 Boolean inSync;
196
197 generation = xpc_dictionary_get_uint64(request, DNSINFO_GENERATION);
198
199 if (*S_debug) {
78403150 200 SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("<%p:%d> DNS configuration ack: %llu"),
5e9ce69e
A
201 connection,
202 xpc_connection_get_pid(connection),
203 generation);
edebe297
A
204 }
205
5e9ce69e 206 (void) _libSC_info_server_acknowledged(&S_dns_info, connection, generation);
dbf6a266 207
5e9ce69e
A
208 // Note: all of the mDNSResponder ack's should result
209 // in a [new] network change being posted
dbf6a266 210
5e9ce69e 211 inSync = _libSC_info_server_in_sync(&S_dns_info);
78403150
A
212 if (S_sync_handler) {
213 S_sync_handler(inSync);
214 }
5e9ce69e
A
215 return;
216}
217
218
219static void
220process_request(xpc_connection_t connection, xpc_object_t request)
221{
222 int64_t op;
223
224 op = xpc_dictionary_get_int64(request, DNSINFO_REQUEST);
225 switch (op) {
226 case DNSINFO_REQUEST_COPY :
227 /*
228 * Return the DNS configuration
229 */
230 _dnsinfo_copy(connection, request);
231 break;
232
233 case DNSINFO_REQUEST_ACKNOWLEDGE :
234 /*
235 * Acknowlege a [processed] DNS configuration
236 */
237 _dnsinfo_acknowledge(connection, request);
238
239 break;
240 default :
241 SCLoggerLog(S_logger, LOG_ERR,
78403150 242 CFSTR("<%p> unknown request : %lld"),
5e9ce69e
A
243 connection,
244 op);
245
246 break;
dbf6a266
A
247 }
248
5e9ce69e
A
249 return;
250}
dbf6a266 251
dbf6a266 252
5e9ce69e
A
253static void
254process_new_connection(xpc_connection_t c)
255{
256 if (*S_debug) {
78403150 257 SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("<%p:%d> DNS configuration session: open"),
5e9ce69e
A
258 c,
259 xpc_connection_get_pid(c));
260 }
261
262 _libSC_info_server_open(&S_dns_info, c);
263
264 xpc_connection_set_target_queue(c, _dnsinfo_server_queue());
265
266 xpc_connection_set_event_handler(c, ^(xpc_object_t xobj) {
267 xpc_type_t type;
268
269 type = xpc_get_type(xobj);
270 if (type == XPC_TYPE_DICTIONARY) {
271 // process the request
272 process_request(c, xobj);
273
274 } else if (type == XPC_TYPE_ERROR) {
275 const char *desc;
276
277 desc = xpc_dictionary_get_string(xobj, XPC_ERROR_KEY_DESCRIPTION);
278 if (xobj == XPC_ERROR_CONNECTION_INVALID) {
279 Boolean changed;
280
281 if (*S_debug) {
78403150 282 SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("<%p:%d> DNS configuration session: close"),
5e9ce69e
A
283 c,
284 xpc_connection_get_pid(c));
285 }
286
287 changed = _libSC_info_server_close(&S_dns_info, c);
288 if (changed) {
289 Boolean inSync;
290
291 // report change
292 inSync = _libSC_info_server_in_sync(&S_dns_info);
293 S_sync_handler(inSync);
294 }
295
296 } else if (xobj == XPC_ERROR_CONNECTION_INTERRUPTED) {
297 SCLoggerLog(S_logger, LOG_ERR,
298 CFSTR("<%p:%d> %s"),
299 c,
300 xpc_connection_get_pid(c),
301 desc);
302
303 } else {
304 SCLoggerLog(S_logger, LOG_ERR,
78403150 305 CFSTR("<%p:%d> Connection error: %p : %s"),
5e9ce69e
A
306 c,
307 xpc_connection_get_pid(c),
308 xobj,
309 desc);
310 }
311
312 } else {
313 SCLoggerLog(S_logger, LOG_ERR,
78403150 314 CFSTR("<%p:%d> unknown event type : %p"),
5e9ce69e
A
315 c,
316 xpc_connection_get_pid(c),
317 type);
318 }
319 });
320
321 xpc_connection_resume(c);
322
323 return;
dbf6a266 324}
17d3ee29
A
325
326
5e9ce69e
A
327#pragma mark -
328#pragma mark DNS configuration server SPIs
329
330
17d3ee29 331__private_extern__
5e9ce69e
A
332void
333load_DNSConfiguration(CFBundleRef bundle,
334 SCLoggerRef logger,
335 Boolean *bundleVerbose,
336 _dns_sync_handler_t syncHandler)
17d3ee29 337{
5e9ce69e
A
338 xpc_connection_t c;
339 const char *name;
340
341 S_debug = bundleVerbose;
342 S_logger = logger;
343
344 /*
345 * keep track of DNS configuration acknowledgements
346 */
347 _libSC_info_server_init(&S_dns_info);
348
349 /*
350 * save the in-sync/not-in-sync handler
351 */
352 S_sync_handler = Block_copy(syncHandler);
353
354 // create XPC listener
355 name = getenv(DNSINFO_SERVICE_NAME);
356 if (name == NULL) {
357 name = DNSINFO_SERVICE_NAME;
358 }
359
360 c = xpc_connection_create_mach_service(name,
361 _dnsinfo_server_queue(),
362 XPC_CONNECTION_MACH_SERVICE_LISTENER);
363
364 xpc_connection_set_event_handler(c, ^(xpc_object_t event) {
365 xpc_type_t type;
366
367 type = xpc_get_type(event);
368 if (type == XPC_TYPE_CONNECTION) {
369 process_new_connection(event);
370
371 } else if (type == XPC_TYPE_ERROR) {
372 const char *desc;
373
374 desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
375 if (event == XPC_ERROR_CONNECTION_INVALID) {
376 SCLoggerLog(S_logger, LOG_ERR, CFSTR("DNS configuration server: %s"), desc);
377 xpc_release(c);
378 } else if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
379 SCLoggerLog(S_logger, LOG_ERR, CFSTR("DNS configuration server: %s"), desc);
380 } else {
381 SCLoggerLog(S_logger, LOG_ERR,
78403150 382 CFSTR("DNS configuration server: Connection error: %p : %s"),
5e9ce69e
A
383 event,
384 desc);
385 }
386
387 } else {
388 SCLoggerLog(S_logger, LOG_ERR,
78403150 389 CFSTR("DNS configuration server: unknown event type : %p"),
5e9ce69e
A
390 type);
391
392 }
393 });
394
395 xpc_connection_resume(c);
396
397SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("XPC server \"%s\" started"), name);
17d3ee29 398
5e9ce69e 399 return;
17d3ee29
A
400}
401
402
403__private_extern__
5e9ce69e
A
404_Bool
405_dns_configuration_store(dns_create_config_t *_config)
17d3ee29 406{
5e9ce69e
A
407 _dns_config_buf_t *config = (_dns_config_buf_t *)*_config;
408 Boolean in_sync;
409 uint64_t new_generation = 0;
410 CFDataRef new_dns_info = NULL;
411 const char *notify_key;
17d3ee29 412
5e9ce69e
A
413 if (config != NULL) {
414 const UInt8 *bytes;
415 CFIndex len;
17d3ee29 416
5e9ce69e
A
417 new_generation = config->config.generation;
418
419 if (*S_debug) {
78403150 420 SCLoggerLog(S_logger, LOG_DEBUG, CFSTR("DNS configuration updated: %llu"),
5e9ce69e 421 new_generation);
17d3ee29 422 }
5e9ce69e
A
423
424 bytes = (const UInt8 *)config;
425 len = sizeof(_dns_config_buf_t) + ntohl(config->n_attribute);
426
427 new_dns_info = CFDataCreate(NULL, bytes, len);
17d3ee29
A
428 }
429
5e9ce69e
A
430 dispatch_sync(_dnsinfo_server_queue(), ^{
431 _libSC_info_server_set_data(&S_dns_info, new_dns_info, new_generation);
432 });
433
434 if (new_dns_info != NULL) {
435 CFRelease(new_dns_info);
436 }
437
438 // if anyone is keeping us in sync, they now need to catch up
439 in_sync = _libSC_info_server_in_sync(&S_dns_info);
78403150
A
440 if (S_sync_handler) {
441 S_sync_handler(in_sync);
442 }
5e9ce69e
A
443
444 // and let everyone else know that the configuration has been updated
445 notify_key = dns_configuration_notify_key();
446 if (notify_key != NULL) {
447 uint32_t status;
17d3ee29 448
5e9ce69e
A
449 status = notify_post(notify_key);
450 if (status != NOTIFY_STATUS_OK) {
451 SCLoggerLog(S_logger, LOG_ERR, CFSTR("notify_post() failed: %d"), status);
452 // notification posting failures are non-fatal
453 }
454 }
455
456 return TRUE;
17d3ee29
A
457}
458
459
5e9ce69e
A
460#pragma mark -
461#pragma mark Testing
462
17d3ee29 463
5e9ce69e 464#ifdef MAIN
17d3ee29 465
5e9ce69e
A
466int
467main(int argc, char **argv)
468{
469 static Boolean verbose = (argc > 1) ? TRUE : FALSE;
470// _sc_log = FALSE;
471 _sc_verbose = (argc > 1) ? TRUE : FALSE;
472 _sc_debug = TRUE;
473
474 load_DNSConfiguration(CFBundleGetMainBundle(), // bundle
475 NULL, //SCLogger
476 &verbose, // bundleVerbose
477 ^(Boolean inSync) { // sync handler
478 SCLoggerLog(NULL, LOG_INFO,
479 CFSTR("in sync: %s"),
480 inSync ? "Yes" : "No")
481 });
482 CFRunLoopRun();
483 /* not reached */
484 exit(0);
485 return 0;
17d3ee29 486}
5e9ce69e
A
487
488#endif /* MAIN */