1/*
2 * Copyright (c) 2000 Apple Computer, 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/* -----------------------------------------------------------------------------
26includes
27----------------------------------------------------------------------------- */
28#include <mach/mach.h>
29#include <string.h>
30#include <stdio.h>
31#include <termios.h>
32#include <unistd.h>
33#include <sys/errno.h>
34#include <sys/signal.h>
35#include <sys/param.h>
36#include <sys/socket.h>
37#include <net/if.h>
38#include <CoreFoundation/CoreFoundation.h>
39#include <netinet/in.h>
40#include <arpa/inet.h>
41#include <SystemConfiguration/SystemConfiguration.h>
42#include <SystemConfiguration/SCPrivate.h>      // for SCLog()
43#include <SystemConfiguration/SCValidation.h>
44#include <sys/ioctl.h>
45#include <net/if_dl.h>
46#include <net/if_utun.h>
47#include <notify.h>
48#include <sys/kern_control.h>
49#include <sys/sys_domain.h>
50#include <servers/bootstrap.h>
51#include <mach/task_special_ports.h>
52#include "pppcontroller_types.h"
53#include "pppcontroller.h"
54#include <bsm/libbsm.h>
55#include <sys/kern_event.h>
56#include <netinet/in_var.h>
57#include <netinet6/in6_var.h>
58#include <netinet6/nd6.h>
59#include <network_information.h>
60
61#include "ppp_msg.h"
62#include "../Family/if_ppplink.h"
63#include "scnc_main.h"
64#include "scnc_client.h"
65#include "scnc_utils.h"
66#include "ppp_option.h"
67#include "PPPControllerPriv.h"
68#include "../Family/ppp_domain.h"
69#include "../Helpers/pppd/pppd.h"
70#include "../Drivers/PPTP/PPTP-plugin/pptp.h"
71#include "../Drivers/L2TP/L2TP-plugin/l2tp.h"
72#include "../Drivers/PPPoE/PPPoE-extension/PPPoE.h"
73
74/* -----------------------------------------------------------------------------
75definitions
76----------------------------------------------------------------------------- */
77#undef CONSTSTR
78#define CONSTSTR(str) (const char *)str
79
80/* -----------------------------------------------------------------------------
81Forward Declarations
82----------------------------------------------------------------------------- */
83
84
85/* -----------------------------------------------------------------------------
86globals
87----------------------------------------------------------------------------- */
88const char *scnc_ctrl_stopped = "Controller Stopped";
89const char *scnc_sys_sleep = "System will sleep";
90const char *scnc_usr_logout = "User Logged out";
91const char *scnc_usr_switch = "User Switched";
92const char *scnc_sock_disco = "Socket disconnect";
93const char *scnc_plugin_chg = "Plugin Change";
94const char *scnc_app_rem = "App removed";
95const char *scnc_usr_req = "User Requested";
96const char *scnc_term_all = "Terminated All";
97const char *scnc_serv_disp = "Service Disposed";
98const char *ppp_fatal = "Fatal Error";
99const char *ppp_option = "Option Error";
100const char *ppp_not_root = "Not Root";
101const char *ppp_no_kern = "No Kernel Support";
102const char *ppp_user_req = "User requested";
103const char *ppp_lock_fail = "Lock Failed";
104const char *ppp_open_fail = "Open Failed";
105const char *ppp_conn_fail = "Connect Failed";
106const char *ppp_pty_fail = "Pty command Failed";
107const char *ppp_nego_fail = "Negotiation Failed";
108const char *ppp_peer_auth_fail = "Peer Authentication Failed";
109const char *ppp_idle_tmo = "Idle Timeout";
110const char *ppp_sess_tmo = "Session Timeout";
111const char *ppp_callback = "Callback";
112const char *ppp_peer_dead = "Peer Dead";
113const char *ppp_disco_by_dev = "Disconnect by Device";
114const char *ppp_loopback = "Loopback Error";
115const char *ppp_init_fail = "Init Failed";
116const char *ppp_auth_fail = "Authentication to Peer Failed";
117const char *ppp_term_fail = "Terminal Failed";
118const char *ppp_dev_err = "Device Error";
119const char *ppp_peer_unauth = "Peer Not Authorized";
120const char *ppp_cnid_auth_fail = "CNID Authentication Failed";
121const char *ppp_peer_unreach = "Peer Unreachable";
122const char *ppp_dev_no_srvr = "No Server";
123const char *ppp_dev_no_ans = "No Answer";
124const char *ppp_dev_prot_err = "Protocol Error";
125const char *ppp_dev_net_chg = "Network Changed";
126const char *ppp_dev_psk = "Shared Secret";
127const char *ppp_dev_cert = "No Certificate";
128const char *ppp_dev_no_car = "No Carrier";
129const char *ppp_dev_no_num = "No Number";
130const char *ppp_dev_bad_script = "Bad Script";
131const char *ppp_dev_busy = "Busy";
132const char *ppp_dev_no_dial = "No Dial Tone";
133const char *ppp_dev_modem_err = "Modem Error";
134const char *ppp_dev_hang = "Hang-up";
135const char *ppp_dev_no_srvc = "No Service";
136const char *ppp_dev_no_ac = "No AC";
137const char *ppp_dev_no_ac_srvc = "No AC Service";
138const char *ppp_dev_conn_refuse = "Connection Refused";
139const char *ipsec_gen_err = "Generic Error";
140const char *ipsec_no_srvr_addr = "No Server Address";
141const char *ipsec_no_psk = "No Shared Secret";
142const char *ipsec_no_cert = "No Certificate";
143const char *ipsec_dns_err = "Resolve Address Error";
144const char *ipsec_no_local = "No Local Network";
145const char *ipsec_cfg_err = "Configuration Error";
146const char *ipsec_ctrl_err = "Racoon Control Error";
147const char *ipsec_conn_err = "Connection Error";
148const char *ipsec_nego_err = "Negotiation Error";
149const char *ipsec_psk_err = "Shared Secret Error";
150const char *ipsec_srvr_cert_err = "Server Certificate Error";
151const char *ipsec_cli_cert_err = "Client Certificate Error";
152const char *ipsec_xauth_err = "Xauth Error";
153const char *ipsec_net_chg = "Network Change";
154const char *ipsec_peer_disco = "Peer Disconnect";
155const char *ipsec_peer_dead = "Peer Dead";
156const char *ipsec_edge_err = "Edge Activation Error";
157const char *ipsec_idle_tmo = "Idle Timeout";
158const char *ipsec_cli_cert_pre = "Client Certificate premature";
159const char *ipsec_cli_cert_exp = "Client Certificate expired";
160const char *ipsec_srvr_cert_pre = "Server Certificate premature";
161const char *ipsec_srvr_cert_exp = "Server Certificate expired";
162const char *ipsec_srvr_cert_id = "Server Certificate identity incorrect";
163const char *vpn_gen_err = "Generic Error";
164const char *vpn_no_srvr_addr = "No Server Address";
165const char *vpn_no_cert = "No Certificate";
166const char *vpn_dns_err = "Resolve Address Error";
167const char *vpn_no_local = "No Local Network";
168const char *vpn_cfg_err = "Configuration Error";
169const char *vpn_ctrl_err = "Control Error";
170const char *vpn_conn_err = "Connection Error";
171const char *vpn_net_chg = "Network Change";
172const char *vpn_peer_disco = "Peer Disconnect";
173const char *vpn_peer_dead = "Peer Dead";
174const char *vpn_peer_unresp = "Peer not responding";
175const char *vpn_nego_err = "Negotiation Error";
176const char *vpn_xauth_err = "Xauth Error";
177const char *vpn_edge_err = "Edge Activation Error";
178const char *vpn_idle_tmo = "Idle Timeout";
179const char *vpn_addr_invalid = "Address invalid";
180const char *vpn_ap_req = "AP required";
181const char *vpn_cli_cert_pre = "Client Certificate premature";
182const char *vpn_cli_cert_exp = "Client Certificate expired";
183const char *vpn_srvr_cert_pre = "Server Certificate premature";
184const char *vpn_srvr_cert_exp = "Server Certificate expired";
185const char *vpn_srvr_cert_id = "Server Certificate identity incorrect";
186const char *vpn_plugin_upd = "Plugin update required";
187const char *vpn_plugin_dis = "Plugin disabled";
188
189
190
191/* -----------------------------------------------------------------------------
192 Given a string 'key' and a string prefix 'prefix',
193 return the next component in the slash '/' separated
194 key.  If no slash follows the prefix, return NULL.
195
196 Examples:
197 1. key = "a/b/c" prefix = "a/"    returns "b"
198 2. key = "a/b/c" prefix = "a/b/"  returns NULL
199----------------------------------------------------------------------------- */
200CFStringRef parse_component(CFStringRef key, CFStringRef prefix)
201{
202    CFMutableStringRef	comp;
203    CFRange		range;
204
205    if (!CFStringHasPrefix(key, prefix))
206    	return NULL;
207
208    comp = CFStringCreateMutableCopy(NULL, 0, key);
209    CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix)));
210    range = CFStringFind(comp, CFSTR("/"), 0);
211    if (range.location == kCFNotFound) {
212        CFRelease(comp);
213        return NULL;
214    }
215    range.length = CFStringGetLength(comp) - range.location;
216    CFStringDelete(comp, range);
217    return comp;
218}
219
220/* -----------------------------------------------------------------------------
221----------------------------------------------------------------------------- */
222CFDictionaryRef copyService(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID)
223{
224    CFTypeRef		data = NULL;
225    CFMutableDictionaryRef	service = NULL;
226    CFStringRef		key = NULL;
227    int			i;
228    CFStringRef         copy[] = {
229        kSCEntNetPPP,
230        kSCEntNetModem,
231        kSCEntNetInterface,
232    	kSCEntNetIPv4,
233    	kSCEntNetIPv6,
234#if !TARGET_OS_EMBEDDED
235    	kSCEntNetSMB,
236#endif
237        kSCEntNetDNS,
238        kSCEntNetL2TP,
239        kSCEntNetPPTP,
240        kSCEntNetIPSec,
241        NULL,
242    };
243
244    key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@"), domain, kSCCompNetwork, kSCCompService, serviceID);
245    if (key == 0)
246        goto fail;
247
248    data = SCDynamicStoreCopyValue(store, key);
249    if (data == 0) {
250		data = CFDictionaryCreate(NULL, 0, 0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
251		if (data == 0)
252			goto fail;
253	}
254
255    CFRelease(key);
256	key = NULL;
257
258    service = CFDictionaryCreateMutableCopy(NULL, 0, data);
259    if (service == 0)
260        goto fail;
261
262    CFRelease(data);
263
264    for (i = 0; copy[i]; i++) {
265        data = copyEntity(store, domain, serviceID, copy[i]);
266        if (data) {
267
268            CFDictionaryAddValue(service, copy[i], data);
269            CFRelease(data);
270        }
271    }
272
273    return service;
274
275fail:
276    if (key)
277        CFRelease(key);
278    if (data)
279        CFRelease(data);
280    if (service)
281        CFRelease(service);
282    return 0;
283}
284
285/* -----------------------------------------------------------------------------
286----------------------------------------------------------------------------- */
287CFDictionaryRef copyEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, CFStringRef entity)
288{
289    CFTypeRef		data = NULL;
290    CFStringRef		key;
291
292    if (serviceID)
293        key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, domain, serviceID, entity);
294    else
295        key = SCDynamicStoreKeyCreateNetworkGlobalEntity(0, domain, entity);
296
297    if (key) {
298        data = SCDynamicStoreCopyValue(store, key);
299        CFRelease(key);
300    }
301    return data;
302}
303
304/* -----------------------------------------------------------------------------
305----------------------------------------------------------------------------- */
306int existEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, CFStringRef entity)
307{
308    CFTypeRef		data;
309
310    data = copyEntity(store, domain, serviceID, entity);
311    if (data) {
312        CFRelease(data);
313        return 1;
314    }
315
316    return 0;
317}
318
319/* -----------------------------------------------------------------------------
320get a string from the dictionnary, in service/property
321----------------------------------------------------------------------------- */
322int getString(CFDictionaryRef service, CFStringRef property, u_char *str, u_int16_t maxlen)
323{
324    CFStringRef		string;
325    CFDataRef		ref;
326    const UInt8    *dataptr;
327    int            len;
328
329    str[0] = 0;
330    ref  = CFDictionaryGetValue(service, property);
331    if (ref) {
332        if (CFGetTypeID(ref) == CFStringGetTypeID()) {
333            CFStringGetCString((CFStringRef)ref, (char*)str, maxlen, kCFStringEncodingUTF8);
334            return 1;
335        }
336        else if (CFGetTypeID(ref) == CFDataGetTypeID()) {
337            CFStringEncoding    encoding;
338
339            if ((len = CFDataGetLength(ref)) && (dataptr = CFDataGetBytePtr(ref))){
340#if     __BIG_ENDIAN__
341                encoding = (*(dataptr + 1) == 0x00) ? kCFStringEncodingUTF16LE : kCFStringEncodingUTF16BE;
342#else   // __LITTLE_ENDIAN__
343                encoding = (*dataptr == 0x00) ? kCFStringEncodingUTF16BE : kCFStringEncodingUTF16LE;
344#endif
345                string = CFStringCreateWithBytes(NULL, (const UInt8 *)dataptr, len, encoding, FALSE);
346                if (string) {
347                    CFStringGetCString((CFStringRef)string, (char*)str, maxlen, kCFStringEncodingUTF8);
348                    CFRelease(string);
349                    return 1;
350                }
351            }
352        }
353    }
354    return 0;
355}
356
357/* -----------------------------------------------------------------------------
358get a number from the dictionnary, in service/property
359----------------------------------------------------------------------------- */
360int getNumber(CFDictionaryRef dict, CFStringRef property, u_int32_t *outval)
361{
362    CFNumberRef		ref;
363
364    ref  = CFDictionaryGetValue(dict, property);
365    if (ref && (CFGetTypeID(ref) == CFNumberGetTypeID())) {
366        CFNumberGetValue(ref, kCFNumberSInt32Type, outval);
367        return 1;
368    }
369    return 0;
370}
371
372/* -----------------------------------------------------------------------------
373----------------------------------------------------------------------------- */
374int getNumberFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
375        CFStringRef entity, CFStringRef property, u_int32_t *outval)
376{
377    CFTypeRef		data;
378    int 		ok = 0;
379
380    if ((data = copyEntity(store, domain, serviceID, entity))) {
381        ok = getNumber(data, property, outval);
382        CFRelease(data);
383    }
384    return ok;
385}
386
387/* -----------------------------------------------------------------------------
388----------------------------------------------------------------------------- */
389int getStringFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
390        CFStringRef entity, CFStringRef property, u_char *str, u_int16_t maxlen)
391{
392    CFTypeRef		data;
393    int 		ok = 0;
394
395    data = copyEntity(store, domain, serviceID, entity);
396    if (data) {
397        ok = getString(data, property, str, maxlen);
398        CFRelease(data);
399    }
400    return ok;
401}
402
403/* -----------------------------------------------------------------------------
404----------------------------------------------------------------------------- */
405CFStringRef copyCFStringFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
406        CFStringRef entity, CFStringRef property)
407{
408    CFTypeRef		data;
409    CFStringRef		string, ret = 0;
410
411    data = copyEntity(store, domain, serviceID, entity);
412    if (data) {
413        string  = CFDictionaryGetValue(data, property);
414        if (string && (CFGetTypeID(string) == CFStringGetTypeID())) {
415            CFRetain(string);
416            ret = string;
417        }
418
419        CFRelease(data);
420    }
421    return ret;
422}
423
424/* -----------------------------------------------------------------------------
425----------------------------------------------------------------------------- */
426u_int32_t CFStringAddrToLong(CFStringRef string)
427{
428    char 	str[100];
429    u_int32_t	ret = 0;
430
431    if (string) {
432	str[0] = 0;
433        CFStringGetCString(string, str, sizeof(str), kCFStringEncodingMacRoman);
434        ret = ntohl(inet_addr(str));
435    }
436    return ret;
437}
438
439/* -----------------------------------------------------------------------------
440----------------------------------------------------------------------------- */
441int getAddressFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
442        CFStringRef entity, CFStringRef property, u_int32_t *outval)
443{
444    CFTypeRef		data;
445    int 		ok = 0;
446    CFArrayRef		array;
447
448    data = copyEntity(store, domain, serviceID, entity);
449    if (data) {
450        array = CFDictionaryGetValue(data, property);
451        if (array && CFArrayGetCount(array)) {
452            *outval = CFStringAddrToLong(CFArrayGetValueAtIndex(array, 0));
453            ok = 1;
454        }
455        CFRelease(data);
456    }
457    return ok;
458}
459
460/* -----------------------------------------------------------------------------
461----------------------------------------------------------------------------- */
462Boolean my_CFEqual(CFTypeRef obj1, CFTypeRef obj2)
463{
464    if (obj1 == NULL && obj2 == NULL)
465        return true;
466    else if (obj1 == NULL || obj2 == NULL)
467        return false;
468
469    return CFEqual(obj1, obj2);
470}
471
472/* -----------------------------------------------------------------------------
473----------------------------------------------------------------------------- */
474void my_CFRelease(void *t)
475{
476    void * * obj = (void * *)t;
477    if (obj && *obj) {
478	CFRelease(*obj);
479	*obj = NULL;
480    }
481    return;
482}
483
484/* -----------------------------------------------------------------------------
485----------------------------------------------------------------------------- */
486void my_close(int fd)
487{
488    if (fd != -1)
489        close(fd);
490}
491
492/* -----------------------------------------------------------------------------
493----------------------------------------------------------------------------- */
494CFTypeRef my_CFRetain(CFTypeRef obj)
495{
496    if (obj)
497        CFRetain(obj);
498	return obj;
499}
500
501/* -----------------------------------------------------------------------------
502----------------------------------------------------------------------------- */
503Boolean isDictionary (CFTypeRef obj)
504{
505    return (obj && CFGetTypeID(obj) == CFDictionaryGetTypeID());
506}
507
508/* -----------------------------------------------------------------------------
509----------------------------------------------------------------------------- */
510Boolean isArray (CFTypeRef obj)
511{
512    return (obj && CFGetTypeID(obj) == CFArrayGetTypeID());
513}
514
515/* -----------------------------------------------------------------------------
516----------------------------------------------------------------------------- */
517Boolean isString (CFTypeRef obj)
518{
519    return (obj && CFGetTypeID(obj) == CFStringGetTypeID());
520}
521
522/* -----------------------------------------------------------------------------
523----------------------------------------------------------------------------- */
524Boolean isNumber (CFTypeRef obj)
525{
526    return (obj && CFGetTypeID(obj) == CFNumberGetTypeID());
527}
528
529/* -----------------------------------------------------------------------------
530----------------------------------------------------------------------------- */
531Boolean isData (CFTypeRef obj)
532{
533    return (obj && CFGetTypeID(obj) == CFDataGetTypeID());
534}
535
536
537/* -----------------------------------------------------------------------------
538----------------------------------------------------------------------------- */
539void AddNumber(CFMutableDictionaryRef dict, CFStringRef property, u_int32_t number)
540{
541   CFNumberRef num;
542    num = CFNumberCreate(NULL, kCFNumberSInt32Type, &number);
543    if (num) {
544        CFDictionaryAddValue(dict, property, num);
545        CFRelease(num);
546    }
547}
548
549/* -----------------------------------------------------------------------------
550----------------------------------------------------------------------------- */
551void AddNumber64(CFMutableDictionaryRef dict, CFStringRef property, u_int64_t number)
552{
553   CFNumberRef num;
554    num = CFNumberCreate(NULL, kCFNumberSInt64Type, &number);
555    if (num) {
556        CFDictionaryAddValue(dict, property, num);
557        CFRelease(num);
558    }
559}
560
561/* -----------------------------------------------------------------------------
562----------------------------------------------------------------------------- */
563void AddString(CFMutableDictionaryRef dict, CFStringRef property, char *string)
564{
565    CFStringRef str;
566    str = CFStringCreateWithCString(NULL, string, kCFStringEncodingUTF8);
567    if (str) {
568        CFDictionaryAddValue(dict, property, str);
569        CFRelease(str);
570    }
571}
572
573/* -----------------------------------------------------------------------------
574----------------------------------------------------------------------------- */
575void AddNumberFromState(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef entity, CFStringRef property, CFMutableDictionaryRef dict)
576{
577    u_int32_t 	lval;
578
579    if (getNumberFromEntity(store, kSCDynamicStoreDomainState, serviceID, entity, property, &lval))
580        AddNumber(dict, property, lval);
581}
582
583/* -----------------------------------------------------------------------------
584----------------------------------------------------------------------------- */
585void AddStringFromState(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef entity, CFStringRef property, CFMutableDictionaryRef dict)
586{
587    CFStringRef	string;
588
589    if ((string = copyCFStringFromEntity(store, kSCDynamicStoreDomainState, serviceID, entity, property))) {
590        CFDictionaryAddValue(dict, property, string);
591        CFRelease(string);
592    }
593}
594
595/* -------------------------------------------------------------------------------------------
596------------------------------------------------------------------------------------------- */
597CFDataRef Serialize(CFPropertyListRef obj, void **data, u_int32_t *dataLen)
598{
599    CFDataRef           	xml;
600
601    xml = CFPropertyListCreateXMLData(NULL, obj);
602    if (xml) {
603        *data = (void*)CFDataGetBytePtr(xml);
604        *dataLen = CFDataGetLength(xml);
605    }
606    return xml;
607}
608
609/* -------------------------------------------------------------------------------------------
610------------------------------------------------------------------------------------------- */
611CFPropertyListRef Unserialize(void *data, u_int32_t dataLen)
612{
613    CFDataRef           	xml;
614    CFPropertyListRef	ref = 0;
615
616    xml = CFDataCreate(NULL, data, dataLen);
617    if (xml) {
618        ref = CFPropertyListCreateFromXMLData(NULL,
619                xml,  kCFPropertyListImmutable, NULL);
620        CFRelease(xml);
621    }
622
623    return ref;
624}
625
626/* -----------------------------------------------------------------------------
627----------------------------------------------------------------------------- */
628void *my_Allocate(int size)
629{
630	void			*addr;
631	kern_return_t	status;
632
633	status = vm_allocate(mach_task_self(), (vm_address_t *)&addr, size, TRUE);
634	if (status != KERN_SUCCESS) {
635		return 0;
636	}
637
638	return addr;
639}
640
641/* -----------------------------------------------------------------------------
642----------------------------------------------------------------------------- */
643void my_Deallocate(void * addr, int size)
644{
645	kern_return_t	status;
646
647	if (addr == 0)
648		return;
649
650	status = vm_deallocate(mach_task_self(), (vm_address_t)addr, size);
651	if (status != KERN_SUCCESS) {
652	}
653
654	return;
655}
656
657// ----------------------------------------------------------------------------
658//	GetIntFromDict
659// ----------------------------------------------------------------------------
660Boolean GetIntFromDict (CFDictionaryRef dict, CFStringRef property, u_int32_t *outval, u_int32_t defaultval)
661{
662    CFNumberRef		ref;
663
664	ref  = CFDictionaryGetValue(dict, property);
665	if (isNumber(ref)
666		&&  CFNumberGetValue(ref, kCFNumberSInt32Type, outval))
667		return TRUE;
668
669	*outval = defaultval;
670	return FALSE;
671}
672
673// ----------------------------------------------------------------------------
674//	GetStrFromDict
675// ----------------------------------------------------------------------------
676int GetStrFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen, char *defaultval)
677{
678    CFStringRef		ref;
679
680	ref  = CFDictionaryGetValue(dict, property);
681	if (!isString(ref)
682		|| !CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8))
683		strncpy(outstr, defaultval, maxlen);
684
685	return strlen(outstr);
686}
687
688// ----------------------------------------------------------------------------
689//	GetStrAddrFromDict
690// ----------------------------------------------------------------------------
691Boolean GetStrAddrFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen)
692{
693    CFStringRef		ref;
694	in_addr_t               addr;
695
696	ref  = CFDictionaryGetValue(dict, property);
697	if (isString(ref)
698			&& CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8)) {
699					addr = inet_addr(outstr);
700					return addr != INADDR_NONE;
701	}
702
703	return FALSE;
704}
705
706// ----------------------------------------------------------------------------
707//	GetStrNetFromDict
708// ----------------------------------------------------------------------------
709Boolean GetStrNetFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen)
710{
711    CFStringRef		ref;
712	in_addr_t               net;
713
714	ref  = CFDictionaryGetValue(dict, property);
715	if (isString(ref)
716			&& CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8)) {
717			net = inet_network(outstr);
718			return net != INADDR_NONE;// && net != 0;
719	}
720
721	return FALSE;
722}
723
724
725
726/* -----------------------------------------------------------------------------
727publish a dictionnary entry in the cache, given a key
728----------------------------------------------------------------------------- */
729int publish_keyentry(SCDynamicStoreRef store, CFStringRef key, CFStringRef entry, CFTypeRef value)
730{
731    CFMutableDictionaryRef	dict;
732    CFPropertyListRef		ref;
733
734    if ((ref = SCDynamicStoreCopyValue(store, key))) {
735        dict = CFDictionaryCreateMutableCopy(0, 0, ref);
736        CFRelease(ref);
737    }
738    else
739        dict = CFDictionaryCreateMutable(0, 0,
740                &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
741
742    if (dict == 0)
743        return 0;
744
745    CFDictionarySetValue(dict,  entry, value);
746    SCDynamicStoreSetValue(store, key, dict);
747    CFRelease(dict);
748
749    return 1;
750 }
751/* -----------------------------------------------------------------------------
752unpublish a dictionnary entry from the cache, given the dict key
753----------------------------------------------------------------------------- */
754int unpublish_keyentry(SCDynamicStoreRef store, CFStringRef key, CFStringRef entry)
755{
756    CFMutableDictionaryRef	dict;
757    CFPropertyListRef		ref;
758
759    if ((ref = SCDynamicStoreCopyValue(store, key))) {
760        if ((dict = CFDictionaryCreateMutableCopy(0, 0, ref))) {
761            CFDictionaryRemoveValue(dict, entry);
762            SCDynamicStoreSetValue(store, key, dict);
763            CFRelease(dict);
764        }
765        CFRelease(ref);
766    }
767    return 0;
768}
769
770
771/* -----------------------------------------------------------------------------
772publish a numerical entry in the cache, given a dictionary
773----------------------------------------------------------------------------- */
774int publish_dictnumentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry, int val)
775{
776    int			ret = ENOMEM;
777    CFNumberRef		num;
778    CFStringRef		key;
779
780    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
781    if (key) {
782        num = CFNumberCreate(NULL, kCFNumberIntType, &val);
783        if (num) {
784            ret = publish_keyentry(store, key, entry, num);
785            CFRelease(num);
786            ret = 0;
787        }
788        CFRelease(key);
789    }
790    return ret;
791}
792
793
794/* -----------------------------------------------------------------------------
795 unpublish a dictionnary entry from the cache, given the dict name
796 ----------------------------------------------------------------------------- */
797int unpublish_dictentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry)
798{
799    int			ret = ENOMEM;
800    CFStringRef		key;
801
802    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
803    if (key) {
804        ret = unpublish_keyentry(store, key, entry);
805        CFRelease(key);
806        ret = 0;
807    }
808    return ret;
809}
810
811/* -----------------------------------------------------------------------------
812 publishes multiple dictionaries to the cache, given the dict names and the dicts. Indices must match up exactly
813 ----------------------------------------------------------------------------- */
814int publish_multiple_dicts(SCDynamicStoreRef store, CFStringRef serviceID, CFArrayRef dictNames, CFArrayRef dicts)
815{
816    CFDictionaryRef     dict = NULL;
817    CFStringRef         dictName = NULL;
818    int                 i;
819    CFStringRef         key;
820    CFMutableDictionaryRef   keys_to_add;
821    int                 numDicts;
822    int                 ret = ENOMEM;
823
824	if (!store)
825		return -1;
826
827    /* Check arrays */
828    if (!dictNames || !dicts)
829        return -1;
830
831    /* Verify sizes */
832    numDicts = CFArrayGetCount(dictNames);
833    if (numDicts != CFArrayGetCount(dicts))
834        return -1;
835
836    keys_to_add = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
837
838    for (i = 0; i < numDicts; i++) {
839        dictName = CFArrayGetValueAtIndex(dictNames, i);
840        dict = CFArrayGetValueAtIndex(dicts, i);
841        if (isA_CFString(dictName) && isA_CFDictionary(dict)) {
842            key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dictName);
843            if (key) {
844                CFDictionaryAddValue(keys_to_add, key, dict);
845                CFRelease(key);
846            }
847        }
848    }
849
850    SCDynamicStoreSetMultiple(store, keys_to_add, NULL, NULL);
851
852    my_CFRelease(&keys_to_add);
853
854    return ret;
855}
856
857/* -----------------------------------------------------------------------------
858 unpublish a dictionnary entry from the cache, given the dict name
859 ----------------------------------------------------------------------------- */
860int unpublish_dict(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict)
861{
862    int			ret = ENOMEM;
863    CFStringRef		key;
864
865	if (!store)
866		return -1;
867
868	if (dict)
869		key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
870	else
871		key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@"), kSCDynamicStoreDomainState, kSCCompNetwork, kSCCompService, serviceID);
872    if (key) {
873        SCDynamicStoreRemoveValue(store, key);
874        CFRelease(key);
875		ret = 0;
876    }
877
878    return ret;
879}
880
881/* -----------------------------------------------------------------------------
882 unpublish multiple dictionary entries from the cache, given an array of dict names
883 ----------------------------------------------------------------------------- */
884int unpublish_multiple_dicts(SCDynamicStoreRef store, CFStringRef serviceID, CFArrayRef dictNames, Boolean removeService)
885{
886    CFStringRef         dictName = NULL;
887    int                 i;
888    CFStringRef         key;
889    CFMutableArrayRef   keys_to_remove;
890    int                 numDictNames;
891    int                 ret = ENOMEM;
892
893	if (!store)
894		return -1;
895
896    keys_to_remove = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
897
898    if (dictNames) {
899        numDictNames = CFArrayGetCount(dictNames);
900        for (i = 0; i < numDictNames; i++) {
901            dictName = CFArrayGetValueAtIndex(dictNames, i);
902            if (isA_CFString(dictName)) {
903                key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dictName);
904                if (key) {
905                    CFArrayAppendValue(keys_to_remove, key);
906                    CFRelease(key);
907                }
908            }
909        }
910    }
911
912    if (removeService) {
913        key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@"), kSCDynamicStoreDomainState, kSCCompNetwork, kSCCompService, serviceID);
914        if (key) {
915            CFArrayAppendValue(keys_to_remove, key);
916            CFRelease(key);
917        }
918    }
919
920    SCDynamicStoreSetMultiple(store, NULL, keys_to_remove, NULL);
921
922    my_CFRelease(&keys_to_remove);
923
924    return ret;
925}
926
927/* -----------------------------------------------------------------------------
928publish a string entry in the cache, given a dictionary
929----------------------------------------------------------------------------- */
930int publish_dictstrentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry, char *str, int encoding)
931{
932
933    int			ret = ENOMEM;
934    CFStringRef 	ref;
935    CFStringRef		key;
936
937    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
938    if (key) {
939        ref = CFStringCreateWithCString(NULL, str, encoding);
940        if (ref) {
941            ret = publish_keyentry(store, key, entry, ref);
942            CFRelease(ref);
943            ret = 0;
944        }
945        CFRelease(key);
946    }
947    return ret;
948}
949
950/* -----------------------------------------------------------------------------
951 return f s CFString contains an IP address
952 ----------------------------------------------------------------------------- */
953int
954cfstring_is_ip(CFStringRef str)
955{
956	char *buf;
957	struct in_addr ip = { 0 };
958	CFIndex l;
959	int n, result;
960	CFRange range;
961
962	if (!isString(str) || (l = CFStringGetLength(str)) == 0)
963		return 0;
964
965	buf = malloc(l+1);
966	if (buf == NULL) {
967		SCLog(TRUE, LOG_ERR, CFSTR("Failed to allocate memory"));
968		return 0;
969	}
970
971	range = CFRangeMake(0, l);
972	n = CFStringGetBytes(str, range, kCFStringEncodingMacRoman,
973						 0, FALSE, (UInt8 *)buf, l, &l);
974	buf[l] = '\0';
975
976	result = inet_aton(buf, &ip);
977	free(buf);
978	return result;
979}
980
981/* -----------------------------------------------------------------------------
982 ----------------------------------------------------------------------------- */
983CFStringRef
984copyPrimaryService (SCDynamicStoreRef store)
985{
986    CFDictionaryRef	dict;
987    CFStringRef		key;
988    CFStringRef		primary = NULL;
989
990    if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
991                                                          kSCDynamicStoreDomainState,
992                                                          kSCEntNetIPv4)) == NULL) {
993        return NULL;
994    }
995
996    dict = SCDynamicStoreCopyValue(store, key);
997    CFRelease(key);
998    if (isA_CFDictionary(dict)) {
999        primary = CFDictionaryGetValue(dict,
1000                                       kSCDynamicStorePropNetPrimaryService);
1001
1002        primary = isA_CFString(primary);
1003        if (primary)
1004            CFRetain(primary);
1005    }
1006    if (dict != NULL) {
1007        CFRelease(dict);
1008    }
1009    return primary;
1010}
1011
1012/* -----------------------------------------------------------------------------
1013 ----------------------------------------------------------------------------- */
1014Boolean UpdatePasswordPrefs(CFStringRef serviceID, CFStringRef interfaceType, SCNetworkInterfacePasswordType passwordType,
1015								   CFStringRef passwordEncryptionKey, CFStringRef passwordEncryptionValue, CFStringRef logTitle)
1016{
1017	SCPreferencesRef		prefs = NULL;
1018	SCNetworkServiceRef		service = NULL;
1019	SCNetworkInterfaceRef	interface = NULL;
1020	CFMutableDictionaryRef	newConfig = NULL;
1021	CFDictionaryRef			config;
1022	Boolean					ok, locked = FALSE, success = FALSE;
1023
1024	prefs = SCPreferencesCreate(NULL, CFSTR("UpdatePassword"), NULL);
1025	if (prefs == NULL) {
1026		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesCreate fails"), logTitle);
1027        goto done;
1028	}
1029	// lock the prefs
1030	ok = SCPreferencesLock(prefs, TRUE);
1031	if (!ok) {
1032		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesLock fails"), logTitle);
1033        goto done;
1034	}
1035
1036	locked = TRUE;
1037
1038	// get the service
1039	service = SCNetworkServiceCopy(prefs, serviceID);
1040	if (service == NULL) {
1041		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkServiceCopy fails"), logTitle);
1042        goto done;
1043	}
1044	// get the interface associated with the service
1045	interface = SCNetworkServiceGetInterface(service);
1046	if ((interface == NULL) || !CFEqual(SCNetworkInterfaceGetInterfaceType(interface), interfaceType)) {
1047		SCLog(TRUE, LOG_ERR, CFSTR("%@: interface not %@"), logTitle, interfaceType);
1048        goto done;
1049	}
1050
1051	// remove any current password (from the system keychain)
1052	if (SCNetworkInterfaceCheckPassword(interface, passwordType)) {
1053        // if password current associated with this interface
1054        ok = SCNetworkInterfaceRemovePassword(interface,  passwordType);
1055        if (!ok) {
1056			SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkInterfaceRemovePassword fails"), logTitle);
1057        }
1058	}
1059
1060	// update passworEncryptionKey
1061	config = SCNetworkInterfaceGetConfiguration(interface);
1062
1063	if (config != NULL) {
1064        newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
1065	}
1066	else {
1067        newConfig = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1068	}
1069
1070	if (newConfig == NULL) {
1071		SCLog(TRUE, LOG_ERR, CFSTR("%@: cannot allocate new interface configuration"), logTitle);
1072		goto done;
1073	}
1074
1075	if (passwordEncryptionValue) {
1076		CFDictionarySetValue(newConfig, passwordEncryptionKey, passwordEncryptionValue);
1077	} else {
1078		CFDictionaryRemoveValue( newConfig, passwordEncryptionKey);
1079	}
1080
1081	ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
1082	if ( !ok ) {
1083		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkInterfaceSetConfiguration fails"), logTitle);
1084		goto done;
1085	}
1086
1087	// commit & apply the changes
1088	ok = SCPreferencesCommitChanges(prefs);
1089	if (!ok) {
1090		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesCommitChanges fails"), logTitle);
1091		goto done;
1092	}
1093	ok = SCPreferencesApplyChanges(prefs);
1094	if (!ok) {
1095		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesApplyChanges fails"), logTitle);
1096		goto done;
1097	}
1098
1099	success = TRUE;
1100
1101	done :
1102	if (newConfig!= NULL) {
1103		CFRelease(newConfig);
1104	}
1105	if (service != NULL) {
1106		CFRelease(service);
1107	}
1108	if (locked) {
1109		SCPreferencesUnlock(prefs);
1110	}
1111	if (prefs != NULL) {
1112		CFRelease(prefs);
1113	}
1114	return success;
1115}
1116
1117
1118/* -----------------------------------------------------------------------------
1119set the sa_family field of a struct sockaddr, if it exists.
1120----------------------------------------------------------------------------- */
1121#define SET_SA_FAMILY(addr, family)		\
1122    bzero((char *) &(addr), sizeof(addr));	\
1123    addr.sa_family = (family); 			\
1124    addr.sa_len = sizeof(addr);
1125
1126/* -----------------------------------------------------------------------------
1127Config the interface MTU
1128----------------------------------------------------------------------------- */
1129int set_ifmtu(char *ifname, int mtu)
1130{
1131    struct ifreq ifr;
1132	int ip_sockfd;
1133
1134    ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
1135    if (ip_sockfd < 0) {
1136		syslog(LOG_INFO, "sifmtu: cannot create ip socket, %s",
1137	       strerror(errno));
1138		return 0;
1139	}
1140
1141    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1142    ifr.ifr_mtu = mtu;
1143    ioctl(ip_sockfd, SIOCSIFMTU, (caddr_t) &ifr);
1144
1145	close(ip_sockfd);
1146	return 1;
1147}
1148
1149/* -----------------------------------------------------------------------------
1150Config the interface IP addresses and netmask
1151----------------------------------------------------------------------------- */
1152int set_ifaddr(char *ifname, u_int32_t o, u_int32_t h, u_int32_t m)
1153{
1154    struct ifaliasreq ifra __attribute__ ((aligned (4)));   // Wcast-align fix - force alignment
1155	int ip_sockfd;
1156
1157    ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
1158    if (ip_sockfd < 0) {
1159		syslog(LOG_INFO, "sifaddr: cannot create ip socket, %s",
1160	       strerror(errno));
1161		return 0;
1162	}
1163
1164    strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
1165
1166    SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
1167    (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
1168
1169	SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
1170    (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
1171
1172	if (m != 0) {
1173		SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
1174		(ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
1175    }
1176	else
1177		bzero(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
1178
1179    if (ioctl(ip_sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
1180		if (errno != EEXIST) {
1181			//error("Couldn't set interface address: %m");
1182			close(ip_sockfd);
1183			return 0;
1184		}
1185		//warning("Couldn't set interface address: Address %I already exists", o);
1186    }
1187
1188	close(ip_sockfd);
1189	return 1;
1190}
1191
1192/* -----------------------------------------------------------------------------
1193Clear the interface IP addresses, and delete routes
1194 * through the interface if possible
1195 ----------------------------------------------------------------------------- */
1196int clear_ifaddr(char *ifname, u_int32_t o, u_int32_t h)
1197{
1198	struct ifreq ifr __attribute__ ((aligned (4)));       // Wcast-align fix - force alignment
1199	int ip_sockfd;
1200
1201	ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
1202	if (ip_sockfd < 0) {
1203		syslog(LOG_INFO, "cifaddr: cannot create ip socket, %s",
1204		   strerror(errno));
1205		return 0;
1206	}
1207
1208	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1209	SET_SA_FAMILY(ifr.ifr_ifru.ifru_addr, AF_INET);
1210	(ALIGNED_CAST(struct sockaddr_in *) &ifr.ifr_ifru.ifru_addr)->sin_addr.s_addr = o;
1211	if (ioctl(ip_sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) {
1212		close(ip_sockfd);
1213		return 0;
1214	}
1215
1216	close(ip_sockfd);
1217	return 1;
1218}
1219
1220/* -----------------------------------------------------------------------------
1221----------------------------------------------------------------------------- */
1222void
1223in6_len2mask(struct in6_addr *mask, int len)
1224{
1225	int i;
1226
1227	bzero(mask, sizeof(*mask));
1228	for (i = 0; i < len / 8; i++)
1229		mask->s6_addr[i] = 0xff;
1230	if (len % 8)
1231		mask->s6_addr[i] = (0xff00 >> (len % 8)) & 0xff;
1232}
1233
1234/* -----------------------------------------------------------------------------
1235mask address according to the mask
1236----------------------------------------------------------------------------- */
1237void
1238in6_maskaddr(struct in6_addr *addr, struct in6_addr *mask)
1239{
1240	int i;
1241
1242	for (i = 0; i < sizeof(struct in6_addr); i++)
1243		addr->s6_addr[i] &= mask->s6_addr[i];
1244}
1245
1246/* -----------------------------------------------------------------------------
1247----------------------------------------------------------------------------- */
1248void
1249in6_addr2net(struct in6_addr *addr, int prefix, struct in6_addr *net) {
1250
1251    struct in6_addr	mask;
1252	int i;
1253
1254	in6_len2mask(&mask, prefix);
1255
1256	for (i = 0; i < sizeof(mask.s6_addr); i++)
1257		(*net).s6_addr[i] = (*addr).s6_addr[i] & (mask).s6_addr[i];
1258
1259}
1260
1261/* -----------------------------------------------------------------------------
1262Config the interface IPv6 addresses
1263ll_addr must be a 64 bits address.
1264----------------------------------------------------------------------------- */
1265int set_ifaddr6 (char *ifname, struct in6_addr *addr, int prefix)
1266{
1267	int s;
1268	struct in6_aliasreq addreq6;
1269	struct in6_addr		mask;
1270
1271	s = socket(AF_INET6, SOCK_DGRAM, 0);
1272	if (s < 0) {
1273		syslog(LOG_ERR, "set_ifaddr6: can't create IPv6 socket, %s",
1274			   strerror(errno));
1275		return 0;
1276	}
1277
1278	memset(&addreq6, 0, sizeof(addreq6));
1279	strlcpy(addreq6.ifra_name, ifname, sizeof(addreq6.ifra_name));
1280
1281	/* my addr */
1282	addreq6.ifra_addr.sin6_family = AF_INET6;
1283	addreq6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
1284	memcpy(&addreq6.ifra_addr.sin6_addr, addr, sizeof(struct in6_addr));
1285
1286	/* prefix mask: 128bit */
1287	addreq6.ifra_prefixmask.sin6_family = AF_INET6;
1288	addreq6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
1289	in6_len2mask(&mask, prefix);
1290    memcpy(&addreq6.ifra_prefixmask.sin6_addr, &mask, sizeof(struct in6_addr));
1291
1292	/* address lifetime (infty) */
1293	addreq6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
1294	addreq6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
1295
1296	if (IN6_IS_ADDR_LINKLOCAL(addr)) {
1297		if (ioctl(s, SIOCLL_START, &addreq6) < 0) {
1298			syslog(LOG_ERR, "set_ifaddr6: can't set link-local IPv6 address, %s",
1299				   strerror(errno));
1300			close(s);
1301			return 0;
1302		}
1303	} else {
1304		if (ioctl(s, SIOCAIFADDR_IN6, &addreq6) < 0) {
1305			syslog(LOG_ERR, "set_ifaddr6: can't set IPv6 address, %s",
1306				   strerror(errno));
1307			close(s);
1308			return 0;
1309		}
1310	}
1311
1312	close(s);
1313	return 1;
1314}
1315
1316/* -----------------------------------------------------------------------------
1317Clear the interface IPv6 addresses
1318 ----------------------------------------------------------------------------- */
1319int clear_ifaddr6 (char *ifname, struct in6_addr *addr)
1320{
1321    int s;
1322    struct in6_ifreq ifreq6;
1323
1324   s = socket(AF_INET6, SOCK_DGRAM, 0);
1325    if (s < 0) {
1326        syslog(LOG_ERR, "set_ifaddr6: can't create IPv6 socket, %s",
1327	       strerror(errno));
1328        return 0;
1329    }
1330
1331    memset(&ifreq6, 0, sizeof(ifreq6));
1332    strlcpy(ifreq6.ifr_name, ifname, sizeof(ifreq6.ifr_name));
1333
1334    /* my addr */
1335    ifreq6.ifr_ifru.ifru_addr.sin6_family = AF_INET6;
1336    ifreq6.ifr_ifru.ifru_addr.sin6_len = sizeof(struct sockaddr_in6);
1337    memcpy(&ifreq6.ifr_ifru.ifru_addr.sin6_addr, addr, sizeof(struct in6_addr));
1338
1339    if (ioctl(s, SIOCDIFADDR_IN6, &ifreq6) < 0) {
1340        syslog(LOG_ERR, "set_ifaddr6: can't set IPv6 address, %s",
1341	       strerror(errno));
1342        close(s);
1343        return 0;
1344    }
1345
1346    close(s);
1347    return 1;
1348}
1349
1350
1351/* ----------------------------------------------------------------------------
1352----------------------------------------------------------------------------- */
1353const char *inet_sockaddr_to_p(struct sockaddr *addr, char *buf, int buflen)
1354{
1355	void *p;
1356
1357    // Wcast-align fixes (void*) OK - inet_ntop has no alignment requirement
1358	switch (addr->sa_family) {
1359		case AF_INET:
1360            p = &((struct sockaddr_in *)(void*)addr)->sin_addr;
1361            break;
1362		case AF_INET6:
1363            p = &((struct sockaddr_in6 *)(void*)addr)->sin6_addr;
1364			break;
1365		default:
1366			return NULL;
1367	}
1368
1369	return inet_ntop(addr->sa_family, p, buf, buflen);
1370}
1371
1372/* ----------------------------------------------------------------------------
1373----------------------------------------------------------------------------- */
1374int inet_p_to_sockaddr(char *buf, struct sockaddr *addr, int addrlen)
1375{
1376    bzero(addr, addrlen);
1377
1378    // Wcast-align fixes (void*) OK - inet_pton has no alignment requirement
1379	if (addrlen >= sizeof(struct sockaddr_in)
1380		&& inet_pton(AF_INET, buf, &((struct sockaddr_in *)(void*)addr)->sin_addr)) {
1381        addr->sa_len = sizeof(struct sockaddr_in);
1382        addr->sa_family = AF_INET;
1383        return 1;
1384	}
1385
1386	if (addrlen >= sizeof(struct sockaddr_in6)
1387		&& inet_pton(AF_INET6, buf, &((struct sockaddr_in6 *)(void*)addr)->sin6_addr)) {
1388        addr->sa_len = sizeof(struct sockaddr_in6);
1389        addr->sa_family = AF_INET6;
1390        return 1;
1391	}
1392
1393	return 0;
1394}
1395
1396
1397/* ----------------------------------------------------------------------------
1398return the default interface name and gateway for a given protocol
1399----------------------------------------------------------------------------- */
1400Boolean copyGateway(SCDynamicStoreRef store, u_int8_t family, char *ifname, int ifnamesize, struct sockaddr *gateway, int gatewaysize)
1401{
1402	CFDictionaryRef dict;
1403	CFStringRef key, string;
1404	Boolean found_interface = FALSE;
1405	Boolean found_router = FALSE;
1406
1407 	if (ifname)
1408		ifname[0] = 0;
1409	if (gateway)
1410		bzero(gateway, gatewaysize);
1411
1412	if (family != AF_INET && family != AF_INET6)
1413		return FALSE;
1414
1415	key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState,
1416		(family == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6);
1417    if (key) {
1418      dict = SCDynamicStoreCopyValue(store, key);
1419		CFRelease(key);
1420        if (dict) {
1421
1422			if ((string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface))) {
1423				found_interface = TRUE;
1424				if (ifname)
1425					CFStringGetCString(string, ifname, ifnamesize, kCFStringEncodingUTF8);
1426			}
1427			if ((string = CFDictionaryGetValue(dict, (family == AF_INET) ? kSCPropNetIPv4Router : kSCPropNetIPv6Router))) {
1428				char routeraddress[256];
1429				routeraddress[0] = 0;
1430				CFStringGetCString(string, (char*)routeraddress, sizeof(routeraddress), kCFStringEncodingUTF8);
1431				if (routeraddress[0]) {
1432					struct sockaddr_storage addr;
1433					if (inet_p_to_sockaddr(routeraddress, (struct sockaddr *)&addr, sizeof(addr))) {
1434						found_router = TRUE;
1435						if (gateway && gatewaysize >= addr.ss_len)
1436							bcopy(&addr, gateway, addr.ss_len);
1437					}
1438				}
1439			}
1440			CFRelease(dict);
1441		}
1442	}
1443	return (found_interface && found_router);
1444}
1445
1446/* ----------------------------------------------------------------------------
1447return TRUE if there is a default interface and gateway for a given protocol
1448----------------------------------------------------------------------------- */
1449Boolean hasGateway(SCDynamicStoreRef store, u_int8_t family)
1450{
1451	return copyGateway(store, family, 0, 0, 0, 0);
1452
1453}
1454
1455/* ----------------------------------------------------------------------------
1456 Create a "NULL Service" primary IPv6 dictionary for the dynamic store. This
1457 prevents any other service from becoming primary on IPv6.
1458 ----------------------------------------------------------------------------- */
1459#ifndef kIsNULL
1460#define kIsNULL		CFSTR("IsNULL") /* CFBoolean */
1461#endif
1462CFDictionaryRef create_ipv6_dummy_primary(char *if_name)
1463{
1464	CFMutableArrayRef		array;
1465	CFMutableDictionaryRef	ipv6_dict;
1466	int						isprimary = 1;
1467	CFNumberRef				num;
1468	CFStringRef				str;
1469
1470	/* create the IPv6 dictionnary */
1471	if ((ipv6_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0)
1472		return NULL;
1473
1474	if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) {
1475		CFArrayAppendValue(array, CFSTR("::1"));
1476		CFDictionarySetValue(ipv6_dict, kSCPropNetIPv6Addresses, array);
1477		CFRelease(array);
1478	}
1479
1480	CFDictionarySetValue(ipv6_dict, kSCPropNetIPv6Router, CFSTR("::1"));
1481
1482	num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &isprimary);
1483	if (num) {
1484		CFDictionarySetValue(ipv6_dict, kSCPropNetOverridePrimary, num);
1485		CFRelease(num);
1486	}
1487
1488	CFDictionarySetValue(ipv6_dict, kIsNULL, kCFBooleanTrue);
1489
1490	if (if_name) {
1491		if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), if_name))) {
1492			CFDictionarySetValue(ipv6_dict, kSCPropInterfaceName, str);
1493			CFRelease(str);
1494		}
1495	}
1496
1497	return ipv6_dict;
1498}
1499
1500/* ----------------------------------------------------------------------------
1501get dictionary for ip addresses to publish later to configd
1502use new state information model
1503----------------------------------------------------------------------------- */
1504CFDictionaryRef create_stateaddr(SCDynamicStoreRef store, CFStringRef serviceID, char *if_name, u_int32_t server, u_int32_t o,
1505			u_int32_t h, u_int32_t m, int isprimary)
1506{
1507    struct in_addr		addr;
1508    CFMutableArrayRef		array;
1509    CFMutableDictionaryRef	ipv4_dict;
1510    CFStringRef			str;
1511    CFNumberRef		num;
1512	SCNetworkServiceRef netservRef;
1513
1514    /* create the IPV4 dictionnary */
1515    if ((ipv4_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0)
1516        return NULL;
1517
1518	/* set the ip address src and dest arrays */
1519    if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) {
1520        addr.s_addr = o;
1521        if ((str = CFStringCreateWithFormat(0, 0, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
1522            CFArrayAppendValue(array, str);
1523            CFRelease(str);
1524            CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Addresses, array);
1525        }
1526        CFRelease(array);
1527    }
1528
1529    /* set the router */
1530    addr.s_addr = h;
1531    if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
1532        CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Router, str);
1533        CFRelease(str);
1534    }
1535
1536	num = CFNumberCreate(NULL, kCFNumberIntType, &isprimary);
1537	if (num) {
1538        CFDictionarySetValue(ipv4_dict, kSCPropNetOverridePrimary, num);
1539		CFRelease(num);
1540	}
1541
1542	if (if_name) {
1543		if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), if_name))) {
1544			CFDictionarySetValue(ipv4_dict, kSCPropInterfaceName, str);
1545			CFRelease(str);
1546		}
1547	}
1548
1549    /* set the server */
1550    addr.s_addr = server;
1551    if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
1552		CFDictionarySetValue(ipv4_dict, CFSTR("ServerAddress"), str);
1553        CFRelease(str);
1554    }
1555
1556#if 0
1557    /* add the network signature */
1558    if (network_signature) {
1559		if (str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), network_signature)) {
1560			CFDictionarySetValue(ipv4_dict, CFSTR("NetworkSignature"), str);
1561			CFRelease(str);
1562		}
1563	}
1564#endif
1565
1566
1567	/* rank service, to prevent it from becoming primary */
1568	if (!isprimary) {
1569		netservRef = _SCNetworkServiceCopyActive(store, serviceID);
1570		if (netservRef) {
1571			SCNetworkServiceSetPrimaryRank(netservRef, kSCNetworkServicePrimaryRankLast);
1572			CFRelease(netservRef);
1573		}
1574	}
1575
1576    return ipv4_dict;
1577}
1578
1579/* -----------------------------------------------------------------------------
1580 get dns information
1581 ----------------------------------------------------------------------------- */
1582CFDictionaryRef create_dns(SCDynamicStoreRef store, CFStringRef serviceID, CFArrayRef dns, CFStringRef domain, CFArrayRef supp_domains, Boolean neverSearchDomains)
1583{
1584    CFMutableDictionaryRef	dict = NULL;
1585    CFStringRef			key = NULL;
1586    CFPropertyListRef		ref;
1587
1588    if (store == NULL)
1589        return NULL;
1590
1591    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, kSCEntNetDNS);
1592    if (!key)
1593        goto end;
1594
1595    if ((ref = SCDynamicStoreCopyValue(store, key))) {
1596        dict = CFDictionaryCreateMutableCopy(0, 0, ref);
1597        CFRelease(ref);
1598    } else
1599        dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1600
1601    if (!dict || (CFGetTypeID(dict) != CFDictionaryGetTypeID()))
1602        goto end;
1603
1604    CFDictionarySetValue(dict, kSCPropNetDNSServerAddresses, dns);
1605
1606    if (domain)
1607		CFDictionarySetValue(dict, kSCPropNetDNSDomainName, domain);
1608
1609    if (supp_domains)
1610		CFDictionarySetValue(dict, kSCPropNetDNSSupplementalMatchDomains, supp_domains);
1611
1612#ifndef kSCPropNetDNSSupplementalMatchDomainsNoSearch
1613#define kSCPropNetDNSSupplementalMatchDomainsNoSearch CFSTR("SupplementalMatchDomainsNoSearch")
1614#endif
1615
1616    if (neverSearchDomains) {
1617        AddNumber(dict, kSCPropNetDNSSupplementalMatchDomainsNoSearch, 1);
1618    }
1619
1620	/* warn lookupd of upcoming change */
1621	notify_post("com.apple.system.dns.delay");
1622
1623end:
1624    my_CFRelease(&key);
1625    return dict;
1626
1627}
1628
1629/* -----------------------------------------------------------------------------
1630 ----------------------------------------------------------------------------- */
1631Boolean equal_address(struct sockaddr *addr1, struct sockaddr *addr2)
1632{
1633
1634	if (addr1->sa_family != addr2->sa_family)
1635		return FALSE;
1636
1637    /* Wcast-align fixes - don't use assignement or standard compare for ptrs of unknown alignment */
1638	if (addr1->sa_family == AF_INET) {
1639        return (!bcmp(&((struct sockaddr_in *)(void*)addr1)->sin_addr.s_addr,
1640                      &((struct sockaddr_in *)(void*)addr2)->sin_addr.s_addr,
1641                      sizeof(struct in_addr)));
1642	}
1643
1644	if (addr1->sa_family == AF_INET6) {
1645		return (!bcmp(&((struct sockaddr_in6 *)(void*)addr1)->sin6_addr,
1646                      &((struct sockaddr_in6 *)(void*)addr2)->sin6_addr,
1647                      sizeof(struct in6_addr)));
1648	}
1649
1650	return FALSE;
1651}
1652
1653/* -----------------------------------------------------------------------------
1654    add/remove a route via a gateway
1655----------------------------------------------------------------------------- */
1656int
1657route_gateway(int cmd, struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *gateway, int use_gway_flag, int use_blackhole_flag)
1658{
1659    int 			len;
1660    int 			rtm_seq = 0;
1661
1662    struct rtmsg_in4 {
1663	struct rt_msghdr	hdr;
1664	struct sockaddr_in	dst;
1665	struct sockaddr_in	gway;
1666	struct sockaddr_in	mask;
1667    };
1668    struct rtmsg_in6 {
1669	struct rt_msghdr	hdr;
1670	struct sockaddr_in6	dst;
1671	struct sockaddr_in6	gway;
1672	struct sockaddr_in6	mask;
1673    };
1674
1675    int 			sockfd = -1;
1676    struct rtmsg_in6 rtmsg; // use rtmsg_in6 since it is the bigger one;
1677
1678	if (dest == NULL || (dest->sa_family != AF_INET
1679		&& dest->sa_family != AF_INET6))
1680		return -1;
1681
1682    if ((sockfd = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) {
1683	syslog(LOG_INFO, "route_gateway: open routing socket failed, %s",
1684	       strerror(errno));
1685	return (-1);
1686    }
1687
1688    memset(&rtmsg, 0, sizeof(rtmsg));
1689
1690	// fill in header, which is common to IPv4 and IPv6
1691    rtmsg.hdr.rtm_type = cmd;
1692    rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
1693    if (use_gway_flag)
1694        rtmsg.hdr.rtm_flags |= RTF_GATEWAY;
1695    if (use_blackhole_flag)
1696        rtmsg.hdr.rtm_flags |= RTF_BLACKHOLE;
1697    rtmsg.hdr.rtm_version = RTM_VERSION;
1698    rtmsg.hdr.rtm_seq = ++rtm_seq;
1699    rtmsg.hdr.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
1700
1701	// then fill in address specific portion
1702	if (dest->sa_family == AF_INET) {
1703		struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg;
1704
1705		bcopy(dest, &rtmsg4->dst, sizeof(rtmsg4->dst));
1706		if (gateway)
1707			bcopy(gateway, &rtmsg4->gway, sizeof(rtmsg4->gway));
1708		if (mask)
1709			bcopy(mask, &rtmsg4->mask, sizeof(rtmsg4->mask));
1710
1711		len = sizeof(struct rtmsg_in4);
1712	}
1713	else {
1714		struct rtmsg_in6 *rtmsg6 = (struct rtmsg_in6 *)&rtmsg;
1715
1716		bcopy(dest, &rtmsg6->dst, sizeof(rtmsg6->dst));
1717		if (gateway)
1718			bcopy(gateway, &rtmsg6->gway, sizeof(rtmsg6->gway));
1719		if (mask)
1720			bcopy(mask, &rtmsg6->mask, sizeof(rtmsg6->mask));
1721
1722		len = sizeof(struct rtmsg_in6);
1723	}
1724
1725	rtmsg.hdr.rtm_msglen = len;
1726    if (write(sockfd, &rtmsg, len) < 0) {
1727		syslog((cmd == RTM_DELETE)? LOG_DEBUG : LOG_ERR, "route_gateway: write routing socket failed, %s", strerror(errno));
1728
1729#if 0
1730		/* print routing message for debugging */
1731		char buf[256];
1732		syslog(LOG_ERR, "-------");
1733		struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg;
1734		inet_sockaddr_to_p(dest->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->dst : (struct sockaddr *)&rtmsg.dst, buf, sizeof(buf));
1735		syslog(LOG_ERR, "route_gateway: rtmsg.dst = %s", buf);
1736		inet_sockaddr_to_p(dest->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->gway : (struct sockaddr *)&rtmsg.gway, buf, sizeof(buf));
1737		syslog(LOG_ERR, "route_gateway: rtmsg.gway = %s", buf);
1738		inet_sockaddr_to_p(dest->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->mask : (struct sockaddr *)&rtmsg.mask, buf, sizeof(buf));
1739		syslog(LOG_ERR, "route_gateway: rtmsg.mask = %s", buf);
1740		syslog(LOG_ERR, "-------");
1741#endif
1742
1743		close(sockfd);
1744		return (-1);
1745    }
1746
1747    close(sockfd);
1748    return (0);
1749}
1750
1751/* -----------------------------------------------------------------------------
1752add/remove a host route
1753----------------------------------------------------------------------------- */
1754boolean_t
1755set_host_gateway(int cmd, struct sockaddr *host, struct sockaddr *gateway, char *ifname, int isnet)
1756{
1757    int 			len;
1758    int 			rtm_seq = 0;
1759    struct rtmsg_in4 {
1760	struct rt_msghdr	hdr;
1761	struct sockaddr_in	dst;
1762	struct sockaddr_in	gway;
1763	struct sockaddr_in	mask;
1764	struct sockaddr_dl	link;
1765    };
1766    struct rtmsg_in6 {
1767	struct rt_msghdr	hdr;
1768	struct sockaddr_in6	dst;
1769	struct sockaddr_in6	gway;
1770	struct sockaddr_in6	mask;
1771	struct sockaddr_dl	link;
1772    };
1773
1774    int 			sockfd = -1;
1775    struct rtmsg_in6 rtmsg; // use rtmsg_in6 since it is the bigger one;
1776	struct sockaddr_dl *link;
1777	struct in6_addr     ip6_zeros;
1778    struct in_addr      ip4_zeros;
1779
1780	if (host == NULL || (host->sa_family != AF_INET
1781		&& host->sa_family != AF_INET6))
1782		return FALSE;
1783
1784    if ((sockfd = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) {
1785	syslog(LOG_INFO, "host_gateway: open routing socket failed, %s",
1786	       strerror(errno));
1787	return (FALSE);
1788    }
1789
1790    memset(&rtmsg, 0, sizeof(rtmsg));
1791    rtmsg.hdr.rtm_type = cmd;
1792    rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
1793    if (isnet)
1794        rtmsg.hdr.rtm_flags |= RTF_CLONING;
1795    else
1796        rtmsg.hdr.rtm_flags |= RTF_HOST;
1797	bzero(&ip6_zeros, sizeof(ip6_zeros));
1798    bzero(&ip4_zeros, sizeof(ip4_zeros));
1799    // Wcast-align fix - use memcmp for unaligned comparison
1800    if (gateway && (((gateway->sa_family == AF_INET && memcmp(&((struct sockaddr_in *)(void*)gateway)->sin_addr.s_addr, &ip4_zeros, sizeof(struct in_addr)))) ||
1801		(gateway->sa_family == AF_INET6 && memcmp(&((struct sockaddr_in6 *)(void*)gateway)->sin6_addr, &ip6_zeros, sizeof(struct in6_addr))))) {
1802        rtmsg.hdr.rtm_flags |= RTF_GATEWAY;
1803	}
1804
1805	rtmsg.hdr.rtm_version = RTM_VERSION;
1806    rtmsg.hdr.rtm_seq = ++rtm_seq;
1807    rtmsg.hdr.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
1808
1809	if (host->sa_family == AF_INET) {
1810		struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg;
1811
1812		bcopy(host, &rtmsg4->dst, sizeof(rtmsg4->dst));
1813
1814		if (gateway)
1815			bcopy(gateway, &rtmsg4->gway, sizeof(rtmsg4->gway));
1816
1817		rtmsg4->mask.sin_len = sizeof(rtmsg4->mask);
1818		rtmsg4->mask.sin_family = AF_INET;
1819		rtmsg4->mask.sin_addr.s_addr = 0xFFFFFFFF;
1820
1821		len = sizeof(struct rtmsg_in4);
1822		link = &rtmsg4->link;
1823	}
1824	else {
1825		struct rtmsg_in6 *rtmsg6 = (struct rtmsg_in6 *)&rtmsg;
1826
1827		bcopy(host, &rtmsg6->dst, sizeof(rtmsg6->dst));
1828
1829		if (gateway)
1830			bcopy(gateway, &rtmsg6->gway, sizeof(rtmsg6->gway));
1831
1832		rtmsg6->mask.sin6_len = sizeof(rtmsg6->mask);
1833		rtmsg6->mask.sin6_family = AF_INET6;
1834		rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[0] = 0xFFFFFFFF;
1835		rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[1] = 0xFFFFFFFF;
1836		rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[2] = 0xFFFFFFFF;
1837		rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[3] = 0xFFFFFFFF;
1838
1839		len = sizeof(struct rtmsg_in6);
1840		link = &rtmsg6->link;
1841	}
1842
1843    if (ifname) {
1844		link->sdl_len = sizeof(rtmsg.link);
1845		link->sdl_family = AF_LINK;
1846		link->sdl_nlen = MIN(strlen(ifname), sizeof(link->sdl_data));
1847		rtmsg.hdr.rtm_addrs |= RTA_IFP;
1848		bcopy(ifname, link->sdl_data, link->sdl_nlen);
1849    }
1850    else {
1851		/* no link information */
1852		len -= sizeof(rtmsg.link);
1853    }
1854
1855    rtmsg.hdr.rtm_msglen = len;
1856    if (write(sockfd, &rtmsg, len) < 0) {
1857		syslog((cmd == RTM_DELETE)? LOG_DEBUG : LOG_ERR, "host_gateway: write routing socket failed, command %d, %s", cmd, strerror(errno));
1858
1859#if 0
1860		/* print routing message for debugging */
1861		char buf[256];
1862		syslog(LOG_ERR, "********");
1863		struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg;
1864		syslog(LOG_ERR, "host_gateway: dest->sa_family = %d rtmsg.hdr.rtm_msglen = %d", host->sa_family, rtmsg.hdr.rtm_msglen);
1865		inet_sockaddr_to_p(host->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->dst : (struct sockaddr *)&rtmsg.dst, buf, sizeof(buf));
1866		syslog(LOG_ERR, "host_gateway: rtmsg.dst = %s", buf);
1867		inet_sockaddr_to_p(host->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->gway : (struct sockaddr *)&rtmsg.gway, buf, sizeof(buf));
1868		syslog(LOG_ERR, "host_gateway: rtmsg.gway = %s", buf);
1869		inet_sockaddr_to_p(host->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->mask : (struct sockaddr *)&rtmsg.mask, buf, sizeof(buf));
1870		syslog(LOG_ERR, "host_gateway: rtmsg.mask = %s", buf);
1871		syslog(LOG_ERR, "********");
1872#endif
1873		close(sockfd);
1874		return (FALSE);
1875    }
1876
1877    close(sockfd);
1878    return (TRUE);
1879}
1880
1881/* ----------------------------------------------------------------------------
1882 get proxies using to publish to configd
1883 ----------------------------------------------------------------------------- */
1884CFDictionaryRef create_proxies(SCDynamicStoreRef store, CFStringRef serviceID, int autodetect, CFStringRef server, int port, int bypasslocal,
1885		CFStringRef exceptionlist, CFArrayRef supp_domains)
1886{
1887	int				val, ret = -1;
1888    CFStringRef		cfstr = NULL;
1889    CFArrayRef		cfarray;
1890    CFNumberRef		cfnum,  cfone = NULL;
1891    CFMutableDictionaryRef	proxies_dict = NULL;
1892
1893    if ((proxies_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0)
1894        goto fail;
1895
1896	val = 1;
1897	cfone = CFNumberCreate(NULL, kCFNumberIntType, &val);
1898	if (cfone == NULL)
1899		goto fail;
1900
1901	if (autodetect) {
1902		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesProxyAutoDiscoveryEnable, cfone);
1903	}
1904	else if (server) {
1905
1906		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesFTPEnable, cfone);
1907		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPEnable, cfone);
1908		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPSEnable, cfone);
1909
1910		cfnum = CFNumberCreate(NULL, kCFNumberIntType, &port);
1911		if (cfnum == NULL)
1912			goto fail;
1913
1914		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesFTPPort, cfnum);
1915		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPPort, cfnum);
1916		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPSPort, cfnum);
1917		CFRelease(cfnum);
1918
1919		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesFTPProxy, server);
1920		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPProxy, server);
1921		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPSProxy, server);
1922
1923		cfnum = CFNumberCreate(NULL, kCFNumberIntType, &bypasslocal);
1924		if (cfnum == NULL)
1925			goto fail;
1926		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesExcludeSimpleHostnames, cfnum);
1927		CFRelease(cfnum);
1928
1929		if (exceptionlist) {
1930			cfarray = CFStringCreateArrayBySeparatingStrings(NULL, exceptionlist, CFSTR(";"));
1931			if (cfarray) {
1932				CFDictionarySetValue(proxies_dict, kSCPropNetProxiesExceptionsList, cfarray);
1933				CFRelease(cfarray);
1934			}
1935		}
1936	}
1937
1938#ifndef kSCPropNetProxiesSupplementalMatchDomains
1939#define kSCPropNetProxiesSupplementalMatchDomains kSCPropNetDNSSupplementalMatchDomains
1940#endif
1941
1942    if (supp_domains)
1943		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesSupplementalMatchDomains, supp_domains);
1944
1945	ret = 0;
1946
1947fail:
1948
1949    my_CFRelease(&cfone);
1950	my_CFRelease(&cfstr);
1951    return proxies_dict;
1952}
1953
1954/* -----------------------------------------------------------------------------
1955 Create the new tun interface, and return the socket
1956 ----------------------------------------------------------------------------- */
1957int create_tun_interface(char *name, int name_max_len, int *index, int flags, int ext_stats)
1958{
1959
1960	struct ctl_info kernctl_info;
1961	struct sockaddr_ctl kernctl_addr;
1962	u_int32_t optlen;
1963	int tunsock = -1;
1964
1965	tunsock = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
1966	if (tunsock == -1) {
1967		SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: cannot create kernel control socket (errno = %d)"), errno);
1968		goto fail;
1969	}
1970
1971	bzero(&kernctl_info, sizeof(kernctl_info));
1972    strlcpy(kernctl_info.ctl_name, UTUN_CONTROL_NAME, sizeof(kernctl_info.ctl_name));
1973	if (ioctl(tunsock, CTLIOCGINFO, &kernctl_info)) {
1974		SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: ioctl failed on kernel control socket (errno = %d)"), errno);
1975		goto fail;
1976	}
1977
1978	bzero(&kernctl_addr, sizeof(kernctl_addr)); // sets the sc_unit field to 0
1979	kernctl_addr.sc_len = sizeof(kernctl_addr);
1980	kernctl_addr.sc_family = AF_SYSTEM;
1981	kernctl_addr.ss_sysaddr = AF_SYS_CONTROL;
1982	kernctl_addr.sc_id = kernctl_info.ctl_id;
1983	kernctl_addr.sc_unit = 0; // we will get the unit number from getpeername
1984	if (connect(tunsock, (struct sockaddr *)&kernctl_addr, sizeof(kernctl_addr))) {
1985		SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: connect failed on kernel control socket (errno = %d)"), errno);
1986		goto fail;
1987	}
1988
1989	optlen = name_max_len;
1990	if (getsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &optlen)) {
1991		SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: getsockopt ifname failed on kernel control socket (errno = %d)"), errno);
1992		goto fail;
1993	}
1994
1995	*index = if_nametoindex(name);
1996
1997	if (flags) {
1998		int optflags = 0;
1999		optlen = sizeof(u_int32_t);
2000		if (getsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_FLAGS, &optflags, &optlen)) {
2001			SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: getsockopt flags failed on kernel control socket (errno = %d)"), errno);
2002			goto fail;
2003		}
2004
2005		optflags |= (UTUN_FLAGS_NO_INPUT + UTUN_FLAGS_NO_OUTPUT);
2006		optlen = sizeof(u_int32_t);
2007		if (setsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_FLAGS, &optflags, optlen)) {
2008			SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: setsockopt flags failed on kernel control socket (errno = %d)"), errno);
2009			goto fail;
2010		}
2011	}
2012
2013	if (ext_stats) {
2014		int optval = 1;
2015		if (setsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_EXT_IFDATA_STATS, &optval, sizeof(optval))) {
2016			SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: setsockopt externat stats failed on kernel control socket (errno = %d)"), errno);
2017			goto fail;
2018		}
2019	}
2020
2021	return tunsock;
2022
2023fail:
2024	my_close(tunsock);
2025	return -1;
2026
2027}
2028
2029/* -----------------------------------------------------------------------------
2030 Set the delegate interface for the tun interface
2031 ----------------------------------------------------------------------------- */
2032int set_tun_delegate(int tunsock, char *delegate_ifname)
2033{
2034    int result = 0;
2035
2036    if ((result = setsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_SET_DELEGATE_INTERFACE, delegate_ifname, strlen(delegate_ifname))))
2037        SCLog(TRUE, LOG_ERR, CFSTR("set_tun_delegate: setsockopt delegate interface failed on kernel control socket (errno = %s)"), strerror(errno));
2038
2039    return result;
2040}
2041
2042/* -----------------------------------------------------------------------------
2043----------------------------------------------------------------------------- */
2044int event_create_socket(void * ctxt, int *eventfd, CFSocketRef *eventref, CFSocketCallBack callout, Boolean anysubclass)
2045{
2046    CFRunLoopSourceRef	rls;
2047    CFSocketContext	context = { 0, ctxt, NULL, NULL, NULL };
2048    struct kev_request	kev_req;
2049
2050	*eventfd = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
2051	if (*eventfd < 0) {
2052		SCLog(TRUE, LOG_ERR, CFSTR("event_create_socket cannot create event socket (errno = %d) "), errno);
2053		goto fail;
2054	}
2055
2056	kev_req.vendor_code = KEV_VENDOR_APPLE;
2057	kev_req.kev_class = KEV_NETWORK_CLASS;
2058	kev_req.kev_subclass = anysubclass ? KEV_ANY_SUBCLASS : KEV_INET_SUBCLASS;
2059	ioctl(*eventfd, SIOCSKEVFILT, &kev_req);
2060
2061    if ((*eventref = CFSocketCreateWithNative(NULL, *eventfd,
2062                    kCFSocketReadCallBack, callout, &context)) == 0) {
2063        goto fail;
2064    }
2065    if ((rls = CFSocketCreateRunLoopSource(NULL, *eventref, 0)) == 0)
2066        goto fail;
2067
2068    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
2069    CFRelease(rls);
2070
2071    return 0;
2072
2073fail:
2074	if (*eventref) {
2075		CFSocketInvalidate(*eventref);
2076		CFRelease(*eventref);
2077	}
2078	else
2079		if (*eventfd >= 0) {
2080			close(*eventfd);
2081	}
2082	*eventref = 0;
2083	*eventfd = -1;
2084
2085    return -1;
2086}
2087
2088/* -----------------------------------------------------------------------------
2089 ----------------------------------------------------------------------------- */
2090typedef struct exec_callback_args {
2091	CFRunLoopRef            rl;
2092	CFRunLoopSourceRef      rls;
2093	CFRunLoopSourceContext  rlc;
2094	pid_t                   pid;
2095	int                     status;
2096	struct rusage	        rusage;
2097	SCDPluginExecCallBack   callback;
2098	void                   *callbackContext;
2099} exec_callback_args_t;
2100
2101/* -----------------------------------------------------------------------------
2102 ----------------------------------------------------------------------------- */
2103static
2104void exec_callback(pid_t pid, int status, struct rusage *rusage, void *context)
2105{
2106	if (isA_CFData(context)) {
2107		exec_callback_args_t *args = ALIGNED_CAST(__typeof__(args))CFDataGetMutableBytePtr((CFMutableDataRef)context);
2108		args->pid = pid;
2109		args->status = status;
2110		bcopy(rusage, &args->rusage, sizeof(args->rusage));
2111		// args->context already contains the service
2112		CFRunLoopSourceSignal(args->rls);
2113		CFRunLoopWakeUp(args->rl);
2114	}
2115}
2116
2117static void
2118SCNCPluginExecCallbackRunLoopSource (void *info)
2119{
2120	if (isA_CFData(info)) {
2121		exec_callback_args_t *args = ALIGNED_CAST(__typeof__(args))CFDataGetMutableBytePtr((CFMutableDataRef)info);
2122		if (args->callback) {
2123			args->callback(args->pid, args->status, &args->rusage, args->callbackContext);
2124		}
2125		CFRunLoopSourceInvalidate(args->rls);
2126		CFRelease(args->rls);
2127		CFRelease(args->rl);
2128		CFRelease((CFMutableDataRef)info); // release (was allocated in SCNCPluginExecCallbackRunLoopSourceInit)
2129	}
2130}
2131
2132CFMutableDataRef
2133SCNCPluginExecCallbackRunLoopSourceInit (CFRunLoopRef           runloop,
2134										 SCDPluginExecCallBack  callback,
2135										 void	               *callbackContext)
2136{
2137	CFMutableDataRef      dataRef; // to be used as SCNCPluginExecCallbackRunLoopSource's info
2138	UInt8                *dataPtr;
2139	exec_callback_args_t  args;
2140
2141	// create dataref and fill it with runloop args
2142	dataRef = CFDataCreateMutable(NULL, sizeof(args));
2143	if (dataRef == NULL) {
2144		return NULL;
2145	}
2146	CFDataSetLength(dataRef, sizeof(args));
2147	dataPtr = CFDataGetMutableBytePtr(dataRef);
2148
2149	bzero(&args, sizeof(args));
2150	args.rlc.info = dataRef; // use as SCNCPluginExecCallbackRunLoopSource's info
2151	args.rlc.perform = SCNCPluginExecCallbackRunLoopSource;
2152	args.rls = CFRunLoopSourceCreate(NULL, 0, &args.rlc);
2153	if (!args.rls){
2154		CFRelease(dataRef);
2155		return NULL;
2156	}
2157	args.callback = callback;
2158	args.callbackContext = callbackContext;
2159	if (!runloop) {
2160		args.rl = CFRunLoopGetCurrent();
2161	} else {
2162		args.rl = runloop;
2163	}
2164	CFRetain(args.rl);
2165	CFRunLoopAddSource(args.rl, args.rls, kCFRunLoopDefaultMode);
2166	bcopy(&args, dataPtr, sizeof(args));
2167	return dataRef; // to be used as exec_callback's context
2168}
2169
2170pid_t
2171SCNCPluginExecCommand (CFRunLoopRef           runloop,
2172					   SCDPluginExecCallBack  callback,
2173					   void        	         *callbackContext,
2174					   uid_t                  uid,
2175					   gid_t                  gid,
2176					   const char            *path,
2177					   char * const           argv[])
2178{
2179	pid_t            rc;
2180	CFMutableDataRef exec_callback_context;
2181
2182	exec_callback_context = SCNCPluginExecCallbackRunLoopSourceInit(runloop, callback, callbackContext);
2183	if (!exec_callback_context){
2184		SCLog(TRUE, LOG_ERR, CFSTR("SCNC: failed to initialize plugin exec_callback's runloop source"));
2185		return -1;
2186	}
2187
2188	rc = _SCDPluginExecCommand(exec_callback,
2189							   exec_callback_context,
2190							   uid,
2191							   gid,
2192							   path,
2193							   argv);
2194	return rc;
2195}
2196
2197pid_t
2198SCNCPluginExecCommand2 (CFRunLoopRef           runloop,
2199						SCDPluginExecCallBack  callback,
2200						void                  *callbackContext,
2201						uid_t                  uid,
2202						gid_t                  gid,
2203						const char            *path,
2204						char * const           argv[],
2205						SCDPluginExecSetup     setup,
2206						void                  *setupContext)
2207{
2208	pid_t            rc;
2209	CFMutableDataRef exec_callback_context;
2210
2211	exec_callback_context = SCNCPluginExecCallbackRunLoopSourceInit(runloop, callback, callbackContext);
2212	if (!exec_callback_context){
2213		SCLog(TRUE, LOG_ERR, CFSTR("SCNC: failed to initialize plugin exec_callback's runloop source"));
2214		return -1;
2215	}
2216
2217	rc = _SCDPluginExecCommand2(exec_callback,
2218								exec_callback_context,
2219								uid,
2220								gid,
2221								path,
2222								argv,
2223								setup,
2224								setupContext);
2225	return rc;
2226}
2227
2228#define SBSLAUNCHER_NAME "sbslauncher"
2229#define MAX_SBSLAUNCHER_ARGS 16
2230
2231/* Variable arguments are of type char*, and the last argument must be NULL */
2232pid_t
2233SCNCExecSBSLauncherCommandWithArguments (char *command,
2234										 SCDPluginExecSetup setup,
2235										 SCDPluginExecCallBack callback,
2236										 void *callbackContext,
2237										 ...)
2238{
2239	va_list			arguments;
2240	CFStringRef 	resourceDir = NULL;
2241	CFURLRef 		resourceURL = NULL, absoluteURL = NULL;
2242	char			thepath[MAXPATHLEN];
2243	pid_t			pid = 0;
2244	char 			*cmdarg[MAX_SBSLAUNCHER_ARGS];
2245
2246	resourceURL = CFBundleCopyResourcesDirectoryURL(gBundleRef);
2247
2248	if (resourceURL == NULL)
2249		goto done;
2250
2251	absoluteURL = CFURLCopyAbsoluteURL(resourceURL);
2252	if (absoluteURL == NULL)
2253		goto done;
2254
2255	resourceDir = CFURLCopyPath(absoluteURL);
2256	if (resourceDir == NULL)
2257		goto done;
2258
2259	if (!CFStringGetCString(resourceDir, thepath, sizeof(thepath), kCFStringEncodingMacRoman))
2260		goto done;
2261
2262	strlcat(thepath, SBSLAUNCHER_NAME, sizeof(thepath));
2263
2264	cmdarg[0] = SBSLAUNCHER_NAME;
2265	cmdarg[1] = command;
2266
2267	va_start(arguments, callbackContext);
2268	int i = 2;
2269
2270	char *arg_i = va_arg(arguments, char *);
2271	while (arg_i != NULL && i < (MAX_SBSLAUNCHER_ARGS - 1)) {
2272		cmdarg[i++] = arg_i;
2273		arg_i = va_arg(arguments, char *);
2274	}
2275	cmdarg[i] = NULL;
2276	va_end(arguments);
2277
2278	if (setup) {
2279		pid = SCNCPluginExecCommand2(NULL, callback, callbackContext, 0, 0, thepath, cmdarg, setup, callbackContext);
2280	} else {
2281		pid = SCNCPluginExecCommand(NULL, callback, callbackContext, 0, 0, thepath, cmdarg);
2282	}
2283
2284done:
2285	if (resourceDir)
2286		CFRelease(resourceDir);
2287	if (absoluteURL)
2288		CFRelease(absoluteURL);
2289	if (resourceURL)
2290		CFRelease(resourceURL);
2291
2292	return pid;
2293}
2294
2295void
2296applyEnvironmentVariablesApplierFunction (const void *key, const void *value, void *context)
2297{
2298	CFRange range;
2299
2300	if (isA_CFString(key)) {
2301		char key_buf[256];
2302		char value_buf[256];
2303
2304		range.location = 0;
2305		range.length = CFStringGetLength((CFStringRef)key);
2306		if (range.length <= 0 ||
2307			range.length >= sizeof(key_buf) ||
2308			CFStringGetBytes((CFStringRef)key, range, kCFStringEncodingUTF8, 0, false, (UInt8 *)key_buf, sizeof(key_buf), NULL) <= 0) {
2309			SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value);
2310			return;
2311		}
2312		key_buf[range.length] = '\0';
2313
2314		unsetenv((const char *)key_buf);
2315
2316		if (isA_CFString(value)) {
2317			range.location = 0;
2318			range.length = CFStringGetLength((CFStringRef)value);
2319			if (range.length <= 0 ||
2320				range.length >= sizeof(value_buf) ||
2321				CFStringGetBytes((CFStringRef)value, range, kCFStringEncodingUTF8, 0, false, (UInt8 *)value_buf, sizeof(value_buf), NULL) <= 0) {
2322				SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value);
2323				return;
2324			}
2325			value_buf[range.length] = '\0';
2326		} else if (isA_CFNumber(value)) {
2327			int64_t number = 0;
2328			if (CFNumberGetValue((CFNumberRef)value, kCFNumberSInt64Type, &number)) {
2329				snprintf(value_buf,sizeof(value_buf), "%lld", number);
2330			} else {
2331				SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value);
2332				return;
2333			}
2334		} else if (isA_CFBoolean(value)) {
2335			snprintf(value_buf, sizeof(value_buf), "%s", CFBooleanGetValue((CFBooleanRef)value) ? "Yes" : "No");
2336		} else {
2337			SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value);
2338			return;
2339		}
2340
2341		setenv(key_buf, value_buf, TRUE);
2342	} else {
2343		SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key"));
2344	}
2345}
2346
2347CFDictionaryRef
2348collectEnvironmentVariables (SCDynamicStoreRef storeRef, CFStringRef serviceID)
2349{
2350	if (!storeRef) {
2351		SCLog(TRUE, LOG_ERR, CFSTR("invalid DynamicStore passed to %s"), __FUNCTION__);
2352		return NULL;
2353	}
2354
2355	if (!serviceID) {
2356		SCLog(TRUE, LOG_ERR, CFSTR("invalid serviceID passed to %s"), __FUNCTION__);
2357		return NULL;
2358	}
2359
2360	return copyEntity(storeRef, kSCDynamicStoreDomainSetup, serviceID, CFSTR("EnvironmentVariables"));
2361}
2362
2363void
2364applyEnvironmentVariables (CFDictionaryRef envVarDict)
2365{
2366	if (!envVarDict) {
2367		return;
2368	} else if (isA_CFDictionary(envVarDict) &&
2369			   CFDictionaryGetCount(envVarDict) > 0) {
2370		CFDictionaryApplyFunction(envVarDict, applyEnvironmentVariablesApplierFunction, NULL);
2371	} else {
2372		/* don't call SCLog() as it's unsafe in a post-fork handler that requires async-signal safe. */
2373		// SCLog(TRUE, LOG_ERR, CFSTR("empty or invalid EnvironmentVariables dictionary"));
2374	}
2375}
2376
2377const char *
2378scnc_get_reason_str(int scnc_reason)
2379{
2380	switch (scnc_reason) {
2381		case SCNC_STOP_CTRL_STOP:
2382			return scnc_ctrl_stopped;
2383		case SCNC_STOP_SYS_SLEEP:
2384			return scnc_sys_sleep;
2385		case SCNC_STOP_USER_LOGOUT:
2386			return scnc_usr_logout;
2387		case SCNC_STOP_USER_SWITCH:
2388			return scnc_usr_switch;
2389		case SCNC_STOP_SOCK_DISCONNECT:
2390		case SCNC_STOP_SOCK_DISCONNECT_NO_CLIENT:
2391			return scnc_sock_disco;
2392		case SCNC_STOP_PLUGIN_CHANGE:
2393			return scnc_plugin_chg;
2394		case SCNC_STOP_APP_REMOVED:
2395			return scnc_app_rem;
2396		case SCNC_STOP_USER_REQ:
2397		case SCNC_STOP_USER_REQ_NO_CLIENT:
2398			return scnc_usr_req;
2399		case SCNC_STOP_SERV_DISPOSE:
2400			return scnc_serv_disp;
2401		case SCNC_STOP_TERM_ALL:
2402			return scnc_term_all;
2403	}
2404	return CONSTSTR(NULL);
2405}
2406
2407const char *
2408ppp_error_to_string (u_int32_t native_ppp_error)
2409{
2410    switch (native_ppp_error) {
2411        case EXIT_FATAL_ERROR:
2412            return ppp_fatal;
2413        case EXIT_OPTION_ERROR:
2414            return ppp_option;
2415        case EXIT_NOT_ROOT:
2416            return ppp_not_root;
2417        case EXIT_NO_KERNEL_SUPPORT:
2418            return ppp_no_kern;
2419        case EXIT_USER_REQUEST:
2420            return ppp_user_req;
2421        case EXIT_LOCK_FAILED:
2422            return ppp_lock_fail;
2423        case EXIT_OPEN_FAILED:
2424            return ppp_open_fail;
2425        case EXIT_CONNECT_FAILED:
2426            return ppp_conn_fail;
2427        case EXIT_PTYCMD_FAILED:
2428            return ppp_pty_fail;
2429        case EXIT_NEGOTIATION_FAILED:
2430            return ppp_nego_fail;
2431        case EXIT_PEER_AUTH_FAILED:
2432            return ppp_peer_auth_fail;
2433        case EXIT_IDLE_TIMEOUT:
2434            return ppp_idle_tmo;
2435        case EXIT_CONNECT_TIME:
2436            return ppp_sess_tmo;
2437        case EXIT_CALLBACK:
2438            return ppp_callback;
2439        case EXIT_PEER_DEAD:
2440            return ppp_peer_dead;
2441        case EXIT_HANGUP:
2442            return ppp_disco_by_dev;
2443        case EXIT_LOOPBACK:
2444            return ppp_loopback;
2445        case EXIT_INIT_FAILED:
2446            return ppp_init_fail;
2447        case EXIT_AUTH_TOPEER_FAILED:
2448            return ppp_auth_fail;
2449        case EXIT_TERMINAL_FAILED:
2450            return ppp_term_fail;
2451        case EXIT_DEVICE_ERROR:
2452            return ppp_dev_err;
2453        case EXIT_PEER_NOT_AUTHORIZED:
2454            return ppp_peer_unauth;
2455        case EXIT_CNID_AUTH_FAILED:
2456            return ppp_cnid_auth_fail;
2457        case EXIT_PEER_UNREACHABLE:
2458            return ppp_peer_unreach;
2459    }
2460
2461    return CONSTSTR(NULL);
2462}
2463
2464const char *
2465ppp_dev_error_to_string (u_int16_t subtype, u_int32_t native_dev_error)
2466{
2467    // override with a more specific error
2468    if (native_dev_error) {
2469        switch (subtype) {
2470            case PPP_TYPE_L2TP:
2471                switch (native_dev_error) {
2472                    case EXIT_L2TP_NOSERVER:
2473                        return ppp_dev_no_srvr;
2474                    case EXIT_L2TP_NOANSWER:
2475                        return ppp_dev_no_ans;
2476                    case EXIT_L2TP_PROTOCOLERROR:
2477                        return ppp_dev_prot_err;
2478                    case EXIT_L2TP_NETWORKCHANGED:
2479                        return ppp_dev_net_chg;
2480                    case EXIT_L2TP_NOSHAREDSECRET:
2481                        return ppp_dev_psk;
2482                    case EXIT_L2TP_NOCERTIFICATE:
2483                        return ppp_dev_cert;
2484                }
2485                break;
2486
2487            case PPP_TYPE_PPTP:
2488                switch (native_dev_error) {
2489                    case EXIT_PPTP_NOSERVER:
2490                        return ppp_dev_no_srvr;
2491                    case EXIT_PPTP_NOANSWER:
2492                        return ppp_dev_no_ans;
2493                    case EXIT_PPTP_PROTOCOLERROR:
2494                        return ppp_dev_prot_err;
2495                    case EXIT_PPTP_NETWORKCHANGED:
2496                        return ppp_dev_net_chg;
2497                }
2498                break;
2499
2500            case PPP_TYPE_SERIAL:
2501                switch (native_dev_error) {
2502                    case EXIT_PPPSERIAL_NOCARRIER:
2503                        return ppp_dev_no_car;
2504                    case EXIT_PPPSERIAL_NONUMBER:
2505                        return ppp_dev_no_num;
2506                    case EXIT_PPPSERIAL_BADSCRIPT:
2507                        return ppp_dev_bad_script;
2508                    case EXIT_PPPSERIAL_BUSY:
2509                        return ppp_dev_busy;
2510                    case EXIT_PPPSERIAL_NODIALTONE:
2511                        return ppp_dev_no_dial;
2512                    case EXIT_PPPSERIAL_ERROR:
2513                        return ppp_dev_modem_err;
2514                    case EXIT_PPPSERIAL_NOANSWER:
2515                        return ppp_dev_no_ans;
2516                    case EXIT_PPPSERIAL_HANGUP:
2517                        return ppp_dev_hang;
2518                }
2519                break;
2520
2521            case PPP_TYPE_PPPoE:
2522                switch (native_dev_error) {
2523                    case EXIT_PPPoE_NOSERVER:
2524                        return ppp_dev_no_srvr;
2525                    case EXIT_PPPoE_NOSERVICE:
2526                        return ppp_dev_no_srvc;
2527                    case EXIT_PPPoE_NOAC:
2528                        return ppp_dev_no_ac;
2529                    case EXIT_PPPoE_NOACSERVICE:
2530                        return ppp_dev_no_ac_srvc;
2531                    case EXIT_PPPoE_CONNREFUSED:
2532                        return ppp_dev_conn_refuse;
2533                }
2534                break;
2535        }
2536    }
2537
2538    return CONSTSTR(NULL);
2539}
2540
2541const char *
2542ipsec_error_to_string (int status)
2543{
2544    switch (status) {
2545        case IPSEC_GENERIC_ERROR:
2546            return ipsec_gen_err;
2547        case IPSEC_NOSERVERADDRESS_ERROR:
2548            return ipsec_no_srvr_addr;
2549        case IPSEC_NOSHAREDSECRET_ERROR:
2550            return ipsec_no_psk;
2551        case IPSEC_NOCERTIFICATE_ERROR:
2552            return ipsec_no_cert;
2553        case IPSEC_RESOLVEADDRESS_ERROR:
2554            return ipsec_dns_err;
2555        case IPSEC_NOLOCALNETWORK_ERROR:
2556            return ipsec_no_local;
2557        case IPSEC_CONFIGURATION_ERROR:
2558            return ipsec_cfg_err;
2559        case IPSEC_RACOONCONTROL_ERROR:
2560            return ipsec_ctrl_err;
2561        case IPSEC_CONNECTION_ERROR:
2562            return ipsec_conn_err;
2563        case IPSEC_NEGOTIATION_ERROR:
2564            return ipsec_nego_err;
2565        case IPSEC_SHAREDSECRET_ERROR:
2566            return ipsec_psk_err;
2567        case IPSEC_SERVER_CERTIFICATE_ERROR:
2568            return ipsec_srvr_cert_err;
2569        case IPSEC_CLIENT_CERTIFICATE_ERROR:
2570            return ipsec_cli_cert_err;
2571        case IPSEC_XAUTH_ERROR:
2572            return ipsec_xauth_err;
2573        case IPSEC_NETWORKCHANGE_ERROR:
2574            return ipsec_net_chg;
2575        case IPSEC_PEERDISCONNECT_ERROR:
2576            return ipsec_peer_disco;
2577        case IPSEC_PEERDEADETECTION_ERROR:
2578            return ipsec_peer_dead;
2579        case IPSEC_EDGE_ACTIVATION_ERROR:
2580            return ipsec_edge_err;
2581        case IPSEC_IDLETIMEOUT_ERROR:
2582            return ipsec_idle_tmo;
2583        case IPSEC_CLIENT_CERTIFICATE_PREMATURE:
2584            return ipsec_cli_cert_pre;
2585        case IPSEC_CLIENT_CERTIFICATE_EXPIRED:
2586            return ipsec_cli_cert_exp;
2587        case IPSEC_SERVER_CERTIFICATE_PREMATURE:
2588            return ipsec_srvr_cert_pre;
2589        case IPSEC_SERVER_CERTIFICATE_EXPIRED:
2590            return ipsec_srvr_cert_exp;
2591        case IPSEC_SERVER_CERTIFICATE_INVALID_ID:
2592            return ipsec_srvr_cert_id;
2593    }
2594
2595    return CONSTSTR(NULL);
2596}
2597
2598const char *
2599vpn_error_to_string (u_int32_t status)
2600{
2601    switch (status) {
2602		case VPN_GENERIC_ERROR:
2603			return vpn_gen_err;
2604		case VPN_NOSERVERADDRESS_ERROR:
2605			return vpn_no_srvr_addr;
2606		case VPN_NOCERTIFICATE_ERROR:
2607			return vpn_no_cert;
2608		case VPN_RESOLVEADDRESS_ERROR:
2609			return vpn_dns_err;
2610		case VPN_NOLOCALNETWORK_ERROR:
2611			return vpn_no_local;
2612		case VPN_CONFIGURATION_ERROR:
2613			return vpn_cfg_err;
2614		case VPN_CONTROL_ERROR:
2615			return vpn_ctrl_err;
2616		case VPN_CONNECTION_ERROR:
2617			return vpn_conn_err;
2618		case VPN_NETWORKCHANGE_ERROR:
2619			return vpn_net_chg;
2620		case VPN_PEERDISCONNECT_ERROR:
2621			return vpn_peer_disco;
2622		case VPN_PEERDEADETECTION_ERROR:
2623			return vpn_peer_dead;
2624		case VPN_PEERNOTRESPONDING_ERROR:
2625			return vpn_peer_unresp;
2626		case VPN_NEGOTIATION_ERROR:
2627			return vpn_nego_err;
2628		case VPN_XAUTH_ERROR:
2629			return vpn_xauth_err;
2630		case VPN_EDGE_ACTIVATION_ERROR:
2631			return vpn_edge_err;
2632		case VPN_IDLETIMEOUT_ERROR:
2633			return vpn_idle_tmo;
2634		case VPN_ADDRESSINVALID_ERROR:
2635			return vpn_addr_invalid;
2636		case VPN_APPREQUIRED_ERROR:
2637			return vpn_ap_req;
2638		case VPN_CLIENT_CERTIFICATE_PREMATURE:
2639			return vpn_cli_cert_pre;
2640		case VPN_CLIENT_CERTIFICATE_EXPIRED:
2641			return vpn_cli_cert_exp;
2642		case VPN_SERVER_CERTIFICATE_PREMATURE:
2643			return vpn_srvr_cert_pre;
2644		case VPN_SERVER_CERTIFICATE_EXPIRED:
2645			return vpn_srvr_cert_exp;
2646		case VPN_SERVER_CERTIFICATE_INVALID_ID:
2647			return vpn_srvr_cert_id;
2648		case VPN_PLUGIN_UPDATE_REQUIRED:
2649			return vpn_plugin_upd;
2650		case VPN_PLUGIN_DISABLED:
2651			return vpn_plugin_dis;
2652	}
2653
2654    return CONSTSTR(NULL);
2655}
2656
2657/* -----------------------------------------------------------------------------
2658 cleanup dynamic store for serv->serviceID.
2659 ----------------------------------------------------------------------------- */
2660static void
2661removekeys( void *key, const void *value, void *context)
2662{
2663    Boolean ret;
2664
2665    ret = SCDynamicStoreRemoveValue((SCDynamicStoreRef)context, (CFStringRef)key);
2666    if (!ret)
2667        SCLog(TRUE, LOG_ERR, CFSTR("PPP Controller: removekeys SCDynamicStoreRemoveValue fails to remove key %@."), key);
2668}
2669
2670void
2671cleanup_dynamicstore(void *serv)
2672{
2673    CFDictionaryRef     entities = NULL;
2674    CFMutableArrayRef   patterns = NULL;
2675    CFStringRef         pattern = NULL;
2676
2677    /* clean up dynamic store */
2678    pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, ((struct service*)serv)->serviceID, kSCCompAnyRegex);
2679    if (pattern == NULL)
2680        return;
2681    patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2682    if (patterns == NULL)
2683        goto fail;
2684    CFArrayAppendValue(patterns, pattern);
2685    entities = SCDynamicStoreCopyMultiple(gDynamicStore, NULL, patterns);
2686    if (entities)
2687        CFDictionaryApplyFunction(entities, (CFDictionaryApplierFunction)removekeys, (void*)gDynamicStore);
2688
2689fail:
2690    my_CFRelease((void *)&pattern);
2691    my_CFRelease((void *)&patterns);
2692    my_CFRelease((void *)&entities);
2693}
2694
2695/* -----------------------------------------------------------------------------
2696 Pass in the optional exceptionServiceID to find the primary interface excluding
2697 the specified service; if the exceptionServiceID is primary, find the next active
2698 service interface based on NWI order.
2699
2700 If NULL is passed for exceptionServiceID, find the true primary interface.
2701 ----------------------------------------------------------------------------- */
2702CFStringRef copy_primary_interface_name(CFStringRef exceptionServiceID)
2703{
2704    CFStringRef		interfaceName = NULL, string = NULL, key = NULL, serviceID = NULL;
2705    CFDictionaryRef dict = NULL;
2706    Boolean			mustSearchNWIOrder = FALSE;
2707
2708    key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
2709    if (key) {
2710        dict = SCDynamicStoreCopyValue(gDynamicStore, key);
2711        CFRelease(key);
2712        if (isDictionary(dict)) {
2713            string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
2714            if (isString(string)) {
2715                serviceID = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryService);
2716                if (serviceID && my_CFEqual(serviceID, exceptionServiceID)) {
2717                    mustSearchNWIOrder = TRUE;
2718                } else {
2719                    // The interface is not the exception, so allow
2720                    interfaceName = CFStringCreateCopy(NULL, string);
2721                }
2722            }
2723            CFRelease(dict);
2724        }
2725    }
2726
2727    if (interfaceName == NULL && mustSearchNWIOrder && exceptionServiceID != NULL) {
2728        CFStringRef exceptionInterfaceName = copy_interface_name(exceptionServiceID);
2729        nwi_state_t nwi_state = nwi_state_copy();
2730        if (exceptionInterfaceName && nwi_state) {
2731            for (nwi_ifstate_t interface = nwi_state_get_first_ifstate(nwi_state, AF_INET); interface != NULL; interface = nwi_ifstate_get_next(interface, AF_INET)) {
2732                char *nwi_interface_name = nwi_ifstate_get_ifname(interface);
2733                CFStringRef nwiInterfaceName = CFStringCreateWithCString(kCFAllocatorDefault, nwi_interface_name, kCFStringEncodingASCII);
2734                if (nwiInterfaceName && !my_CFEqual(nwiInterfaceName, exceptionInterfaceName)) {
2735                    nwi_ifstate_flags flags = nwi_ifstate_get_flags(interface);
2736                    if ((flags & NWI_IFSTATE_FLAGS_HAS_IPV4) && (flags & NWI_IFSTATE_FLAGS_HAS_DNS)) {
2737                        interfaceName = my_CFRetain(nwiInterfaceName);
2738                    }
2739                }
2740                my_CFRelease(&nwiInterfaceName);
2741
2742                // If we found the desired interface, exit now
2743                if (interfaceName != NULL) {
2744                    break;
2745                }
2746            }
2747        }
2748        my_CFRelease(&exceptionInterfaceName);
2749        nwi_state_release(nwi_state);
2750    }
2751
2752    return interfaceName;
2753}
2754
2755/* -----------------------------------------------------------------------------
2756 copy the string separatedy by / at index
2757 ----------------------------------------------------------------------------- */
2758static
2759CFStringRef copy_str_at_index(CFStringRef key, int index)
2760{
2761
2762    CFArrayRef	components;
2763    CFStringRef foundstr = NULL;
2764
2765    components = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
2766    if (CFArrayGetCount(components) == 5) {
2767        if ((foundstr = CFArrayGetValueAtIndex(components, index))){
2768            CFRetain(foundstr);
2769        }
2770    }
2771    CFRelease(components);
2772    return foundstr;
2773}
2774
2775/* -----------------------------------------------------------------------------
2776 ----------------------------------------------------------------------------- */
2777CFStringRef copy_service_id_for_interface(CFStringRef interfaceName)
2778{
2779    CFDictionaryRef     dict = NULL;
2780    CFStringRef         pattern = NULL;
2781    CFMutableArrayRef   patterns = NULL;
2782    CFStringRef         *keys = NULL;
2783    CFDictionaryRef     *values = NULL;
2784    CFIndex             count = 0;
2785    CFIndex             i = 0;
2786    CFStringRef         serviceID = NULL;
2787
2788    if (!isString(interfaceName)) {
2789        goto done;
2790    }
2791
2792    patterns = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2793    pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
2794                                                          kSCDynamicStoreDomainState,
2795                                                          kSCCompAnyRegex,
2796                                                          kSCEntNetIPv4);
2797
2798    if (patterns == NULL || pattern == NULL)
2799        goto done;
2800    CFArrayAppendValue(patterns, pattern);
2801
2802    dict = SCDynamicStoreCopyMultiple(gDynamicStore, NULL, patterns);
2803    count = CFDictionaryGetCount(dict);
2804
2805    keys = calloc(count, sizeof(CFStringRef));
2806    values = calloc(count, sizeof(CFDictionaryRef));
2807    if (keys == NULL || values == NULL)
2808        goto done;
2809    CFDictionaryGetKeysAndValues(dict, (const void**)keys, (const void**)values);
2810
2811    for (i=0; i < count; i++) {
2812        CFDictionaryRef ipv4Dict = NULL;
2813        CFStringRef     ipv4Key = NULL;
2814
2815        ipv4Key  = keys[i];
2816        ipv4Dict = values[i];
2817
2818        if (!isString(ipv4Key) || !isDictionary(ipv4Dict)) {
2819            continue;
2820        }
2821
2822        /* Match interface name here */
2823        if (my_CFEqual(CFDictionaryGetValue(ipv4Dict, kSCPropInterfaceName), interfaceName)) {
2824            if ((CFStringHasPrefix(ipv4Key, kSCDynamicStoreDomainState)) && (CFStringHasSuffix(ipv4Key, kSCEntNetIPv4))) {
2825                /* Copy Service ID */
2826                serviceID = copy_str_at_index(ipv4Key, 3);
2827            }
2828            break;
2829        }
2830    }
2831
2832done:
2833    my_CFRelease(&pattern);
2834    my_CFRelease(&patterns);
2835    my_CFRelease(&dict);
2836    if (keys) {
2837        free(keys);
2838    }
2839    if (values) {
2840        free(values);
2841    }
2842
2843    return serviceID;
2844}
2845
2846/* -----------------------------------------------------------------------------
2847 ----------------------------------------------------------------------------- */
2848CFStringRef copy_interface_type(CFStringRef serviceID)
2849{
2850	CFDictionaryRef interface_dict = NULL;
2851	CFStringRef interface_key = NULL;
2852	CFStringRef hardware = NULL;
2853	CFStringRef interface_type = NULL;
2854
2855	if (!isString(serviceID)) {
2856		goto done;
2857	}
2858
2859	interface_key = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
2860                                                                kSCDynamicStoreDomainSetup,
2861                                                                serviceID,
2862                                                                kSCEntNetInterface);
2863
2864	interface_dict = SCDynamicStoreCopyValue(gDynamicStore, interface_key);
2865	if (!isDictionary(interface_dict)) {
2866		goto done;
2867	}
2868
2869	hardware = CFDictionaryGetValue(interface_dict, kSCPropNetInterfaceHardware);
2870
2871	if (isString(hardware)) {
2872        if (my_CFEqual(hardware, kSCEntNetAirPort)) {
2873            interface_type = CFRetain(kSCValNetVPNOnDemandRuleInterfaceTypeMatchWiFi);
2874        } else if (my_CFEqual(hardware, kSCEntNetEthernet)) {
2875            interface_type = CFRetain(kSCValNetVPNOnDemandRuleInterfaceTypeMatchEthernet);
2876        }
2877#if TARGET_OS_IPHONE
2878        else if (my_CFEqual(hardware, kSCEntNetCommCenter)) {
2879            interface_type = CFRetain(kSCValNetVPNOnDemandRuleInterfaceTypeMatchCellular);
2880        }
2881#endif
2882	}
2883
2884done:
2885    my_CFRelease(&interface_key);
2886    my_CFRelease(&interface_dict);
2887
2888	return interface_type;
2889}
2890
2891/* -----------------------------------------------------------------------------
2892 ----------------------------------------------------------------------------- */
2893CFDictionaryRef copy_dns_dict(CFStringRef serviceID)
2894{
2895    CFStringRef     dnsKey = NULL;
2896    CFDictionaryRef dnsDict = NULL;
2897
2898    if (!isString(serviceID)) {
2899		goto done;
2900	}
2901
2902    dnsKey = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
2903                                                         kSCDynamicStoreDomainState,
2904                                                         serviceID,
2905                                                         kSCEntNetDNS);
2906    if (dnsKey == NULL) {
2907        goto done;
2908    }
2909
2910    dnsDict = SCDynamicStoreCopyValue(gDynamicStore, dnsKey);
2911    if (dnsDict == NULL) {
2912        goto done;
2913    }
2914
2915done:
2916	my_CFRelease(&dnsKey);
2917
2918	return dnsDict;
2919}
2920
2921/* -----------------------------------------------------------------------------
2922 ----------------------------------------------------------------------------- */
2923CFStringRef copy_interface_name(CFStringRef serviceID)
2924{
2925    CFStringRef		interfaceName = NULL;
2926    CFStringRef     ipv4Key = NULL;
2927    CFDictionaryRef ipv4Dict = NULL;
2928
2929    if (!isString(serviceID)) {
2930        goto done;
2931    }
2932
2933    ipv4Key = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
2934                                                         kSCDynamicStoreDomainState,
2935                                                         serviceID,
2936                                                         kSCEntNetIPv4);
2937    if (ipv4Key == NULL) {
2938        goto done;
2939    }
2940
2941    ipv4Dict = SCDynamicStoreCopyValue(gDynamicStore, ipv4Key);
2942    if (ipv4Dict == NULL) {
2943        goto done;
2944    }
2945
2946    interfaceName = CFDictionaryGetValue(ipv4Dict, kSCPropInterfaceName);
2947    if (interfaceName) {
2948        interfaceName = CFStringCreateCopy(kCFAllocatorDefault, interfaceName);
2949    }
2950
2951done:
2952    my_CFRelease(&ipv4Key);
2953    my_CFRelease(&ipv4Dict);
2954
2955    return interfaceName;
2956}
2957
2958/* -----------------------------------------------------------------------------
2959 ----------------------------------------------------------------------------- */
2960CFArrayRef
2961copy_service_order(void)
2962{
2963	CFDictionaryRef	ip_dict = NULL;
2964	CFStringRef		key;
2965	CFArrayRef		serviceorder = NULL;
2966
2967	key = CREATEGLOBALSETUP(kSCEntNetIPv4);
2968	if (key) {
2969		ip_dict = (CFDictionaryRef)SCDynamicStoreCopyValue(gDynamicStore, key);
2970		if (ip_dict) {
2971			serviceorder = CFDictionaryGetValue(ip_dict, kSCPropNetServiceOrder);
2972			if (serviceorder) {
2973				CFRetain(serviceorder);
2974			}
2975			CFRelease(ip_dict);
2976		}
2977		CFRelease(key);
2978	}
2979
2980	return serviceorder;
2981}
2982