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 <System/net/pfkeyv2.h>
65 #include <netinet/in.h>
66 #ifndef HAVE_NETINET6_IPSEC
67 #include <netinet/ipsec.h>
69 #include <netinet6/ipsec.h>
90 #include "localconf.h"
91 #include "remoteconf.h"
92 #include "grabmyaddr.h"
93 #include "isakmp_var.h"
99 #include "ipsec_doi.h"
100 #include "vpn_control.h"
101 #include "vpn_control_var.h"
102 #include "isakmp_inf.h"
104 #include "gcmalloc.h"
106 #ifdef ENABLE_VPNCONTROL_PORT
107 char *vpncontrolsock_path
= VPNCONTROLSOCK_PATH
;
108 uid_t vpncontrolsock_owner
= 0;
109 gid_t vpncontrolsock_group
= 0;
110 mode_t vpncontrolsock_mode
= 0600;
112 static struct sockaddr_un sunaddr
;
113 static int vpncontrol_process(struct vpnctl_socket_elem
*, char *);
114 static int vpncontrol_reply(int, char *);
115 static void vpncontrol_close_comm(struct vpnctl_socket_elem
*);
120 struct sockaddr_storage from
;
121 socklen_t fromlen
= sizeof(from
);
123 struct vpnctl_socket_elem
*sock_elem
;
125 sock_elem
= racoon_malloc(sizeof(struct vpnctl_socket_elem
));
126 if (sock_elem
== NULL
) {
127 plog(LLV_ERROR
, LOCATION
, NULL
,
128 "memory error: %s\n", strerror(errno
));
131 LIST_INIT(&sock_elem
->bound_addresses
);
133 sock_elem
->sock
= accept(lcconf
->sock_vpncontrol
, (struct sockaddr
*)&from
, &fromlen
);
134 if (sock_elem
->sock
< 0) {
135 plog(LLV_ERROR
, LOCATION
, NULL
,
136 "failed to accept vpn_control command: %s\n", strerror(errno
));
137 racoon_free(sock_elem
);
140 LIST_INSERT_HEAD(&lcconf
->vpnctl_comm_socks
, sock_elem
, chain
);
141 plog(LLV_NOTIFY
, LOCATION
, NULL
,
142 "accepted connection on vpn control socket.\n");
150 vpncontrol_comm_handler(struct vpnctl_socket_elem
*elem
)
152 struct vpnctl_hdr hdr
;
156 /* get buffer length */
157 while ((len
= recv(elem
->sock
, (char *)&hdr
, sizeof(hdr
), MSG_PEEK
)) < 0) {
160 plog(LLV_ERROR
, LOCATION
, NULL
,
161 "failed to recv vpn_control command: %s\n", strerror(errno
));
165 plog(LLV_NOTIFY
, LOCATION
, NULL
,
166 "vpn_control socket closed by peer.\n");
167 vpncontrol_close_comm(elem
);
172 if (len
< sizeof(hdr
)) {
173 plog(LLV_ERROR
, LOCATION
, NULL
,
174 "invalid header length of vpn_control command - len=%d - expected %d\n", len
, sizeof(hdr
));
178 /* get buffer to receive */
179 if ((combuf
= racoon_malloc(ntohs(hdr
.len
) + sizeof(hdr
))) == 0) {
180 plog(LLV_ERROR
, LOCATION
, NULL
,
181 "failed to alloc buffer for vpn_control command\n");
186 while ((len
= recv(elem
->sock
, combuf
, ntohs(hdr
.len
) + sizeof(hdr
), 0)) < 0) {
189 plog(LLV_ERROR
, LOCATION
, NULL
,
190 "failed to recv vpn_control command: %s\n",
195 (void)vpncontrol_process(elem
, combuf
);
200 return 0; // return -1 only if a socket is closed
204 vpncontrol_process(struct vpnctl_socket_elem
*elem
, char *combuf
)
207 struct vpnctl_hdr
*hdr
= (struct vpnctl_hdr
*)combuf
;
209 switch (ntohs(hdr
->msg_type
)) {
211 case VPNCTL_CMD_BIND
:
213 struct vpnctl_cmd_bind
*pkt
= (struct vpnctl_cmd_bind
*)combuf
;
214 struct bound_addr
*addr
;
216 plog(LLV_DEBUG
, LOCATION
, NULL
,
217 "received bind command on vpn control socket.\n");
218 addr
= racoon_malloc(sizeof(struct bound_addr
));
220 plog(LLV_ERROR
, LOCATION
, NULL
,
221 "memory error: %s\n", strerror(errno
));
225 addr
->address
= pkt
->address
;
226 LIST_INSERT_HEAD(&elem
->bound_addresses
, addr
, chain
);
227 lcconf
->auto_exit_state
|= LC_AUTOEXITSTATE_CLIENT
; /* client side */
231 case VPNCTL_CMD_UNBIND
:
233 struct vpnctl_cmd_unbind
*pkt
= (struct vpnctl_cmd_unbind
*)combuf
;
234 struct bound_addr
*addr
;
235 struct bound_addr
*t_addr
;
237 plog(LLV_DEBUG
, LOCATION
, NULL
,
238 "received unbind command on vpn control socket.\n");
239 LIST_FOREACH_SAFE(addr
, &elem
->bound_addresses
, chain
, t_addr
) {
240 if (pkt
->address
== 0xFFFFFFFF ||
241 pkt
->address
== addr
->address
) {
242 LIST_REMOVE(addr
, chain
);
249 case VPNCTL_CMD_REDIRECT
:
251 struct vpnctl_cmd_redirect
*redirect_msg
= (struct vpnctl_cmd_redirect
*)combuf
;
252 struct redirect
*raddr
;
253 struct redirect
*t_raddr
;
256 plog(LLV_DEBUG
, LOCATION
, NULL
,
257 "received redirect command on vpn control socket - address = %x.\n", ntohl(redirect_msg
->redirect_address
));
259 LIST_FOREACH_SAFE(raddr
, &lcconf
->redirect_addresses
, chain
, t_raddr
) {
260 if (raddr
->cluster_address
== redirect_msg
->address
) {
261 if (redirect_msg
->redirect_address
== 0) {
262 LIST_REMOVE(raddr
, chain
);
265 raddr
->redirect_address
= redirect_msg
->redirect_address
;
266 raddr
->force
= ntohs(redirect_msg
->force
);
273 raddr
= racoon_malloc(sizeof(struct redirect
));
275 plog(LLV_DEBUG
, LOCATION
, NULL
,
276 "cannot allcoate memory for redirect address.\n");
280 raddr
->cluster_address
= redirect_msg
->address
;
281 raddr
->redirect_address
= redirect_msg
->redirect_address
;
282 raddr
->force
= ntohs(redirect_msg
->force
);
283 LIST_INSERT_HEAD(&lcconf
->redirect_addresses
, raddr
, chain
);
289 case VPNCTL_CMD_PING
:
290 break; // just reply for now
293 plog(LLV_ERROR
, LOCATION
, NULL
,
294 "invalid command: %d\n", ntohs(hdr
->msg_type
));
295 error
= -1; // for now
300 hdr
->result
= htons(error
);
301 if (vpncontrol_reply(elem
->sock
, combuf
) < 0)
309 vpncontrol_reply(int so
, char *combuf
)
313 tlen
= send(so
, combuf
, sizeof(struct vpnctl_hdr
), 0);
315 plog(LLV_ERROR
, LOCATION
, NULL
,
316 "failed to send vpn_control message: %s\n", strerror(errno
));
324 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
)
326 struct vpnctl_status_failed
*msg
;
327 struct vpnctl_socket_elem
*sock_elem
;
328 struct bound_addr
*bound_addr
;
331 len
= sizeof(struct vpnctl_status_failed
) + data_len
;
333 msg
= (struct vpnctl_status_failed
*)racoon_malloc(len
);
335 plog(LLV_DEBUG
, LOCATION
, NULL
,
336 "unable to allcate memory for vpn control status message.\n");
340 msg
->hdr
.msg_type
= htons(VPNCTL_STATUS_IKE_FAILED
);
341 msg
->hdr
.flags
= msg
->hdr
.cookie
= msg
->hdr
.reserved
= msg
->hdr
.result
= 0;
342 msg
->hdr
.len
= htons(len
- sizeof(struct vpnctl_hdr
));
343 msg
->address
= address
;
344 msg
->ike_code
= htons(notify_code
);
345 msg
->from
= htons(from
);
347 memcpy(msg
->data
, data
, data_len
);
348 plog(LLV_DEBUG
, LOCATION
, NULL
,
349 "sending vpn_control ike notify failed message - code=%d from=%s.\n", notify_code
,
350 (from
== FROM_LOCAL
? "local" : "remote"));
352 LIST_FOREACH(sock_elem
, &lcconf
->vpnctl_comm_socks
, chain
) {
353 LIST_FOREACH(bound_addr
, &sock_elem
->bound_addresses
, chain
) {
354 if (bound_addr
->address
== 0xFFFFFFFF ||
355 bound_addr
->address
== address
) {
356 tlen
= send(sock_elem
->sock
, msg
, len
, 0);
358 plog(LLV_ERROR
, LOCATION
, NULL
,
359 "unable to send vpn_control ike notify failed: %s\n", strerror(errno
));
370 vpncontrol_notify_phase_change(int start
, u_int16_t from
, struct ph1handle
*iph1
, struct ph2handle
*iph2
)
372 struct vpnctl_status_phase_change msg
;
373 struct vpnctl_socket_elem
*sock_elem
;
374 struct bound_addr
*bound_addr
;
379 if (iph1
->remote
->sa_family
== AF_INET
)
380 address
= ((struct sockaddr_in
*)iph1
->remote
)->sin_addr
.s_addr
;
383 msg
.hdr
.msg_type
= htons(start
?
384 (from
== FROM_LOCAL
? VPNCTL_STATUS_PH1_START_US
: VPNCTL_STATUS_PH1_START_PEER
)
385 : VPNCTL_STATUS_PH1_ESTABLISHED
);
387 if (iph2
->dst
->sa_family
== AF_INET
)
388 address
= ((struct sockaddr_in
*)iph2
->dst
)->sin_addr
.s_addr
;
391 msg
.hdr
.msg_type
= htons(start
? VPNCTL_STATUS_PH2_START
: VPNCTL_STATUS_PH2_ESTABLISHED
);
393 msg
.hdr
.flags
= msg
.hdr
.cookie
= msg
.hdr
.reserved
= msg
.hdr
.result
= 0;
394 msg
.hdr
.len
= htons(sizeof(struct vpnctl_status_phase_change
) - sizeof(struct vpnctl_hdr
));
395 msg
.address
= address
;
397 LIST_FOREACH(sock_elem
, &lcconf
->vpnctl_comm_socks
, chain
) {
398 LIST_FOREACH(bound_addr
, &sock_elem
->bound_addresses
, chain
) {
399 if (bound_addr
->address
== 0xFFFFFFFF ||
400 bound_addr
->address
== address
) {
401 tlen
= send(sock_elem
->sock
, &msg
, sizeof(struct vpnctl_status_phase_change
), 0);
403 plog(LLV_ERROR
, LOCATION
, NULL
,
404 "failed to send vpn_control phase change status: %s\n", strerror(errno
));
418 if (vpncontrolsock_path
== NULL
) {
419 lcconf
->sock_vpncontrol
= -1;
423 memset(&sunaddr
, 0, sizeof(sunaddr
));
424 sunaddr
.sun_family
= AF_UNIX
;
425 snprintf(sunaddr
.sun_path
, sizeof(sunaddr
.sun_path
),
426 "%s", vpncontrolsock_path
);
428 lcconf
->sock_vpncontrol
= socket(AF_UNIX
, SOCK_STREAM
, 0);
429 if (lcconf
->sock_vpncontrol
== -1) {
430 plog(LLV_ERROR
, LOCATION
, NULL
,
431 "socket: %s\n", strerror(errno
));
435 unlink(sunaddr
.sun_path
);
436 if (bind(lcconf
->sock_vpncontrol
, (struct sockaddr
*)&sunaddr
,
437 sizeof(sunaddr
)) != 0) {
438 plog(LLV_ERROR
, LOCATION
, NULL
,
439 "bind(sockname:%s): %s\n",
440 sunaddr
.sun_path
, strerror(errno
));
441 (void)close(lcconf
->sock_vpncontrol
);
445 if (chown(sunaddr
.sun_path
, vpncontrolsock_owner
, vpncontrolsock_group
) != 0) {
446 plog(LLV_ERROR
, LOCATION
, NULL
,
447 "chown(%s, %d, %d): %s\n",
448 sunaddr
.sun_path
, vpncontrolsock_owner
,
449 vpncontrolsock_group
, strerror(errno
));
450 (void)close(lcconf
->sock_vpncontrol
);
454 if (chmod(sunaddr
.sun_path
, vpncontrolsock_mode
) != 0) {
455 plog(LLV_ERROR
, LOCATION
, NULL
,
456 "chmod(%s, 0%03o): %s\n",
457 sunaddr
.sun_path
, vpncontrolsock_mode
, strerror(errno
));
458 (void)close(lcconf
->sock_vpncontrol
);
462 if (listen(lcconf
->sock_vpncontrol
, 5) != 0) {
463 plog(LLV_ERROR
, LOCATION
, NULL
,
464 "listen(sockname:%s): %s\n",
465 sunaddr
.sun_path
, strerror(errno
));
466 (void)close(lcconf
->sock_vpncontrol
);
469 plog(LLV_DEBUG
, LOCATION
, NULL
,
470 "opened %s as racoon management.\n", sunaddr
.sun_path
);
479 struct vpnctl_socket_elem
*elem
;
480 struct vpnctl_socket_elem
*t_elem
;
482 if (lcconf
->sock_vpncontrol
!= -1) {
483 close(lcconf
->sock_vpncontrol
);
484 lcconf
->sock_vpncontrol
= -1;
486 LIST_FOREACH_SAFE(elem
, &lcconf
->vpnctl_comm_socks
, chain
, t_elem
)
487 vpncontrol_close_comm(elem
);
491 vpncontrol_close_comm(struct vpnctl_socket_elem
*elem
)
493 struct bound_addr
*addr
;
494 struct bound_addr
*t_addr
;
496 LIST_REMOVE(elem
, chain
);
497 if (elem
->sock
!= -1)
499 LIST_FOREACH_SAFE(addr
, &elem
->bound_addresses
, chain
, t_addr
) {
500 LIST_REMOVE(addr
, chain
);
508 vpn_control_connected(void)
510 if (LIST_EMPTY(&lcconf
->vpnctl_comm_socks
))