]> git.saurik.com Git - apple/ipsec.git/blobdiff - ipsec-tools/racoon/vpn_control.c
ipsec-258.1.3.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / vpn_control.c
index 3a6f7fa4bd6ea8c7d72867fa4baa835a8d17e3ef..39c20a99fe778d3a7276a682cf5a4438e38099ac 100644 (file)
@@ -51,6 +51,9 @@
  * SUCH DAMAGE.
  */
 
+//#define LION_TEST 1
+
+
 #include "config.h"
 
 #include <sys/types.h>
@@ -60,7 +63,7 @@
 #include <sys/stat.h>
 #include <sys/un.h>
 
-#include <System/net/pfkeyv2.h>
+#include <net/pfkeyv2.h>
 
 #include <netinet/in.h>
 #ifndef HAVE_NETINET6_IPSEC
 #include <unistd.h>
 #endif
 #include <launch.h>
+#ifndef LION_TEST
+#include <launch_priv.h>
+#endif
+#include <fcntl.h>
 
 #include "var.h"
 #include "misc.h"
 #include "isakmp.h"
 #include "oakley.h"
 #include "handler.h"
-#include "evt.h"
 #include "pfkey.h"
 #include "ipsec_doi.h"
 #include "vpn_control.h"
 #include "session.h"
 #include "gcmalloc.h"
 #include "isakmp_cfg.h"
+#include "sainfo.h"
 
 #ifdef ENABLE_VPNCONTROL_PORT
 char *vpncontrolsock_path = VPNCONTROLSOCK_PATH;
@@ -112,19 +119,21 @@ gid_t vpncontrolsock_group = 0;
 mode_t vpncontrolsock_mode = 0600;
 
 static struct sockaddr_un sunaddr;
-static int vpncontrol_process(struct vpnctl_socket_elem *, char *);
-static int vpncontrol_reply(int, char *);
-static void vpncontrol_close_comm(struct vpnctl_socket_elem *);
-static int checklaunchd();
-extern int vpn_get_config __P((struct ph1handle *, struct vpnctl_status_phase_change **, size_t *));
-extern int vpn_xauth_reply __P((u_int32_t, void *, size_t));
+static int vpncontrol_process (struct vpnctl_socket_elem *, char *);
+static int vpncontrol_reply (int, char *);
+static void vpncontrol_close_comm (struct vpnctl_socket_elem *);
+static int checklaunchd (void);
+extern int vpn_get_config (phase1_handle_t *, struct vpnctl_status_phase_change **, size_t *);
+extern int vpn_xauth_reply (u_int32_t, void *, size_t);
 
 
 int                     
 checklaunchd()                  
 {               
        launch_data_t checkin_response = NULL; 
-       launch_data_t checkin_request = NULL;
+#ifdef LION_TEST
+    launch_data_t checkin_request = NULL;
+#endif
        launch_data_t sockets_dict, listening_fd_array;
        launch_data_t listening_fd;
        struct sockaddr_storage fdsockaddr;
@@ -136,35 +145,40 @@ checklaunchd()
        int fd;
        
        /* check in with launchd */
-       if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                        "failed to launch_data_new_string.\n");
-               goto done;
-       }
-       if ((checkin_response = launch_msg(checkin_request)) == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                        "failed to launch_msg.\n");
+#ifdef LION_TEST
+    if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) {
+#else
+       if ((checkin_response = launch_socket_service_check_in()) == NULL) {
+#endif
+               plog(ASL_LEVEL_ERR, 
+                        "failed to launch_socket_service_check_in.\n");
                goto done;
        }
+#ifdef LION_TEST
+    if ((checkin_response = launch_msg(checkin_request)) == NULL) {
+        plog(ASL_LEVEL_ERR, "failed to launch_msg.\n");
+        goto done;
+    }
+#endif
        if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                         "launch_data_get_type error %d\n",
                         launch_data_get_errno(checkin_response));
                goto done;
        }
        if ( (sockets_dict = launch_data_dict_lookup(checkin_response, LAUNCH_JOBKEY_SOCKETS)) == NULL){
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                         "failed to launch_data_dict_lookup.\n");
                goto done;
        }
        if ( !(socketct = launch_data_dict_get_count(sockets_dict))){
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                         "launch_data_dict_get_count returns no socket defined.\n");
                goto done;
        }
        
        if ( (listening_fd_array = launch_data_dict_lookup(sockets_dict, "Listeners")) == NULL ){
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                         "failed to launch_data_dict_lookup.\n");
                goto done;
        }
@@ -172,15 +186,15 @@ checklaunchd()
        for (i = 0; i < listenerct; i++) {
                listening_fd = launch_data_array_get_index(listening_fd_array, i);
                fd = launch_data_get_fd( listening_fd );
-               if ( getsockname( fd , (struct sockaddr*)&fdsockaddr, &fdsockaddrlen)){
+               if ( getsockname( fd , (struct sockaddr *)&fdsockaddr, &fdsockaddrlen)){
                        continue;
                }
                
                /* Is this the VPN control socket? */ 
-               if ( (((struct sockaddr*)&fdsockaddr)->sa_family) == AF_UNIX && 
+               if ( fdsockaddr.ss_family == AF_UNIX && 
                                (!(strcmp(vpncontrolsock_path, ((struct sockaddr_un *)&fdsockaddr)->sun_path))))
                {       
-                       plog(LLV_INFO, LOCATION, NULL,
+                       plog(ASL_LEVEL_INFO, 
                                 "found launchd socket.\n");
                        returnval = fd;
                        break;
@@ -188,84 +202,105 @@ checklaunchd()
        }
        // TODO: check if we have any leaked fd
        if ( listenerct == i){
-               plog(LLV_ERROR, LOCATION, NULL
+               plog(ASL_LEVEL_ERR
                         "failed to find launchd socket\n");               
                returnval = 0;
        }
        
 done:   
-       if (checkin_request)
-               launch_data_free(checkin_request);
        if (checkin_response)
                launch_data_free(checkin_response);
        return(returnval);
 }
 
                
-int
-vpncontrol_handler()
+void
+vpncontrol_handler(void *unused)
 {
        struct sockaddr_storage from;
        socklen_t fromlen = sizeof(from);
+    int sock;
 
        struct vpnctl_socket_elem *sock_elem;
        
-       sock_elem = racoon_malloc(sizeof(struct vpnctl_socket_elem));
+    sock_elem = racoon_malloc(sizeof(struct vpnctl_socket_elem));
        if (sock_elem == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "memory error: %s\n", strerror(errno));
-               return -1;
+               return; //%%%%%% terminate
        }
        LIST_INIT(&sock_elem->bound_addresses);
-
+    
        sock_elem->sock = accept(lcconf->sock_vpncontrol, (struct sockaddr *)&from, &fromlen);
        if (sock_elem->sock < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "failed to accept vpn_control command: %s\n", strerror(errno));
                racoon_free(sock_elem);
-               return -1;
+               return; //%%%%% terminate
        }
        LIST_INSERT_HEAD(&lcconf->vpnctl_comm_socks, sock_elem, chain);
-       plog(LLV_NOTIFY, LOCATION, NULL,
-               "accepted connection on vpn control socket.\n");
-               
+    
+    sock_elem->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, sock_elem->sock, 0, dispatch_get_main_queue());
+    if (sock_elem->source == NULL) {
+               plog(ASL_LEVEL_ERR, "could not create comm socket source.");
+               racoon_free(sock_elem);
+               return; //%%%%% terminate
+    }
+    dispatch_source_set_event_handler(sock_elem->source, 
+                                        ^{
+                                                vpncontrol_comm_handler(sock_elem);
+                                        });
+    sock = sock_elem->sock;
+       
+    dispatch_source_t the_source = sock_elem->source;
+    dispatch_source_set_cancel_handler(sock_elem->source,
+                                       ^{
+                                           close(sock);
+                                           dispatch_release(the_source); /* Release the source on cancel */
+                                       });
+    dispatch_resume(sock_elem->source);
+    
+       plog(ASL_LEVEL_NOTICE, 
+               "accepted connection on vpn control socket.\n");                
        check_auto_exit();
                
-       return 0;
+       return;
 }
 
-int
+void
 vpncontrol_comm_handler(struct vpnctl_socket_elem *elem)
 {
        struct vpnctl_hdr hdr;
        char *combuf = NULL;
-       int len;
+       ssize_t len;
 
        /* get buffer length */
        while ((len = recv(elem->sock, (char *)&hdr, sizeof(hdr), MSG_PEEK)) < 0) {
                if (errno == EINTR)
                        continue;
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "failed to recv vpn_control command: %s\n", strerror(errno));
                goto end;
        }
        if (len == 0) {
-               plog(LLV_DEBUG, LOCATION, NULL,
+               plog(ASL_LEVEL_DEBUG, 
                        "vpn_control socket closed by peer.\n");
+        /* kill all related connections */
+        vpncontrol_disconnect_all(elem, ike_session_stopped_by_controller_comm_lost);
                vpncontrol_close_comm(elem);
-               return -1;
+               return; // %%%%%% terminate
        }
                
        /* sanity check */
        if (len < sizeof(hdr)) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                       "invalid header length of vpn_control command - len=%d - expected %d\n", len, sizeof(hdr));
+               plog(ASL_LEVEL_ERR, 
+                       "invalid header length of vpn_control command - len=%ld - expected %ld\n", len, sizeof(hdr));
                goto end;
        }
 
        /* get buffer to receive */
        if ((combuf = racoon_malloc(ntohs(hdr.len) + sizeof(hdr))) == 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "failed to alloc buffer for vpn_control command\n");
                goto end;
        }
@@ -274,7 +309,7 @@ vpncontrol_comm_handler(struct vpnctl_socket_elem *elem)
        while ((len = recv(elem->sock, combuf, ntohs(hdr.len) + sizeof(hdr), 0)) < 0) {
                if (errno == EINTR)
                        continue;
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "failed to recv vpn_control command: %s\n",
                        strerror(errno));
                goto end;
@@ -285,27 +320,27 @@ vpncontrol_comm_handler(struct vpnctl_socket_elem *elem)
 end:
        if (combuf)
                racoon_free(combuf);
-       return 0;               // return -1 only if a socket is closed
+       return;
 }
 
 static int
 vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
 {
        u_int16_t       error = 0;
-       struct vpnctl_hdr *hdr = (struct vpnctl_hdr *)combuf;
+       struct vpnctl_hdr *hdr = ALIGNED_CAST(struct vpnctl_hdr *)combuf;
 
        switch (ntohs(hdr->msg_type)) {
        
                case VPNCTL_CMD_BIND:
                        {
-                               struct vpnctl_cmd_bind *pkt = (struct vpnctl_cmd_bind *)combuf;
+                               struct vpnctl_cmd_bind *pkt = ALIGNED_CAST(struct vpnctl_cmd_bind *)combuf;
                                struct bound_addr *addr;
                        
-                               plog(LLV_DEBUG, LOCATION, NULL,
+                               plog(ASL_LEVEL_DEBUG, 
                                        "received bind command on vpn control socket.\n");
                                addr = racoon_calloc(1, sizeof(struct bound_addr));
                                if (addr == NULL) {
-                                       plog(LLV_ERROR, LOCATION, NULL, 
+                                       plog(ASL_LEVEL_ERR,     
                                                "memory error: %s\n", strerror(errno));
                                        error = -1;
                                        break;
@@ -313,7 +348,7 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
                                if (ntohs(pkt->vers_len)) {
                                        addr->version = vmalloc(ntohs(pkt->vers_len));
                                        if (addr->version == NULL) {
-                                               plog(LLV_ERROR, LOCATION, NULL, 
+                                               plog(ASL_LEVEL_ERR,     
                                                        "memory error: %s\n", strerror(errno));
                                                error = -1;
                                                break;
@@ -328,11 +363,11 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
                        
                case VPNCTL_CMD_UNBIND:
                        {
-                               struct vpnctl_cmd_unbind *pkt = (struct vpnctl_cmd_unbind *)combuf;
+                               struct vpnctl_cmd_unbind *pkt = ALIGNED_CAST(struct vpnctl_cmd_unbind *)combuf;
                                struct bound_addr *addr;
                                struct bound_addr *t_addr;
 
-                               plog(LLV_DEBUG, LOCATION, NULL,
+                               plog(ASL_LEVEL_DEBUG, 
                                        "received unbind command on vpn control socket.\n");
                                LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
                                        if (pkt->address == 0xFFFFFFFF ||
@@ -349,12 +384,12 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
 
                case VPNCTL_CMD_REDIRECT:
                        {
-                               struct vpnctl_cmd_redirect *redirect_msg = (struct vpnctl_cmd_redirect *)combuf;
+                               struct vpnctl_cmd_redirect *redirect_msg = ALIGNED_CAST(struct vpnctl_cmd_redirect *)combuf;
                                struct redirect *raddr;
                                struct redirect *t_raddr;
                                int found = 0;
                                
-                               plog(LLV_DEBUG, LOCATION, NULL,
+                               plog(ASL_LEVEL_DEBUG, 
                                        "received redirect command on vpn control socket - address = %x.\n", ntohl(redirect_msg->redirect_address));
                                
                                LIST_FOREACH_SAFE(raddr, &lcconf->redirect_addresses, chain, t_raddr) {
@@ -373,7 +408,7 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
                                if (!found) {
                                        raddr = racoon_malloc(sizeof(struct redirect));
                                        if (raddr == NULL) {
-                                               plog(LLV_DEBUG, LOCATION, NULL,
+                                               plog(ASL_LEVEL_DEBUG, 
                                                        "cannot allcoate memory for redirect address.\n");                                      
                                                error = -1;
                                                break;
@@ -392,12 +427,12 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
 
                case VPNCTL_CMD_XAUTH_INFO:
                        {
-                               struct vpnctl_cmd_xauth_info *pkt = (struct vpnctl_cmd_xauth_info *)combuf;
+                               struct vpnctl_cmd_xauth_info *pkt = ALIGNED_CAST(struct vpnctl_cmd_xauth_info *)combuf;
                                struct bound_addr *addr;
                                struct bound_addr *t_addr;
                                void *attr_list;
 
-                               plog(LLV_DEBUG, LOCATION, NULL,
+                               plog(ASL_LEVEL_DEBUG, 
                                        "received xauth info command vpn control socket.\n");
                                LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
                                        if (pkt->address == addr->address) {
@@ -412,11 +447,11 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
                                
                case VPNCTL_CMD_CONNECT:
                        {
-                               struct vpnctl_cmd_connect *pkt = (struct vpnctl_cmd_connect *)combuf;
+                               struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
                                struct bound_addr *addr;
                                struct bound_addr *t_addr;
 
-                               plog(LLV_DEBUG, LOCATION, NULL,
+                               plog(ASL_LEVEL_DEBUG, 
                                        "received connect command on vpn control socket.\n");
                                LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
                                        if (pkt->address == addr->address) {
@@ -430,16 +465,16 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
                        
                case VPNCTL_CMD_DISCONNECT:
                        {
-                               struct vpnctl_cmd_connect *pkt = (struct vpnctl_cmd_connect *)combuf;
+                               struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
                                struct bound_addr *addr;
                                struct bound_addr *t_addr;
 
-                               plog(LLV_DEBUG, LOCATION, NULL,
+                               plog(ASL_LEVEL_DEBUG, 
                                        "received disconnect command on vpn control socket.\n");
                                LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
                                        if (pkt->address == addr->address) {
                                                /* stop the connection */
-                                               error = vpn_disconnect(addr);
+                                               error = vpn_disconnect(addr, ike_session_stopped_by_vpn_disconnect);
                                                break;
                                        }
                                }
@@ -448,13 +483,11 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
                        
                case VPNCTL_CMD_START_PH2:
                        {
-                               struct vpnctl_cmd_start_ph2 *pkt = (struct vpnctl_cmd_start_ph2 *)combuf;
+                               struct vpnctl_cmd_start_ph2 *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_ph2 *)combuf;
                                struct bound_addr *addr;
                                struct bound_addr *t_addr;
 
-                               plog(LLV_DEBUG, LOCATION, NULL,
-                                       "received start_ph2 command on vpn control socket.\n");
-                               plogdump(LLV_DEBUG2, pkt, ntohs(hdr->len) + sizeof(struct vpnctl_hdr));
+                               plog(ASL_LEVEL_DEBUG, "received start_ph2 command on vpn control socket.\n");
                                LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
                                        if (pkt->address == addr->address) {
                                                /* start the connection */
@@ -467,24 +500,27 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
 
                case VPNCTL_CMD_START_DPD:
             {
-                struct vpnctl_cmd_start_dpd *pkt = (struct vpnctl_cmd_start_dpd *)combuf;
+                struct vpnctl_cmd_start_dpd *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_dpd *)combuf;
                 struct bound_addr *srv;
                 struct bound_addr *t_addr;
 
-                plog(LLV_DEBUG, LOCATION, NULL,
+                plog(ASL_LEVEL_DEBUG, 
                      "received start_dpd command on vpn control socket.\n");
                 LIST_FOREACH_SAFE(srv, &elem->bound_addresses, chain, t_addr) {
                     if (pkt->address == srv->address) {
-                        struct sockaddr_in     daddr;
+                        union {                             // Wcast-align fix - force alignment
+                            struct sockaddr_storage ss;
+                            struct sockaddr_in addr_in;
+                        } daddr;
 
-                        bzero(&daddr, sizeof(daddr));
-                        daddr.sin_len = sizeof(daddr);
-                        daddr.sin_addr.s_addr = srv->address;
-                        daddr.sin_port = 0;
-                        daddr.sin_family = AF_INET;
+                        bzero(&daddr, sizeof(struct sockaddr_in));
+                        daddr.addr_in.sin_len = sizeof(struct sockaddr_in);
+                        daddr.addr_in.sin_addr.s_addr = srv->address;
+                        daddr.addr_in.sin_port = 0;
+                        daddr.addr_in.sin_family = AF_INET;
 
                         /* start the dpd */
-                        error = ph1_force_dpd(&daddr);
+                        error = ike_session_ph1_force_dpd(&daddr.ss);
                         break;
                     }
                 }
@@ -493,15 +529,13 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
 
                case VPNCTL_CMD_ASSERT:
                        {
-                               struct vpnctl_cmd_assert *pkt = (struct vpnctl_cmd_assert *)combuf;
+                               struct vpnctl_cmd_assert *pkt = ALIGNED_CAST(struct vpnctl_cmd_assert *)combuf;
 //                             struct bound_addr *addr;
 //                             struct bound_addr *t_addr;
                                struct sockaddr_in saddr;
                                struct sockaddr_in daddr;
 
-                               plog(LLV_DEBUG, LOCATION, NULL,
-                                        "received assert command on vpn control socket.\n");
-                               plogdump(LLV_DEBUG2, pkt, ntohs(hdr->len) + sizeof(struct vpnctl_hdr));
+                               plogdump(ASL_LEVEL_DEBUG, pkt, ntohs(hdr->len) + sizeof(struct vpnctl_hdr), "received assert command on vpn control socket.\n");
 //                             LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
 //                                     if (pkt->dst_address == addr->address) {
                                                bzero(&saddr, sizeof(saddr));
@@ -515,7 +549,7 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
                                                daddr.sin_port = 0;
                                                daddr.sin_family = AF_INET;
 
-                                               error = vpn_assert((struct sockaddr *)&saddr, (struct sockaddr *)&daddr);
+                                               error = vpn_assert((struct sockaddr_storage *)&saddr, (struct sockaddr_storage *)&daddr);
                                                break;
 //                                     }
 //                             }
@@ -524,11 +558,11 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
 
                case VPNCTL_CMD_RECONNECT:
                        {
-                               struct vpnctl_cmd_connect *pkt = (struct vpnctl_cmd_connect *)combuf;
+                               struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
                                struct bound_addr *addr;
                                struct bound_addr *t_addr;
 
-                               plog(LLV_DEBUG, LOCATION, NULL,
+                               plog(ASL_LEVEL_DEBUG, 
                                         "received reconnect command on vpn control socket.\n");
                                LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
                                        if (pkt->address == addr->address) {
@@ -541,7 +575,7 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
                        break;
 
                default:
-                       plog(LLV_ERROR, LOCATION, NULL,
+                       plog(ASL_LEVEL_ERR, 
                                "invalid command: %d\n", ntohs(hdr->msg_type));
                        error = -1;             // for now
                        break;
@@ -559,11 +593,11 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
 static int
 vpncontrol_reply(int so, char *combuf)
 {
-       size_t tlen;
+       ssize_t tlen;
 
        tlen = send(so, combuf, sizeof(struct vpnctl_hdr), 0);
        if (tlen < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "failed to send vpn_control message: %s\n", strerror(errno));
                return -1;
        }
@@ -572,30 +606,31 @@ vpncontrol_reply(int so, char *combuf)
 }
 
 int
-vpncontrol_notify_need_authinfo(struct ph1handle *iph1, void* attr_list, size_t attr_len)
+vpncontrol_notify_need_authinfo(phase1_handle_t *iph1, void* attr_list, size_t attr_len)
 {
        struct vpnctl_status_need_authinfo *msg = NULL; 
        struct vpnctl_socket_elem *sock_elem;
        struct bound_addr *bound_addr;
-       size_t tlen, msg_size;  
+       size_t msg_size;
+       ssize_t tlen;
        u_int32_t address;
        void *ptr;
        
        if (!iph1)
                goto end;
 
-       plog(LLV_DEBUG, LOCATION, NULL,
+       plog(ASL_LEVEL_DEBUG, 
                "sending vpn_control xauth need info status\n");
 
        msg = (struct vpnctl_status_need_authinfo *)racoon_malloc(msg_size = sizeof(struct vpnctl_status_need_authinfo) + attr_len);
        if (msg == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "unable to allocate space for vpn control message.\n");
                return -1;
        }
        msg->hdr.flags = 0;
                                
-       if (iph1->remote->sa_family == AF_INET)
+       if (iph1->remote->ss_family == AF_INET)
                address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
        else
                goto end;               // for now              
@@ -615,12 +650,10 @@ vpncontrol_notify_need_authinfo(struct ph1handle *iph1, void* attr_list, size_t
                LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
                        if (bound_addr->address == 0xFFFFFFFF ||
                                bound_addr->address == address) {
-                               plog(LLV_DEBUG, LOCATION, NULL,
-                                               "vpn control writing %d bytes\n", msg_size);
-                               plogdump(LLV_DEBUG, msg, msg_size);
+                               plog(ASL_LEVEL_DEBUG, "vpn control writing %zu bytes\n", msg_size);
                                tlen = send(sock_elem->sock, msg, msg_size, 0);
                                if (tlen < 0) {
-                                       plog(LLV_ERROR, LOCATION, NULL,
+                                       plog(ASL_LEVEL_ERR, 
                                                "failed to send vpn_control need authinfo status: %s\n", strerror(errno));
                                }
                                break;
@@ -640,13 +673,14 @@ vpncontrol_notify_ike_failed(u_int16_t notify_code, u_int16_t from, u_int32_t ad
        struct vpnctl_status_failed *msg = NULL; 
        struct vpnctl_socket_elem *sock_elem;
        struct bound_addr *bound_addr;
-       size_t tlen, len;
+       size_t len;
+    ssize_t tlen;
        
        len = sizeof(struct vpnctl_status_failed) + data_len;
        
        msg = (struct vpnctl_status_failed *)racoon_malloc(len);
        if (msg == NULL) {
-               plog(LLV_DEBUG, LOCATION, NULL,
+               plog(ASL_LEVEL_DEBUG, 
                                "unable to allcate memory for vpn control status message.\n");
                return -1;
        }
@@ -659,7 +693,7 @@ vpncontrol_notify_ike_failed(u_int16_t notify_code, u_int16_t from, u_int32_t ad
        msg->from = htons(from);
        if (data_len > 0)
                memcpy(msg->data, data, data_len);      
-       plog(LLV_DEBUG, LOCATION, NULL,
+       plog(ASL_LEVEL_DEBUG, 
                        "sending vpn_control ike failed message - code=%d  from=%s.\n", notify_code,
                                        (from == FROM_LOCAL ? "local" : "remote"));
 
@@ -669,8 +703,8 @@ vpncontrol_notify_ike_failed(u_int16_t notify_code, u_int16_t from, u_int32_t ad
                                bound_addr->address == address) {
                                tlen = send(sock_elem->sock, msg, len, 0);
                                if (tlen < 0) {
-                                       plog(LLV_ERROR, LOCATION, NULL,
-                                               "unable to send vpn_control ike notify failed: %s\n", strerror(errno));
+                                       plog(ASL_LEVEL_ERR, 
+                                               "Unable to send vpn_control ike notify failed: %s\n", strerror(errno));
                                }
                                break;
                        }
@@ -682,20 +716,43 @@ vpncontrol_notify_ike_failed(u_int16_t notify_code, u_int16_t from, u_int32_t ad
        return 0;
 }
 
+char *
+vpncontrol_status_2_str(u_int16_t msg_type)
+{
+    switch (msg_type) {
+        case VPNCTL_STATUS_IKE_FAILED:
+            return "IKE failed";
+        case VPNCTL_STATUS_PH1_START_US:
+            return "Phase 1 started by us";
+        case VPNCTL_STATUS_PH1_START_PEER:
+            return "Phase 1 started by peer";
+        case VPNCTL_STATUS_PH1_ESTABLISHED:
+            return "Phase 1 established";
+        case VPNCTL_STATUS_PH2_START:
+            return "Phase 2 started";
+        case VPNCTL_STATUS_PH2_ESTABLISHED:
+            return "Phase 2 established";
+        case VPNCTL_STATUS_NEED_AUTHINFO:
+            return "Need authentication info";
+        case VPNCTL_STATUS_NEED_REAUTHINFO:
+            return "Need re-authentication info";
+        default:
+            return "";
+    }
+}
+
 
 int
-vpncontrol_notify_phase_change(int start, u_int16_t from, struct ph1handle *iph1, struct ph2handle *iph2)
+vpncontrol_notify_phase_change(int start, u_int16_t from, phase1_handle_t *iph1, phase2_handle_t *iph2)
 {
        struct vpnctl_status_phase_change *msg; 
        struct vpnctl_socket_elem *sock_elem;
        struct bound_addr *bound_addr;
-       size_t tlen, msg_size;  
+       ssize_t tlen;
+       size_t msg_size;        
        u_int32_t address;
        
-       plog(LLV_DEBUG, LOCATION, NULL,
-               "sending vpn_control phase change status\n");
-
-       if (iph1 && !start && iph1->mode_cfg && iph1->mode_cfg->xauth.status != XAUTHST_OK) {
+    if (iph1 && !start && iph1->mode_cfg && iph1->mode_cfg->xauth.status != XAUTHST_OK) {
                if (vpn_get_config(iph1, &msg, &msg_size) == 1)
                        return 0;       /* mode config not finished yet */
        } else {
@@ -704,25 +761,30 @@ vpncontrol_notify_phase_change(int start, u_int16_t from, struct ph1handle *iph1
        }
                
        if (msg == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                                                "unable to allocate space for vpn control message.\n");
                return -1;
        }
        if (iph1) {
-               if (iph1->remote->sa_family == AF_INET)
+               if (iph1->remote->ss_family == AF_INET)
                        address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
                else
                        goto end;               // for now              
                msg->hdr.msg_type = htons(start ? 
                        (from == FROM_LOCAL ? VPNCTL_STATUS_PH1_START_US : VPNCTL_STATUS_PH1_START_PEER) 
                        : VPNCTL_STATUS_PH1_ESTABLISHED);
+               // TODO: indicate version
        } else {
-               if (iph2->dst->sa_family == AF_INET)
+               if (iph2->dst->ss_family == AF_INET)
                        address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
                else
                        goto end;               // for now
                msg->hdr.msg_type = htons(start ? VPNCTL_STATUS_PH2_START : VPNCTL_STATUS_PH2_ESTABLISHED);
+               // TODO: indicate version
        }
+    plog(ASL_LEVEL_NOTICE,
+         ">>>>> phase change status = %s\n", vpncontrol_status_2_str(ntohs(msg->hdr.msg_type)));
+
        msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
        msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));
        msg->address = address;
@@ -731,12 +793,10 @@ vpncontrol_notify_phase_change(int start, u_int16_t from, struct ph1handle *iph1
                LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
                        if (bound_addr->address == 0xFFFFFFFF ||
                                bound_addr->address == address) {
-                               plog(LLV_DEBUG, LOCATION, NULL,
-                                               "vpn control writing %d bytes\n", msg_size);
-                               plogdump(LLV_DEBUG, msg, msg_size);
+                               plog(ASL_LEVEL_DEBUG, "vpn control writing %zu bytes\n", msg_size);
                                tlen = send(sock_elem->sock, msg, msg_size, 0);
                                if (tlen < 0) {
-                                       plog(LLV_ERROR, LOCATION, NULL,
+                                       plog(ASL_LEVEL_ERR, 
                                                "failed to send vpn_control phase change status: %s\n", strerror(errno));
                                }
                                break;
@@ -756,7 +816,7 @@ vpncontrol_notify_peer_resp (u_int16_t notify_code, u_int32_t address)
        struct vpnctl_status_peer_resp msg; 
        struct vpnctl_socket_elem *sock_elem;
        struct bound_addr *bound_addr;
-       size_t tlen;
+       ssize_t tlen;
        int    rc = -1;
 
        bzero(&msg, sizeof(msg));
@@ -765,7 +825,7 @@ vpncontrol_notify_peer_resp (u_int16_t notify_code, u_int32_t address)
        msg.hdr.len = htons(sizeof(msg) - sizeof(msg.hdr));
        msg.address = address;
        msg.ike_code = notify_code;
-       plog(LLV_DEBUG, LOCATION, NULL,
+       plog(ASL_LEVEL_DEBUG, 
                 "sending vpn_control status (peer response) message - code=%d  addr=%x.\n", notify_code, address);
        
        LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
@@ -774,7 +834,7 @@ vpncontrol_notify_peer_resp (u_int16_t notify_code, u_int32_t address)
                                bound_addr->address == address) {
                                tlen = send(sock_elem->sock, &msg, sizeof(msg), 0);
                                if (tlen < 0) {
-                                       plog(LLV_ERROR, LOCATION, NULL,
+                                       plog(ASL_LEVEL_ERR, 
                                                 "unable to send vpn_control status (peer response): %s\n", strerror(errno));
                                } else {
                                        rc = 0;
@@ -788,13 +848,13 @@ vpncontrol_notify_peer_resp (u_int16_t notify_code, u_int32_t address)
 }
 
 int
-vpncontrol_notify_peer_resp_ph1 (u_int16_t notify_code, struct ph1handle *iph1)
+vpncontrol_notify_peer_resp_ph1 (u_int16_t notify_code, phase1_handle_t *iph1)
 {
        u_int32_t address;
        int       rc;
 
        if (iph1 && iph1->parent_session && iph1->parent_session->controller_awaiting_peer_resp) {
-               if (iph1->remote->sa_family == AF_INET)
+               if (iph1->remote->ss_family == AF_INET)
                        address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
                else
                        address = 0;
@@ -809,13 +869,13 @@ vpncontrol_notify_peer_resp_ph1 (u_int16_t notify_code, struct ph1handle *iph1)
 }
        
 int
-vpncontrol_notify_peer_resp_ph2 (u_int16_t notify_code, struct ph2handle *iph2)
+vpncontrol_notify_peer_resp_ph2 (u_int16_t notify_code, phase2_handle_t *iph2)
 {
        u_int32_t address;
        int       rc;
 
        if (iph2 && iph2->parent_session && iph2->parent_session->controller_awaiting_peer_resp) {
-               if (iph2->dst->sa_family == AF_INET)
+               if (iph2->dst->ss_family == AF_INET)
                        address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
                else
                        address = 0;
@@ -830,18 +890,16 @@ vpncontrol_notify_peer_resp_ph2 (u_int16_t notify_code, struct ph2handle *iph2)
 }
 
 int
-vpncontrol_init()
+vpncontrol_init(void)
 {
+    int sock;
+    
        if (vpncontrolsock_path == NULL) {
                lcconf->sock_vpncontrol = -1;
                return 0;
        }
 
-       if ( (lcconf->sock_vpncontrol = checklaunchd()) ){
-               return 0;
-       }
-       else {  
-               
+       if ( (lcconf->sock_vpncontrol = checklaunchd()) == 0 ) { 
                memset(&sunaddr, 0, sizeof(sunaddr));
                sunaddr.sun_family = AF_UNIX;
                snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
@@ -849,15 +907,19 @@ vpncontrol_init()
 
                lcconf->sock_vpncontrol = socket(AF_UNIX, SOCK_STREAM, 0);
                if (lcconf->sock_vpncontrol == -1) {
-                       plog(LLV_ERROR, LOCATION, NULL,
+                       plog(ASL_LEVEL_ERR, 
                                "socket: %s\n", strerror(errno));
                        return -1;
                }
 
+               if (fcntl(lcconf->sock_vpncontrol, F_SETFL, O_NONBLOCK) == -1) {
+                       plog(ASL_LEVEL_ERR, "failed to put VPN-Control socket in non-blocking mode\n");
+               }
+        
                unlink(sunaddr.sun_path);
                if (bind(lcconf->sock_vpncontrol, (struct sockaddr *)&sunaddr,
                                sizeof(sunaddr)) != 0) {
-                       plog(LLV_ERROR, LOCATION, NULL,
+                       plog(ASL_LEVEL_ERR, 
                                "bind(sockname:%s): %s\n",
                                sunaddr.sun_path, strerror(errno));
                        (void)close(lcconf->sock_vpncontrol);
@@ -865,7 +927,7 @@ vpncontrol_init()
                }
 
                if (chown(sunaddr.sun_path, vpncontrolsock_owner, vpncontrolsock_group) != 0) {
-                       plog(LLV_ERROR, LOCATION, NULL
+                       plog(ASL_LEVEL_ERR
                                "chown(%s, %d, %d): %s\n", 
                                sunaddr.sun_path, vpncontrolsock_owner, 
                                vpncontrolsock_group, strerror(errno));
@@ -874,7 +936,7 @@ vpncontrol_init()
                }
 
                if (chmod(sunaddr.sun_path, vpncontrolsock_mode) != 0) {
-                       plog(LLV_ERROR, LOCATION, NULL
+                       plog(ASL_LEVEL_ERR
                                "chmod(%s, 0%03o): %s\n", 
                                sunaddr.sun_path, vpncontrolsock_mode, strerror(errno));
                        (void)close(lcconf->sock_vpncontrol);
@@ -882,36 +944,60 @@ vpncontrol_init()
                }
 
                if (listen(lcconf->sock_vpncontrol, 5) != 0) {
-                       plog(LLV_ERROR, LOCATION, NULL,
+                       plog(ASL_LEVEL_ERR, 
                                "listen(sockname:%s): %s\n",
                                sunaddr.sun_path, strerror(errno));
                        (void)close(lcconf->sock_vpncontrol);
                        return -1;
                }
-               plog(LLV_DEBUG, LOCATION, NULL,
+               plog(ASL_LEVEL_DEBUG, 
                        "opened %s as racoon management.\n", sunaddr.sun_path);
-
-               return 0;
        }
+    lcconf->vpncontrol_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, lcconf->sock_vpncontrol, 0, dispatch_get_main_queue());
+    if (lcconf->vpncontrol_source == NULL) {
+        plog(ASL_LEVEL_ERR, "could not create vpncontrol socket source.");
+        return -1;
+    }
+    dispatch_source_set_event_handler_f(lcconf->vpncontrol_source, vpncontrol_handler);
+    sock = lcconf->sock_vpncontrol;
+    dispatch_source_set_cancel_handler(lcconf->vpncontrol_source, 
+                                         ^{
+                                                close(sock);
+                                         });
+    dispatch_resume(lcconf->vpncontrol_source);
+    return 0;
 }
 
+void
+vpncontrol_disconnect_all(struct vpnctl_socket_elem *elem, const char *reason)
+{
+    struct bound_addr *addr;
+    struct bound_addr *t_addr;
+    
+    plog(ASL_LEVEL_DEBUG, 
+         "received disconnect all command.\n");
+    
+    LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
+        /* stop any connections */
+        vpn_disconnect(addr, reason);
+    }
+}
 
 void
 vpncontrol_close()
 {
-       struct vpnctl_socket_elem *elem;
+    struct vpnctl_socket_elem *elem;
        struct vpnctl_socket_elem *t_elem;
        
-       plog(LLV_DEBUG, LOCATION, NULL,
-               "vpncontrol_close.\n");
-
-       if (lcconf->sock_vpncontrol != -1) {
-               close(lcconf->sock_vpncontrol);
-               lcconf->sock_vpncontrol = -1;
-       }
-       LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem)
-               vpncontrol_close_comm(elem);
-               
+    plog(ASL_LEVEL_DEBUG, 
+         "vpncontrol_close.\n");
+
+    dispatch_source_cancel(lcconf->vpncontrol_source);
+    lcconf->vpncontrol_source = NULL;
+    
+    lcconf->sock_vpncontrol = -1;
+    LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem)
+        vpncontrol_close_comm(elem);
 }
 
 static void
@@ -920,12 +1006,12 @@ vpncontrol_close_comm(struct vpnctl_socket_elem *elem)
        struct bound_addr *addr;
        struct bound_addr *t_addr;
 
-       plog(LLV_DEBUG, LOCATION, NULL,
+       plog(ASL_LEVEL_DEBUG, 
                "vpncontrol_close_comm.\n");
        
        LIST_REMOVE(elem, chain);
-       if (elem->sock != -1)   
-               close(elem->sock);
+       if (elem->sock != -1)
+               dispatch_source_cancel(elem->source);
        LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
                flushsainfo_dynamic(addr->address);
                LIST_REMOVE(addr, chain);