grabmyaddr.c revision 1.25
1/*	$NetBSD: grabmyaddr.c,v 1.25 2010/10/21 06:15:28 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) == 0)
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) == 0)
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) != 0)
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) == 0)
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) == 0)
280			return extract_port((struct sockaddr *) &my->addr);
281	}
282
283	return PORT_ISAKMP;
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 void
323parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
324{
325	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
326	while (RTA_OK(rta, len)) {
327		if (rta->rta_type <= max)
328			tb[rta->rta_type] = rta;
329		rta = RTA_NEXT(rta,len);
330	}
331}
332
333static int
334netlink_enumerate(fd, family, type)
335	int fd;
336	int family;
337	int type;
338{
339	struct {
340		struct nlmsghdr nlh;
341		struct rtgenmsg g;
342	} req;
343	struct sockaddr_nl addr;
344	static __u32 seq = 0;
345
346	memset(&addr, 0, sizeof(addr));
347	addr.nl_family = AF_NETLINK;
348
349	memset(&req, 0, sizeof(req));
350	req.nlh.nlmsg_len = sizeof(req);
351	req.nlh.nlmsg_type = type;
352	req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
353	req.nlh.nlmsg_pid = 0;
354	req.nlh.nlmsg_seq = ++seq;
355	req.g.rtgen_family = family;
356
357	return sendto(fd, (void *) &req, sizeof(req), 0,
358		      (struct sockaddr *) &addr, sizeof(addr)) >= 0;
359}
360
361static int
362netlink_process(struct nlmsghdr *h)
363{
364	struct sockaddr_storage addr;
365	struct ifaddrmsg *ifa;
366	struct rtattr *rta[IFA_MAX+1];
367	struct sockaddr_in *sin;
368#ifdef INET6
369	struct sockaddr_in6 *sin6;
370#endif
371
372	/* is this message interesting? */
373	if (h->nlmsg_type != RTM_NEWADDR &&
374	    h->nlmsg_type != RTM_DELADDR)
375		return 0;
376
377	ifa = NLMSG_DATA(h);
378	parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h));
379
380	if (ifa->ifa_flags & IFA_F_TENTATIVE)
381		return 0;
382
383	if (rta[IFA_LOCAL] == NULL)
384		rta[IFA_LOCAL] = rta[IFA_ADDRESS];
385	if (rta[IFA_LOCAL] == NULL)
386		return 0;
387
388	/* setup the socket address */
389	memset(&addr, 0, sizeof(addr));
390	addr.ss_family = ifa->ifa_family;
391	switch (ifa->ifa_family) {
392	case AF_INET:
393		sin = (struct sockaddr_in *) &addr;
394		memcpy(&sin->sin_addr, RTA_DATA(rta[IFA_LOCAL]),
395			sizeof(sin->sin_addr));
396		break;
397#ifdef INET6
398	case AF_INET6:
399		sin6 = (struct sockaddr_in6 *) &addr;
400		memcpy(&sin6->sin6_addr, RTA_DATA(rta[IFA_LOCAL]),
401			sizeof(sin6->sin6_addr));
402		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
403			sin6->sin6_scope_id = ifa->ifa_index;
404		break;
405#endif
406	default:
407		return 0;
408	}
409
410	plog(LLV_DEBUG, LOCATION, NULL,
411	     "Netlink: address %s %s\n",
412	     saddrwop2str((struct sockaddr *) &addr),
413	     h->nlmsg_type == RTM_NEWADDR ? "added" : "deleted");
414
415	if (h->nlmsg_type == RTM_NEWADDR)
416		myaddr_open_all_configured((struct sockaddr *) &addr);
417	else
418		myaddr_close_all_open((struct sockaddr *) &addr);
419
420	return 0;
421}
422
423static int
424kernel_receive(ctx, fd)
425	void *ctx;
426	int fd;
427{
428	struct sockaddr_nl nladdr;
429	struct iovec iov;
430	struct msghdr msg = {
431		.msg_name = &nladdr,
432		.msg_namelen = sizeof(nladdr),
433		.msg_iov = &iov,
434		.msg_iovlen = 1,
435	};
436	struct nlmsghdr *h;
437	int len, status;
438	char buf[16*1024];
439
440	iov.iov_base = buf;
441	while (1) {
442		iov.iov_len = sizeof(buf);
443		status = recvmsg(fd, &msg, MSG_DONTWAIT);
444		if (status < 0) {
445			if (errno == EINTR)
446				continue;
447			if (errno == EAGAIN)
448				return FALSE;
449			continue;
450		}
451		if (status == 0)
452			return FALSE;
453
454		h = (struct nlmsghdr *) buf;
455		while (NLMSG_OK(h, status)) {
456			netlink_process(h);
457			h = NLMSG_NEXT(h, status);
458		}
459	}
460
461	return TRUE;
462}
463
464static int
465kernel_open_socket()
466{
467	struct sockaddr_nl nl;
468	int fd;
469
470	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
471	if (fd < 0) {
472		plog(LLV_ERROR, LOCATION, NULL,
473			"socket(PF_NETLINK) failed: %s",
474			strerror(errno));
475		return -1;
476	}
477	close_on_exec(fd);
478	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
479		plog(LLV_WARNING, LOCATION, NULL,
480		     "failed to put socket in non-blocking mode\n");
481
482	memset(&nl, 0, sizeof(nl));
483	nl.nl_family = AF_NETLINK;
484	nl.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
485	if (bind(fd, (struct sockaddr*) &nl, sizeof(nl)) < 0) {
486		plog(LLV_ERROR, LOCATION, NULL,
487		     "bind(PF_NETLINK) failed: %s\n",
488		     strerror(errno));
489		close(fd);
490		return -1;
491	}
492	return fd;
493}
494
495static void
496kernel_sync()
497{
498	int fd = lcconf->rtsock;
499
500	/* refresh addresses */
501	if (!netlink_enumerate(fd, PF_UNSPEC, RTM_GETADDR)) {
502		plog(LLV_ERROR, LOCATION, NULL,
503		     "unable to enumerate addresses: %s\n",
504		     strerror(errno));
505		return;
506	}
507
508	/* receive replies */
509	while (kernel_receive(NULL, fd) == TRUE);
510}
511
512#elif defined(USE_ROUTE)
513
514#define ROUNDUP(a) \
515  ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
516
517#define SAROUNDUP(X)   ROUNDUP(((struct sockaddr *)(X))->sa_len)
518
519static size_t
520parse_address(start, end, dest)
521	caddr_t start;
522	caddr_t end;
523	struct sockaddr_storage *dest;
524{
525	int len;
526
527	if (start >= end)
528		return 0;
529
530	len = SAROUNDUP(start);
531	if (start + len > end)
532		return end - start;
533
534	if (dest != NULL && len <= sizeof(struct sockaddr_storage))
535		memcpy(dest, start, len);
536
537	return len;
538}
539
540static void
541parse_addresses(start, end, flags, addr)
542	caddr_t start;
543	caddr_t end;
544	int flags;
545	struct sockaddr_storage *addr;
546{
547	memset(addr, 0, sizeof(*addr));
548	if (flags & RTA_DST)
549		start += parse_address(start, end, NULL);
550	if (flags & RTA_GATEWAY)
551		start += parse_address(start, end, NULL);
552	if (flags & RTA_NETMASK)
553		start += parse_address(start, end, NULL);
554	if (flags & RTA_GENMASK)
555		start += parse_address(start, end, NULL);
556	if (flags & RTA_IFP)
557		start += parse_address(start, end, NULL);
558	if (flags & RTA_IFA)
559		start += parse_address(start, end, addr);
560	if (flags & RTA_AUTHOR)
561		start += parse_address(start, end, NULL);
562	if (flags & RTA_BRD)
563		start += parse_address(start, end, NULL);
564}
565
566static void
567kernel_handle_message(msg)
568	caddr_t msg;
569{
570	struct rt_msghdr *rtm = (struct rt_msghdr *) msg;
571	struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg;
572	struct sockaddr_storage addr;
573
574	switch (rtm->rtm_type) {
575	case RTM_NEWADDR:
576		parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
577				ifa->ifam_addrs, &addr);
578		myaddr_open_all_configured((struct sockaddr *) &addr);
579		break;
580	case RTM_DELADDR:
581		parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
582				ifa->ifam_addrs, &addr);
583		myaddr_close_all_open((struct sockaddr *) &addr);
584		break;
585	case RTM_ADD:
586	case RTM_DELETE:
587	case RTM_CHANGE:
588	case RTM_MISS:
589	case RTM_IFINFO:
590#ifdef RTM_OIFINFO
591	case RTM_OIFINFO:
592#endif
593#ifdef RTM_NEWMADDR
594	case RTM_NEWMADDR:
595	case RTM_DELMADDR:
596#endif
597#ifdef RTM_IFANNOUNCE
598	case RTM_IFANNOUNCE:
599#endif
600		break;
601	default:
602		plog(LLV_WARNING, LOCATION, NULL,
603		     "unrecognized route message with rtm_type: %d",
604		     rtm->rtm_type);
605		break;
606	}
607}
608
609static int
610kernel_receive(ctx, fd)
611	void *ctx;
612	int fd;
613{
614	char buf[16*1024];
615	struct rt_msghdr *rtm = (struct rt_msghdr *) buf;
616	int len;
617
618	len = read(fd, &buf, sizeof(buf));
619	if (len <= 0) {
620		if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
621			plog(LLV_WARNING, LOCATION, NULL,
622			     "routing socket error: %s", strerror(errno));
623		return FALSE;
624	}
625
626	if (rtm->rtm_msglen != len) {
627		plog(LLV_WARNING, LOCATION, NULL,
628		     "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n",
629		     rtm->rtm_msglen, len, rtm->rtm_type);
630		return FALSE;
631	}
632
633	kernel_handle_message(buf);
634	return TRUE;
635}
636
637static int
638kernel_open_socket()
639{
640	int fd;
641
642	fd = socket(PF_ROUTE, SOCK_RAW, 0);
643	if (fd < 0) {
644		plog(LLV_ERROR, LOCATION, NULL,
645			"socket(PF_ROUTE) failed: %s",
646			strerror(errno));
647		return -1;
648	}
649	close_on_exec(fd);
650	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
651		plog(LLV_WARNING, LOCATION, NULL,
652		     "failed to put socket in non-blocking mode\n");
653
654	return fd;
655}
656
657static void
658kernel_sync()
659{
660	caddr_t ref, buf, end;
661	size_t bufsiz;
662	struct if_msghdr *ifm;
663	struct interface *ifp;
664
665#define MIBSIZ 6
666	int mib[MIBSIZ] = {
667		CTL_NET,
668		PF_ROUTE,
669		0,
670		0, /*  AF_INET & AF_INET6 */
671		NET_RT_IFLIST,
672		0
673	};
674
675	if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) {
676		plog(LLV_WARNING, LOCATION, NULL,
677		     "sysctl() error: %s", strerror(errno));
678		return;
679	}
680
681	ref = buf = racoon_malloc(bufsiz);
682
683	if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) {
684		/* Parse both interfaces and addresses. */
685		for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) {
686			ifm = (struct if_msghdr *) buf;
687			kernel_handle_message(buf);
688		}
689	} else {
690		plog(LLV_WARNING, LOCATION, NULL,
691		     "sysctl() error: %s", strerror(errno));
692	}
693
694	racoon_free(ref);
695}
696
697#else
698
699#error No supported interface to monitor local addresses.
700
701#endif
702