1/*	$NetBSD: grabmyaddr.c,v 1.29 2012/01/01 15:54:51 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.
18 *
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.
30 */
31
32#include "config.h"
33
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>
41
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
53
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"
61
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"
69
70static int kernel_receive __P((void *ctx, int fd));
71static int kernel_open_socket __P((void));
72static void kernel_sync __P((void));
73
74struct myaddr {
75	LIST_ENTRY(myaddr) chain;
76	struct sockaddr_storage addr;
77	int fd;
78	int udp_encap;
79};
80
81static LIST_HEAD(_myaddr_list_, myaddr) configured, opened;
82
83static void
84myaddr_delete(my)
85	struct myaddr *my;
86{
87	if (my->fd != -1)
88		isakmp_close(my->fd);
89	LIST_REMOVE(my, chain);
90	racoon_free(my);
91}
92
93static int
94myaddr_configured(addr)
95	struct sockaddr *addr;
96{
97	struct myaddr *cfg;
98
99	if (LIST_EMPTY(&configured))
100		return TRUE;
101
102	LIST_FOREACH(cfg, &configured, chain) {
103		if (cmpsaddr(addr, (struct sockaddr *) &cfg->addr) <= CMPSADDR_WILDPORT_MATCH)
104			return TRUE;
105	}
106
107	return FALSE;
108}
109
110static int
111myaddr_open(addr, udp_encap)
112	struct sockaddr *addr;
113	int udp_encap;
114{
115	struct myaddr *my;
116
117	/* Already open? */
118	LIST_FOREACH(my, &opened, chain) {
119		if (cmpsaddr(addr, (struct sockaddr *) &my->addr) <= CMPSADDR_WILDPORT_MATCH)
120			return TRUE;
121	}
122
123	my = racoon_calloc(1, sizeof(struct myaddr));
124	if (my == NULL)
125		return FALSE;
126
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;
132	}
133	my->udp_encap = udp_encap;
134	LIST_INSERT_HEAD(&opened, my, chain);
135	return TRUE;
136}
137
138static int
139myaddr_open_all_configured(addr)
140	struct sockaddr *addr;
141{
142	/* create all configured, not already opened addresses */
143	struct myaddr *cfg, *my;
144
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;
154		}
155	}
156
157	LIST_FOREACH(cfg, &configured, chain) {
158		if (addr != NULL &&
159		    cmpsaddr(addr, (struct sockaddr *) &cfg->addr) > CMPSADDR_WILDPORT_MATCH)
160			continue;
161		if (!myaddr_open((struct sockaddr *) &cfg->addr, cfg->udp_encap))
162			return FALSE;
163	}
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
176	}
177	return TRUE;
178}
179
180static void
181myaddr_close_all_open(addr)
182	struct sockaddr *addr;
183{
184	/* delete all matching open sockets */
185	struct myaddr *my, *next;
186
187	for (my = LIST_FIRST(&opened); my; my = next) {
188		next = LIST_NEXT(my, chain);
189
190		if (cmpsaddr((struct sockaddr *) addr,
191			     (struct sockaddr *) &my->addr)
192		    <= CMPSADDR_WOP_MATCH)
193			myaddr_delete(my);
194	}
195}
196
197static void
198myaddr_flush_list(list)
199	struct _myaddr_list_ *list;
200{
201	struct myaddr *my, *next;
202
203	for (my = LIST_FIRST(list); my; my = next) {
204		next = LIST_NEXT(my, chain);
205		myaddr_delete(my);
206	}
207}
208
209void
210myaddr_flush()
211{
212	myaddr_flush_list(&configured);
213}
214
215int
216myaddr_listen(addr, udp_encap)
217	struct sockaddr *addr;
218	int udp_encap;
219{
220	struct myaddr *my;
221
222	if (sysdep_sa_len(addr) > sizeof(my->addr)) {
223		plog(LLV_ERROR, LOCATION, NULL,
224		     "sockaddr size larger than sockaddr_storage\n");
225		return -1;
226	}
227
228	my = racoon_calloc(1, sizeof(struct myaddr));
229	if (my == NULL)
230		return -1;
231
232	memcpy(&my->addr, addr, sysdep_sa_len(addr));
233	my->udp_encap = udp_encap;
234	my->fd = -1;
235	LIST_INSERT_HEAD(&configured, my, chain);
236
237	return 0;
238}
239
240void
241myaddr_sync()
242{
243	struct myaddr *my, *next;
244
245	if (!lcconf->strict_address) {
246		kernel_sync();
247
248		/* delete all existing listeners which are not configured */
249		for (my = LIST_FIRST(&opened); my; my = next) {
250			next = LIST_NEXT(my, chain);
251
252			if (!myaddr_configured((struct sockaddr *) &my->addr))
253				myaddr_delete(my);
254		}
255	}
256}
257
258int
259myaddr_getfd(addr)
260        struct sockaddr *addr;
261{
262	struct myaddr *my;
263
264	LIST_FOREACH(my, &opened, chain) {
265		if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH)
266			return my->fd;
267	}
268
269	return -1;
270}
271
272int
273myaddr_getsport(addr)
274	struct sockaddr *addr;
275{
276	struct myaddr *my;
277
278	LIST_FOREACH(my, &opened, chain) {
279		if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH)
280			return extract_port((struct sockaddr *) &my->addr);
281	}
282
283	return -1;
284}
285
286void
287myaddr_init_lists()
288{
289	LIST_INIT(&configured);
290	LIST_INIT(&opened);
291}
292
293int
294myaddr_init()
295{
296        if (!lcconf->strict_address) {
297		lcconf->rtsock = kernel_open_socket();
298		if (lcconf->rtsock < 0)
299			return -1;
300		monitor_fd(lcconf->rtsock, kernel_receive, NULL, 0);
301	} else {
302		lcconf->rtsock = -1;
303		if (!myaddr_open_all_configured(NULL))
304			return -1;
305	}
306	return 0;
307}
308
309void
310myaddr_close()
311{
312	myaddr_flush_list(&configured);
313	myaddr_flush_list(&opened);
314	if (lcconf->rtsock != -1) {
315		unmonitor_fd(lcconf->rtsock);
316		close(lcconf->rtsock);
317	}
318}
319
320#if defined(USE_NETLINK)
321
322static int netlink_fd = -1;
323
324#define NLMSG_TAIL(nmsg) \
325	((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
326
327static void
328parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
329{
330	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
331	while (RTA_OK(rta, len)) {
332		if (rta->rta_type <= max)
333			tb[rta->rta_type] = rta;
334		rta = RTA_NEXT(rta,len);
335	}
336}
337
338static int
339netlink_add_rtattr_l(struct nlmsghdr *n, int maxlen, int type,
340		     const void *data, int alen)
341{
342	int len = RTA_LENGTH(alen);
343	struct rtattr *rta;
344
345	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
346		return FALSE;
347
348	rta = NLMSG_TAIL(n);
349	rta->rta_type = type;
350	rta->rta_len = len;
351	memcpy(RTA_DATA(rta), data, alen);
352	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
353	return TRUE;
354}
355
356static int
357netlink_enumerate(fd, family, type)
358	int fd;
359	int family;
360	int type;
361{
362	struct {
363		struct nlmsghdr nlh;
364		struct rtgenmsg g;
365	} req;
366	struct sockaddr_nl addr;
367	static __u32 seq = 0;
368
369	memset(&addr, 0, sizeof(addr));
370	addr.nl_family = AF_NETLINK;
371
372	memset(&req, 0, sizeof(req));
373	req.nlh.nlmsg_len = sizeof(req);
374	req.nlh.nlmsg_type = type;
375	req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
376	req.nlh.nlmsg_pid = 0;
377	req.nlh.nlmsg_seq = ++seq;
378	req.g.rtgen_family = family;
379
380	return sendto(fd, (void *) &req, sizeof(req), 0,
381		      (struct sockaddr *) &addr, sizeof(addr)) >= 0;
382}
383
384static void
385netlink_add_del_address(int add, struct sockaddr *saddr)
386{
387	plog(LLV_DEBUG, LOCATION, NULL,
388	     "Netlink: address %s %s\n",
389	     saddrwop2str((struct sockaddr *) saddr),
390	     add ? "added" : "deleted");
391
392	if (add)
393		myaddr_open_all_configured(saddr);
394	else
395		myaddr_close_all_open(saddr);
396}
397
398#ifdef INET6
399static int
400netlink_process_addr(struct nlmsghdr *h)
401{
402	struct sockaddr_storage addr;
403	struct ifaddrmsg *ifa;
404	struct rtattr *rta[IFA_MAX+1];
405	struct sockaddr_in6 *sin6;
406
407	ifa = NLMSG_DATA(h);
408	parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h));
409
410	if (ifa->ifa_family != AF_INET6)
411		return 0;
412	if (ifa->ifa_flags & IFA_F_TENTATIVE)
413		return 0;
414	if (rta[IFA_LOCAL] == NULL)
415		rta[IFA_LOCAL] = rta[IFA_ADDRESS];
416	if (rta[IFA_LOCAL] == NULL)
417		return 0;
418
419	memset(&addr, 0, sizeof(addr));
420	addr.ss_family = ifa->ifa_family;
421	sin6 = (struct sockaddr_in6 *) &addr;
422	memcpy(&sin6->sin6_addr, RTA_DATA(rta[IFA_LOCAL]),
423		sizeof(sin6->sin6_addr));
424	if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
425		return 0;
426	sin6->sin6_scope_id = ifa->ifa_index;
427
428	netlink_add_del_address(h->nlmsg_type == RTM_NEWADDR,
429				(struct sockaddr *) &addr);
430
431	return 0;
432}
433#endif
434
435static int
436netlink_route_is_local(int family, const unsigned char *addr, size_t addr_len)
437{
438	struct {
439		struct nlmsghdr n;
440		struct rtmsg    r;
441		char            buf[1024];
442	} req;
443	struct rtmsg *r = NLMSG_DATA(&req.n);
444	struct rtattr *rta[RTA_MAX+1];
445	struct sockaddr_nl nladdr;
446	ssize_t rlen;
447
448	memset(&req, 0, sizeof(req));
449	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
450	req.n.nlmsg_flags = NLM_F_REQUEST;
451	req.n.nlmsg_type = RTM_GETROUTE;
452	req.r.rtm_family = family;
453	netlink_add_rtattr_l(&req.n, sizeof(req), RTA_DST,
454			     addr, addr_len);
455	req.r.rtm_dst_len = addr_len * 8;
456
457	memset(&nladdr, 0, sizeof(nladdr));
458	nladdr.nl_family = AF_NETLINK;
459
460	if (sendto(netlink_fd, &req, sizeof(req), 0,
461		   (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0)
462		return 0;
463	rlen = recv(netlink_fd, &req, sizeof(req), 0);
464	if (rlen < 0)
465		return 0;
466
467	return  req.n.nlmsg_type == RTM_NEWROUTE &&
468		req.r.rtm_type == RTN_LOCAL;
469}
470
471static int
472netlink_process_route(struct nlmsghdr *h)
473{
474	struct sockaddr_storage addr;
475	struct rtmsg *rtm;
476	struct rtattr *rta[RTA_MAX+1];
477	struct sockaddr_in *sin;
478#ifdef INET6
479	struct sockaddr_in6 *sin6;
480#endif
481
482	rtm = NLMSG_DATA(h);
483
484	/* local IP addresses get local route in the local table */
485	if (rtm->rtm_type != RTN_LOCAL ||
486	    rtm->rtm_table != RT_TABLE_LOCAL)
487		return 0;
488
489	parse_rtattr(rta, IFA_MAX, RTM_RTA(rtm), IFA_PAYLOAD(h));
490	if (rta[RTA_DST] == NULL)
491 		return 0;
492
493	/* setup the socket address */
494	memset(&addr, 0, sizeof(addr));
495	addr.ss_family = rtm->rtm_family;
496	switch (rtm->rtm_family) {
497	case AF_INET:
498		sin = (struct sockaddr_in *) &addr;
499		memcpy(&sin->sin_addr, RTA_DATA(rta[RTA_DST]),
500			sizeof(sin->sin_addr));
501		break;
502#ifdef INET6
503	case AF_INET6:
504		sin6 = (struct sockaddr_in6 *) &addr;
505		memcpy(&sin6->sin6_addr, RTA_DATA(rta[RTA_DST]),
506			sizeof(sin6->sin6_addr));
507		/* Link-local addresses are handled with RTM_NEWADDR
508		 * notifications */
509		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
510			return 0;
511		break;
512#endif
513	default:
514		return 0;
515	}
516
517	/* If local route was deleted, check if there is still local
518	 * route for the same IP on another interface */
519	if (h->nlmsg_type == RTM_DELROUTE &&
520	    netlink_route_is_local(rtm->rtm_family,
521				   RTA_DATA(rta[RTA_DST]),
522				   RTA_PAYLOAD(rta[RTA_DST]))) {
523		plog(LLV_DEBUG, LOCATION, NULL,
524			"Netlink: not deleting %s yet, it exists still\n",
525			saddrwop2str((struct sockaddr *) &addr));
526		return 0;
527	}
528
529	netlink_add_del_address(h->nlmsg_type == RTM_NEWROUTE,
530				(struct sockaddr *) &addr);
531	return 0;
532}
533
534static int
535netlink_process(struct nlmsghdr *h)
536{
537	switch (h->nlmsg_type) {
538#ifdef INET6
539	case RTM_NEWADDR:
540	case RTM_DELADDR:
541		return netlink_process_addr(h);
542#endif
543	case RTM_NEWROUTE:
544	case RTM_DELROUTE:
545		return netlink_process_route(h);
546	}
547	return 0;
548}
549
550static int
551kernel_receive(ctx, fd)
552	void *ctx;
553	int fd;
554{
555	struct sockaddr_nl nladdr;
556	struct iovec iov;
557	struct msghdr msg = {
558		.msg_name = &nladdr,
559		.msg_namelen = sizeof(nladdr),
560		.msg_iov = &iov,
561		.msg_iovlen = 1,
562	};
563	struct nlmsghdr *h;
564	int len, status;
565	char buf[16*1024];
566
567	iov.iov_base = buf;
568	while (1) {
569		iov.iov_len = sizeof(buf);
570		status = recvmsg(fd, &msg, MSG_DONTWAIT);
571		if (status < 0) {
572			if (errno == EINTR)
573				continue;
574			if (errno == EAGAIN)
575				return FALSE;
576			continue;
577		}
578		if (status == 0)
579			return FALSE;
580
581		h = (struct nlmsghdr *) buf;
582		while (NLMSG_OK(h, status)) {
583			netlink_process(h);
584			h = NLMSG_NEXT(h, status);
585		}
586	}
587
588	return TRUE;
589}
590
591static int
592netlink_open_socket()
593{
594	int fd;
595
596	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
597	if (fd < 0) {
598		plog(LLV_ERROR, LOCATION, NULL,
599			"socket(PF_NETLINK) failed: %s",
600			strerror(errno));
601		return -1;
602	}
603	close_on_exec(fd);
604	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
605		plog(LLV_WARNING, LOCATION, NULL,
606		     "failed to put socket in non-blocking mode\n");
607
608	return fd;
609}
610
611static int
612kernel_open_socket()
613{
614	struct sockaddr_nl nl;
615	int fd;
616
617	if (netlink_fd < 0) {
618		netlink_fd = netlink_open_socket();
619		if (netlink_fd < 0)
620			return -1;
621	}
622
623	fd = netlink_open_socket();
624	if (fd < 0)
625		return fd;
626
627	/* We monitor IPv4 addresses using RTMGRP_IPV4_ROUTE group
628	 * the get the RTN_LOCAL routes which are automatically added
629	 * by kernel. This is because:
630	 *  - Linux kernel has a bug that calling bind() immediately
631	 *    after IPv4 RTM_NEWADDR event can fail
632	 *  - if IP is configured in multiple interfaces, we get
633	 *    RTM_DELADDR for each of them. RTN_LOCAL gets deleted only
634	 *    after the last IP address is deconfigured.
635	 * The latter reason is also why I chose to use route
636	 * notifications for IPv6. However, we do need to use RTM_NEWADDR
637	 * for the link-local IPv6 addresses to get the interface index
638	 * that is needed in bind().
639	 */
640	memset(&nl, 0, sizeof(nl));
641	nl.nl_family = AF_NETLINK;
642	nl.nl_groups = RTMGRP_IPV4_ROUTE
643#ifdef INET6
644			| RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE
645#endif
646			;
647	if (bind(fd, (struct sockaddr*) &nl, sizeof(nl)) < 0) {
648		plog(LLV_ERROR, LOCATION, NULL,
649		     "bind(PF_NETLINK) failed: %s\n",
650		     strerror(errno));
651		close(fd);
652		return -1;
653	}
654	return fd;
655}
656
657static void
658kernel_sync()
659{
660	int fd = lcconf->rtsock;
661
662	/* refresh addresses */
663	if (!netlink_enumerate(fd, PF_UNSPEC, RTM_GETROUTE)) {
664		plog(LLV_ERROR, LOCATION, NULL,
665		     "unable to enumerate addresses: %s\n",
666		     strerror(errno));
667	}
668	while (kernel_receive(NULL, fd) == TRUE);
669
670#ifdef INET6
671	if (!netlink_enumerate(fd, PF_INET6, RTM_GETADDR)) {
672		plog(LLV_ERROR, LOCATION, NULL,
673		     "unable to enumerate addresses: %s\n",
674		     strerror(errno));
675	}
676	while (kernel_receive(NULL, fd) == TRUE);
677#endif
678}
679
680#elif defined(USE_ROUTE)
681
682#define ROUNDUP(a) \
683  ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
684
685#define SAROUNDUP(X)   ROUNDUP(((struct sockaddr *)(X))->sa_len)
686
687static size_t
688parse_address(start, end, dest)
689	caddr_t start;
690	caddr_t end;
691	struct sockaddr_storage *dest;
692{
693	int len;
694
695	if (start >= end)
696		return 0;
697
698	len = SAROUNDUP(start);
699	if (start + len > end)
700		return end - start;
701
702	if (dest != NULL && len <= sizeof(struct sockaddr_storage))
703		memcpy(dest, start, len);
704
705	return len;
706}
707
708static void
709parse_addresses(start, end, flags, addr)
710	caddr_t start;
711	caddr_t end;
712	int flags;
713	struct sockaddr_storage *addr;
714{
715	memset(addr, 0, sizeof(*addr));
716	if (flags & RTA_DST)
717		start += parse_address(start, end, NULL);
718	if (flags & RTA_GATEWAY)
719		start += parse_address(start, end, NULL);
720	if (flags & RTA_NETMASK)
721		start += parse_address(start, end, NULL);
722	if (flags & RTA_GENMASK)
723		start += parse_address(start, end, NULL);
724	if (flags & RTA_IFP)
725		start += parse_address(start, end, NULL);
726	if (flags & RTA_IFA)
727		start += parse_address(start, end, addr);
728	if (flags & RTA_AUTHOR)
729		start += parse_address(start, end, NULL);
730	if (flags & RTA_BRD)
731		start += parse_address(start, end, NULL);
732}
733
734static void
735kernel_handle_message(msg)
736	caddr_t msg;
737{
738	struct rt_msghdr *rtm = (struct rt_msghdr *) msg;
739	struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg;
740	struct sockaddr_storage addr;
741
742	switch (rtm->rtm_type) {
743	case RTM_NEWADDR:
744		parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
745				ifa->ifam_addrs, &addr);
746		myaddr_open_all_configured((struct sockaddr *) &addr);
747		break;
748	case RTM_DELADDR:
749		parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
750				ifa->ifam_addrs, &addr);
751		myaddr_close_all_open((struct sockaddr *) &addr);
752		break;
753	case RTM_ADD:
754	case RTM_DELETE:
755	case RTM_CHANGE:
756	case RTM_MISS:
757	case RTM_IFINFO:
758#ifdef RTM_OIFINFO
759	case RTM_OIFINFO:
760#endif
761#ifdef RTM_NEWMADDR
762	case RTM_NEWMADDR:
763	case RTM_DELMADDR:
764#endif
765#ifdef RTM_IFANNOUNCE
766	case RTM_IFANNOUNCE:
767#endif
768		break;
769	default:
770		plog(LLV_WARNING, LOCATION, NULL,
771		     "unrecognized route message with rtm_type: %d",
772		     rtm->rtm_type);
773		break;
774	}
775}
776
777static int
778kernel_receive(ctx, fd)
779	void *ctx;
780	int fd;
781{
782	char buf[16*1024];
783	struct rt_msghdr *rtm = (struct rt_msghdr *) buf;
784	int len;
785
786	len = read(fd, &buf, sizeof(buf));
787	if (len <= 0) {
788		if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
789			plog(LLV_WARNING, LOCATION, NULL,
790			     "routing socket error: %s", strerror(errno));
791		return FALSE;
792	}
793
794	if (rtm->rtm_msglen != len) {
795		plog(LLV_WARNING, LOCATION, NULL,
796		     "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n",
797		     rtm->rtm_msglen, len, rtm->rtm_type);
798		return FALSE;
799	}
800
801	kernel_handle_message(buf);
802	return TRUE;
803}
804
805static int
806kernel_open_socket()
807{
808	int fd;
809
810	fd = socket(PF_ROUTE, SOCK_RAW, 0);
811	if (fd < 0) {
812		plog(LLV_ERROR, LOCATION, NULL,
813			"socket(PF_ROUTE) failed: %s",
814			strerror(errno));
815		return -1;
816	}
817	close_on_exec(fd);
818	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
819		plog(LLV_WARNING, LOCATION, NULL,
820		     "failed to put socket in non-blocking mode\n");
821
822	return fd;
823}
824
825static void
826kernel_sync()
827{
828	caddr_t ref, buf, end;
829	size_t bufsiz;
830	struct if_msghdr *ifm;
831	struct interface *ifp;
832
833#define MIBSIZ 6
834	int mib[MIBSIZ] = {
835		CTL_NET,
836		PF_ROUTE,
837		0,
838		0, /*  AF_INET & AF_INET6 */
839		NET_RT_IFLIST,
840		0
841	};
842
843	if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) {
844		plog(LLV_WARNING, LOCATION, NULL,
845		     "sysctl() error: %s", strerror(errno));
846		return;
847	}
848
849	ref = buf = racoon_malloc(bufsiz);
850
851	if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) {
852		/* Parse both interfaces and addresses. */
853		for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) {
854			ifm = (struct if_msghdr *) buf;
855			kernel_handle_message(buf);
856		}
857	} else {
858		plog(LLV_WARNING, LOCATION, NULL,
859		     "sysctl() error: %s", strerror(errno));
860	}
861
862	racoon_free(ref);
863}
864
865#else
866
867#error No supported interface to monitor local addresses.
868
869#endif
870