1 /* $NetBSD: grabmyaddr.c,v 1.22 2009/04/21 18:38:31 tteras Exp $ */
3 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
4 * Copyright (C) 2008 Timo Teras <timo.teras@iki.fi>.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
38 #include <sys/types.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
43 #include <linux/netlink.h>
44 #include <linux/rtnetlink.h>
47 #include <net/route.h>
49 #include <net/if_dl.h>
50 #include <sys/sysctl.h>
62 #include "localconf.h"
64 #include "grabmyaddr.h"
66 #include "isakmp_var.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));
75 LIST_ENTRY(myaddr
) chain
;
76 struct sockaddr_storage addr
;
81 static LIST_HEAD(_myaddr_list_
, myaddr
) configured
, opened
;
89 LIST_REMOVE(my
, chain
);
94 myaddr_configured(addr
)
95 struct sockaddr
*addr
;
99 if (LIST_EMPTY(&configured
))
102 LIST_FOREACH(cfg
, &configured
, chain
) {
103 if (cmpsaddr(addr
, (struct sockaddr
*) &cfg
->addr
) == 0)
111 myaddr_open(addr
, udp_encap
)
112 struct sockaddr
*addr
;
118 LIST_FOREACH(my
, &opened
, chain
) {
119 if (cmpsaddr(addr
, (struct sockaddr
*) &my
->addr
) == 0)
123 my
= racoon_calloc(1, sizeof(struct myaddr
));
127 memcpy(&my
->addr
, addr
, sysdep_sa_len(addr
));
128 my
->fd
= isakmp_open(addr
, udp_encap
);
133 my
->udp_encap
= udp_encap
;
134 LIST_INSERT_HEAD(&opened
, my
, chain
);
139 myaddr_open_all_configured(addr
)
140 struct sockaddr
*addr
;
142 /* create all configured, not already opened addresses */
143 struct myaddr
*cfg
, *my
;
146 switch (addr
->sa_family
) {
157 LIST_FOREACH(cfg
, &configured
, chain
) {
159 cmpsaddr(addr
, (struct sockaddr
*) &cfg
->addr
) != 0)
161 if (!myaddr_open((struct sockaddr
*) &cfg
->addr
, cfg
->udp_encap
))
164 if (LIST_EMPTY(&configured
)) {
166 /* Exclude any address we got through ISAKMP mode config */
167 if (exclude_cfg_addr(addr
) == 0)
170 set_port(addr
, lcconf
->port_isakmp
);
171 myaddr_open(addr
, FALSE
);
173 set_port(addr
, lcconf
->port_isakmp_natt
);
174 myaddr_open(addr
, TRUE
);
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
))
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
);
211 myaddr_flush_list(&configured
);
215 myaddr_listen(addr
, udp_encap
)
216 struct sockaddr
*addr
;
221 if (sysdep_sa_len(addr
) > sizeof(my
->addr
)) {
222 plog(LLV_ERROR
, LOCATION
, NULL
,
223 "sockaddr size larger than sockaddr_storage\n");
227 my
= racoon_calloc(1, sizeof(struct myaddr
));
231 memcpy(&my
->addr
, addr
, sysdep_sa_len(addr
));
232 my
->udp_encap
= udp_encap
;
234 LIST_INSERT_HEAD(&configured
, my
, chain
);
242 struct myaddr
*my
, *next
;
244 if (!lcconf
->strict_address
) {
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
))
259 struct sockaddr
*addr
;
263 LIST_FOREACH(my
, &opened
, chain
) {
264 if (cmpsaddr((struct sockaddr
*) &my
->addr
, addr
) == 0)
272 myaddr_getsport(addr
)
273 struct sockaddr
*addr
;
277 LIST_FOREACH(my
, &opened
, chain
) {
278 if (cmpsaddr((struct sockaddr
*) &my
->addr
, addr
) == 0)
279 return extract_port((struct sockaddr
*) &my
->addr
);
288 LIST_INIT(&configured
);
295 if (!lcconf
->strict_address
) {
296 lcconf
->rtsock
= kernel_open_socket();
297 if (lcconf
->rtsock
< 0)
299 monitor_fd(lcconf
->rtsock
, kernel_receive
, NULL
);
302 if (!myaddr_open_all_configured(NULL
))
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)
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
);
333 netlink_enumerate(fd
, family
, type
)
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;
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
;
368 struct sockaddr_in6
*sin6
;
371 /* is this message interesting? */
372 if (h
->nlmsg_type
!= RTM_NEWADDR
&&
373 h
->nlmsg_type
!= RTM_DELADDR
)
377 parse_rtattr(rta
, IFA_MAX
, IFA_RTA(ifa
), IFA_PAYLOAD(h
));
379 if (ifa
->ifa_flags
& IFA_F_TENTATIVE
)
382 if (rta
[IFA_LOCAL
] == NULL
)
383 rta
[IFA_LOCAL
] = rta
[IFA_ADDRESS
];
384 if (rta
[IFA_LOCAL
] == NULL
)
387 /* setup the socket address */
388 memset(&addr
, 0, sizeof(addr
));
389 addr
.ss_family
= ifa
->ifa_family
;
390 switch (ifa
->ifa_family
) {
392 sin
= (struct sockaddr_in
*) &addr
;
393 memcpy(&sin
->sin_addr
, RTA_DATA(rta
[IFA_LOCAL
]),
394 sizeof(sin
->sin_addr
));
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
;
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
);
417 myaddr_close_all_open((struct sockaddr
*) &addr
);
423 kernel_receive(ctx
, fd
)
427 struct sockaddr_nl nladdr
;
429 struct msghdr msg
= {
431 .msg_namelen
= sizeof(nladdr
),
441 iov
.iov_len
= sizeof(buf
);
442 status
= recvmsg(fd
, &msg
, MSG_DONTWAIT
);
453 h
= (struct nlmsghdr
*) buf
;
454 while (NLMSG_OK(h
, status
)) {
456 h
= NLMSG_NEXT(h
, status
);
466 struct sockaddr_nl nl
;
469 fd
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
471 plog(LLV_ERROR
, LOCATION
, NULL
,
472 "socket(PF_NETLINK) failed: %s",
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",
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",
507 /* receive replies */
508 while (kernel_receive(NULL
, fd
) == TRUE
);
511 #elif defined(USE_ROUTE)
514 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
516 #define SAROUNDUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len)
519 parse_address(start
, end
, dest
)
522 struct sockaddr_storage
*dest
;
529 len
= SAROUNDUP(start
);
530 if (start
+ len
> end
)
533 if (dest
!= NULL
&& len
<= sizeof(struct sockaddr_storage
))
534 memcpy(dest
, start
, len
);
540 parse_addresses(start
, end
, flags
, addr
)
544 struct sockaddr_storage
*addr
;
546 memset(addr
, 0, sizeof(*addr
));
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
);
556 start
+= parse_address(start
, end
, NULL
);
558 start
+= parse_address(start
, end
, addr
);
559 if (flags
& RTA_AUTHOR
)
560 start
+= parse_address(start
, end
, NULL
);
562 start
+= parse_address(start
, end
, NULL
);
566 kernel_handle_message(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
) {
575 parse_addresses(ifa
+ 1, msg
+ ifa
->ifam_msglen
,
576 ifa
->ifam_addrs
, &addr
);
577 myaddr_open_all_configured((struct sockaddr
*) &addr
);
580 parse_addresses(ifa
+ 1, msg
+ ifa
->ifam_msglen
,
581 ifa
->ifam_addrs
, &addr
);
582 myaddr_close_all_open((struct sockaddr
*) &addr
);
596 #ifdef RTM_IFANNOUNCE
601 plog(LLV_WARNING
, LOCATION
, NULL
,
602 "unrecognized route message with rtm_type: %d",
609 kernel_receive(ctx
, fd
)
614 struct rt_msghdr
*rtm
= (struct rt_msghdr
*) buf
;
617 len
= read(fd
, &buf
, sizeof(buf
));
619 if (len
< 0 && errno
!= EWOULDBLOCK
&& errno
!= EAGAIN
)
620 plog(LLV_WARNING
, LOCATION
, NULL
,
621 "routing socket error: %s", strerror(errno
));
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
);
632 kernel_handle_message(buf
);
641 fd
= socket(PF_ROUTE
, SOCK_RAW
, 0);
643 plog(LLV_ERROR
, LOCATION
, NULL
,
644 "socket(PF_ROUTE) failed: %s",
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");
659 caddr_t ref
, buf
, end
;
661 struct if_msghdr
*ifm
;
662 struct interface
*ifp
;
669 0, /* AF_INET & AF_INET6 */
674 if (sysctl(mib
, MIBSIZ
, NULL
, &bufsiz
, NULL
, 0) < 0) {
675 plog(LLV_WARNING
, LOCATION
, NULL
,
676 "sysctl() error: %s", strerror(errno
));
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
);
689 plog(LLV_WARNING
, LOCATION
, NULL
,
690 "sysctl() error: %s", strerror(errno
));
698 #error No supported interface to monitor local addresses.