#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 <sys/param.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; }
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_start(CFBundleRef bundle, char *filename);
static int racoon_restart(int launch_if_needed);
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 = 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_start(CFBundleRef bundle, char *filename)
{
int pid, err, tries;
CFURLRef url;
char name[MAXPATHLEN];
name[0] = 0;
if (bundle) {
if (url = CFBundleCopyBundleURL(bundle)) {
CFURLGetFileSystemRepresentation(url, 0, name, MAXPATHLEN - 1);
CFRelease(url);
strcat(name, "/");
if (url = CFBundleCopyResourcesDirectoryURL(bundle)) {
CFURLGetFileSystemRepresentation(url, 0, name + strlen(name),
MAXPATHLEN - strlen(name) - strlen(filename) - 1);
CFRelease(url);
strcat(name, "/");
strcat(name, filename);
}
}
if (name[0] == 0)
return -2;
}
err = racoon_is_started(name);
if (err != 0)
return err;
pid = fork();
if (pid < 0)
return -2;
if (pid == 0) {
closeall();
if (name[0])
execl("/usr/sbin/racoon", "racoon", "-f", name, (char *)0);
else
execl("/usr/sbin/racoon", "racoon", (char *)0);
exit(0);
}
while (waitpid(pid, &err, 0) < 0) {
if (errno == EINTR)
continue;
return -2;
}
sleep(3);
tries = 5; while (!racoon_is_started(name) && tries) {
sleep(1);
tries--;
}
if (tries == 0)
return -1;
return 0;
}
int
racoon_restart(int launch)
{
int pid = racoon_pid();
if (pid) {
kill(pid, SIGHUP);
}
else if (launch)
racoon_start(0, 0);
return 0;
}
#if 0
static int
racoon_stop()
{
int pid = racoon_pid();
if (pid)
kill(pid, SIGTERM);
return 0;
}
#endif
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;
CFStringRef prop_method = NULL;
auth_method = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecProposalAuthenticationMethod);
if (proposal_dict)
prop_method = CFDictionaryGetValue(proposal_dict, kRASPropIPSecProposalAuthenticationMethod);
strcpy(str, "pre_shared_key");
if (isString(auth_method) || isString(prop_method)) {
if (CFEqual(isString(prop_method) ? prop_method : auth_method, kRASValIPSecProposalAuthenticationMethodSharedSecret))
strcpy(str, "pre_shared_key");
else if (CFEqual(isString(prop_method) ? prop_method : auth_method, kRASValIPSecProposalAuthenticationMethodCertificate))
strcpy(str, "rsasig");
else
FAIL("incorrect authentication method";)
}
sprintf(text, "authentication_method %s;\n", str);
WRITE(text);
}
{
char str[256];
CFStringRef algo;
strcpy(str, "sha1");
if (proposal_dict) {
algo = CFDictionaryGetValue(proposal_dict, kRASPropIPSecProposalHashAlgorithm);
if (isString(algo)) {
if (CFEqual(algo, kRASValIPSecProposalHashAlgorithmMD5))
strcpy(str, "md5");
else if (CFEqual(algo, kRASValIPSecProposalHashAlgorithmSHA1))
strcpy(str, "sha1");
else
FAIL("incorrect authentication algorithm";)
}
}
sprintf(text, "hash_algorithm %s;\n", str);
WRITE(text);
}
{
char str[256];
CFStringRef crypto;
strcpy(str, "3des");
if (proposal_dict) {
crypto = CFDictionaryGetValue(proposal_dict, kRASPropIPSecProposalEncryptionAlgorithm);
if (isString(crypto)) {
if (CFEqual(crypto, kRASValIPSecProposalEncryptionAlgorithmDES))
strcpy(str, "des");
else if (CFEqual(crypto, kRASValIPSecProposalEncryptionAlgorithm3DES))
strcpy(str, "3des");
else if (CFEqual(crypto, kRASValIPSecProposalEncryptionAlgorithmAES))
strcpy(str, "aes");
else
FAIL("incorrect encryption algorithm";)
}
}
sprintf(text, "encryption_algorithm %s;\n", str);
WRITE(text);
}
{
u_int32_t lval = 3600;
if (proposal_dict) {
GetIntFromDict(proposal_dict, kRASPropIPSecProposalLifetime, &lval, 3600);
}
sprintf(text, "lifetime time %d sec;\n", lval);
WRITE(text);
}
{
u_int32_t lval = 2;
if (proposal_dict) {
GetIntFromDict(proposal_dict, kRASPropIPSecProposalDHGroup, &lval, 2);
}
sprintf(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;
strcpy(text, "exchange_mode ");
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)
strcat(text, ", ");
if (CFEqual(mode, kRASValIPSecExchangeModeMain))
strcat(text, "main");
else if (CFEqual(mode, kRASValIPSecExchangeModeAggressive))
strcat(text, "aggressive");
else if (CFEqual(mode, kRASValIPSecExchangeModeBase))
strcat(text, "base");
else
FAIL("incorrect phase 1 exchange mode");
}
}
if (nb == 0) {
char str[256];
if (GetStrFromDict(ipsec_dict, kRASPropIPSecLocalIdentifier, str, sizeof(str), ""))
strcat(text, "aggressive");
else
strcat(text, "main");
}
strcat(text, ";\n");
WRITE(text);
}
{
CFArrayRef proposals;
int i, nb;
CFDictionaryRef proposal;
CFStringRef method;
auth_method = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecProposalAuthenticationMethod);
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");
}
}
}
}
if (auth_method == NULL)
auth_method = kRASValIPSecProposalAuthenticationMethodSharedSecret;
if (!CFEqual(auth_method, kRASValIPSecProposalAuthenticationMethodSharedSecret)
&& !CFEqual(auth_method, kRASValIPSecProposalAuthenticationMethodCertificate))
FAIL("incorrect authentication method found");
}
{
char str[256];
char str1[256];
if (GetStrFromDict(ipsec_dict, CFSTR("LocalIdentifierType"), str1, sizeof(str1), "")) {
if (!strcmp(str1, "FQDN"))
strcpy(str1, "fqdn");
else if (!strcmp(str1, "UserFQDN"))
strcpy(str1, "user_fqdn");
else if (!strcmp(str1, "KeyID"))
strcpy(str1, "keyid_use");
else if (!strcmp(str1, "Address"))
strcpy(str1, "address");
else if (!strcmp(str1, "ASN1DN"))
strcpy(str1, "asn1dn");
else
strcpy(str1, "");
}
if (GetStrFromDict(ipsec_dict, kRASPropIPSecLocalIdentifier, str, sizeof(str), "")) {
sprintf(text, "my_identifier %s \"%s\";\n", str1[0] ? str1 : "fqdn", str);
WRITE(text);
}
else {
if (CFEqual(auth_method, kRASValIPSecProposalAuthenticationMethodSharedSecret)) {
}
else if (CFEqual(auth_method, kRASValIPSecProposalAuthenticationMethodCertificate)) {
sprintf(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");
sprintf(text, "peers_identifier address \"%s\";\n", str);
WRITE(text);
if (CFEqual(auth_method, kRASValIPSecProposalAuthenticationMethodCertificate))
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");
sprintf(text, "peers_identifier fqdn \"%s\";\n", str);
WRITE(text);
if (CFEqual(auth_method, kRASValIPSecProposalAuthenticationMethodCertificate))
cert_verification_option = CERT_VERIFICATION_OPTION_PEERS_ID;
}
else if (CFEqual(string, kRASValIPSecIdentifierVerificationUseOpenDirectory)) {
if (!CFEqual(auth_method, kRASValIPSecProposalAuthenticationMethodCertificate))
FAIL("open directory can only be used with certificate authentication");
cert_verification_option = CERT_VERIFICATION_OPTION_OPEN_DIR;
}
else
FAIL("incorrect verification method");
sprintf(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, kRASValIPSecProposalAuthenticationMethodSharedSecret)) {
if (!GetStrFromDict(ipsec_dict, kRASPropIPSecSharedSecret, str, sizeof(str), ""))
FAIL("no shared secret found");
strcpy(str1, "use");
string = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecSharedSecretEncryption);
if (isString(string)) {
if (CFEqual(string, kRASValIPSecSharedSecretEncryptionKey))
strcpy(str1, "key");
else if (CFEqual(string, kRASValIPSecSharedSecretEncryptionKeychain))
strcpy(str1, "keychain");
else
FAIL("incorrect shared secret encryption found");
}
sprintf(text, "shared_secret %s \"%s\";\n", str1, str);
WRITE(text);
}
else if (CFEqual(auth_method, kRASValIPSecProposalAuthenticationMethodCertificate)) {
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 = "";
sprintf(text, "certificate_verification sec_framework%s;\n", option_str);
WRITE(text);
}
}
{
u_int32_t lval;
GetIntFromDict(ipsec_dict, kRASPropIPSecNonceSize, &lval, 16);
sprintf(text, "nonce_size %d;\n", lval);
WRITE(text);
}
WRITE("initial_contact on;\n");
WRITE("support_mip6 on;\n");
{
CFStringRef behavior;
char str[256];
strcpy(str, "claim");
behavior = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecProposalsBehavior);
if (isString(behavior)) {
if (CFEqual(behavior, kRASValIPSecProposalsBehaviorClaim))
strcpy(str, "claim");
else if (CFEqual(behavior, kRASValIPSecProposalsBehaviorObey))
strcpy(str, "obey");
else if (CFEqual(behavior, kRASValIPSecProposalsBehaviorStrict))
strcpy(str, "strict");
else if (CFEqual(behavior, kRASValIPSecProposalsBehaviorExact))
strcpy(str, "exact");
else
FAIL("incorrect proposal behavior");
}
sprintf(text, "proposal_check %s;\n", str);
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;
strcpy(text, "encryption_algorithm ");
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)
strcat(text, ", ");
if (CFEqual(algo, kRASValIPSecPolicyEncryptionAlgorithmDES))
strcat(text, "des");
else if (CFEqual(algo, kRASValIPSecPolicyEncryptionAlgorithm3DES))
strcat(text, "3des");
else if (CFEqual(algo, kRASValIPSecPolicyEncryptionAlgorithmAES))
strcat(text, "aes");
else
FAIL("incorrect encryption algorithm");
found = 1;
}
}
}
}
if (!found)
strcat(text, "aes");
strcat(text, ";\n");
WRITE(text);
}
{
CFArrayRef algos;
int i, nb, found = 0;
strcpy(text, "authentication_algorithm ");
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)
strcat(text, ", ");
if (CFEqual(algo, kRASValIPSecPolicyHashAlgorithmSHA1))
strcat(text, "hmac_sha1");
else if (CFEqual(algo, kRASValIPSecPolicyHashAlgorithmMD5))
strcat(text, "hmac_md5");
else
FAIL("incorrect authentication algorithm");
found = 1;
}
}
}
}
if (!found)
strcat(text, "hmac_sha1");
strcat(text, ";\n");
WRITE(text);
}
{
CFArrayRef algos;
int i, nb, found = 0;
strcpy(text, "compression_algorithm ");
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)
strcat(text, ", ");
if (CFEqual(algo, kRASValIPSecPolicyCompressionAlgorithmDeflate))
strcat(text, "deflate");
else
FAIL("incorrect compression algorithm");
found = 1;
}
}
}
}
if (!found)
strcat(text, "deflate");
strcat(text, ";\n");
WRITE(text);
}
{
u_int32_t lval = 3600;
if (policy)
GetIntFromDict(policy, kRASPropIPSecPolicyLifetime, &lval, 3600);
sprintf(text, "lifetime time %d sec;\n", lval);
WRITE(text);
}
{
u_int32_t lval = 0;
if (policy) {
if (GetIntFromDict(policy, kRASPropIPSecPolicyPFSGroup, &lval, 0)) {
sprintf(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 local_address[32], remote_address[32];
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) {
sprintf(filename, "/etc/racoon/remote/%s.conf", anonymous ? "anonymous" : remote_address);
remove(filename);
}
mask = umask(S_IRWXG|S_IRWXO);
file = fopen(apply ? filename : "/dev/null" , "w");
mask = umask(mask);
if (file == NULL) {
sprintf(text, "cannot create racoon configuration file (error %d)", errno);
FAIL(text);
}
{
sprintf(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)
FAIL("no policies found");
if (anonymous)
nb = 1;
for (i = 0; i < nb; i++) {
CFDictionaryRef policy;
CFStringRef policylevel, policymode;
char local_network[256], remote_network[256];
int local_port, remote_port;
int local_prefix, remote_prefix;
int 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) {
sprintf(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");
sprintf(text, "sainfo address %s/%d 0 address %s/%d 0 {\n",
local_network, local_prefix,
remote_network, remote_prefix);
}
else {
GetIntFromDict(policy, kRASPropIPSecPolicyLocalPort, &local_port, 0);
GetIntFromDict(policy, kRASPropIPSecPolicyRemotePort, &remote_port, 0);
GetIntFromDict(policy, kRASPropIPSecPolicyProtocol, &protocol, 0);
sprintf(text, "sainfo address %s/32 [%d] %d address %s/32 [%d] %d {\n",
local_address, local_port, protocol,
remote_address, remote_port, protocol);
}
}
WRITE(text);
if (configure_sainfo(level + 1, file, ipsec_dict, policy, errstr))
goto fail;
WRITE("}\n\n");
}
}
fclose(file);
if (apply) {
racoon_restart(1);
}
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;
sprintf(filename, "/etc/racoon/remote/%s.conf", remote_address);
remove(filename);
racoon_restart(0);
return 0;
fail:
return -1;
}
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, policy_out;
int policylen_in, policylen_out, local_prefix, remote_prefix;
int 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)) {
sprintf(policystr_out, "out none");
sprintf(policystr_in, "in none");
}
else if (CFEqual(policylevel, kRASValIPSecPolicyLevelRequire)) {
if (tunnel) {
sprintf(policystr_out, "out ipsec esp/tunnel/%s-%s/require", src_address, dst_address);
sprintf(policystr_in, "in ipsec esp/tunnel/%s-%s/require", dst_address, src_address);
}
else {
sprintf(policystr_out, "out ipsec esp/transport//require");
sprintf(policystr_in, "in ipsec esp/transport//require");
}
}
else if (CFEqual(policylevel, kRASValIPSecPolicyLevelDiscard)) {
sprintf(policystr_out, "out discard");
sprintf(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 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 {
int 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;
}
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, policy_out;
int policylen_in, policylen_out, local_prefix, remote_prefix;
int 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");
}
sprintf(policystr_out, "out");
sprintf(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 {
int 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_long)) :\
sizeof(u_long)))
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_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)
{
CFStringRef src_string, dst_string, hostname_string = NULL;
CFMutableDictionaryRef ipsec_dict, proposal_dict, policy0, policy1 = NULL;
CFMutableArrayRef policy_array, proposal_array, encryption_array, hash_array;
CFNumberRef src_port_num, dst_port_num, dst_port1_num, proto_num;
int zero = 0, 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);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecLocalAddress, src_string);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecRemoteAddress, dst_string);
CFDictionarySetValue(ipsec_dict, kRASPropIPSecProposalsBehavior, isClient ? kRASValIPSecProposalsBehaviorObey : kRASValIPSecProposalsBehaviorClaim);
if (isClient && CFEqual(authenticationMethod, kRASValIPSecProposalAuthenticationMethodCertificate)) {
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);
proposal_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(proposal_dict, kRASPropIPSecProposalAuthenticationMethod, 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);
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 (hostname_string)
CFRelease(hostname_string);
return ipsec_dict;
}