controller: Add option to force destruction of an IKE_SA
[strongswan.git] / src / frontends / osx / charon-xpc / xpc_channels.c
index ce2c83b..d013e75 100644 (file)
@@ -78,12 +78,12 @@ static void destroy_entry(entry_t *entry)
 /**
  * Find an IKE_SA unique identifier by a given XPC channel
  */
-static u_int32_t find_ike_sa_by_conn(private_xpc_channels_t *this,
+static uint32_t find_ike_sa_by_conn(private_xpc_channels_t *this,
                                                                         xpc_connection_t conn)
 {
        enumerator_t *enumerator;
        entry_t *entry;
-       u_int32_t ike_sa = 0;
+       uint32_t ike_sa = 0;
 
        this->lock->read_lock(this->lock);
        enumerator = this->channels->create_enumerator(this->channels);
@@ -126,12 +126,12 @@ static void remove_conn(private_xpc_channels_t *this, xpc_connection_t conn)
 /**
  * Trigger termination of a connection
  */
-static void stop_connection(private_xpc_channels_t *this, u_int32_t ike_sa,
+static void stop_connection(private_xpc_channels_t *this, uint32_t ike_sa,
                                                        xpc_object_t request, xpc_object_t reply)
 {
        status_t status;
 
-       status = charon->controller->terminate_ike(charon->controller, ike_sa,
+       status = charon->controller->terminate_ike(charon->controller, ike_sa, FALSE,
                                                                                           NULL, NULL, 0);
        xpc_dictionary_set_bool(reply, "success", status != NOT_FOUND);
 }
@@ -141,7 +141,7 @@ static void stop_connection(private_xpc_channels_t *this, u_int32_t ike_sa,
  */
 static struct {
        char *name;
-       void (*handler)(private_xpc_channels_t *this, u_int32_t ike_sa,
+       void (*handler)(private_xpc_channels_t *this, uint32_t ike_sa,
                                        xpc_object_t request, xpc_object_t reply);
 } commands[] = {
        { "stop_connection", stop_connection },
@@ -156,7 +156,7 @@ static void handle(private_xpc_channels_t *this, xpc_connection_t conn,
        xpc_object_t reply;
        const char *type, *rpc;
        bool found = FALSE;
-       u_int32_t ike_sa;
+       uint32_t ike_sa;
        int i;
 
        type = xpc_dictionary_get_string(request, "type");
@@ -201,7 +201,7 @@ static void handle(private_xpc_channels_t *this, xpc_connection_t conn,
 }
 
 METHOD(xpc_channels_t, add, void,
-       private_xpc_channels_t *this, xpc_connection_t conn, u_int32_t ike_sa)
+       private_xpc_channels_t *this, xpc_connection_t conn, uint32_t ike_sa)
 {
        entry_t *entry;
 
@@ -211,6 +211,7 @@ METHOD(xpc_channels_t, add, void,
                .logger = xpc_logger_create(conn),
        );
 
+       xpc_retain(entry->conn);
        xpc_connection_set_event_handler(entry->conn, ^(xpc_object_t event)
        {
                if (event == XPC_ERROR_CONNECTION_INVALID ||
@@ -234,6 +235,62 @@ METHOD(xpc_channels_t, add, void,
        xpc_connection_resume(conn);
 }
 
+METHOD(listener_t, alert, bool,
+       private_xpc_channels_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args)
+{
+       const char *desc;
+
+       switch (alert)
+       {
+               case ALERT_LOCAL_AUTH_FAILED:
+                       desc = "local-auth";
+                       break;
+               case ALERT_PEER_AUTH_FAILED:
+                       desc = "remote-auth";
+                       break;
+               case ALERT_PEER_ADDR_FAILED:
+                       desc = "dns";
+                       break;
+               case ALERT_PEER_INIT_UNREACHABLE:
+                       desc = "unreachable";
+                       break;
+               case ALERT_RETRANSMIT_SEND_TIMEOUT:
+                       desc = "timeout";
+                       break;
+               case ALERT_PROPOSAL_MISMATCH_IKE:
+               case ALERT_PROPOSAL_MISMATCH_CHILD:
+                       desc = "proposal-mismatch";
+                       break;
+               case ALERT_TS_MISMATCH:
+                       desc = "ts-mismatch";
+                       break;
+               default:
+                       return TRUE;
+       }
+       if (ike_sa)
+       {
+               entry_t *entry;
+               uintptr_t sa;
+
+               sa = ike_sa->get_unique_id(ike_sa);
+               this->lock->read_lock(this->lock);
+               entry = this->channels->get(this->channels, (void*)sa);
+               if (entry)
+               {
+                       xpc_object_t msg;
+
+                       msg = xpc_dictionary_create(NULL, NULL, 0);
+                       xpc_dictionary_set_string(msg, "type", "event");
+                       xpc_dictionary_set_string(msg, "event", "alert");
+                       xpc_dictionary_set_string(msg, "alert", desc);
+                       xpc_connection_send_message(entry->conn, msg);
+                       xpc_release(msg);
+               }
+               this->lock->unlock(this->lock);
+       }
+       return TRUE;
+}
+
 METHOD(listener_t, ike_rekey, bool,
        private_xpc_channels_t *this, ike_sa_t *old, ike_sa_t *new)
 {
@@ -254,6 +311,78 @@ METHOD(listener_t, ike_rekey, bool,
        return TRUE;
 }
 
+METHOD(listener_t, ike_state_change, bool,
+       private_xpc_channels_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
+{
+       if (state == IKE_CONNECTING)
+       {
+               entry_t *entry;
+               uintptr_t sa;
+
+               sa = ike_sa->get_unique_id(ike_sa);
+               this->lock->read_lock(this->lock);
+               entry = this->channels->get(this->channels, (void*)sa);
+               if (entry)
+               {
+                       xpc_object_t msg;
+
+                       msg = xpc_dictionary_create(NULL, NULL, 0);
+                       xpc_dictionary_set_string(msg, "type", "event");
+                       xpc_dictionary_set_string(msg, "event", "connecting");
+                       xpc_connection_send_message(entry->conn, msg);
+                       xpc_release(msg);
+               }
+               this->lock->unlock(this->lock);
+       }
+       return TRUE;
+}
+
+METHOD(listener_t, child_updown, bool,
+       private_xpc_channels_t *this, ike_sa_t *ike_sa,
+       child_sa_t *child_sa, bool up)
+{
+       entry_t *entry;
+       uintptr_t sa;
+
+       sa = ike_sa->get_unique_id(ike_sa);
+       this->lock->read_lock(this->lock);
+       entry = this->channels->get(this->channels, (void*)sa);
+       if (entry)
+       {
+               xpc_object_t msg;
+               linked_list_t *list;
+               char buf[256];
+
+               msg = xpc_dictionary_create(NULL, NULL, 0);
+               xpc_dictionary_set_string(msg, "type", "event");
+               if (up)
+               {
+                       xpc_dictionary_set_string(msg, "event", "child_up");
+               }
+               else
+               {
+                       xpc_dictionary_set_string(msg, "event", "child_down");
+               }
+
+               list = linked_list_create_from_enumerator(
+                                       child_sa->create_ts_enumerator(child_sa, TRUE));
+               snprintf(buf, sizeof(buf), "%#R", list);
+               list->destroy(list);
+               xpc_dictionary_set_string(msg, "ts_local", buf);
+
+               list = linked_list_create_from_enumerator(
+                                       child_sa->create_ts_enumerator(child_sa, FALSE));
+               snprintf(buf, sizeof(buf), "%#R", list);
+               list->destroy(list);
+               xpc_dictionary_set_string(msg, "ts_remote", buf);
+
+               xpc_connection_send_message(entry->conn, msg);
+               xpc_release(msg);
+       }
+       this->lock->unlock(this->lock);
+       return TRUE;
+}
+
 METHOD(listener_t, ike_updown, bool,
        private_xpc_channels_t *this, ike_sa_t *ike_sa, bool up)
 {
@@ -337,7 +466,7 @@ static shared_key_t* password_cb(private_xpc_channels_t *this,
        shared_key_t *shared = NULL;
        ike_sa_t *ike_sa;
        entry_t *entry;
-       u_int32_t sa;
+       uint32_t sa;
 
        switch (type)
        {
@@ -351,7 +480,7 @@ static shared_key_t* password_cb(private_xpc_channels_t *this,
        {
                sa = ike_sa->get_unique_id(ike_sa);
                this->lock->read_lock(this->lock);
-               entry = this->channels->get(this->channels, (void*)sa);
+               entry = this->channels->get(this->channels, (void*)(uintptr_t)sa);
                if (entry && !entry->passworded)
                {
                        entry->passworded = TRUE;
@@ -394,8 +523,11 @@ xpc_channels_t *xpc_channels_create()
        INIT(this,
                .public = {
                        .listener = {
+                               .alert = _alert,
                                .ike_updown = _ike_updown,
                                .ike_rekey = _ike_rekey,
+                               .ike_state_change = _ike_state_change,
+                               .child_updown = _child_updown,
                        },
                        .add = _add,
                        .destroy = _destroy,