1 /* $Id: vpn_control.c,v 1.17.2.4 2005/07/12 11:49:44 manubsd Exp $ */
4 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
6 * @APPLE_LICENSE_HEADER_START@
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.
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
22 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
27 * All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
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.
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
56 #include <sys/types.h>
57 #include <sys/param.h>
58 #include <sys/socket.h>
59 #include <sys/signal.h>
63 #include <net/pfkeyv2.h>
65 #include <netinet/in.h>
66 #ifndef HAVE_NETINET6_IPSEC
67 #include <netinet/ipsec.h>
69 #include <netinet6/ipsec.h>
92 #include "localconf.h"
93 #include "remoteconf.h"
94 #include "grabmyaddr.h"
95 #include "isakmp_var.h"
100 #include "ipsec_doi.h"
101 #include "vpn_control.h"
102 #include "vpn_control_var.h"
103 #include "isakmp_inf.h"
105 #include "gcmalloc.h"
106 #include "isakmp_cfg.h"
109 #ifdef ENABLE_VPNCONTROL_PORT
110 char *vpncontrolsock_path
= VPNCONTROLSOCK_PATH
;
111 uid_t vpncontrolsock_owner
= 0;
112 gid_t vpncontrolsock_group
= 0;
113 mode_t vpncontrolsock_mode
= 0600;
115 static struct sockaddr_un sunaddr
;
116 static int vpncontrol_process (struct vpnctl_socket_elem
*, char *, size_t);
117 static int vpncontrol_reply (int, char *);
118 static void vpncontrol_close_comm (struct vpnctl_socket_elem
*);
119 static int checklaunchd (void);
120 extern int vpn_get_config (phase1_handle_t
*, struct vpnctl_status_phase_change
**, size_t *);
121 extern int vpn_xauth_reply (u_int32_t
, void *, size_t);
128 int *listening_fd_array
= NULL
;
131 int result
= launch_activate_socket("Listeners", &listening_fd_array
, &fd_count
);
133 plog(ASL_LEVEL_ERR
, "failed to launch_activate_socket with error %s.\n", strerror(result
));
137 if (listening_fd_array
!= NULL
) {
139 returnval
= listening_fd_array
[0];
141 free(listening_fd_array
);
142 listening_fd_array
= NULL
;
150 vpncontrol_handler(void *unused
)
152 struct sockaddr_storage from
;
153 socklen_t fromlen
= sizeof(from
);
156 struct vpnctl_socket_elem
*sock_elem
;
159 sock_elem
= racoon_calloc(1, sizeof(struct vpnctl_socket_elem
));
160 if (sock_elem
== NULL
) {
162 "memory error: %s\n", strerror(errno
));
163 return; //%%%%%% terminate
165 LIST_INIT(&sock_elem
->bound_addresses
);
167 sock_elem
->sock
= accept(lcconf
->sock_vpncontrol
, (struct sockaddr
*)&from
, &fromlen
);
168 if (sock_elem
->sock
< 0) {
170 "failed to accept vpn_control command: %s\n", strerror(errno
));
171 racoon_free(sock_elem
);
172 return; //%%%%% terminate
174 LIST_INSERT_HEAD(&lcconf
->vpnctl_comm_socks
, sock_elem
, chain
);
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
182 dispatch_source_set_event_handler(sock_elem
->source
,
184 vpncontrol_comm_handler(sock_elem
);
186 sock
= sock_elem
->sock
;
188 dispatch_source_t the_source
= sock_elem
->source
;
189 dispatch_source_set_cancel_handler(sock_elem
->source
,
192 dispatch_release(the_source
); /* Release the source on cancel */
194 dispatch_resume(sock_elem
->source
);
196 plog(ASL_LEVEL_NOTICE
,
197 "accepted connection on vpn control socket.\n");
204 vpncontrol_comm_handler(struct vpnctl_socket_elem
*elem
)
206 struct vpnctl_hdr hdr
;
209 /* get buffer length */
210 if (elem
->buffer
== NULL
) {
211 while ((len
= recv(elem
->sock
, (char *)&hdr
, sizeof(hdr
), MSG_PEEK
)) < 0) {
214 plog(ASL_LEVEL_ERR
, "failed to recv vpn_control command: %s\n", strerror(errno
));
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
226 if (len
< sizeof(hdr
)) {
228 "invalid header length of vpn_control command - len=%ld - expected %ld\n", len
, sizeof(hdr
));
232 elem
->read_bytes_len
= 0; // Sanity
233 elem
->pending_bytes_len
= ntohs(hdr
.len
) + sizeof(hdr
);
235 /* get buffer to receive */
236 elem
->buffer
= racoon_malloc(elem
->pending_bytes_len
);
237 if (elem
->buffer
== NULL
) {
239 "failed to alloc buffer for vpn_control command\n");
245 while ((len
= recv(elem
->sock
, elem
->buffer
+ elem
->read_bytes_len
, elem
->pending_bytes_len
, 0)) < 0) {
248 plog(ASL_LEVEL_ERR
, "failed to recv vpn_control command: %s\n",
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
);
261 elem
->read_bytes_len
+= len
;
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
;
269 (void)vpncontrol_process(elem
, elem
->buffer
, elem
->read_bytes_len
);
272 elem
->read_bytes_len
= 0;
273 elem
->pending_bytes_len
= 0;
278 vpncontrol_process(struct vpnctl_socket_elem
*elem
, char *combuf
, size_t combuf_len
)
281 struct vpnctl_hdr
*hdr
= ALIGNED_CAST(struct vpnctl_hdr
*)combuf
;
283 switch (ntohs(hdr
->msg_type
)) {
285 case VPNCTL_CMD_BIND
:
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
));
293 struct vpnctl_cmd_bind
*pkt
= ALIGNED_CAST(struct vpnctl_cmd_bind
*)combuf
;
294 struct bound_addr
*addr
;
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
)));
302 plog(ASL_LEVEL_NOTICE
,
303 "received bind command on vpn control socket.\n");
304 addr
= racoon_calloc(1, sizeof(struct bound_addr
));
307 "memory error: %s\n", strerror(errno
));
311 if (ntohs(pkt
->vers_len
)) {
312 addr
->version
= vmalloc(ntohs(pkt
->vers_len
));
313 if (addr
->version
== NULL
) {
315 "memory error: %s\n", strerror(errno
));
320 memcpy(addr
->version
->v
, pkt
+ 1, ntohs(pkt
->vers_len
));
322 addr
->address
= pkt
->address
;
323 LIST_INSERT_HEAD(&elem
->bound_addresses
, addr
, chain
);
324 lcconf
->auto_exit_state
|= LC_AUTOEXITSTATE_CLIENT
; /* client side */
328 case VPNCTL_CMD_UNBIND
:
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
));
336 struct vpnctl_cmd_unbind
*pkt
= ALIGNED_CAST(struct vpnctl_cmd_unbind
*)combuf
;
337 struct bound_addr
*addr
;
338 struct bound_addr
*t_addr
;
340 plog(ASL_LEVEL_NOTICE
,
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
) {
345 flushsainfo_dynamic(addr
->address
);
346 LIST_REMOVE(addr
, chain
);
348 vfree(addr
->version
);
355 case VPNCTL_CMD_REDIRECT
:
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
));
363 struct vpnctl_cmd_redirect
*redirect_msg
= ALIGNED_CAST(struct vpnctl_cmd_redirect
*)combuf
;
364 struct redirect
*raddr
;
365 struct redirect
*t_raddr
;
368 plog(ASL_LEVEL_NOTICE
,
369 "received redirect command on vpn control socket - address = %x.\n", ntohl(redirect_msg
->redirect_address
));
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
);
377 raddr
->redirect_address
= redirect_msg
->redirect_address
;
378 raddr
->force
= ntohs(redirect_msg
->force
);
385 raddr
= racoon_malloc(sizeof(struct redirect
));
388 "cannot allcoate memory for redirect address.\n");
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
);
401 case VPNCTL_CMD_PING
:
402 break; /* just reply for now */
404 case VPNCTL_CMD_XAUTH_INFO
:
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
));
412 struct vpnctl_cmd_xauth_info
*pkt
= ALIGNED_CAST(struct vpnctl_cmd_xauth_info
*)combuf
;
413 struct bound_addr
*addr
;
414 struct bound_addr
*t_addr
;
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
)));
423 plog(ASL_LEVEL_NOTICE
,
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 */
429 error
= vpn_xauth_reply(pkt
->address
, attr_list
, ntohs(pkt
->hdr
.len
) - sizeof(u_int32_t
));
436 case VPNCTL_CMD_SET_NAT64_PREFIX
:
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
));
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
;
448 plog(ASL_LEVEL_NOTICE
,
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
));
456 case VPNCTL_CMD_CONNECT
:
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
));
464 struct vpnctl_cmd_connect
*pkt
= ALIGNED_CAST(struct vpnctl_cmd_connect
*)combuf
;
465 struct bound_addr
*addr
;
466 struct bound_addr
*t_addr
;
468 if (pending_signal_handle
) {
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)
474 pending_signal_handle
= 0;
477 plog(ASL_LEVEL_NOTICE
,
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 */
482 error
= vpn_connect(addr
, VPN_STARTED_BY_API
);
489 case VPNCTL_CMD_DISCONNECT
:
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
));
497 struct vpnctl_cmd_connect
*pkt
= ALIGNED_CAST(struct vpnctl_cmd_connect
*)combuf
;
498 struct bound_addr
*addr
;
499 struct bound_addr
*t_addr
;
501 plog(ASL_LEVEL_NOTICE
,
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 */
506 error
= vpn_disconnect(addr
, ike_session_stopped_by_vpn_disconnect
);
513 case VPNCTL_CMD_START_PH2
:
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
));
521 struct vpnctl_cmd_start_ph2
*pkt
= ALIGNED_CAST(struct vpnctl_cmd_start_ph2
*)combuf
;
522 struct bound_addr
*addr
;
523 struct bound_addr
*t_addr
;
525 plog(ASL_LEVEL_NOTICE
, "received start_ph2 command on vpn control socket.\n");
526 LIST_FOREACH_SAFE(addr
, &elem
->bound_addresses
, chain
, t_addr
) {
527 if (pkt
->address
== addr
->address
) {
528 /* start the connection */
529 error
= vpn_start_ph2(addr
, pkt
, combuf_len
);
536 case VPNCTL_CMD_START_DPD
:
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
));
544 struct vpnctl_cmd_start_dpd
*pkt
= ALIGNED_CAST(struct vpnctl_cmd_start_dpd
*)combuf
;
545 struct bound_addr
*srv
;
546 struct bound_addr
*t_addr
;
548 plog(ASL_LEVEL_NOTICE
,
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
) {
552 union { // Wcast-align fix - force alignment
553 struct sockaddr_storage ss
;
554 struct sockaddr_in addr_in
;
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
;
564 error
= ike_session_ph1_force_dpd(&daddr
.ss
);
571 case VPNCTL_CMD_ASSERT
:
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
));
579 struct vpnctl_cmd_assert
*pkt
= ALIGNED_CAST(struct vpnctl_cmd_assert
*)combuf
;
580 // struct bound_addr *addr;
581 // struct bound_addr *t_addr;
582 struct sockaddr_in saddr
;
583 struct sockaddr_in daddr
;
585 plogdump(ASL_LEVEL_NOTICE
, pkt
, ntohs(hdr
->len
) + sizeof(struct vpnctl_hdr
), "received assert command on vpn control socket.\n");
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
;
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
;
597 daddr
.sin_family
= AF_INET
;
599 error
= vpn_assert(ALIGNED_CAST(struct sockaddr_storage
*)&saddr
, ALIGNED_CAST(struct sockaddr_storage
*)&daddr
);
606 case VPNCTL_CMD_RECONNECT
:
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
));
614 struct vpnctl_cmd_connect
*pkt
= ALIGNED_CAST(struct vpnctl_cmd_connect
*)combuf
;
615 struct bound_addr
*addr
;
616 struct bound_addr
*t_addr
;
618 plog(ASL_LEVEL_NOTICE
,
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
);
632 "invalid command: %d\n", ntohs(hdr
->msg_type
));
633 error
= -1; // for now
638 hdr
->result
= htons(error
);
639 if (vpncontrol_reply(elem
->sock
, combuf
) < 0)
647 vpncontrol_reply(int so
, char *combuf
)
651 tlen
= send(so
, combuf
, sizeof(struct vpnctl_hdr
), 0);
654 "failed to send vpn_control message: %s\n", strerror(errno
));
662 vpncontrol_set_nat64_prefix(nw_nat64_prefix_t
*prefix
)
664 struct vpnctl_socket_elem
*sock_elem
;
665 struct bound_addr
*bound_addr
;
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
));
679 vpncontrol_notify_need_authinfo(phase1_handle_t
*iph1
, void* attr_list
, size_t attr_len
)
681 struct vpnctl_status_need_authinfo
*msg
= NULL
;
682 struct vpnctl_socket_elem
*sock_elem
;
683 struct bound_addr
*bound_addr
;
692 plog(ASL_LEVEL_NOTICE
,
693 "sending vpn_control xauth need info status\n");
695 msg
= (struct vpnctl_status_need_authinfo
*)racoon_malloc(msg_size
= sizeof(struct vpnctl_status_need_authinfo
) + attr_len
);
698 "unable to allocate space for vpn control message.\n");
703 address
= iph1_get_remote_v4_address(iph1
);
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
);
713 msg
->hdr
.msg_type
= htons(VPNCTL_STATUS_NEED_REAUTHINFO
);
715 msg
->address
= iph1_get_remote_v4_address(iph1
);
717 memcpy(ptr
, attr_list
, attr_len
);
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
) {
723 plog(ASL_LEVEL_DEBUG
, "vpn control writing %zu bytes\n", msg_size
);
724 tlen
= send(sock_elem
->sock
, msg
, msg_size
, 0);
727 "failed to send vpn_control need authinfo status: %s\n", strerror(errno
));
741 vpncontrol_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
)
743 struct vpnctl_status_failed
*msg
= NULL
;
744 struct vpnctl_socket_elem
*sock_elem
;
745 struct bound_addr
*bound_addr
;
749 len
= sizeof(struct vpnctl_status_failed
) + data_len
;
751 msg
= (struct vpnctl_status_failed
*)racoon_malloc(len
);
754 "unable to allcate memory for vpn control status message.\n");
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
);
765 memcpy(msg
->data
, data
, data_len
);
767 "sending vpn_control ike failed message - code=%d from=%s.\n", notify_code
,
768 (from
== FROM_LOCAL
? "local" : "remote"));
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);
777 "Unable to send vpn_control ike notify failed: %s\n", strerror(errno
));
779 plog(ASL_LEVEL_DEBUG
,
780 "Sent %zd/%zu bytes\n", tlen
, len
);
793 vpncontrol_status_2_str(u_int16_t msg_type
)
796 case VPNCTL_STATUS_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";
819 vpncontrol_notify_phase_change(int start
, u_int16_t from
, phase1_handle_t
*iph1
, phase2_handle_t
*iph2
)
821 struct vpnctl_status_phase_change
*msg
;
822 struct vpnctl_socket_elem
*sock_elem
;
823 struct bound_addr
*bound_addr
;
828 if (iph1
&& !start
&& iph1
->mode_cfg
&& iph1
->mode_cfg
->xauth
.status
!= XAUTHST_OK
) {
829 if (vpn_get_config(iph1
, &msg
, &msg_size
) == 1)
830 return 0; /* mode config not finished yet */
832 msg
= racoon_malloc(msg_size
= sizeof(struct vpnctl_status_phase_change
));
838 "unable to allocate space for vpn control message.\n");
842 address
= iph1_get_remote_v4_address(iph1
);
844 plog(ASL_LEVEL_ERR
, "bad address for ph1 status change.\n");
847 msg
->hdr
.msg_type
= htons(start
?
848 (from
== FROM_LOCAL
? VPNCTL_STATUS_PH1_START_US
: VPNCTL_STATUS_PH1_START_PEER
)
849 : VPNCTL_STATUS_PH1_ESTABLISHED
);
850 // TODO: indicate version
852 address
= iph2_get_remote_v4_address(iph2
);
854 plog(ASL_LEVEL_ERR
, "bad address for ph2 status change.\n");
857 msg
->hdr
.msg_type
= htons(start
? VPNCTL_STATUS_PH2_START
: VPNCTL_STATUS_PH2_ESTABLISHED
);
858 // TODO: indicate version
860 plog(ASL_LEVEL_NOTICE
,
861 ">>>>> phase change status = %s\n", vpncontrol_status_2_str(ntohs(msg
->hdr
.msg_type
)));
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
;
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
) {
871 plog(ASL_LEVEL_DEBUG
, "vpn control writing %zu bytes\n", msg_size
);
872 tlen
= send(sock_elem
->sock
, msg
, msg_size
, 0);
875 "failed to send vpn_control phase change status: %s\n", strerror(errno
));
889 vpncontrol_notify_peer_resp (u_int16_t notify_code
, u_int32_t address
)
891 struct vpnctl_status_peer_resp msg
;
892 struct vpnctl_socket_elem
*sock_elem
;
893 struct bound_addr
*bound_addr
;
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
;
903 plog(ASL_LEVEL_NOTICE
,
904 "sending vpn_control status (peer response) message - code=%d addr=%x.\n", notify_code
, address
);
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);
913 "unable to send vpn_control status (peer response): %s\n", strerror(errno
));
926 vpncontrol_notify_peer_resp_ph1 (u_int16_t notify_code
, phase1_handle_t
*iph1
)
928 if (iph1
&& iph1
->parent_session
&& iph1
->parent_session
->controller_awaiting_peer_resp
) {
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;
940 vpncontrol_notify_peer_resp_ph2 (u_int16_t notify_code
, phase2_handle_t
*iph2
)
942 if (iph2
&& iph2
->parent_session
&& iph2
->parent_session
->controller_awaiting_peer_resp
) {
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;
954 vpncontrol_init(void)
958 if (vpncontrolsock_path
== NULL
) {
959 lcconf
->sock_vpncontrol
= -1;
963 if ( (lcconf
->sock_vpncontrol
= checklaunchd()) == 0 ) {
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
);
969 lcconf
->sock_vpncontrol
= socket(AF_UNIX
, SOCK_STREAM
, 0);
970 if (lcconf
->sock_vpncontrol
== -1) {
972 "socket: %s\n", strerror(errno
));
976 if (fcntl(lcconf
->sock_vpncontrol
, F_SETFL
, O_NONBLOCK
) == -1) {
977 plog(ASL_LEVEL_ERR
, "failed to put VPN-Control socket in non-blocking mode\n");
980 unlink(sunaddr
.sun_path
);
981 if (bind(lcconf
->sock_vpncontrol
, (struct sockaddr
*)&sunaddr
,
982 sizeof(sunaddr
)) != 0) {
984 "bind(sockname:%s): %s\n",
985 sunaddr
.sun_path
, strerror(errno
));
986 (void)close(lcconf
->sock_vpncontrol
);
990 if (chown(sunaddr
.sun_path
, vpncontrolsock_owner
, vpncontrolsock_group
) != 0) {
992 "chown(%s, %d, %d): %s\n",
993 sunaddr
.sun_path
, vpncontrolsock_owner
,
994 vpncontrolsock_group
, strerror(errno
));
995 (void)close(lcconf
->sock_vpncontrol
);
999 if (chmod(sunaddr
.sun_path
, vpncontrolsock_mode
) != 0) {
1001 "chmod(%s, 0%03o): %s\n",
1002 sunaddr
.sun_path
, vpncontrolsock_mode
, strerror(errno
));
1003 (void)close(lcconf
->sock_vpncontrol
);
1007 if (listen(lcconf
->sock_vpncontrol
, 5) != 0) {
1009 "listen(sockname:%s): %s\n",
1010 sunaddr
.sun_path
, strerror(errno
));
1011 (void)close(lcconf
->sock_vpncontrol
);
1014 plog(ASL_LEVEL_NOTICE
,
1015 "opened %s as racoon management.\n", sunaddr
.sun_path
);
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.");
1022 dispatch_source_set_event_handler_f(lcconf
->vpncontrol_source
, vpncontrol_handler
);
1023 sock
= lcconf
->sock_vpncontrol
;
1024 dispatch_source_set_cancel_handler(lcconf
->vpncontrol_source
,
1028 dispatch_resume(lcconf
->vpncontrol_source
);
1033 vpncontrol_disconnect_all(struct vpnctl_socket_elem
*elem
, const char *reason
)
1035 struct bound_addr
*addr
;
1036 struct bound_addr
*t_addr
;
1038 plog(ASL_LEVEL_NOTICE
,
1039 "received disconnect all command.\n");
1041 LIST_FOREACH_SAFE(addr
, &elem
->bound_addresses
, chain
, t_addr
) {
1042 /* stop any connections */
1043 vpn_disconnect(addr
, reason
);
1050 struct vpnctl_socket_elem
*elem
;
1051 struct vpnctl_socket_elem
*t_elem
;
1053 plog(ASL_LEVEL_NOTICE
,
1054 "vpncontrol_close.\n");
1056 dispatch_source_cancel(lcconf
->vpncontrol_source
);
1057 lcconf
->vpncontrol_source
= NULL
;
1059 lcconf
->sock_vpncontrol
= -1;
1060 LIST_FOREACH_SAFE(elem
, &lcconf
->vpnctl_comm_socks
, chain
, t_elem
)
1061 vpncontrol_close_comm(elem
);
1065 vpncontrol_close_comm(struct vpnctl_socket_elem
*elem
)
1067 struct bound_addr
*addr
;
1068 struct bound_addr
*t_addr
;
1070 plog(ASL_LEVEL_NOTICE
,
1071 "vpncontrol_close_comm.\n");
1073 LIST_REMOVE(elem
, chain
);
1074 if (elem
->sock
!= -1) {
1075 dispatch_source_cancel(elem
->source
);
1078 if (elem
->buffer
!= NULL
) {
1080 elem
->buffer
= NULL
;
1081 elem
->pending_bytes_len
= 0;
1082 elem
->read_bytes_len
= 0;
1084 LIST_FOREACH_SAFE(addr
, &elem
->bound_addresses
, chain
, t_addr
) {
1085 flushsainfo_dynamic(addr
->address
);
1086 LIST_REMOVE(addr
, chain
);
1088 vfree(addr
->version
);
1097 vpn_control_connected(void)
1099 if (LIST_EMPTY(&lcconf
->vpnctl_comm_socks
))