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