]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/vpn_control.c
ipsec-34.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
82 #include "var.h"
83 #include "misc.h"
84 #include "vmbuf.h"
85 #include "plog.h"
86 #include "sockmisc.h"
87 #include "debug.h"
88
89 #include "schedule.h"
90 #include "localconf.h"
91 #include "remoteconf.h"
92 #include "grabmyaddr.h"
93 #include "isakmp_var.h"
94 #include "isakmp.h"
95 #include "oakley.h"
96 #include "handler.h"
97 #include "evt.h"
98 #include "pfkey.h"
99 #include "ipsec_doi.h"
100 #include "vpn_control.h"
101 #include "vpn_control_var.h"
102 #include "isakmp_inf.h"
103 #include "session.h"
104 #include "gcmalloc.h"
105
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;
111
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 *);
116
117 int
118 vpncontrol_handler()
119 {
120 struct sockaddr_storage from;
121 socklen_t fromlen = sizeof(from);
122
123 struct vpnctl_socket_elem *sock_elem;
124
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));
129 return -1;
130 }
131 LIST_INIT(&sock_elem->bound_addresses);
132
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);
138 return -1;
139 }
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");
143
144 check_auto_exit();
145
146 return 0;
147 }
148
149 int
150 vpncontrol_comm_handler(struct vpnctl_socket_elem *elem)
151 {
152 struct vpnctl_hdr hdr;
153 char *combuf = NULL;
154 int len;
155
156 /* get buffer length */
157 while ((len = recv(elem->sock, (char *)&hdr, sizeof(hdr), MSG_PEEK)) < 0) {
158 if (errno == EINTR)
159 continue;
160 plog(LLV_ERROR, LOCATION, NULL,
161 "failed to recv vpn_control command: %s\n", strerror(errno));
162 goto end;
163 }
164 if (len == 0) {
165 plog(LLV_NOTIFY, LOCATION, NULL,
166 "vpn_control socket closed by peer.\n");
167 vpncontrol_close_comm(elem);
168 return -1;
169 }
170
171 /* sanity check */
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));
175 goto end;
176 }
177
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");
182 goto end;
183 }
184
185 /* get real data */
186 while ((len = recv(elem->sock, combuf, ntohs(hdr.len) + sizeof(hdr), 0)) < 0) {
187 if (errno == EINTR)
188 continue;
189 plog(LLV_ERROR, LOCATION, NULL,
190 "failed to recv vpn_control command: %s\n",
191 strerror(errno));
192 goto end;
193 }
194
195 (void)vpncontrol_process(elem, combuf);
196
197 end:
198 if (combuf)
199 racoon_free(combuf);
200 return 0; // return -1 only if a socket is closed
201 }
202
203 static int
204 vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
205 {
206 u_int16_t error = 0;
207 struct vpnctl_hdr *hdr = (struct vpnctl_hdr *)combuf;
208
209 switch (ntohs(hdr->msg_type)) {
210
211 case VPNCTL_CMD_BIND:
212 {
213 struct vpnctl_cmd_bind *pkt = (struct vpnctl_cmd_bind *)combuf;
214 struct bound_addr *addr;
215
216 plog(LLV_DEBUG, LOCATION, NULL,
217 "received bind command on vpn control socket.\n");
218 addr = racoon_malloc(sizeof(struct bound_addr));
219 if (addr == NULL) {
220 plog(LLV_ERROR, LOCATION, NULL,
221 "memory error: %s\n", strerror(errno));
222 error = -1;
223 break;
224 }
225 addr->address = pkt->address;
226 LIST_INSERT_HEAD(&elem->bound_addresses, addr, chain);
227 lcconf->auto_exit_state |= LC_AUTOEXITSTATE_CLIENT; /* client side */
228 }
229 break;
230
231 case VPNCTL_CMD_UNBIND:
232 {
233 struct vpnctl_cmd_unbind *pkt = (struct vpnctl_cmd_unbind *)combuf;
234 struct bound_addr *addr;
235 struct bound_addr *t_addr;
236
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);
243 racoon_free(addr);
244 }
245 }
246 }
247 break;
248
249 case VPNCTL_CMD_REDIRECT:
250 {
251 struct vpnctl_cmd_redirect *redirect_msg = (struct vpnctl_cmd_redirect *)combuf;
252 struct redirect *raddr;
253 struct redirect *t_raddr;
254 int found = 0;
255
256 plog(LLV_DEBUG, LOCATION, NULL,
257 "received redirect command on vpn control socket - address = %x.\n", ntohl(redirect_msg->redirect_address));
258
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);
263 racoon_free(raddr);
264 } else {
265 raddr->redirect_address = redirect_msg->redirect_address;
266 raddr->force = ntohs(redirect_msg->force);
267 }
268 found = 1;
269 break;
270 }
271 }
272 if (!found) {
273 raddr = racoon_malloc(sizeof(struct redirect));
274 if (raddr == NULL) {
275 plog(LLV_DEBUG, LOCATION, NULL,
276 "cannot allcoate memory for redirect address.\n");
277 error = -1;
278 break;
279 }
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);
284
285 }
286 }
287 break;
288
289 case VPNCTL_CMD_PING:
290 break; // just reply for now
291
292 default:
293 plog(LLV_ERROR, LOCATION, NULL,
294 "invalid command: %d\n", ntohs(hdr->msg_type));
295 error = -1; // for now
296 break;
297 }
298
299 hdr->len = 0;
300 hdr->result = htons(error);
301 if (vpncontrol_reply(elem->sock, combuf) < 0)
302 return -1;
303
304 return 0;
305
306 }
307
308 static int
309 vpncontrol_reply(int so, char *combuf)
310 {
311 size_t tlen;
312
313 tlen = send(so, combuf, sizeof(struct vpnctl_hdr), 0);
314 if (tlen < 0) {
315 plog(LLV_ERROR, LOCATION, NULL,
316 "failed to send vpn_control message: %s\n", strerror(errno));
317 return -1;
318 }
319
320 return 0;
321 }
322
323 int
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)
325 {
326 struct vpnctl_status_failed *msg;
327 struct vpnctl_socket_elem *sock_elem;
328 struct bound_addr *bound_addr;
329 size_t tlen, len;
330
331 len = sizeof(struct vpnctl_status_failed) + data_len;
332
333 msg = (struct vpnctl_status_failed *)racoon_malloc(len);
334 if (msg == NULL) {
335 plog(LLV_DEBUG, LOCATION, NULL,
336 "unable to allcate memory for vpn control status message.\n");
337 return -1;
338 }
339
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);
346 if (data_len > 0)
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"));
351
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);
357 if (tlen < 0) {
358 plog(LLV_ERROR, LOCATION, NULL,
359 "unable to send vpn_control ike notify failed: %s\n", strerror(errno));
360 }
361 break;
362 }
363 }
364 }
365 return 0;
366 }
367
368
369 int
370 vpncontrol_notify_phase_change(int start, u_int16_t from, struct ph1handle *iph1, struct ph2handle *iph2)
371 {
372 struct vpnctl_status_phase_change msg;
373 struct vpnctl_socket_elem *sock_elem;
374 struct bound_addr *bound_addr;
375 size_t tlen;
376 u_int32_t address;
377
378 if (iph1) {
379 if (iph1->remote->sa_family == AF_INET)
380 address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
381 else
382 return 0; // for now
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);
386 } else {
387 if (iph2->dst->sa_family == AF_INET)
388 address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
389 else
390 return 0; // for now
391 msg.hdr.msg_type = htons(start ? VPNCTL_STATUS_PH2_START : VPNCTL_STATUS_PH2_ESTABLISHED);
392 }
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;
396
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);
402 if (tlen < 0) {
403 plog(LLV_ERROR, LOCATION, NULL,
404 "failed to send vpn_control phase change status: %s\n", strerror(errno));
405 }
406 break;
407 }
408 }
409 }
410
411 return 0;
412 }
413
414
415 int
416 vpncontrol_init()
417 {
418 if (vpncontrolsock_path == NULL) {
419 lcconf->sock_vpncontrol = -1;
420 return 0;
421 }
422
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);
427
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));
432 return -1;
433 }
434
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);
442 return -1;
443 }
444
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);
451 return -1;
452 }
453
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);
459 return -1;
460 }
461
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);
467 return -1;
468 }
469 plog(LLV_DEBUG, LOCATION, NULL,
470 "opened %s as racoon management.\n", sunaddr.sun_path);
471
472 return 0;
473 }
474
475
476 void
477 vpncontrol_close()
478 {
479 struct vpnctl_socket_elem *elem;
480 struct vpnctl_socket_elem *t_elem;
481
482 if (lcconf->sock_vpncontrol != -1) {
483 close(lcconf->sock_vpncontrol);
484 lcconf->sock_vpncontrol = -1;
485 }
486 LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem)
487 vpncontrol_close_comm(elem);
488 }
489
490 static void
491 vpncontrol_close_comm(struct vpnctl_socket_elem *elem)
492 {
493 struct bound_addr *addr;
494 struct bound_addr *t_addr;
495
496 LIST_REMOVE(elem, chain);
497 if (elem->sock != -1)
498 close(elem->sock);
499 LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
500 LIST_REMOVE(addr, chain);
501 racoon_free(addr);
502 }
503 racoon_free(elem);
504 check_auto_exit();
505 }
506
507 int
508 vpn_control_connected(void)
509 {
510 if (LIST_EMPTY(&lcconf->vpnctl_comm_socks))
511 return 0;
512 else
513 return 1;
514 }
515
516 #endif