]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetwork.c
0d3517298cf1f3ca423d2bfe91b16e4a9a389aa3
[apple/configd.git] / SystemConfiguration.fproj / SCNetwork.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 /*
24 * Modification History
25 *
26 * June 10, 2001 Allan Nathanson <ajn@apple.com>
27 * - updated to use service-based "State:" information
28 *
29 * June 1, 2001 Allan Nathanson <ajn@apple.com>
30 * - public API conversion
31 *
32 * January 30, 2001 Allan Nathanson <ajn@apple.com>
33 * - initial revision
34 */
35
36 #include <SystemConfiguration/SystemConfiguration.h>
37 #include <SystemConfiguration/SCPrivate.h>
38 #include <SystemConfiguration/SCValidation.h>
39
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <arpa/nameser.h>
43 #include <netdb.h>
44 #include <resolv.h>
45 #include <unistd.h>
46 #include <sys/ioctl.h>
47 #include <sys/socket.h>
48 #include <net/if.h>
49
50 #include "ppp.h"
51
52 static int
53 inet_atonCF(CFStringRef cfStr, struct in_addr *addr)
54 {
55 char cStr[sizeof("255.255.255.255")];
56
57 if (!CFStringGetCString(cfStr, cStr, sizeof(cStr), kCFStringEncodingMacRoman)) {
58 return 0;
59 }
60
61 return inet_aton(cStr, addr);
62 }
63
64
65 /*
66 * Function: parse_component
67 * Purpose:
68 * Given a string 'key' and a string prefix 'prefix',
69 * return the next component in the slash '/' separated
70 * key.
71 *
72 * Examples:
73 * 1. key = "a/b/c" prefix = "a/"
74 * returns "b"
75 * 2. key = "a/b/c" prefix = "a/b/"
76 * returns "c"
77 */
78 static CFStringRef
79 parse_component(CFStringRef key, CFStringRef prefix)
80 {
81 CFMutableStringRef comp;
82 CFRange range;
83
84 if (CFStringHasPrefix(key, prefix) == FALSE) {
85 return NULL;
86 }
87 comp = CFStringCreateMutableCopy(NULL, 0, key);
88 CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix)));
89 range = CFStringFind(comp, CFSTR("/"), 0);
90 if (range.location == kCFNotFound) {
91 return comp;
92 }
93 range.length = CFStringGetLength(comp) - range.location;
94 CFStringDelete(comp, range);
95 return comp;
96 }
97
98
99 typedef struct {
100 CFMutableDictionaryRef aDict; /* active services */
101 CFStringRef aPrefix; /* prefix for active services */
102 CFMutableDictionaryRef cDict; /* configured services */
103 CFStringRef cPrefix; /* prefix for configured services */
104 CFMutableDictionaryRef iDict; /* active interfaces */
105 CFStringRef iPrefix; /* prefix for active interfaces */
106 CFMutableArrayRef order; /* service order */
107 } initContext, *initContextRef;
108
109
110 static void
111 collectInfo(const void *key, const void *value, void *context)
112 {
113 initContextRef info = (initContextRef)context;
114 CFStringRef interface;
115 CFStringRef interfaceKey;
116 CFStringRef service;
117 CFStringRef serviceKey;
118
119 if (!isA_CFString(key) || !isA_CFDictionary(value)) {
120 return;
121 }
122
123 service = parse_component((CFStringRef)key, info->cPrefix);
124 if (service) {
125 serviceKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
126 kSCDynamicStoreDomainSetup,
127 service,
128 kSCEntNetIPv4);
129 if (CFEqual((CFStringRef)key, serviceKey)) {
130 CFMutableDictionaryRef dict;
131
132 dict = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value);
133 CFDictionaryAddValue(info->cDict, service, dict);
134 CFRelease(dict);
135 }
136 CFRelease(serviceKey);
137
138 if (!CFArrayContainsValue(info->order, CFRangeMake(0, CFArrayGetCount(info->order)), service)) {
139 CFArrayAppendValue(info->order, service);
140 }
141
142 CFRelease(service);
143 return;
144 }
145
146 service = parse_component((CFStringRef)key, info->aPrefix);
147 if (service) {
148 serviceKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
149 kSCDynamicStoreDomainState,
150 service,
151 kSCEntNetIPv4);
152 if (CFEqual((CFStringRef)key, serviceKey)) {
153 CFMutableDictionaryRef dict;
154
155 dict = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value);
156 CFDictionaryAddValue(info->aDict, service, dict);
157 CFRelease(dict);
158 }
159 CFRelease(serviceKey);
160
161 if (!CFArrayContainsValue(info->order, CFRangeMake(0, CFArrayGetCount(info->order)), service)) {
162 CFArrayAppendValue(info->order, service);
163 }
164
165 CFRelease(service);
166 return;
167 }
168
169 interface = parse_component((CFStringRef)key, info->iPrefix);
170 if (interface) {
171 interfaceKey = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
172 kSCDynamicStoreDomainState,
173 interface,
174 kSCEntNetIPv4);
175 if (CFEqual((CFStringRef)key, interfaceKey)) {
176 CFMutableDictionaryRef dict;
177
178 dict = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)value);
179 CFDictionaryAddValue(info->iDict, interface, dict);
180 CFRelease(dict);
181 }
182 CFRelease(interfaceKey);
183 CFRelease(interface);
184 return;
185 }
186
187 return;
188 }
189
190
191 static void
192 collectExtraInfo(const void *key, const void *value, void *context)
193 {
194 CFStringRef interfaceKey;
195 initContextRef info = (initContextRef)context;
196 CFMutableDictionaryRef dict;
197 Boolean match;
198 CFStringRef pppKey;
199 CFStringRef service;
200
201 if (!isA_CFString(key) || !isA_CFDictionary(value)) {
202 return;
203 }
204
205 service = parse_component((CFStringRef)key, info->cPrefix);
206 if (!service) {
207 /* this key/value pair contains supplemental information */
208 return;
209 }
210
211 dict = (CFMutableDictionaryRef)CFDictionaryGetValue(info->cDict, service);
212 if (!dict) {
213 /* we don't have any IPv4 information for this service */
214 goto done;
215 }
216
217 interfaceKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
218 kSCDynamicStoreDomainSetup,
219 service,
220 kSCEntNetInterface);
221 match = CFEqual((CFStringRef)key, interfaceKey);
222 CFRelease(interfaceKey);
223 if (match) {
224 CFStringRef interface;
225
226 interface = CFDictionaryGetValue((CFDictionaryRef)value,
227 kSCPropNetInterfaceType);
228 if (isA_CFString(interface)) {
229 /* if "InterfaceType" available */
230 CFDictionaryAddValue(dict, kSCPropNetInterfaceType, interface);
231 CFDictionarySetValue(info->cDict, service, dict);
232 }
233 goto done;
234 }
235
236 pppKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
237 kSCDynamicStoreDomainSetup,
238 service,
239 kSCEntNetPPP);
240 match = CFEqual((CFStringRef)key, pppKey);
241 CFRelease(pppKey);
242 if (match) {
243 CFNumberRef dialOnDemand;
244
245 dialOnDemand = CFDictionaryGetValue((CFDictionaryRef)value,
246 kSCPropNetPPPDialOnDemand);
247 if (isA_CFNumber(dialOnDemand)) {
248 /* if "DialOnDemand" information not available */
249 CFDictionaryAddValue(dict, kSCPropNetPPPDialOnDemand, dialOnDemand);
250 CFDictionarySetValue(info->cDict, service, dict);
251 }
252 goto done;
253 }
254
255 done :
256
257 CFRelease(service);
258 return;
259 }
260
261
262 static void
263 removeKnownAddresses(const void *key, const void *value, void *context)
264 {
265 CFMutableDictionaryRef ifDict;
266 CFStringRef ifName;
267 CFMutableDictionaryRef interfaces = (CFMutableDictionaryRef)context;
268 CFMutableDictionaryRef serviceDict = (CFMutableDictionaryRef)value;
269 Boolean updated = FALSE;
270
271 CFIndex i;
272 CFArrayRef iAddrs;
273 CFArrayRef iDests;
274 CFArrayRef iMasks;
275 CFIndex n;
276 CFMutableArrayRef nAddrs = NULL;
277 CFMutableArrayRef nDests = NULL;
278 CFMutableArrayRef nMasks = NULL;
279 CFIndex s;
280 CFArrayRef sAddrs;
281 CFArrayRef sDests;
282 CFArrayRef sMasks;
283
284 ifName = CFDictionaryGetValue(serviceDict, kSCPropInterfaceName);
285 if (!ifName) {
286 /* if no "InterfaceName" for this service */
287 return;
288 }
289
290 ifDict = (CFMutableDictionaryRef)CFDictionaryGetValue(interfaces, ifName);
291 if (!ifDict) {
292 /* if the indicated interface is not active */
293 return;
294 }
295
296 sAddrs = isA_CFArray(CFDictionaryGetValue(serviceDict,
297 kSCPropNetIPv4Addresses));
298 sDests = isA_CFArray(CFDictionaryGetValue(serviceDict,
299 kSCPropNetIPv4DestAddresses));
300 sMasks = isA_CFArray(CFDictionaryGetValue(serviceDict,
301 kSCPropNetIPv4SubnetMasks));
302
303 if (!sAddrs || ((n = CFArrayGetCount(sAddrs)) == 0)) {
304 /* if no addresses */
305 return;
306 }
307
308 if (((sMasks == NULL) && (sDests == NULL)) ||
309 ((sMasks != NULL) && (sDests != NULL))) {
310 /*
311 * sorry, we expect to have "SubnetMasks" or
312 * "DestAddresses" (not both).
313 */
314 return;
315 }
316
317 if (sMasks && (n != CFArrayGetCount(sMasks))) {
318 /* if we don't like the "SubnetMasks" */
319 return;
320 }
321
322 if (sDests && (n != CFArrayGetCount(sDests))) {
323 /* if we don't like the "DestAddresses" */
324 return;
325 }
326
327 iAddrs = isA_CFArray(CFDictionaryGetValue(ifDict,
328 kSCPropNetIPv4Addresses));
329 iDests = isA_CFArray(CFDictionaryGetValue(ifDict,
330 kSCPropNetIPv4DestAddresses));
331 iMasks = isA_CFArray(CFDictionaryGetValue(ifDict,
332 kSCPropNetIPv4SubnetMasks));
333
334 if (((iMasks == NULL) && (iDests == NULL)) ||
335 ((iMasks != NULL) && (iDests != NULL))) {
336 /*
337 * sorry, we expect to have "SubnetMasks" or
338 * "DestAddresses" (not both).
339 */
340 return;
341 }
342
343 if (!iAddrs || ((i = CFArrayGetCount(iAddrs)) == 0)) {
344 /* if no addresses */
345 return;
346 }
347
348 if (iMasks && (i != CFArrayGetCount(iMasks))) {
349 /* if we don't like the "SubnetMasks" */
350 return;
351 }
352
353 if (iDests && (i != CFArrayGetCount(iDests))) {
354 /* if we don't like the "DestAddresses" */
355 return;
356 }
357
358 if (((sMasks == NULL) && (iMasks != NULL)) ||
359 ((sDests == NULL) && (iDests != NULL))) {
360 /* if our addressing schemes are in conflict */
361 return;
362 }
363
364 nAddrs = CFArrayCreateMutableCopy(NULL, 0, iAddrs);
365 if (iMasks) nMasks = CFArrayCreateMutableCopy(NULL, 0, iMasks);
366 if (iDests) nDests = CFArrayCreateMutableCopy(NULL, 0, iDests);
367 for (s=0; s<n; s++) {
368 i = CFArrayGetCount(nAddrs);
369 while (--i >= 0) {
370 if (sMasks &&
371 CFEqual(CFArrayGetValueAtIndex(sAddrs, s),
372 CFArrayGetValueAtIndex(nAddrs, i)) &&
373 CFEqual(CFArrayGetValueAtIndex(sMasks, s),
374 CFArrayGetValueAtIndex(nMasks, i))
375 ) {
376 /* we have a match */
377 CFArrayRemoveValueAtIndex(nAddrs, i);
378 CFArrayRemoveValueAtIndex(nMasks, i);
379 updated = TRUE;
380 } else if (sDests &&
381 CFEqual(CFArrayGetValueAtIndex(sAddrs, s),
382 CFArrayGetValueAtIndex(nAddrs, i)) &&
383 CFEqual(CFArrayGetValueAtIndex(sDests, s),
384 CFArrayGetValueAtIndex(nDests, i))
385 ) {
386 /* we have a match */
387 CFArrayRemoveValueAtIndex(nAddrs, i);
388 CFArrayRemoveValueAtIndex(nDests, i);
389 updated = TRUE;
390 }
391 }
392 }
393
394 if (updated) {
395 if (nAddrs) {
396 CFDictionarySetValue(ifDict,
397 kSCPropNetIPv4Addresses,
398 nAddrs);
399 }
400 if (nMasks) {
401 CFDictionarySetValue(ifDict,
402 kSCPropNetIPv4SubnetMasks,
403 nMasks);
404 } else {
405 CFDictionarySetValue(ifDict,
406 kSCPropNetIPv4DestAddresses,
407 nDests);
408 }
409 CFDictionarySetValue(interfaces, ifName, ifDict);
410 }
411 CFRelease(nAddrs);
412 if (nMasks) CFRelease(nMasks);
413 if (nDests) CFRelease(nDests);
414
415 return;
416 }
417
418
419 static void
420 addUnknownService(const void *key, const void *value, void *context)
421 {
422 CFArrayRef addrs;
423 CFMutableDictionaryRef ifDict = (CFMutableDictionaryRef)value;
424 initContextRef info = (initContextRef)context;
425 CFStringRef service;
426 CFUUIDRef uuid;
427
428 addrs = CFDictionaryGetValue(ifDict, kSCPropNetIPv4Addresses);
429 if (!addrs || (CFArrayGetCount(addrs) == 0)) {
430 /* if no addresses */
431 return;
432 }
433
434 /* add the "InterfaceName" to the (new/fake) service dictionary */
435 CFDictionaryAddValue(ifDict, kSCPropInterfaceName, (CFStringRef)key);
436
437 /* create a (new/fake) service to hold any remaining addresses */
438 uuid = CFUUIDCreate(NULL);
439 service = CFUUIDCreateString(NULL, uuid);
440 CFDictionaryAddValue(info->aDict, service, ifDict);
441 CFArrayAppendValue(info->order, service);
442 CFRelease(service);
443 CFRelease(uuid);
444
445 return;
446 }
447
448
449 static Boolean
450 getAddresses(CFDictionaryRef iDict,
451 CFIndex *nAddrs,
452 CFArrayRef *addrs,
453 CFArrayRef *masks,
454 CFArrayRef *dests)
455 {
456 *addrs = isA_CFArray(CFDictionaryGetValue(iDict,
457 kSCPropNetIPv4Addresses));
458 *masks = isA_CFArray(CFDictionaryGetValue(iDict,
459 kSCPropNetIPv4SubnetMasks));
460 *dests = isA_CFArray(CFDictionaryGetValue(iDict,
461 kSCPropNetIPv4DestAddresses));
462
463 if ((*addrs == NULL) ||
464 ((*nAddrs = CFArrayGetCount(*addrs)) == 0)) {
465 /* sorry, no addresses */
466 _SCErrorSet(kSCStatusReachabilityUnknown);
467 return FALSE;
468 }
469
470 if (((*masks == NULL) && (*dests == NULL)) ||
471 ((*masks != NULL) && (*dests != NULL))) {
472 /*
473 * sorry, we expect to have "SubnetMasks" or
474 * "DestAddresses" (not both) and the count
475 * must match the number of "Addresses".
476 */
477 _SCErrorSet(kSCStatusReachabilityUnknown);
478 return FALSE;
479 }
480
481 if (*masks && (*nAddrs != CFArrayGetCount(*masks))) {
482 /* if we don't like the netmasks */
483 _SCErrorSet(kSCStatusReachabilityUnknown);
484 return FALSE;
485 }
486
487 if (*dests && (*nAddrs != CFArrayGetCount(*dests))) {
488 /* if we don't like the destaddresses */
489 _SCErrorSet(kSCStatusReachabilityUnknown);
490 return FALSE;
491 }
492
493 return TRUE;
494 }
495
496 static Boolean
497 checkAddress(SCDynamicStoreRef store,
498 const struct sockaddr *address,
499 const int addrlen,
500 CFDictionaryRef config,
501 CFDictionaryRef active,
502 CFArrayRef serviceOrder,
503 struct in_addr *defaultRoute,
504 SCNetworkConnectionFlags *flags)
505 {
506 CFIndex aCnt;
507 CFStringRef aType = NULL;
508 CFDictionaryRef cDict = NULL;
509 CFIndex i;
510 CFStringRef key = NULL;
511 int pppRef = -1;
512 int sc_status = kSCStatusReachabilityUnknown;
513 char *statusMessage = NULL;
514
515 if (!address || !flags) {
516 sc_status = kSCStatusInvalidArgument;
517 goto done;
518 }
519
520 *flags = 0;
521
522 if (address->sa_family == AF_INET) {
523 struct sockaddr_in *sin = (struct sockaddr_in *)address;
524
525 SCLog(_sc_debug, LOG_INFO, CFSTR("checkAddress(%s)"), inet_ntoa(sin->sin_addr));
526
527 /*
528 * Check if the address is on one of the subnets
529 * associated with our active IPv4 interfaces
530 */
531 aCnt = CFArrayGetCount(serviceOrder);
532 for (i=0; i<aCnt; i++) {
533 CFDictionaryRef aDict;
534 CFArrayRef addrs;
535 CFArrayRef dests;
536 CFIndex j;
537 CFArrayRef masks;
538 CFIndex nAddrs = 0;
539
540 key = CFArrayGetValueAtIndex(serviceOrder, i);
541 aDict = CFDictionaryGetValue(active, key);
542
543 if (!aDict ||
544 !getAddresses(aDict, &nAddrs, &addrs, &masks, &dests)) {
545 /* if no addresses to check */
546 continue;
547 }
548
549 for (j=0; j<nAddrs; j++) {
550 struct in_addr ifAddr;
551
552 if (inet_atonCF(CFArrayGetValueAtIndex(addrs, j),
553 &ifAddr) == 0) {
554 /* if Addresses string is invalid */
555 break;
556 }
557
558 if (masks) {
559 struct in_addr ifMask;
560
561 if (inet_atonCF(CFArrayGetValueAtIndex(masks, j),
562 &ifMask) == 0) {
563 /* if SubnetMask string is invalid */
564 break;
565 }
566
567 if ((ntohl(ifAddr.s_addr) & ntohl(ifMask.s_addr)) ==
568 (ntohl(sin->sin_addr.s_addr) & ntohl(ifMask.s_addr))) {
569 /* the requested address is on this subnet */
570 statusMessage = "isReachable (my subnet)";
571 *flags |= kSCNetworkFlagsReachable;
572 goto checkInterface;
573 }
574 } else {
575 struct in_addr destAddr;
576
577 /* check remote address */
578 if (inet_atonCF(CFArrayGetValueAtIndex(dests, j),
579 &destAddr) == 0) {
580 /* if DestAddresses string is invalid */
581 break;
582 }
583
584 /* check local address */
585 if (ntohl(sin->sin_addr.s_addr) == ntohl(ifAddr.s_addr)) {
586 /* the address is our side of the link */
587 statusMessage = "isReachable (my local address)";
588 *flags |= kSCNetworkFlagsReachable;
589 goto checkInterface;
590 }
591
592 if (ntohl(sin->sin_addr.s_addr) == ntohl(destAddr.s_addr)) {
593 /* the address is the other side of the link */
594 statusMessage = "isReachable (my remote address)";
595 *flags |= kSCNetworkFlagsReachable;
596 goto checkInterface;
597 }
598 }
599 }
600 }
601
602 /*
603 * Check if the address is accessible via the "default" route.
604 */
605 for (i=0; i<aCnt; i++) {
606 CFDictionaryRef aDict;
607 CFArrayRef addrs;
608 CFArrayRef dests;
609 CFIndex j;
610 CFArrayRef masks;
611 CFIndex nAddrs = 0;
612
613 key = CFArrayGetValueAtIndex(serviceOrder, i);
614 aDict = CFDictionaryGetValue(active, key);
615
616 if (!sin->sin_addr.s_addr ||
617 !defaultRoute ||
618 !aDict ||
619 !getAddresses(aDict, &nAddrs, &addrs, &masks, &dests)) {
620 /* if no addresses to check */
621 continue;
622 }
623
624 for (j=0; defaultRoute && j<nAddrs; j++) {
625 if (masks) {
626 struct in_addr ifAddr;
627 struct in_addr ifMask;
628
629 if (inet_atonCF(CFArrayGetValueAtIndex(addrs, j),
630 &ifAddr) == 0) {
631 /* if Addresses string is invalid */
632 break;
633 }
634
635 if (inet_atonCF(CFArrayGetValueAtIndex(masks, j),
636 &ifMask) == 0) {
637 /* if SubnetMasks string is invalid */
638 break;
639 }
640
641 if ((ntohl(ifAddr.s_addr) & ntohl(ifMask.s_addr)) ==
642 (ntohl(defaultRoute->s_addr) & ntohl(ifMask.s_addr))) {
643 /* the requested address is on this subnet */
644 statusMessage = "isReachable via default route (my subnet)";
645 *flags |= kSCNetworkFlagsReachable;
646 goto checkInterface;
647 }
648 } else {
649 struct in_addr destAddr;
650
651 /* check remote address */
652 if (inet_atonCF(CFArrayGetValueAtIndex(dests, j),
653 &destAddr) == 0) {
654 /* if DestAddresses string is invalid */
655 break;
656 }
657
658 if (ntohl(destAddr.s_addr) == ntohl(defaultRoute->s_addr)) {
659 /* the address is the other side of the link */
660 statusMessage = "isReachable via default route (my remote address)";
661 *flags |= kSCNetworkFlagsReachable;
662 goto checkInterface;
663 }
664 }
665 }
666 }
667
668 /*
669 * Check the not active (but configured) IPv4 services
670 */
671 for (i=0; i<aCnt; i++) {
672 key = CFArrayGetValueAtIndex(serviceOrder, i);
673
674 if (CFDictionaryContainsKey(active, key)) {
675 /* if this service is active */
676 continue;
677 }
678
679 cDict = CFDictionaryGetValue(config, key);
680 if (!cDict) {
681 /* if no configuration for this service */
682 continue;
683 }
684
685 /*
686 * We have a service which "claims" to be a potential path
687 * off of the system. Check to make sure that this is a
688 * type of PPP link before claiming it's viable.
689 */
690 aType = CFDictionaryGetValue(cDict, kSCPropNetInterfaceType);
691 if (!aType || !CFEqual(aType, kSCValNetInterfaceTypePPP)) {
692 /* if we can't get a connection on this service */
693 sc_status = kSCStatusOK;
694 goto done;
695 }
696
697 statusMessage = "is configured w/dynamic addressing";
698 *flags |= kSCNetworkFlagsTransientConnection;
699 *flags |= kSCNetworkFlagsReachable;
700 *flags |= kSCNetworkFlagsConnectionRequired;
701
702 if (_sc_debug) {
703 SCLog(TRUE, LOG_INFO, CFSTR(" status = %s"), statusMessage);
704 SCLog(TRUE, LOG_INFO, CFSTR(" service id = %@"), key);
705 }
706
707 sc_status = kSCStatusOK;
708 goto done;
709 }
710
711 SCLog(_sc_debug, LOG_INFO, CFSTR(" cannot be reached"));
712 sc_status = kSCStatusOK;
713 goto done;
714
715 } else {
716 /*
717 * if no code for this address family (yet)
718 */
719 SCLog(_sc_verbose, LOG_ERR,
720 CFSTR("checkAddress(): unexpected address family %d"),
721 address->sa_family);
722 sc_status = kSCStatusInvalidArgument;
723 goto done;
724 }
725
726 goto done;
727
728 checkInterface :
729
730 if (_sc_debug) {
731 CFDictionaryRef aDict;
732 CFStringRef interface = NULL;
733
734 /* attempt to get the interface type from the config info */
735 aDict = CFDictionaryGetValue(active, key);
736 if (aDict) {
737 interface = CFDictionaryGetValue(aDict, kSCPropInterfaceName);
738 }
739
740 SCLog(TRUE, LOG_INFO, CFSTR(" status = %s"), statusMessage);
741 SCLog(TRUE, LOG_INFO, CFSTR(" service id = %@"), key);
742 SCLog(TRUE, LOG_INFO, CFSTR(" device = %@"), interface ? interface : CFSTR("?"));
743 }
744
745 sc_status = kSCStatusOK;
746
747 /*
748 * We have an interface which "claims" to be a valid path
749 * off of the system. Check to make sure that this isn't
750 * a dial-on-demand PPP link that isn't connected yet.
751 */
752 {
753 CFNumberRef num;
754 CFDictionaryRef cDict;
755
756 /* attempt to get the interface type from the config info */
757 cDict = CFDictionaryGetValue(config, key);
758 if (cDict) {
759 aType = CFDictionaryGetValue(cDict, kSCPropNetInterfaceType);
760 }
761
762 if (!aType || !CFEqual(aType, kSCValNetInterfaceTypePPP)) {
763 /*
764 * if we don't know the interface type or if
765 * it is not a ppp interface
766 */
767 goto done;
768 }
769
770 num = CFDictionaryGetValue(cDict, kSCPropNetPPPDialOnDemand);
771 if (num) {
772 int dialOnDemand;
773
774 CFNumberGetValue(num, kCFNumberIntType, &dialOnDemand);
775 if (dialOnDemand != 0) {
776 *flags |= kSCNetworkFlagsConnectionAutomatic;
777 }
778
779 }
780 }
781
782 *flags |= kSCNetworkFlagsTransientConnection;
783
784 {
785 u_int32_t pppLink;
786 struct ppp_status *pppLinkStatus;
787 int pppStatus;
788
789 /*
790 * The service ID is available, ask the PPP controller
791 * for the extended status.
792 */
793 pppStatus = PPPInit(&pppRef);
794 if (pppStatus != 0) {
795 SCLog(_sc_debug, LOG_DEBUG, CFSTR(" PPPInit() failed: status=%d"), pppStatus);
796 sc_status = kSCStatusReachabilityUnknown;
797 goto done;
798 }
799
800 pppStatus = PPPGetLinkByServiceID(pppRef, key, &pppLink);
801 if (pppStatus != 0) {
802 SCLog(_sc_debug, LOG_DEBUG, CFSTR(" PPPGetLinkByServiceID() failed: status=%d"), pppStatus);
803 sc_status = kSCStatusReachabilityUnknown;
804 goto done;
805 }
806
807 pppStatus = PPPStatus(pppRef, pppLink, &pppLinkStatus);
808 if (pppStatus != 0) {
809 SCLog(_sc_debug, LOG_DEBUG, CFSTR(" PPPStatus() failed: status=%d"), pppStatus);
810 sc_status = kSCStatusReachabilityUnknown;
811 goto done;
812 }
813 #ifdef DEBUG
814 SCLog(_sc_debug, LOG_DEBUG, CFSTR(" PPP link status = %d"), pppLinkStatus->status);
815 #endif /* DEBUG */
816 switch (pppLinkStatus->status) {
817 case PPP_RUNNING :
818 /* if we're really UP and RUNNING */
819 break;
820 case PPP_ONHOLD :
821 /* if we're effectively UP and RUNNING */
822 break;
823 case PPP_IDLE :
824 /* if we're not connected at all */
825 SCLog(_sc_debug, LOG_INFO, CFSTR(" PPP link idle, dial-on-traffic to connect"));
826 *flags |= kSCNetworkFlagsReachable;
827 *flags |= kSCNetworkFlagsConnectionRequired;
828 sc_status = kSCStatusOK;
829 break;
830 default :
831 /* if we're in the process of [dis]connecting */
832 SCLog(_sc_debug, LOG_INFO, CFSTR(" PPP link, connection in progress"));
833 *flags |= kSCNetworkFlagsReachable;
834 *flags |= kSCNetworkFlagsConnectionRequired;
835 sc_status = kSCStatusOK;
836 break;
837 }
838 CFAllocatorDeallocate(NULL, pppLinkStatus);
839 }
840
841 goto done;
842
843 done :
844
845 if (pppRef != -1) (void) PPPDispose(pppRef);
846
847 if (sc_status != kSCStatusOK) {
848 _SCErrorSet(sc_status);
849 return FALSE;
850 }
851
852 return TRUE;
853 }
854
855
856 static void
857 _CheckReachabilityInit(SCDynamicStoreRef store,
858 CFDictionaryRef *config,
859 CFDictionaryRef *active,
860 CFArrayRef *serviceOrder,
861 struct in_addr **defaultRoute)
862 {
863 CFMutableDictionaryRef activeDict;
864 CFMutableDictionaryRef configDict;
865 initContext context;
866 CFDictionaryRef dict;
867 CFMutableDictionaryRef interfaces;
868 CFMutableArrayRef keys;
869 CFMutableArrayRef orderArray;
870 CFDictionaryRef orderDict;
871 CFStringRef orderKey;
872 CFStringRef pattern;
873 CFMutableArrayRef patterns;
874 CFStringRef routeKey;
875 CFDictionaryRef routeDict;
876
877 configDict = CFDictionaryCreateMutable(NULL,
878 0,
879 &kCFTypeDictionaryKeyCallBacks,
880 &kCFTypeDictionaryValueCallBacks);
881 *config = configDict;
882
883 activeDict = CFDictionaryCreateMutable(NULL,
884 0,
885 &kCFTypeDictionaryKeyCallBacks,
886 &kCFTypeDictionaryValueCallBacks);
887 *active = activeDict;
888
889 orderArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
890 *serviceOrder = orderArray;
891
892 *defaultRoute = NULL;
893
894 interfaces = CFDictionaryCreateMutable(NULL,
895 0,
896 &kCFTypeDictionaryKeyCallBacks,
897 &kCFTypeDictionaryValueCallBacks);
898
899 /*
900 * collect information on the configured services and their
901 * associated interface type.
902 */
903 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
904 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
905
906 /*
907 * Setup:/Network/Global/IPv4 (for the ServiceOrder)
908 */
909 orderKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
910 kSCDynamicStoreDomainSetup,
911 kSCEntNetIPv4);
912 CFArrayAppendValue(keys, orderKey);
913
914 /*
915 * State:/Network/Global/IPv4 (for the DefaultRoute)
916 */
917 routeKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
918 kSCDynamicStoreDomainState,
919 kSCEntNetIPv4);
920 CFArrayAppendValue(keys, routeKey);
921
922 /* Setup: per-service IPv4 info */
923 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
924 kSCDynamicStoreDomainSetup,
925 kSCCompAnyRegex,
926 kSCEntNetIPv4);
927 CFArrayAppendValue(patterns, pattern);
928 CFRelease(pattern);
929
930 /* Setup: per-service Interface info */
931 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
932 kSCDynamicStoreDomainSetup,
933 kSCCompAnyRegex,
934 kSCEntNetInterface);
935 CFArrayAppendValue(patterns, pattern);
936 CFRelease(pattern);
937
938 /* Setup: per-service PPP info */
939 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
940 kSCDynamicStoreDomainSetup,
941 kSCCompAnyRegex,
942 kSCEntNetPPP);
943 CFArrayAppendValue(patterns, pattern);
944 CFRelease(pattern);
945
946 /* State: per-service IPv4 info */
947 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
948 kSCDynamicStoreDomainState,
949 kSCCompAnyRegex,
950 kSCEntNetIPv4);
951 CFArrayAppendValue(patterns, pattern);
952 CFRelease(pattern);
953
954 /* State: per-interface IPv4 info */
955 pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
956 kSCDynamicStoreDomainState,
957 kSCCompAnyRegex,
958 kSCEntNetIPv4);
959 CFArrayAppendValue(patterns, pattern);
960 CFRelease(pattern);
961
962 /* fetch the configuration information */
963 dict = SCDynamicStoreCopyMultiple(store, keys, patterns);
964 CFRelease(keys);
965 CFRelease(patterns);
966 if (!dict) {
967 goto done;
968 }
969
970 /*
971 * get the ServiceOrder key from the global settings.
972 */
973 orderDict = CFDictionaryGetValue(dict, orderKey);
974 if (isA_CFDictionary(orderDict)) {
975 CFArrayRef array;
976
977 /* global settings are available */
978 array = (CFMutableArrayRef)CFDictionaryGetValue(orderDict, kSCPropNetServiceOrder);
979 if (isA_CFArray(array)) {
980 CFArrayAppendArray(orderArray,
981 array,
982 CFRangeMake(0, CFArrayGetCount(array)));
983 }
984 }
985
986 /*
987 * get the DefaultRoute
988 */
989 routeDict = CFDictionaryGetValue(dict, routeKey);
990 if (isA_CFDictionary(routeDict)) {
991 CFStringRef addr;
992
993 /* global state is available, get default route */
994 addr = CFDictionaryGetValue(routeDict, kSCPropNetIPv4Router);
995 if (isA_CFString(addr)) {
996 struct in_addr *route;
997
998 route = CFAllocatorAllocate(NULL, sizeof(struct in_addr), 0);
999 if (inet_atonCF(addr, route) == 0) {
1000 /* if address string is invalid */
1001 CFAllocatorDeallocate(NULL, route);
1002 route = NULL;
1003 } else {
1004 *defaultRoute = route;
1005 }
1006 }
1007 }
1008
1009 /*
1010 * collect the configured services, the active services, and
1011 * the active interfaces.
1012 */
1013 context.cDict = configDict;
1014 context.cPrefix = SCDynamicStoreKeyCreate(NULL,
1015 CFSTR("%@/%@/%@/"),
1016 kSCDynamicStoreDomainSetup,
1017 kSCCompNetwork,
1018 kSCCompService);
1019 context.aDict = activeDict;
1020 context.aPrefix = SCDynamicStoreKeyCreate(NULL,
1021 CFSTR("%@/%@/%@/"),
1022 kSCDynamicStoreDomainState,
1023 kSCCompNetwork,
1024 kSCCompService);
1025 context.iDict = interfaces;
1026 context.iPrefix = SCDynamicStoreKeyCreate(NULL,
1027 CFSTR("%@/%@/%@/"),
1028 kSCDynamicStoreDomainState,
1029 kSCCompNetwork,
1030 kSCCompInterface);
1031 context.order = orderArray;
1032
1033 CFDictionaryApplyFunction(dict, collectInfo, &context);
1034
1035 /*
1036 * add additional information for the configured services
1037 */
1038 CFDictionaryApplyFunction(dict, collectExtraInfo, &context);
1039
1040 /*
1041 * remove any addresses associated with known services
1042 */
1043 CFDictionaryApplyFunction(activeDict, removeKnownAddresses, interfaces);
1044
1045 /*
1046 * create new services for any remaining addresses
1047 */
1048 CFDictionaryApplyFunction(interfaces, addUnknownService, &context);
1049
1050 CFRelease(context.cPrefix);
1051 CFRelease(context.aPrefix);
1052 CFRelease(context.iPrefix);
1053 CFRelease(dict);
1054
1055 done :
1056
1057 CFRelease(interfaces);
1058 CFRelease(orderKey);
1059 CFRelease(routeKey);
1060
1061 #ifdef DEBUG
1062 SCLog(_sc_debug, LOG_NOTICE, CFSTR("config = %@"), *config);
1063 SCLog(_sc_debug, LOG_NOTICE, CFSTR("active = %@"), *active);
1064 SCLog(_sc_debug, LOG_NOTICE, CFSTR("serviceOrder = %@"), *serviceOrder);
1065 SCLog(_sc_debug, LOG_NOTICE, CFSTR("defaultRoute = %s"), *defaultRoute?inet_ntoa(**defaultRoute):"None");
1066 #endif /* DEBUG */
1067 return;
1068 }
1069
1070
1071 static void
1072 _CheckReachabilityFree(CFDictionaryRef config,
1073 CFDictionaryRef active,
1074 CFArrayRef serviceOrder,
1075 struct in_addr *defaultRoute)
1076 {
1077 if (config) CFRelease(config);
1078 if (active) CFRelease(active);
1079 if (serviceOrder) CFRelease(serviceOrder);
1080 if (defaultRoute) CFAllocatorDeallocate(NULL, defaultRoute);
1081 return;
1082 }
1083
1084
1085 Boolean
1086 SCNetworkCheckReachabilityByAddress(const struct sockaddr *address,
1087 const int addrlen,
1088 SCNetworkConnectionFlags *flags)
1089 {
1090 CFDictionaryRef active = NULL;
1091 CFDictionaryRef config = NULL;
1092 struct in_addr *defaultRoute = NULL;
1093 Boolean ok;
1094 CFArrayRef serviceOrder = NULL;
1095 SCDynamicStoreRef store = NULL;
1096
1097 *flags = 0;
1098
1099 /*
1100 * Check if 0.0.0.0
1101 */
1102 if (address->sa_family == AF_INET) {
1103 struct sockaddr_in *sin = (struct sockaddr_in *)address;
1104
1105 if (sin->sin_addr.s_addr == 0) {
1106 SCLog(_sc_debug, LOG_INFO, CFSTR("checkAddress(0.0.0.0)"));
1107 SCLog(_sc_debug, LOG_INFO, CFSTR(" status = isReachable (this host)"));
1108 *flags |= kSCNetworkFlagsReachable;
1109 return TRUE;
1110 }
1111 }
1112
1113 store = SCDynamicStoreCreate(NULL,
1114 CFSTR("SCNetworkCheckReachabilityByAddress"),
1115 NULL,
1116 NULL);
1117 if (!store) {
1118 SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreCreate() failed"));
1119 return FALSE;
1120 }
1121
1122 _CheckReachabilityInit(store, &config, &active, &serviceOrder, &defaultRoute);
1123 ok = checkAddress(store,
1124 address,
1125 addrlen,
1126 config,
1127 active,
1128 serviceOrder,
1129 defaultRoute,
1130 flags);
1131 _CheckReachabilityFree(config, active, serviceOrder, defaultRoute);
1132
1133 CFRelease(store);
1134 return ok;
1135 }
1136
1137
1138 /*
1139 * rankReachability()
1140 * Not reachable == 0
1141 * Connection Required == 1
1142 * Reachable == 2
1143 */
1144 static int
1145 rankReachability(int flags)
1146 {
1147 int rank = 0;
1148
1149 if (flags & kSCNetworkFlagsReachable) rank = 2;
1150 if (flags & kSCNetworkFlagsConnectionRequired) rank = 1;
1151 return rank;
1152 }
1153
1154
1155 Boolean
1156 SCNetworkCheckReachabilityByName(const char *nodename,
1157 SCNetworkConnectionFlags *flags)
1158 {
1159 CFDictionaryRef active = NULL;
1160 CFDictionaryRef config = NULL;
1161 struct in_addr *defaultRoute = NULL;
1162 struct hostent *h;
1163 Boolean haveDNS = FALSE;
1164 int i;
1165 Boolean ok = TRUE;
1166 #ifdef CHECK_IPV6_REACHABILITY
1167 struct addrinfo *res = NULL;
1168 struct addrinfo *resP;
1169 #endif /* CHECK_IPV6_REACHABILITY */
1170 CFArrayRef serviceOrder = NULL;
1171 SCDynamicStoreRef store = NULL;
1172
1173 store = SCDynamicStoreCreate(NULL,
1174 CFSTR("SCNetworkCheckReachabilityByName"),
1175 NULL,
1176 NULL);
1177 if (!store) {
1178 SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreCreate() failed"));
1179 return FALSE;
1180 }
1181
1182 _CheckReachabilityInit(store, &config, &active, &serviceOrder, &defaultRoute);
1183
1184 /*
1185 * We first assume that all of the configured DNS servers
1186 * are available. Since we don't know which name server will
1187 * be consulted to resolve the specified nodename we need to
1188 * check the availability of ALL name servers. We can only
1189 * proceed if we know that our query can be answered.
1190 */
1191
1192 *flags = kSCNetworkFlagsReachable;
1193
1194 res_init();
1195 for (i=0; i<_res.nscount; i++) {
1196 SCNetworkConnectionFlags ns_flags = 0;
1197
1198 if (_res.nsaddr_list[i].sin_addr.s_addr == 0) {
1199 continue;
1200 }
1201
1202 haveDNS = TRUE;
1203
1204 if (_res.nsaddr_list[i].sin_len == 0) {
1205 _res.nsaddr_list[i].sin_len = sizeof(_res.nsaddr_list[i]);
1206 }
1207
1208 ok = checkAddress(store,
1209 (struct sockaddr *)&_res.nsaddr_list[i],
1210 _res.nsaddr_list[i].sin_len,
1211 config,
1212 active,
1213 serviceOrder,
1214 defaultRoute,
1215 &ns_flags);
1216 if (!ok) {
1217 /* not today */
1218 break;
1219 }
1220 if (rankReachability(ns_flags) < rankReachability(*flags)) {
1221 /* return the worst case result */
1222 *flags = ns_flags;
1223 }
1224 }
1225
1226 if (!ok || (rankReachability(*flags) < 2)) {
1227 goto done;
1228 }
1229
1230 SCLog(_sc_debug, LOG_INFO, CFSTR("check DNS for \"%s\""), nodename);
1231
1232 /*
1233 * OK, all of the DNS name servers are available. Let's
1234 * first assume that the requested host is NOT available,
1235 * resolve the nodename, and check its address for
1236 * accessibility. We return the best status available.
1237 */
1238 *flags = 0;
1239
1240 /*
1241 * resolve the nodename into an address
1242 */
1243
1244 #ifdef CHECK_IPV6_REACHABILITY
1245 i = getaddrinfo(nodename, NULL, NULL, &res);
1246 if (i != 0) {
1247 SCLog(_sc_verbose, LOG_ERR,
1248 CFSTR("getaddrinfo() failed: %s"),
1249 gai_strerror(i));
1250 goto done;
1251 }
1252
1253 for (resP=res; resP!=NULL; resP=resP->ai_next) {
1254 SCNetworkConnectionFlags ns_flags = 0;
1255
1256 if (resP->ai_addr->sa_family == AF_INET) {
1257 struct sockaddr_in *sin = (struct sockaddr_in *)resP->ai_addr;
1258
1259 if (sin->sin_addr.s_addr == 0) {
1260 SCLog(_sc_debug, LOG_INFO, CFSTR("checkAddress(0.0.0.0)"));
1261 SCLog(_sc_debug, LOG_INFO, CFSTR(" status = isReachable (this host)"));
1262 *flags |= kSCNetworkFlagsReachable;
1263 break;
1264 }
1265 }
1266
1267 ok = checkAddress(store,
1268 resP->ai_addr,
1269 resP->ai_addrlen,
1270 config,
1271 active,
1272 serviceOrder,
1273 defaultRoute,
1274 &ns_flags);
1275 if (!ok) {
1276 /* not today */
1277 break;
1278 }
1279 if (rankReachability(ns_flags) > rankReachability(*flags)) {
1280 /* return the best case result */
1281 *flags = ns_flags;
1282 if (rankReachability(*flags) == 2) {
1283 /* we're in luck */
1284 break;
1285 }
1286 }
1287 }
1288
1289 if (res) {
1290 goto done;
1291 }
1292
1293 /*
1294 * The getaddrinfo() function call didn't return any addresses. While
1295 * this may be the correct answer we have found that some DNS servers
1296 * may, depending on what has been cached, not return all available
1297 * records when issued a T_ANY query. To accomodate these servers
1298 * we double check by using the gethostbyname() function which uses
1299 * a simple T_A query.
1300 */
1301
1302 #ifdef DEBUG
1303 SCLog(_sc_debug,
1304 LOG_INFO,
1305 CFSTR("getaddrinfo() returned no addresses, try gethostbyname()"));
1306 #endif /* DEBUG */
1307 #endif /* CHECK_IPV6_REACHABILITY */
1308
1309 h = gethostbyname(nodename);
1310 if (h && h->h_length) {
1311 struct in_addr **s = (struct in_addr **)h->h_addr_list;
1312
1313 while (*s) {
1314 SCNetworkConnectionFlags ns_flags = 0;
1315 struct sockaddr_in sa;
1316
1317 bzero(&sa, sizeof(sa));
1318 sa.sin_len = sizeof(sa);
1319 sa.sin_family = AF_INET;
1320 sa.sin_addr = **s;
1321
1322 if (sa.sin_addr.s_addr == 0) {
1323 SCLog(_sc_debug, LOG_INFO, CFSTR("checkAddress(0.0.0.0)"));
1324 SCLog(_sc_debug, LOG_INFO, CFSTR(" status = isReachable (this host)"));
1325 *flags |= kSCNetworkFlagsReachable;
1326 break;
1327 }
1328
1329 ok = checkAddress(store,
1330 (struct sockaddr *)&sa,
1331 sizeof(sa),
1332 config,
1333 active,
1334 serviceOrder,
1335 defaultRoute,
1336 &ns_flags);
1337 if (!ok) {
1338 /* not today */
1339 break;
1340 }
1341 if (rankReachability(ns_flags) > rankReachability(*flags)) {
1342 /* return the best case result */
1343 *flags = ns_flags;
1344 if (rankReachability(*flags) == 2) {
1345 /* we're in luck */
1346 break;
1347 }
1348 }
1349
1350 s++;
1351 }
1352 } else {
1353 char *msg;
1354
1355 switch(h_errno) {
1356 case NETDB_INTERNAL :
1357 msg = strerror(errno);
1358 break;
1359 case HOST_NOT_FOUND :
1360 msg = "Host not found.";
1361 if (!haveDNS) {
1362 /*
1363 * No DNS servers are defined. Set flags based on
1364 * the availability of configured (but not active)
1365 * services.
1366 */
1367 struct sockaddr_in sa;
1368
1369 bzero(&sa, sizeof(sa));
1370 sa.sin_len = sizeof(sa);
1371 sa.sin_family = AF_INET;
1372 sa.sin_addr.s_addr = 0;
1373 ok = checkAddress(store,
1374 (struct sockaddr *)&sa,
1375 sizeof(sa),
1376 config,
1377 active,
1378 serviceOrder,
1379 defaultRoute,
1380 flags);
1381 if (ok &&
1382 (*flags & kSCNetworkFlagsReachable) &&
1383 (*flags & kSCNetworkFlagsConnectionRequired)) {
1384 /*
1385 * We might pick up a set of DNS servers
1386 * from this connection, don't reply with
1387 * "Host not found." just yet.
1388 */
1389 goto done;
1390 }
1391 *flags = 0;
1392 }
1393 break;
1394 case TRY_AGAIN :
1395 msg = "Try again.";
1396 break;
1397 case NO_RECOVERY :
1398 msg = "No recovery.";
1399 break;
1400 case NO_DATA :
1401 msg = "No data available.";
1402 break;
1403 default :
1404 msg = "Unknown";
1405 break;
1406 }
1407 SCLog(_sc_debug, LOG_INFO, CFSTR("gethostbyname() failed: %s"), msg);
1408 }
1409
1410 done :
1411
1412 _CheckReachabilityFree(config, active, serviceOrder, defaultRoute);
1413 if (store) CFRelease(store);
1414 #ifdef CHECK_IPV6_REACHABILITY
1415 if (res) freeaddrinfo(res);
1416 #endif /* CHECK_IPV6_REACHABILITY */
1417
1418 return ok;
1419 }