No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / ipsec-tools / src / racoon / grabmyaddr.c
blob48f6eb43037be811ba33d8ff4663373aecca0cac
1 /* $NetBSD: grabmyaddr.c,v 1.22 2009/04/21 18:38:31 tteras Exp $ */
2 /*
3 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
4 * Copyright (C) 2008 Timo Teras <timo.teras@iki.fi>.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include "config.h"
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
42 #ifdef __linux__
43 #include <linux/netlink.h>
44 #include <linux/rtnetlink.h>
45 #define USE_NETLINK
46 #else
47 #include <net/route.h>
48 #include <net/if.h>
49 #include <net/if_dl.h>
50 #include <sys/sysctl.h>
51 #define USE_ROUTE
52 #endif
54 #include "var.h"
55 #include "misc.h"
56 #include "vmbuf.h"
57 #include "plog.h"
58 #include "sockmisc.h"
59 #include "session.h"
60 #include "debug.h"
62 #include "localconf.h"
63 #include "handler.h"
64 #include "grabmyaddr.h"
65 #include "sockmisc.h"
66 #include "isakmp_var.h"
67 #include "gcmalloc.h"
68 #include "nattraversal.h"
70 static int kernel_receive __P((void *ctx, int fd));
71 static int kernel_open_socket __P((void));
72 static void kernel_sync __P((void));
74 struct myaddr {
75 LIST_ENTRY(myaddr) chain;
76 struct sockaddr_storage addr;
77 int fd;
78 int udp_encap;
81 static LIST_HEAD(_myaddr_list_, myaddr) configured, opened;
83 static void
84 myaddr_delete(my)
85 struct myaddr *my;
87 if (my->fd != -1)
88 isakmp_close(my->fd);
89 LIST_REMOVE(my, chain);
90 racoon_free(my);
93 static int
94 myaddr_configured(addr)
95 struct sockaddr *addr;
97 struct myaddr *cfg;
99 if (LIST_EMPTY(&configured))
100 return TRUE;
102 LIST_FOREACH(cfg, &configured, chain) {
103 if (cmpsaddr(addr, (struct sockaddr *) &cfg->addr) == 0)
104 return TRUE;
107 return FALSE;
110 static int
111 myaddr_open(addr, udp_encap)
112 struct sockaddr *addr;
113 int udp_encap;
115 struct myaddr *my;
117 /* Already open? */
118 LIST_FOREACH(my, &opened, chain) {
119 if (cmpsaddr(addr, (struct sockaddr *) &my->addr) == 0)
120 return TRUE;
123 my = racoon_calloc(1, sizeof(struct myaddr));
124 if (my == NULL)
125 return FALSE;
127 memcpy(&my->addr, addr, sysdep_sa_len(addr));
128 my->fd = isakmp_open(addr, udp_encap);
129 if (my->fd < 0) {
130 racoon_free(my);
131 return FALSE;
133 my->udp_encap = udp_encap;
134 LIST_INSERT_HEAD(&opened, my, chain);
135 return TRUE;
138 static int
139 myaddr_open_all_configured(addr)
140 struct sockaddr *addr;
142 /* create all configured, not already opened addresses */
143 struct myaddr *cfg, *my;
145 if (addr != NULL) {
146 switch (addr->sa_family) {
147 case AF_INET:
148 #ifdef INET6
149 case AF_INET6:
150 #endif
151 break;
152 default:
153 return FALSE;
157 LIST_FOREACH(cfg, &configured, chain) {
158 if (addr != NULL &&
159 cmpsaddr(addr, (struct sockaddr *) &cfg->addr) != 0)
160 continue;
161 if (!myaddr_open((struct sockaddr *) &cfg->addr, cfg->udp_encap))
162 return FALSE;
164 if (LIST_EMPTY(&configured)) {
165 #ifdef ENABLE_HYBRID
166 /* Exclude any address we got through ISAKMP mode config */
167 if (exclude_cfg_addr(addr) == 0)
168 return FALSE;
169 #endif
170 set_port(addr, lcconf->port_isakmp);
171 myaddr_open(addr, FALSE);
172 #ifdef ENABLE_NATT
173 set_port(addr, lcconf->port_isakmp_natt);
174 myaddr_open(addr, TRUE);
175 #endif
177 return TRUE;
180 static void
181 myaddr_close_all_open(addr)
182 struct sockaddr *addr;
184 /* delete all matching open sockets */
185 struct myaddr *my, *next;
187 for (my = LIST_FIRST(&opened); my; my = next) {
188 next = LIST_NEXT(my, chain);
190 if (!cmpsaddr((struct sockaddr *) &addr,
191 (struct sockaddr *) &my->addr))
192 myaddr_delete(my);
196 static void
197 myaddr_flush_list(list)
198 struct _myaddr_list_ *list;
200 struct myaddr *my, *next;
202 for (my = LIST_FIRST(list); my; my = next) {
203 next = LIST_NEXT(my, chain);
204 myaddr_delete(my);
208 void
209 myaddr_flush()
211 myaddr_flush_list(&configured);
215 myaddr_listen(addr, udp_encap)
216 struct sockaddr *addr;
217 int udp_encap;
219 struct myaddr *my;
221 if (sysdep_sa_len(addr) > sizeof(my->addr)) {
222 plog(LLV_ERROR, LOCATION, NULL,
223 "sockaddr size larger than sockaddr_storage\n");
224 return -1;
227 my = racoon_calloc(1, sizeof(struct myaddr));
228 if (my == NULL)
229 return -1;
231 memcpy(&my->addr, addr, sysdep_sa_len(addr));
232 my->udp_encap = udp_encap;
233 my->fd = -1;
234 LIST_INSERT_HEAD(&configured, my, chain);
236 return 0;
239 void
240 myaddr_sync()
242 struct myaddr *my, *next;
244 if (!lcconf->strict_address) {
245 kernel_sync();
247 /* delete all existing listeners which are not configured */
248 for (my = LIST_FIRST(&opened); my; my = next) {
249 next = LIST_NEXT(my, chain);
251 if (!myaddr_configured((struct sockaddr *) &my->addr))
252 myaddr_delete(my);
258 myaddr_getfd(addr)
259 struct sockaddr *addr;
261 struct myaddr *my;
263 LIST_FOREACH(my, &opened, chain) {
264 if (cmpsaddr((struct sockaddr *) &my->addr, addr) == 0)
265 return my->fd;
268 return -1;
272 myaddr_getsport(addr)
273 struct sockaddr *addr;
275 struct myaddr *my;
277 LIST_FOREACH(my, &opened, chain) {
278 if (cmpsaddr((struct sockaddr *) &my->addr, addr) == 0)
279 return extract_port((struct sockaddr *) &my->addr);
282 return PORT_ISAKMP;
285 void
286 myaddr_init_lists()
288 LIST_INIT(&configured);
289 LIST_INIT(&opened);
293 myaddr_init()
295 if (!lcconf->strict_address) {
296 lcconf->rtsock = kernel_open_socket();
297 if (lcconf->rtsock < 0)
298 return -1;
299 monitor_fd(lcconf->rtsock, kernel_receive, NULL);
300 } else {
301 lcconf->rtsock = -1;
302 if (!myaddr_open_all_configured(NULL))
303 return -1;
305 return 0;
308 void
309 myaddr_close()
311 myaddr_flush_list(&configured);
312 myaddr_flush_list(&opened);
313 if (lcconf->rtsock != -1) {
314 unmonitor_fd(lcconf->rtsock);
315 close(lcconf->rtsock);
319 #if defined(USE_NETLINK)
321 static void
322 parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
324 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
325 while (RTA_OK(rta, len)) {
326 if (rta->rta_type <= max)
327 tb[rta->rta_type] = rta;
328 rta = RTA_NEXT(rta,len);
332 static int
333 netlink_enumerate(fd, family, type)
334 int fd;
335 int family;
336 int type;
338 struct {
339 struct nlmsghdr nlh;
340 struct rtgenmsg g;
341 } req;
342 struct sockaddr_nl addr;
343 static __u32 seq = 0;
345 memset(&addr, 0, sizeof(addr));
346 addr.nl_family = AF_NETLINK;
348 memset(&req, 0, sizeof(req));
349 req.nlh.nlmsg_len = sizeof(req);
350 req.nlh.nlmsg_type = type;
351 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
352 req.nlh.nlmsg_pid = 0;
353 req.nlh.nlmsg_seq = ++seq;
354 req.g.rtgen_family = family;
356 return sendto(fd, (void *) &req, sizeof(req), 0,
357 (struct sockaddr *) &addr, sizeof(addr)) >= 0;
360 static int
361 netlink_process(struct nlmsghdr *h)
363 struct sockaddr_storage addr;
364 struct ifaddrmsg *ifa;
365 struct rtattr *rta[IFA_MAX+1];
366 struct sockaddr_in *sin;
367 #ifdef INET6
368 struct sockaddr_in6 *sin6;
369 #endif
371 /* is this message interesting? */
372 if (h->nlmsg_type != RTM_NEWADDR &&
373 h->nlmsg_type != RTM_DELADDR)
374 return 0;
376 ifa = NLMSG_DATA(h);
377 parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h));
379 if (ifa->ifa_flags & IFA_F_TENTATIVE)
380 return 0;
382 if (rta[IFA_LOCAL] == NULL)
383 rta[IFA_LOCAL] = rta[IFA_ADDRESS];
384 if (rta[IFA_LOCAL] == NULL)
385 return 0;
387 /* setup the socket address */
388 memset(&addr, 0, sizeof(addr));
389 addr.ss_family = ifa->ifa_family;
390 switch (ifa->ifa_family) {
391 case AF_INET:
392 sin = (struct sockaddr_in *) &addr;
393 memcpy(&sin->sin_addr, RTA_DATA(rta[IFA_LOCAL]),
394 sizeof(sin->sin_addr));
395 break;
396 #ifdef INET6
397 case AF_INET6:
398 sin6 = (struct sockaddr_in6 *) &addr;
399 memcpy(&sin6->sin6_addr, RTA_DATA(rta[IFA_LOCAL]),
400 sizeof(sin6->sin6_addr));
401 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
402 sin6->sin6_scope_id = ifa->ifa_index;
403 break;
404 #endif
405 default:
406 return 0;
409 plog(LLV_DEBUG, LOCATION, NULL,
410 "Netlink: address %s %s\n",
411 saddrwop2str((struct sockaddr *) &addr),
412 h->nlmsg_type == RTM_NEWADDR ? "added" : "deleted");
414 if (h->nlmsg_type == RTM_NEWADDR)
415 myaddr_open_all_configured((struct sockaddr *) &addr);
416 else
417 myaddr_close_all_open((struct sockaddr *) &addr);
419 return 0;
422 static int
423 kernel_receive(ctx, fd)
424 void *ctx;
425 int fd;
427 struct sockaddr_nl nladdr;
428 struct iovec iov;
429 struct msghdr msg = {
430 .msg_name = &nladdr,
431 .msg_namelen = sizeof(nladdr),
432 .msg_iov = &iov,
433 .msg_iovlen = 1,
435 struct nlmsghdr *h;
436 int len, status;
437 char buf[16*1024];
439 iov.iov_base = buf;
440 while (1) {
441 iov.iov_len = sizeof(buf);
442 status = recvmsg(fd, &msg, MSG_DONTWAIT);
443 if (status < 0) {
444 if (errno == EINTR)
445 continue;
446 if (errno == EAGAIN)
447 return FALSE;
448 continue;
450 if (status == 0)
451 return FALSE;
453 h = (struct nlmsghdr *) buf;
454 while (NLMSG_OK(h, status)) {
455 netlink_process(h);
456 h = NLMSG_NEXT(h, status);
460 return TRUE;
463 static int
464 kernel_open_socket()
466 struct sockaddr_nl nl;
467 int fd;
469 fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
470 if (fd < 0) {
471 plog(LLV_ERROR, LOCATION, NULL,
472 "socket(PF_NETLINK) failed: %s",
473 strerror(errno));
474 return -1;
476 close_on_exec(fd);
477 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
478 plog(LLV_WARNING, LOCATION, NULL,
479 "failed to put socket in non-blocking mode\n");
481 memset(&nl, 0, sizeof(nl));
482 nl.nl_family = AF_NETLINK;
483 nl.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
484 if (bind(fd, (struct sockaddr*) &nl, sizeof(nl)) < 0) {
485 plog(LLV_ERROR, LOCATION, NULL,
486 "bind(PF_NETLINK) failed: %s\n",
487 strerror(errno));
488 close(fd);
489 return -1;
491 return fd;
494 static void
495 kernel_sync()
497 int fd = lcconf->rtsock;
499 /* refresh addresses */
500 if (!netlink_enumerate(fd, PF_UNSPEC, RTM_GETADDR)) {
501 plog(LLV_ERROR, LOCATION, NULL,
502 "unable to enumerate addresses: %s\n",
503 strerror(errno));
504 return;
507 /* receive replies */
508 while (kernel_receive(NULL, fd) == TRUE);
511 #elif defined(USE_ROUTE)
513 #define ROUNDUP(a) \
514 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
516 #define SAROUNDUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len)
518 static size_t
519 parse_address(start, end, dest)
520 caddr_t start;
521 caddr_t end;
522 struct sockaddr_storage *dest;
524 int len;
526 if (start >= end)
527 return 0;
529 len = SAROUNDUP(start);
530 if (start + len > end)
531 return end - start;
533 if (dest != NULL && len <= sizeof(struct sockaddr_storage))
534 memcpy(dest, start, len);
536 return len;
539 static void
540 parse_addresses(start, end, flags, addr)
541 caddr_t start;
542 caddr_t end;
543 int flags;
544 struct sockaddr_storage *addr;
546 memset(addr, 0, sizeof(*addr));
547 if (flags & RTA_DST)
548 start += parse_address(start, end, NULL);
549 if (flags & RTA_GATEWAY)
550 start += parse_address(start, end, NULL);
551 if (flags & RTA_NETMASK)
552 start += parse_address(start, end, NULL);
553 if (flags & RTA_GENMASK)
554 start += parse_address(start, end, NULL);
555 if (flags & RTA_IFP)
556 start += parse_address(start, end, NULL);
557 if (flags & RTA_IFA)
558 start += parse_address(start, end, addr);
559 if (flags & RTA_AUTHOR)
560 start += parse_address(start, end, NULL);
561 if (flags & RTA_BRD)
562 start += parse_address(start, end, NULL);
565 static void
566 kernel_handle_message(msg)
567 caddr_t msg;
569 struct rt_msghdr *rtm = (struct rt_msghdr *) msg;
570 struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg;
571 struct sockaddr_storage addr;
573 switch (rtm->rtm_type) {
574 case RTM_NEWADDR:
575 parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
576 ifa->ifam_addrs, &addr);
577 myaddr_open_all_configured((struct sockaddr *) &addr);
578 break;
579 case RTM_DELADDR:
580 parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
581 ifa->ifam_addrs, &addr);
582 myaddr_close_all_open((struct sockaddr *) &addr);
583 break;
584 case RTM_ADD:
585 case RTM_DELETE:
586 case RTM_CHANGE:
587 case RTM_MISS:
588 case RTM_IFINFO:
589 #ifdef RTM_OIFINFO
590 case RTM_OIFINFO:
591 #endif
592 #ifdef RTM_NEWMADDR
593 case RTM_NEWMADDR:
594 case RTM_DELMADDR:
595 #endif
596 #ifdef RTM_IFANNOUNCE
597 case RTM_IFANNOUNCE:
598 #endif
599 break;
600 default:
601 plog(LLV_WARNING, LOCATION, NULL,
602 "unrecognized route message with rtm_type: %d",
603 rtm->rtm_type);
604 break;
608 static int
609 kernel_receive(ctx, fd)
610 void *ctx;
611 int fd;
613 char buf[16*1024];
614 struct rt_msghdr *rtm = (struct rt_msghdr *) buf;
615 int len;
617 len = read(fd, &buf, sizeof(buf));
618 if (len <= 0) {
619 if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
620 plog(LLV_WARNING, LOCATION, NULL,
621 "routing socket error: %s", strerror(errno));
622 return FALSE;
625 if (rtm->rtm_msglen != len) {
626 plog(LLV_WARNING, LOCATION, NULL,
627 "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n",
628 rtm->rtm_msglen, len, rtm->rtm_type);
629 return FALSE;
632 kernel_handle_message(buf);
633 return TRUE;
636 static int
637 kernel_open_socket()
639 int fd;
641 fd = socket(PF_ROUTE, SOCK_RAW, 0);
642 if (fd < 0) {
643 plog(LLV_ERROR, LOCATION, NULL,
644 "socket(PF_ROUTE) failed: %s",
645 strerror(errno));
646 return -1;
648 close_on_exec(fd);
649 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
650 plog(LLV_WARNING, LOCATION, NULL,
651 "failed to put socket in non-blocking mode\n");
653 return fd;
656 static void
657 kernel_sync()
659 caddr_t ref, buf, end;
660 size_t bufsiz;
661 struct if_msghdr *ifm;
662 struct interface *ifp;
664 #define MIBSIZ 6
665 int mib[MIBSIZ] = {
666 CTL_NET,
667 PF_ROUTE,
669 0, /* AF_INET & AF_INET6 */
670 NET_RT_IFLIST,
674 if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) {
675 plog(LLV_WARNING, LOCATION, NULL,
676 "sysctl() error: %s", strerror(errno));
677 return;
680 ref = buf = racoon_malloc(bufsiz);
682 if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) {
683 /* Parse both interfaces and addresses. */
684 for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) {
685 ifm = (struct if_msghdr *) buf;
686 kernel_handle_message(buf);
688 } else {
689 plog(LLV_WARNING, LOCATION, NULL,
690 "sysctl() error: %s", strerror(errno));
693 racoon_free(ref);
696 #else
698 #error No supported interface to monitor local addresses.
700 #endif