]> git.saurik.com Git - apple/ipsec.git/blame - ipsec-tools/racoon/vpn_control.c
ipsec-317.220.1.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@
7ebaebe2 7 *
52b7d2ce
A
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.
7ebaebe2 13 *
52b7d2ce
A
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.
7ebaebe2 21 *
52b7d2ce
A
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25/*
26 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
27 * All rights reserved.
7ebaebe2 28 *
52b7d2ce
A
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.
7ebaebe2 40 *
52b7d2ce
A
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>
7ebaebe2 71#else
52b7d2ce
A
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
7ebaebe2
A
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 152#endif
7ebaebe2 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)) {
7ebaebe2 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){
7ebaebe2 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))){
7ebaebe2 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 ){
7ebaebe2 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
7ebaebe2
A
193 /* Is this the VPN control socket? */
194 if ( fdsockaddr.ss_family == AF_UNIX &&
d1e348cf 195 (!(strcmp(vpncontrolsock_path, ((struct sockaddr_un *)&fdsockaddr)->sun_path))))
7ebaebe2
A
196 {
197 plog(ASL_LEVEL_NOTICE,
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){
7ebaebe2
A
205 plog(ASL_LEVEL_ERR,
206 "failed to find launchd socket\n");
d1e348cf
A
207 returnval = 0;
208 }
209
7ebaebe2 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
7ebaebe2 227 sock_elem = racoon_calloc(1, sizeof(struct vpnctl_socket_elem));
52b7d2ce 228 if (sock_elem == NULL) {
7ebaebe2 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);
7ebaebe2 234
52b7d2ce
A
235 sock_elem->sock = accept(lcconf->sock_vpncontrol, (struct sockaddr *)&from, &fromlen);
236 if (sock_elem->sock < 0) {
7ebaebe2 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);
7ebaebe2 243
65c25746
A
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 }
7ebaebe2 250 dispatch_source_set_event_handler(sock_elem->source,
65c25746
A
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);
7ebaebe2
A
263
264 plog(ASL_LEVEL_NOTICE,
65c25746 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;
85f41bec 275 ssize_t len;
52b7d2ce
A
276
277 /* get buffer length */
7ebaebe2
A
278 if (elem->buffer == NULL) {
279 while ((len = recv(elem->sock, (char *)&hdr, sizeof(hdr), MSG_PEEK)) < 0) {
280 if (errno == EINTR)
281 continue;
282 plog(ASL_LEVEL_ERR, "failed to recv vpn_control command: %s\n", strerror(errno));
283 return;
284 }
285 if (len == 0) {
286 plog(ASL_LEVEL_NOTICE, "vpn_control socket closed by peer.\n");
287 /* kill all related connections */
288 vpncontrol_disconnect_all(elem, ike_session_stopped_by_controller_comm_lost);
289 vpncontrol_close_comm(elem);
290 return; // %%%%%% terminate
291 }
52b7d2ce 292
7ebaebe2
A
293 /* sanity check */
294 if (len < sizeof(hdr)) {
295 plog(ASL_LEVEL_ERR,
296 "invalid header length of vpn_control command - len=%ld - expected %ld\n", len, sizeof(hdr));
297 return;
298 }
299
300 elem->read_bytes_len = 0; // Sanity
301 elem->pending_bytes_len = ntohs(hdr.len) + sizeof(hdr);
302
303 /* get buffer to receive */
304 elem->buffer = racoon_malloc(elem->pending_bytes_len);
305 if (elem->buffer == NULL) {
306 plog(ASL_LEVEL_ERR,
307 "failed to alloc buffer for vpn_control command\n");
308 return;
309 }
52b7d2ce
A
310 }
311
312 /* get real data */
7ebaebe2 313 while ((len = recv(elem->sock, elem->buffer + elem->read_bytes_len, elem->pending_bytes_len, 0)) < 0) {
52b7d2ce
A
314 if (errno == EINTR)
315 continue;
7ebaebe2
A
316 plog(ASL_LEVEL_ERR, "failed to recv vpn_control command: %s\n",
317 strerror(errno));
318 return;
52b7d2ce
A
319 }
320
7ebaebe2
A
321 if (len == 0) {
322 plog(ASL_LEVEL_NOTICE, "vpn_control socket closed by peer while reading packet\n");
323 /* kill all related connections */
324 vpncontrol_disconnect_all(elem, ike_session_stopped_by_controller_comm_lost);
325 vpncontrol_close_comm(elem);
326 return;
886926c0
A
327 }
328
7ebaebe2 329 elem->read_bytes_len += len;
52b7d2ce 330
7ebaebe2
A
331 if (len < elem->pending_bytes_len) {
332 plog(ASL_LEVEL_NOTICE,
333 "received partial vpn_control command - len=%ld - expected %u\n", len, elem->pending_bytes_len);
334 elem->pending_bytes_len -= len;
335 return;
336 } else {
337 (void)vpncontrol_process(elem, elem->buffer, elem->read_bytes_len);
338 free(elem->buffer);
339 elem->buffer = NULL;
340 elem->read_bytes_len = 0;
341 elem->pending_bytes_len = 0;
342 }
52b7d2ce
A
343}
344
345static int
886926c0 346vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf, size_t combuf_len)
52b7d2ce
A
347{
348 u_int16_t error = 0;
85f41bec 349 struct vpnctl_hdr *hdr = ALIGNED_CAST(struct vpnctl_hdr *)combuf;
52b7d2ce
A
350
351 switch (ntohs(hdr->msg_type)) {
352
353 case VPNCTL_CMD_BIND:
354 {
886926c0
A
355 if (combuf_len < sizeof(struct vpnctl_cmd_bind)) {
356 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl bind cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_bind));
357 error = -1;
358 break;
359 }
360
85f41bec 361 struct vpnctl_cmd_bind *pkt = ALIGNED_CAST(struct vpnctl_cmd_bind *)combuf;
52b7d2ce 362 struct bound_addr *addr;
886926c0
A
363
364 if (combuf_len < (sizeof(struct vpnctl_cmd_bind) + ntohs(pkt->vers_len))) {
365 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)));
366 error = -1;
367 break;
368 }
52b7d2ce 369
7ebaebe2 370 plog(ASL_LEVEL_NOTICE,
52b7d2ce 371 "received bind command on vpn control socket.\n");
d1e348cf 372 addr = racoon_calloc(1, sizeof(struct bound_addr));
52b7d2ce 373 if (addr == NULL) {
65c25746 374 plog(ASL_LEVEL_ERR,
52b7d2ce
A
375 "memory error: %s\n", strerror(errno));
376 error = -1;
377 break;
378 }
d1e348cf
A
379 if (ntohs(pkt->vers_len)) {
380 addr->version = vmalloc(ntohs(pkt->vers_len));
381 if (addr->version == NULL) {
65c25746 382 plog(ASL_LEVEL_ERR,
d1e348cf
A
383 "memory error: %s\n", strerror(errno));
384 error = -1;
7ebaebe2 385 racoon_free(addr);
d1e348cf
A
386 break;
387 }
388 memcpy(addr->version->v, pkt + 1, ntohs(pkt->vers_len));
389 }
52b7d2ce
A
390 addr->address = pkt->address;
391 LIST_INSERT_HEAD(&elem->bound_addresses, addr, chain);
392 lcconf->auto_exit_state |= LC_AUTOEXITSTATE_CLIENT; /* client side */
393 }
394 break;
395
396 case VPNCTL_CMD_UNBIND:
397 {
886926c0
A
398 if (combuf_len < sizeof(struct vpnctl_cmd_unbind)) {
399 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl unbind cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_unbind));
400 error = -1;
401 break;
402 }
403
85f41bec 404 struct vpnctl_cmd_unbind *pkt = ALIGNED_CAST(struct vpnctl_cmd_unbind *)combuf;
52b7d2ce
A
405 struct bound_addr *addr;
406 struct bound_addr *t_addr;
407
7ebaebe2 408 plog(ASL_LEVEL_NOTICE,
52b7d2ce
A
409 "received unbind command on vpn control socket.\n");
410 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
411 if (pkt->address == 0xFFFFFFFF ||
412 pkt->address == addr->address) {
d1e348cf 413 flushsainfo_dynamic(addr->address);
52b7d2ce 414 LIST_REMOVE(addr, chain);
d1e348cf
A
415 if (addr->version)
416 vfree(addr->version);
52b7d2ce
A
417 racoon_free(addr);
418 }
419 }
420 }
421 break;
422
423 case VPNCTL_CMD_REDIRECT:
424 {
886926c0
A
425 if (combuf_len < sizeof(struct vpnctl_cmd_redirect)) {
426 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl redirect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_redirect));
427 error = -1;
428 break;
429 }
430
85f41bec 431 struct vpnctl_cmd_redirect *redirect_msg = ALIGNED_CAST(struct vpnctl_cmd_redirect *)combuf;
52b7d2ce
A
432 struct redirect *raddr;
433 struct redirect *t_raddr;
434 int found = 0;
435
7ebaebe2 436 plog(ASL_LEVEL_NOTICE,
52b7d2ce
A
437 "received redirect command on vpn control socket - address = %x.\n", ntohl(redirect_msg->redirect_address));
438
439 LIST_FOREACH_SAFE(raddr, &lcconf->redirect_addresses, chain, t_raddr) {
440 if (raddr->cluster_address == redirect_msg->address) {
441 if (redirect_msg->redirect_address == 0) {
442 LIST_REMOVE(raddr, chain);
443 racoon_free(raddr);
444 } else {
445 raddr->redirect_address = redirect_msg->redirect_address;
446 raddr->force = ntohs(redirect_msg->force);
447 }
448 found = 1;
449 break;
450 }
451 }
452 if (!found) {
453 raddr = racoon_malloc(sizeof(struct redirect));
454 if (raddr == NULL) {
7ebaebe2 455 plog(ASL_LEVEL_ERR,
52b7d2ce
A
456 "cannot allcoate memory for redirect address.\n");
457 error = -1;
458 break;
459 }
460 raddr->cluster_address = redirect_msg->address;
461 raddr->redirect_address = redirect_msg->redirect_address;
462 raddr->force = ntohs(redirect_msg->force);
463 LIST_INSERT_HEAD(&lcconf->redirect_addresses, raddr, chain);
464
465 }
466 }
467 break;
468
469 case VPNCTL_CMD_PING:
d1e348cf
A
470 break; /* just reply for now */
471
472 case VPNCTL_CMD_XAUTH_INFO:
473 {
886926c0
A
474 if (combuf_len < sizeof(struct vpnctl_cmd_xauth_info)) {
475 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));
476 error = -1;
477 break;
478 }
479
85f41bec 480 struct vpnctl_cmd_xauth_info *pkt = ALIGNED_CAST(struct vpnctl_cmd_xauth_info *)combuf;
d1e348cf
A
481 struct bound_addr *addr;
482 struct bound_addr *t_addr;
483 void *attr_list;
484
886926c0
A
485 if (combuf_len < (sizeof(struct vpnctl_cmd_xauth_info) + ntohs(pkt->hdr.len) - sizeof(u_int32_t))) {
486 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)));
487 error = -1;
488 break;
489 }
490
7ebaebe2 491 plog(ASL_LEVEL_NOTICE,
d1e348cf
A
492 "received xauth info command vpn control socket.\n");
493 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
494 if (pkt->address == addr->address) {
495 /* reply to the last xauth request */
496 attr_list = pkt + 1;
497 error = vpn_xauth_reply(pkt->address, attr_list, ntohs(pkt->hdr.len) - sizeof(u_int32_t));
498 break;
499 }
500 }
501 }
502 break;
d06a7ccb
A
503
504 case VPNCTL_CMD_SET_NAT64_PREFIX:
505 {
886926c0
A
506 if (combuf_len < sizeof(struct vpnctl_cmd_set_nat64_prefix)) {
507 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));
508 error = -1;
509 break;
510 }
511
d06a7ccb
A
512 struct vpnctl_cmd_set_nat64_prefix *pkt = ALIGNED_CAST(struct vpnctl_cmd_set_nat64_prefix *)combuf;
513 struct bound_addr *addr;
514 struct bound_addr *t_addr;
515
7ebaebe2 516 plog(ASL_LEVEL_NOTICE,
d06a7ccb
A
517 "received set v6 prefix of len %u command on vpn control socket, adding to all addresses.\n", pkt->nat64_prefix.length);
518 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
519 memcpy(&addr->nat64_prefix, &pkt->nat64_prefix, sizeof(addr->nat64_prefix));
520 }
521 }
522 break;
523
d1e348cf
A
524 case VPNCTL_CMD_CONNECT:
525 {
886926c0
A
526 if (combuf_len < sizeof(struct vpnctl_cmd_connect)) {
527 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl connect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_connect));
528 error = -1;
529 break;
530 }
531
85f41bec 532 struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
d1e348cf
A
533 struct bound_addr *addr;
534 struct bound_addr *t_addr;
535
886926c0
A
536 if (pending_signal_handle) {
537 /*
538 * This check is done to ensure that a SIGUSR1 signal to re-read the configuration file
539 * is completed before calling a connect. This is to fix the issue seen in (rdar://problem/25641686)
540 */
541 check_sigreq();
542 pending_signal_handle = 0;
543 }
544
7ebaebe2 545 plog(ASL_LEVEL_NOTICE,
d1e348cf
A
546 "received connect command on vpn control socket.\n");
547 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
548 if (pkt->address == addr->address) {
549 /* start the connection */
e8d9021d 550 error = vpn_connect(addr, VPN_STARTED_BY_API);
d1e348cf
A
551 break;
552 }
553 }
554 }
555 break;
556
557 case VPNCTL_CMD_DISCONNECT:
558 {
886926c0
A
559 if (combuf_len < sizeof(struct vpnctl_cmd_connect)) {
560 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl disconnect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_connect));
561 error = -1;
562 break;
563 }
564
85f41bec 565 struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
d1e348cf
A
566 struct bound_addr *addr;
567 struct bound_addr *t_addr;
568
7ebaebe2 569 plog(ASL_LEVEL_NOTICE,
d1e348cf
A
570 "received disconnect command on vpn control socket.\n");
571 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
572 if (pkt->address == addr->address) {
573 /* stop the connection */
85f41bec 574 error = vpn_disconnect(addr, ike_session_stopped_by_vpn_disconnect);
d1e348cf
A
575 break;
576 }
577 }
578 }
579 break;
580
581 case VPNCTL_CMD_START_PH2:
582 {
886926c0
A
583 if (combuf_len < sizeof(struct vpnctl_cmd_start_ph2)) {
584 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));
585 error = -1;
586 break;
587 }
588
85f41bec 589 struct vpnctl_cmd_start_ph2 *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_ph2 *)combuf;
d1e348cf
A
590 struct bound_addr *addr;
591 struct bound_addr *t_addr;
592
7ebaebe2 593 plog(ASL_LEVEL_NOTICE, "received start_ph2 command on vpn control socket.\n");
d1e348cf
A
594 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
595 if (pkt->address == addr->address) {
596 /* start the connection */
886926c0 597 error = vpn_start_ph2(addr, pkt, combuf_len);
d1e348cf
A
598 break;
599 }
600 }
601 }
602 break;
603
604 case VPNCTL_CMD_START_DPD:
605 {
886926c0
A
606 if (combuf_len < sizeof(struct vpnctl_cmd_start_dpd)) {
607 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));
608 error = -1;
609 break;
610 }
611
85f41bec 612 struct vpnctl_cmd_start_dpd *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_dpd *)combuf;
d1e348cf
A
613 struct bound_addr *srv;
614 struct bound_addr *t_addr;
615
7ebaebe2 616 plog(ASL_LEVEL_NOTICE,
d1e348cf
A
617 "received start_dpd command on vpn control socket.\n");
618 LIST_FOREACH_SAFE(srv, &elem->bound_addresses, chain, t_addr) {
619 if (pkt->address == srv->address) {
85f41bec
A
620 union { // Wcast-align fix - force alignment
621 struct sockaddr_storage ss;
622 struct sockaddr_in addr_in;
623 } daddr;
d1e348cf 624
85f41bec
A
625 bzero(&daddr, sizeof(struct sockaddr_in));
626 daddr.addr_in.sin_len = sizeof(struct sockaddr_in);
627 daddr.addr_in.sin_addr.s_addr = srv->address;
628 daddr.addr_in.sin_port = 0;
629 daddr.addr_in.sin_family = AF_INET;
d1e348cf
A
630
631 /* start the dpd */
65c25746 632 error = ike_session_ph1_force_dpd(&daddr.ss);
d1e348cf
A
633 break;
634 }
635 }
636 }
637 break;
52b7d2ce 638
e8d9021d
A
639 case VPNCTL_CMD_ASSERT:
640 {
886926c0
A
641 if (combuf_len < sizeof(struct vpnctl_cmd_assert)) {
642 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl assert cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_assert));
643 error = -1;
644 break;
645 }
646
85f41bec 647 struct vpnctl_cmd_assert *pkt = ALIGNED_CAST(struct vpnctl_cmd_assert *)combuf;
e8d9021d
A
648// struct bound_addr *addr;
649// struct bound_addr *t_addr;
650 struct sockaddr_in saddr;
651 struct sockaddr_in daddr;
652
7ebaebe2 653 plogdump(ASL_LEVEL_NOTICE, pkt, ntohs(hdr->len) + sizeof(struct vpnctl_hdr), "received assert command on vpn control socket.\n");
e8d9021d
A
654// LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
655// if (pkt->dst_address == addr->address) {
656 bzero(&saddr, sizeof(saddr));
657 saddr.sin_len = sizeof(saddr);
658 saddr.sin_addr.s_addr = pkt->src_address;
659 saddr.sin_port = 0;
660 saddr.sin_family = AF_INET;
661 bzero(&daddr, sizeof(daddr));
662 daddr.sin_len = sizeof(daddr);
663 daddr.sin_addr.s_addr = pkt->dst_address;
664 daddr.sin_port = 0;
665 daddr.sin_family = AF_INET;
666
d06a7ccb 667 error = vpn_assert(ALIGNED_CAST(struct sockaddr_storage *)&saddr, ALIGNED_CAST(struct sockaddr_storage *)&daddr);
e8d9021d
A
668 break;
669// }
670// }
671 }
672 break;
673
674 case VPNCTL_CMD_RECONNECT:
675 {
886926c0
A
676 if (combuf_len < sizeof(struct vpnctl_cmd_connect)) {
677 plog(ASL_LEVEL_ERR, "invalid header length for vpnctl reconnect cmd - len=%ld - expected %ld\n", combuf_len, sizeof(struct vpnctl_cmd_connect));
678 error = -1;
679 break;
680 }
681
85f41bec 682 struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
e8d9021d
A
683 struct bound_addr *addr;
684 struct bound_addr *t_addr;
685
7ebaebe2 686 plog(ASL_LEVEL_NOTICE,
e8d9021d
A
687 "received reconnect command on vpn control socket.\n");
688 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
689 if (pkt->address == addr->address) {
690 /* start the connection */
691 error = vpn_connect(addr, VPN_RESTARTED_BY_API);
692 break;
693 }
694 }
695 }
696 break;
697
52b7d2ce 698 default:
7ebaebe2 699 plog(ASL_LEVEL_ERR,
52b7d2ce
A
700 "invalid command: %d\n", ntohs(hdr->msg_type));
701 error = -1; // for now
702 break;
703 }
704
705 hdr->len = 0;
706 hdr->result = htons(error);
707 if (vpncontrol_reply(elem->sock, combuf) < 0)
708 return -1;
709
710 return 0;
711
712}
713
714static int
715vpncontrol_reply(int so, char *combuf)
716{
85f41bec 717 ssize_t tlen;
52b7d2ce
A
718
719 tlen = send(so, combuf, sizeof(struct vpnctl_hdr), 0);
720 if (tlen < 0) {
7ebaebe2 721 plog(ASL_LEVEL_ERR,
52b7d2ce
A
722 "failed to send vpn_control message: %s\n", strerror(errno));
723 return -1;
724 }
725
726 return 0;
727}
728
d06a7ccb
A
729bool
730vpncontrol_set_nat64_prefix(nw_nat64_prefix_t *prefix)
731{
732 struct vpnctl_socket_elem *sock_elem;
733 struct bound_addr *bound_addr;
734
735 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
736 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
737 if (bound_addr->nat64_prefix.length != 0) {
738 memcpy(prefix, &bound_addr->nat64_prefix, sizeof(*prefix));
739 return true;
740 }
741 }
742 }
743 return false;
744}
745
d1e348cf 746int
65c25746 747vpncontrol_notify_need_authinfo(phase1_handle_t *iph1, void* attr_list, size_t attr_len)
d1e348cf 748{
7ebaebe2 749 struct vpnctl_status_need_authinfo *msg = NULL;
d1e348cf
A
750 struct vpnctl_socket_elem *sock_elem;
751 struct bound_addr *bound_addr;
85f41bec
A
752 size_t msg_size;
753 ssize_t tlen;
d1e348cf
A
754 u_int32_t address;
755 void *ptr;
756
757 if (!iph1)
758 goto end;
759
7ebaebe2 760 plog(ASL_LEVEL_NOTICE,
d1e348cf
A
761 "sending vpn_control xauth need info status\n");
762
763 msg = (struct vpnctl_status_need_authinfo *)racoon_malloc(msg_size = sizeof(struct vpnctl_status_need_authinfo) + attr_len);
764 if (msg == NULL) {
7ebaebe2 765 plog(ASL_LEVEL_ERR,
d1e348cf
A
766 "unable to allocate space for vpn control message.\n");
767 return -1;
768 }
769 msg->hdr.flags = 0;
d06a7ccb
A
770
771 address = iph1_get_remote_v4_address(iph1);
772 if (address == 0) {
773 goto end;
774 }
d1e348cf
A
775
776 msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
777 msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));
778 if (!ike_session_is_client_ph1_rekey(iph1)) {
779 msg->hdr.msg_type = htons(VPNCTL_STATUS_NEED_AUTHINFO);
780 } else {
781 msg->hdr.msg_type = htons(VPNCTL_STATUS_NEED_REAUTHINFO);
782 }
d06a7ccb 783 msg->address = iph1_get_remote_v4_address(iph1);
d1e348cf
A
784 ptr = msg + 1;
785 memcpy(ptr, attr_list, attr_len);
786
787 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
788 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
789 if (bound_addr->address == 0xFFFFFFFF ||
790 bound_addr->address == address) {
65c25746 791 plog(ASL_LEVEL_DEBUG, "vpn control writing %zu bytes\n", msg_size);
d1e348cf
A
792 tlen = send(sock_elem->sock, msg, msg_size, 0);
793 if (tlen < 0) {
7ebaebe2 794 plog(ASL_LEVEL_ERR,
d1e348cf
A
795 "failed to send vpn_control need authinfo status: %s\n", strerror(errno));
796 }
797 break;
798 }
799 }
800 }
801
802end:
803 if (msg)
804 racoon_free(msg);
805 return 0;
806}
807
52b7d2ce
A
808int
809vpncontrol_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)
810{
7ebaebe2 811 struct vpnctl_status_failed *msg = NULL;
52b7d2ce
A
812 struct vpnctl_socket_elem *sock_elem;
813 struct bound_addr *bound_addr;
85f41bec
A
814 size_t len;
815 ssize_t tlen;
52b7d2ce
A
816
817 len = sizeof(struct vpnctl_status_failed) + data_len;
818
819 msg = (struct vpnctl_status_failed *)racoon_malloc(len);
820 if (msg == NULL) {
7ebaebe2 821 plog(ASL_LEVEL_ERR,
52b7d2ce
A
822 "unable to allcate memory for vpn control status message.\n");
823 return -1;
824 }
825
826 msg->hdr.msg_type = htons(VPNCTL_STATUS_IKE_FAILED);
827 msg->hdr.flags = msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
828 msg->hdr.len = htons(len - sizeof(struct vpnctl_hdr));
829 msg->address = address;
830 msg->ike_code = htons(notify_code);
831 msg->from = htons(from);
832 if (data_len > 0)
833 memcpy(msg->data, data, data_len);
7ebaebe2 834 plog(ASL_LEVEL_ERR,
d1e348cf 835 "sending vpn_control ike failed message - code=%d from=%s.\n", notify_code,
52b7d2ce
A
836 (from == FROM_LOCAL ? "local" : "remote"));
837
838 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
839 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
840 if (bound_addr->address == 0xFFFFFFFF ||
841 bound_addr->address == address) {
842 tlen = send(sock_elem->sock, msg, len, 0);
843 if (tlen < 0) {
7ebaebe2 844 plog(ASL_LEVEL_ERR,
65c25746 845 "Unable to send vpn_control ike notify failed: %s\n", strerror(errno));
7ebaebe2
A
846 } else {
847 plog(ASL_LEVEL_DEBUG,
848 "Sent %zd/%zu bytes\n", tlen, len);
52b7d2ce
A
849 }
850 break;
851 }
852 }
853 }
d1e348cf
A
854
855 if (msg)
856 racoon_free(msg);
52b7d2ce
A
857 return 0;
858}
859
65c25746
A
860char *
861vpncontrol_status_2_str(u_int16_t msg_type)
862{
863 switch (msg_type) {
864 case VPNCTL_STATUS_IKE_FAILED:
865 return "IKE failed";
866 case VPNCTL_STATUS_PH1_START_US:
867 return "Phase 1 started by us";
868 case VPNCTL_STATUS_PH1_START_PEER:
869 return "Phase 1 started by peer";
870 case VPNCTL_STATUS_PH1_ESTABLISHED:
871 return "Phase 1 established";
872 case VPNCTL_STATUS_PH2_START:
873 return "Phase 2 started";
874 case VPNCTL_STATUS_PH2_ESTABLISHED:
875 return "Phase 2 established";
876 case VPNCTL_STATUS_NEED_AUTHINFO:
877 return "Need authentication info";
878 case VPNCTL_STATUS_NEED_REAUTHINFO:
879 return "Need re-authentication info";
880 default:
881 return "";
882 }
883}
884
52b7d2ce
A
885
886int
65c25746 887vpncontrol_notify_phase_change(int start, u_int16_t from, phase1_handle_t *iph1, phase2_handle_t *iph2)
52b7d2ce 888{
7ebaebe2 889 struct vpnctl_status_phase_change *msg;
52b7d2ce
A
890 struct vpnctl_socket_elem *sock_elem;
891 struct bound_addr *bound_addr;
85f41bec
A
892 ssize_t tlen;
893 size_t msg_size;
52b7d2ce 894 u_int32_t address;
d1e348cf 895
65c25746 896 if (iph1 && !start && iph1->mode_cfg && iph1->mode_cfg->xauth.status != XAUTHST_OK) {
d1e348cf
A
897 if (vpn_get_config(iph1, &msg, &msg_size) == 1)
898 return 0; /* mode config not finished yet */
899 } else {
900 msg = racoon_malloc(msg_size = sizeof(struct vpnctl_status_phase_change));
901 msg->hdr.flags = 0;
902 }
52b7d2ce 903
d1e348cf 904 if (msg == NULL) {
7ebaebe2 905 plog(ASL_LEVEL_ERR,
d1e348cf
A
906 "unable to allocate space for vpn control message.\n");
907 return -1;
908 }
52b7d2ce 909 if (iph1) {
d06a7ccb
A
910 address = iph1_get_remote_v4_address(iph1);
911 if (address == 0) {
912 plog(ASL_LEVEL_ERR, "bad address for ph1 status change.\n");
913 goto end;
914 }
7ebaebe2
A
915 msg->hdr.msg_type = htons(start ?
916 (from == FROM_LOCAL ? VPNCTL_STATUS_PH1_START_US : VPNCTL_STATUS_PH1_START_PEER)
52b7d2ce 917 : VPNCTL_STATUS_PH1_ESTABLISHED);
65c25746 918 // TODO: indicate version
52b7d2ce 919 } else {
d06a7ccb
A
920 address = iph2_get_remote_v4_address(iph2);
921 if (address == 0) {
922 plog(ASL_LEVEL_ERR, "bad address for ph2 status change.\n");
923 goto end;
924 }
d1e348cf 925 msg->hdr.msg_type = htons(start ? VPNCTL_STATUS_PH2_START : VPNCTL_STATUS_PH2_ESTABLISHED);
65c25746 926 // TODO: indicate version
52b7d2ce 927 }
65c25746
A
928 plog(ASL_LEVEL_NOTICE,
929 ">>>>> phase change status = %s\n", vpncontrol_status_2_str(ntohs(msg->hdr.msg_type)));
930
d1e348cf
A
931 msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
932 msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));
933 msg->address = address;
52b7d2ce
A
934
935 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
936 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
937 if (bound_addr->address == 0xFFFFFFFF ||
938 bound_addr->address == address) {
65c25746 939 plog(ASL_LEVEL_DEBUG, "vpn control writing %zu bytes\n", msg_size);
d1e348cf 940 tlen = send(sock_elem->sock, msg, msg_size, 0);
52b7d2ce 941 if (tlen < 0) {
7ebaebe2 942 plog(ASL_LEVEL_ERR,
52b7d2ce
A
943 "failed to send vpn_control phase change status: %s\n", strerror(errno));
944 }
945 break;
946 }
947 }
948 }
949
d1e348cf
A
950end:
951 if (msg)
952 racoon_free(msg);
52b7d2ce
A
953 return 0;
954}
955
e8d9021d
A
956static int
957vpncontrol_notify_peer_resp (u_int16_t notify_code, u_int32_t address)
958{
7ebaebe2 959 struct vpnctl_status_peer_resp msg;
e8d9021d
A
960 struct vpnctl_socket_elem *sock_elem;
961 struct bound_addr *bound_addr;
85f41bec 962 ssize_t tlen;
e8d9021d
A
963 int rc = -1;
964
965 bzero(&msg, sizeof(msg));
966 msg.hdr.msg_type = htons(VPNCTL_STATUS_PEER_RESP);
967 msg.hdr.cookie = msg.hdr.reserved = msg.hdr.result = 0;
968 msg.hdr.len = htons(sizeof(msg) - sizeof(msg.hdr));
969 msg.address = address;
970 msg.ike_code = notify_code;
7ebaebe2 971 plog(ASL_LEVEL_NOTICE,
e8d9021d
A
972 "sending vpn_control status (peer response) message - code=%d addr=%x.\n", notify_code, address);
973
974 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
975 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
976 if (bound_addr->address == 0xFFFFFFFF ||
977 bound_addr->address == address) {
978 tlen = send(sock_elem->sock, &msg, sizeof(msg), 0);
979 if (tlen < 0) {
7ebaebe2 980 plog(ASL_LEVEL_ERR,
e8d9021d
A
981 "unable to send vpn_control status (peer response): %s\n", strerror(errno));
982 } else {
983 rc = 0;
984 }
985 break;
986 }
987 }
988 }
989
990 return rc;
991}
992
993int
65c25746 994vpncontrol_notify_peer_resp_ph1 (u_int16_t notify_code, phase1_handle_t *iph1)
e8d9021d 995{
e8d9021d 996 if (iph1 && iph1->parent_session && iph1->parent_session->controller_awaiting_peer_resp) {
d06a7ccb
A
997 int rc;
998 if ((rc = vpncontrol_notify_peer_resp(notify_code, iph1_get_remote_v4_address(iph1))) == 0) {
999 iph1->parent_session->controller_awaiting_peer_resp = 0;
1000 }
1001 return rc;
e8d9021d
A
1002 } else {
1003 return 0;
1004 }
e8d9021d
A
1005}
1006
1007int
65c25746 1008vpncontrol_notify_peer_resp_ph2 (u_int16_t notify_code, phase2_handle_t *iph2)
e8d9021d 1009{
e8d9021d 1010 if (iph2 && iph2->parent_session && iph2->parent_session->controller_awaiting_peer_resp) {
d06a7ccb
A
1011 int rc;
1012 if ((rc = vpncontrol_notify_peer_resp(notify_code, iph2_get_remote_v4_address(iph2))) == 0) {
1013 iph2->parent_session->controller_awaiting_peer_resp = 0;
1014 }
1015 return rc;
e8d9021d
A
1016 } else {
1017 return 0;
1018 }
e8d9021d 1019}
52b7d2ce
A
1020
1021int
65c25746 1022vpncontrol_init(void)
52b7d2ce 1023{
65c25746 1024 int sock;
7ebaebe2 1025
52b7d2ce
A
1026 if (vpncontrolsock_path == NULL) {
1027 lcconf->sock_vpncontrol = -1;
1028 return 0;
1029 }
1030
7ebaebe2 1031 if ( (lcconf->sock_vpncontrol = checklaunchd()) == 0 ) {
d1e348cf
A
1032 memset(&sunaddr, 0, sizeof(sunaddr));
1033 sunaddr.sun_family = AF_UNIX;
1034 snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
1035 "%s", vpncontrolsock_path);
52b7d2ce 1036
d1e348cf
A
1037 lcconf->sock_vpncontrol = socket(AF_UNIX, SOCK_STREAM, 0);
1038 if (lcconf->sock_vpncontrol == -1) {
7ebaebe2 1039 plog(ASL_LEVEL_ERR,
d1e348cf
A
1040 "socket: %s\n", strerror(errno));
1041 return -1;
1042 }
52b7d2ce 1043
85f41bec 1044 if (fcntl(lcconf->sock_vpncontrol, F_SETFL, O_NONBLOCK) == -1) {
65c25746 1045 plog(ASL_LEVEL_ERR, "failed to put VPN-Control socket in non-blocking mode\n");
85f41bec 1046 }
7ebaebe2 1047
d1e348cf
A
1048 unlink(sunaddr.sun_path);
1049 if (bind(lcconf->sock_vpncontrol, (struct sockaddr *)&sunaddr,
1050 sizeof(sunaddr)) != 0) {
7ebaebe2 1051 plog(ASL_LEVEL_ERR,
d1e348cf
A
1052 "bind(sockname:%s): %s\n",
1053 sunaddr.sun_path, strerror(errno));
1054 (void)close(lcconf->sock_vpncontrol);
1055 return -1;
1056 }
52b7d2ce 1057
d1e348cf 1058 if (chown(sunaddr.sun_path, vpncontrolsock_owner, vpncontrolsock_group) != 0) {
7ebaebe2
A
1059 plog(ASL_LEVEL_ERR,
1060 "chown(%s, %d, %d): %s\n",
1061 sunaddr.sun_path, vpncontrolsock_owner,
d1e348cf
A
1062 vpncontrolsock_group, strerror(errno));
1063 (void)close(lcconf->sock_vpncontrol);
1064 return -1;
1065 }
52b7d2ce 1066
d1e348cf 1067 if (chmod(sunaddr.sun_path, vpncontrolsock_mode) != 0) {
7ebaebe2
A
1068 plog(ASL_LEVEL_ERR,
1069 "chmod(%s, 0%03o): %s\n",
d1e348cf
A
1070 sunaddr.sun_path, vpncontrolsock_mode, strerror(errno));
1071 (void)close(lcconf->sock_vpncontrol);
1072 return -1;
1073 }
52b7d2ce 1074
d1e348cf 1075 if (listen(lcconf->sock_vpncontrol, 5) != 0) {
7ebaebe2 1076 plog(ASL_LEVEL_ERR,
d1e348cf
A
1077 "listen(sockname:%s): %s\n",
1078 sunaddr.sun_path, strerror(errno));
1079 (void)close(lcconf->sock_vpncontrol);
1080 return -1;
1081 }
7ebaebe2 1082 plog(ASL_LEVEL_NOTICE,
d1e348cf 1083 "opened %s as racoon management.\n", sunaddr.sun_path);
d1e348cf 1084 }
65c25746
A
1085 lcconf->vpncontrol_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, lcconf->sock_vpncontrol, 0, dispatch_get_main_queue());
1086 if (lcconf->vpncontrol_source == NULL) {
1087 plog(ASL_LEVEL_ERR, "could not create vpncontrol socket source.");
1088 return -1;
1089 }
1090 dispatch_source_set_event_handler_f(lcconf->vpncontrol_source, vpncontrol_handler);
1091 sock = lcconf->sock_vpncontrol;
7ebaebe2 1092 dispatch_source_set_cancel_handler(lcconf->vpncontrol_source,
65c25746
A
1093 ^{
1094 close(sock);
1095 });
1096 dispatch_resume(lcconf->vpncontrol_source);
1097 return 0;
52b7d2ce
A
1098}
1099
85f41bec
A
1100void
1101vpncontrol_disconnect_all(struct vpnctl_socket_elem *elem, const char *reason)
1102{
1103 struct bound_addr *addr;
1104 struct bound_addr *t_addr;
7ebaebe2
A
1105
1106 plog(ASL_LEVEL_NOTICE,
85f41bec 1107 "received disconnect all command.\n");
7ebaebe2 1108
85f41bec
A
1109 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
1110 /* stop any connections */
1111 vpn_disconnect(addr, reason);
1112 }
1113}
1114
52b7d2ce
A
1115void
1116vpncontrol_close()
1117{
65c25746 1118 struct vpnctl_socket_elem *elem;
52b7d2ce
A
1119 struct vpnctl_socket_elem *t_elem;
1120
7ebaebe2 1121 plog(ASL_LEVEL_NOTICE,
65c25746 1122 "vpncontrol_close.\n");
d1e348cf 1123
65c25746
A
1124 dispatch_source_cancel(lcconf->vpncontrol_source);
1125 lcconf->vpncontrol_source = NULL;
7ebaebe2 1126
65c25746
A
1127 lcconf->sock_vpncontrol = -1;
1128 LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem)
1129 vpncontrol_close_comm(elem);
52b7d2ce
A
1130}
1131
1132static void
1133vpncontrol_close_comm(struct vpnctl_socket_elem *elem)
1134{
1135 struct bound_addr *addr;
1136 struct bound_addr *t_addr;
d1e348cf 1137
7ebaebe2 1138 plog(ASL_LEVEL_NOTICE,
d1e348cf 1139 "vpncontrol_close_comm.\n");
52b7d2ce
A
1140
1141 LIST_REMOVE(elem, chain);
7ebaebe2 1142 if (elem->sock != -1) {
65c25746 1143 dispatch_source_cancel(elem->source);
7ebaebe2
A
1144 elem->sock = -1;
1145 }
1146 if (elem->buffer != NULL) {
1147 free(elem->buffer);
1148 elem->buffer = NULL;
1149 elem->pending_bytes_len = 0;
1150 elem->read_bytes_len = 0;
1151 }
52b7d2ce 1152 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
d1e348cf 1153 flushsainfo_dynamic(addr->address);
52b7d2ce 1154 LIST_REMOVE(addr, chain);
d1e348cf
A
1155 if (addr->version)
1156 vfree(addr->version);
52b7d2ce
A
1157 racoon_free(addr);
1158 }
1159 racoon_free(elem);
1160 check_auto_exit();
d9c572c0 1161
52b7d2ce
A
1162}
1163
1164int
1165vpn_control_connected(void)
1166{
1167 if (LIST_EMPTY(&lcconf->vpnctl_comm_socks))
1168 return 0;
1169 else
1170 return 1;
1171}
1172
1173#endif