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