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