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#include <stdio.h> 26#include <string.h> 27#include <stdlib.h> 28#include <unistd.h> 29#include <errno.h> 30#include <fcntl.h> 31#include <termios.h> 32#include <signal.h> 33#include <util.h> 34#include <sys/ioctl.h> 35#include <sys/types.h> 36#include <sys/socket.h> 37#include <sys/time.h> 38#include <sys/stat.h> 39#include <sys/param.h> 40#include <sys/wait.h> 41#include <net/if.h> 42#include <netinet/in.h> 43#include <net/if_types.h> 44#include <ifaddrs.h> 45#include <mach-o/dyld.h> 46#include <dirent.h> 47#include <NSSystemDirectories.h> 48#include <mach/mach_time.h> 49#include <SystemConfiguration/SystemConfiguration.h> 50#include <CoreFoundation/CFBundle.h> 51#include <ppp_defs.h> 52#include <ppp_domain.h> 53#include <ppp_msg.h> 54#include <ppp_privmsg.h> 55 56#include "vpnd.h" 57#include "vpnoptions.h" 58#include "cf_utils.h" 59#include "ipsec_utils.h" 60 61 62/* ----------------------------------------------------------------------------- 63 Definitions 64----------------------------------------------------------------------------- */ 65 66#define PPP_NKE_PATH "/System/Library/Extensions/PPP.kext" 67 68 69/* ----------------------------------------------------------------------------- 70 Globals 71----------------------------------------------------------------------------- */ 72 73bool noload = 0; /* don't load the kernel extension */ 74 75 76 77 78/* ----------------------------------------------------------------------------- 79----------------------------------------------------------------------------- */ 80void closeall() 81{ 82 int i; 83 84 for (i = getdtablesize() - 1; i >= 0; i--) close(i); 85 open("/dev/null", O_RDWR, 0); 86 dup(0); 87 dup(0); 88 return; 89} 90 91/* ----------------------------------------------------------------------------- 92----------------------------------------------------------------------------- */ 93u_long load_kext(char *kext, int byBundleID) 94{ 95 int pid; 96 97 if ((pid = fork()) < 0) 98 return 1; 99 100 if (pid == 0) { 101 closeall(); 102 // PPP kernel extension not loaded, try load it... 103 if (byBundleID) 104 execle("/sbin/kextload", "kextload", "-b", kext, (char *)0, (char *)0); 105 else 106 execle("/sbin/kextload", "kextload", kext, (char *)0, (char *)0); 107 exit(1); 108 } 109 110 while (waitpid(pid, 0, 0) < 0) { 111 if (errno == EINTR) 112 continue; 113 return 1; 114 } 115 return 0; 116} 117 118/* ----------------------------------------------------------------------------- 119check if the kernel supports PPP 120----------------------------------------------------------------------------- */ 121int ppp_available() 122{ 123 int s; 124 125 // open to socket to the PF_PPP family 126 // if that works, the kernel extension is loaded. 127 if ((s = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL)) < 0) { 128 129#if !TARGET_OS_EMBEDDED // This file is not built for Embedded 130 if (!noload && !load_kext(PPP_NKE_PATH, 0)) 131#else 132 if (!noload && !load_kext(PPP_NKE_ID, 1)) 133#endif 134 s = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); 135 136 if (s < 0) 137 return 0; 138 } 139 140 // could be smarter and get the version of the ppp family, 141 // using get option or ioctl 142 143 close(s); 144 145 return 1; 146} 147 148/* ----------------------------------------------------------------------------- 149Copy the IPAddress of the default interface 150----------------------------------------------------------------------------- */ 151CFStringRef CopyDefaultIPAddress() 152{ 153 SCDynamicStoreRef store; 154 CFDictionaryRef dict = 0; 155 CFStringRef string, key; 156 CFArrayRef array; 157 158 store = SCDynamicStoreCreate(0, CFSTR("vpnd"), 0, 0); 159 if (store == 0) 160 return 0; 161 162 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(0, kSCDynamicStoreDomainState, kSCEntNetIPv4); 163 dict = SCDynamicStoreCopyValue(store, key); 164 CFRelease(key); 165 166 if (!isDictionary(dict)) 167 goto error; 168 169 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryService); 170 if (!isString(string)) 171 goto error; 172 173 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, string, kSCEntNetIPv4); 174 CFRelease(dict); 175 dict = SCDynamicStoreCopyValue(store, key); 176 CFRelease(key); 177 178 if (!isDictionary(dict)) 179 goto error; 180 181 array = CFDictionaryGetValue(dict, kSCPropNetIPv4Addresses); 182 if (!isArray(array)) 183 goto error; 184 185 string = CFArrayGetValueAtIndex(array, 0); 186 if (!isString(string)) 187 goto error; 188 189 /* we got the address ! */ 190 CFRetain(string); 191 192 CFRelease(dict); 193 CFRelease(store); 194 return string; 195 196error: 197 if (dict) 198 CFRelease(dict); 199 CFRelease(store); 200 return 0; 201} 202 203/* ---------------------------------------------------------------------------- 204 find the interface that has address target_address assigned and return 205 the interface name and its primary_address 206 Return code: 207 0 if successful, -1 otherwise. 208 ---------------------------------------------------------------------------- */ 209int get_interface(struct sockaddr_in *primary_address, const struct sockaddr_in *target_address, char *interface) 210{ 211 struct ifaddrs *ifap = NULL; 212 int ret = -1; 213 214 215 if (getifaddrs(&ifap) == 0) { 216 struct ifaddrs *ifa, *ifa1; 217 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 218 219 if (ifa->ifa_name 220 && ifa->ifa_addr 221 && ifa->ifa_addr->sa_family == target_address->sin_family 222 && ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == target_address->sin_addr.s_addr) { 223 224 strncpy(interface, ifa->ifa_name, IF_NAMESIZE); 225 226 if (primary_address) { 227 for (ifa1 = ifap; ifa1; ifa1 = ifa1->ifa_next) { 228 229 if (ifa1->ifa_name 230 && !strncmp(ifa1->ifa_name, interface, IFNAMSIZ) 231 && ifa1->ifa_addr 232 && target_address 233 && ifa1->ifa_addr->sa_family == target_address->sin_family) { 234 235 bcopy(ifa1->ifa_addr, primary_address, sizeof(*primary_address)); 236 break; 237 } 238 } 239 } 240 ret = 0; 241 break; 242 } 243 244 } 245 246 freeifaddrs(ifap); 247 } 248 249 return ret; 250} 251 252/* ---------------------------------------------------------------------------- 253 check if a given interface (or any if null) has the address assigned 254 Return code: 255 1 if address is found. 256 ---------------------------------------------------------------------------- */ 257int find_address(const struct sockaddr_in *address, char *interface) 258{ 259 struct ifaddrs *ifap = NULL; 260 int found = 0; 261 262 if (getifaddrs(&ifap) == 0) { 263 struct ifaddrs *ifa; 264 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 265 266 if (ifa->ifa_name 267 && ifa->ifa_addr 268 && (!interface || !strncmp(interface, ifa->ifa_name, IFNAMSIZ)) 269 && ifa->ifa_addr->sa_family == address->sin_family 270 && ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == address->sin_addr.s_addr) { 271 272 found = 1; 273 break; 274 } 275 276 } 277 278 freeifaddrs(ifap); 279 } 280 281 return found; 282} 283 284/* ---------------------------------------------------------------------------- 285 get the address and return the interface name and main address of the interface 286 Return code: 287 0 if successful, -1 otherwise. 288 ---------------------------------------------------------------------------- */ 289int get_route_interface(struct sockaddr *src, const struct sockaddr *dst, char *if_name) 290{ 291 int ret = -1; 292 293 // look if the cluster address is already assigned to an interface 294 if ((ret = get_interface((struct sockaddr_in *)src, (struct sockaddr_in *)dst, if_name))) { 295 296 // if not, then look ask the routing table for the interface to the cluster address is already assigned to an interface 297 ret = get_src_address(src, dst, NULL, if_name); 298 299 } 300 301 return ret; 302} 303 304 305// ---------------------------------------------------------------------------- 306// read function 307// ---------------------------------------------------------------------------- 308int readn(int ref, void *data, int len) 309{ 310 int n, left = len; 311 void *p = data; 312 313 while (left > 0) { 314 if ((n = read(ref, p, left)) < 0) { 315 if (errno != EINTR) 316 return -1; 317 n = 0; 318 } 319 else if (n == 0) 320 break; /* EOF */ 321 322 left -= n; 323 p += n; 324 } 325 return (len - left); 326} 327 328// ---------------------------------------------------------------------------- 329// write function 330// ---------------------------------------------------------------------------- 331int writen(int ref, void *data, int len) 332{ 333 int n, left = len; 334 void *p = data; 335 336 while (left > 0) { 337 if ((n = write(ref, p, left)) <= 0) { 338 if (errno != EINTR) 339 return -1; 340 n = 0; 341 } 342 left -= n; 343 p += n; 344 } 345 return len; 346} 347 348