grabmyaddr.c revision 1.31
1/*	$NetBSD: grabmyaddr.c,v 1.31 2013/04/12 09:53:10 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	int port = 0, wport;
278
279	LIST_FOREACH(my, &opened, chain) {
280		switch (cmpsaddr((struct sockaddr *) &my->addr, addr)) {
281		case CMPSADDR_MATCH:
282			return extract_port((struct sockaddr *) &my->addr);
283		case CMPSADDR_WILDPORT_MATCH:
284			wport = extract_port((struct sockaddr *) &my->addr);
285			if (port == 0 || wport < port)
286				port = wport;
287			break;
288		}
289	}
290
291	if (port == 0)
292		port = PORT_ISAKMP;
293
294	return port;
295}
296
297void
298myaddr_init_lists()
299{
300	LIST_INIT(&configured);
301	LIST_INIT(&opened);
302}
303
304int
305myaddr_init()
306{
307        if (!lcconf->strict_address) {
308		lcconf->rtsock = kernel_open_socket();
309		if (lcconf->rtsock < 0)
310			return -1;
311		monitor_fd(lcconf->rtsock, kernel_receive, NULL, 0);
312	} else {
313		lcconf->rtsock = -1;
314		if (!myaddr_open_all_configured(NULL))
315			return -1;
316	}
317	return 0;
318}
319
320void
321myaddr_close()
322{
323	myaddr_flush_list(&configured);
324	myaddr_flush_list(&opened);
325	if (lcconf->rtsock != -1) {
326		unmonitor_fd(lcconf->rtsock);
327		close(lcconf->rtsock);
328	}
329}
330
331#if defined(USE_NETLINK)
332
333static int netlink_fd = -1;
334
335#define NLMSG_TAIL(nmsg) \
336	((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
337
338static void
339parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
340{
341	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
342	while (RTA_OK(rta, len)) {
343		if (rta->rta_type <= max)
344			tb[rta->rta_type] = rta;
345		rta = RTA_NEXT(rta,len);
346	}
347}
348
349static int
350netlink_add_rtattr_l(struct nlmsghdr *n, int maxlen, int type,
351		     const void *data, int alen)
352{
353	int len = RTA_LENGTH(alen);
354	struct rtattr *rta;
355
356	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
357		return FALSE;
358
359	rta = NLMSG_TAIL(n);
360	rta->rta_type = type;
361	rta->rta_len = len;
362	memcpy(RTA_DATA(rta), data, alen);
363	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
364	return TRUE;
365}
366
367static int
368netlink_enumerate(fd, family, type)
369	int fd;
370	int family;
371	int type;
372{
373	struct {
374		struct nlmsghdr nlh;
375		struct rtgenmsg g;
376	} req;
377	struct sockaddr_nl addr;
378	static __u32 seq = 0;
379
380	memset(&addr, 0, sizeof(addr));
381	addr.nl_family = AF_NETLINK;
382
383	memset(&req, 0, sizeof(req));
384	req.nlh.nlmsg_len = sizeof(req);
385	req.nlh.nlmsg_type = type;
386	req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
387	req.nlh.nlmsg_pid = 0;
388	req.nlh.nlmsg_seq = ++seq;
389	req.g.rtgen_family = family;
390
391	return sendto(fd, (void *) &req, sizeof(req), 0,
392		      (struct sockaddr *) &addr, sizeof(addr)) >= 0;
393}
394
395static void
396netlink_add_del_address(int add, struct sockaddr *saddr)
397{
398	plog(LLV_DEBUG, LOCATION, NULL,
399	     "Netlink: address %s %s\n",
400	     saddrwop2str((struct sockaddr *) saddr),
401	     add ? "added" : "deleted");
402
403	if (add)
404		myaddr_open_all_configured(saddr);
405	else
406		myaddr_close_all_open(saddr);
407}
408
409#ifdef INET6
410static int
411netlink_process_addr(struct nlmsghdr *h)
412{
413	struct sockaddr_storage addr;
414	struct ifaddrmsg *ifa;
415	struct rtattr *rta[IFA_MAX+1];
416	struct sockaddr_in6 *sin6;
417
418	ifa = NLMSG_DATA(h);
419	parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h));
420
421	if (ifa->ifa_family != AF_INET6)
422		return 0;
423	if (ifa->ifa_flags & IFA_F_TENTATIVE)
424		return 0;
425	if (rta[IFA_LOCAL] == NULL)
426		rta[IFA_LOCAL] = rta[IFA_ADDRESS];
427	if (rta[IFA_LOCAL] == NULL)
428		return 0;
429
430	memset(&addr, 0, sizeof(addr));
431	addr.ss_family = ifa->ifa_family;
432	sin6 = (struct sockaddr_in6 *) &addr;
433	memcpy(&sin6->sin6_addr, RTA_DATA(rta[IFA_LOCAL]),
434		sizeof(sin6->sin6_addr));
435	if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
436		return 0;
437	sin6->sin6_scope_id = ifa->ifa_index;
438
439	netlink_add_del_address(h->nlmsg_type == RTM_NEWADDR,
440				(struct sockaddr *) &addr);
441
442	return 0;
443}
444#endif
445
446static int
447netlink_route_is_local(int family, const unsigned char *addr, size_t addr_len)
448{
449	struct {
450		struct nlmsghdr n;
451		struct rtmsg    r;
452		char            buf[1024];
453	} req;
454	struct rtmsg *r = NLMSG_DATA(&req.n);
455	struct rtattr *rta[RTA_MAX+1];
456	struct sockaddr_nl nladdr;
457	ssize_t rlen;
458
459	memset(&req, 0, sizeof(req));
460	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
461	req.n.nlmsg_flags = NLM_F_REQUEST;
462	req.n.nlmsg_type = RTM_GETROUTE;
463	req.r.rtm_family = family;
464	netlink_add_rtattr_l(&req.n, sizeof(req), RTA_DST,
465			     addr, addr_len);
466	req.r.rtm_dst_len = addr_len * 8;
467
468	memset(&nladdr, 0, sizeof(nladdr));
469	nladdr.nl_family = AF_NETLINK;
470
471	if (sendto(netlink_fd, &req, sizeof(req), 0,
472		   (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0)
473		return 0;
474	rlen = recv(netlink_fd, &req, sizeof(req), 0);
475	if (rlen < 0)
476		return 0;
477
478	return  req.n.nlmsg_type == RTM_NEWROUTE &&
479		req.r.rtm_type == RTN_LOCAL;
480}
481
482static int
483netlink_process_route(struct nlmsghdr *h)
484{
485	struct sockaddr_storage addr;
486	struct rtmsg *rtm;
487	struct rtattr *rta[RTA_MAX+1];
488	struct sockaddr_in *sin;
489#ifdef INET6
490	struct sockaddr_in6 *sin6;
491#endif
492
493	rtm = NLMSG_DATA(h);
494
495	/* local IP addresses get local route in the local table */
496	if (rtm->rtm_type != RTN_LOCAL ||
497	    rtm->rtm_table != RT_TABLE_LOCAL)
498		return 0;
499
500	parse_rtattr(rta, IFA_MAX, RTM_RTA(rtm), IFA_PAYLOAD(h));
501	if (rta[RTA_DST] == NULL)
502 		return 0;
503
504	/* setup the socket address */
505	memset(&addr, 0, sizeof(addr));
506	addr.ss_family = rtm->rtm_family;
507	switch (rtm->rtm_family) {
508	case AF_INET:
509		sin = (struct sockaddr_in *) &addr;
510		memcpy(&sin->sin_addr, RTA_DATA(rta[RTA_DST]),
511			sizeof(sin->sin_addr));
512		break;
513#ifdef INET6
514	case AF_INET6:
515		sin6 = (struct sockaddr_in6 *) &addr;
516		memcpy(&sin6->sin6_addr, RTA_DATA(rta[RTA_DST]),
517			sizeof(sin6->sin6_addr));
518		/* Link-local addresses are handled with RTM_NEWADDR
519		 * notifications */
520		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
521			return 0;
522		break;
523#endif
524	default:
525		return 0;
526	}
527
528	/* If local route was deleted, check if there is still local
529	 * route for the same IP on another interface */
530	if (h->nlmsg_type == RTM_DELROUTE &&
531	    netlink_route_is_local(rtm->rtm_family,
532				   RTA_DATA(rta[RTA_DST]),
533				   RTA_PAYLOAD(rta[RTA_DST]))) {
534		plog(LLV_DEBUG, LOCATION, NULL,
535			"Netlink: not deleting %s yet, it exists still\n",
536			saddrwop2str((struct sockaddr *) &addr));
537		return 0;
538	}
539
540	netlink_add_del_address(h->nlmsg_type == RTM_NEWROUTE,
541				(struct sockaddr *) &addr);
542	return 0;
543}
544
545static int
546netlink_process(struct nlmsghdr *h)
547{
548	switch (h->nlmsg_type) {
549#ifdef INET6
550	case RTM_NEWADDR:
551	case RTM_DELADDR:
552		return netlink_process_addr(h);
553#endif
554	case RTM_NEWROUTE:
555	case RTM_DELROUTE:
556		return netlink_process_route(h);
557	}
558	return 0;
559}
560
561static int
562kernel_receive(ctx, fd)
563	void *ctx;
564	int fd;
565{
566	struct sockaddr_nl nladdr;
567	struct iovec iov;
568	struct msghdr msg = {
569		.msg_name = &nladdr,
570		.msg_namelen = sizeof(nladdr),
571		.msg_iov = &iov,
572		.msg_iovlen = 1,
573	};
574	struct nlmsghdr *h;
575	int len, status;
576	char buf[16*1024];
577
578	iov.iov_base = buf;
579	while (1) {
580		iov.iov_len = sizeof(buf);
581		status = recvmsg(fd, &msg, MSG_DONTWAIT);
582		if (status < 0) {
583			if (errno == EINTR)
584				continue;
585			if (errno == EAGAIN)
586				return FALSE;
587			continue;
588		}
589		if (status == 0)
590			return FALSE;
591
592		h = (struct nlmsghdr *) buf;
593		while (NLMSG_OK(h, status)) {
594			netlink_process(h);
595			h = NLMSG_NEXT(h, status);
596		}
597	}
598
599	return TRUE;
600}
601
602static int
603netlink_open_socket()
604{
605	int fd;
606
607	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
608	if (fd < 0) {
609		plog(LLV_ERROR, LOCATION, NULL,
610			"socket(PF_NETLINK) failed: %s",
611			strerror(errno));
612		return -1;
613	}
614	close_on_exec(fd);
615	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
616		plog(LLV_WARNING, LOCATION, NULL,
617		     "failed to put socket in non-blocking mode\n");
618
619	return fd;
620}
621
622static int
623kernel_open_socket()
624{
625	struct sockaddr_nl nl;
626	int fd;
627
628	if (netlink_fd < 0) {
629		netlink_fd = netlink_open_socket();
630		if (netlink_fd < 0)
631			return -1;
632	}
633
634	fd = netlink_open_socket();
635	if (fd < 0)
636		return fd;
637
638	/* We monitor IPv4 addresses using RTMGRP_IPV4_ROUTE group
639	 * the get the RTN_LOCAL routes which are automatically added
640	 * by kernel. This is because:
641	 *  - Linux kernel has a bug that calling bind() immediately
642	 *    after IPv4 RTM_NEWADDR event can fail
643	 *  - if IP is configured in multiple interfaces, we get
644	 *    RTM_DELADDR for each of them. RTN_LOCAL gets deleted only
645	 *    after the last IP address is deconfigured.
646	 * The latter reason is also why I chose to use route
647	 * notifications for IPv6. However, we do need to use RTM_NEWADDR
648	 * for the link-local IPv6 addresses to get the interface index
649	 * that is needed in bind().
650	 */
651	memset(&nl, 0, sizeof(nl));
652	nl.nl_family = AF_NETLINK;
653	nl.nl_groups = RTMGRP_IPV4_ROUTE
654#ifdef INET6
655			| RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE
656#endif
657			;
658	if (bind(fd, (struct sockaddr*) &nl, sizeof(nl)) < 0) {
659		plog(LLV_ERROR, LOCATION, NULL,
660		     "bind(PF_NETLINK) failed: %s\n",
661		     strerror(errno));
662		close(fd);
663		return -1;
664	}
665	return fd;
666}
667
668static void
669kernel_sync()
670{
671	int fd = lcconf->rtsock;
672
673	/* refresh addresses */
674	if (!netlink_enumerate(fd, PF_UNSPEC, RTM_GETROUTE)) {
675		plog(LLV_ERROR, LOCATION, NULL,
676		     "unable to enumerate addresses: %s\n",
677		     strerror(errno));
678	}
679	while (kernel_receive(NULL, fd) == TRUE);
680
681#ifdef INET6
682	if (!netlink_enumerate(fd, PF_INET6, RTM_GETADDR)) {
683		plog(LLV_ERROR, LOCATION, NULL,
684		     "unable to enumerate addresses: %s\n",
685		     strerror(errno));
686	}
687	while (kernel_receive(NULL, fd) == TRUE);
688#endif
689}
690
691#elif defined(USE_ROUTE)
692
693#define ROUNDUP(a) \
694  ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
695
696#define SAROUNDUP(X)   ROUNDUP(((struct sockaddr *)(X))->sa_len)
697
698static size_t
699parse_address(start, end, dest)
700	caddr_t start;
701	caddr_t end;
702	struct sockaddr_storage *dest;
703{
704	int len;
705
706	if (start >= end)
707		return 0;
708
709	len = SAROUNDUP(start);
710	if (start + len > end)
711		return end - start;
712
713	if (dest != NULL && len <= sizeof(struct sockaddr_storage))
714		memcpy(dest, start, len);
715
716	return len;
717}
718
719static void
720parse_addresses(start, end, flags, addr)
721	caddr_t start;
722	caddr_t end;
723	int flags;
724	struct sockaddr_storage *addr;
725{
726	memset(addr, 0, sizeof(*addr));
727	if (flags & RTA_DST)
728		start += parse_address(start, end, NULL);
729	if (flags & RTA_GATEWAY)
730		start += parse_address(start, end, NULL);
731	if (flags & RTA_NETMASK)
732		start += parse_address(start, end, NULL);
733	if (flags & RTA_GENMASK)
734		start += parse_address(start, end, NULL);
735	if (flags & RTA_IFP)
736		start += parse_address(start, end, NULL);
737	if (flags & RTA_IFA)
738		start += parse_address(start, end, addr);
739	if (flags & RTA_AUTHOR)
740		start += parse_address(start, end, NULL);
741	if (flags & RTA_BRD)
742		start += parse_address(start, end, NULL);
743}
744
745static void
746kernel_handle_message(msg)
747	caddr_t msg;
748{
749	struct rt_msghdr *rtm = (struct rt_msghdr *) msg;
750	struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg;
751	struct sockaddr_storage addr;
752
753	switch (rtm->rtm_type) {
754	case RTM_NEWADDR:
755		parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
756				ifa->ifam_addrs, &addr);
757		myaddr_open_all_configured((struct sockaddr *) &addr);
758		break;
759	case RTM_DELADDR:
760		parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
761				ifa->ifam_addrs, &addr);
762		myaddr_close_all_open((struct sockaddr *) &addr);
763		break;
764	case RTM_ADD:
765	case RTM_DELETE:
766	case RTM_CHANGE:
767	case RTM_GET:
768	case RTM_MISS:
769	case RTM_IFINFO:
770#ifdef RTM_OIFINFO
771	case RTM_OIFINFO:
772#endif
773#ifdef RTM_NEWMADDR
774	case RTM_NEWMADDR:
775	case RTM_DELMADDR:
776#endif
777#ifdef RTM_IFANNOUNCE
778	case RTM_IFANNOUNCE:
779#endif
780		break;
781	default:
782		plog(LLV_WARNING, LOCATION, NULL,
783		     "unrecognized route message with rtm_type: %d\n",
784		     rtm->rtm_type);
785		break;
786	}
787}
788
789static int
790kernel_receive(ctx, fd)
791	void *ctx;
792	int fd;
793{
794	char buf[16*1024];
795	struct rt_msghdr *rtm = (struct rt_msghdr *) buf;
796	int len;
797
798	len = read(fd, &buf, sizeof(buf));
799	if (len <= 0) {
800		if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
801			plog(LLV_WARNING, LOCATION, NULL,
802			     "routing socket error: %s", strerror(errno));
803		return FALSE;
804	}
805
806	if (rtm->rtm_msglen != len) {
807		plog(LLV_WARNING, LOCATION, NULL,
808		     "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n",
809		     rtm->rtm_msglen, len, rtm->rtm_type);
810		return FALSE;
811	}
812
813	kernel_handle_message(buf);
814	return TRUE;
815}
816
817static int
818kernel_open_socket()
819{
820	int fd;
821
822	fd = socket(PF_ROUTE, SOCK_RAW, 0);
823	if (fd < 0) {
824		plog(LLV_ERROR, LOCATION, NULL,
825			"socket(PF_ROUTE) failed: %s",
826			strerror(errno));
827		return -1;
828	}
829	close_on_exec(fd);
830	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
831		plog(LLV_WARNING, LOCATION, NULL,
832		     "failed to put socket in non-blocking mode\n");
833
834	return fd;
835}
836
837static void
838kernel_sync()
839{
840	caddr_t ref, buf, end;
841	size_t bufsiz;
842	struct if_msghdr *ifm;
843	struct interface *ifp;
844
845#define MIBSIZ 6
846	int mib[MIBSIZ] = {
847		CTL_NET,
848		PF_ROUTE,
849		0,
850		0, /*  AF_INET & AF_INET6 */
851		NET_RT_IFLIST,
852		0
853	};
854
855	if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) {
856		plog(LLV_WARNING, LOCATION, NULL,
857		     "sysctl() error: %s", strerror(errno));
858		return;
859	}
860
861	ref = buf = racoon_malloc(bufsiz);
862
863	if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) {
864		/* Parse both interfaces and addresses. */
865		for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) {
866			ifm = (struct if_msghdr *) buf;
867			kernel_handle_message(buf);
868		}
869	} else {
870		plog(LLV_WARNING, LOCATION, NULL,
871		     "sysctl() error: %s", strerror(errno));
872	}
873
874	racoon_free(ref);
875}
876
877#else
878
879#error No supported interface to monitor local addresses.
880
881#endif
882