Annotation of embedaddon/miniupnpd/linux/ifacewatcher.c, revision 1.1.1.2

1.1.1.2 ! misho       1: /* $Id: ifacewatcher.c,v 1.7 2012/05/27 22:16:10 nanard Exp $ */
1.1       misho       2: /* MiniUPnP project
                      3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
1.1.1.2 ! misho       4:  * (c) 2006-2012 Thomas Bernard
1.1       misho       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:  *
1.1.1.2 ! misho      12:  * Copyright (c) 2011, Alexey Osipov <simba@lerlan.ru>
1.1       misho      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: 
1.1.1.2 ! misho      38: #include <stdio.h>
1.1       misho      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>
1.1.1.2 ! misho      49: #include <signal.h>
1.1       misho      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: 
1.1.1.2 ! misho      61: extern volatile sig_atomic_t should_send_public_address_change_notif;
1.1       misho      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;
1.1.1.2 ! misho      80:        /*addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;*/
1.1       misho      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: 
1.1.1.2 ! misho     243:        struct rtattr *rth;
1.1       misho     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;
1.1.1.2 ! misho     267:             NLMSG_OK (nlhdr, (unsigned int)len);
1.1       misho     268:             nlhdr = NLMSG_NEXT (nlhdr, len))
                    269:        {
1.1.1.2 ! misho     270:                int is_del = 0;
        !           271:                char address[48];
        !           272:                char ifname[IFNAMSIZ];
        !           273:                address[0] = '\0';
        !           274:                ifname[0] = '\0';
1.1       misho     275:                if (nlhdr->nlmsg_type == NLMSG_DONE)
                    276:                        break;
                    277:                switch(nlhdr->nlmsg_type) {
                    278:                case RTM_DELLINK:
1.1.1.2 ! misho     279:                        is_del = 1;
1.1       misho     280:                case RTM_NEWLINK:
                    281:                        ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
1.1.1.2 ! misho     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
1.1       misho     291:                        break;
1.1.1.2 ! misho     292:                case RTM_DELADDR:
        !           293:                        is_del = 1;
1.1       misho     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);
1.1.1.2 ! misho     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);
1.1       misho     301:                        for(rth = IFA_RTA(ifa), rtl = IFA_PAYLOAD(nlhdr);
                    302:                            rtl && RTA_OK(rth, rtl);
                    303:                            rth = RTA_NEXT(rth, rtl)) {
1.1.1.2 ! misho     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:                                }
1.1       misho     330:                                syslog(LOG_DEBUG, " - %u - %s type=%d",
1.1.1.2 ! misho     331:                                       ifa->ifa_index, tmp,
1.1       misho     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:
1.1.1.2 ! misho     339:                        syslog(LOG_DEBUG, "%s type %d ignored",
        !           340:                               "ProcessInterfaceWatchNotify", nlhdr->nlmsg_type);
1.1       misho     341:                }
                    342:        }
                    343: 
                    344: }
                    345: 
                    346: #endif

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