]> git.saurik.com Git - apple/configd.git/blob - nwi/network_information_server.c
configd-888.51.2.tar.gz
[apple/configd.git] / nwi / network_information_server.c
1 /*
2 * Copyright (c) 2012-2016 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 * February 8, 2012 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31 #include <notify.h>
32 #include <dispatch/dispatch.h>
33 #include <xpc/xpc.h>
34 #include <CommonCrypto/CommonDigest.h>
35 #include <CoreFoundation/CoreFoundation.h>
36 #include <SystemConfiguration/SCPrivate.h>
37
38 #include "libSystemConfiguration_client.h"
39 #include "libSystemConfiguration_server.h"
40
41 #include <network_information.h>
42 #include "network_state_information_priv.h"
43 #include "network_information_server.h"
44
45 #if !TARGET_OS_SIMULATOR
46 #include "agent-monitor.h"
47 #include "configAgentDefines.h"
48 #include "network_config_agent_info_priv.h"
49 #endif // !TARGET_OS_SIMULATOR
50
51 #ifdef SC_LOG_HANDLE
52 #include <os/log.h>
53 os_log_t SC_LOG_HANDLE;
54 #endif //SC_LOG_HANDLE
55
56
57 #pragma mark -
58 #pragma mark Globals
59
60
61 /*
62 * S_nwi_info
63 *
64 * Note: all accesses should be made while running on the _nwi_server_queue()
65 */
66 static libSC_info_server_t S_nwi_info;
67
68
69 /*
70 * S_sync_handler
71 * ACK (in-sync or not-in-sync) updates should be posted using
72 * this handler
73 *
74 * Note: all accesses should be made while running on the _nwi_server_queue()
75 */
76 static _nwi_sync_handler_t S_sync_handler = NULL;
77
78
79 #pragma mark -
80 #pragma mark Support functions
81
82
83 #pragma mark -
84 #pragma mark Network information server "main"
85
86
87 static dispatch_queue_t
88 _nwi_state_server_queue()
89 {
90 static dispatch_once_t once;
91 static dispatch_queue_t q;
92
93 dispatch_once(&once, ^{
94 q = dispatch_queue_create(NWI_SERVICE_NAME ".server", NULL);
95 });
96
97 return q;
98 }
99
100
101 /*
102 * _nwi_state_copy
103 *
104 * Called when a client wants a copy of the current
105 * Network information
106 *
107 * - caller must be running on the _nwi_server_queue()
108 */
109 static void
110 _nwi_state_copy(xpc_connection_t connection, xpc_object_t request)
111 {
112 CFDataRef data;
113 uint64_t generation;
114 const char *proc_name;
115 xpc_connection_t remote;
116 xpc_object_t reply;
117
118 remote = xpc_dictionary_get_remote_connection(request);
119 reply = xpc_dictionary_create_reply(request);
120 if (reply == NULL) {
121 SC_log(LOG_ERR, "<%p> _nwi_state_copy: xpc_dictionary_create_reply: failed",
122 connection);
123 return;
124 }
125
126 // extract data and generation #
127 data = _libSC_info_server_get_data(&S_nwi_info, connection, &generation);
128
129 // extract process name
130 proc_name = xpc_dictionary_get_string(request, NWI_PROC_NAME);
131 if (proc_name == NULL) {
132 proc_name = "???";
133 }
134
135 SC_log(LOG_DEBUG, "<%p:%s[%d]> Network information copy: %llu",
136 connection,
137 proc_name,
138 xpc_connection_get_pid(connection),
139 generation);
140
141 // return the Network information (if available)
142 if (data != NULL) {
143 xpc_dictionary_set_data(reply,
144 NWI_CONFIGURATION,
145 CFDataGetBytePtr(data),
146 CFDataGetLength(data));
147 }
148
149 // reply
150 xpc_connection_send_message(remote, reply);
151 xpc_release(reply);
152
153 return;
154 }
155
156
157 /*
158 * _nwi_state_acknowledge
159 *
160 * Called when a client wants to acknowledge processing
161 * of the Network information
162 *
163 * - caller must be running on the _nwi_server_queue()
164 */
165 static void
166 _nwi_state_acknowledge(xpc_connection_t connection, xpc_object_t request)
167 {
168 Boolean changed;
169 uint64_t generation;
170
171 generation = xpc_dictionary_get_uint64(request, NWI_GENERATION);
172
173 SC_log(LOG_DEBUG, "<%p:%d> Network information ack: %llu",
174 connection,
175 xpc_connection_get_pid(connection),
176 generation);
177
178 changed = _libSC_info_server_acknowledged(&S_nwi_info, connection, generation);
179 if (changed) {
180 Boolean inSync;
181
182 // report change
183 inSync = _libSC_info_server_in_sync(&S_nwi_info);
184 if (S_sync_handler != NULL) {
185 S_sync_handler(inSync);
186 }
187 }
188
189 return;
190 }
191
192 #if !TARGET_OS_SIMULATOR
193 /*
194 * _nwi_config_agent_copy
195 *
196 * Called when a client wants a copy of the agent data
197 *
198 * - caller must be running on the _nwi_server_queue()
199 */
200 static void
201 _nwi_config_agent_copy(xpc_connection_t connection, xpc_object_t request)
202 {
203 const void *buffer = NULL;
204 const char *proc_name = NULL;
205 uint64_t length = 0;
206 xpc_connection_t remote;
207 xpc_object_t reply = NULL;
208
209 remote = xpc_dictionary_get_remote_connection(request);
210 reply = xpc_dictionary_create_reply(request);
211
212 uuid_t agent_uuid;
213 const uint8_t *agent_uuid_value = xpc_dictionary_get_uuid(request, kConfigAgentAgentUUID);
214 if (agent_uuid_value != NULL) {
215 uuid_copy(agent_uuid, agent_uuid_value);
216 } else {
217 goto done;
218 }
219
220 const char *agent_type = xpc_dictionary_get_string(request, kConfigAgentType);
221 if (agent_type == NULL) {
222 goto done;
223 }
224
225 proc_name = xpc_dictionary_get_string(request, NWI_PROC_NAME);
226 if (proc_name == NULL) {
227 proc_name = "???";
228 }
229
230 SC_log(LOG_DEBUG, "<%p:%s[%d]> Config agent information copy",
231 connection,
232 proc_name,
233 xpc_connection_get_pid(connection));
234
235 if (strcmp(agent_type, kConfigAgentTypeDNS) == 0) {
236 buffer = copy_dns_information_for_agent_uuid(agent_uuid, &length);
237 } else if (strcmp(agent_type, kConfigAgentTypeProxy) == 0) {
238 buffer = copy_proxy_information_for_agent_uuid(agent_uuid, &length);
239 }
240
241 if (buffer != NULL && length > 0) {
242 xpc_dictionary_set_data(reply,
243 kConfigAgentAgentData,
244 buffer,
245 (size_t)length);
246 }
247
248 xpc_connection_send_message(remote, reply);
249
250 done:
251 if (reply != NULL) {
252 xpc_release(reply);
253 }
254
255 if (buffer != NULL) {
256 free((void *)buffer);
257 }
258
259 return;
260 }
261 #endif // !TARGET_OS_SIMULATOR
262
263
264 static void
265 process_request(xpc_connection_t connection, xpc_object_t request)
266 {
267 int64_t op;
268
269 op = xpc_dictionary_get_int64(request, NWI_REQUEST);
270 switch (op) {
271 case NWI_STATE_REQUEST_COPY :
272 /*
273 * Return the Network information
274 */
275 _nwi_state_copy(connection, request);
276 break;
277
278 case NWI_STATE_REQUEST_ACKNOWLEDGE :
279 /*
280 * Acknowlege a [processed] Network information
281 */
282 _nwi_state_acknowledge(connection, request);
283
284 break;
285 #if !TARGET_OS_SIMULATOR
286 case NWI_CONFIG_AGENT_REQUEST_COPY :
287 /*
288 * Return the agent information
289 */
290 _nwi_config_agent_copy(connection, request);
291
292 break;
293 #endif // !TARGET_OS_SIMULATOR
294 default :
295 SC_log(LOG_ERR, "<%p> unknown request : %lld",
296 connection,
297 op);
298
299 break;
300 }
301
302 return;
303 }
304
305
306 static void
307 process_new_connection(xpc_connection_t c)
308 {
309 SC_log(LOG_DEBUG, "<%p:%d> Network information session: open",
310 c,
311 xpc_connection_get_pid(c));
312
313 _libSC_info_server_open(&S_nwi_info, c);
314
315 xpc_connection_set_target_queue(c, _nwi_state_server_queue());
316
317 xpc_connection_set_event_handler(c, ^(xpc_object_t xobj) {
318 xpc_type_t type;
319
320 type = xpc_get_type(xobj);
321 if (type == XPC_TYPE_DICTIONARY) {
322 // process the request
323 process_request(c, xobj);
324
325 } else if (type == XPC_TYPE_ERROR) {
326 const char *desc;
327
328 desc = xpc_dictionary_get_string(xobj, XPC_ERROR_KEY_DESCRIPTION);
329 if (xobj == XPC_ERROR_CONNECTION_INVALID) {
330 Boolean changed;
331
332 SC_log(LOG_DEBUG, "<%p:%d> Network information session: close",
333 c,
334 xpc_connection_get_pid(c));
335
336 changed = _libSC_info_server_close(&S_nwi_info, c);
337 if (changed) {
338 Boolean inSync;
339
340 // report change
341 inSync = _libSC_info_server_in_sync(&S_nwi_info);
342 if (S_sync_handler != NULL) {
343 S_sync_handler(inSync);
344 }
345 }
346
347 } else if (xobj == XPC_ERROR_CONNECTION_INTERRUPTED) {
348 SC_log(LOG_ERR, "<%p:%d> %s",
349 c,
350 xpc_connection_get_pid(c),
351 desc);
352
353 } else {
354 SC_log(LOG_ERR, "<%p:%d> Connection error: %p : %s",
355 c,
356 xpc_connection_get_pid(c),
357 xobj,
358 desc);
359 }
360
361 } else {
362 SC_log(LOG_ERR, "<%p:%d> unknown event type : %p",
363 c,
364 xpc_connection_get_pid(c),
365 type);
366 }
367 });
368
369 xpc_connection_resume(c);
370
371 return;
372 }
373
374
375 #pragma mark -
376 #pragma mark Network Information server SPIs
377
378
379 __private_extern__
380 void
381 load_NetworkInformation(CFBundleRef bundle,
382 _nwi_sync_handler_t syncHandler)
383 {
384 xpc_connection_t c;
385 const char *name;
386
387 /*
388 * keep track of Network information acknowledgements
389 */
390 _libSC_info_server_init(&S_nwi_info);
391
392 /*
393 * save the in-sync/not-in-sync handler
394 */
395 S_sync_handler = Block_copy(syncHandler);
396
397 // create XPC listener
398 name = getenv(NWI_SERVICE_NAME);
399 if (name == NULL) {
400 name = NWI_SERVICE_NAME;
401 }
402
403 c = xpc_connection_create_mach_service(name,
404 _nwi_state_server_queue(),
405 XPC_CONNECTION_MACH_SERVICE_LISTENER);
406
407 xpc_connection_set_event_handler(c, ^(xpc_object_t event) {
408 xpc_type_t type;
409
410 type = xpc_get_type(event);
411 if (type == XPC_TYPE_CONNECTION) {
412 process_new_connection(event);
413
414 } else if (type == XPC_TYPE_ERROR) {
415 const char *desc;
416
417 desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
418 if (event == XPC_ERROR_CONNECTION_INVALID) {
419 SC_log(LOG_ERR, "Network information server: %s", desc);
420 xpc_release(c);
421 } else if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
422 SC_log(LOG_ERR, "Network information server: %s", desc);
423 } else {
424 SC_log(LOG_ERR, "Network information server: Connection error: %p : %s",
425 event,
426 desc);
427 }
428
429 } else {
430 SC_log(LOG_ERR, "Network information server: unknown event type : %p", type);
431
432 }
433 });
434
435 xpc_connection_resume(c);
436
437 SC_log(LOG_DEBUG, "XPC server \"%s\" started", name);
438
439 return;
440 }
441
442
443 __private_extern__
444 _Bool
445 _nwi_state_store(nwi_state *state)
446 {
447 Boolean in_sync;
448 uint64_t new_generation = 0;
449 CFDataRef new_nwi_info = NULL;
450 const char *notify_key;
451
452 if (state != NULL) {
453 const UInt8 *bytes;
454 CFIndex len;
455
456 new_generation = state->generation_count;
457
458 SC_log(LOG_DEBUG, "Network information updated: %llu",
459 new_generation);
460
461 bytes = (const UInt8 *)state;
462 len = nwi_state_size(state);
463
464 new_nwi_info = CFDataCreate(NULL, bytes, len);
465 }
466
467 dispatch_sync(_nwi_state_server_queue(), ^{
468 _libSC_info_server_set_data(&S_nwi_info, new_nwi_info, new_generation);
469 });
470
471 if (new_nwi_info != NULL) {
472 CFRelease(new_nwi_info);
473 }
474
475 // if anyone is keeping us in sync, they now need to catchup
476 in_sync = _libSC_info_server_in_sync(&S_nwi_info);
477 if (S_sync_handler != NULL) {
478 S_sync_handler(in_sync);
479 }
480
481 // and let everyone else know that the configuration has been updated
482 notify_key = nwi_state_get_notify_key();
483 if (notify_key != NULL) {
484 uint32_t status;
485
486 _nwi_state_force_refresh();
487 status = notify_post(notify_key);
488 if (status != NOTIFY_STATUS_OK) {
489 SC_log(LOG_ERR, "notify_post() failed: %d", status);
490 // notification posting failures are non-fatal
491 }
492 }
493
494 return TRUE;
495 }
496
497
498 #pragma mark -
499 #pragma mark Testing
500
501
502 #ifdef MAIN
503
504 int
505 main(int argc, char **argv)
506 {
507 static Boolean verbose = (argc > 1) ? TRUE : FALSE;
508 // _sc_log = FALSE;
509 _sc_verbose = (argc > 1) ? TRUE : FALSE;
510 _sc_debug = TRUE;
511
512 load_NetworkInformation(CFBundleGetMainBundle(), // bundle
513 ^(Boolean inSync) { // sync handler
514 SC_log(LOG_INFO,
515 "in sync: %s",
516 inSync ? "Yes" : "No")
517 });
518 CFRunLoopRun();
519 /* not reached */
520 exit(0);
521 return 0;
522 }
523
524 #endif /* MAIN */