#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <netinet6/ipsec.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCValidation.h>
#include <sys/param.h>
#include <syslog.h>
#include <netinet/in_var.h>
#include <sys/kern_event.h>
#include "libpfkey.h"
#include "cf_utils.h"
#include "ipsec_utils.h"
#include "RASSchemaDefinitions.h"
#include "vpnoptions.h"
#define WRITE(t) fprintf(file, "%s%s", TAB_LEVEL[level], t)
#define TWRITE(t) fprintf(file, "%s", t)
#define FAIL(e) { *errstr = e; goto fail; }
#define RACOON_CONFIG_PATH "/var/run/racoon"
char *TAB_LEVEL[] = {
"",
" ",
" ",
" "
};
static int racoon_configure(CFDictionaryRef ipsec_dict, char **errstr, int apply);
static int configure_sainfo(int level, FILE *file, CFDictionaryRef ipsec_dict, CFDictionaryRef policy, char **errstr);
static int configure_remote(int level, FILE *file, CFDictionaryRef ipsec_dict, char **errstr);
static int configure_proposal(int level, FILE *file, CFDictionaryRef ipsec_dict, CFDictionaryRef proposal_dict, char **errstr);
static void closeall();
static int racoon_pid();
static int racoon_is_started(char *filename);
static int racoon_restart();
static int makepath( char *path);
static int makepath( char *path)
{
char *c;
char *thepath;
int slen=0;
int done = 0;
mode_t oldmask, newmask;
struct stat sb;
int error=0;
oldmask = umask(0);
newmask = S_IRWXU | S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH;
slen = strlen(path);
if ( !(thepath = malloc( slen+1) ))
return -1;
strlcpy( thepath, path, slen+1);
c = thepath;
if ( *c == '/' )
c++;
for( ; !done; c++){
if ( (*c == '/') || ( *c == '\0' )){
if ( *c == '\0' )
done = 1;
else
*c = '\0';
if ( mkdir( thepath, newmask) ){
if ( errno == EEXIST || errno == EISDIR){
if ( stat(thepath, &sb) < 0){
error = -1;
break;
}
} else {
error = -1;
break;
}
}
*c = '/';
}
}
free(thepath);
umask(oldmask);
return error;
}
static int EncodeDataUsingBase64(CFDataRef inputData, char *outputData, int maxOutputLen) {
static const char __CFPLDataEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const uint8_t *bytes = CFDataGetBytePtr(inputData);
CFIndex length = CFDataGetLength(inputData);
CFIndex i, pos;
const uint8_t *p;
uint8_t * outp = (uint8_t *)outputData;
if (maxOutputLen < (length + (length / 3) + (length % 3) + 1))
return 0;
pos = 0;
for (i = 0, p = bytes; i < length; i++, p++) {
switch (i % 3) {
case 0:
outp[pos++] = __CFPLDataEncodeTable [ ((p[0] >> 2) & 0x3f)];
break;
case 1:
outp[pos++] = __CFPLDataEncodeTable [ ((((p[-1] << 8) | p[0]) >> 4) & 0x3f)];
break;
case 2:
outp[pos++] = __CFPLDataEncodeTable [ ((((p[-1] << 8) | p[0]) >> 6) & 0x3f)];
outp[pos++] = __CFPLDataEncodeTable [ (p[0] & 0x3f)];
break;
}
}
switch (i % 3) {
case 0:
break;
case 1:
outp[pos++] = __CFPLDataEncodeTable [ ((p[-1] << 4) & 0x30)];
outp[pos++] = '=';
outp[pos++] = '=';
break;
case 2:
outp[pos++] = __CFPLDataEncodeTable [ ((p[-1] << 2) & 0x3c)];
outp[pos++] = '=';
break;
}
outp[pos] = 0;
return pos;
}
static inline u_int
max(u_int a, u_int b)
{
return (a > b ? a : b);
}
void
closeall()
{
int i;
for (i = getdtablesize() - 1; i >= 0; i--) close(i);
open("/dev/null", O_RDWR, 0);
dup(0);
dup(0);
return;
}
int
racoon_pid()
{
int pid = 0, err, name[4];
FILE *f;
size_t namelen, infolen;
struct kinfo_proc info;
f = fopen("/var/run/racoon.pid", "r");
if (f) {
fscanf(f, "%d", &pid);
fclose(f);
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_PID;
name[3] = pid;
namelen = 4;
bzero(&info, sizeof(info));
infolen = sizeof(info);
err = sysctl(name, namelen, &info, &infolen, 0, 0);
if (err == 0 && !strcmp("racoon", info.kp_proc.p_comm)) {
return pid;
}
}
return 0;
}
int
racoon_is_started(char *filename)
{
return (racoon_pid() != 0);
}
int
racoon_restart()
{
int pid = racoon_pid();
if (pid) {
#ifdef TARGET_EMBEDDED_OS
kill(pid, SIGHUP);
#else
kill(pid, SIGUSR1);
#endif
}
return 0;
}
static int
racoon_stop()
{
int pid = racoon_pid();
if (pid)
kill(pid, SIGTERM);
return 0;
}
int
configure_proposal(int level, FILE *file, CFDictionaryRef ipsec_dict, CFDictionaryRef proposal_dict, char **errstr)
{
char text[MAXPATHLEN];
{
char str[256];
CFStringRef auth_method = NULL;
u_int32_t xauth_enabled = 0;
auth_method = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecAuthenticationMethod);
GetIntFromDict(ipsec_dict, kRASPropIPSecXAuthEnabled, &xauth_enabled, 0);
#if 0
if (proposal_dict)
prop_method = CFDictionaryGetValue(proposal_dict, kRASPropIPSecProposalAuthenticationMethod);
strlcpy(str, "pre_shared_key", sizeof(str));
if (isString(auth_method) || isString(prop_method)) {
if (CFEqual(isString(prop_method) ? prop_method : auth_method, kRASValIPSecProposalAuthenticationMethodSharedSecret))
strlcpy(str, "pre_shared_key", sizeof(str));
else if (CFEqual(isString(prop_method) ? prop_method : auth_method, kRASValIPSecProposalAuthenticationMethodCertificate))
strlcpy(str, "rsasig", sizeof(str));
else if (CFEqual(isString(prop_method) ? prop_method : auth_method, kRASValIPSecProposalAuthenticationMethodXauthSharedSecretClient))
strlcpy(str, "xauth_psk_client", sizeof(str));
else if (CFEqual(isString(prop_method) ? prop_method : auth_method, kRASValIPSecProposalAuthenticationMethodXauthCertificateClient))
strlcpy(str, "xauth_rsa_client", sizeof(str));
else if (CFEqual(isString(prop_method) ? prop_method : auth_method, kRASValIPSecProposalAuthenticationMethodHybridCertificateClient))
strlcpy(str, "hybrid_rsa_client", sizeof(str));
else
FAIL("incorrect authentication method";)
}
#endif
strlcpy(str, "pre_shared_key", sizeof(str));
if (isString(auth_method)) {
if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodSharedSecret))
strlcpy(str, xauth_enabled ? "xauth_psk_client" : "pre_shared_key", sizeof(str));
else if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodCertificate))
strlcpy(str, xauth_enabled ? "xauth_rsa_client" : "rsasig", sizeof(str));
else if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodHybrid))
strlcpy(str, "hybrid_rsa_client", sizeof(str));
else
FAIL("incorrect authentication method";)
}
snprintf(text, sizeof(text), "authentication_method %s;\n", str);
WRITE(text);
}
{
char str[256];
CFStringRef algo;
strlcpy(str, "sha1", sizeof(str));
if (proposal_dict) {
algo = CFDictionaryGetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm);
if (isString(algo)) {
if (CFEqual(algo, kRASValIPSecProposalHashAlgorithmMD5))
strlcpy(str, "md5", sizeof(str));
else if (CFEqual(algo, kRASValIPSecProposalHashAlgorithmSHA1))
strlcpy(str, "sha1", sizeof(str));
else
FAIL("incorrect authentication algorithm";)
}
}
snprintf(text, sizeof(text), "hash_algorithm %s;\n", str);
WRITE(text);
}
{
char str[256];
CFStringRef crypto;
strlcpy(str, "3des", sizeof(str));
if (proposal_dict) {
crypto = CFDictionaryGetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm);
if (isString(crypto)) {
if (CFEqual(crypto, kRASValIPSecProposalEncryptionAlgorithmDES))
strlcpy(str, "des", sizeof(str));
else if (CFEqual(crypto, kRASValIPSecProposalEncryptionAlgorithm3DES))
strlcpy(str, "3des", sizeof(str));
else if (CFEqual(crypto, kRASValIPSecProposalEncryptionAlgorithmAES))
strlcpy(str, "aes", sizeof(str));
else if (CFEqual(crypto, kRASValIPSecProposalEncryptionAlgorithmAES256))
strlcpy(str, "aes 256", sizeof(str));
else
FAIL("incorrect encryption algorithm";)
}
}
snprintf(text, sizeof(text), "encryption_algorithm %s;\n", str);
WRITE(text);
}
{
u_int32_t lval = 3600;
if (proposal_dict) {
GetIntFromDict(proposal_dict, kRASPropIPSecProposalLifetime, &lval, 3600);
}
snprintf(text, sizeof(text), "lifetime time %d sec;\n", lval);
WRITE(text);
}
{
u_int32_t lval = 2;
if (proposal_dict) {
GetIntFromDict(proposal_dict, kRASPropIPSecProposalDHGroup, &lval, 2);
}
snprintf(text, sizeof(text), "dh_group %d;\n", lval);
WRITE(text);
}
return 0;
fail:
return -1;
}
#define CERT_VERIFICATION_OPTION_NONE 0
#define CERT_VERIFICATION_OPTION_OPEN_DIR 1
#define CERT_VERIFICATION_OPTION_PEERS_ID 2
int
configure_remote(int level, FILE *file, CFDictionaryRef ipsec_dict, char **errstr)
{
char text[MAXPATHLEN];
CFStringRef auth_method = NULL;
int cert_verification_option = CERT_VERIFICATION_OPTION_NONE;
char *option_str;
WRITE("doi ipsec_doi;\n");
WRITE("situation identity_only;\n");
{
int i, nb;
CFArrayRef modes;
CFStringRef mode;
strlcpy(text, "exchange_mode ", sizeof(text));
nb = 0;
modes = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecExchangeMode);
if (isArray(modes)) {
nb = max(CFArrayGetCount(modes), 3);
for (i = 0; i < nb; i++) {
mode = CFArrayGetValueAtIndex(modes, i);
if (!isString(mode))
continue;
if (i)
strlcat(text, ", ", sizeof(text));
if (CFEqual(mode, kRASValIPSecExchangeModeMain))
strlcat(text, "main", sizeof(text));
else if (CFEqual(mode, kRASValIPSecExchangeModeAggressive))
strlcat(text, "aggressive", sizeof(text));
else if (CFEqual(mode, kRASValIPSecExchangeModeBase))
strlcat(text, "base", sizeof(text));
else
FAIL("incorrect phase 1 exchange mode");
}
}
if (nb == 0) {
char str[256];
if (GetStrFromDict(ipsec_dict, kRASPropIPSecLocalIdentifier, str, sizeof(str), ""))
strlcat(text, "aggressive", sizeof(text));
else
strlcat(text, "main", sizeof(text));
}
strlcat(text, ";\n", sizeof(text));
WRITE(text);
}
{
auth_method = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecAuthenticationMethod);
#if 0
CFArrayRef proposals;
int i, nb;
CFDictionaryRef proposal;
CFStringRef method;
proposals = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecProposals);
if (isArray(proposals)) {
nb = CFArrayGetCount(proposals);
for (i = 0; i < nb; i++) {
proposal = CFArrayGetValueAtIndex(proposals, i);
if (isDictionary(proposal)) {
method = CFDictionaryGetValue(proposal, kRASPropIPSecProposalAuthenticationMethod);
if (isString(method)) {
if (auth_method == NULL)
auth_method = method;
else if (!CFEqual(auth_method, method))
FAIL("inconsistent authentication methods");
}
}
}
}
#endif
if (auth_method == NULL)
auth_method = kRASValIPSecAuthenticationMethodSharedSecret;
if (!CFEqual(auth_method, kRASValIPSecAuthenticationMethodSharedSecret)
&& !CFEqual(auth_method, kRASValIPSecAuthenticationMethodCertificate)
&& !CFEqual(auth_method, kRASValIPSecAuthenticationMethodHybrid))
FAIL("incorrect authentication method found");
}
{
char str[256];
char str1[256];
if (GetStrFromDict(ipsec_dict, CFSTR("LocalIdentifierType"), str1, sizeof(str1), "")) {
if (!strcmp(str1, "FQDN"))
strlcpy(str1, "fqdn", sizeof(str1));
else if (!strcmp(str1, "UserFQDN"))
strlcpy(str1, "user_fqdn", sizeof(str1));
else if (!strcmp(str1, "KeyID"))
strlcpy(str1, "keyid_use", sizeof(str1));
else if (!strcmp(str1, "Address"))
strlcpy(str1, "address", sizeof(str1));
else if (!strcmp(str1, "ASN1DN"))
strlcpy(str1, "asn1dn", sizeof(str1));
else
strlcpy(str1, "", sizeof(str1));
}
if (GetStrFromDict(ipsec_dict, kRASPropIPSecLocalIdentifier, str, sizeof(str), "")) {
snprintf(text, sizeof(text), "my_identifier %s \"%s\";\n", str1[0] ? str1 : "fqdn", str);
WRITE(text);
}
else {
if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodSharedSecret)
|| CFEqual(auth_method, kRASValIPSecAuthenticationMethodHybrid)) {
}
else if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodCertificate)) {
snprintf(text, sizeof(text), "my_identifier asn1dn;\n");
WRITE(text);
}
}
}
{
CFStringRef string;
char str[256];
string = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecIdentifierVerification);
if (!isString(string))
string = kRASValIPSecIdentifierVerificationGenerateFromRemoteAddress;
if (CFEqual(string, kRASValIPSecIdentifierVerificationNone)) {
WRITE("verify_identifier off;\n");
}
else {
if (CFEqual(string, kRASValIPSecIdentifierVerificationGenerateFromRemoteAddress)) {
if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecRemoteAddress, str, sizeof(str)))
FAIL("no remote address found");
snprintf(text, sizeof(text), "peers_identifier address \"%s\";\n", str);
WRITE(text);
if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodCertificate))
cert_verification_option = CERT_VERIFICATION_OPTION_PEERS_ID;
}
else if (CFEqual(string, kRASValIPSecIdentifierVerificationUseRemoteIdentifier)) {
if (!GetStrFromDict(ipsec_dict, kRASPropIPSecRemoteIdentifier, str, sizeof(str), ""))
FAIL("no remote identifier found");
snprintf(text, sizeof(text), "peers_identifier fqdn \"%s\";\n", str);
WRITE(text);
if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodCertificate))
cert_verification_option = CERT_VERIFICATION_OPTION_PEERS_ID;
}
else if (CFEqual(string, kRASValIPSecIdentifierVerificationUseOpenDirectory)) {
if (!CFEqual(auth_method, kRASValIPSecAuthenticationMethodCertificate))
FAIL("open directory can only be used with certificate authentication");
cert_verification_option = CERT_VERIFICATION_OPTION_OPEN_DIR;
}
else
FAIL("incorrect verification method");
snprintf(text, sizeof(text), "verify_identifier %s;\n", (cert_verification_option == CERT_VERIFICATION_OPTION_NONE ? "on" : "off"));
WRITE(text);
}
}
{
char str[256], str1[256];
CFStringRef string;
if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodSharedSecret)
|| CFEqual(auth_method, kRASValIPSecAuthenticationMethodHybrid)) {
if (!GetStrFromDict(ipsec_dict, kRASPropIPSecSharedSecret, str, sizeof(str), ""))
FAIL("no shared secret found");
strlcpy(str1, "use", sizeof(str1));
string = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecSharedSecretEncryption);
if (isString(string)) {
if (CFEqual(string, kRASValIPSecSharedSecretEncryptionKey))
strlcpy(str1, "key", sizeof(str1));
else if (CFEqual(string, kRASValIPSecSharedSecretEncryptionKeychain))
strlcpy(str1, "keychain", sizeof(str1));
else
FAIL("incorrect shared secret encryption found");
}
snprintf(text, sizeof(text), "shared_secret %s \"%s\";\n", str1, str);
WRITE(text);
}
else if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodCertificate)) {
CFDataRef local_cert;
local_cert = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecLocalCertificate);
if (isData(local_cert)) {
WRITE("certificate_type x509 in_keychain \"");
fwrite(text, 1, EncodeDataUsingBase64(local_cert, text, sizeof(text)), file);
TWRITE("\";\n");
}
else
WRITE("certificate_type x509 in_keychain;\n");
WRITE("verify_cert on;\n");
if (cert_verification_option == CERT_VERIFICATION_OPTION_OPEN_DIR)
option_str = " use_open_dir";
else if (cert_verification_option == CERT_VERIFICATION_OPTION_PEERS_ID)
option_str = " use_peers_identifier";
else
option_str = "";
snprintf(text, sizeof(text), "certificate_verification sec_framework%s;\n", option_str);
WRITE(text);
}
}
{
u_int32_t lval;
GetIntFromDict(ipsec_dict, kRASPropIPSecNonceSize, &lval, 16);
snprintf(text, sizeof(text), "nonce_size %d;\n", lval);
WRITE(text);
}
{
u_int32_t natt_multi_user;
if (GetIntFromDict(ipsec_dict, kRASPropIPSecNattMultipleUsersEnabled, &natt_multi_user, 0)) {
snprintf(text, sizeof(text), "nat_traversal_multi_user %s;\n", natt_multi_user ? "on" : "off");
WRITE(text);
}
}
{
u_int32_t natt_keepalive;
if (GetIntFromDict(ipsec_dict, kRASPropIPSecNattKeepAliveEnabled, &natt_keepalive, 1)) {
snprintf(text, sizeof(text), "nat_traversal_keepalive %s;\n", natt_keepalive ? "on" : "off");
WRITE(text);
}
}
{
int dpd_enabled, dpd_delay, dpd_retry, dpd_maxfail, blackhole_enabled;
if (GetIntFromDict(ipsec_dict, kRASPropIPSecDeadPeerDetectionEnabled, (u_int32_t *)&dpd_enabled, 0)) {
GetIntFromDict(ipsec_dict, kRASPropIPSecDeadPeerDetectionDelay, (u_int32_t *)&dpd_delay, 30);
GetIntFromDict(ipsec_dict, kRASPropIPSecDeadPeerDetectionRetry, (u_int32_t *)&dpd_retry, 5);
GetIntFromDict(ipsec_dict, kRASPropIPSecDeadPeerDetectionMaxFail, (u_int32_t *)&dpd_maxfail, 5);
GetIntFromDict(ipsec_dict, kRASPropIPSecBlackHoleDetectionEnabled, (u_int32_t *)&blackhole_enabled, 1);
snprintf(text, sizeof(text), "dpd_delay %d;\n", dpd_delay);
WRITE(text);
snprintf(text, sizeof(text), "dpd_retry %d;\n", dpd_retry);
WRITE(text);
snprintf(text, sizeof(text), "dpd_maxfail %d;\n", dpd_maxfail);
WRITE(text);
snprintf(text, sizeof(text), "dpd_algorithm %s;\n", blackhole_enabled ? "dpd_blackhole_detect" : "dpd_inbound_detect");
WRITE(text);
}
}
{
int disconnect_on_idle, disconnect_on_idle_timer;
if (GetIntFromDict(ipsec_dict, kRASPropIPSecDisconnectOnIdle, (u_int32_t *)&disconnect_on_idle, 0)) {
GetIntFromDict(ipsec_dict, kRASPropIPSecDisconnectOnIdleTimer, (u_int32_t *)&disconnect_on_idle_timer, 120);
snprintf(text, sizeof(text), "disconnect_on_idle idle_timeout %d idle_direction idle_outbound;\n", disconnect_on_idle_timer);
WRITE(text);
}
}
WRITE("initial_contact on;\n");
WRITE("support_mip6 on;\n");
{
CFStringRef behavior;
char str[256];
strlcpy(str, "claim", sizeof(str));
behavior = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecProposalsBehavior);
if (isString(behavior)) {
if (CFEqual(behavior, kRASValIPSecProposalsBehaviorClaim))
strlcpy(str, "claim", sizeof(str));
else if (CFEqual(behavior, kRASValIPSecProposalsBehaviorObey))
strlcpy(str, "obey", sizeof(str));
else if (CFEqual(behavior, kRASValIPSecProposalsBehaviorStrict))
strlcpy(str, "strict", sizeof(str));
else if (CFEqual(behavior, kRASValIPSecProposalsBehaviorExact))
strlcpy(str, "exact", sizeof(str));
else
FAIL("incorrect proposal behavior");
}
snprintf(text, sizeof(text), "proposal_check %s;\n", str);
WRITE(text);
}
{
char str[256];
if (GetStrFromDict(ipsec_dict, kRASPropIPSecXAuthName, str, sizeof(str), "")) {
snprintf(text, sizeof(text), "xauth_login \"%s\";\n", str);
WRITE(text);
}
}
{
u_int32_t modeconfig;
if (GetIntFromDict(ipsec_dict, kRASPropIPSecModeConfigEnabled, &modeconfig, 0)) {
snprintf(text, sizeof(text), "mode_cfg %s;\n", modeconfig ? "on" : "off");
WRITE(text);
}
}
{
int i = 0, nb = 0;
CFArrayRef proposals;
CFDictionaryRef proposal = NULL;
proposals = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecProposals);
if (isArray(proposals))
nb = CFArrayGetCount(proposals);
do {
if (nb) {
proposal = CFArrayGetValueAtIndex(proposals, i);
if (!isDictionary(proposal))
FAIL("incorrect phase 1 proposal");
}
WRITE("\n");
WRITE("proposal {\n");
if (configure_proposal(level + 1, file, ipsec_dict, proposal, errstr))
goto fail;
WRITE("}\n");
} while (++i < nb);
}
return 0;
fail:
return -1;
}
int
configure_sainfo(int level, FILE *file, CFDictionaryRef ipsec_dict, CFDictionaryRef policy, char **errstr)
{
char text[MAXPATHLEN];
{
CFArrayRef algos;
int i, nb, found = 0;
strlcpy(text, "encryption_algorithm ", sizeof(text));
if (policy) {
algos = CFDictionaryGetValue(policy, kRASPropIPSecPolicyEncryptionAlgorithm);
if (isArray(algos)) {
nb = CFArrayGetCount(algos);
if (nb) {
for (i = 0; i < nb; i++) {
CFStringRef algo;
algo = CFArrayGetValueAtIndex(algos, i);
if (!isString(algo))
continue;
if (found)
strlcat(text, ", ", sizeof(text));
if (CFEqual(algo, kRASValIPSecPolicyEncryptionAlgorithmDES))
strlcat(text, "des", sizeof(text));
else if (CFEqual(algo, kRASValIPSecPolicyEncryptionAlgorithm3DES))
strlcat(text, "3des", sizeof(text));
else if (CFEqual(algo, kRASValIPSecPolicyEncryptionAlgorithmAES))
strlcat(text, "aes", sizeof(text));
else
FAIL("incorrect encryption algorithm");
found = 1;
}
}
}
}
if (!found)
strlcat(text, "aes", sizeof(text));
strlcat(text, ";\n", sizeof(text));
WRITE(text);
}
{
CFArrayRef algos;
int i, nb, found = 0;
strlcpy(text, "authentication_algorithm ", sizeof(text));
if (policy) {
algos = CFDictionaryGetValue(policy, kRASPropIPSecPolicyHashAlgorithm);
if (isArray(algos)) {
nb = CFArrayGetCount(algos);
if (nb) {
for (i = 0; i < nb; i++) {
CFStringRef algo;
algo = CFArrayGetValueAtIndex(algos, i);
if (!isString(algo))
continue;
if (found)
strlcat(text, ", ", sizeof(text));
if (CFEqual(algo, kRASValIPSecPolicyHashAlgorithmSHA1))
strlcat(text, "hmac_sha1", sizeof(text));
else if (CFEqual(algo, kRASValIPSecPolicyHashAlgorithmMD5))
strlcat(text, "hmac_md5", sizeof(text));
else
FAIL("incorrect authentication algorithm");
found = 1;
}
}
}
}
if (!found)
strlcat(text, "hmac_sha1", sizeof(text));
strlcat(text, ";\n", sizeof(text));
WRITE(text);
}
{
CFArrayRef algos;
int i, nb, found = 0;
strlcpy(text, "compression_algorithm ", sizeof(text));
if (policy) {
algos = CFDictionaryGetValue(policy, kRASPropIPSecPolicyCompressionAlgorithm);
if (isArray(algos)) {
nb = CFArrayGetCount(algos);
if (nb) {
for (i = 0; i < nb; i++) {
CFStringRef algo;
algo = CFArrayGetValueAtIndex(algos, i);
if (!isString(algo))
continue;
if (found)
strlcat(text, ", ", sizeof(text));
if (CFEqual(algo, kRASValIPSecPolicyCompressionAlgorithmDeflate))
strlcat(text, "deflate", sizeof(text));
else
FAIL("incorrect compression algorithm");
found = 1;
}
}
}
}
if (!found)
strlcat(text, "deflate", sizeof(text));
strlcat(text, ";\n", sizeof(text));
WRITE(text);
}
{
u_int32_t lval = 3600;
if (policy)
GetIntFromDict(policy, kRASPropIPSecPolicyLifetime, &lval, 3600);
snprintf(text, sizeof(text), "lifetime time %d sec;\n", lval);
WRITE(text);
}
{
u_int32_t lval = 0;
if (policy) {
if (GetIntFromDict(policy, kRASPropIPSecPolicyPFSGroup, &lval, 0) && lval) {
snprintf(text, sizeof(text), "pfs_group %d;\n", lval);
WRITE(text);
}
}
}
return 0;
fail:
return -1;
}
int
IPSecApplyConfiguration(CFDictionaryRef ipsec_dict, char **errstr)
{
return racoon_configure(ipsec_dict, errstr, 1);
}
int
IPSecValidateConfiguration(CFDictionaryRef ipsec_dict, char **errstr)
{
return racoon_configure(ipsec_dict, errstr, 0);
}
int
racoon_configure(CFDictionaryRef ipsec_dict, char **errstr, int apply)
{
int level = 0, anonymous;
mode_t mask;
FILE *file = 0;
char filename[256], text[256];
char text2[256];
char local_address[32], remote_address[32];
struct stat sb;
filename[0] = 0;
if (!isDictionary(ipsec_dict))
FAIL("IPSec dictionary not present");
if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecLocalAddress, local_address, sizeof(local_address)))
FAIL("incorrect local address found");
if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecRemoteAddress, remote_address, sizeof(remote_address)))
FAIL("incorrect remote address found");
anonymous = inet_addr(remote_address) == 0;
if (apply) {
snprintf(filename, sizeof(filename), RACOON_CONFIG_PATH "/%s.conf", anonymous ? "anonymous" : remote_address);
remove(filename);
if (stat(RACOON_CONFIG_PATH, &sb) != 0 && errno == ENOENT) {
if ( makepath( RACOON_CONFIG_PATH ) ){
snprintf(text, sizeof(text), "cannot create racoon configuration file path (error %d)", errno);
FAIL(text);
}
}
}
mask = umask(S_IRWXG|S_IRWXO);
file = fopen(apply ? filename : "/dev/null" , "w");
mask = umask(mask);
if (file == NULL) {
snprintf(text, sizeof(text), "cannot create racoon configuration file (error %d)", errno);
FAIL(text);
}
if (CFDictionaryGetValue(ipsec_dict, CFSTR("UseAnonymousPolicy")))
anonymous = 1;
{
snprintf(text, sizeof(text), "remote %s {\n", anonymous ? "anonymous" : remote_address);
WRITE(text);
if (configure_remote(level + 1, file, ipsec_dict, errstr))
goto fail;
WRITE("}\n\n");
}
{
CFArrayRef policies;
int i, nb;
policies = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecPolicies);
if (!isArray(policies)
|| (nb = CFArrayGetCount(policies)) == 0)
goto no_policy;
if (anonymous)
nb = 1;
for (i = 0; i < nb; i++) {
CFDictionaryRef policy;
CFStringRef policylevel, policymode;
char local_network[256], remote_network[256];
u_int32_t local_port, remote_port;
u_int32_t local_prefix, remote_prefix;
u_int32_t protocol, tunnel;
policy = CFArrayGetValueAtIndex(policies, i);
if (!isDictionary(policy))
FAIL("incorrect policy found");
policylevel = CFDictionaryGetValue(policy, kRASPropIPSecPolicyLevel);
if (!isString(policylevel) || CFEqual(policylevel, kRASValIPSecPolicyLevelNone))
continue;
else if (CFEqual(policylevel, kRASValIPSecPolicyLevelDiscard))
continue;
else if (!CFEqual(policylevel, kRASValIPSecPolicyLevelRequire))
FAIL("incorrect policy level found");
if (anonymous) {
snprintf(text, sizeof(text), "sainfo anonymous {\n");
}
else {
tunnel = 1;
policymode = CFDictionaryGetValue(policy, kRASPropIPSecPolicyMode);
if (isString(policymode)) {
if (CFEqual(policymode, kRASValIPSecPolicyModeTunnel))
tunnel = 1;
else if (CFEqual(policymode, kRASValIPSecPolicyModeTransport))
tunnel = 0;
else
FAIL("incorrect policy type found");
}
if (tunnel) {
if (!GetStrNetFromDict(policy, kRASPropIPSecPolicyLocalAddress, local_network, sizeof(local_network)))
FAIL("incorrect policy local network");
if (!GetStrNetFromDict(policy, kRASPropIPSecPolicyRemoteAddress, remote_network, sizeof(remote_network)))
FAIL("incorrect policy remote network");
GetIntFromDict(policy, kRASPropIPSecPolicyLocalPrefix, &local_prefix, 24);
if (local_prefix == 0)
FAIL("incorrect policy local prefix");
GetIntFromDict(policy, kRASPropIPSecPolicyRemotePrefix, &remote_prefix, 24);
if (remote_prefix == 0)
FAIL("incorrect policy remote prefix");
snprintf(text, sizeof(text), "sainfo address %s/%d 0 address %s/%d 0 {\n",
local_network, local_prefix,
remote_network, remote_prefix);
snprintf(text2, sizeof(text2), "sainfo address %s/%d 0 address %s/%d 0 {\n",
remote_network, remote_prefix,
local_network, local_prefix);
}
else {
GetIntFromDict(policy, kRASPropIPSecPolicyLocalPort, &local_port, 0);
GetIntFromDict(policy, kRASPropIPSecPolicyRemotePort, &remote_port, 0);
GetIntFromDict(policy, kRASPropIPSecPolicyProtocol, &protocol, 0);
snprintf(text, sizeof(text), "sainfo address %s/32 [%d] %d address %s/32 [%d] %d {\n",
local_address, local_port, protocol,
remote_address, remote_port, protocol);
snprintf(text2, sizeof(text2), "sainfo address %s/32 [%d] %d address %s/32 [%d] %d {\n",
remote_address, remote_port, protocol,
local_address, local_port, protocol);
}
}
WRITE(text);
if (configure_sainfo(level + 1, file, ipsec_dict, policy, errstr))
goto fail;
WRITE("}\n\n");
if ( !anonymous ){
WRITE(text2);
if (configure_sainfo(level + 1, file, ipsec_dict, policy, errstr))
goto fail;
WRITE("}\n\n");
}
}
no_policy:
;
}
fclose(file);
if (apply) {
racoon_restart();
}
return 0;
fail:
if (file)
fclose(file);
if (filename[0])
remove(filename);
return -1;
}
int
IPSecRemoveConfiguration(CFDictionaryRef ipsec_dict, char **errstr)
{
int anonymous;
char filename[256];
char remote_address[32];
filename[0] = 0;
if (!isDictionary(ipsec_dict))
FAIL("IPSec dictionary not present");
if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecRemoteAddress, remote_address, sizeof(remote_address)))
FAIL("incorrect remote address found");
anonymous = inet_addr(remote_address) == 0;
if (anonymous)
return 0;
snprintf(filename, sizeof(filename), RACOON_CONFIG_PATH "/%s.conf", remote_address);
remove(filename);
racoon_restart();
return 0;
fail:
return -1;
}
int
IPSecRemoveConfigurationFile(CFDictionaryRef ipsec_dict, char **errstr)
{
int anonymous;
char filename[256];
char remote_address[32];
filename[0] = 0;
if (!isDictionary(ipsec_dict))
FAIL("IPSec dictionary not present");
if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecRemoteAddress, remote_address, sizeof(remote_address)))
FAIL("incorrect remote address found");
anonymous = inet_addr(remote_address) == 0;
if (anonymous)
return 0;
snprintf(filename, sizeof(filename), RACOON_CONFIG_PATH "/%s.conf", remote_address);
remove(filename);
return 0;
fail:
return -1;
}
int
IPSecKickConfiguration()
{
racoon_restart();
return 0;
}
int
IPSecCountPolicies(CFDictionaryRef ipsec_dict)
{
CFArrayRef policies;
policies = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecPolicies);
if (isArray(policies))
return CFArrayGetCount(policies);
return 0;
}
int
IPSecInstallPolicies(CFDictionaryRef ipsec_dict, CFIndex index, char ** errstr)
{
int s = -1, err, seq = 0, i, nb;
char policystr_in[64], policystr_out[64], src_address[32], dst_address[32], str[32];
caddr_t policy_in = 0, policy_out = 0;
u_int32_t policylen_in, policylen_out, local_prefix, remote_prefix;
u_int32_t protocol = 0xFF;
CFArrayRef policies;
struct sockaddr_in local_net;
struct sockaddr_in remote_net;
CFIndex start, end;
s = pfkey_open();
if (s < 0)
FAIL("cannot open a pfkey socket");
if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecLocalAddress, src_address, sizeof(src_address)))
FAIL("incorrect local address");
if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecRemoteAddress, dst_address, sizeof(dst_address)))
FAIL("incorrect remote address");
policies = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecPolicies);
if (!isArray(policies)
|| (nb = CFArrayGetCount(policies)) == 0
|| index > nb)
FAIL("no policies found");
if (index == -1) {
start = 0;
end = nb;
}
else {
start = index;
end = index + 1;
}
for (i = start; i < end; i++) {
int tunnel, in, out;
CFDictionaryRef policy;
CFStringRef policymode, policydirection, policylevel;
policy = CFArrayGetValueAtIndex(policies, i);
if (!isDictionary(policy))
FAIL("incorrect policy found");
tunnel = 1;
policymode = CFDictionaryGetValue(policy, kRASPropIPSecPolicyMode);
if (isString(policymode)) {
if (CFEqual(policymode, kRASValIPSecPolicyModeTunnel))
tunnel = 1;
else if (CFEqual(policymode, kRASValIPSecPolicyModeTransport))
tunnel = 0;
else
FAIL("incorrect policy type found");
}
in = out = 1;
policydirection = CFDictionaryGetValue(policy, kRASPropIPSecPolicyDirection);
if (isString(policydirection)) {
if (CFEqual(policydirection, kRASValIPSecPolicyDirectionIn))
out = 0;
else if (CFEqual(policydirection, kRASValIPSecPolicyDirectionOut))
in = 0;
else if (!CFEqual(policydirection, kRASValIPSecPolicyDirectionInOut))
FAIL("incorrect policy direction found");
}
policylevel = CFDictionaryGetValue(policy, kRASPropIPSecPolicyLevel);
if (!isString(policylevel) || CFEqual(policylevel, kRASValIPSecPolicyLevelNone)) {
snprintf(policystr_out, sizeof(policystr_out), "out none");
snprintf(policystr_in, sizeof(policystr_in), "in none");
}
else if (CFEqual(policylevel, kRASValIPSecPolicyLevelUnique)) {
if (tunnel) {
snprintf(policystr_out, sizeof(policystr_out), "out ipsec esp/tunnel/%s-%s/unique", src_address, dst_address);
snprintf(policystr_in, sizeof(policystr_in), "in ipsec esp/tunnel/%s-%s/unique", dst_address, src_address);
}
else {
snprintf(policystr_out, sizeof(policystr_out), "out ipsec esp/transport//unique");
snprintf(policystr_in, sizeof(policystr_in), "in ipsec esp/transport//unique");
}
}
else if (CFEqual(policylevel, kRASValIPSecPolicyLevelRequire)) {
if (tunnel) {
snprintf(policystr_out, sizeof(policystr_out), "out ipsec esp/tunnel/%s-%s/require", src_address, dst_address);
snprintf(policystr_in, sizeof(policystr_in), "in ipsec esp/tunnel/%s-%s/require", dst_address, src_address);
}
else {
snprintf(policystr_out, sizeof(policystr_out), "out ipsec esp/transport//require");
snprintf(policystr_in, sizeof(policystr_in), "in ipsec esp/transport//require");
}
}
else if (CFEqual(policylevel, kRASValIPSecPolicyLevelDiscard)) {
snprintf(policystr_out, sizeof(policystr_out), "out discard");
snprintf(policystr_in, sizeof(policystr_in), "in discard");
}
else
FAIL("incorrect policy level");
policy_in = ipsec_set_policy(policystr_in, strlen(policystr_in));
if (policy_in == 0)
FAIL("cannot set policy in");
policy_out = ipsec_set_policy(policystr_out, strlen(policystr_out));
if (policy_out == 0)
FAIL("cannot set policy out");
policylen_in = ((struct sadb_x_policy *)policy_in)->sadb_x_policy_len << 3;
policylen_out = ((struct sadb_x_policy *)policy_out)->sadb_x_policy_len << 3;
if (tunnel) {
if (!GetStrNetFromDict(policy, kRASPropIPSecPolicyLocalAddress, str, sizeof(str)))
FAIL("incorrect local network");
local_net.sin_len = sizeof(local_net);
local_net.sin_family = AF_INET;
local_net.sin_port = htons(0);
if (!inet_aton(str, &local_net.sin_addr))
FAIL("incorrect local network");
GetIntFromDict(policy, kRASPropIPSecPolicyLocalPrefix, &local_prefix, 24);
if (!GetStrNetFromDict(policy, kRASPropIPSecPolicyRemoteAddress, str, sizeof(str)))
FAIL("incorrect remote network0");
remote_net.sin_len = sizeof(remote_net);
remote_net.sin_family = AF_INET;
remote_net.sin_port = htons(0);
if (!inet_aton(str, &remote_net.sin_addr))
FAIL("incorrect remote network1");
GetIntFromDict(policy, kRASPropIPSecPolicyRemotePrefix, &remote_prefix, 24);
}
else {
u_int32_t val;
local_net.sin_len = sizeof(local_net);
local_net.sin_family = AF_INET;
GetIntFromDict(policy, kRASPropIPSecPolicyLocalPort, &val, 0);
local_net.sin_port = htons(val);
if (!inet_aton(src_address, &local_net.sin_addr))
FAIL("incorrect local address");
local_prefix = local_net.sin_addr.s_addr ? 32 : 0;
remote_net.sin_len = sizeof(remote_net);
remote_net.sin_family = AF_INET;
GetIntFromDict(policy, kRASPropIPSecPolicyRemotePort, &val, 0);
remote_net.sin_port = htons(val);
if (!inet_aton(dst_address, &remote_net.sin_addr))
FAIL("incorrect remote address");
remote_prefix = remote_net.sin_addr.s_addr ? 32 : 0;
GetIntFromDict(policy, kRASPropIPSecPolicyProtocol, &protocol, 0);
}
if (out) {
err = pfkey_send_spdadd(s, (struct sockaddr *)&local_net, local_prefix, (struct sockaddr *)&remote_net, remote_prefix, protocol, policy_out, policylen_out, seq++);
if (err < 0)
FAIL("cannot add policy out");
}
if (in) {
err = pfkey_send_spdadd(s, (struct sockaddr *)&remote_net, remote_prefix, (struct sockaddr *)&local_net, local_prefix, protocol, policy_in, policylen_in, seq++);
if (err < 0)
FAIL("cannot add policy in");
}
free(policy_in);
free(policy_out);
policy_in = 0;
policy_out = 0;
}
pfkey_close(s);
return 0;
fail:
if (policy_in)
free(policy_in);
if (policy_out)
free(policy_out);
if (s != -1)
pfkey_close(s);
return -1;
}
static int
install_remove_routes(int cmd, CFDictionaryRef ipsec_dict, CFIndex index, char ** errstr, struct in_addr gateway)
{
int s = -1, i, nb;
char src_address[32], dst_address[32], str[32];
u_int32_t remote_prefix;
CFArrayRef policies;
struct sockaddr_in local_net;
struct sockaddr_in remote_net;
CFIndex start, end;
int len;
int rtm_seq = 0;
struct {
struct rt_msghdr hdr;
struct sockaddr_in dst;
struct sockaddr_in gway;
struct sockaddr_in mask;
} rtmsg;
s = socket(PF_ROUTE, SOCK_RAW, AF_INET);
if (s < 0)
FAIL("cannot open a routing socket");
if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecLocalAddress, src_address, sizeof(src_address)))
FAIL("incorrect local address");
if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecRemoteAddress, dst_address, sizeof(dst_address)))
FAIL("incorrect remote address");
policies = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecPolicies);
if (!isArray(policies)
|| (nb = CFArrayGetCount(policies)) == 0
|| index > nb)
FAIL("no policies found");
if (index == -1) {
start = 0;
end = nb;
}
else {
start = index;
end = index + 1;
}
for (i = start; i < end; i++) {
int tunnel, in, out;
CFDictionaryRef policy;
CFStringRef policymode, policydirection, policylevel;
policy = CFArrayGetValueAtIndex(policies, i);
if (!isDictionary(policy))
FAIL("incorrect policy found");
tunnel = 1;
policymode = CFDictionaryGetValue(policy, kRASPropIPSecPolicyMode);
if (isString(policymode)) {
if (CFEqual(policymode, kRASValIPSecPolicyModeTunnel))
tunnel = 1;
else if (CFEqual(policymode, kRASValIPSecPolicyModeTransport))
tunnel = 0;
else
FAIL("incorrect policy type found");
}
if (tunnel == 0)
continue;
in = out = 1;
policydirection = CFDictionaryGetValue(policy, kRASPropIPSecPolicyDirection);
if (isString(policydirection)) {
if (CFEqual(policydirection, kRASValIPSecPolicyDirectionIn))
out = 0;
else if (CFEqual(policydirection, kRASValIPSecPolicyDirectionOut))
in = 0;
else if (!CFEqual(policydirection, kRASValIPSecPolicyDirectionInOut))
FAIL("incorrect policy direction found");
}
if (out == 0)
continue;
policylevel = CFDictionaryGetValue(policy, kRASPropIPSecPolicyLevel);
if (!isString(policylevel) || CFEqual(policylevel, kRASValIPSecPolicyLevelNone))
continue;
if (!CFEqual(policylevel, kRASValIPSecPolicyLevelRequire) && !CFEqual(policylevel, kRASValIPSecPolicyLevelDiscard) && !CFEqual(policylevel, kRASValIPSecPolicyLevelUnique))
FAIL("incorrect policy level");
if (!GetStrNetFromDict(policy, kRASPropIPSecPolicyLocalAddress, str, sizeof(str)))
FAIL("incorrect local network");
local_net.sin_len = sizeof(local_net);
local_net.sin_family = AF_INET;
local_net.sin_port = htons(0);
if (!inet_aton(str, &local_net.sin_addr))
FAIL("incorrect local network");
if (!GetStrNetFromDict(policy, kRASPropIPSecPolicyRemoteAddress, str, sizeof(str)))
FAIL("incorrect remote network0");
remote_net.sin_len = sizeof(remote_net);
remote_net.sin_family = AF_INET;
remote_net.sin_port = htons(0);
if (!inet_aton(str, &remote_net.sin_addr))
FAIL("incorrect remote network1");
memset(&rtmsg, 0, sizeof(rtmsg));
rtmsg.hdr.rtm_type = cmd;
rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
rtmsg.hdr.rtm_flags |= RTF_GATEWAY;
rtmsg.hdr.rtm_version = RTM_VERSION;
rtmsg.hdr.rtm_seq = ++rtm_seq;
rtmsg.hdr.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
rtmsg.dst.sin_len = sizeof(rtmsg.dst);
rtmsg.dst.sin_family = AF_INET;
rtmsg.dst.sin_addr = remote_net.sin_addr;
rtmsg.gway.sin_len = sizeof(rtmsg.gway);
rtmsg.gway.sin_family = AF_INET;
rtmsg.gway.sin_addr = gateway;
rtmsg.mask.sin_len = sizeof(rtmsg.mask);
rtmsg.mask.sin_family = AF_INET;
GetIntFromDict(policy, kRASPropIPSecPolicyRemotePrefix, &remote_prefix, 24);
for (rtmsg.mask.sin_addr.s_addr = 0; remote_prefix; remote_prefix--)
rtmsg.mask.sin_addr.s_addr = (rtmsg.mask.sin_addr.s_addr>>1)|0x80000000;
rtmsg.mask.sin_addr.s_addr = htonl(rtmsg.mask.sin_addr.s_addr);
len = sizeof(rtmsg);
rtmsg.hdr.rtm_msglen = len;
if (write(s, &rtmsg, len) < 0)
printf("cannot write on routing socket %d (0x%x --> 0x%x)\n", errno, htonl(remote_net.sin_addr.s_addr), htonl(gateway.s_addr)); ;
}
close(s);
return 0;
fail:
if (s != -1)
close(s);
return -1;
}
int
IPSecInstallRoutes(CFDictionaryRef ipsec_dict, CFIndex index, char ** errstr, struct in_addr gateway)
{
return install_remove_routes(RTM_ADD, ipsec_dict, index, errstr, gateway);
}
int
IPSecRemoveRoutes(CFDictionaryRef ipsec_dict, CFIndex index, char ** errstr, struct in_addr gateway)
{
return install_remove_routes(RTM_DELETE, ipsec_dict, index, errstr, gateway);
}
int
IPSecRemovePolicies(CFDictionaryRef ipsec_dict, CFIndex index, char ** errstr)
{
int s = -1, err, seq = 0, nb, i;
char policystr_in[64], policystr_out[64], str[32];
caddr_t policy_in = 0, policy_out = 0;
u_int32_t policylen_in, policylen_out, local_prefix, remote_prefix;
u_int32_t protocol = 0xFF;
CFArrayRef policies;
struct sockaddr_in local_net;
struct sockaddr_in remote_net;
char src_address[32], dst_address[32];
CFIndex start, end;
s = pfkey_open();
if (s < 0)
FAIL("cannot open a pfkey socket");
if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecLocalAddress, src_address, sizeof(src_address)))
FAIL("incorrect local address");
if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecRemoteAddress, dst_address, sizeof(dst_address)))
FAIL("incorrect remote address");
policies = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecPolicies);
if (!isArray(policies)
|| (nb = CFArrayGetCount(policies)) == 0
|| index > nb)
FAIL("no policies found");
if (index == -1) {
start = 0;
end = nb;
}
else {
start = index;
end = index + 1;
}
for (i = start; i < end; i++) {
CFDictionaryRef policy;
int tunnel, in, out;
CFStringRef policymode, policydirection;
policy = CFArrayGetValueAtIndex(policies, i);
if (!isDictionary(policy))
FAIL("incorrect policy found");
tunnel = 1;
policymode = CFDictionaryGetValue(policy, kRASPropIPSecPolicyMode);
if (isString(policymode)) {
if (CFEqual(policymode, kRASValIPSecPolicyModeTunnel))
tunnel = 1;
else if (CFEqual(policymode, kRASValIPSecPolicyModeTransport))
tunnel = 0;
else
FAIL("incorrect policy type found");
}
in = out = 1;
policydirection = CFDictionaryGetValue(policy, kRASPropIPSecPolicyDirection);
if (isString(policydirection)) {
if (CFEqual(policydirection, kRASValIPSecPolicyDirectionIn))
out = 0;
else if (CFEqual(policydirection, kRASValIPSecPolicyDirectionOut))
in = 0;
else if (!CFEqual(policydirection, kRASValIPSecPolicyDirectionInOut))
FAIL("incorrect policy direction found");
}
snprintf(policystr_out, sizeof(policystr_out), "out");
snprintf(policystr_in, sizeof(policystr_in), "in");
policy_in = ipsec_set_policy(policystr_in, strlen(policystr_in));
if (policy_in == 0)
FAIL("cannot set policy in");
policy_out = ipsec_set_policy(policystr_out, strlen(policystr_out));
if (policy_out == 0)
FAIL("cannot set policy out");
policylen_in = ((struct sadb_x_policy *)policy_in)->sadb_x_policy_len << 3;
policylen_out = ((struct sadb_x_policy *)policy_out)->sadb_x_policy_len << 3;
if (tunnel) {
if (!GetStrNetFromDict(policy, kRASPropIPSecPolicyLocalAddress, str, sizeof(str)))
FAIL("incorrect local network");
local_net.sin_len = sizeof(local_net);
local_net.sin_family = AF_INET;
local_net.sin_port = htons(0);
if (!inet_aton(str, &local_net.sin_addr))
FAIL("incorrect local network");
GetIntFromDict(policy, kRASPropIPSecPolicyLocalPrefix, &local_prefix, 24);
if (!GetStrNetFromDict(policy, kRASPropIPSecPolicyRemoteAddress, str, sizeof(str)))
FAIL("incorrect remote network");
remote_net.sin_len = sizeof(remote_net);
remote_net.sin_family = AF_INET;
remote_net.sin_port = htons(0);
if (!inet_aton(str, &remote_net.sin_addr))
FAIL("incorrect remote network");
GetIntFromDict(policy, kRASPropIPSecPolicyRemotePrefix, &remote_prefix, 24);
}
else {
u_int32_t val;
local_net.sin_len = sizeof(local_net);
local_net.sin_family = AF_INET;
GetIntFromDict(policy, kRASPropIPSecPolicyLocalPort, &val, 0);
local_net.sin_port = htons(val);
if (!inet_aton(src_address, &local_net.sin_addr))
FAIL("incorrect local address");
local_prefix = local_net.sin_addr.s_addr ? 32 : 0;
remote_net.sin_len = sizeof(remote_net);
remote_net.sin_family = AF_INET;
GetIntFromDict(policy, kRASPropIPSecPolicyRemotePort, &val, 0);
remote_net.sin_port = htons(val);
if (!inet_aton(dst_address, &remote_net.sin_addr))
FAIL("incorrect remote address");
remote_prefix = remote_net.sin_addr.s_addr ? 32 : 0;
GetIntFromDict(policy, kRASPropIPSecPolicyProtocol, &protocol, 0);
}
if (out) {
err = pfkey_send_spddelete(s, (struct sockaddr *)&local_net, local_prefix, (struct sockaddr *)&remote_net, remote_prefix, protocol, policy_out, policylen_out, seq++);
if (err < 0)
FAIL("cannot delete policy out");
}
if (in) {
err = pfkey_send_spddelete(s, (struct sockaddr *)&remote_net, remote_prefix, (struct sockaddr *)&local_net, local_prefix, protocol, policy_in, policylen_in, seq++);
if (err < 0)
FAIL("cannot delete policy in");
}
free(policy_in);
free(policy_out);
policy_in = 0;
policy_out = 0;
}
pfkey_close(s);
return 0;
fail:
if (policy_in)
free(policy_in);
if (policy_out)
free(policy_out);
if (s != -1)
pfkey_close(s);
return -1;
}
int
IPSecRemoveSecurityAssociations(struct sockaddr *src, struct sockaddr *dst)
{
int s, err;
s = pfkey_open();
if (s < 0)
return -1;
err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
if (err < 0)
goto end;
err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
if (err < 0)
goto end;
end:
pfkey_close(s);
return err;
}
#define ROUNDUP(a, size) \
(((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
sizeof(u_int32_t)) :\
sizeof(u_int32_t)))
static void
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
{
int i;
for (i = 0; i < RTAX_MAX; i++) {
if (addrs & (1 << i)) {
rti_info[i] = sa;
NEXT_SA(sa);
addrs ^= (1 << i);
} else
rti_info[i] = NULL;
}
}
#define BUFLEN (sizeof(struct rt_msghdr) + 512)
void
sockaddr_to_string(const struct sockaddr *address, char *buf, size_t bufLen)
{
bzero(buf, bufLen);
switch (address->sa_family) {
case AF_INET :
(void)inet_ntop(((struct sockaddr_in *)address)->sin_family,
&((struct sockaddr_in *)address)->sin_addr,
buf,
bufLen);
break;
case AF_INET6 : {
(void)inet_ntop(((struct sockaddr_in6 *)address)->sin6_family,
&((struct sockaddr_in6 *)address)->sin6_addr,
buf,
bufLen);
if (((struct sockaddr_in6 *)address)->sin6_scope_id) {
int n;
n = strlen(buf);
if ((n+IF_NAMESIZE+1) <= bufLen) {
buf[n++] = '%';
if_indextoname(((struct sockaddr_in6 *)address)->sin6_scope_id, &buf[n]);
}
}
break;
}
case AF_LINK :
if (((struct sockaddr_dl *)address)->sdl_len < bufLen) {
bufLen = ((struct sockaddr_dl *)address)->sdl_len;
} else {
bufLen = bufLen - 1;
}
bcopy(((struct sockaddr_dl *)address)->sdl_data, buf, bufLen);
break;
default :
snprintf(buf, bufLen, "unexpected address family %d", address->sa_family);
break;
}
}
int
get_src_address(struct sockaddr *src, const struct sockaddr *dst, char *if_name)
{
char buf[BUFLEN];
struct rt_msghdr *rtm;
pid_t pid = getpid();
int rsock = -1, seq = 0, n;
struct sockaddr *rti_info[RTAX_MAX], *sa;
struct sockaddr_dl *sdl;
rsock = socket(PF_ROUTE, SOCK_RAW, 0);
if (rsock == -1)
return -1;
bzero(&buf, sizeof(buf));
rtm = (struct rt_msghdr *)&buf;
rtm->rtm_msglen = sizeof(struct rt_msghdr);
rtm->rtm_version = RTM_VERSION;
rtm->rtm_type = RTM_GET;
rtm->rtm_flags = RTF_STATIC|RTF_UP|RTF_HOST|RTF_GATEWAY;
rtm->rtm_addrs = RTA_DST|RTA_IFP;
rtm->rtm_pid = pid;
rtm->rtm_seq = ++seq;
sa = (struct sockaddr *) (rtm + 1);
bcopy(dst, sa, dst->sa_len);
rtm->rtm_msglen += sa->sa_len;
sdl = (struct sockaddr_dl *) ((void *)sa + sa->sa_len);
sdl->sdl_family = AF_LINK;
sdl->sdl_len = sizeof (struct sockaddr_dl);
rtm->rtm_msglen += sdl->sdl_len;
do {
n = write(rsock, &buf, rtm->rtm_msglen);
if (n == -1 && errno != EINTR) {
close(rsock);
return -1;
}
} while (n == -1);
do {
do {
n = read(rsock, (void *)&buf, sizeof(buf));
if (n == -1 && errno != EINTR) {
close(rsock);
return -1;
}
} while (n == -1);
} while (rtm->rtm_type != RTM_GET
|| rtm->rtm_seq != seq
|| rtm->rtm_pid != pid);
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
#if 0
{
int i;
char buf[200];
for (i=0; i<RTAX_MAX; i++) {
if (rti_info[i] != NULL) {
sockaddr_to_string(rti_info[i], buf, sizeof(buf));
printf("%d: %s\n", i, buf);
}
}
}
#endif
bcopy(rti_info[5], src, rti_info[5]->sa_len);
if (if_name)
strncpy(if_name, ((struct sockaddr_dl *)rti_info[4])->sdl_data, IF_NAMESIZE);
close(rsock);
return 0;
}
u_int32_t
get_if_mtu(char *if_name)
{
struct ifreq ifr;
int s, err;
ifr.ifr_mtu = 1500;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s >= 0) {
strlcpy(ifr.ifr_name, if_name, sizeof (ifr.ifr_name));
if ((err = ioctl(s, SIOCGIFMTU, (caddr_t) &ifr)) < 0)
;
close(s);
}
return ifr.ifr_mtu;
}
u_int32_t
get_if_media(char *if_name)
{
struct ifmediareq ifr;
int s, err;
bzero(&ifr, sizeof(ifr));
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s >= 0) {
strlcpy(ifr.ifm_name, if_name, sizeof (ifr.ifm_name));
if ((err = ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifr)) < 0) {
}
close(s);
}
return ifr.ifm_current;
}
u_int32_t
get_if_baudrate(char *if_name)
{
char * buf = NULL;
size_t buf_len = 0;
struct if_msghdr * ifm;
unsigned int if_index;
u_int32_t baudrate = 0;
int mib[6];
if_index = if_nametoindex(if_name);
if (if_index == 0) {
goto done; }
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_LINK;
mib[4] = NET_RT_IFLIST;
mib[5] = if_index;
if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) < 0) {
goto done;
}
buf = malloc(buf_len);
if (sysctl(mib, 6, buf, &buf_len, NULL, 0) < 0) {
goto done;
}
ifm = (struct if_msghdr *)buf;
switch (ifm->ifm_type) {
case RTM_IFINFO : {
baudrate = ifm->ifm_data.ifi_baudrate;
break;
}
}
done :
if (buf != NULL)
free(buf);
return baudrate;
}
int IPSecSetSecurityAssociationsPreference(int *oldval, int newval)
{
size_t len = sizeof(int);
if (newval != 0 && newval != 1)
return 0;
return sysctlbyname("net.key.prefered_oldsa", oldval, &len, &newval, sizeof(int));
}
CFMutableDictionaryRef
IPSecCreateL2TPDefaultConfiguration(struct sockaddr *src, struct sockaddr *dst, char *dst_hostName, CFStringRef authenticationMethod,
int isClient, int natt_multiple_users, CFStringRef identifierVerification)
{
CFStringRef src_string, dst_string, hostname_string = NULL;
CFMutableDictionaryRef ipsec_dict, policy0, policy1 = NULL;
CFMutableArrayRef policy_array, encryption_array, hash_array;
#if 0
CFMutableDictionaryRef proposal_dict;
CFMutableArrayRef proposal_array;
#endif
CFNumberRef src_port_num, dst_port_num, dst_port1_num, proto_num, natt_multiuser_mode = NULL;
int zero = 0, one = 1, udpproto = IPPROTO_UDP, val;
struct sockaddr_in *our_address = (struct sockaddr_in *)src;
struct sockaddr_in *peer_address = (struct sockaddr_in *)dst;
ipsec_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (dst_hostName)
hostname_string = CFStringCreateWithCString(0, dst_hostName, kCFStringEncodingASCII);
src_string = CFStringCreateWithCString(0, addr2ascii(AF_INET, &our_address->sin_addr, sizeof(our_address->sin_addr), 0), kCFStringEncodingASCII);
dst_string = CFStringCreateWithCString(0, addr2ascii(AF_INET, &peer_address->sin_addr, sizeof(peer_address->sin_addr), 0), kCFStringEncodingASCII);
val = ntohs(our_address->sin_port);
src_port_num = CFNumberCreate(0, kCFNumberIntType, &val);
val = ntohs(peer_address->sin_port);
dst_port_num = CFNumberCreate(0, kCFNumberIntType, &val);
dst_port1_num = CFNumberCreate(0, kCFNumberIntType, &zero);
proto_num = CFNumberCreate(0, kCFNumberIntType, &udpproto);
if (!isClient)
natt_multiuser_mode = CFNumberCreate(0, kCFNumberIntType, natt_multiple_users ? &one : &zero);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecAuthenticationMethod, authenticationMethod);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecLocalAddress, src_string);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecRemoteAddress, dst_string);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecProposalsBehavior, isClient ? kRASValIPSecProposalsBehaviorObey : kRASValIPSecProposalsBehaviorClaim);
if (isClient && CFEqual(authenticationMethod, kRASValIPSecAuthenticationMethodCertificate)) {
if (identifierVerification) {
CFDictionarySetValue(ipsec_dict, kRASPropIPSecIdentifierVerification, identifierVerification);
}
else {
if (dst_hostName) {
CFDictionarySetValue(ipsec_dict, kRASPropIPSecRemoteIdentifier, hostname_string);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecIdentifierVerification, kRASValIPSecIdentifierVerificationUseRemoteIdentifier);
} else
CFDictionarySetValue(ipsec_dict, kRASPropIPSecIdentifierVerification, kRASValIPSecIdentifierVerificationGenerateFromRemoteAddress);
}
} else
CFDictionarySetValue(ipsec_dict, kRASPropIPSecIdentifierVerification, kRASValIPSecIdentifierVerificationNone);
if (!isClient)
CFDictionarySetValue(ipsec_dict, kRASPropIPSecNattMultipleUsersEnabled, natt_multiuser_mode);
#if 0
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecAuthenticationMethod, authenticationMethod);
proposal_array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(proposal_array, 0, proposal_dict);
CFRelease(proposal_dict);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecProposals, proposal_array);
CFRelease(proposal_array);
#endif
policy0 = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyLocalPort, src_port_num);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyRemotePort, dst_port_num);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyProtocol, proto_num);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyMode, kRASValIPSecPolicyModeTransport);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyLevel, kRASValIPSecPolicyLevelRequire);
encryption_array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(encryption_array, 0, kRASValIPSecPolicyEncryptionAlgorithmAES);
CFArraySetValueAtIndex(encryption_array, 1, kRASValIPSecPolicyEncryptionAlgorithm3DES);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyEncryptionAlgorithm, encryption_array);
CFRelease(encryption_array);
hash_array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(hash_array, 0, kRASValIPSecPolicyHashAlgorithmSHA1);
CFArraySetValueAtIndex(hash_array, 1, kRASValIPSecPolicyHashAlgorithmMD5);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyHashAlgorithm, hash_array);
CFRelease(hash_array);
if (isClient) {
policy1 = CFDictionaryCreateMutableCopy(0, 0, policy0);
CFDictionarySetValue(policy1, kRASPropIPSecPolicyRemotePort, dst_port1_num);
CFDictionarySetValue(policy1, kRASPropIPSecPolicyDirection, kRASValIPSecPolicyDirectionIn);
}
policy_array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(policy_array, 0, policy0);
if (isClient)
CFArraySetValueAtIndex(policy_array, 1, policy1);
CFRelease(policy0);
if (isClient)
CFRelease(policy1);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecPolicies, policy_array);
CFRelease(policy_array);
CFRelease(src_string);
CFRelease(dst_string);
CFRelease(src_port_num);
CFRelease(dst_port_num);
CFRelease(proto_num);
if (!isClient)
CFRelease(natt_multiuser_mode);
if (hostname_string)
CFRelease(hostname_string);
return ipsec_dict;
}
CFMutableDictionaryRef
IPSecCreateCiscoDefaultConfiguration(struct sockaddr *src, struct sockaddr *dst, CFStringRef dst_hostName, CFStringRef authenticationMethod,
int isClient, int natt_multiple_users, CFStringRef identifierVerification)
{
CFStringRef src_string, dst_string;
CFMutableDictionaryRef ipsec_dict, proposal_dict;
CFMutableArrayRef proposal_array;
#if 0
CFMutableDictionaryRef policy0, policy1 = NULL;
CFMutableArrayRef policy_array, encryption_array, hash_array;
#endif
CFNumberRef src_port_num, dst_port_num, dst_port1_num, proto_num, natt_multiuser_mode = NULL, cfone = NULL, cfzero = NULL, dhgroup, lifetime, dpd_delay;
int zero = 0, one = 1, anyproto = -1, val, nb;
struct sockaddr_in *our_address = (struct sockaddr_in *)src;
struct sockaddr_in *peer_address = (struct sockaddr_in *)dst;
#define ADD_DHGROUP5 1
#ifdef ADD_DHGROUP5
int add_group5 = 0, val5 = 5;
CFNumberRef dhgroup5 = NULL;
#endif
ipsec_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
src_string = CFStringCreateWithCString(0, addr2ascii(AF_INET, &our_address->sin_addr, sizeof(our_address->sin_addr), 0), kCFStringEncodingASCII);
dst_string = CFStringCreateWithCString(0, addr2ascii(AF_INET, &peer_address->sin_addr, sizeof(peer_address->sin_addr), 0), kCFStringEncodingASCII);
val = ntohs(our_address->sin_port);
src_port_num = CFNumberCreate(0, kCFNumberIntType, &val);
val = ntohs(peer_address->sin_port);
dst_port_num = CFNumberCreate(0, kCFNumberIntType, &val);
dst_port1_num = CFNumberCreate(0, kCFNumberIntType, &zero);
proto_num = CFNumberCreate(0, kCFNumberIntType, &anyproto);
if (!isClient)
natt_multiuser_mode = CFNumberCreate(0, kCFNumberIntType, natt_multiple_users ? &one : &zero);
cfzero = CFNumberCreate(0, kCFNumberIntType, &zero);
cfone = CFNumberCreate(0, kCFNumberIntType, &one);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecModeConfigEnabled, cfone);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecXAuthEnabled, cfone);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecLocalAddress, src_string);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecRemoteAddress, dst_string);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecProposalsBehavior, isClient ? kRASValIPSecProposalsBehaviorObey : kRASValIPSecProposalsBehaviorClaim);
if (isClient && CFEqual(authenticationMethod, kRASValIPSecAuthenticationMethodCertificate)) {
#ifdef ADD_DHGROUP5
add_group5 = 1;
#endif
if (identifierVerification) {
CFDictionarySetValue(ipsec_dict, kRASPropIPSecIdentifierVerification, identifierVerification);
}
else {
if (dst_hostName) {
CFDictionarySetValue(ipsec_dict, kRASPropIPSecRemoteIdentifier, dst_hostName);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecIdentifierVerification, kRASValIPSecIdentifierVerificationUseRemoteIdentifier);
} else
CFDictionarySetValue(ipsec_dict, kRASPropIPSecIdentifierVerification, kRASValIPSecIdentifierVerificationGenerateFromRemoteAddress);
}
} else
CFDictionarySetValue(ipsec_dict, kRASPropIPSecIdentifierVerification, kRASValIPSecIdentifierVerificationNone);
if (!isClient)
CFDictionarySetValue(ipsec_dict, kRASPropIPSecNattMultipleUsersEnabled, natt_multiuser_mode);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecDeadPeerDetectionEnabled, cfone);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecBlackHoleDetectionEnabled, cfone);
val = 20; dpd_delay = CFNumberCreate(0, kCFNumberIntType, &val);
if (dpd_delay) {
CFDictionarySetValue(ipsec_dict, kRASPropIPSecDeadPeerDetectionDelay, dpd_delay);
CFRelease(dpd_delay);
}
#if 1
proposal_array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
val = 3600;
lifetime = CFNumberCreate(0, kCFNumberIntType, &val);
nb = 0;
int i, dh_group[] = { 2, 0 };
for (i = 0; val = dh_group[i]; i++) {
dhgroup = CFNumberCreate(0, kCFNumberIntType, &val);
#ifdef ADD_DHGROUP5
if (add_group5)
dhgroup5 = CFNumberCreate(0, kCFNumberIntType, &val5);
#endif
#ifdef ADD_DHGROUP5
if (add_group5) {
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm, kRASValIPSecProposalEncryptionAlgorithmAES256);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm, kRASValIPSecProposalHashAlgorithmSHA1);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalDHGroup, dhgroup5);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalLifetime, lifetime);
CFArraySetValueAtIndex(proposal_array, nb++, proposal_dict);
CFRelease(proposal_dict);
}
#endif
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm, kRASValIPSecProposalEncryptionAlgorithmAES256);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm, kRASValIPSecProposalHashAlgorithmSHA1);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalDHGroup, dhgroup);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalLifetime, lifetime);
CFArraySetValueAtIndex(proposal_array, nb++, proposal_dict);
CFRelease(proposal_dict);
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm, kRASValIPSecProposalEncryptionAlgorithmAES);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm, kRASValIPSecProposalHashAlgorithmSHA1);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalDHGroup, dhgroup);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalLifetime, lifetime);
CFArraySetValueAtIndex(proposal_array, nb++, proposal_dict);
CFRelease(proposal_dict);
#ifdef ADD_DHGROUP5
if (add_group5) {
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm, kRASValIPSecProposalEncryptionAlgorithmAES256);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm, kRASValIPSecProposalHashAlgorithmMD5);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalDHGroup, dhgroup5);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalLifetime, lifetime);
CFArraySetValueAtIndex(proposal_array, nb++, proposal_dict);
CFRelease(proposal_dict);
}
#endif
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm, kRASValIPSecProposalEncryptionAlgorithmAES256);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm, kRASValIPSecProposalHashAlgorithmMD5);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalDHGroup, dhgroup);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalLifetime, lifetime);
CFArraySetValueAtIndex(proposal_array, nb++, proposal_dict);
CFRelease(proposal_dict);
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm, kRASValIPSecProposalEncryptionAlgorithmAES);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm, kRASValIPSecProposalHashAlgorithmMD5);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalDHGroup, dhgroup);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalLifetime, lifetime);
CFArraySetValueAtIndex(proposal_array, nb++, proposal_dict);
CFRelease(proposal_dict);
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm, kRASValIPSecProposalEncryptionAlgorithm3DES);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm, kRASValIPSecProposalHashAlgorithmSHA1);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalDHGroup, dhgroup);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalLifetime, lifetime);
CFArraySetValueAtIndex(proposal_array, nb++, proposal_dict);
CFRelease(proposal_dict);
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm, kRASValIPSecProposalEncryptionAlgorithm3DES);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm, kRASValIPSecProposalHashAlgorithmMD5);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalDHGroup, dhgroup);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalLifetime, lifetime);
CFArraySetValueAtIndex(proposal_array, nb++, proposal_dict);
CFRelease(proposal_dict);
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm, kRASValIPSecProposalEncryptionAlgorithmDES);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm, kRASValIPSecProposalHashAlgorithmSHA1);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalDHGroup, dhgroup);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalLifetime, lifetime);
CFArraySetValueAtIndex(proposal_array, nb++, proposal_dict);
CFRelease(proposal_dict);
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm, kRASValIPSecProposalEncryptionAlgorithmDES);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm, kRASValIPSecProposalHashAlgorithmMD5);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalDHGroup, dhgroup);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalLifetime, lifetime);
CFArraySetValueAtIndex(proposal_array, nb++, proposal_dict);
CFRelease(proposal_dict);
CFRelease(dhgroup);
#ifdef ADD_DHGROUP5
if (add_group5)
CFRelease(dhgroup5);
#endif
}
CFRelease(lifetime);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecProposals, proposal_array);
CFRelease(proposal_array);
#endif
#if 0
policy0 = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyLocalPort, src_port_num);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyRemotePort, dst_port_num);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyProtocol, proto_num);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyMode, kRASValIPSecPolicyModeTransport);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyLevel, kRASValIPSecPolicyLevelRequire);
val = 0;
dhgroup = CFNumberCreate(0, kCFNumberIntType, &val);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyPFSGroup, dhgroup);
CFRelease(dhgroup);
val = 3600;
lifetime = CFNumberCreate(0, kCFNumberIntType, &val);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyLifetime, lifetime);
CFRelease(lifetime);
encryption_array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(encryption_array, 0, kRASValIPSecPolicyEncryptionAlgorithmAES);
CFArraySetValueAtIndex(encryption_array, 1, kRASValIPSecPolicyEncryptionAlgorithm3DES);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyEncryptionAlgorithm, encryption_array);
CFRelease(encryption_array);
hash_array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(hash_array, 0, kRASValIPSecPolicyHashAlgorithmSHA1);
CFArraySetValueAtIndex(hash_array, 1, kRASValIPSecPolicyHashAlgorithmMD5);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyHashAlgorithm, hash_array);
CFRelease(hash_array);
if (isClient) {
policy1 = CFDictionaryCreateMutableCopy(0, 0, policy0);
CFDictionarySetValue(policy1, kRASPropIPSecPolicyRemotePort, dst_port1_num);
CFDictionarySetValue(policy1, kRASPropIPSecPolicyDirection, kRASValIPSecPolicyDirectionIn);
}
policy_array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(policy_array, 0, policy0);
if (isClient)
CFArraySetValueAtIndex(policy_array, 1, policy1);
CFRelease(policy0);
if (isClient)
CFRelease(policy1);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecPolicies, policy_array);
CFRelease(policy_array);
#endif
#if 0
policy0 = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(ipsec_dict, CFSTR("UseAnonymousPolicy"), CFSTR("UseAnonymousPolicy"));
CFDictionarySetValue(policy0, kRASPropIPSecPolicyLocalPort, src_port_num);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyRemotePort, dst_port_num);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyProtocol, proto_num);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyMode, kRASValIPSecPolicyModeTransport);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyLevel, kRASValIPSecPolicyLevelRequire);
val = 0;
dhgroup = CFNumberCreate(0, kCFNumberIntType, &val);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyPFSGroup, dhgroup);
CFRelease(dhgroup);
val = 3600;
lifetime = CFNumberCreate(0, kCFNumberIntType, &val);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyLifetime, lifetime);
CFRelease(lifetime);
encryption_array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(encryption_array, 0, kRASValIPSecPolicyEncryptionAlgorithmAES);
CFArraySetValueAtIndex(encryption_array, 1, kRASValIPSecPolicyEncryptionAlgorithm3DES);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyEncryptionAlgorithm, encryption_array);
CFRelease(encryption_array);
hash_array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(hash_array, 0, kRASValIPSecPolicyHashAlgorithmSHA1);
CFArraySetValueAtIndex(hash_array, 1, kRASValIPSecPolicyHashAlgorithmMD5);
CFDictionarySetValue(policy0, kRASPropIPSecPolicyHashAlgorithm, hash_array);
CFRelease(hash_array);
if (isClient) {
policy1 = CFDictionaryCreateMutableCopy(0, 0, policy0);
CFDictionarySetValue(policy1, kRASPropIPSecPolicyRemotePort, dst_port1_num);
CFDictionarySetValue(policy1, kRASPropIPSecPolicyDirection, kRASValIPSecPolicyDirectionIn);
}
policy_array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
CFArraySetValueAtIndex(policy_array, 0, policy0);
if (isClient)
CFArraySetValueAtIndex(policy_array, 1, policy1);
CFRelease(policy0);
if (isClient)
CFRelease(policy1);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecPolicies, policy_array);
CFRelease(policy_array);
#endif
CFRelease(src_string);
CFRelease(dst_string);
CFRelease(src_port_num);
CFRelease(dst_port_num);
CFRelease(proto_num);
if (cfone)
CFRelease(cfone);
if (cfzero)
CFRelease(cfzero);
if (!isClient)
CFRelease(natt_multiuser_mode);
return ipsec_dict;
}
int
IPSecSelfRepair()
{
int err;
racoon_stop();
return 0;
}
static char unknown_if_family_str[16];
static char *
if_family2ascii (u_int32_t if_family)
{
switch (if_family) {
case APPLE_IF_FAM_LOOPBACK:
return("Loopback");
case APPLE_IF_FAM_ETHERNET:
return("Ether");
case APPLE_IF_FAM_SLIP:
return("SLIP");
case APPLE_IF_FAM_TUN:
return("TUN");
case APPLE_IF_FAM_VLAN:
return("VLAN");
case APPLE_IF_FAM_PPP:
return("PPP");
case APPLE_IF_FAM_PVC:
return("PVC");
case APPLE_IF_FAM_DISC:
return("DISC");
case APPLE_IF_FAM_MDECAP:
return("MDECAP");
case APPLE_IF_FAM_GIF:
return("GIF");
case APPLE_IF_FAM_FAITH:
return("FAITH");
case APPLE_IF_FAM_STF:
return("STF");
case APPLE_IF_FAM_FIREWIRE:
return("FireWire");
case APPLE_IF_FAM_BOND:
return("Bond");
default:
snprintf(unknown_if_family_str, sizeof(unknown_if_family_str), "%d", if_family);
return(unknown_if_family_str);
}
}
void
IPSecLogVPNInterfaceAddressEvent (char *location,
struct kern_event_msg *ev_msg,
int wait_interface_timeout,
char *interface,
struct in_addr *our_address)
{
struct in_addr mask;
char our_addr_str[INET_ADDRSTRLEN];
if (!ev_msg) {
syslog(LOG_NOTICE, "%s: %d secs TIMEOUT waiting for interface to be reconfigured. previous setting (name: %s, address: %s).",
location,
wait_interface_timeout,
interface,
addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str));
return;
} else {
struct kev_in_data *inetdata = (struct kev_in_data *) &ev_msg->event_data[0];
struct kev_in_collision *inetdata_coll = (struct kev_in_collision *) &ev_msg->event_data[0];
char new_addr_str[INET_ADDRSTRLEN];
char new_mask_str[INET_ADDRSTRLEN];
char dst_addr_str[INET_ADDRSTRLEN];
mask.s_addr = ntohl(inetdata->ia_netmask);
switch (ev_msg->event_code) {
case KEV_INET_NEW_ADDR:
syslog(LOG_NOTICE, "%s: Address added. previous interface setting (name: %s, address: %s), current interface setting (name: %s%d, family: %s, address: %s, subnet: %s, destination: %s).",
location,
interface,
addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str),
inetdata->link_data.if_name, inetdata->link_data.if_unit,
if_family2ascii(inetdata->link_data.if_family),
addr2ascii(AF_INET, &inetdata->ia_addr, sizeof(inetdata->ia_addr), new_addr_str),
addr2ascii(AF_INET, &mask, sizeof(mask), new_mask_str),
addr2ascii(AF_INET, &inetdata->ia_dstaddr, sizeof(inetdata->ia_dstaddr), dst_addr_str));
break;
case KEV_INET_CHANGED_ADDR:
syslog(LOG_NOTICE, "%s: Address changed. previous interface setting (name: %s, address: %s), current interface setting (name: %s%d, family: %s, address: %s, subnet: %s, destination: %s).",
location,
interface,
addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str),
inetdata->link_data.if_name, inetdata->link_data.if_unit,
if_family2ascii(inetdata->link_data.if_family),
addr2ascii(AF_INET, &inetdata->ia_addr, sizeof(inetdata->ia_addr), new_addr_str),
addr2ascii(AF_INET, &mask, sizeof(mask), new_mask_str),
addr2ascii(AF_INET, &inetdata->ia_dstaddr, sizeof(inetdata->ia_dstaddr), dst_addr_str));
break;
case KEV_INET_ADDR_DELETED:
syslog(LOG_NOTICE, "%s: Address deleted. previous interface setting (name: %s, address: %s), deleted interface setting (name: %s%d, family: %s, address: %s, subnet: %s, destination: %s).",
location,
interface,
addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str),
inetdata->link_data.if_name, inetdata->link_data.if_unit,
if_family2ascii(inetdata->link_data.if_family),
addr2ascii(AF_INET, &inetdata->ia_addr, sizeof(inetdata->ia_addr), new_addr_str),
addr2ascii(AF_INET, &mask, sizeof(mask), new_mask_str),
addr2ascii(AF_INET, &inetdata->ia_dstaddr, sizeof(inetdata->ia_dstaddr), dst_addr_str));
break;
case KEV_INET_ARPCOLLISION:
syslog(LOG_NOTICE, "%s: ARP collided. previous interface setting (name: %s, address: %s), conflicting interface setting (name: %s%d, family: %s, address: %s, mac: %x:%x:%x:%x:%x:%x).",
location,
interface,
addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str),
inetdata_coll->link_data.if_name,
inetdata_coll->link_data.if_unit,
if_family2ascii(inetdata_coll->link_data.if_family),
addr2ascii(AF_INET, &inetdata_coll->ia_ipaddr, sizeof(inetdata_coll->ia_ipaddr), new_addr_str),
inetdata_coll->hw_addr[5],inetdata_coll->hw_addr[4],inetdata_coll->hw_addr[3],inetdata_coll->hw_addr[2],inetdata_coll->hw_addr[1],inetdata_coll->hw_addr[0]);
break;
default:
syslog(LOG_NOTICE, "%s: Unknown Address event (%d). previous interface setting (name: %s, address: %s), other interface setting (name: %s%d, family: %s, address: %s, subnet: %s, destination: %s).",
location,
ev_msg->event_code,
interface,
addr2ascii(AF_INET, our_address, sizeof(*our_address), our_addr_str),
inetdata->link_data.if_name, inetdata->link_data.if_unit,
if_family2ascii(inetdata->link_data.if_family),
addr2ascii(AF_INET, &inetdata->ia_addr, sizeof(inetdata->ia_addr), new_addr_str),
addr2ascii(AF_INET, &mask, sizeof(mask), new_mask_str),
addr2ascii(AF_INET, &inetdata->ia_dstaddr, sizeof(inetdata->ia_dstaddr), dst_addr_str));
break;
}
}
}
int
IPSecCheckVPNInterfaceOrServiceUnrecoverable (void *dynamicStore,
char *location,
struct kern_event_msg *ev_msg,
char *interface_buf)
{
SCDynamicStoreRef dynamicStoreRef = (SCDynamicStoreRef)dynamicStore;
if (!dynamicStoreRef)
syslog(LOG_DEBUG, "%s: invalid SCDynamicStore reference", location);
if (dynamicStoreRef &&
(ev_msg->event_code == KEV_INET_ADDR_DELETED || ev_msg->event_code == KEV_INET_CHANGED_ADDR)) {
CFStringRef interf_key;
CFMutableArrayRef interf_keys;
CFStringRef pattern;
CFMutableArrayRef patterns;
CFDictionaryRef dict = NULL;
CFIndex i;
const void * keys_q[128];
const void ** keys = keys_q;
const void * values_q[128];
const void ** values = values_q;
CFIndex n;
CFStringRef vpn_if;
int other_serv_found = 0, interf_down = 0;
vpn_if = CFStringCreateWithCStringNoCopy(NULL,
interface_buf,
kCFStringEncodingASCII,
kCFAllocatorNull);
if (!vpn_if) {
syslog(LOG_NOTICE, "%s: failed to initialize interface CFString", location);
goto done;
}
interf_keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
interf_key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
kSCDynamicStoreDomainSetup,
vpn_if,
kSCEntNetAirPort);
CFArrayAppendValue(interf_keys, interf_key);
CFRelease(interf_key);
interf_key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
kSCDynamicStoreDomainState,
vpn_if,
kSCEntNetAirPort);
CFArrayAppendValue(interf_keys, interf_key);
CFRelease(interf_key);
pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainSetup,
kSCCompAnyRegex,
kSCEntNetInterface);
CFArrayAppendValue(patterns, pattern);
CFRelease(pattern);
pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainSetup,
kSCCompAnyRegex,
kSCEntNetIPv4);
CFArrayAppendValue(patterns, pattern);
CFRelease(pattern);
dict = SCDynamicStoreCopyMultiple(dynamicStoreRef, interf_keys, patterns);
CFRelease(interf_keys);
CFRelease(patterns);
if (!dict) {
syslog(LOG_NOTICE, "%s: failed to initialize SCDynamicStore dictionary", location);
goto done;
}
n = CFDictionaryGetCount(dict);
if (n <= 0) {
syslog(LOG_NOTICE, "%s: empty SCDynamicStore dictionary", location);
goto done;
}
if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
values = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
}
CFDictionaryGetKeysAndValues(dict, keys, values);
for (i=0; i < n; i++) {
CFStringRef s_key = (CFStringRef)keys[i];
CFDictionaryRef s_dict = (CFDictionaryRef)values[i];
CFStringRef s_if;
if (!isA_CFString(s_key) || !isA_CFDictionary(s_dict)) {
continue;
}
if (CFStringHasSuffix(s_key, kSCEntNetInterface)) {
s_if = CFDictionaryGetValue(s_dict, kSCPropNetInterfaceDeviceName);
if (isA_CFString(s_if) && CFEqual(vpn_if, s_if)) {
CFArrayRef components;
CFStringRef serviceIDRef = NULL, serviceKey = NULL;
CFPropertyListRef serviceRef = NULL;
syslog(LOG_NOTICE, "linked service found: %s \n", CFStringGetCStringPtr(s_key, kCFStringEncodingMacRoman));
other_serv_found = 1;
components = CFStringCreateArrayBySeparatingStrings(NULL, s_key, CFSTR("/"));
if (CFArrayGetCount(components) > 3) {
serviceIDRef = CFArrayGetValueAtIndex(components, 3);
serviceKey = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainSetup, serviceIDRef, kSCEntNetIPv4);
if (!serviceKey ||
!(serviceRef = CFDictionaryGetValue(dict, serviceKey))) {
syslog(LOG_NOTICE, "%s: detected disabled IPv4 Config", location);
interf_down = 1;
}
if (serviceKey) CFRelease(serviceKey);
}
if (components) CFRelease(components);
if (interf_down) break;
}
continue;
} else if (CFStringHasSuffix(s_key, kSCEntNetAirPort)) {
if (CFStringHasPrefix(s_key, kSCDynamicStoreDomainSetup)) {
CFBooleanRef powerEnable = CFDictionaryGetValue(s_dict, kSCPropNetAirPortPowerEnabled);
if (isA_CFBoolean(powerEnable) &&
CFEqual(powerEnable, kCFBooleanFalse)) {
syslog(LOG_NOTICE, "%s: detected AirPort, PowerEnable == FALSE", location);
interf_down = 1;
break;
}
} else if (CFStringHasPrefix(s_key, kSCDynamicStoreDomainState)) {
UInt16 temp;
CFNumberRef airStatus = CFDictionaryGetValue(s_dict, CFSTR("Power Status"));
if (isA_CFNumber(airStatus) &&
CFNumberGetValue(airStatus, kCFNumberShortType, &temp)) {
if (temp ==0) {
syslog(LOG_NOTICE, "%s: detected AirPort, PowerStatus == 0", location);
}
}
}
continue;
}
}
if (vpn_if) CFRelease(vpn_if);
if (keys != keys_q) {
CFAllocatorDeallocate(NULL, keys);
CFAllocatorDeallocate(NULL, values);
}
done :
if (dict) CFRelease(dict);
return (other_serv_found == 0 || interf_down == 1);
}
return 0;
}
int
IPSecCheckVPNInterfaceAddressChange (int transport_down,
struct kern_event_msg *ev_msg,
char *interface_buf,
struct in_addr *our_address)
{
struct kev_in_data *inetdata;
if (transport_down &&
(ev_msg->event_code == KEV_INET_NEW_ADDR || ev_msg->event_code == KEV_INET_CHANGED_ADDR)) {
inetdata = (struct kev_in_data *) &ev_msg->event_data[0];
#if 0
syslog(LOG_NOTICE, "%s: checking for interface address change. underlying %s, old-addr %x, new-addr %x\n",
__FUNCTION__, interface_buf, our_address->s_addr, inetdata->ia_addr.s_addr);
#endif
if (our_address->s_addr != inetdata->ia_addr.s_addr &&
!IN_LINKLOCAL(ntohl(inetdata->ia_addr.s_addr))) {
return 1;
}
}
return 0;
}
int
IPSecCheckVPNInterfaceAddressAlternate (int transport_down,
struct kern_event_msg *ev_msg,
char *interface_buf)
{
struct kev_in_data *inetdata;
if (transport_down &&
(ev_msg->event_code == KEV_INET_NEW_ADDR || ev_msg->event_code == KEV_INET_CHANGED_ADDR)) {
inetdata = (struct kev_in_data *) &ev_msg->event_data[0];
#if 0
syslog(LOG_NOTICE, "%s: checking for alternate interface. underlying %s, new-addr %x\n",
__FUNCTION__, interface_buf, inetdata->ia_addr.s_addr);
#endif
if (!IN_LINKLOCAL(ntohl(inetdata->ia_addr.s_addr))) {
return 1;
}
}
return 0;
}