grabmyaddr.c revision 1.16
1/*	$NetBSD: grabmyaddr.c,v 1.16 2008/12/11 15:45:24 vanhu Exp $	*/
2
3/* Id: grabmyaddr.c,v 1.27 2006/04/06 16:27:05 manubsd Exp */
4
5/*
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "config.h"
35
36#include <sys/types.h>
37#include <sys/param.h>
38#include <sys/socket.h>
39#include <sys/ioctl.h>
40
41#include <net/if.h>
42#if defined(__FreeBSD__) && __FreeBSD__ >= 3
43#include <net/if_var.h>
44#endif
45#if defined(__NetBSD__) || defined(__FreeBSD__) ||	\
46  (defined(__APPLE__) && defined(__MACH__))
47#include <netinet/in.h>
48#include <netinet6/in6_var.h>
49#endif
50#include <net/route.h>
51
52#include <stdlib.h>
53#include <stdio.h>
54#include <string.h>
55#include <errno.h>
56#ifdef HAVE_UNISTD_H
57#include <unistd.h>
58#endif
59#include <netdb.h>
60#ifdef HAVE_GETIFADDRS
61#include <ifaddrs.h>
62#include <net/if.h>
63#endif
64#if defined(__FreeBSD__)
65#include <net/route.h>
66#endif
67
68#include "var.h"
69#include "misc.h"
70#include "vmbuf.h"
71#include "plog.h"
72#include "sockmisc.h"
73#include "debug.h"
74
75#include "localconf.h"
76#include "handler.h"
77#include "grabmyaddr.h"
78#include "sockmisc.h"
79#include "isakmp_var.h"
80#include "gcmalloc.h"
81#include "nattraversal.h"
82
83#ifdef __linux__
84#include <linux/types.h>
85#include <linux/rtnetlink.h>
86#ifndef HAVE_GETIFADDRS
87#define HAVE_GETIFADDRS
88#define NEED_LINUX_GETIFADDRS
89#endif
90#endif
91
92#ifndef HAVE_GETIFADDRS
93static unsigned int if_maxindex __P((void));
94#endif
95static struct myaddrs *find_myaddr __P((struct myaddrs *, struct myaddrs *));
96static int suitable_ifaddr __P((const char *, const struct sockaddr *));
97#ifdef INET6
98static int suitable_ifaddr6 __P((const char *, const struct sockaddr *));
99#endif
100
101#ifdef NEED_LINUX_GETIFADDRS
102
103/* We could do this _much_ better. kame racoon in its current form
104 * will esentially die at frequent changes of address configuration.
105 */
106
107struct ifaddrs
108{
109	struct ifaddrs *ifa_next;
110	char		ifa_name[16];
111	int		ifa_ifindex;
112	struct sockaddr *ifa_addr;
113	struct sockaddr_storage ifa_addrbuf;
114};
115
116static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
117{
118	while (RTA_OK(rta, len)) {
119		if (rta->rta_type <= max)
120			tb[rta->rta_type] = rta;
121		rta = RTA_NEXT(rta,len);
122	}
123	return 0;
124}
125
126static void recvaddrs(int fd, struct ifaddrs **ifa, __u32 seq)
127{
128	char	buf[8192];
129	struct sockaddr_nl nladdr;
130	struct iovec iov = { buf, sizeof(buf) };
131	struct ifaddrmsg *m;
132	struct rtattr * rta_tb[IFA_MAX+1];
133	struct ifaddrs *I;
134
135	while (1) {
136		int status;
137		struct nlmsghdr *h;
138
139		struct msghdr msg = {
140			(void*)&nladdr, sizeof(nladdr),
141			&iov,	1,
142			NULL,	0,
143			0
144		};
145
146		status = recvmsg(fd, &msg, 0);
147
148		if (status < 0)
149			continue;
150
151		if (status == 0)
152			return;
153
154		if (nladdr.nl_pid) /* Message not from kernel */
155			continue;
156
157		h = (struct nlmsghdr*)buf;
158		while (NLMSG_OK(h, status)) {
159			if (h->nlmsg_seq != seq)
160				goto skip_it;
161
162			if (h->nlmsg_type == NLMSG_DONE)
163				return;
164
165			if (h->nlmsg_type == NLMSG_ERROR)
166				return;
167
168			if (h->nlmsg_type != RTM_NEWADDR)
169				goto skip_it;
170
171			m = NLMSG_DATA(h);
172
173			if (m->ifa_family != AF_INET &&
174			    m->ifa_family != AF_INET6)
175				goto skip_it;
176
177			if (m->ifa_flags&IFA_F_TENTATIVE)
178				goto skip_it;
179
180			memset(rta_tb, 0, sizeof(rta_tb));
181			parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(m), h->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
182
183			if (rta_tb[IFA_LOCAL] == NULL)
184				rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
185			if (rta_tb[IFA_LOCAL] == NULL)
186				goto skip_it;
187
188			I = malloc(sizeof(struct ifaddrs));
189			if (!I)
190				return;
191			memset(I, 0, sizeof(*I));
192
193			I->ifa_ifindex = m->ifa_index;
194			I->ifa_addr = (struct sockaddr*)&I->ifa_addrbuf;
195			I->ifa_addr->sa_family = m->ifa_family;
196			if (m->ifa_family == AF_INET) {
197				struct sockaddr_in *sin = (void*)I->ifa_addr;
198				memcpy(&sin->sin_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 4);
199			} else {
200				struct sockaddr_in6 *sin = (void*)I->ifa_addr;
201				memcpy(&sin->sin6_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 16);
202				if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
203					sin->sin6_scope_id = I->ifa_ifindex;
204			}
205			I->ifa_next = *ifa;
206			*ifa = I;
207
208skip_it:
209			h = NLMSG_NEXT(h, status);
210		}
211		if (msg.msg_flags & MSG_TRUNC)
212			continue;
213	}
214	return;
215}
216
217static int getifaddrs(struct ifaddrs **ifa0)
218{
219	struct {
220		struct nlmsghdr nlh;
221		struct rtgenmsg g;
222	} req;
223	struct sockaddr_nl nladdr;
224	static __u32 seq;
225	struct ifaddrs *i;
226	int fd;
227
228	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
229	if (fd < 0)
230		return -1;
231
232	memset(&nladdr, 0, sizeof(nladdr));
233	nladdr.nl_family = AF_NETLINK;
234
235	req.nlh.nlmsg_len = sizeof(req);
236	req.nlh.nlmsg_type = RTM_GETADDR;
237	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
238	req.nlh.nlmsg_pid = 0;
239	req.nlh.nlmsg_seq = ++seq;
240	req.g.rtgen_family = AF_UNSPEC;
241
242	if (sendto(fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) {
243		close(fd);
244		return -1;
245	}
246
247	*ifa0 = NULL;
248
249	recvaddrs(fd, ifa0, seq);
250
251	close(fd);
252
253	fd = socket(AF_INET, SOCK_DGRAM, 0);
254
255	for (i=*ifa0; i; i = i->ifa_next) {
256		struct ifreq ifr;
257		ifr.ifr_ifindex = i->ifa_ifindex;
258		ioctl(fd, SIOCGIFNAME, (void*)&ifr);
259		memcpy(i->ifa_name, ifr.ifr_name, 16);
260	}
261	close(fd);
262
263	return 0;
264}
265
266static void freeifaddrs(struct ifaddrs *ifa0)
267{
268        struct ifaddrs *i;
269
270        while (ifa0) {
271                i = ifa0;
272                ifa0 = i->ifa_next;
273                free(i);
274        }
275}
276
277#endif
278
279#ifndef HAVE_GETIFADDRS
280static unsigned int
281if_maxindex()
282{
283	struct if_nameindex *p, *p0;
284	unsigned int max = 0;
285
286	p0 = if_nameindex();
287	for (p = p0; p && p->if_index && p->if_name; p++) {
288		if (max < p->if_index)
289			max = p->if_index;
290	}
291	if_freenameindex(p0);
292	return max;
293}
294#endif
295
296void
297clear_myaddr(db)
298	struct myaddrs **db;
299{
300	struct myaddrs *p;
301
302	while (*db) {
303		p = (*db)->next;
304		delmyaddr(*db);
305		*db = p;
306	}
307}
308
309static struct myaddrs *
310find_myaddr(db, p)
311	struct myaddrs *db;
312	struct myaddrs *p;
313{
314	struct myaddrs *q;
315	char h1[NI_MAXHOST], h2[NI_MAXHOST];
316
317	if (getnameinfo(p->addr, sysdep_sa_len(p->addr), h1, sizeof(h1), NULL, 0,
318	    NI_NUMERICHOST | niflags) != 0)
319		return NULL;
320
321	for (q = db; q; q = q->next) {
322		if (p->addr->sa_family != q->addr->sa_family)
323			continue;
324		if (getnameinfo(q->addr, sysdep_sa_len(q->addr), h2, sizeof(h2),
325		    NULL, 0, NI_NUMERICHOST | niflags) != 0)
326			return NULL;
327		if (strcmp(h1, h2) == 0)
328			return q;
329	}
330
331	return NULL;
332}
333
334void
335grab_myaddrs()
336{
337#ifdef HAVE_GETIFADDRS
338	struct myaddrs *p, *q, *old;
339	struct ifaddrs *ifa0, *ifap;
340#ifdef INET6
341	struct sockaddr_in6 *sin6;
342#endif
343
344	char addr1[NI_MAXHOST];
345
346	if (getifaddrs(&ifa0)) {
347		plog(LLV_ERROR, LOCATION, NULL,
348			"getifaddrs failed: %s\n", strerror(errno));
349		exit(1);
350		/*NOTREACHED*/
351	}
352
353	old = lcconf->myaddrs;
354
355	for (ifap = ifa0; ifap; ifap = ifap->ifa_next) {
356		if (! ifap->ifa_addr)
357			continue;
358
359		if (ifap->ifa_addr->sa_family != AF_INET
360#ifdef INET6
361		 && ifap->ifa_addr->sa_family != AF_INET6
362#endif
363		)
364			continue;
365
366		if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) {
367			plog(LLV_INFO, LOCATION, NULL,
368				"unsuitable address: %s %s\n",
369				ifap->ifa_name,
370				saddrwop2str(ifap->ifa_addr));
371			continue;
372		}
373
374		p = newmyaddr();
375		if (p == NULL) {
376			exit(1);
377			/*NOTREACHED*/
378		}
379		p->addr = dupsaddr(ifap->ifa_addr);
380		if (p->addr == NULL) {
381			exit(1);
382			/*NOTREACHED*/
383		}
384#ifdef INET6
385#ifdef __KAME__
386		if (ifap->ifa_addr->sa_family == AF_INET6) {
387			sin6 = (struct sockaddr_in6 *)p->addr;
388			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)
389			 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
390				sin6->sin6_scope_id =
391					ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
392				sin6->sin6_addr.s6_addr[2] = 0;
393				sin6->sin6_addr.s6_addr[3] = 0;
394			}
395		}
396#else /* !__KAME__ */
397		if (ifap->ifa_addr->sa_family == AF_INET6) {
398			sin6 = (struct sockaddr_in6 *)p->addr;
399			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)
400			 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
401				sin6->sin6_scope_id =
402					if_nametoindex(ifap->ifa_name);
403			}
404		}
405
406#endif
407#endif
408		if (getnameinfo(p->addr, sysdep_sa_len(p->addr),
409				addr1, sizeof(addr1), NULL, 0,
410				NI_NUMERICHOST | niflags))
411			strlcpy(addr1, "(invalid)", sizeof(addr1));
412
413		plog(LLV_DEBUG, LOCATION, NULL,
414			"my interface: %s (%s)\n",
415			addr1, ifap->ifa_name);
416		q = find_myaddr(old, p);
417		if (q)
418			p->sock = q->sock;
419		else
420			p->sock = -1;
421		insmyaddr(p, &lcconf->myaddrs);
422	}
423
424	freeifaddrs(ifa0);
425
426	clear_myaddr(&old);
427
428#else /*!HAVE_GETIFADDRS*/
429	int s;
430	unsigned int maxif;
431	int len;
432	struct ifreq *iflist;
433	struct ifconf ifconf;
434	struct ifreq *ifr, *ifr_end;
435	struct myaddrs *p, *q, *old;
436#ifdef INET6
437#ifdef __KAME__
438	struct sockaddr_in6 *sin6;
439#endif
440#endif
441
442	char addr1[NI_MAXHOST];
443
444	maxif = if_maxindex() + 1;
445	len = maxif * sizeof(struct sockaddr_storage) * 4; /* guess guess */
446
447	iflist = (struct ifreq *)racoon_malloc(len);
448	if (!iflist) {
449		plog(LLV_ERROR, LOCATION, NULL,
450			"failed to allocate buffer\n");
451		exit(1);
452		/*NOTREACHED*/
453	}
454
455	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
456		plog(LLV_ERROR, LOCATION, NULL,
457			"socket(SOCK_DGRAM) failed: %s\n",
458			strerror(errno));
459		exit(1);
460		/*NOTREACHED*/
461	}
462	memset(&ifconf, 0, sizeof(ifconf));
463	ifconf.ifc_req = iflist;
464	ifconf.ifc_len = len;
465	if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) {
466		close(s);
467		plog(LLV_ERROR, LOCATION, NULL,
468			"ioctl(SIOCGIFCONF) failed: %s\n",
469			strerror(errno));
470		exit(1);
471		/*NOTREACHED*/
472	}
473	close(s);
474
475	old = lcconf->myaddrs;
476
477	/* Look for this interface in the list */
478	ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len);
479
480#define _IFREQ_LEN(p) \
481  (sizeof((p)->ifr_name) + sysdep_sa_len(&(p)->ifr_addr) > sizeof(struct ifreq) \
482    ? sizeof((p)->ifr_name) + sysdep_sa_len(&(p)->ifr_addr) : sizeof(struct ifreq))
483
484	for (ifr = ifconf.ifc_req;
485	     ifr < ifr_end;
486	     ifr = (struct ifreq *)((caddr_t)ifr + _IFREQ_LEN(ifr))) {
487
488		switch (ifr->ifr_addr.sa_family) {
489		case AF_INET:
490#ifdef INET6
491		case AF_INET6:
492#endif
493			if (!suitable_ifaddr(ifr->ifr_name, &ifr->ifr_addr)) {
494				plog(LLV_INFO, LOCATION, NULL,
495					"unsuitable address: %s %s\n",
496					ifr->ifr_name,
497					saddrwop2str(&ifr->ifr_addr));
498				continue;
499			}
500
501			p = newmyaddr();
502			if (p == NULL) {
503				exit(1);
504				/*NOTREACHED*/
505			}
506			p->addr = dupsaddr(&ifr->ifr_addr);
507			if (p->addr == NULL) {
508				exit(1);
509				/*NOTREACHED*/
510			}
511#ifdef INET6
512#ifdef __KAME__
513			sin6 = (struct sockaddr_in6 *)p->addr;
514			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)
515			 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
516				sin6->sin6_scope_id =
517					ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
518				sin6->sin6_addr.s6_addr[2] = 0;
519				sin6->sin6_addr.s6_addr[3] = 0;
520			}
521#endif
522#endif
523			if (getnameinfo(p->addr, sysdep_sa_len(p->addr),
524					addr1, sizeof(addr1), NULL, 0,
525					NI_NUMERICHOST | niflags))
526				strlcpy(addr1, "(invalid)", sizeof(addr1));
527
528			plog(LLV_DEBUG, LOCATION, NULL,
529				"my interface: %s (%s)\n",
530				addr1, ifr->ifr_name);
531			q = find_myaddr(old, p);
532			if (q)
533				p->sock = q->sock;
534			else
535				p->sock = -1;
536			insmyaddr(p, &lcconf->myaddrs);
537			break;
538		default:
539			break;
540		}
541	}
542
543	clear_myaddr(&old);
544
545	racoon_free(iflist);
546#endif /*HAVE_GETIFADDRS*/
547}
548
549/*
550 * check the interface is suitable or not
551 */
552static int
553suitable_ifaddr(ifname, ifaddr)
554	const char *ifname;
555	const struct sockaddr *ifaddr;
556{
557#ifdef ENABLE_HYBRID
558	/* Exclude any address we got through ISAKMP mode config */
559	if (exclude_cfg_addr(ifaddr) == 0)
560		return 0;
561#endif
562	switch(ifaddr->sa_family) {
563	case AF_INET:
564		if (((struct sockaddr_in *)ifaddr)->sin_addr.s_addr ==
565		    htonl(INADDR_ANY)) {
566			plog(LLV_DEBUG, LOCATION, NULL,
567			     "discarding unsuitable wildcard address\n");
568			return 0;
569		}
570		else if (((struct sockaddr_in *)ifaddr)->sin_addr.s_addr ==
571			 htonl(INADDR_LOOPBACK)) {
572			plog(LLV_DEBUG, LOCATION, NULL,
573			     "discarding unsuitable loopback address\n");
574			return 0;
575		}
576		return 1;
577#ifdef INET6
578	case AF_INET6:
579		return suitable_ifaddr6(ifname, ifaddr);
580#endif
581	default:
582		return 0;
583	}
584	/*NOTREACHED*/
585}
586
587#ifdef INET6
588static int
589suitable_ifaddr6(ifname, ifaddr)
590	const char *ifname;
591	const struct sockaddr *ifaddr;
592{
593#ifndef __linux__
594	struct in6_ifreq ifr6;
595	int s;
596#endif
597
598	if (ifaddr->sa_family != AF_INET6)
599		return 0;
600
601	if (IN6_IS_ADDR_UNSPECIFIED(&((const struct sockaddr_in6 *)ifaddr)->sin6_addr)) {
602		plog(LLV_DEBUG, LOCATION, NULL,
603		     "discarding unsuitable unspecified v6 address\n");
604		return 0;
605	}
606
607	if (IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6 *)ifaddr)->sin6_addr)) {
608		plog(LLV_DEBUG, LOCATION, NULL,
609		     "discarding unsuitable loopback v6 address\n");
610		return 0;
611	}
612
613#ifndef __linux__
614	s = socket(PF_INET6, SOCK_DGRAM, 0);
615	if (s == -1) {
616		plog(LLV_ERROR, LOCATION, NULL,
617			"socket(SOCK_DGRAM) failed:%s\n", strerror(errno));
618		return 0;
619	}
620
621	memset(&ifr6, 0, sizeof(ifr6));
622	strncpy(ifr6.ifr_name, ifname, strlen(ifname));
623
624	ifr6.ifr_addr = *(const struct sockaddr_in6 *)ifaddr;
625
626	if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
627		plog(LLV_ERROR, LOCATION, NULL,
628			"ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno));
629		close(s);
630		return 0;
631	}
632
633	close(s);
634
635	if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED
636	 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED
637	 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
638		return 0;
639#endif
640
641	/* suitable */
642	return 1;
643}
644#endif
645
646int
647update_myaddrs()
648{
649#ifdef __linux__
650	char msg[BUFSIZ];
651	int len;
652	struct nlmsghdr *h = (void*)msg;
653	len = read(lcconf->rtsock, msg, sizeof(msg));
654	if (len < 0)
655		return errno == ENOBUFS;
656	if (len < sizeof(*h))
657		return 0;
658	if (h->nlmsg_pid) /* not from kernel! */
659		return 0;
660	if (h->nlmsg_type == RTM_NEWLINK)
661		return 0;
662	plog(LLV_DEBUG, LOCATION, NULL,
663		"netlink signals update interface address list\n");
664	return 1;
665#else
666	char msg[BUFSIZ];
667	int len;
668	struct rt_msghdr *rtm;
669
670	len = read(lcconf->rtsock, msg, sizeof(msg));
671	if (len < 0) {
672		plog(LLV_ERROR, LOCATION, NULL,
673			"read(PF_ROUTE) failed: %s\n",
674			strerror(errno));
675		return 0;
676	}
677	rtm = (struct rt_msghdr *)msg;
678	if (len < rtm->rtm_msglen) {
679		plog(LLV_ERROR, LOCATION, NULL,
680			"read(PF_ROUTE) short read\n");
681		return 0;
682	}
683	if (rtm->rtm_version != RTM_VERSION) {
684		plog(LLV_ERROR, LOCATION, NULL,
685			"routing socket version mismatch\n");
686		close(lcconf->rtsock);
687		lcconf->rtsock = -1;
688		return 0;
689	}
690	switch (rtm->rtm_type) {
691	case RTM_NEWADDR:
692	case RTM_DELADDR:
693#ifdef RTM_IFANNOUNCE
694	case RTM_IFANNOUNCE:
695#endif
696		break;
697	case RTM_DELETE:
698	case RTM_IFINFO:
699#ifdef RTM_OIFINFO
700	case RTM_OIFINFO:
701#endif
702	case RTM_MISS:
703		/* ignore this message silently */
704		return 0;
705	default:
706		plog(LLV_DEBUG, LOCATION, NULL,
707			"rtm msg %d not interesting\n", rtm->rtm_type);
708		return 0;
709	}
710	/* XXX more filters here? */
711
712	plog(LLV_DEBUG, LOCATION, NULL,
713		"caught rtm:%d, need update interface address list\n",
714		rtm->rtm_type);
715	return 1;
716#endif /* __linux__ */
717}
718
719/*
720 * initialize default port for ISAKMP to send, if no "listen"
721 * directive is specified in config file.
722 *
723 * DO NOT listen to wildcard addresses.  if you receive packets to
724 * wildcard address, you'll be in trouble (DoS attack possible by
725 * broadcast storm).
726 */
727int
728autoconf_myaddrsport()
729{
730	struct myaddrs *p;
731	int n;
732
733	plog(LLV_DEBUG, LOCATION, NULL,
734		"configuring default isakmp port.\n");
735
736#ifdef ENABLE_NATT
737	if (natt_enabled_in_rmconf ()) {
738		plog(LLV_NOTIFY, LOCATION, NULL, "NAT-T is enabled, autoconfiguring ports\n");
739		for (p = lcconf->myaddrs; p; p = p->next) {
740			struct myaddrs *new;
741			if (! p->udp_encap) {
742				new = dupmyaddr(p);
743				new->udp_encap = 1;
744			}
745		}
746	}
747#endif
748
749	for (p = lcconf->myaddrs, n = 0; p; p = p->next, n++) {
750		set_port (p->addr, p->udp_encap ? lcconf->port_isakmp_natt : lcconf->port_isakmp);
751	}
752	plog(LLV_DEBUG, LOCATION, NULL,
753		"%d addrs are configured successfully\n", n);
754
755	return 0;
756}
757
758/*
759 * get a port number to which racoon binded.
760 */
761u_short
762getmyaddrsport(local)
763	struct sockaddr *local;
764{
765	struct myaddrs *p, *bestmatch = NULL;
766	u_short bestmatch_port = PORT_ISAKMP;
767
768	/* get a relative port */
769	for (p = lcconf->myaddrs; p; p = p->next) {
770		if (!p->addr)
771			continue;
772		if (cmpsaddrwop(local, p->addr))
773			continue;
774
775		/* use first matching address regardless of port */
776		if (!bestmatch) {
777			bestmatch = p;
778			continue;
779		}
780
781		/* matching address with port PORT_ISAKMP */
782		if (extract_port(p->addr) == PORT_ISAKMP) {
783			bestmatch = p;
784			bestmatch_port = PORT_ISAKMP;
785		}
786	}
787
788	return bestmatch_port;
789}
790
791struct myaddrs *
792newmyaddr()
793{
794	struct myaddrs *new;
795
796	new = racoon_calloc(1, sizeof(*new));
797	if (new == NULL) {
798		plog(LLV_ERROR, LOCATION, NULL,
799			"failed to allocate buffer for myaddrs.\n");
800		return NULL;
801	}
802
803	new->next = NULL;
804	new->addr = NULL;
805	new->sock = -1;
806
807	return new;
808}
809
810struct myaddrs *
811dupmyaddr(struct myaddrs *old)
812{
813	struct myaddrs *new;
814
815	new = racoon_calloc(1, sizeof(*new));
816	if (new == NULL) {
817		plog(LLV_ERROR, LOCATION, NULL,
818			"failed to allocate buffer for myaddrs.\n");
819		return NULL;
820	}
821
822	/* Copy the whole structure and set the differences.  */
823	memcpy (new, old, sizeof (*new));
824	new->addr = dupsaddr (old->addr);
825	if (new->addr == NULL) {
826		plog(LLV_ERROR, LOCATION, NULL,
827			"failed to allocate buffer for myaddrs.\n");
828		racoon_free(new);
829		return NULL;
830	}
831	new->next = old->next;
832	old->next = new;
833
834	return new;
835}
836
837void
838insmyaddr(new, head)
839	struct myaddrs *new;
840	struct myaddrs **head;
841{
842	new->next = *head;
843	*head = new;
844}
845
846void
847delmyaddr(myaddr)
848	struct myaddrs *myaddr;
849{
850	if (myaddr->addr)
851		racoon_free(myaddr->addr);
852	racoon_free(myaddr);
853}
854
855int
856initmyaddr()
857{
858	/* initialize routing socket */
859	lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
860	if (lcconf->rtsock < 0) {
861		plog(LLV_ERROR, LOCATION, NULL,
862			"socket(PF_ROUTE) failed: %s",
863			strerror(errno));
864		return -1;
865	}
866	close_on_exec(lcconf->rtsock);
867
868#ifdef __linux__
869   {
870	struct sockaddr_nl nl;
871	u_int addr_len;
872
873	memset(&nl, 0, sizeof(nl));
874	nl.nl_family = AF_NETLINK;
875	nl.nl_groups = RTMGRP_IPV4_IFADDR|RTMGRP_LINK|RTMGRP_IPV6_IFADDR;
876
877	if (bind(lcconf->rtsock, (struct sockaddr*)&nl, sizeof(nl)) < 0) {
878		plog(LLV_ERROR, LOCATION, NULL,
879		     "bind(PF_NETLINK) failed: %s\n",
880		     strerror(errno));
881		return -1;
882	}
883	addr_len = sizeof(nl);
884	if (getsockname(lcconf->rtsock, (struct sockaddr*)&nl, &addr_len) < 0) {
885		plog(LLV_ERROR, LOCATION, NULL,
886		     "getsockname(PF_NETLINK) failed: %s\n",
887		     strerror(errno));
888		return -1;
889	}
890   }
891#endif
892
893	if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) {
894		grab_myaddrs();
895
896		if (autoconf_myaddrsport() < 0)
897			return -1;
898	}
899
900	return 0;
901}
902
903/* select the socket to be sent */
904/* should implement other method. */
905int
906getsockmyaddr(my)
907	struct sockaddr *my;
908{
909	struct myaddrs *p, *lastresort = NULL;
910#if defined(INET6) && defined(__linux__)
911	struct myaddrs *match_wo_scope_id = NULL;
912	int check_wo_scope_id = (my->sa_family == AF_INET6) &&
913		IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)my)->sin6_addr);
914#endif
915
916	for (p = lcconf->myaddrs; p; p = p->next) {
917		if (p->addr == NULL)
918			continue;
919		if (my->sa_family == p->addr->sa_family) {
920			lastresort = p;
921		} else continue;
922		if (sysdep_sa_len(my) == sysdep_sa_len(p->addr)
923		 && memcmp(my, p->addr, sysdep_sa_len(my)) == 0) {
924			break;
925		}
926#if defined(INET6) && defined(__linux__)
927		if (check_wo_scope_id && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)p->addr)->sin6_addr) &&
928			/* XXX: this depends on sin6_scope_id to be last
929			 * item in struct sockaddr_in6 */
930			memcmp(my, p->addr,
931				sysdep_sa_len(my) - sizeof(uint32_t)) == 0) {
932			match_wo_scope_id = p;
933		}
934#endif
935	}
936#if defined(INET6) && defined(__linux__)
937	if (!p)
938		p = match_wo_scope_id;
939#endif
940	if (!p)
941		p = lastresort;
942	if (!p) {
943		plog(LLV_ERROR, LOCATION, NULL,
944			"no socket matches address family %d\n",
945			my->sa_family);
946		return -1;
947	}
948
949	return p->sock;
950}
951