//----------------------------------------------------------------------------- // builtin ipsec listen //----------------------------------------------------------------------------- static int plugin_listen() { int err; char *errstr; /* add security policies */ err = IPSecApplyConfiguration(ipsec_conf, &errstr); if (err) { vpnlog(LOG_ERR, "IPSec plugin: cannot configure racoon files (%s)...\n", errstr); return -1; } err = IPSecInstallPolicies(ipsec_conf, -1, &errstr); if (err) { vpnlog(LOG_ERR, "IPSec plugin: cannot configure kernel policies (%s)...\n", errstr); IPSecRemoveConfiguration(ipsec_conf, &errstr); return -1; } /* set IPSec Key management to prefer most recent key */ if (IPSecSetSecurityAssociationsPreference(&key_preference, 0)) vpnlog(LOG_ERR, "IPSec plugin: cannot set IPSec Key management preference (error %d)\n", errno); secure_transport = 1; return 0; }
//----------------------------------------------------------------------------- // process_interface_prefs //----------------------------------------------------------------------------- static int process_interface_prefs(struct vpn_params *params) { CFStringRef str = 0; CFDictionaryRef dict; // get type/subtype of server dict = CFDictionaryGetValue(params->serverRef, kRASEntInterface); if (!isDictionary(dict)) { vpnlog(LOG_ERR, "No Interface dictionary found\n"); return -1; } str = CFDictionaryGetValue(dict, kRASPropInterfaceType); if (!isString(str)) { vpnlog(LOG_ERR, "No Interface type found\n"); return -1; } if (CFStringCompare(str, kRASValInterfaceTypePPP, 0) == kCFCompareEqualTo) params->server_type = SERVER_TYPE_PPP; else if (CFStringCompare(str, kRASValInterfaceTypeIPSec, 0) == kCFCompareEqualTo) params->server_type = SERVER_TYPE_IPSEC; else { vpnlog(LOG_ERR, "Incorrect server type found\n"); return -1; } return 0; }
/* ----------------------------------------------------------------------------- plugin entry point, called by vpnd ref is the vpn bundle reference pppref is the ppp bundle reference bundles can be layout in two different ways - As simple vpn bundles (bundle.vpn). the bundle contains the vpn bundle binary. - As full ppp bundles (bundle.ppp). The bundle contains the ppp bundle binary, and also the vpn kext and the vpn bundle binary in its Plugins directory. if a simple vpn bundle was used, pppref will be NULL. if a ppp bundle was used, the vpn plugin will be able to get access to the Plugins directory and load the vpn kext. ----------------------------------------------------------------------------- */ int start(struct vpn_channel* the_vpn_channel, CFBundleRef ref, CFBundleRef pppref, int debug_mode) { char name[MAXPATHLEN]; CFURLRef url; debug = debug_mode; /* first load the kext if we are loaded as part of a ppp bundle */ if (pppref) { while ((listen_sockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_L2TP)) < 0) if (errno != EINTR) break; if (listen_sockfd < 0) { vpnlog(LOG_DEBUG, "first call to socket failed - attempting to load kext\n"); if (url = CFBundleCopyBundleURL(pppref)) { name[0] = 0; CFURLGetFileSystemRepresentation(url, 0, name, MAXPATHLEN - 1); CFRelease(url); strcat(name, "/"); if (url = CFBundleCopyBuiltInPlugInsURL(pppref)) { CFURLGetFileSystemRepresentation(url, 0, name + strlen(name), MAXPATHLEN - strlen(name) - strlen(L2TP_NKE) - 1); CFRelease(url); strcat(name, "/"); strcat(name, L2TP_NKE); if (!load_kext(name)) while ((listen_sockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_L2TP)) < 0) if (errno != EINTR) break; } } if (listen_sockfd < 0) { vpnlog(LOG_ERR, "VPND L2TP plugin: Unable to load L2TP kernel extension\n"); return -1; } } } /* retain reference */ bundle = ref; CFRetain(bundle); pppbundle = pppref; CFRetain(pppbundle); // hookup our socket handlers bzero(the_vpn_channel, sizeof(struct vpn_channel)); the_vpn_channel->get_pppd_args = l2tpvpn_get_pppd_args; the_vpn_channel->listen = l2tpvpn_listen; the_vpn_channel->accept = l2tpvpn_accept; the_vpn_channel->refuse = l2tpvpn_refuse; the_vpn_channel->close = l2tpvpn_close; return 0; }
/* ----------------------------------------------------------------------------- l2tpvpn_listen - called by vpnd to setup listening socket ----------------------------------------------------------------------------- */ int l2tpvpn_listen(void) { if (listen_sockfd <= 0) return -1; if (!opt_noipsec) { vpnlog(LOG_INFO, "VPND L2TP plugin: start racoon...\n"); /* start racoon */ if (start_racoon(0 /*pppbundle*/, 0 /*"racoon.l2tp"*/) < 0) { vpnlog(LOG_ERR, "VPND L2TP plugin: cannot start racoon...\n"); return -1; } /* XXX if we started racoon, we will need to stop it */ /* racoon should probably provide a control API */ need_stop_racoon = 1; } set_flag(listen_sockfd, debug, L2TP_FLAG_DEBUG); set_flag(listen_sockfd, 1, L2TP_FLAG_CONTROL); /* unknown src and dst addresses */ any_address.sin_len = sizeof(any_address); any_address.sin_family = AF_INET; any_address.sin_port = 0; any_address.sin_addr.s_addr = INADDR_ANY; /* bind the socket in the kernel with L2TP port */ listen_address.sin_len = sizeof(listen_address); listen_address.sin_family = AF_INET; listen_address.sin_port = L2TP_UDP_PORT; listen_address.sin_addr.s_addr = INADDR_ANY; l2tp_set_ouraddress(listen_sockfd, (struct sockaddr *)&listen_address); our_address = listen_address; /* add security policies */ if (!opt_noipsec) { if (configure_racoon(&our_address, &any_address, 0, IPPROTO_UDP, opt_ipsecsharedsecret, opt_ipsecsharedsecrettype) || require_secure_transport((struct sockaddr *)&any_address, (struct sockaddr *)&listen_address, IPPROTO_UDP, "in")) { vpnlog(LOG_ERR, "VPND L2TP plugin: cannot configure secure transport...\n"); return -1; } /* set IPSec Key management to prefer most recent key */ if (set_key_preference(&key_preference, 0)) vpnlog(LOG_ERR, "VPND L2TP plugin: cannot set IPSec Key management preference (error %d)\n", errno); secure_transport = 1; } return listen_sockfd; }
/* ----------------------------------------------------------------------------- l2tpvpn_close ----------------------------------------------------------------------------- */ void l2tpvpn_close(void) { char *errstr; if (racoon_sockfd != -1) { close(racoon_sockfd); racoon_sockfd = -1; } if (listen_sockfd != -1) { while (close(listen_sockfd) < 0) if (errno == EINTR) continue; listen_sockfd = -1; } /* remove security policies */ if (ipsec_dict) { IPSecRemoveConfiguration(ipsec_dict, &errstr); IPSecRemovePolicies(ipsec_dict, -1, &errstr); /* restore IPSec Key management preference */ if (IPSecSetSecurityAssociationsPreference(0, key_preference)) vpnlog(LOG_ERR, "L2TP plugin: cannot reset IPSec Key management preference (error %d)\n", errno); CFRelease(ipsec_dict); ipsec_dict = NULL; } if (ipsec_settings) { CFRelease(ipsec_settings); ipsec_settings = NULL; } }
/* ----------------------------------------------------------------------------- l2tpvpn_accept ----------------------------------------------------------------------------- */ int l2tpvpn_accept(void) { u_int8_t recv_buf[1500]; socklen_t addrlen; struct sockaddr_in6 from; int newSockfd; /* we should check if there are too many call from the same IP address in the last xxx minutes, proving a denial of service attack */ while((newSockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_L2TP)) < 0) if (errno != EINTR) { vpnlog(LOG_ERR, "L2TP plugin: Unable to open L2TP socket during accept\n"); return -1; } /* accept the call. it will copy the data to the new socket */ //set_flag(newSockfd, kerneldebug & 1, L2TP_FLAG_DEBUG); setsockopt(newSockfd, PPPPROTO_L2TP, L2TP_OPT_ACCEPT, 0, 0); /* read the duplicated SCCRQ from the listen socket and ignore for now */ if (l2tp_sys_recvfrom(listen_sockfd, recv_buf, 1500, MSG_DONTWAIT, (struct sockaddr*)&from, &addrlen) < 0) return -1; return newSockfd; }
/* ----------------------------------------------------------------------------- l2tpvpn_refuse - called by vpnd to refuse an incomming connection. return values: -1 error socket# launch pppd with next server address 0 handled, do nothing ----------------------------------------------------------------------------- */ int l2tpvpn_refuse(void) { u_int8_t recv_buf[1500]; int addrlen; struct sockaddr_in6 from; int newSockfd; /* we should check if there are too many call from the same IP address in the last xxx minutes, proving a denial of service attack */ /* need t read the packet to empty the socket buffer */ while((newSockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_L2TP)) < 0) if (errno != EINTR) { vpnlog(LOG_ERR, "VPND L2TP plugin: Unable to open L2TP socket during refuse\n"); return -1; } /* accept the call. it will copy the data to the new socket */ setsockopt(newSockfd, PPPPROTO_L2TP, L2TP_OPT_ACCEPT, 0, 0); /* and close it right away */ close(newSockfd); /* read the duplicated SCCRQ from the listen socket and ignore for now */ if (l2tp_sys_recvfrom(listen_sockfd, recv_buf, 1500, MSG_DONTWAIT, (struct sockaddr*)&from, &addrlen) < 0) return -1; return 0; }
/* ----------------------------------------------------------------------------- l2tpvpn_close ----------------------------------------------------------------------------- */ void l2tpvpn_close(void) { if (listen_sockfd != -1) { while (close(listen_sockfd) < 0) if (errno == EINTR) continue; listen_sockfd = -1; } /* remove security policies */ if (secure_transport) { cleanup_racoon(&our_address, &any_address); remove_secure_transport((struct sockaddr *)&any_address, (struct sockaddr *)&listen_address, IPPROTO_UDP, "in"); /* restore IPSec Key management preference */ if (set_key_preference(0, key_preference)) vpnlog(LOG_ERR, "VPND L2TP plugin: cannot reset IPSec Key management preference (error %d)\n", errno); } if (need_stop_racoon) { need_stop_racoon = 0; // let racoon running //stop_racoon(); } }
int l2tp_sys_setsockopt(int sockfd, int level, int optname, const void *optval, int optlen) { while (setsockopt(sockfd, level, optname, optval, optlen) < 0) if (errno != EINTR) { vpnlog(LOG_ERR, "VPND L2TP plugin: error calling setsockopt for option %d (%s)\n", optname, strerror(errno)); return -1; } return 0; }
//----------------------------------------------------------------------------- // builtin ipsec close //----------------------------------------------------------------------------- static void plugin_close() { int err; char *errstr; /* remove security policies */ if (secure_transport) { err = IPSecRemoveConfiguration(ipsec_conf, &errstr); if (err) vpnlog(LOG_ERR, "IPSec plugin: cannot remove IPSec configuration (%s)...\n", errstr); err = IPSecRemovePolicies(ipsec_conf, -1, &errstr); if (err) vpnlog(LOG_ERR, "IPSec plugin: cannot delete kernel policies (%s)...\n", errstr); /* restore IPSec Key management preference */ if (IPSecSetSecurityAssociationsPreference(0, key_preference)) vpnlog(LOG_ERR, "L2TP plugin: cannot reset IPSec Key management preference (error %d)\n", errno); } }
int l2tp_sys_recvfrom(int sockfd, void *buff, size_t nbytes, int flags, struct sockaddr *from, int *addrlen) { while (recvfrom(sockfd, buff, nbytes, flags, from, addrlen) < 0) if (errno != EINTR) { vpnlog(LOG_ERR, "VPND L2TP plugin: error calling recvfrom = %s\n", strerror(errno)); return -1; } return 0; }
// ---------------------------------------------------------------------------- // get_active_server // ---------------------------------------------------------------------------- CFArrayRef get_active_servers(struct vpn_params *params) { SCPreferencesRef prefs = 0; CFPropertyListRef active_servers; CFArrayRef arrayCopy = 0; char pathStr[MAXPATHLEN]; // open the prefs file prefs = SCPreferencesCreate(0, CFSTR("vpnd"), kRASServerPrefsFileName); if (prefs == NULL) { CFStringGetCString(kRASServerPrefsFileName, pathStr, MAXPATHLEN, kCFStringEncodingMacRoman); vpnlog(LOG_ERR, "Unable to read vpnd prefs file '%s'\n", pathStr); return 0; } // get active servers list from the plist active_servers = SCPreferencesGetValue(prefs, kRASActiveServers); if (active_servers && isArray(active_servers)) if (CFArrayGetCount(active_servers) > 0) arrayCopy = CFArrayCreateCopy(0, active_servers); CFRelease(prefs); return arrayCopy; }
/* ----------------------------------------------------------------------------- l2tpvpn_health_check ----------------------------------------------------------------------------- */ int l2tpvpn_health_check(int *outfd, int event) { size_t size; struct sockaddr_un sun; int ret = -1, flags; char data[256]; struct vpnctl_hdr *hdr = (struct vpnctl_hdr *)data; switch (event) { case 0: // periodic check // no ipsec, no need for health check if (opt_noipsec) { *outfd = -1; break; } if (sick_timeleft) { sick_timeleft--; if (sick_timeleft == 0) goto fail; } // racoon socket is already opened, just query racoon if (racoon_sockfd != -1) { if (ping_timeleft) { ping_timeleft--; if (ping_timeleft == 0) { // error on racoon socket. racoon exited ? ret = -2; // L2TP is sick, but don't die yet, give it 60 seconds to recover sick_timeleft = IPSEC_SICK_TIME; goto fail; } } else { // query racoon here bzero(hdr, sizeof(struct vpnctl_hdr)); hdr->msg_type = htons(VPNCTL_CMD_PING); hdr->cookie = htonl(++racoon_ping_seed); ping_timeleft = IPSEC_PING_TIME; // give few seconds to get a reply writen(racoon_sockfd, hdr, sizeof(struct vpnctl_hdr)); } break; } // attempt to kill and restart racoon every 10 seconds if ((sick_timeleft % IPSEC_REPAIR_TIME) == 0) { vpnlog(LOG_ERR, "IPSecSelfRepair\n"); IPSecSelfRepair(); } // racoon socket is not yet opened, so opened it /* open the racoon control socket */ racoon_sockfd = socket(PF_LOCAL, SOCK_STREAM, 0); if (racoon_sockfd < 0) { vpnlog(LOG_ERR, "Unable to create racoon control socket (errno = %d)\n", errno); goto fail; } bzero(&sun, sizeof(sun)); sun.sun_family = AF_LOCAL; strncpy(sun.sun_path, "/var/run/vpncontrol.sock", sizeof(sun.sun_path)); if (connect(racoon_sockfd, (struct sockaddr *)&sun, sizeof(sun)) < 0) { vpnlog(LOG_ERR, "Unable to connect racoon control socket (errno = %d)\n", errno); ret = -2; goto fail; } if ((flags = fcntl(racoon_sockfd, F_GETFL)) == -1 || fcntl(racoon_sockfd, F_SETFL, flags | O_NONBLOCK) == -1) { vpnlog(LOG_ERR, "Unable to set racoon control socket in non-blocking mode (errno = %d)\n", errno); ret = -2; goto fail; } *outfd = racoon_sockfd; sick_timeleft = 0; ping_timeleft = 0; break; case 1: // event on racoon fd size = recvfrom (racoon_sockfd, data, sizeof(struct vpnctl_hdr), 0, 0, 0); if (size == 0) { // error on racoon socket. racoon exited ? ret = -2; // L2TP is sick, but don't die yet, give it 60 seconds to recover sick_timeleft = IPSEC_SICK_TIME; ping_timeleft = 0; goto fail; } /* read end of packet */ if (ntohs(hdr->len)) { size = recvfrom (racoon_sockfd, data + sizeof(struct vpnctl_hdr), ntohs(hdr->len), 0, 0, 0); if (size == 0) { // error on racoon socket. racoon exited ? ret = -2; // L2TP is sick, but don't die yet, give it 60 seconds to recover sick_timeleft = IPSEC_SICK_TIME; ping_timeleft = 0; goto fail; } } switch (ntohs(hdr->msg_type)) { case VPNCTL_CMD_PING: if (racoon_ping_seed == ntohl(hdr->cookie)) { // good ! ping_timeleft = 0; //vpnlog(LOG_DEBUG, "receive racoon PING REPLY cookie %d\n", ntohl(hdr->cookie)); } break; default: /* ignore other messages */ //vpnlog(LOG_DEBUG, "receive racoon message type %d, result %d\n", ntohs(hdr->msg_type), ntohs(hdr->result)); break; } break; } return 0; fail: if (racoon_sockfd != -1) { close(racoon_sockfd); racoon_sockfd = -1; *outfd = -1; } return ret; }
/* ----------------------------------------------------------------------------- plugin entry point, called by vpnd ref is the vpn bundle reference pppref is the ppp bundle reference bundles can be layout in two different ways - As simple vpn bundles (bundle.vpn). the bundle contains the vpn bundle binary. - As full ppp bundles (bundle.ppp). The bundle contains the ppp bundle binary, and also the vpn kext and the vpn bundle binary in its Plugins directory. if a simple vpn bundle was used, pppref will be NULL. if a ppp bundle was used, the vpn plugin will be able to get access to the Plugins directory and load the vpn kext. ----------------------------------------------------------------------------- */ int start(struct vpn_channel* the_vpn_channel, CFBundleRef ref, CFBundleRef pppref, int debug_mode, int log_verbose) { char name[MAXPATHLEN]; CFURLRef url; size_t len; int nb_cpu = 1, nb_threads = 0; debug = debug_mode; /* first load the kext if we are loaded as part of a ppp bundle */ if (pppref) { while ((listen_sockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_L2TP)) < 0) if (errno != EINTR) break; if (listen_sockfd < 0) { vpnlog(LOG_DEBUG, "L2TP plugin: first call to socket failed - attempting to load kext\n"); if (url = CFBundleCopyBundleURL(pppref)) { name[0] = 0; CFURLGetFileSystemRepresentation(url, 0, (UInt8 *)name, MAXPATHLEN - 1); CFRelease(url); strlcat(name, "/", sizeof(name)); if (url = CFBundleCopyBuiltInPlugInsURL(pppref)) { CFURLGetFileSystemRepresentation(url, 0, (UInt8 *)(name + strlen(name)), MAXPATHLEN - strlen(name) - strlen(L2TP_NKE) - 1); CFRelease(url); strlcat(name, "/", sizeof(name)); strlcat(name, L2TP_NKE, sizeof(name)); #if !TARGET_OS_EMBEDDED // This file is not built for Embedded if (!load_kext(name, 0)) #else if (!load_kext(L2TP_NKE_ID, 1)) #endif while ((listen_sockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_L2TP)) < 0) if (errno != EINTR) break; } } if (listen_sockfd < 0) { vpnlog(LOG_ERR, "L2TP plugin: Unable to load L2TP kernel extension\n"); return -1; } } } #if !TARGET_OS_EMBEDDED // This file is not built for Embedded /* increase the number of threads for l2tp to nb cpus - 1 */ len = sizeof(int); sysctlbyname("hw.ncpu", &nb_cpu, &len, NULL, 0); if (nb_cpu > 1) { sysctlbyname("net.ppp.l2tp.nb_threads", &nb_threads, &len, 0, 0); if (nb_threads < (nb_cpu - 1)) { nb_threads = nb_cpu - 1; sysctlbyname("net.ppp.l2tp.nb_threads", 0, 0, &nb_threads, sizeof(int)); } } #endif /* retain reference */ bundle = ref; CFRetain(bundle); pppbundle = pppref; if (pppbundle) CFRetain(pppbundle); // hookup our socket handlers bzero(the_vpn_channel, sizeof(struct vpn_channel)); the_vpn_channel->get_pppd_args = l2tpvpn_get_pppd_args; the_vpn_channel->listen = l2tpvpn_listen; the_vpn_channel->accept = l2tpvpn_accept; the_vpn_channel->refuse = l2tpvpn_refuse; the_vpn_channel->close = l2tpvpn_close; the_vpn_channel->health_check = l2tpvpn_health_check; the_vpn_channel->lb_redirect = l2tpvpn_lb_redirect; return 0; }
/* ----------------------------------------------------------------------------- l2tpvpn_listen - called by vpnd to setup listening socket ----------------------------------------------------------------------------- */ int l2tpvpn_listen(void) { char *errstr; if (listen_sockfd <= 0) return -1; //set_flag(listen_sockfd, kerneldebug & 1, L2TP_FLAG_DEBUG); set_flag(listen_sockfd, 1, L2TP_FLAG_CONTROL); set_flag(listen_sockfd, !opt_noipsec, L2TP_FLAG_IPSEC); /* unknown src and dst addresses */ any_address.sin_len = sizeof(any_address); any_address.sin_family = AF_INET; any_address.sin_port = 0; any_address.sin_addr.s_addr = INADDR_ANY; /* bind the socket in the kernel with L2TP port */ listen_address.sin_len = sizeof(listen_address); listen_address.sin_family = AF_INET; listen_address.sin_port = htons(L2TP_UDP_PORT); listen_address.sin_addr.s_addr = INADDR_ANY; l2tp_set_ouraddress(listen_sockfd, (struct sockaddr *)&listen_address); our_address = listen_address; /* add security policies */ if (!opt_noipsec) { CFStringRef auth_method; CFStringRef string; CFDataRef data; uint32_t natt_multiple_users; /* get authentication method from the IPSec dict */ auth_method = CFDictionaryGetValue(ipsec_settings, kRASPropIPSecAuthenticationMethod); if (!isString(auth_method)) auth_method = kRASValIPSecAuthenticationMethodSharedSecret; /* get setting for nat traversal multiple user support - default is enabled for server */ GetIntFromDict(ipsec_settings, kRASPropIPSecNattMultipleUsersEnabled, &natt_multiple_users, 1); ipsec_dict = IPSecCreateL2TPDefaultConfiguration( (struct sockaddr *)&our_address, (struct sockaddr *)&any_address, NULL, auth_method, 0, natt_multiple_users, 0); /* set the authentication information */ if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodSharedSecret)) { string = CFDictionaryGetValue(ipsec_settings, kRASPropIPSecSharedSecret); if (isString(string)) CFDictionarySetValue(ipsec_dict, kRASPropIPSecSharedSecret, string); else if (isData(string) && ((CFDataGetLength((CFDataRef)string) % sizeof(UniChar)) == 0)) { CFStringEncoding encoding; data = (CFDataRef)string; #if __BIG_ENDIAN__ encoding = (*(CFDataGetBytePtr(data) + 1) == 0x00) ? kCFStringEncodingUTF16LE : kCFStringEncodingUTF16BE; #else // __LITTLE_ENDIAN__ encoding = (*(CFDataGetBytePtr(data) ) == 0x00) ? kCFStringEncodingUTF16BE : kCFStringEncodingUTF16LE; #endif string = CFStringCreateWithBytes(NULL, (const UInt8 *)CFDataGetBytePtr(data), CFDataGetLength(data), encoding, FALSE); CFDictionarySetValue(ipsec_dict, kRASPropIPSecSharedSecret, string); CFRelease(string); } string = CFDictionaryGetValue(ipsec_settings, kRASPropIPSecSharedSecretEncryption); if (isString(string)) CFDictionarySetValue(ipsec_dict, kRASPropIPSecSharedSecretEncryption, string); } else if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodCertificate)) { data = CFDictionaryGetValue(ipsec_settings, kRASPropIPSecLocalCertificate); if (isData(data)) CFDictionarySetValue(ipsec_dict, kRASPropIPSecLocalCertificate, data); } if (IPSecApplyConfiguration(ipsec_dict, &errstr) || IPSecInstallPolicies(ipsec_dict, -1, &errstr)) { vpnlog(LOG_ERR, "L2TP plugin: cannot configure secure transport (%s).\n", errstr); IPSecRemoveConfiguration(ipsec_dict, &errstr); CFRelease(ipsec_dict); ipsec_dict = 0; return -1; } /* set IPSec Key management to prefer most recent key */ if (IPSecSetSecurityAssociationsPreference(&key_preference, 0)) vpnlog(LOG_ERR, "L2TP plugin: cannot set IPSec Key management preference (error %d)\n", errno); sick_timeleft = IPSEC_SICK_TIME; ping_timeleft = 0; } return listen_sockfd; }
// ---------------------------------------------------------------------------- // process_prefs // ---------------------------------------------------------------------------- int ipsec_process_prefs(struct vpn_params *params) { char *errstr, c; CFStringRef string; if (ipsec_conf) { CFRelease(ipsec_conf); ipsec_conf = NULL; } ipsec_conf = (CFMutableDictionaryRef)CFDictionaryGetValue(params->serverRef, kRASEntIPSec); if (ipsec_conf == NULL) { vpnlog(LOG_ERR, "IPSec plugin: IPSec dictionary not present\n"); goto fail; } ipsec_conf = CFDictionaryCreateMutableCopy(NULL, 0, ipsec_conf); remoteaddress[0] = 0; string = CFDictionaryGetValue(ipsec_conf, kRASPropIPSecRemoteAddress); if (isString(string)) CFStringGetCString(string, remoteaddress, sizeof(remoteaddress), kCFStringEncodingUTF8); if (inet_aton(remoteaddress, &peer_address) == 0) { if (pipe(resolverfds) < 0) { vpnlog(LOG_ERR, "IPSec plugin: failed to create pipe for gethostbyname\n"); goto fail; } if (pthread_create(&resolverthread, NULL, ipsec_resolver_thread, NULL)) { vpnlog(LOG_ERR, "IPSec plugin: failed to create thread for gethostbyname...\n"); close(resolverfds[0]); close(resolverfds[1]); goto fail; } while (read(resolverfds[0], &c, 1) != 1) { if (got_terminate()) { pthread_cancel(resolverthread); break; } } close(resolverfds[0]); close(resolverfds[1]); if (got_terminate()) goto fail; if (c) { vpnlog(LOG_ERR, "IPSec plugin: Host '%s' not found...\n", remoteaddress); goto fail; } string = CFStringCreateWithCString(0, addr2ascii(AF_INET, &peer_address, sizeof(peer_address), 0), kCFStringEncodingASCII); CFDictionarySetValue(ipsec_conf, kRASPropIPSecRemoteAddress, string); CFRelease(string); } // verify the dictionary if (IPSecValidateConfiguration(ipsec_conf, &errstr)) { vpnlog(LOG_ERR, "IPSec plugin: Incorrect preferences (%s)\n", errstr); goto fail; } return 0; fail: if (ipsec_conf) { CFRelease(ipsec_conf); ipsec_conf = NULL; } return -1; }
/* ----------------------------------------------------------------------------- l2tpvpn_get_pppd_args ----------------------------------------------------------------------------- */ int l2tpvpn_get_pppd_args(struct vpn_params *params, int reload) { CFStringRef string; int noipsec = 0; CFMutableDictionaryRef dict = NULL; if (reload) { noipsec = opt_noipsec; } if (params->serverRef) { /* arguments from the preferences file */ addstrparam(params->exec_args, ¶ms->next_arg_index, "l2tpmode", "answer"); string = get_cfstr_option(params->serverRef, kRASEntL2TP, kRASPropL2TPTransport); if (string && CFEqual(string, kRASValL2TPTransportIP)) { addparam(params->exec_args, ¶ms->next_arg_index, "l2tpnoipsec"); opt_noipsec = 1; } dict = (CFMutableDictionaryRef)CFDictionaryGetValue(params->serverRef, kRASEntIPSec); if (isDictionary(dict)) { /* get the parameters from the IPSec dictionary */ dict = CFDictionaryCreateMutableCopy(0, 0, dict); } else { /* get the parameters from the L2TP dictionary */ dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); string = get_cfstr_option(params->serverRef, kRASEntL2TP, kRASPropL2TPIPSecSharedSecretEncryption); if (isString(string)) CFDictionarySetValue(dict, kRASPropIPSecSharedSecretEncryption, string); string = get_cfstr_option(params->serverRef, kRASEntL2TP, kRASPropL2TPIPSecSharedSecret); if (isString(string)) CFDictionarySetValue(dict, kRASPropIPSecSharedSecret, string); } } else { /* arguments from command line */ if (opt_noipsec) addparam(params->exec_args, ¶ms->next_arg_index, "l2tpnoipsec"); } if (reload) { if (noipsec != opt_noipsec || !CFEqual(dict, ipsec_settings)) { vpnlog(LOG_ERR, "reload prefs - IPSec shared secret cannot be changed\n"); if (dict) CFRelease(dict); return -1; } } if (ipsec_settings) CFRelease(ipsec_settings); ipsec_settings = dict; return 0; }
// ---------------------------------------------------------------------------- // process_prefs // ---------------------------------------------------------------------------- int process_prefs(struct vpn_params *params) { char pathStr[MAXPATHLEN]; SCPreferencesRef prefs = 0; CFPropertyListRef servers_list; char text[512] = ""; // open the prefs file prefs = SCPreferencesCreate(0, CFSTR("vpnd"), kRASServerPrefsFileName); if (prefs == NULL) { CFStringGetCString(kRASServerPrefsFileName, pathStr, MAXPATHLEN, kCFStringEncodingMacRoman); snprintf(text, sizeof(text), "Unable to read vpnd prefs file '%s'\n", pathStr); goto fail; } // get servers list from the plist servers_list = SCPreferencesGetValue(prefs, kRASServers); if (servers_list == NULL) { snprintf(text, sizeof(text), "Could not get servers dictionary\n"); goto fail; } // retrieve the information for the given Server ID params->serverIDRef = CFStringCreateWithCString(0, params->server_id, kCFStringEncodingMacRoman); if (params->serverIDRef == NULL) { snprintf(text, sizeof(text), "Could not create CFString for server ID\n"); goto fail; } params->serverRef = CFDictionaryGetValue(servers_list, params->serverIDRef); if (params->serverRef == NULL || isDictionary(params->serverRef) == 0) { snprintf(text, sizeof(text), "Server ID '%.64s' invalid\n", params->server_id); params->serverRef = 0; goto fail; } CFRetain(params->serverRef); CFRelease(prefs); prefs = 0; // process the dictionaries if (process_server_prefs(params)) goto fail; if (process_interface_prefs(params)) goto fail; switch (params->server_type) { case SERVER_TYPE_PPP: if (ppp_process_prefs(params)) { snprintf(text, sizeof(text), "Error while reading PPP preferences\n"); goto fail; } break; case SERVER_TYPE_IPSEC: if (ipsec_process_prefs(params)) { snprintf(text, sizeof(text), "Error while reading IPSec preferences\n"); goto fail; } break; } return 0; fail: vpnlog(LOG_ERR, text[0] ? text : "Error while reading preferences\n"); if (params->serverIDRef) { CFRelease(params->serverIDRef); params->serverIDRef = 0; } if (params->serverRef) { CFRelease(params->serverRef); params->serverRef = 0; } if (prefs) CFRelease(prefs); return -1; }
//----------------------------------------------------------------------------- // process_server_prefs //----------------------------------------------------------------------------- static int process_server_prefs(struct vpn_params *params) { u_int32_t lval, len; u_char str[MAXPATHLEN]; int err ; struct hostent *hostent; get_int_option(params->serverRef, kRASEntServer, kRASPropServerMaximumSessions, &lval, 0); if (lval) params->max_sessions = lval; len = sizeof(str); get_str_option(params->serverRef, kRASEntServer, kRASPropServerLogfile, str, sizeof(str), &len, (u_char*)default_log_path); if (str[0]) memcpy(params->log_path, str, len + 1); get_int_option(params->serverRef, kRASEntServer, kRASPropServerVerboseLogging, &lval, 0); if (lval) params->log_verbose = lval; // Load balancing parameters get_int_option(params->serverRef, kRASEntServer, kRASPropServerLoadBalancingEnabled, &lval, 0); if (lval) { params->lb_enable = 1; // will determine the interface from the cluster address //len = sizeof(str); //get_str_option(params->serverRef, kRASEntServer, kRASPropServerLoadBalancingInterface, str, sizeof(str), &len, "en1"); //strncpy(params->lb_interface, str, sizeof(params->lb_interface)); // is priority really useful ? //get_int_option(params->serverRef, kRASEntServer, kRASPropServerLoadBalancingPriority, &lval, 5); //if (lval < 1) lval = 1; //else if (lval > LB_MAX_PRIORITY) lval = LB_MAX_PRIORITY; //params->lb_priority = lval; get_int_option(params->serverRef, kRASEntServer, kRASPropServerLoadBalancingPort, &lval, LB_DEFAULT_PORT); params->lb_port = htons(lval); len = sizeof(str); get_str_option(params->serverRef, kRASEntServer, kRASPropServerLoadBalancingAddress, str, sizeof(str), &len, empty_str); // ask the system to look up the given name. hostent = getipnodebyname ((char*)str, AF_INET, 0, &err); if (!hostent) { vpnlog(LOG_ERR, "Incorrect Load Balancing address found '%s'\n", str); params->lb_enable = 0; } else { struct sockaddr_in src, dst; params->lb_cluster_address = *(struct in_addr *)hostent->h_addr_list[0]; freehostent(hostent); bzero(&dst, sizeof(dst)); dst.sin_family = PF_INET; dst.sin_len = sizeof(dst); dst.sin_addr = params->lb_cluster_address; // look for the interface and primary address of the cluster address if (get_route_interface((struct sockaddr *)&src, (struct sockaddr *)&dst, params->lb_interface)) { vpnlog(LOG_ERR, "Cannot get load balancing redirect address and interface (errno = %d)\n", errno); params->lb_enable = 0; } params->lb_redirect_address = src.sin_addr; } } return 0; }