Annotation of embedaddon/miniupnpd/linux/ifacewatcher.c, revision 1.1.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>