Annotation of embedaddon/miniupnpd/linux/ifacewatcher.c, revision 1.1
1.1 ! misho 1: /* $Id: ifacewatcher.c,v 1.1 2011/05/20 09:33:07 nanard Exp $ */
! 2: /* MiniUPnP project
! 3: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
! 4: * (c) 2006-2009 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:
! 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:
! 50: #include "../config.h"
! 51:
! 52: #ifdef USE_IFACEWATCHER
! 53:
! 54: #include "../ifacewatcher.h"
! 55: #include "../minissdp.h"
! 56: #include "../getifaddr.h"
! 57: #include "../upnpglobalvars.h"
! 58: #include "../natpmp.h"
! 59:
! 60: extern volatile int should_send_public_address_change_notif;
! 61:
! 62:
! 63: int
! 64: OpenAndConfInterfaceWatchSocket(void)
! 65: {
! 66: int s;
! 67: struct sockaddr_nl addr;
! 68:
! 69: s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
! 70: if (s == -1)
! 71: {
! 72: syslog(LOG_ERR, "socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE): %m");
! 73: return -1;
! 74: }
! 75:
! 76: memset(&addr, 0, sizeof(addr));
! 77: addr.nl_family = AF_NETLINK;
! 78: addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
! 79:
! 80: if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
! 81: {
! 82: syslog(LOG_ERR, "bind(netlink): %m");
! 83: close(s);
! 84: return -1;
! 85: }
! 86:
! 87: return s;
! 88: }
! 89:
! 90: #if 0
! 91: /* disabled at the moment */
! 92: int
! 93: ProcessInterfaceUp(struct ifinfomsg *ifi)
! 94: {
! 95: struct lan_iface_s * lan_iface;
! 96: struct lan_iface_s * lan_iface2;
! 97: struct lan_addr_s * lan_addr;
! 98: char ifname[IFNAMSIZ];
! 99: char ifstraddr[16];
! 100: struct in_addr ifaddr;
! 101:
! 102: /* check if we already have this iface */
! 103: for(lan_iface = lan_ifaces.lh_first; lan_iface != NULL; lan_iface = lan_iface->list.le_next)
! 104: if (lan_iface->iface.index == ifi->ifi_index)
! 105: break;
! 106:
! 107: if (lan_iface != NULL)
! 108: return 0;
! 109:
! 110: if (if_indextoname(ifi->ifi_index, ifname) == NULL)
! 111: {
! 112: syslog(LOG_ERR, "if_indextoname(%d, ifname) failed", ifi->ifi_index);
! 113: return -1;
! 114: }
! 115:
! 116: if (getifaddr(ifname, ifstraddr, 16) < 0)
! 117: {
! 118: syslog(LOG_DEBUG, "getifaddr(%s, ifaddr, 16) failed", ifname);
! 119: return 1;
! 120: }
! 121:
! 122: if (inet_pton(AF_INET, ifstraddr, &ifaddr) != 1)
! 123: {
! 124: syslog(LOG_ERR, "inet_pton(AF_INET, \"%s\", &ifaddr) failed", ifstraddr);
! 125: return -1;
! 126: }
! 127:
! 128: /* check if this new interface has address which we need to listen to */
! 129: for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
! 130: {
! 131: if (lan_addr->addr.s_addr != ifaddr.s_addr)
! 132: continue;
! 133:
! 134: syslog(LOG_INFO, "Interface up: %s (%s)", ifname, ifstraddr);
! 135:
! 136: /* adding new lan_iface entry */
! 137: lan_iface = (struct lan_iface_s *) malloc(sizeof(struct lan_iface_s));
! 138: if (lan_iface == NULL)
! 139: {
! 140: syslog(LOG_ERR, "malloc(sizeof(struct lan_iface_s): %m");
! 141: continue;
! 142: }
! 143:
! 144: lan_iface->lan_addr = lan_addr;
! 145: strncpy(lan_iface->iface.name, ifname, IFNAMSIZ);
! 146: lan_iface->iface.index = ifi->ifi_index;
! 147: lan_iface->iface.addr = ifaddr;
! 148: lan_iface->snotify = -1;
! 149: #ifdef ENABLE_NATPMP
! 150: lan_iface->snatpmp = -1;
! 151: #endif
! 152:
! 153: LIST_INSERT_HEAD(&lan_ifaces, lan_iface, list);
! 154:
! 155: /* adding multicast membership for SSDP */
! 156: if(AddMulticastMembership(sudp, ifaddr.s_addr, ifi->ifi_index) < 0)
! 157: syslog(LOG_WARNING, "Failed to add multicast membership for interface %s (%s)", ifname, ifstraddr);
! 158: else
! 159: syslog(LOG_INFO, "Multicast membership added for %s (%s)", ifname, ifstraddr);
! 160:
! 161: /* create SSDP notify socket */
! 162: if (OpenAndConfSSDPNotifySocket(lan_iface) < 0)
! 163: syslog(LOG_WARNING, "Failed to open SSDP notify socket for interface %s (%s)", ifname, ifstraddr);
! 164:
! 165: #ifdef ENABLE_NATPMP
! 166: /* create NAT-PMP socket */
! 167: for(lan_iface2 = lan_ifaces.lh_first; lan_iface2 != NULL; lan_iface2 = lan_iface2->list.le_next)
! 168: if (lan_iface2->lan_addr->addr.s_addr == lan_iface->lan_addr->addr.s_addr &&
! 169: lan_iface2->snatpmp >= 0)
! 170: lan_iface->snatpmp = lan_iface2->snatpmp;
! 171:
! 172: if (lan_iface->snatpmp < 0)
! 173: {
! 174: lan_iface->snatpmp = OpenAndConfNATPMPSocket(ifaddr.s_addr);
! 175: if (lan_iface->snatpmp < 0)
! 176: syslog(LOG_ERR, "OpenAndConfNATPMPSocket(ifaddr.s_addr) failed for %s (%s)", ifname, ifstraddr);
! 177: else
! 178: syslog(LOG_INFO, "Listening for NAT-PMP connection on %s:%d", ifstraddr, NATPMP_PORT);
! 179: }
! 180: #endif
! 181: }
! 182:
! 183: return 0;
! 184: }
! 185:
! 186: int
! 187: ProcessInterfaceDown(struct ifinfomsg *ifi)
! 188: {
! 189: struct lan_iface_s * lan_iface;
! 190: struct lan_iface_s * lan_iface2;
! 191:
! 192: /* check if we have this iface */
! 193: for(lan_iface = lan_ifaces.lh_first; lan_iface != NULL; lan_iface = lan_iface->list.le_next)
! 194: if (lan_iface->iface.index == ifi->ifi_index)
! 195: break;
! 196:
! 197: if (lan_iface == NULL)
! 198: return 0;
! 199:
! 200: /* one of our interfaces is going down, clean up */
! 201: syslog(LOG_INFO, "Interface down: %s", lan_iface->iface.name);
! 202:
! 203: /* remove multicast membership for SSDP */
! 204: if(DropMulticastMembership(sudp, lan_iface->lan_addr->addr.s_addr, lan_iface->iface.index) < 0)
! 205: syslog(LOG_WARNING, "Failed to drop multicast membership for interface %s (%s)", lan_iface->iface.name, lan_iface->lan_addr->str);
! 206: else
! 207: syslog(LOG_INFO, "Multicast membership dropped for %s (%s)", lan_iface->iface.name, lan_iface->lan_addr->str);
! 208:
! 209: /* closing SSDP notify socket */
! 210: close(lan_iface->snotify);
! 211:
! 212: #ifdef ENABLE_NATPMP
! 213: /* closing NAT-PMP socket if it's not used anymore */
! 214: for(lan_iface2 = lan_ifaces.lh_first; lan_iface2 != NULL; lan_iface2 = lan_iface2->list.le_next)
! 215: if (lan_iface2 != lan_iface && lan_iface2->snatpmp == lan_iface->snatpmp)
! 216: break;
! 217:
! 218: if (lan_iface2 == NULL)
! 219: close(lan_iface->snatpmp);
! 220: #endif
! 221:
! 222: /* del corresponding lan_iface entry */
! 223: LIST_REMOVE(lan_iface, list);
! 224: free(lan_iface);
! 225:
! 226: return 0;
! 227: }
! 228: #endif
! 229:
! 230: void
! 231: ProcessInterfaceWatchNotify(int s)
! 232: {
! 233: char buffer[4096];
! 234: struct iovec iov;
! 235: struct msghdr hdr;
! 236: struct nlmsghdr *nlhdr;
! 237: struct ifinfomsg *ifi;
! 238: struct ifaddrmsg *ifa;
! 239: int len;
! 240:
! 241: struct rtattr *rth; //
! 242: int rtl;
! 243:
! 244: unsigned int ext_if_name_index = 0;
! 245:
! 246: iov.iov_base = buffer;
! 247: iov.iov_len = sizeof(buffer);
! 248:
! 249: memset(&hdr, 0, sizeof(hdr));
! 250: hdr.msg_iov = &iov;
! 251: hdr.msg_iovlen = 1;
! 252:
! 253: len = recvmsg(s, &hdr, 0);
! 254: if (len < 0)
! 255: {
! 256: syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m");
! 257: return;
! 258: }
! 259:
! 260: if(ext_if_name) {
! 261: ext_if_name_index = if_nametoindex(ext_if_name);
! 262: }
! 263:
! 264: for (nlhdr = (struct nlmsghdr *) buffer;
! 265: NLMSG_OK (nlhdr, len);
! 266: nlhdr = NLMSG_NEXT (nlhdr, len))
! 267: {
! 268: if (nlhdr->nlmsg_type == NLMSG_DONE)
! 269: break;
! 270: switch(nlhdr->nlmsg_type) {
! 271: case RTM_DELLINK:
! 272: ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
! 273: /*if (ProcessInterfaceDown(ifi) < 0)
! 274: syslog(LOG_ERR, "ProcessInterfaceDown(ifi) failed");*/
! 275: break;
! 276: case RTM_NEWLINK:
! 277: ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
! 278: /*if (ProcessInterfaceUp(ifi) < 0)
! 279: syslog(LOG_ERR, "ProcessInterfaceUp(ifi) failed");*/
! 280: break;
! 281: case RTM_NEWADDR:
! 282: /* see /usr/include/linux/netlink.h
! 283: * and /usr/include/linux/rtnetlink.h */
! 284: ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr);
! 285: syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_NEWADDR");
! 286: for(rth = IFA_RTA(ifa), rtl = IFA_PAYLOAD(nlhdr);
! 287: rtl && RTA_OK(rth, rtl);
! 288: rth = RTA_NEXT(rth, rtl)) {
! 289: syslog(LOG_DEBUG, " - %u - %s type=%d",
! 290: ifa->ifa_index, inet_ntoa(*((struct in_addr *)RTA_DATA(rth))),
! 291: rth->rta_type);
! 292: }
! 293: if(ifa->ifa_index == ext_if_name_index) {
! 294: should_send_public_address_change_notif = 1;
! 295: }
! 296: break;
! 297: case RTM_DELADDR:
! 298: ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr);
! 299: syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_DELADDR");
! 300: if(ifa->ifa_index == ext_if_name_index) {
! 301: should_send_public_address_change_notif = 1;
! 302: }
! 303: break;
! 304: default:
! 305: syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify type %d ignored", nlhdr->nlmsg_type);
! 306: }
! 307: }
! 308:
! 309: }
! 310:
! 311: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>