]> git.saurik.com Git - apple/ipsec.git/blobdiff - ipsec-tools/racoon/vpn_control.c
ipsec-305.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / vpn_control.c
index cc81603469182354da1b1b11b79527db0f45a7b3..1b70dd2daec25b91fa1947d030be432ee031f229 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 "isakmp_inf.h"
 #include "session.h"
 #include "gcmalloc.h"
+#include "isakmp_cfg.h"
+#include "sainfo.h"
 
 #ifdef ENABLE_VPNCONTROL_PORT
 char *vpncontrolsock_path = VPNCONTROLSOCK_PATH;
@@ -111,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 *, size_t);
+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;
@@ -135,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;
        }
@@ -171,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;
@@ -187,84 +202,106 @@ 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;
        }
@@ -273,38 +310,56 @@ 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;
        }
 
-       (void)vpncontrol_process(elem, combuf);
+       if (len < (sizeof(hdr) + ntohs(hdr.len))) {
+               plog(ASL_LEVEL_ERR,
+                        "invalid length of vpn_control command - len=%ld - expected %ld\n", len, (sizeof(hdr) + ntohs(hdr.len)));
+               goto end;
+       }
+
+       (void)vpncontrol_process(elem, combuf, len);
 
 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)
+vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf, size_t combuf_len)
 {
        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;
+                               if (combuf_len < sizeof(struct vpnctl_cmd_bind)) {
+                                       plog(ASL_LEVEL_ERR, "invalid header length for vpnctl bind cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_bind));
+                                       error = -1;
+                                       break;
+                               }
+
+                               struct vpnctl_cmd_bind *pkt = ALIGNED_CAST(struct vpnctl_cmd_bind *)combuf;
                                struct bound_addr *addr;
+
+                               if (combuf_len < (sizeof(struct vpnctl_cmd_bind) + ntohs(pkt->vers_len))) {
+                                       plog(ASL_LEVEL_ERR, "invalid length for vpnctl bind cmd - len=%ld - expected %ld\n", combuf_len, (sizeof(struct vpnctl_cmd_bind) + ntohs(pkt->vers_len)));
+                                       error = -1;
+                                       break;
+                               }
                        
-                               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;
@@ -312,7 +367,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;
@@ -327,11 +382,17 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
                        
                case VPNCTL_CMD_UNBIND:
                        {
-                               struct vpnctl_cmd_unbind *pkt = (struct vpnctl_cmd_unbind *)combuf;
+                               if (combuf_len < sizeof(struct vpnctl_cmd_unbind)) {
+                                       plog(ASL_LEVEL_ERR, "invalid header length for vpnctl unbind cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_unbind));
+                                       error = -1;
+                                       break;
+                               }
+
+                               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 ||
@@ -348,12 +409,18 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
 
                case VPNCTL_CMD_REDIRECT:
                        {
-                               struct vpnctl_cmd_redirect *redirect_msg = (struct vpnctl_cmd_redirect *)combuf;
+                               if (combuf_len < sizeof(struct vpnctl_cmd_redirect)) {
+                                       plog(ASL_LEVEL_ERR, "invalid header length for vpnctl redirect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_redirect));
+                                       error = -1;
+                                       break;
+                               }
+
+                               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) {
@@ -372,7 +439,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;
@@ -391,12 +458,24 @@ 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;
+                               if (combuf_len < sizeof(struct vpnctl_cmd_xauth_info)) {
+                                       plog(ASL_LEVEL_ERR, "invalid header length for vpnctl xauth info cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_xauth_info));
+                                       error = -1;
+                                       break;
+                               }
+
+                               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,
+                               if (combuf_len < (sizeof(struct vpnctl_cmd_xauth_info) + ntohs(pkt->hdr.len) - sizeof(u_int32_t))) {
+                                       plog(ASL_LEVEL_ERR, "invalid length for vpnctl xauth info cmd - len=%ld - expected %ld\n", combuf_len, (sizeof(struct vpnctl_cmd_xauth_info) + ntohs(pkt->hdr.len) - sizeof(u_int32_t)));
+                                       error = -1;
+                                       break;
+                               }
+
+                               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) {
@@ -408,19 +487,54 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
                                }
                        }
                        break;
-                               
+
+               case VPNCTL_CMD_SET_NAT64_PREFIX:
+                       {
+                               if (combuf_len < sizeof(struct vpnctl_cmd_set_nat64_prefix)) {
+                                       plog(ASL_LEVEL_ERR, "invalid header length for vpnctl nat64 prefix cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_set_nat64_prefix));
+                                       error = -1;
+                                       break;
+                               }
+
+                               struct vpnctl_cmd_set_nat64_prefix *pkt = ALIGNED_CAST(struct vpnctl_cmd_set_nat64_prefix *)combuf;
+                               struct bound_addr *addr;
+                               struct bound_addr *t_addr;
+
+                               plog(ASL_LEVEL_DEBUG,
+                                               "received set v6 prefix of len %u command on vpn control socket, adding to all addresses.\n", pkt->nat64_prefix.length);
+                               LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
+                                       memcpy(&addr->nat64_prefix, &pkt->nat64_prefix, sizeof(addr->nat64_prefix));
+                               }
+                       }
+                       break;
+
                case VPNCTL_CMD_CONNECT:
                        {
-                               struct vpnctl_cmd_connect *pkt = (struct vpnctl_cmd_connect *)combuf;
+                               if (combuf_len < sizeof(struct vpnctl_cmd_connect)) {
+                                       plog(ASL_LEVEL_ERR, "invalid header length for vpnctl connect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_connect));
+                                       error = -1;
+                                       break;
+                               }
+
+                               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,
+                               if (pending_signal_handle) {
+                                       /*
+                                        * This check is done to ensure that a SIGUSR1 signal to re-read the configuration file
+                                        * is completed before calling a connect. This is to fix the issue seen in (rdar://problem/25641686)
+                                        */
+                                       check_sigreq();
+                                       pending_signal_handle = 0;
+                               }
+
+                               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) {
                                                /* start the connection */
-                                               error = vpn_connect(addr);
+                                               error = vpn_connect(addr, VPN_STARTED_BY_API);
                                                break;
                                        }
                                }
@@ -429,16 +543,22 @@ vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
                        
                case VPNCTL_CMD_DISCONNECT:
                        {
-                               struct vpnctl_cmd_connect *pkt = (struct vpnctl_cmd_connect *)combuf;
+                               if (combuf_len < sizeof(struct vpnctl_cmd_connect)) {
+                                       plog(ASL_LEVEL_ERR, "invalid header length for vpnctl disconnect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_connect));
+                                       error = -1;
+                                       break;
+                               }
+
+                               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;
                                        }
                                }
@@ -447,17 +567,21 @@ 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;
+                               if (combuf_len < sizeof(struct vpnctl_cmd_start_ph2)) {
+                                       plog(ASL_LEVEL_ERR, "invalid header length for vpnctl start ph2 cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_start_ph2));
+                                       error = -1;
+                                       break;
+                               }
+
+                               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 */
-                                               error = vpn_start_ph2(addr, pkt);
+                                               error = vpn_start_ph2(addr, pkt, combuf_len);
                                                break;
                                        }
                                }
@@ -466,32 +590,100 @@ 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;
+                               if (combuf_len < sizeof(struct vpnctl_cmd_start_dpd)) {
+                                       plog(ASL_LEVEL_ERR, "invalid header length for vpnctl start dpd cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_start_dpd));
+                                       error = -1;
+                                       break;
+                               }
+
+                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;
                     }
                 }
             }
                        break;
 
+               case VPNCTL_CMD_ASSERT:
+                       {
+                               if (combuf_len < sizeof(struct vpnctl_cmd_assert)) {
+                                       plog(ASL_LEVEL_ERR, "invalid header length for vpnctl assert cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_assert));
+                                       error = -1;
+                                       break;
+                               }
+
+                               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;
+
+                               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));
+                                               saddr.sin_len = sizeof(saddr);
+                                               saddr.sin_addr.s_addr = pkt->src_address;
+                                               saddr.sin_port = 0;
+                                               saddr.sin_family = AF_INET;
+                                               bzero(&daddr, sizeof(daddr));
+                                               daddr.sin_len = sizeof(daddr);
+                                               daddr.sin_addr.s_addr = pkt->dst_address;
+                                               daddr.sin_port = 0;
+                                               daddr.sin_family = AF_INET;
+
+                                               error = vpn_assert(ALIGNED_CAST(struct sockaddr_storage *)&saddr, ALIGNED_CAST(struct sockaddr_storage *)&daddr);
+                                               break;
+//                                     }
+//                             }
+                       }
+                       break;
+
+               case VPNCTL_CMD_RECONNECT:
+                       {
+                               if (combuf_len < sizeof(struct vpnctl_cmd_connect)) {
+                                       plog(ASL_LEVEL_ERR, "invalid header length for vpnctl reconnect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_connect));
+                                       error = -1;
+                                       break;
+                               }
+
+                               struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
+                               struct bound_addr *addr;
+                               struct bound_addr *t_addr;
+
+                               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) {
+                                               /* start the connection */
+                                               error = vpn_connect(addr, VPN_RESTARTED_BY_API);
+                                               break;
+                                       }
+                               }
+                       }
+                       break;
+
                default:
-                       plog(LLV_ERROR, LOCATION, NULL,
+                       plog(ASL_LEVEL_ERR, 
                                "invalid command: %d\n", ntohs(hdr->msg_type));
                        error = -1;             // for now
                        break;
@@ -509,11 +701,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;
        }
@@ -521,34 +713,52 @@ vpncontrol_reply(int so, char *combuf)
        return 0;
 }
 
+bool
+vpncontrol_set_nat64_prefix(nw_nat64_prefix_t *prefix)
+{
+       struct vpnctl_socket_elem *sock_elem;
+       struct bound_addr *bound_addr;
+
+       LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
+               LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
+                       if (bound_addr->nat64_prefix.length != 0) {
+                               memcpy(prefix, &bound_addr->nat64_prefix, sizeof(*prefix));
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
 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)
-               address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
-       else
-               goto end;               // for now              
+
+       address = iph1_get_remote_v4_address(iph1);
+       if (address == 0) {
+               goto end;
+       }
 
        msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
        msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));   
@@ -557,7 +767,7 @@ vpncontrol_notify_need_authinfo(struct ph1handle *iph1, void* attr_list, size_t
        } else {
                msg->hdr.msg_type = htons(VPNCTL_STATUS_NEED_REAUTHINFO);
        }
-       msg->address = address;
+       msg->address = iph1_get_remote_v4_address(iph1);
        ptr = msg + 1;
        memcpy(ptr, attr_list, attr_len);
 
@@ -565,12 +775,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;
@@ -590,13 +798,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;
        }
@@ -609,7 +818,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"));
 
@@ -619,8 +828,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;
                        }
@@ -632,20 +841,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) {
+    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 {
@@ -654,25 +886,32 @@ 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)
-                       address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
-               else
-                       goto end;               // for now              
+               address = iph1_get_remote_v4_address(iph1);
+               if (address == 0) {
+                       plog(ASL_LEVEL_ERR, "bad address for ph1 status change.\n");
+                       goto end;
+               }
                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)
-                       address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
-               else
-                       goto end;               // for now
+               address = iph2_get_remote_v4_address(iph2);
+               if (address == 0) {
+                       plog(ASL_LEVEL_ERR, "bad address for ph2 status change.\n");
+                       goto end;
+               }
                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;
@@ -681,12 +920,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;
@@ -700,20 +937,82 @@ end:
        return 0;
 }
 
+static int
+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;
+       ssize_t tlen;
+       int    rc = -1;
+
+       bzero(&msg, sizeof(msg));
+       msg.hdr.msg_type = htons(VPNCTL_STATUS_PEER_RESP);
+       msg.hdr.cookie = msg.hdr.reserved = msg.hdr.result = 0;
+       msg.hdr.len = htons(sizeof(msg) - sizeof(msg.hdr));
+       msg.address = address;
+       msg.ike_code = notify_code;
+       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) {
+               LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
+                       if (bound_addr->address == 0xFFFFFFFF ||
+                               bound_addr->address == address) {
+                               tlen = send(sock_elem->sock, &msg, sizeof(msg), 0);
+                               if (tlen < 0) {
+                                       plog(ASL_LEVEL_ERR, 
+                                                "unable to send vpn_control status (peer response): %s\n", strerror(errno));
+                               } else {
+                                       rc = 0;
+                               }
+                               break;
+                       }
+               }
+       }
+
+       return rc;
+}
 
 int
-vpncontrol_init()
+vpncontrol_notify_peer_resp_ph1 (u_int16_t notify_code, phase1_handle_t *iph1)
 {
-       if (vpncontrolsock_path == NULL) {
-               lcconf->sock_vpncontrol = -1;
+       if (iph1 && iph1->parent_session && iph1->parent_session->controller_awaiting_peer_resp) {
+               int rc;
+               if ((rc = vpncontrol_notify_peer_resp(notify_code, iph1_get_remote_v4_address(iph1))) == 0) {
+                       iph1->parent_session->controller_awaiting_peer_resp = 0;
+               }
+               return rc;
+       } else {
+               return 0;
+       }
+}
+       
+int
+vpncontrol_notify_peer_resp_ph2 (u_int16_t notify_code, phase2_handle_t *iph2)
+{
+       if (iph2 && iph2->parent_session && iph2->parent_session->controller_awaiting_peer_resp) {
+               int rc;
+               if ((rc = vpncontrol_notify_peer_resp(notify_code, iph2_get_remote_v4_address(iph2))) == 0) {
+                       iph2->parent_session->controller_awaiting_peer_resp = 0;
+               }
+               return rc;
+       } else {
                return 0;
        }
+}
 
-       if ( (lcconf->sock_vpncontrol = checklaunchd()) ){
+int
+vpncontrol_init(void)
+{
+    int sock;
+    
+       if (vpncontrolsock_path == NULL) {
+               lcconf->sock_vpncontrol = -1;
                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),
@@ -721,15 +1020,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);
@@ -737,7 +1040,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));
@@ -746,7 +1049,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);
@@ -754,36 +1057,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
@@ -792,12 +1119,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);
@@ -807,6 +1134,7 @@ vpncontrol_close_comm(struct vpnctl_socket_elem *elem)
        }
        racoon_free(elem);
        check_auto_exit();
+
 }
 
 int