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