#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
-#include <resolv.h>
#include <TargetConditionals.h>
#include <vproc_priv.h>
#include <dispatch/dispatch.h>
+#include <xpc/xpc.h>
#include "libpfkey.h"
#include "sainfo.h"
#include "power_mgmt.h"
+#include <NetworkExtension/NEPolicy.h>
+#include <sys/proc_info.h>
+#include <libproc.h>
extern pid_t racoon_pid;
static void close_session (int);
static int init_signal (void);
static int set_signal (int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *));
-static void check_sigreq (void);
static void check_flushsa_stub (void *);
static void check_flushsa (void);
static void auto_exit_do (void *);
static volatile sig_atomic_t sigreq[NSIG + 1];
int terminated = 0;
+int pending_signal_handle = 0;
static int64_t racoon_keepalive = -1;
dispatch_queue_t main_queue;
+static NEPolicySessionRef policySession = NULL;
+
/*
* This is used to (manually) update racoon's launchd keepalive, which is needed because racoon is (mostly)
* launched on demand and for <rdar://problem/8768510> requires a keepalive on dirty/failure exits.
return racoon_keepalive;
}
+static CFUUIDRef
+copy_racoon_proc_uuid(void)
+{
+ struct proc_uniqidentifierinfo procu;
+ CFUUIDBytes uuidBytes;
+ int size = 0;
+
+ memset(&procu, 0, sizeof(procu));
+ size = proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO, 1, &procu, PROC_PIDUNIQIDENTIFIERINFO_SIZE);
+ if (size != PROC_PIDUNIQIDENTIFIERINFO_SIZE) {
+ return (NULL);
+ }
+
+ memcpy(&uuidBytes, procu.p_uuid, sizeof(CFUUIDBytes));
+ return CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, uuidBytes);
+}
+
+static bool
+policy_session_init(void)
+{
+ bool success = true;
+ policySession = NEPolicyCreateSession(kCFAllocatorDefault, CFSTR("racoon"), NULL, NULL);
+ if (policySession == NULL) {
+ return false;
+ }
+
+ CFUUIDRef proc_uuid = copy_racoon_proc_uuid();
+ if (proc_uuid == NULL) {
+ return false;
+ }
+
+ CFMutableArrayRef conditions = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ if (conditions) {
+ CFMutableDictionaryRef uuidCondition = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (uuidCondition) {
+ CFDictionarySetValue(uuidCondition, kNEPolicyConditionType, kNEPolicyValPolicyConditionTypeApplication);
+ CFDictionarySetValue(uuidCondition, kNEPolicyApplicationUUID, proc_uuid);
+ CFArrayAppendValue(conditions, uuidCondition);
+ CFRelease(uuidCondition);
+ } else {
+ success = false;
+ }
+
+ CFMutableDictionaryRef interfacesCondition = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (interfacesCondition) {
+ CFDictionarySetValue(interfacesCondition, kNEPolicyConditionType, kNEPolicyValPolicyConditionTypeAllInterfaces);
+ CFArrayAppendValue(conditions, interfacesCondition);
+ CFRelease(interfacesCondition);
+ } else {
+ success = false;
+ }
+ } else {
+ success = false;
+ }
+
+ CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (result) {
+ CFDictionaryAddValue(result, kNEPolicyResult, kNEPolicyValPolicyResultPass);
+ } else {
+ success = false;
+ }
+
+ if (success) {
+ success = (NEPolicyAdd(policySession, 0, conditions, result, NULL) != kNEPolicyIDInvalid);
+ }
+
+ if (result) {
+ CFRelease(result);
+ }
+ if (conditions) {
+ CFRelease(conditions);
+ }
+ if (proc_uuid) {
+ CFRelease(proc_uuid);
+ }
+
+ return (success && NEPolicyApply(policySession));
+}
+
//
// Session
//
plog(ASL_LEVEL_ERR, "failed to initialize route socket.\n");
exit(1);
}
+
+ if (!policy_session_init()) {
+ plog(ASL_LEVEL_ERR, "failed to initialize NEPolicy session.\n");
+ }
+
if (initmyaddr()) {
plog(ASL_LEVEL_ERR, "failed to initialize listening addresses.\n");
exit(1);
"cannot open %s", pid_file);
}
}
+
+ xpc_transaction_begin();
+
#if !TARGET_OS_EMBEDDED
// enable keepalive for recovery (from crashes and bad exits... after init)
(void)launchd_update_racoon_keepalive(true);
ike_session_flush_all_phase1(false);
close_sockets();
+ xpc_transaction_end();
+
#if !TARGET_OS_EMBEDDED
// a clean exit, so disable launchd keepalive
(void)launchd_update_racoon_keepalive(false);
#endif // !TARGET_OS_EMBEDDED
- plog(ASL_LEVEL_INFO, "racoon shutdown\n");
+ plog(ASL_LEVEL_NOTICE, "racoon shutdown\n");
exit(0);
}
void
auto_exit_do(void *p)
{
- plog(ASL_LEVEL_DEBUG,
+ plog(ASL_LEVEL_NOTICE,
"performing auto exit\n");
+#if ENABLE_NO_SA_FLUSH
+ close_session(0);
+#else
pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
sched_new(1, check_flushsa_stub, NULL);
dying();
+#endif /* ENABLE_NO_SA_FLUSH */
}
void
};
-static void
+void
check_sigreq()
{
int sig;
#if TARGET_OS_EMBEDDED
if (no_remote_configs(TRUE)) {
+#if ENABLE_NO_SA_FLUSH
+ close_session(0);
+#else
pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
#ifdef ENABLE_FASTQUIT
close_session(0);
#else
sched_new(1, check_flushsa_stub, NULL);
-#endif
+#endif /* ENABLE_FASTQUIT */
dying();
+#endif /* ENABLE_NO_SA_FLUSH */
}
#endif
case SIGINT:
case SIGTERM:
- plog(ASL_LEVEL_INFO,
+ plog(ASL_LEVEL_NOTICE,
"caught signal %d\n", sig);
- pfkey_send_flush(lcconf->sock_pfkey,
+#if ENABLE_NO_SA_FLUSH
+ close_session(0);
+#else
+ pfkey_send_flush(lcconf->sock_pfkey,
SADB_SATYPE_UNSPEC);
if ( sig == SIGTERM ){
terminated = 1; /* in case if it hasn't been set yet */
sched_new(1, check_flushsa_stub, NULL);
dying();
+#endif /* ENABLE_NO_SA_FLUSH */
break;
default:
- plog(ASL_LEVEL_INFO,
+ plog(ASL_LEVEL_NOTICE,
"caught signal %d\n", sig);
break;
}
signal_handler(int sig, siginfo_t *sigi, void *ctx)
{
#if 0
- plog(ASL_LEVEL_DEBUG,
+ plog(ASL_LEVEL_NOTICE,
"%s received signal %d from pid %d uid %d\n\n",
__FUNCTION__, sig, sigi->si_pid, sigi->si_uid);
#endif
if ( sig == SIGTERM ){
terminated = 1;
}
+
+ pending_signal_handle = 1;
dispatch_async(main_queue,
^{
- check_sigreq();
+ if (pending_signal_handle) {
+ check_sigreq();
+ pending_signal_handle = 0;
+ }
});
}