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>