]> git.saurik.com Git - apple/ipsec.git/blame - ipsec-tools/racoon/vpn_control.c
ipsec-305.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / vpn_control.c
CommitLineData
52b7d2ce
A
1/* $Id: vpn_control.c,v 1.17.2.4 2005/07/12 11:49:44 manubsd Exp $ */
2
3/*
4 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
5 *
6 * @APPLE_LICENSE_HEADER_START@
7 *
8 * The contents of this file constitute Original Code as defined in and
9 * are subject to the Apple Public Source License Version 1.1 (the
10 * "License"). You may not use this file except in compliance with the
11 * License. Please obtain a copy of the License at
12 * http://www.apple.com/publicsource and read it before using this file.
13 *
14 * This Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25/*
26 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. Neither the name of the project nor the names of its contributors
38 * may be used to endorse or promote products derived from this software
39 * without specific prior written permission.
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 */
53
65c25746
A
54//#define LION_TEST 1
55
56
52b7d2ce
A
57#include "config.h"
58
59#include <sys/types.h>
60#include <sys/param.h>
61#include <sys/socket.h>
62#include <sys/signal.h>
63#include <sys/stat.h>
64#include <sys/un.h>
65
65c25746 66#include <net/pfkeyv2.h>
52b7d2ce
A
67
68#include <netinet/in.h>
69#ifndef HAVE_NETINET6_IPSEC
70#include <netinet/ipsec.h>
71#else
72#include <netinet6/ipsec.h>
73#endif
74
75
76#include <stdlib.h>
77#include <stdio.h>
78#include <string.h>
79#include <errno.h>
80#include <netdb.h>
81#ifdef HAVE_UNISTD_H
82#include <unistd.h>
83#endif
d1e348cf 84#include <launch.h>
65c25746 85#ifndef LION_TEST
85f41bec 86#include <launch_priv.h>
65c25746 87#endif
85f41bec 88#include <fcntl.h>
52b7d2ce
A
89
90#include "var.h"
91#include "misc.h"
92#include "vmbuf.h"
93#include "plog.h"
94#include "sockmisc.h"
95#include "debug.h"
96
97#include "schedule.h"
98#include "localconf.h"
99#include "remoteconf.h"
100#include "grabmyaddr.h"
101#include "isakmp_var.h"
102#include "isakmp.h"
103#include "oakley.h"
104#include "handler.h"
52b7d2ce
A
105#include "pfkey.h"
106#include "ipsec_doi.h"
107#include "vpn_control.h"
108#include "vpn_control_var.h"
109#include "isakmp_inf.h"
110#include "session.h"
111#include "gcmalloc.h"
e8d9021d 112#include "isakmp_cfg.h"
85f41bec 113#include "sainfo.h"
52b7d2ce
A
114
115#ifdef ENABLE_VPNCONTROL_PORT
116char *vpncontrolsock_path = VPNCONTROLSOCK_PATH;
117uid_t vpncontrolsock_owner = 0;
118gid_t vpncontrolsock_group = 0;
119mode_t vpncontrolsock_mode = 0600;
120
121static struct sockaddr_un sunaddr;
886926c0 122static int vpncontrol_process (struct vpnctl_socket_elem *, char *, size_t);
65c25746
A
123static int vpncontrol_reply (int, char *);
124static void vpncontrol_close_comm (struct vpnctl_socket_elem *);
125static int checklaunchd (void);
126extern int vpn_get_config (phase1_handle_t *, struct vpnctl_status_phase_change **, size_t *);
127extern int vpn_xauth_reply (u_int32_t, void *, size_t);
d1e348cf
A
128
129
130int
131checklaunchd()
132{
133 launch_data_t checkin_response = NULL;
65c25746
A
134#ifdef LION_TEST
135 launch_data_t checkin_request = NULL;
136#endif
d1e348cf
A
137 launch_data_t sockets_dict, listening_fd_array;
138 launch_data_t listening_fd;
139 struct sockaddr_storage fdsockaddr;
140 socklen_t fdsockaddrlen = sizeof(fdsockaddr);
141 int socketct;
142 int i;
143 int listenerct;
144 int returnval = 0;
145 int fd;
146
147 /* check in with launchd */
65c25746
A
148#ifdef LION_TEST
149 if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) {
150#else
85f41bec 151 if ((checkin_response = launch_socket_service_check_in()) == NULL) {
65c25746
A
152#endif
153 plog(ASL_LEVEL_ERR,
85f41bec 154 "failed to launch_socket_service_check_in.\n");
d1e348cf
A
155 goto done;
156 }
65c25746
A
157#ifdef LION_TEST
158 if ((checkin_response = launch_msg(checkin_request)) == NULL) {
159 plog(ASL_LEVEL_ERR, "failed to launch_msg.\n");
160 goto done;
161 }
162#endif
d1e348cf 163 if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) {
65c25746 164 plog(ASL_LEVEL_ERR,
d1e348cf
A
165 "launch_data_get_type error %d\n",
166 launch_data_get_errno(checkin_response));
167 goto done;
168 }
169 if ( (sockets_dict = launch_data_dict_lookup(checkin_response, LAUNCH_JOBKEY_SOCKETS)) == NULL){
65c25746 170 plog(ASL_LEVEL_ERR,
d1e348cf
A
171 "failed to launch_data_dict_lookup.\n");
172 goto done;
173 }
174 if ( !(socketct = launch_data_dict_get_count(sockets_dict))){
65c25746 175 plog(ASL_LEVEL_ERR,
d1e348cf
A
176 "launch_data_dict_get_count returns no socket defined.\n");
177 goto done;
178 }
179
180 if ( (listening_fd_array = launch_data_dict_lookup(sockets_dict, "Listeners")) == NULL ){
65c25746 181 plog(ASL_LEVEL_ERR,
d1e348cf
A
182 "failed to launch_data_dict_lookup.\n");
183 goto done;
184 }
185 listenerct = launch_data_array_get_count(listening_fd_array);
186 for (i = 0; i < listenerct; i++) {
187 listening_fd = launch_data_array_get_index(listening_fd_array, i);
188 fd = launch_data_get_fd( listening_fd );
85f41bec 189 if ( getsockname( fd , (struct sockaddr *)&fdsockaddr, &fdsockaddrlen)){
d1e348cf
A
190 continue;
191 }
192
193 /* Is this the VPN control socket? */
85f41bec 194 if ( fdsockaddr.ss_family == AF_UNIX &&
d1e348cf
A
195 (!(strcmp(vpncontrolsock_path, ((struct sockaddr_un *)&fdsockaddr)->sun_path))))
196 {
65c25746 197 plog(ASL_LEVEL_INFO,
d1e348cf
A
198 "found launchd socket.\n");
199 returnval = fd;
200 break;
201 }
202 }
203 // TODO: check if we have any leaked fd
204 if ( listenerct == i){
65c25746 205 plog(ASL_LEVEL_ERR,
d1e348cf
A
206 "failed to find launchd socket\n");
207 returnval = 0;
208 }
209
210done:
d1e348cf
A
211 if (checkin_response)
212 launch_data_free(checkin_response);
213 return(returnval);
214}
52b7d2ce 215
d1e348cf 216
65c25746
A
217void
218vpncontrol_handler(void *unused)
52b7d2ce
A
219{
220 struct sockaddr_storage from;
221 socklen_t fromlen = sizeof(from);
65c25746 222 int sock;
52b7d2ce
A
223
224 struct vpnctl_socket_elem *sock_elem;
d9c572c0 225
52b7d2ce 226
65c25746 227 sock_elem = racoon_malloc(sizeof(struct vpnctl_socket_elem));
52b7d2ce 228 if (sock_elem == NULL) {
65c25746 229 plog(ASL_LEVEL_ERR,
52b7d2ce 230 "memory error: %s\n", strerror(errno));
65c25746 231 return; //%%%%%% terminate
52b7d2ce
A
232 }
233 LIST_INIT(&sock_elem->bound_addresses);
65c25746 234
52b7d2ce
A
235 sock_elem->sock = accept(lcconf->sock_vpncontrol, (struct sockaddr *)&from, &fromlen);
236 if (sock_elem->sock < 0) {
65c25746 237 plog(ASL_LEVEL_ERR,
52b7d2ce
A
238 "failed to accept vpn_control command: %s\n", strerror(errno));
239 racoon_free(sock_elem);
65c25746 240 return; //%%%%% terminate
52b7d2ce
A
241 }
242 LIST_INSERT_HEAD(&lcconf->vpnctl_comm_socks, sock_elem, chain);
65c25746
A
243
244 sock_elem->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, sock_elem->sock, 0, dispatch_get_main_queue());
245 if (sock_elem->source == NULL) {
246 plog(ASL_LEVEL_ERR, "could not create comm socket source.");
247 racoon_free(sock_elem);
248 return; //%%%%% terminate
249 }
250 dispatch_source_set_event_handler(sock_elem->source,
251 ^{
252 vpncontrol_comm_handler(sock_elem);
253 });
254 sock = sock_elem->sock;
255
256 dispatch_source_t the_source = sock_elem->source;
257 dispatch_source_set_cancel_handler(sock_elem->source,
258 ^{
259 close(sock);
260 dispatch_release(the_source); /* Release the source on cancel */
261 });
262 dispatch_resume(sock_elem->source);
263
264 plog(ASL_LEVEL_NOTICE,
265 "accepted connection on vpn control socket.\n");
52b7d2ce
A
266 check_auto_exit();
267
65c25746 268 return;
52b7d2ce
A
269}
270
65c25746 271void
52b7d2ce
A
272vpncontrol_comm_handler(struct vpnctl_socket_elem *elem)
273{
274 struct vpnctl_hdr hdr;
275 char *combuf = NULL;
85f41bec 276 ssize_t len;
52b7d2ce
A
277
278 /* get buffer length */
279 while ((len = recv(elem->sock, (char *)&hdr, sizeof(hdr), MSG_PEEK)) < 0) {
280 if (errno == EINTR)
281 continue;
65c25746 282 plog(ASL_LEVEL_ERR,
52b7d2ce
A
283 "failed to recv vpn_control command: %s\n", strerror(errno));
284 goto end;
285 }
286 if (len == 0) {
65c25746 287 plog(ASL_LEVEL_DEBUG,
52b7d2ce 288 "vpn_control socket closed by peer.\n");
85f41bec
A
289 /* kill all related connections */
290 vpncontrol_disconnect_all(elem, ike_session_stopped_by_controller_comm_lost);
52b7d2ce 291 vpncontrol_close_comm(elem);
65c25746 292 return; // %%%%%% terminate
52b7d2ce
A
293 }
294
295 /* sanity check */
296 if (len < sizeof(hdr)) {
65c25746
A
297 plog(ASL_LEVEL_ERR,
298 "invalid header length of vpn_control command - len=%ld - expected %ld\n", len, sizeof(hdr));
52b7d2ce
A
299 goto end;
300 }
301
302 /* get buffer to receive */
303 if ((combuf = racoon_malloc(ntohs(hdr.len) + sizeof(hdr))) == 0) {
65c25746 304 plog(ASL_LEVEL_ERR,
52b7d2ce
A
305 "failed to alloc buffer for vpn_control command\n");
306 goto end;
307 }
308
309 /* get real data */
310 while ((len = recv(elem->sock, combuf, ntohs(hdr.len) + sizeof(hdr), 0)) < 0) {
311 if (errno == EINTR)
312 continue;
65c25746 313 plog(ASL_LEVEL_ERR,
52b7d2ce
A
314 "failed to recv vpn_control command: %s\n",
315 strerror(errno));
316 goto end;
317 }
318
886926c0
A
319 if (len < (sizeof(hdr) + ntohs(hdr.len))) {
320 plog(ASL_LEVEL_ERR,
321 "invalid length of vpn_control command - len=%ld - expected %ld\n", len, (sizeof(hdr) + ntohs(hdr.len)));
322 goto end;
323 }
324
325 (void)vpncontrol_process(elem, combuf, len);
52b7d2ce
A
326
327end:
328 if (combuf)
329 racoon_free(combuf);
65c25746 330 return;
52b7d2ce
A
331}
332
333static int
886926c0 334vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf, size_t combuf_len)
52b7d2ce
A
335{
336 u_int16_t error = 0;
85f41bec 337 struct vpnctl_hdr *hdr = ALIGNED_CAST(struct vpnctl_hdr *)combuf;
52b7d2ce
A
338
339 switch (ntohs(hdr->msg_type)) {
340
341 case VPNCTL_CMD_BIND:
342 {
886926c0
A
343 if (combuf_len < sizeof(struct vpnctl_cmd_bind)) {
344 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl bind cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_bind));
345 error = -1;
346 break;
347 }
348
85f41bec 349 struct vpnctl_cmd_bind *pkt = ALIGNED_CAST(struct vpnctl_cmd_bind *)combuf;
52b7d2ce 350 struct bound_addr *addr;
886926c0
A
351
352 if (combuf_len < (sizeof(struct vpnctl_cmd_bind) + ntohs(pkt->vers_len))) {
353 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)));
354 error = -1;
355 break;
356 }
52b7d2ce 357
65c25746 358 plog(ASL_LEVEL_DEBUG,
52b7d2ce 359 "received bind command on vpn control socket.\n");
d1e348cf 360 addr = racoon_calloc(1, sizeof(struct bound_addr));
52b7d2ce 361 if (addr == NULL) {
65c25746 362 plog(ASL_LEVEL_ERR,
52b7d2ce
A
363 "memory error: %s\n", strerror(errno));
364 error = -1;
365 break;
366 }
d1e348cf
A
367 if (ntohs(pkt->vers_len)) {
368 addr->version = vmalloc(ntohs(pkt->vers_len));
369 if (addr->version == NULL) {
65c25746 370 plog(ASL_LEVEL_ERR,
d1e348cf
A
371 "memory error: %s\n", strerror(errno));
372 error = -1;
373 break;
374 }
375 memcpy(addr->version->v, pkt + 1, ntohs(pkt->vers_len));
376 }
52b7d2ce
A
377 addr->address = pkt->address;
378 LIST_INSERT_HEAD(&elem->bound_addresses, addr, chain);
379 lcconf->auto_exit_state |= LC_AUTOEXITSTATE_CLIENT; /* client side */
380 }
381 break;
382
383 case VPNCTL_CMD_UNBIND:
384 {
886926c0
A
385 if (combuf_len < sizeof(struct vpnctl_cmd_unbind)) {
386 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl unbind cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_unbind));
387 error = -1;
388 break;
389 }
390
85f41bec 391 struct vpnctl_cmd_unbind *pkt = ALIGNED_CAST(struct vpnctl_cmd_unbind *)combuf;
52b7d2ce
A
392 struct bound_addr *addr;
393 struct bound_addr *t_addr;
394
65c25746 395 plog(ASL_LEVEL_DEBUG,
52b7d2ce
A
396 "received unbind command on vpn control socket.\n");
397 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
398 if (pkt->address == 0xFFFFFFFF ||
399 pkt->address == addr->address) {
d1e348cf 400 flushsainfo_dynamic(addr->address);
52b7d2ce 401 LIST_REMOVE(addr, chain);
d1e348cf
A
402 if (addr->version)
403 vfree(addr->version);
52b7d2ce
A
404 racoon_free(addr);
405 }
406 }
407 }
408 break;
409
410 case VPNCTL_CMD_REDIRECT:
411 {
886926c0
A
412 if (combuf_len < sizeof(struct vpnctl_cmd_redirect)) {
413 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl redirect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_redirect));
414 error = -1;
415 break;
416 }
417
85f41bec 418 struct vpnctl_cmd_redirect *redirect_msg = ALIGNED_CAST(struct vpnctl_cmd_redirect *)combuf;
52b7d2ce
A
419 struct redirect *raddr;
420 struct redirect *t_raddr;
421 int found = 0;
422
65c25746 423 plog(ASL_LEVEL_DEBUG,
52b7d2ce
A
424 "received redirect command on vpn control socket - address = %x.\n", ntohl(redirect_msg->redirect_address));
425
426 LIST_FOREACH_SAFE(raddr, &lcconf->redirect_addresses, chain, t_raddr) {
427 if (raddr->cluster_address == redirect_msg->address) {
428 if (redirect_msg->redirect_address == 0) {
429 LIST_REMOVE(raddr, chain);
430 racoon_free(raddr);
431 } else {
432 raddr->redirect_address = redirect_msg->redirect_address;
433 raddr->force = ntohs(redirect_msg->force);
434 }
435 found = 1;
436 break;
437 }
438 }
439 if (!found) {
440 raddr = racoon_malloc(sizeof(struct redirect));
441 if (raddr == NULL) {
65c25746 442 plog(ASL_LEVEL_DEBUG,
52b7d2ce
A
443 "cannot allcoate memory for redirect address.\n");
444 error = -1;
445 break;
446 }
447 raddr->cluster_address = redirect_msg->address;
448 raddr->redirect_address = redirect_msg->redirect_address;
449 raddr->force = ntohs(redirect_msg->force);
450 LIST_INSERT_HEAD(&lcconf->redirect_addresses, raddr, chain);
451
452 }
453 }
454 break;
455
456 case VPNCTL_CMD_PING:
d1e348cf
A
457 break; /* just reply for now */
458
459 case VPNCTL_CMD_XAUTH_INFO:
460 {
886926c0
A
461 if (combuf_len < sizeof(struct vpnctl_cmd_xauth_info)) {
462 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));
463 error = -1;
464 break;
465 }
466
85f41bec 467 struct vpnctl_cmd_xauth_info *pkt = ALIGNED_CAST(struct vpnctl_cmd_xauth_info *)combuf;
d1e348cf
A
468 struct bound_addr *addr;
469 struct bound_addr *t_addr;
470 void *attr_list;
471
886926c0
A
472 if (combuf_len < (sizeof(struct vpnctl_cmd_xauth_info) + ntohs(pkt->hdr.len) - sizeof(u_int32_t))) {
473 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)));
474 error = -1;
475 break;
476 }
477
478 plog(ASL_LEVEL_DEBUG,
d1e348cf
A
479 "received xauth info command vpn control socket.\n");
480 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
481 if (pkt->address == addr->address) {
482 /* reply to the last xauth request */
483 attr_list = pkt + 1;
484 error = vpn_xauth_reply(pkt->address, attr_list, ntohs(pkt->hdr.len) - sizeof(u_int32_t));
485 break;
486 }
487 }
488 }
489 break;
d06a7ccb
A
490
491 case VPNCTL_CMD_SET_NAT64_PREFIX:
492 {
886926c0
A
493 if (combuf_len < sizeof(struct vpnctl_cmd_set_nat64_prefix)) {
494 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));
495 error = -1;
496 break;
497 }
498
d06a7ccb
A
499 struct vpnctl_cmd_set_nat64_prefix *pkt = ALIGNED_CAST(struct vpnctl_cmd_set_nat64_prefix *)combuf;
500 struct bound_addr *addr;
501 struct bound_addr *t_addr;
502
503 plog(ASL_LEVEL_DEBUG,
504 "received set v6 prefix of len %u command on vpn control socket, adding to all addresses.\n", pkt->nat64_prefix.length);
505 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
506 memcpy(&addr->nat64_prefix, &pkt->nat64_prefix, sizeof(addr->nat64_prefix));
507 }
508 }
509 break;
510
d1e348cf
A
511 case VPNCTL_CMD_CONNECT:
512 {
886926c0
A
513 if (combuf_len < sizeof(struct vpnctl_cmd_connect)) {
514 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl connect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_connect));
515 error = -1;
516 break;
517 }
518
85f41bec 519 struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
d1e348cf
A
520 struct bound_addr *addr;
521 struct bound_addr *t_addr;
522
886926c0
A
523 if (pending_signal_handle) {
524 /*
525 * This check is done to ensure that a SIGUSR1 signal to re-read the configuration file
526 * is completed before calling a connect. This is to fix the issue seen in (rdar://problem/25641686)
527 */
528 check_sigreq();
529 pending_signal_handle = 0;
530 }
531
65c25746 532 plog(ASL_LEVEL_DEBUG,
d1e348cf
A
533 "received connect command on vpn control socket.\n");
534 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
535 if (pkt->address == addr->address) {
536 /* start the connection */
e8d9021d 537 error = vpn_connect(addr, VPN_STARTED_BY_API);
d1e348cf
A
538 break;
539 }
540 }
541 }
542 break;
543
544 case VPNCTL_CMD_DISCONNECT:
545 {
886926c0
A
546 if (combuf_len < sizeof(struct vpnctl_cmd_connect)) {
547 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl disconnect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_connect));
548 error = -1;
549 break;
550 }
551
85f41bec 552 struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
d1e348cf
A
553 struct bound_addr *addr;
554 struct bound_addr *t_addr;
555
65c25746 556 plog(ASL_LEVEL_DEBUG,
d1e348cf
A
557 "received disconnect command on vpn control socket.\n");
558 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
559 if (pkt->address == addr->address) {
560 /* stop the connection */
85f41bec 561 error = vpn_disconnect(addr, ike_session_stopped_by_vpn_disconnect);
d1e348cf
A
562 break;
563 }
564 }
565 }
566 break;
567
568 case VPNCTL_CMD_START_PH2:
569 {
886926c0
A
570 if (combuf_len < sizeof(struct vpnctl_cmd_start_ph2)) {
571 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));
572 error = -1;
573 break;
574 }
575
85f41bec 576 struct vpnctl_cmd_start_ph2 *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_ph2 *)combuf;
d1e348cf
A
577 struct bound_addr *addr;
578 struct bound_addr *t_addr;
579
65c25746 580 plog(ASL_LEVEL_DEBUG, "received start_ph2 command on vpn control socket.\n");
d1e348cf
A
581 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
582 if (pkt->address == addr->address) {
583 /* start the connection */
886926c0 584 error = vpn_start_ph2(addr, pkt, combuf_len);
d1e348cf
A
585 break;
586 }
587 }
588 }
589 break;
590
591 case VPNCTL_CMD_START_DPD:
592 {
886926c0
A
593 if (combuf_len < sizeof(struct vpnctl_cmd_start_dpd)) {
594 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));
595 error = -1;
596 break;
597 }
598
85f41bec 599 struct vpnctl_cmd_start_dpd *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_dpd *)combuf;
d1e348cf
A
600 struct bound_addr *srv;
601 struct bound_addr *t_addr;
602
65c25746 603 plog(ASL_LEVEL_DEBUG,
d1e348cf
A
604 "received start_dpd command on vpn control socket.\n");
605 LIST_FOREACH_SAFE(srv, &elem->bound_addresses, chain, t_addr) {
606 if (pkt->address == srv->address) {
85f41bec
A
607 union { // Wcast-align fix - force alignment
608 struct sockaddr_storage ss;
609 struct sockaddr_in addr_in;
610 } daddr;
d1e348cf 611
85f41bec
A
612 bzero(&daddr, sizeof(struct sockaddr_in));
613 daddr.addr_in.sin_len = sizeof(struct sockaddr_in);
614 daddr.addr_in.sin_addr.s_addr = srv->address;
615 daddr.addr_in.sin_port = 0;
616 daddr.addr_in.sin_family = AF_INET;
d1e348cf
A
617
618 /* start the dpd */
65c25746 619 error = ike_session_ph1_force_dpd(&daddr.ss);
d1e348cf
A
620 break;
621 }
622 }
623 }
624 break;
52b7d2ce 625
e8d9021d
A
626 case VPNCTL_CMD_ASSERT:
627 {
886926c0
A
628 if (combuf_len < sizeof(struct vpnctl_cmd_assert)) {
629 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl assert cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_assert));
630 error = -1;
631 break;
632 }
633
85f41bec 634 struct vpnctl_cmd_assert *pkt = ALIGNED_CAST(struct vpnctl_cmd_assert *)combuf;
e8d9021d
A
635// struct bound_addr *addr;
636// struct bound_addr *t_addr;
637 struct sockaddr_in saddr;
638 struct sockaddr_in daddr;
639
65c25746 640 plogdump(ASL_LEVEL_DEBUG, pkt, ntohs(hdr->len) + sizeof(struct vpnctl_hdr), "received assert command on vpn control socket.\n");
e8d9021d
A
641// LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
642// if (pkt->dst_address == addr->address) {
643 bzero(&saddr, sizeof(saddr));
644 saddr.sin_len = sizeof(saddr);
645 saddr.sin_addr.s_addr = pkt->src_address;
646 saddr.sin_port = 0;
647 saddr.sin_family = AF_INET;
648 bzero(&daddr, sizeof(daddr));
649 daddr.sin_len = sizeof(daddr);
650 daddr.sin_addr.s_addr = pkt->dst_address;
651 daddr.sin_port = 0;
652 daddr.sin_family = AF_INET;
653
d06a7ccb 654 error = vpn_assert(ALIGNED_CAST(struct sockaddr_storage *)&saddr, ALIGNED_CAST(struct sockaddr_storage *)&daddr);
e8d9021d
A
655 break;
656// }
657// }
658 }
659 break;
660
661 case VPNCTL_CMD_RECONNECT:
662 {
886926c0
A
663 if (combuf_len < sizeof(struct vpnctl_cmd_connect)) {
664 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl reconnect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_connect));
665 error = -1;
666 break;
667 }
668
85f41bec 669 struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
e8d9021d
A
670 struct bound_addr *addr;
671 struct bound_addr *t_addr;
672
65c25746 673 plog(ASL_LEVEL_DEBUG,
e8d9021d
A
674 "received reconnect command on vpn control socket.\n");
675 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
676 if (pkt->address == addr->address) {
677 /* start the connection */
678 error = vpn_connect(addr, VPN_RESTARTED_BY_API);
679 break;
680 }
681 }
682 }
683 break;
684
52b7d2ce 685 default:
65c25746 686 plog(ASL_LEVEL_ERR,
52b7d2ce
A
687 "invalid command: %d\n", ntohs(hdr->msg_type));
688 error = -1; // for now
689 break;
690 }
691
692 hdr->len = 0;
693 hdr->result = htons(error);
694 if (vpncontrol_reply(elem->sock, combuf) < 0)
695 return -1;
696
697 return 0;
698
699}
700
701static int
702vpncontrol_reply(int so, char *combuf)
703{
85f41bec 704 ssize_t tlen;
52b7d2ce
A
705
706 tlen = send(so, combuf, sizeof(struct vpnctl_hdr), 0);
707 if (tlen < 0) {
65c25746 708 plog(ASL_LEVEL_ERR,
52b7d2ce
A
709 "failed to send vpn_control message: %s\n", strerror(errno));
710 return -1;
711 }
712
713 return 0;
714}
715
d06a7ccb
A
716bool
717vpncontrol_set_nat64_prefix(nw_nat64_prefix_t *prefix)
718{
719 struct vpnctl_socket_elem *sock_elem;
720 struct bound_addr *bound_addr;
721
722 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
723 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
724 if (bound_addr->nat64_prefix.length != 0) {
725 memcpy(prefix, &bound_addr->nat64_prefix, sizeof(*prefix));
726 return true;
727 }
728 }
729 }
730 return false;
731}
732
d1e348cf 733int
65c25746 734vpncontrol_notify_need_authinfo(phase1_handle_t *iph1, void* attr_list, size_t attr_len)
d1e348cf
A
735{
736 struct vpnctl_status_need_authinfo *msg = NULL;
737 struct vpnctl_socket_elem *sock_elem;
738 struct bound_addr *bound_addr;
85f41bec
A
739 size_t msg_size;
740 ssize_t tlen;
d1e348cf
A
741 u_int32_t address;
742 void *ptr;
743
744 if (!iph1)
745 goto end;
746
65c25746 747 plog(ASL_LEVEL_DEBUG,
d1e348cf
A
748 "sending vpn_control xauth need info status\n");
749
750 msg = (struct vpnctl_status_need_authinfo *)racoon_malloc(msg_size = sizeof(struct vpnctl_status_need_authinfo) + attr_len);
751 if (msg == NULL) {
65c25746 752 plog(ASL_LEVEL_ERR,
d1e348cf
A
753 "unable to allocate space for vpn control message.\n");
754 return -1;
755 }
756 msg->hdr.flags = 0;
d06a7ccb
A
757
758 address = iph1_get_remote_v4_address(iph1);
759 if (address == 0) {
760 goto end;
761 }
d1e348cf
A
762
763 msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
764 msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));
765 if (!ike_session_is_client_ph1_rekey(iph1)) {
766 msg->hdr.msg_type = htons(VPNCTL_STATUS_NEED_AUTHINFO);
767 } else {
768 msg->hdr.msg_type = htons(VPNCTL_STATUS_NEED_REAUTHINFO);
769 }
d06a7ccb 770 msg->address = iph1_get_remote_v4_address(iph1);
d1e348cf
A
771 ptr = msg + 1;
772 memcpy(ptr, attr_list, attr_len);
773
774 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
775 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
776 if (bound_addr->address == 0xFFFFFFFF ||
777 bound_addr->address == address) {
65c25746 778 plog(ASL_LEVEL_DEBUG, "vpn control writing %zu bytes\n", msg_size);
d1e348cf
A
779 tlen = send(sock_elem->sock, msg, msg_size, 0);
780 if (tlen < 0) {
65c25746 781 plog(ASL_LEVEL_ERR,
d1e348cf
A
782 "failed to send vpn_control need authinfo status: %s\n", strerror(errno));
783 }
784 break;
785 }
786 }
787 }
788
789end:
790 if (msg)
791 racoon_free(msg);
792 return 0;
793}
794
52b7d2ce
A
795int
796vpncontrol_notify_ike_failed(u_int16_t notify_code, u_int16_t from, u_int32_t address, u_int16_t data_len, u_int8_t *data)
797{
d1e348cf 798 struct vpnctl_status_failed *msg = NULL;
52b7d2ce
A
799 struct vpnctl_socket_elem *sock_elem;
800 struct bound_addr *bound_addr;
85f41bec
A
801 size_t len;
802 ssize_t tlen;
52b7d2ce
A
803
804 len = sizeof(struct vpnctl_status_failed) + data_len;
805
806 msg = (struct vpnctl_status_failed *)racoon_malloc(len);
807 if (msg == NULL) {
65c25746 808 plog(ASL_LEVEL_DEBUG,
52b7d2ce
A
809 "unable to allcate memory for vpn control status message.\n");
810 return -1;
811 }
812
813 msg->hdr.msg_type = htons(VPNCTL_STATUS_IKE_FAILED);
814 msg->hdr.flags = msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
815 msg->hdr.len = htons(len - sizeof(struct vpnctl_hdr));
816 msg->address = address;
817 msg->ike_code = htons(notify_code);
818 msg->from = htons(from);
819 if (data_len > 0)
820 memcpy(msg->data, data, data_len);
65c25746 821 plog(ASL_LEVEL_DEBUG,
d1e348cf 822 "sending vpn_control ike failed message - code=%d from=%s.\n", notify_code,
52b7d2ce
A
823 (from == FROM_LOCAL ? "local" : "remote"));
824
825 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
826 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
827 if (bound_addr->address == 0xFFFFFFFF ||
828 bound_addr->address == address) {
829 tlen = send(sock_elem->sock, msg, len, 0);
830 if (tlen < 0) {
65c25746
A
831 plog(ASL_LEVEL_ERR,
832 "Unable to send vpn_control ike notify failed: %s\n", strerror(errno));
52b7d2ce
A
833 }
834 break;
835 }
836 }
837 }
d1e348cf
A
838
839 if (msg)
840 racoon_free(msg);
52b7d2ce
A
841 return 0;
842}
843
65c25746
A
844char *
845vpncontrol_status_2_str(u_int16_t msg_type)
846{
847 switch (msg_type) {
848 case VPNCTL_STATUS_IKE_FAILED:
849 return "IKE failed";
850 case VPNCTL_STATUS_PH1_START_US:
851 return "Phase 1 started by us";
852 case VPNCTL_STATUS_PH1_START_PEER:
853 return "Phase 1 started by peer";
854 case VPNCTL_STATUS_PH1_ESTABLISHED:
855 return "Phase 1 established";
856 case VPNCTL_STATUS_PH2_START:
857 return "Phase 2 started";
858 case VPNCTL_STATUS_PH2_ESTABLISHED:
859 return "Phase 2 established";
860 case VPNCTL_STATUS_NEED_AUTHINFO:
861 return "Need authentication info";
862 case VPNCTL_STATUS_NEED_REAUTHINFO:
863 return "Need re-authentication info";
864 default:
865 return "";
866 }
867}
868
52b7d2ce
A
869
870int
65c25746 871vpncontrol_notify_phase_change(int start, u_int16_t from, phase1_handle_t *iph1, phase2_handle_t *iph2)
52b7d2ce 872{
d1e348cf 873 struct vpnctl_status_phase_change *msg;
52b7d2ce
A
874 struct vpnctl_socket_elem *sock_elem;
875 struct bound_addr *bound_addr;
85f41bec
A
876 ssize_t tlen;
877 size_t msg_size;
52b7d2ce 878 u_int32_t address;
d1e348cf 879
65c25746 880 if (iph1 && !start && iph1->mode_cfg && iph1->mode_cfg->xauth.status != XAUTHST_OK) {
d1e348cf
A
881 if (vpn_get_config(iph1, &msg, &msg_size) == 1)
882 return 0; /* mode config not finished yet */
883 } else {
884 msg = racoon_malloc(msg_size = sizeof(struct vpnctl_status_phase_change));
885 msg->hdr.flags = 0;
886 }
52b7d2ce 887
d1e348cf 888 if (msg == NULL) {
65c25746 889 plog(ASL_LEVEL_ERR,
d1e348cf
A
890 "unable to allocate space for vpn control message.\n");
891 return -1;
892 }
52b7d2ce 893 if (iph1) {
d06a7ccb
A
894 address = iph1_get_remote_v4_address(iph1);
895 if (address == 0) {
896 plog(ASL_LEVEL_ERR, "bad address for ph1 status change.\n");
897 goto end;
898 }
d1e348cf 899 msg->hdr.msg_type = htons(start ?
52b7d2ce
A
900 (from == FROM_LOCAL ? VPNCTL_STATUS_PH1_START_US : VPNCTL_STATUS_PH1_START_PEER)
901 : VPNCTL_STATUS_PH1_ESTABLISHED);
65c25746 902 // TODO: indicate version
52b7d2ce 903 } else {
d06a7ccb
A
904 address = iph2_get_remote_v4_address(iph2);
905 if (address == 0) {
906 plog(ASL_LEVEL_ERR, "bad address for ph2 status change.\n");
907 goto end;
908 }
d1e348cf 909 msg->hdr.msg_type = htons(start ? VPNCTL_STATUS_PH2_START : VPNCTL_STATUS_PH2_ESTABLISHED);
65c25746 910 // TODO: indicate version
52b7d2ce 911 }
65c25746
A
912 plog(ASL_LEVEL_NOTICE,
913 ">>>>> phase change status = %s\n", vpncontrol_status_2_str(ntohs(msg->hdr.msg_type)));
914
d1e348cf
A
915 msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
916 msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));
917 msg->address = address;
52b7d2ce
A
918
919 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
920 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
921 if (bound_addr->address == 0xFFFFFFFF ||
922 bound_addr->address == address) {
65c25746 923 plog(ASL_LEVEL_DEBUG, "vpn control writing %zu bytes\n", msg_size);
d1e348cf 924 tlen = send(sock_elem->sock, msg, msg_size, 0);
52b7d2ce 925 if (tlen < 0) {
65c25746 926 plog(ASL_LEVEL_ERR,
52b7d2ce
A
927 "failed to send vpn_control phase change status: %s\n", strerror(errno));
928 }
929 break;
930 }
931 }
932 }
933
d1e348cf
A
934end:
935 if (msg)
936 racoon_free(msg);
52b7d2ce
A
937 return 0;
938}
939
e8d9021d
A
940static int
941vpncontrol_notify_peer_resp (u_int16_t notify_code, u_int32_t address)
942{
943 struct vpnctl_status_peer_resp msg;
944 struct vpnctl_socket_elem *sock_elem;
945 struct bound_addr *bound_addr;
85f41bec 946 ssize_t tlen;
e8d9021d
A
947 int rc = -1;
948
949 bzero(&msg, sizeof(msg));
950 msg.hdr.msg_type = htons(VPNCTL_STATUS_PEER_RESP);
951 msg.hdr.cookie = msg.hdr.reserved = msg.hdr.result = 0;
952 msg.hdr.len = htons(sizeof(msg) - sizeof(msg.hdr));
953 msg.address = address;
954 msg.ike_code = notify_code;
65c25746 955 plog(ASL_LEVEL_DEBUG,
e8d9021d
A
956 "sending vpn_control status (peer response) message - code=%d addr=%x.\n", notify_code, address);
957
958 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
959 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
960 if (bound_addr->address == 0xFFFFFFFF ||
961 bound_addr->address == address) {
962 tlen = send(sock_elem->sock, &msg, sizeof(msg), 0);
963 if (tlen < 0) {
65c25746 964 plog(ASL_LEVEL_ERR,
e8d9021d
A
965 "unable to send vpn_control status (peer response): %s\n", strerror(errno));
966 } else {
967 rc = 0;
968 }
969 break;
970 }
971 }
972 }
973
974 return rc;
975}
976
977int
65c25746 978vpncontrol_notify_peer_resp_ph1 (u_int16_t notify_code, phase1_handle_t *iph1)
e8d9021d 979{
e8d9021d 980 if (iph1 && iph1->parent_session && iph1->parent_session->controller_awaiting_peer_resp) {
d06a7ccb
A
981 int rc;
982 if ((rc = vpncontrol_notify_peer_resp(notify_code, iph1_get_remote_v4_address(iph1))) == 0) {
983 iph1->parent_session->controller_awaiting_peer_resp = 0;
984 }
985 return rc;
e8d9021d
A
986 } else {
987 return 0;
988 }
e8d9021d
A
989}
990
991int
65c25746 992vpncontrol_notify_peer_resp_ph2 (u_int16_t notify_code, phase2_handle_t *iph2)
e8d9021d 993{
e8d9021d 994 if (iph2 && iph2->parent_session && iph2->parent_session->controller_awaiting_peer_resp) {
d06a7ccb
A
995 int rc;
996 if ((rc = vpncontrol_notify_peer_resp(notify_code, iph2_get_remote_v4_address(iph2))) == 0) {
997 iph2->parent_session->controller_awaiting_peer_resp = 0;
998 }
999 return rc;
e8d9021d
A
1000 } else {
1001 return 0;
1002 }
e8d9021d 1003}
52b7d2ce
A
1004
1005int
65c25746 1006vpncontrol_init(void)
52b7d2ce 1007{
65c25746
A
1008 int sock;
1009
52b7d2ce
A
1010 if (vpncontrolsock_path == NULL) {
1011 lcconf->sock_vpncontrol = -1;
1012 return 0;
1013 }
1014
65c25746 1015 if ( (lcconf->sock_vpncontrol = checklaunchd()) == 0 ) {
d1e348cf
A
1016 memset(&sunaddr, 0, sizeof(sunaddr));
1017 sunaddr.sun_family = AF_UNIX;
1018 snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
1019 "%s", vpncontrolsock_path);
52b7d2ce 1020
d1e348cf
A
1021 lcconf->sock_vpncontrol = socket(AF_UNIX, SOCK_STREAM, 0);
1022 if (lcconf->sock_vpncontrol == -1) {
65c25746 1023 plog(ASL_LEVEL_ERR,
d1e348cf
A
1024 "socket: %s\n", strerror(errno));
1025 return -1;
1026 }
52b7d2ce 1027
85f41bec 1028 if (fcntl(lcconf->sock_vpncontrol, F_SETFL, O_NONBLOCK) == -1) {
65c25746 1029 plog(ASL_LEVEL_ERR, "failed to put VPN-Control socket in non-blocking mode\n");
85f41bec 1030 }
65c25746 1031
d1e348cf
A
1032 unlink(sunaddr.sun_path);
1033 if (bind(lcconf->sock_vpncontrol, (struct sockaddr *)&sunaddr,
1034 sizeof(sunaddr)) != 0) {
65c25746 1035 plog(ASL_LEVEL_ERR,
d1e348cf
A
1036 "bind(sockname:%s): %s\n",
1037 sunaddr.sun_path, strerror(errno));
1038 (void)close(lcconf->sock_vpncontrol);
1039 return -1;
1040 }
52b7d2ce 1041
d1e348cf 1042 if (chown(sunaddr.sun_path, vpncontrolsock_owner, vpncontrolsock_group) != 0) {
65c25746 1043 plog(ASL_LEVEL_ERR,
d1e348cf
A
1044 "chown(%s, %d, %d): %s\n",
1045 sunaddr.sun_path, vpncontrolsock_owner,
1046 vpncontrolsock_group, strerror(errno));
1047 (void)close(lcconf->sock_vpncontrol);
1048 return -1;
1049 }
52b7d2ce 1050
d1e348cf 1051 if (chmod(sunaddr.sun_path, vpncontrolsock_mode) != 0) {
65c25746 1052 plog(ASL_LEVEL_ERR,
d1e348cf
A
1053 "chmod(%s, 0%03o): %s\n",
1054 sunaddr.sun_path, vpncontrolsock_mode, strerror(errno));
1055 (void)close(lcconf->sock_vpncontrol);
1056 return -1;
1057 }
52b7d2ce 1058
d1e348cf 1059 if (listen(lcconf->sock_vpncontrol, 5) != 0) {
65c25746 1060 plog(ASL_LEVEL_ERR,
d1e348cf
A
1061 "listen(sockname:%s): %s\n",
1062 sunaddr.sun_path, strerror(errno));
1063 (void)close(lcconf->sock_vpncontrol);
1064 return -1;
1065 }
65c25746 1066 plog(ASL_LEVEL_DEBUG,
d1e348cf 1067 "opened %s as racoon management.\n", sunaddr.sun_path);
d1e348cf 1068 }
65c25746
A
1069 lcconf->vpncontrol_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, lcconf->sock_vpncontrol, 0, dispatch_get_main_queue());
1070 if (lcconf->vpncontrol_source == NULL) {
1071 plog(ASL_LEVEL_ERR, "could not create vpncontrol socket source.");
1072 return -1;
1073 }
1074 dispatch_source_set_event_handler_f(lcconf->vpncontrol_source, vpncontrol_handler);
1075 sock = lcconf->sock_vpncontrol;
1076 dispatch_source_set_cancel_handler(lcconf->vpncontrol_source,
1077 ^{
1078 close(sock);
1079 });
1080 dispatch_resume(lcconf->vpncontrol_source);
1081 return 0;
52b7d2ce
A
1082}
1083
85f41bec
A
1084void
1085vpncontrol_disconnect_all(struct vpnctl_socket_elem *elem, const char *reason)
1086{
1087 struct bound_addr *addr;
1088 struct bound_addr *t_addr;
1089
65c25746 1090 plog(ASL_LEVEL_DEBUG,
85f41bec
A
1091 "received disconnect all command.\n");
1092
1093 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
1094 /* stop any connections */
1095 vpn_disconnect(addr, reason);
1096 }
1097}
1098
52b7d2ce
A
1099void
1100vpncontrol_close()
1101{
65c25746 1102 struct vpnctl_socket_elem *elem;
52b7d2ce
A
1103 struct vpnctl_socket_elem *t_elem;
1104
65c25746
A
1105 plog(ASL_LEVEL_DEBUG,
1106 "vpncontrol_close.\n");
d1e348cf 1107
65c25746
A
1108 dispatch_source_cancel(lcconf->vpncontrol_source);
1109 lcconf->vpncontrol_source = NULL;
1110
1111 lcconf->sock_vpncontrol = -1;
1112 LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem)
1113 vpncontrol_close_comm(elem);
52b7d2ce
A
1114}
1115
1116static void
1117vpncontrol_close_comm(struct vpnctl_socket_elem *elem)
1118{
1119 struct bound_addr *addr;
1120 struct bound_addr *t_addr;
d1e348cf 1121
65c25746 1122 plog(ASL_LEVEL_DEBUG,
d1e348cf 1123 "vpncontrol_close_comm.\n");
52b7d2ce
A
1124
1125 LIST_REMOVE(elem, chain);
65c25746
A
1126 if (elem->sock != -1)
1127 dispatch_source_cancel(elem->source);
52b7d2ce 1128 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
d1e348cf 1129 flushsainfo_dynamic(addr->address);
52b7d2ce 1130 LIST_REMOVE(addr, chain);
d1e348cf
A
1131 if (addr->version)
1132 vfree(addr->version);
52b7d2ce
A
1133 racoon_free(addr);
1134 }
1135 racoon_free(elem);
1136 check_auto_exit();
d9c572c0 1137
52b7d2ce
A
1138}
1139
1140int
1141vpn_control_connected(void)
1142{
1143 if (LIST_EMPTY(&lcconf->vpnctl_comm_socks))
1144 return 0;
1145 else
1146 return 1;
1147}
1148
1149#endif