1 /* $Id: grabmyaddr.c,v 1.23.4.2 2005/07/16 04:41:01 monas Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
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
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/socket.h>
37 #include <sys/ioctl.h>
40 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
41 #include <net/if_var.h>
43 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__)
44 #include <netinet/in.h>
45 #include <netinet6/in6_var.h>
47 #include <net/route.h>
57 #ifdef HAVE_GETIFADDRS
69 #include "localconf.h"
71 #include "grabmyaddr.h"
73 #include "isakmp_var.h"
75 #include "nattraversal.h"
78 #include <linux/types.h>
79 #include <linux/rtnetlink.h>
80 #ifndef HAVE_GETIFADDRS
81 #define HAVE_GETIFADDRS
82 #define NEED_LINUX_GETIFADDRS
86 #ifndef HAVE_GETIFADDRS
87 static unsigned int if_maxindex
__P((void));
90 static int suitable_ifaddr
__P((const char *, const struct sockaddr
*));
92 static int suitable_ifaddr6
__P((const char *, const struct sockaddr
*));
95 #ifdef NEED_LINUX_GETIFADDRS
97 /* We could do this _much_ better. kame racoon in its current form
98 * will esentially die at frequent changes of address configuration.
103 struct ifaddrs
*ifa_next
;
106 struct sockaddr
*ifa_addr
;
107 struct sockaddr_storage ifa_addrbuf
;
110 static int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
112 while (RTA_OK(rta
, len
)) {
113 if (rta
->rta_type
<= max
)
114 tb
[rta
->rta_type
] = rta
;
115 rta
= RTA_NEXT(rta
,len
);
120 static void recvaddrs(int fd
, struct ifaddrs
**ifa
, __u32 seq
)
123 struct sockaddr_nl nladdr
;
124 struct iovec iov
= { buf
, sizeof(buf
) };
126 struct rtattr
* rta_tb
[IFA_MAX
+1];
133 struct msghdr msg
= {
134 (void*)&nladdr
, sizeof(nladdr
),
140 status
= recvmsg(fd
, &msg
, 0);
148 if (nladdr
.nl_pid
) /* Message not from kernel */
151 h
= (struct nlmsghdr
*)buf
;
152 while (NLMSG_OK(h
, status
)) {
153 if (h
->nlmsg_seq
!= seq
)
156 if (h
->nlmsg_type
== NLMSG_DONE
)
159 if (h
->nlmsg_type
== NLMSG_ERROR
)
162 if (h
->nlmsg_type
!= RTM_NEWADDR
)
167 if (m
->ifa_family
!= AF_INET
&&
168 m
->ifa_family
!= AF_INET6
)
171 if (m
->ifa_flags
&IFA_F_TENTATIVE
)
174 memset(rta_tb
, 0, sizeof(rta_tb
));
175 parse_rtattr(rta_tb
, IFA_MAX
, IFA_RTA(m
), h
->nlmsg_len
- NLMSG_LENGTH(sizeof(*m
)));
177 if (rta_tb
[IFA_LOCAL
] == NULL
)
178 rta_tb
[IFA_LOCAL
] = rta_tb
[IFA_ADDRESS
];
179 if (rta_tb
[IFA_LOCAL
] == NULL
)
182 I
= malloc(sizeof(struct ifaddrs
));
185 memset(I
, 0, sizeof(*I
));
187 I
->ifa_ifindex
= m
->ifa_index
;
188 I
->ifa_addr
= (struct sockaddr
*)&I
->ifa_addrbuf
;
189 I
->ifa_addr
->sa_family
= m
->ifa_family
;
190 if (m
->ifa_family
== AF_INET
) {
191 struct sockaddr_in
*sin
= (void*)I
->ifa_addr
;
192 memcpy(&sin
->sin_addr
, RTA_DATA(rta_tb
[IFA_LOCAL
]), 4);
194 struct sockaddr_in6
*sin
= (void*)I
->ifa_addr
;
195 memcpy(&sin
->sin6_addr
, RTA_DATA(rta_tb
[IFA_LOCAL
]), 16);
196 if (IN6_IS_ADDR_LINKLOCAL(&sin
->sin6_addr
))
197 sin
->sin6_scope_id
= I
->ifa_ifindex
;
203 h
= NLMSG_NEXT(h
, status
);
205 if (msg
.msg_flags
& MSG_TRUNC
)
211 static int getifaddrs(struct ifaddrs
**ifa0
)
217 struct sockaddr_nl nladdr
;
222 fd
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
226 memset(&nladdr
, 0, sizeof(nladdr
));
227 nladdr
.nl_family
= AF_NETLINK
;
229 req
.nlh
.nlmsg_len
= sizeof(req
);
230 req
.nlh
.nlmsg_type
= RTM_GETADDR
;
231 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
|NLM_F_MATCH
|NLM_F_REQUEST
;
232 req
.nlh
.nlmsg_pid
= 0;
233 req
.nlh
.nlmsg_seq
= ++seq
;
234 req
.g
.rtgen_family
= AF_UNSPEC
;
236 if (sendto(fd
, (void*)&req
, sizeof(req
), 0, (struct sockaddr
*)&nladdr
, sizeof(nladdr
)) < 0) {
243 recvaddrs(fd
, ifa0
, seq
);
247 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
249 for (i
=*ifa0
; i
; i
= i
->ifa_next
) {
251 ifr
.ifr_ifindex
= i
->ifa_ifindex
;
252 ioctl(fd
, SIOCGIFNAME
, (void*)&ifr
);
253 memcpy(i
->ifa_name
, ifr
.ifr_name
, 16);
260 static void freeifaddrs(struct ifaddrs
*ifa0
)
273 #ifndef HAVE_GETIFADDRS
277 struct if_nameindex
*p
, *p0
;
278 unsigned int max
= 0;
281 for (p
= p0
; p
&& p
->if_index
&& p
->if_name
; p
++) {
282 if (max
< p
->if_index
)
285 if_freenameindex(p0
);
294 struct myaddrs
*p
, *next
;
296 for (p
= lcconf
->myaddrs
; p
; p
= next
) {
302 lcconf
->myaddrs
= NULL
;
308 find_myaddr(addr
, udp_encap
)
309 struct sockaddr
*addr
;
313 char h1
[NI_MAXHOST
], h2
[NI_MAXHOST
];
315 if (getnameinfo(addr
, sysdep_sa_len(addr
), h1
, sizeof(h1
), NULL
, 0,
316 NI_NUMERICHOST
| niflags
) != 0)
319 for (q
= lcconf
->myaddrs
; q
; q
= q
->next
) {
322 if (q
->udp_encap
&& !udp_encap
323 || !q
->udp_encap
&& udp_encap
)
325 if (addr
->sa_family
!= q
->addr
->sa_family
)
327 if (getnameinfo(q
->addr
, sysdep_sa_len(q
->addr
), h2
, sizeof(h2
),
328 NULL
, 0, NI_NUMERICHOST
| niflags
) != 0)
330 if (strcmp(h1
, h2
) == 0)
338 // modified to avoid closing and opening sockets for
339 // all interfaces each time an interface change occurs.
340 // on return: addrcount = zero indicates address no longer used
341 // sock = -1 indicates a new address - no socket opened yet.
345 #ifdef HAVE_GETIFADDRS
346 struct myaddrs
*p
, *q
;
347 struct ifaddrs
*ifa0
, *ifap
;
349 struct sockaddr_in6
*sin6
;
352 char addr1
[NI_MAXHOST
];
354 if (getifaddrs(&ifa0
)) {
355 plog(LLV_ERROR2
, LOCATION
, NULL
,
356 "getifaddrs failed: %s\n", strerror(errno
));
361 // clear the in_use flag for each address in the list
362 for (p
= lcconf
->myaddrs
; p
; p
= p
->next
)
365 for (ifap
= ifa0
; ifap
; ifap
= ifap
->ifa_next
) {
367 if (ifap
->ifa_addr
->sa_family
!= AF_INET
369 && ifap
->ifa_addr
->sa_family
!= AF_INET6
374 if (!suitable_ifaddr(ifap
->ifa_name
, ifap
->ifa_addr
)) {
375 plog(LLV_DEBUG2
, LOCATION
, NULL
,
376 "unsuitable address: %s %s\n",
378 saddrwop2str(ifap
->ifa_addr
));
382 p
= find_myaddr(ifap
->ifa_addr
, 0);
386 q
= find_myaddr(ifap
->ifa_addr
, 1);
393 plog(LLV_ERROR2
, LOCATION
, NULL
,
394 "unable to allocate space for addr.\n");
398 p
->addr
= dupsaddr(ifap
->ifa_addr
);
399 if (p
->addr
== NULL
) {
400 plog(LLV_ERROR2
, LOCATION
, NULL
,
401 "unable to duplicate addr.\n");
405 p
->ifname
= racoon_strdup(ifap
->ifa_name
);
406 if (p
->ifname
== NULL
) {
407 plog(LLV_ERROR2
, LOCATION
, NULL
,
408 "unable to duplicate ifname.\n");
416 if (getnameinfo(p
->addr
, p
->addr
->sa_len
,
417 addr1
, sizeof(addr1
),
419 NI_NUMERICHOST
| niflags
))
420 strlcpy(addr1
, "(invalid)", sizeof(addr1
));
421 plog(LLV_DEBUG
, LOCATION
, NULL
,
422 "my interface: %s (%s)\n",
423 addr1
, ifap
->ifa_name
);
425 p
->next
= lcconf
->myaddrs
;
429 if (natt_enabled_in_rmconf ()) {
432 plog(LLV_ERROR2
, LOCATION
, NULL
,
433 "unable to allocate space for natt addr.\n");
446 #else /*!HAVE_GETIFADDRS*/
447 #error "NOT SUPPORTED"
448 #endif /*HAVE_GETIFADDRS*/
453 * check the interface is suitable or not
456 suitable_ifaddr(ifname
, ifaddr
)
458 const struct sockaddr
*ifaddr
;
461 /* Exclude any address we got through ISAKMP mode config */
462 if (exclude_cfg_addr(ifaddr
) == 0)
465 switch(ifaddr
->sa_family
) {
470 return suitable_ifaddr6(ifname
, ifaddr
);
480 suitable_ifaddr6(ifname
, ifaddr
)
482 const struct sockaddr
*ifaddr
;
485 struct in6_ifreq ifr6
;
489 if (ifaddr
->sa_family
!= AF_INET6
)
493 s
= socket(PF_INET6
, SOCK_DGRAM
, 0);
495 plog(LLV_ERROR
, LOCATION
, NULL
,
496 "socket(SOCK_DGRAM) failed:%s\n", strerror(errno
));
500 memset(&ifr6
, 0, sizeof(ifr6
));
501 strlcpy(ifr6
.ifr_name
, ifname
, sizeof(ifr6
.ifr_name
));
503 ifr6
.ifr_addr
= *(const struct sockaddr_in6
*)ifaddr
;
505 if (ioctl(s
, SIOCGIFAFLAG_IN6
, &ifr6
) < 0) {
506 plog(LLV_ERROR
, LOCATION
, NULL
,
507 "ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno
));
514 if (ifr6
.ifr_ifru
.ifru_flags6
& IN6_IFF_DUPLICATED
515 || ifr6
.ifr_ifru
.ifru_flags6
& IN6_IFF_DETACHED
516 || ifr6
.ifr_ifru
.ifru_flags6
& IN6_IFF_ANYCAST
)
531 struct nlmsghdr
*h
= (void*)msg
;
532 len
= read(lcconf
->rtsock
, msg
, sizeof(msg
));
534 return errno
== ENOBUFS
;
535 if (len
< sizeof(*h
))
537 if (h
->nlmsg_pid
) /* not from kernel! */
539 if (h
->nlmsg_type
== RTM_NEWLINK
)
541 plog(LLV_DEBUG
, LOCATION
, NULL
,
542 "netlink signals update interface address list\n");
547 struct rt_msghdr
*rtm
;
549 len
= read(lcconf
->rtsock
, msg
, sizeof(msg
));
551 plog(LLV_ERROR
, LOCATION
, NULL
,
552 "read(PF_ROUTE) failed: %s\n",
556 rtm
= (struct rt_msghdr
*)msg
;
557 if (len
< rtm
->rtm_msglen
) {
558 plog(LLV_ERROR
, LOCATION
, NULL
,
559 "read(PF_ROUTE) short read\n");
562 if (rtm
->rtm_version
!= RTM_VERSION
) {
563 plog(LLV_ERROR
, LOCATION
, NULL
,
564 "routing socket version mismatch\n");
565 close(lcconf
->rtsock
);
569 switch (rtm
->rtm_type
) {
576 /* ignore this message silently */
579 plog(LLV_DEBUG
, LOCATION
, NULL
,
580 "msg %d not interesting\n", rtm
->rtm_type
);
583 /* XXX more filters here? */
585 plog(LLV_DEBUG
, LOCATION
, NULL
,
586 "caught rtm:%d, need update interface address list\n",
590 #endif /* __linux__ */
594 * initialize default port for ISAKMP to send, if no "listen"
595 * directive is specified in config file.
597 * DO NOT listen to wildcard addresses. if you receive packets to
598 * wildcard address, you'll be in trouble (DoS attack possible by
602 autoconf_myaddrsport()
607 plog(LLV_DEBUG
, LOCATION
, NULL
,
608 "configuring default isakmp port.\n");
610 for (p
= lcconf
->myaddrs
, n
= 0; p
; p
= p
->next
, n
++) {
611 set_port (p
->addr
, p
->udp_encap
? lcconf
->port_isakmp_natt
: lcconf
->port_isakmp
);
613 plog(LLV_DEBUG
, LOCATION
, NULL
,
614 "%d addrs are configured successfully\n", n
);
620 * get a port number to which racoon binded.
621 * NOTE: network byte order returned.
624 getmyaddrsport(local
)
625 struct sockaddr
*local
;
627 struct myaddrs
*p
, *bestmatch
= NULL
;
628 u_short bestmatch_port
= PORT_ISAKMP
;
630 /* get a relative port */
631 for (p
= lcconf
->myaddrs
; p
; p
= p
->next
) {
634 if (!cmpsaddrwop(local
, p
->addr
)) {
640 switch (p
->addr
->sa_family
) {
642 if (((struct sockaddr_in
*)p
->addr
)->sin_port
== PORT_ISAKMP
) {
644 bestmatch_port
= ((struct sockaddr_in
*)p
->addr
)->sin_port
;
650 if (((struct sockaddr_in6
*)p
->addr
)->sin6_port
== PORT_ISAKMP
) {
652 bestmatch_port
= ((struct sockaddr_in6
*)p
->addr
)->sin6_port
;
658 plog(LLV_ERROR
, LOCATION
, NULL
,
659 "unsupported AF %d\n", p
->addr
->sa_family
);
665 return htons(bestmatch_port
);
673 new = racoon_calloc(1, sizeof(*new));
675 plog(LLV_ERROR
, LOCATION
, NULL
,
676 "failed to allocate buffer for myaddrs.\n");
690 dupmyaddr(struct myaddrs
*old
)
694 new = racoon_calloc(1, sizeof(*new));
696 plog(LLV_ERROR
, LOCATION
, NULL
,
697 "failed to allocate buffer for myaddrs.\n");
701 /* Copy the whole structure and set the differences. */
702 memcpy (new, old
, sizeof (*new));
703 new->addr
= dupsaddr (old
->addr
);
704 if (new->addr
== NULL
) {
705 plog(LLV_ERROR
, LOCATION
, NULL
,
706 "failed to allocate buffer for duplicate addr.\n");
711 new->ifname
= racoon_strdup(old
->ifname
);
712 if (new->ifname
== NULL
) {
713 plog(LLV_ERROR
, LOCATION
, NULL
,
714 "failed to allocate buffer for duplicate ifname.\n");
715 racoon_free(new->addr
);
721 new->next
= old
->next
;
730 struct myaddrs
**head
;
738 struct myaddrs
*myaddr
;
741 racoon_free(myaddr
->addr
);
744 racoon_free(myaddr
->ifname
);
752 /* initialize routing socket */
753 lcconf
->rtsock
= socket(PF_ROUTE
, SOCK_RAW
, PF_UNSPEC
);
754 if (lcconf
->rtsock
< 0) {
755 plog(LLV_ERROR
, LOCATION
, NULL
,
756 "socket(PF_ROUTE) failed: %s",
763 struct sockaddr_nl nl
;
766 memset(&nl
, 0, sizeof(nl
));
767 nl
.nl_family
= AF_NETLINK
;
768 nl
.nl_groups
= RTMGRP_IPV4_IFADDR
|RTMGRP_LINK
;
770 if (bind(lcconf
->rtsock
, (struct sockaddr
*)&nl
, sizeof(nl
)) < 0) {
771 plog(LLV_ERROR
, LOCATION
, NULL
,
772 "bind(PF_NETLINK) failed: %s\n",
776 addr_len
= sizeof(nl
);
777 if (getsockname(lcconf
->rtsock
, (struct sockaddr
*)&nl
, &addr_len
) < 0) {
778 plog(LLV_ERROR
, LOCATION
, NULL
,
779 "getsockname(PF_NETLINK) failed: %s\n",
786 if (lcconf
->myaddrs
== NULL
&& lcconf
->autograbaddr
== 1) {
789 if (autoconf_myaddrsport() < 0)
796 /* select the socket to be sent */
797 /* should implement other method. */
802 struct myaddrs
*p
, *lastresort
= NULL
;
803 #if defined(INET6) && defined(__linux__)
804 struct myaddrs
*match_wo_scope_id
= NULL
;
805 int check_wo_scope_id
= (my
->sa_family
== AF_INET6
) &&
806 IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6
*)my
)->sin6_addr
);
809 for (p
= lcconf
->myaddrs
; p
; p
= p
->next
) {
812 if (my
->sa_family
== p
->addr
->sa_family
) {
815 if (sysdep_sa_len(my
) == sysdep_sa_len(p
->addr
)
816 && memcmp(my
, p
->addr
, sysdep_sa_len(my
)) == 0) {
819 #if defined(INET6) && defined(__linux__)
820 if (check_wo_scope_id
&& IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6
*)p
->addr
)->sin6_addr
) &&
821 /* XXX: this depends on sin6_scope_id to be last
822 * item in struct sockaddr_in6 */
824 sysdep_sa_len(my
) - sizeof(uint32_t)) == 0) {
825 match_wo_scope_id
= p
;
829 #if defined(INET6) && defined(__linux__)
831 p
= match_wo_scope_id
;
836 plog(LLV_ERROR
, LOCATION
, NULL
,
837 "no socket matches address family %d\n",