File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / linux / ifacewatcher.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 00:32:35 2013 UTC (10 years, 11 months ago) by misho
Branches: miniupnpd, elwix, MAIN
CVS tags: v1_8p0, v1_8, HEAD
1.8

    1: /* $Id: ifacewatcher.c,v 1.1.1.2 2013/07/22 00:32:35 misho Exp $ */
    2: /* MiniUPnP project
    3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
    4:  * (c) 2006-2012 Thomas Bernard
    5:  *
    6:  * ifacewatcher.c
    7:  *
    8:  * This file implements dynamic serving of new network interfaces
    9:  * which weren't available during daemon start. It also takes care
   10:  * of interfaces which become unavailable.
   11:  *
   12:  * Copyright (c) 2011, Alexey Osipov <simba@lerlan.ru>
   13:  * All rights reserved.
   14:  *
   15:  * Redistribution and use in source and binary forms, with or without
   16:  * modification, are permitted provided that the following conditions are met:
   17:  *
   18:  *    * Redistributions of source code must retain the above copyright notice,
   19:  *      this list of conditions and the following disclaimer.
   20:  *    * Redistributions in binary form must reproduce the above copyright notice,
   21:  *      this list of conditions and the following disclaimer in the documentation
   22:  *      and/or other materials provided with the distribution.
   23:  *    * The name of the author may not be used to endorse or promote products
   24:  *      derived from this software without specific prior written permission.
   25:  *
   26:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   27:  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29:  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   30:  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36:  * POSSIBILITY OF SUCH DAMAGE. */
   37: 
   38: #include <stdio.h>
   39: #include <sys/types.h>
   40: #include <sys/socket.h>
   41: #include <linux/netlink.h>
   42: #include <linux/rtnetlink.h>
   43: #include <arpa/inet.h>
   44: #include <net/if.h>
   45: #include <syslog.h>
   46: #include <string.h>
   47: #include <unistd.h>
   48: #include <stdlib.h>
   49: #include <signal.h>
   50: 
   51: #include "../config.h"
   52: 
   53: #ifdef USE_IFACEWATCHER
   54: 
   55: #include "../ifacewatcher.h"
   56: #include "../minissdp.h"
   57: #include "../getifaddr.h"
   58: #include "../upnpglobalvars.h"
   59: #include "../natpmp.h"
   60: 
   61: extern volatile sig_atomic_t should_send_public_address_change_notif;
   62: 
   63: 
   64: int
   65: OpenAndConfInterfaceWatchSocket(void)
   66: {
   67: 	int s;
   68: 	struct sockaddr_nl addr;
   69: 
   70: 	s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
   71: 	if (s == -1)
   72: 	{
   73: 		syslog(LOG_ERR, "socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE): %m");
   74: 		return -1;
   75: 	}
   76: 
   77: 	memset(&addr, 0, sizeof(addr));
   78: 	addr.nl_family = AF_NETLINK;
   79: 	addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
   80: 	/*addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;*/
   81: 
   82: 	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
   83: 	{
   84: 		syslog(LOG_ERR, "bind(netlink): %m");
   85: 		close(s);
   86: 		return -1;
   87: 	}
   88: 
   89: 	return s;
   90: }
   91: 
   92: #if 0
   93: /* disabled at the moment */
   94: int
   95: ProcessInterfaceUp(struct ifinfomsg *ifi)
   96: {
   97: 	struct lan_iface_s * lan_iface;
   98: 	struct lan_iface_s * lan_iface2;
   99: 	struct lan_addr_s * lan_addr;
  100: 	char ifname[IFNAMSIZ];
  101: 	char ifstraddr[16];
  102: 	struct in_addr ifaddr;
  103: 
  104: 	/* check if we already have this iface */
  105: 	for(lan_iface = lan_ifaces.lh_first; lan_iface != NULL; lan_iface = lan_iface->list.le_next)
  106: 		if (lan_iface->iface.index == ifi->ifi_index)
  107: 			break;
  108: 
  109: 	if (lan_iface != NULL)
  110: 		return 0;
  111: 
  112: 	if (if_indextoname(ifi->ifi_index, ifname) == NULL)
  113: 	{
  114: 		syslog(LOG_ERR, "if_indextoname(%d, ifname) failed", ifi->ifi_index);
  115: 		return -1;
  116: 	}
  117: 
  118: 	if (getifaddr(ifname, ifstraddr, 16) < 0)
  119: 	{
  120: 		syslog(LOG_DEBUG, "getifaddr(%s, ifaddr, 16) failed", ifname);
  121: 		return 1;
  122: 	}
  123: 
  124: 	if (inet_pton(AF_INET, ifstraddr, &ifaddr) != 1)
  125: 	{
  126: 		syslog(LOG_ERR, "inet_pton(AF_INET, \"%s\", &ifaddr) failed", ifstraddr);
  127: 		return -1;
  128: 	}
  129: 
  130: 	/* check if this new interface has address which we need to listen to */
  131: 	for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
  132: 	{
  133: 		if (lan_addr->addr.s_addr != ifaddr.s_addr)
  134: 			continue;
  135: 
  136: 		syslog(LOG_INFO, "Interface up: %s (%s)", ifname, ifstraddr);
  137: 
  138: 		/* adding new lan_iface entry */
  139: 		lan_iface = (struct lan_iface_s *) malloc(sizeof(struct lan_iface_s));
  140: 		if (lan_iface == NULL)
  141: 		{
  142: 			syslog(LOG_ERR, "malloc(sizeof(struct lan_iface_s): %m");
  143: 			continue;
  144: 		}
  145: 
  146: 		lan_iface->lan_addr = lan_addr;
  147: 		strncpy(lan_iface->iface.name, ifname, IFNAMSIZ);
  148: 		lan_iface->iface.index = ifi->ifi_index;
  149: 		lan_iface->iface.addr = ifaddr;
  150: 		lan_iface->snotify = -1;
  151: #ifdef ENABLE_NATPMP
  152: 		lan_iface->snatpmp = -1;
  153: #endif
  154: 
  155: 		LIST_INSERT_HEAD(&lan_ifaces, lan_iface, list);
  156: 
  157: 		/* adding multicast membership for SSDP */
  158: 		if(AddMulticastMembership(sudp, ifaddr.s_addr, ifi->ifi_index) < 0)
  159: 			syslog(LOG_WARNING, "Failed to add multicast membership for interface %s (%s)", ifname, ifstraddr);
  160: 		else
  161: 			syslog(LOG_INFO, "Multicast membership added for %s (%s)", ifname, ifstraddr);
  162: 
  163: 		/* create SSDP notify socket */
  164: 		if (OpenAndConfSSDPNotifySocket(lan_iface) < 0)
  165: 			syslog(LOG_WARNING, "Failed to open SSDP notify socket for interface %s (%s)", ifname, ifstraddr);
  166: 
  167: #ifdef ENABLE_NATPMP
  168: 		/* create NAT-PMP socket */
  169: 		for(lan_iface2 = lan_ifaces.lh_first; lan_iface2 != NULL; lan_iface2 = lan_iface2->list.le_next)
  170: 			if (lan_iface2->lan_addr->addr.s_addr == lan_iface->lan_addr->addr.s_addr &&
  171: 			    lan_iface2->snatpmp >= 0)
  172: 				lan_iface->snatpmp = lan_iface2->snatpmp;
  173: 
  174: 		if (lan_iface->snatpmp < 0)
  175: 		{
  176: 			lan_iface->snatpmp = OpenAndConfNATPMPSocket(ifaddr.s_addr);
  177: 			if (lan_iface->snatpmp < 0)
  178: 				syslog(LOG_ERR, "OpenAndConfNATPMPSocket(ifaddr.s_addr) failed for %s (%s)", ifname, ifstraddr);
  179: 			else
  180: 				syslog(LOG_INFO, "Listening for NAT-PMP connection on %s:%d", ifstraddr, NATPMP_PORT);
  181: 		}
  182: #endif
  183: 	}
  184: 
  185: 	return 0;
  186: }
  187: 
  188: int
  189: ProcessInterfaceDown(struct ifinfomsg *ifi)
  190: {
  191: 	struct lan_iface_s * lan_iface;
  192: 	struct lan_iface_s * lan_iface2;
  193: 
  194: 	/* check if we have this iface */
  195: 	for(lan_iface = lan_ifaces.lh_first; lan_iface != NULL; lan_iface = lan_iface->list.le_next)
  196: 		if (lan_iface->iface.index == ifi->ifi_index)
  197: 			break;
  198: 
  199: 	if (lan_iface == NULL)
  200: 		return 0;
  201: 
  202: 	/* one of our interfaces is going down, clean up */
  203: 	syslog(LOG_INFO, "Interface down: %s", lan_iface->iface.name);
  204: 
  205: 	/* remove multicast membership for SSDP */
  206: 	if(DropMulticastMembership(sudp, lan_iface->lan_addr->addr.s_addr, lan_iface->iface.index) < 0)
  207: 		syslog(LOG_WARNING, "Failed to drop multicast membership for interface %s (%s)", lan_iface->iface.name, lan_iface->lan_addr->str);
  208: 	else
  209: 		syslog(LOG_INFO, "Multicast membership dropped for %s (%s)", lan_iface->iface.name, lan_iface->lan_addr->str);
  210: 
  211: 	/* closing SSDP notify socket */
  212: 	close(lan_iface->snotify);
  213: 
  214: #ifdef ENABLE_NATPMP
  215: 	/* closing NAT-PMP socket if it's not used anymore */
  216: 	for(lan_iface2 = lan_ifaces.lh_first; lan_iface2 != NULL; lan_iface2 = lan_iface2->list.le_next)
  217: 		if (lan_iface2 != lan_iface && lan_iface2->snatpmp == lan_iface->snatpmp)
  218: 			break;
  219: 
  220: 	if (lan_iface2 == NULL)
  221: 		close(lan_iface->snatpmp);
  222: #endif
  223: 
  224: 	/* del corresponding lan_iface entry */
  225: 	LIST_REMOVE(lan_iface, list);
  226: 	free(lan_iface);
  227: 
  228: 	return 0;
  229: }
  230: #endif
  231: 
  232: void
  233: ProcessInterfaceWatchNotify(int s)
  234: {
  235: 	char buffer[4096];
  236: 	struct iovec iov;
  237: 	struct msghdr hdr;
  238: 	struct nlmsghdr *nlhdr;
  239: 	struct ifinfomsg *ifi;
  240: 	struct ifaddrmsg *ifa;
  241: 	int len;
  242: 
  243: 	struct rtattr *rth;
  244: 	int rtl;
  245: 
  246: 	unsigned int ext_if_name_index = 0;
  247: 
  248: 	iov.iov_base = buffer;
  249: 	iov.iov_len = sizeof(buffer);
  250: 
  251: 	memset(&hdr, 0, sizeof(hdr));
  252: 	hdr.msg_iov = &iov;
  253: 	hdr.msg_iovlen = 1;
  254: 
  255: 	len = recvmsg(s, &hdr, 0);
  256: 	if (len < 0)
  257: 	{
  258: 		syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m");
  259: 		return;
  260: 	}
  261: 
  262: 	if(ext_if_name) {
  263: 		ext_if_name_index = if_nametoindex(ext_if_name);
  264: 	}
  265: 
  266: 	for (nlhdr = (struct nlmsghdr *) buffer;
  267: 	     NLMSG_OK (nlhdr, (unsigned int)len);
  268: 	     nlhdr = NLMSG_NEXT (nlhdr, len))
  269: 	{
  270: 		int is_del = 0;
  271: 		char address[48];
  272: 		char ifname[IFNAMSIZ];
  273: 		address[0] = '\0';
  274: 		ifname[0] = '\0';
  275: 		if (nlhdr->nlmsg_type == NLMSG_DONE)
  276: 			break;
  277: 		switch(nlhdr->nlmsg_type) {
  278: 		case RTM_DELLINK:
  279: 			is_del = 1;
  280: 		case RTM_NEWLINK:
  281: 			ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
  282: #if 0
  283: 			if(is_del) {
  284: 				if(ProcessInterfaceDown(ifi) < 0)
  285: 					syslog(LOG_ERR, "ProcessInterfaceDown(ifi) failed");
  286: 			} else {
  287: 				if(ProcessInterfaceUp(ifi) < 0)
  288: 					syslog(LOG_ERR, "ProcessInterfaceUp(ifi) failed");
  289: 			}
  290: #endif
  291: 			break;
  292: 		case RTM_DELADDR:
  293: 			is_del = 1;
  294: 		case RTM_NEWADDR:
  295: 			/* see /usr/include/linux/netlink.h
  296: 			 * and /usr/include/linux/rtnetlink.h */
  297: 			ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr);
  298: 			syslog(LOG_DEBUG, "%s %s index=%d fam=%d", "ProcessInterfaceWatchNotify",
  299: 			       is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
  300: 			       ifa->ifa_index, ifa->ifa_family);
  301: 			for(rth = IFA_RTA(ifa), rtl = IFA_PAYLOAD(nlhdr);
  302: 			    rtl && RTA_OK(rth, rtl);
  303: 			    rth = RTA_NEXT(rth, rtl)) {
  304: 				char tmp[128];
  305: 				memset(tmp, 0, sizeof(tmp));
  306: 				switch(rth->rta_type) {
  307: 				case IFA_ADDRESS:
  308: 				case IFA_LOCAL:
  309: 				case IFA_BROADCAST:
  310: 				case IFA_ANYCAST:
  311: 					inet_ntop(ifa->ifa_family, RTA_DATA(rth), tmp, sizeof(tmp));
  312: 					if(rth->rta_type == IFA_ADDRESS)
  313: 						strncpy(address, tmp, sizeof(address));
  314: 					break;
  315: 				case IFA_LABEL:
  316: 					strncpy(tmp, RTA_DATA(rth), sizeof(tmp));
  317: 					strncpy(ifname, tmp, sizeof(ifname));
  318: 					break;
  319: 				case IFA_CACHEINFO:
  320: 					{
  321: 						struct ifa_cacheinfo *cache_info;
  322: 						cache_info = RTA_DATA(rth);
  323: 						snprintf(tmp, sizeof(tmp), "valid=%u prefered=%u",
  324: 						         cache_info->ifa_valid, cache_info->ifa_prefered);
  325: 					}
  326: 					break;
  327: 				default:
  328: 					strncpy(tmp, "*unknown*", sizeof(tmp));
  329: 				}
  330: 				syslog(LOG_DEBUG, " - %u - %s type=%d",
  331: 				       ifa->ifa_index, tmp,
  332: 				       rth->rta_type);
  333: 			}
  334: 			if(ifa->ifa_index == ext_if_name_index) {
  335: 				should_send_public_address_change_notif = 1;
  336: 			}
  337: 			break;
  338: 		default:
  339: 			syslog(LOG_DEBUG, "%s type %d ignored",
  340: 			       "ProcessInterfaceWatchNotify", nlhdr->nlmsg_type);
  341: 		}
  342: 	}
  343: 
  344: }
  345: 
  346: #endif

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