File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ipsec-tools / src / racoon / grabmyaddr.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:45:58 2016 UTC (7 years, 8 months ago) by misho
Branches: ipsec-tools, MAIN
CVS tags: v0_8_2p2, HEAD
ipsec-tools 0.8.2

    1: /*	$NetBSD: grabmyaddr.c,v 1.28.2.2 2013/04/12 09:53:52 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: 
   70: static int kernel_receive __P((void *ctx, int fd));
   71: static int kernel_open_socket __P((void));
   72: static void kernel_sync __P((void));
   73: 
   74: struct myaddr {
   75: 	LIST_ENTRY(myaddr) chain;
   76: 	struct sockaddr_storage addr;
   77: 	int fd;
   78: 	int udp_encap;
   79: };
   80: 
   81: static LIST_HEAD(_myaddr_list_, myaddr) configured, opened;
   82: 
   83: static void
   84: myaddr_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: 
   93: static int
   94: myaddr_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: 
  110: static int
  111: myaddr_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: 
  138: static int
  139: myaddr_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: 
  180: static void
  181: myaddr_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: 
  197: static void
  198: myaddr_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: 
  209: void
  210: myaddr_flush()
  211: {
  212: 	myaddr_flush_list(&configured);
  213: }
  214: 
  215: int
  216: myaddr_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: 
  240: void
  241: myaddr_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: 
  258: int
  259: myaddr_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: 
  272: int
  273: myaddr_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: 
  297: void
  298: myaddr_init_lists()
  299: {
  300: 	LIST_INIT(&configured);
  301: 	LIST_INIT(&opened);
  302: }
  303: 
  304: int
  305: myaddr_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: 
  320: void
  321: myaddr_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: 
  333: static int netlink_fd = -1;
  334: 
  335: #define NLMSG_TAIL(nmsg) \
  336: 	((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
  337: 
  338: static void
  339: parse_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: 
  349: static int
  350: netlink_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: 
  367: static int
  368: netlink_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: 
  395: static void
  396: netlink_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
  410: static int
  411: netlink_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: 
  446: static int
  447: netlink_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: 
  482: static int
  483: netlink_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: 
  545: static int
  546: netlink_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: 
  561: static int
  562: kernel_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: 
  602: static int
  603: netlink_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: 
  622: static int
  623: kernel_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: 
  668: static void
  669: kernel_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: 
  698: static size_t
  699: parse_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: 
  719: static void
  720: parse_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: 
  745: static void
  746: kernel_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: 
  789: static int
  790: kernel_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: 
  817: static int
  818: kernel_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: 
  837: static void
  838: kernel_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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>