]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/vpn_control.c
ipsec-93.13.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / vpn_control.c
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
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
63 #include <System/net/pfkeyv2.h>
64
65 #include <netinet/in.h>
66 #ifndef HAVE_NETINET6_IPSEC
67 #include <netinet/ipsec.h>
68 #else
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
81 #include <launch.h>
82
83 #include "var.h"
84 #include "misc.h"
85 #include "vmbuf.h"
86 #include "plog.h"
87 #include "sockmisc.h"
88 #include "debug.h"
89
90 #include "schedule.h"
91 #include "localconf.h"
92 #include "remoteconf.h"
93 #include "grabmyaddr.h"
94 #include "isakmp_var.h"
95 #include "isakmp.h"
96 #include "oakley.h"
97 #include "handler.h"
98 #include "evt.h"
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"
106
107 #ifdef ENABLE_VPNCONTROL_PORT
108 char *vpncontrolsock_path = VPNCONTROLSOCK_PATH;
109 uid_t vpncontrolsock_owner = 0;
110 gid_t vpncontrolsock_group = 0;
111 mode_t vpncontrolsock_mode = 0600;
112
113 static struct sockaddr_un sunaddr;
114 static int vpncontrol_process(struct vpnctl_socket_elem *, char *);
115 static int vpncontrol_reply(int, char *);
116 static void vpncontrol_close_comm(struct vpnctl_socket_elem *);
117 static int checklaunchd();
118 extern int vpn_get_config __P((struct ph1handle *, struct vpnctl_status_phase_change **, size_t *));
119 extern int vpn_xauth_reply __P((u_int32_t, void *, size_t));
120
121
122 int
123 checklaunchd()
124 {
125 launch_data_t checkin_response = NULL;
126 launch_data_t checkin_request = NULL;
127 launch_data_t sockets_dict, listening_fd_array;
128 launch_data_t listening_fd;
129 struct sockaddr_storage fdsockaddr;
130 socklen_t fdsockaddrlen = sizeof(fdsockaddr);
131 int socketct;
132 int i;
133 int listenerct;
134 int returnval = 0;
135 int fd;
136
137 /* check in with launchd */
138 if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) {
139 plog(LLV_ERROR, LOCATION, NULL,
140 "failed to launch_data_new_string.\n");
141 goto done;
142 }
143 if ((checkin_response = launch_msg(checkin_request)) == NULL) {
144 plog(LLV_ERROR, LOCATION, NULL,
145 "failed to launch_msg.\n");
146 goto done;
147 }
148 if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) {
149 plog(LLV_ERROR, LOCATION, NULL,
150 "launch_data_get_type error %d\n",
151 launch_data_get_errno(checkin_response));
152 goto done;
153 }
154 if ( (sockets_dict = launch_data_dict_lookup(checkin_response, LAUNCH_JOBKEY_SOCKETS)) == NULL){
155 plog(LLV_ERROR, LOCATION, NULL,
156 "failed to launch_data_dict_lookup.\n");
157 goto done;
158 }
159 if ( !(socketct = launch_data_dict_get_count(sockets_dict))){
160 plog(LLV_ERROR, LOCATION, NULL,
161 "launch_data_dict_get_count returns no socket defined.\n");
162 goto done;
163 }
164
165 if ( (listening_fd_array = launch_data_dict_lookup(sockets_dict, "Listeners")) == NULL ){
166 plog(LLV_ERROR, LOCATION, NULL,
167 "failed to launch_data_dict_lookup.\n");
168 goto done;
169 }
170 listenerct = launch_data_array_get_count(listening_fd_array);
171 for (i = 0; i < listenerct; i++) {
172 listening_fd = launch_data_array_get_index(listening_fd_array, i);
173 fd = launch_data_get_fd( listening_fd );
174 if ( getsockname( fd , (struct sockaddr*)&fdsockaddr, &fdsockaddrlen)){
175 continue;
176 }
177
178 /* Is this the VPN control socket? */
179 if ( (((struct sockaddr*)&fdsockaddr)->sa_family) == AF_UNIX &&
180 (!(strcmp(vpncontrolsock_path, ((struct sockaddr_un *)&fdsockaddr)->sun_path))))
181 {
182 plog(LLV_INFO, LOCATION, NULL,
183 "found launchd socket.\n");
184 returnval = fd;
185 break;
186 }
187 }
188 // TODO: check if we have any leaked fd
189 if ( listenerct == i){
190 plog(LLV_ERROR, LOCATION, NULL,
191 "failed to find launchd socket\n");
192 returnval = 0;
193 }
194
195 done:
196 if (checkin_request)
197 launch_data_free(checkin_request);
198 if (checkin_response)
199 launch_data_free(checkin_response);
200 return(returnval);
201 }
202
203
204 int
205 vpncontrol_handler()
206 {
207 struct sockaddr_storage from;
208 socklen_t fromlen = sizeof(from);
209
210 struct vpnctl_socket_elem *sock_elem;
211
212 sock_elem = racoon_malloc(sizeof(struct vpnctl_socket_elem));
213 if (sock_elem == NULL) {
214 plog(LLV_ERROR, LOCATION, NULL,
215 "memory error: %s\n", strerror(errno));
216 return -1;
217 }
218 LIST_INIT(&sock_elem->bound_addresses);
219
220 sock_elem->sock = accept(lcconf->sock_vpncontrol, (struct sockaddr *)&from, &fromlen);
221 if (sock_elem->sock < 0) {
222 plog(LLV_ERROR, LOCATION, NULL,
223 "failed to accept vpn_control command: %s\n", strerror(errno));
224 racoon_free(sock_elem);
225 return -1;
226 }
227 LIST_INSERT_HEAD(&lcconf->vpnctl_comm_socks, sock_elem, chain);
228 plog(LLV_NOTIFY, LOCATION, NULL,
229 "accepted connection on vpn control socket.\n");
230
231 check_auto_exit();
232
233 return 0;
234 }
235
236 int
237 vpncontrol_comm_handler(struct vpnctl_socket_elem *elem)
238 {
239 struct vpnctl_hdr hdr;
240 char *combuf = NULL;
241 int len;
242
243 /* get buffer length */
244 while ((len = recv(elem->sock, (char *)&hdr, sizeof(hdr), MSG_PEEK)) < 0) {
245 if (errno == EINTR)
246 continue;
247 plog(LLV_ERROR, LOCATION, NULL,
248 "failed to recv vpn_control command: %s\n", strerror(errno));
249 goto end;
250 }
251 if (len == 0) {
252 plog(LLV_DEBUG, LOCATION, NULL,
253 "vpn_control socket closed by peer.\n");
254 vpncontrol_close_comm(elem);
255 return -1;
256 }
257
258 /* sanity check */
259 if (len < sizeof(hdr)) {
260 plog(LLV_ERROR, LOCATION, NULL,
261 "invalid header length of vpn_control command - len=%d - expected %d\n", len, sizeof(hdr));
262 goto end;
263 }
264
265 /* get buffer to receive */
266 if ((combuf = racoon_malloc(ntohs(hdr.len) + sizeof(hdr))) == 0) {
267 plog(LLV_ERROR, LOCATION, NULL,
268 "failed to alloc buffer for vpn_control command\n");
269 goto end;
270 }
271
272 /* get real data */
273 while ((len = recv(elem->sock, combuf, ntohs(hdr.len) + sizeof(hdr), 0)) < 0) {
274 if (errno == EINTR)
275 continue;
276 plog(LLV_ERROR, LOCATION, NULL,
277 "failed to recv vpn_control command: %s\n",
278 strerror(errno));
279 goto end;
280 }
281
282 (void)vpncontrol_process(elem, combuf);
283
284 end:
285 if (combuf)
286 racoon_free(combuf);
287 return 0; // return -1 only if a socket is closed
288 }
289
290 static int
291 vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
292 {
293 u_int16_t error = 0;
294 struct vpnctl_hdr *hdr = (struct vpnctl_hdr *)combuf;
295
296 switch (ntohs(hdr->msg_type)) {
297
298 case VPNCTL_CMD_BIND:
299 {
300 struct vpnctl_cmd_bind *pkt = (struct vpnctl_cmd_bind *)combuf;
301 struct bound_addr *addr;
302
303 plog(LLV_DEBUG, LOCATION, NULL,
304 "received bind command on vpn control socket.\n");
305 addr = racoon_calloc(1, sizeof(struct bound_addr));
306 if (addr == NULL) {
307 plog(LLV_ERROR, LOCATION, NULL,
308 "memory error: %s\n", strerror(errno));
309 error = -1;
310 break;
311 }
312 if (ntohs(pkt->vers_len)) {
313 addr->version = vmalloc(ntohs(pkt->vers_len));
314 if (addr->version == NULL) {
315 plog(LLV_ERROR, LOCATION, NULL,
316 "memory error: %s\n", strerror(errno));
317 error = -1;
318 break;
319 }
320 memcpy(addr->version->v, pkt + 1, ntohs(pkt->vers_len));
321 }
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 {
330 struct vpnctl_cmd_unbind *pkt = (struct vpnctl_cmd_unbind *)combuf;
331 struct bound_addr *addr;
332 struct bound_addr *t_addr;
333
334 plog(LLV_DEBUG, LOCATION, NULL,
335 "received unbind command on vpn control socket.\n");
336 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
337 if (pkt->address == 0xFFFFFFFF ||
338 pkt->address == addr->address) {
339 flushsainfo_dynamic(addr->address);
340 LIST_REMOVE(addr, chain);
341 if (addr->version)
342 vfree(addr->version);
343 racoon_free(addr);
344 }
345 }
346 }
347 break;
348
349 case VPNCTL_CMD_REDIRECT:
350 {
351 struct vpnctl_cmd_redirect *redirect_msg = (struct vpnctl_cmd_redirect *)combuf;
352 struct redirect *raddr;
353 struct redirect *t_raddr;
354 int found = 0;
355
356 plog(LLV_DEBUG, LOCATION, NULL,
357 "received redirect command on vpn control socket - address = %x.\n", ntohl(redirect_msg->redirect_address));
358
359 LIST_FOREACH_SAFE(raddr, &lcconf->redirect_addresses, chain, t_raddr) {
360 if (raddr->cluster_address == redirect_msg->address) {
361 if (redirect_msg->redirect_address == 0) {
362 LIST_REMOVE(raddr, chain);
363 racoon_free(raddr);
364 } else {
365 raddr->redirect_address = redirect_msg->redirect_address;
366 raddr->force = ntohs(redirect_msg->force);
367 }
368 found = 1;
369 break;
370 }
371 }
372 if (!found) {
373 raddr = racoon_malloc(sizeof(struct redirect));
374 if (raddr == NULL) {
375 plog(LLV_DEBUG, LOCATION, NULL,
376 "cannot allcoate memory for redirect address.\n");
377 error = -1;
378 break;
379 }
380 raddr->cluster_address = redirect_msg->address;
381 raddr->redirect_address = redirect_msg->redirect_address;
382 raddr->force = ntohs(redirect_msg->force);
383 LIST_INSERT_HEAD(&lcconf->redirect_addresses, raddr, chain);
384
385 }
386 }
387 break;
388
389 case VPNCTL_CMD_PING:
390 break; /* just reply for now */
391
392 case VPNCTL_CMD_XAUTH_INFO:
393 {
394 struct vpnctl_cmd_xauth_info *pkt = (struct vpnctl_cmd_xauth_info *)combuf;
395 struct bound_addr *addr;
396 struct bound_addr *t_addr;
397 void *attr_list;
398
399 plog(LLV_DEBUG, LOCATION, NULL,
400 "received xauth info command vpn control socket.\n");
401 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
402 if (pkt->address == addr->address) {
403 /* reply to the last xauth request */
404 attr_list = pkt + 1;
405 error = vpn_xauth_reply(pkt->address, attr_list, ntohs(pkt->hdr.len) - sizeof(u_int32_t));
406 break;
407 }
408 }
409 }
410 break;
411
412 case VPNCTL_CMD_CONNECT:
413 {
414 struct vpnctl_cmd_connect *pkt = (struct vpnctl_cmd_connect *)combuf;
415 struct bound_addr *addr;
416 struct bound_addr *t_addr;
417
418 plog(LLV_DEBUG, LOCATION, NULL,
419 "received connect command on vpn control socket.\n");
420 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
421 if (pkt->address == addr->address) {
422 /* start the connection */
423 error = vpn_connect(addr);
424 break;
425 }
426 }
427 }
428 break;
429
430 case VPNCTL_CMD_DISCONNECT:
431 {
432 struct vpnctl_cmd_connect *pkt = (struct vpnctl_cmd_connect *)combuf;
433 struct bound_addr *addr;
434 struct bound_addr *t_addr;
435
436 plog(LLV_DEBUG, LOCATION, NULL,
437 "received disconnect command on vpn control socket.\n");
438 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
439 if (pkt->address == addr->address) {
440 /* stop the connection */
441 error = vpn_disconnect(addr);
442 break;
443 }
444 }
445 }
446 break;
447
448 case VPNCTL_CMD_START_PH2:
449 {
450 struct vpnctl_cmd_start_ph2 *pkt = (struct vpnctl_cmd_start_ph2 *)combuf;
451 struct bound_addr *addr;
452 struct bound_addr *t_addr;
453
454 plog(LLV_DEBUG, LOCATION, NULL,
455 "received start_ph2 command on vpn control socket.\n");
456 plogdump(LLV_DEBUG2, pkt, ntohs(hdr->len) + sizeof(struct vpnctl_hdr));
457 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
458 if (pkt->address == addr->address) {
459 /* start the connection */
460 error = vpn_start_ph2(addr, pkt);
461 break;
462 }
463 }
464 }
465 break;
466
467 case VPNCTL_CMD_START_DPD:
468 {
469 struct vpnctl_cmd_start_dpd *pkt = (struct vpnctl_cmd_start_dpd *)combuf;
470 struct bound_addr *srv;
471 struct bound_addr *t_addr;
472
473 plog(LLV_DEBUG, LOCATION, NULL,
474 "received start_dpd command on vpn control socket.\n");
475 LIST_FOREACH_SAFE(srv, &elem->bound_addresses, chain, t_addr) {
476 if (pkt->address == srv->address) {
477 struct sockaddr_in daddr;
478
479 bzero(&daddr, sizeof(daddr));
480 daddr.sin_len = sizeof(daddr);
481 daddr.sin_addr.s_addr = srv->address;
482 daddr.sin_port = 0;
483 daddr.sin_family = AF_INET;
484
485 /* start the dpd */
486 error = ph1_force_dpd(&daddr);
487 break;
488 }
489 }
490 }
491 break;
492
493 default:
494 plog(LLV_ERROR, LOCATION, NULL,
495 "invalid command: %d\n", ntohs(hdr->msg_type));
496 error = -1; // for now
497 break;
498 }
499
500 hdr->len = 0;
501 hdr->result = htons(error);
502 if (vpncontrol_reply(elem->sock, combuf) < 0)
503 return -1;
504
505 return 0;
506
507 }
508
509 static int
510 vpncontrol_reply(int so, char *combuf)
511 {
512 size_t tlen;
513
514 tlen = send(so, combuf, sizeof(struct vpnctl_hdr), 0);
515 if (tlen < 0) {
516 plog(LLV_ERROR, LOCATION, NULL,
517 "failed to send vpn_control message: %s\n", strerror(errno));
518 return -1;
519 }
520
521 return 0;
522 }
523
524 int
525 vpncontrol_notify_need_authinfo(struct ph1handle *iph1, void* attr_list, size_t attr_len)
526 {
527 struct vpnctl_status_need_authinfo *msg = NULL;
528 struct vpnctl_socket_elem *sock_elem;
529 struct bound_addr *bound_addr;
530 size_t tlen, msg_size;
531 u_int32_t address;
532 void *ptr;
533
534 if (!iph1)
535 goto end;
536
537 plog(LLV_DEBUG, LOCATION, NULL,
538 "sending vpn_control xauth need info status\n");
539
540 msg = (struct vpnctl_status_need_authinfo *)racoon_malloc(msg_size = sizeof(struct vpnctl_status_need_authinfo) + attr_len);
541 if (msg == NULL) {
542 plog(LLV_ERROR, LOCATION, NULL,
543 "unable to allocate space for vpn control message.\n");
544 return -1;
545 }
546 msg->hdr.flags = 0;
547
548 if (iph1->remote->sa_family == AF_INET)
549 address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
550 else
551 goto end; // for now
552
553 msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
554 msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));
555 if (!ike_session_is_client_ph1_rekey(iph1)) {
556 msg->hdr.msg_type = htons(VPNCTL_STATUS_NEED_AUTHINFO);
557 } else {
558 msg->hdr.msg_type = htons(VPNCTL_STATUS_NEED_REAUTHINFO);
559 }
560 msg->address = address;
561 ptr = msg + 1;
562 memcpy(ptr, attr_list, attr_len);
563
564 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
565 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
566 if (bound_addr->address == 0xFFFFFFFF ||
567 bound_addr->address == address) {
568 plog(LLV_DEBUG, LOCATION, NULL,
569 "vpn control writing %d bytes\n", msg_size);
570 plogdump(LLV_DEBUG, msg, msg_size);
571 tlen = send(sock_elem->sock, msg, msg_size, 0);
572 if (tlen < 0) {
573 plog(LLV_ERROR, LOCATION, NULL,
574 "failed to send vpn_control need authinfo status: %s\n", strerror(errno));
575 }
576 break;
577 }
578 }
579 }
580
581 end:
582 if (msg)
583 racoon_free(msg);
584 return 0;
585 }
586
587 int
588 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)
589 {
590 struct vpnctl_status_failed *msg = NULL;
591 struct vpnctl_socket_elem *sock_elem;
592 struct bound_addr *bound_addr;
593 size_t tlen, len;
594
595 len = sizeof(struct vpnctl_status_failed) + data_len;
596
597 msg = (struct vpnctl_status_failed *)racoon_malloc(len);
598 if (msg == NULL) {
599 plog(LLV_DEBUG, LOCATION, NULL,
600 "unable to allcate memory for vpn control status message.\n");
601 return -1;
602 }
603
604 msg->hdr.msg_type = htons(VPNCTL_STATUS_IKE_FAILED);
605 msg->hdr.flags = msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
606 msg->hdr.len = htons(len - sizeof(struct vpnctl_hdr));
607 msg->address = address;
608 msg->ike_code = htons(notify_code);
609 msg->from = htons(from);
610 if (data_len > 0)
611 memcpy(msg->data, data, data_len);
612 plog(LLV_DEBUG, LOCATION, NULL,
613 "sending vpn_control ike failed message - code=%d from=%s.\n", notify_code,
614 (from == FROM_LOCAL ? "local" : "remote"));
615
616 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
617 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
618 if (bound_addr->address == 0xFFFFFFFF ||
619 bound_addr->address == address) {
620 tlen = send(sock_elem->sock, msg, len, 0);
621 if (tlen < 0) {
622 plog(LLV_ERROR, LOCATION, NULL,
623 "unable to send vpn_control ike notify failed: %s\n", strerror(errno));
624 }
625 break;
626 }
627 }
628 }
629
630 if (msg)
631 racoon_free(msg);
632 return 0;
633 }
634
635
636 int
637 vpncontrol_notify_phase_change(int start, u_int16_t from, struct ph1handle *iph1, struct ph2handle *iph2)
638 {
639 struct vpnctl_status_phase_change *msg;
640 struct vpnctl_socket_elem *sock_elem;
641 struct bound_addr *bound_addr;
642 size_t tlen, msg_size;
643 u_int32_t address;
644
645 plog(LLV_DEBUG, LOCATION, NULL,
646 "sending vpn_control phase change status\n");
647
648 if (iph1 && !start && iph1->mode_cfg) {
649 if (vpn_get_config(iph1, &msg, &msg_size) == 1)
650 return 0; /* mode config not finished yet */
651 } else {
652 msg = racoon_malloc(msg_size = sizeof(struct vpnctl_status_phase_change));
653 msg->hdr.flags = 0;
654 }
655
656 if (msg == NULL) {
657 plog(LLV_ERROR, LOCATION, NULL,
658 "unable to allocate space for vpn control message.\n");
659 return -1;
660 }
661 if (iph1) {
662 if (iph1->remote->sa_family == AF_INET)
663 address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
664 else
665 goto end; // for now
666 msg->hdr.msg_type = htons(start ?
667 (from == FROM_LOCAL ? VPNCTL_STATUS_PH1_START_US : VPNCTL_STATUS_PH1_START_PEER)
668 : VPNCTL_STATUS_PH1_ESTABLISHED);
669 } else {
670 if (iph2->dst->sa_family == AF_INET)
671 address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
672 else
673 goto end; // for now
674 msg->hdr.msg_type = htons(start ? VPNCTL_STATUS_PH2_START : VPNCTL_STATUS_PH2_ESTABLISHED);
675 }
676 msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
677 msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));
678 msg->address = address;
679
680 LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
681 LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
682 if (bound_addr->address == 0xFFFFFFFF ||
683 bound_addr->address == address) {
684 plog(LLV_DEBUG, LOCATION, NULL,
685 "vpn control writing %d bytes\n", msg_size);
686 plogdump(LLV_DEBUG, msg, msg_size);
687 tlen = send(sock_elem->sock, msg, msg_size, 0);
688 if (tlen < 0) {
689 plog(LLV_ERROR, LOCATION, NULL,
690 "failed to send vpn_control phase change status: %s\n", strerror(errno));
691 }
692 break;
693 }
694 }
695 }
696
697 end:
698 if (msg)
699 racoon_free(msg);
700 return 0;
701 }
702
703
704 int
705 vpncontrol_init()
706 {
707 if (vpncontrolsock_path == NULL) {
708 lcconf->sock_vpncontrol = -1;
709 return 0;
710 }
711
712 if ( (lcconf->sock_vpncontrol = checklaunchd()) ){
713 return 0;
714 }
715 else {
716
717 memset(&sunaddr, 0, sizeof(sunaddr));
718 sunaddr.sun_family = AF_UNIX;
719 snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
720 "%s", vpncontrolsock_path);
721
722 lcconf->sock_vpncontrol = socket(AF_UNIX, SOCK_STREAM, 0);
723 if (lcconf->sock_vpncontrol == -1) {
724 plog(LLV_ERROR, LOCATION, NULL,
725 "socket: %s\n", strerror(errno));
726 return -1;
727 }
728
729 unlink(sunaddr.sun_path);
730 if (bind(lcconf->sock_vpncontrol, (struct sockaddr *)&sunaddr,
731 sizeof(sunaddr)) != 0) {
732 plog(LLV_ERROR, LOCATION, NULL,
733 "bind(sockname:%s): %s\n",
734 sunaddr.sun_path, strerror(errno));
735 (void)close(lcconf->sock_vpncontrol);
736 return -1;
737 }
738
739 if (chown(sunaddr.sun_path, vpncontrolsock_owner, vpncontrolsock_group) != 0) {
740 plog(LLV_ERROR, LOCATION, NULL,
741 "chown(%s, %d, %d): %s\n",
742 sunaddr.sun_path, vpncontrolsock_owner,
743 vpncontrolsock_group, strerror(errno));
744 (void)close(lcconf->sock_vpncontrol);
745 return -1;
746 }
747
748 if (chmod(sunaddr.sun_path, vpncontrolsock_mode) != 0) {
749 plog(LLV_ERROR, LOCATION, NULL,
750 "chmod(%s, 0%03o): %s\n",
751 sunaddr.sun_path, vpncontrolsock_mode, strerror(errno));
752 (void)close(lcconf->sock_vpncontrol);
753 return -1;
754 }
755
756 if (listen(lcconf->sock_vpncontrol, 5) != 0) {
757 plog(LLV_ERROR, LOCATION, NULL,
758 "listen(sockname:%s): %s\n",
759 sunaddr.sun_path, strerror(errno));
760 (void)close(lcconf->sock_vpncontrol);
761 return -1;
762 }
763 plog(LLV_DEBUG, LOCATION, NULL,
764 "opened %s as racoon management.\n", sunaddr.sun_path);
765
766 return 0;
767 }
768 }
769
770
771 void
772 vpncontrol_close()
773 {
774 struct vpnctl_socket_elem *elem;
775 struct vpnctl_socket_elem *t_elem;
776
777 plog(LLV_DEBUG, LOCATION, NULL,
778 "vpncontrol_close.\n");
779
780 if (lcconf->sock_vpncontrol != -1) {
781 close(lcconf->sock_vpncontrol);
782 lcconf->sock_vpncontrol = -1;
783 }
784 LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem)
785 vpncontrol_close_comm(elem);
786
787 }
788
789 static void
790 vpncontrol_close_comm(struct vpnctl_socket_elem *elem)
791 {
792 struct bound_addr *addr;
793 struct bound_addr *t_addr;
794
795 plog(LLV_DEBUG, LOCATION, NULL,
796 "vpncontrol_close_comm.\n");
797
798 LIST_REMOVE(elem, chain);
799 if (elem->sock != -1)
800 close(elem->sock);
801 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
802 flushsainfo_dynamic(addr->address);
803 LIST_REMOVE(addr, chain);
804 if (addr->version)
805 vfree(addr->version);
806 racoon_free(addr);
807 }
808 racoon_free(elem);
809 check_auto_exit();
810 }
811
812 int
813 vpn_control_connected(void)
814 {
815 if (LIST_EMPTY(&lcconf->vpnctl_comm_socks))
816 return 0;
817 else
818 return 1;
819 }
820
821 #endif