Annotation of embedaddon/miniupnpd/minissdpd/ifacewatch.c, revision 1.1

1.1     ! misho       1: /* $Id: ifacewatch.c,v 1.16 2015/09/03 18:31:25 nanard Exp $ */
        !             2: /* MiniUPnP project
        !             3:  * (c) 2011-2018 Thomas Bernard
        !             4:  * website : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
        !             5:  * This software is subject to the conditions detailed
        !             6:  * in the LICENCE file provided within the distribution */
        !             7: #include "config.h"
        !             8: 
        !             9: #include <stdlib.h>
        !            10: #include <stdio.h>
        !            11: #include <unistd.h>
        !            12: #include <string.h>
        !            13: #include <sys/types.h>
        !            14: #include <sys/socket.h>
        !            15: #include <netinet/in.h>
        !            16: #include <arpa/inet.h>
        !            17: #include <net/if.h>
        !            18: #ifdef __linux__
        !            19: #include <linux/netlink.h>
        !            20: #include <linux/rtnetlink.h>
        !            21: #else  /* __linux__ */
        !            22: #include <net/route.h>
        !            23: #ifdef AF_LINK
        !            24: #include <net/if_dl.h>
        !            25: #endif
        !            26: #endif /* __linux__ */
        !            27: #include <syslog.h>
        !            28: #include <inttypes.h>
        !            29: 
        !            30: #include "config.h"
        !            31: #include "openssdpsocket.h"
        !            32: #include "upnputils.h"
        !            33: #include "minissdpdtypes.h"
        !            34: 
        !            35: extern struct lan_addr_list lan_addrs;
        !            36: 
        !            37: #ifndef __linux__
        !            38: #if defined(__OpenBSD__) || defined(__FreeBSD__)
        !            39: #define SALIGN (sizeof(long) - 1)
        !            40: #else
        !            41: #define SALIGN (sizeof(int32_t) - 1)
        !            42: #endif
        !            43: #define SA_RLEN(sa) (SA_LEN(sa) ? ((SA_LEN(sa) + SALIGN) & ~SALIGN) : (SALIGN + 1))
        !            44: #endif
        !            45: 
        !            46: int
        !            47: OpenAndConfInterfaceWatchSocket(void)
        !            48: {
        !            49:        int s;
        !            50: #ifdef __linux__
        !            51:        struct sockaddr_nl addr;
        !            52: 
        !            53:        s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        !            54: #else  /* __linux__*/
        !            55:        /*s = socket(PF_ROUTE, SOCK_RAW, AF_INET);*/
        !            56:        s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
        !            57: /* The family parameter may be AF_UNSPEC which will provide routing informa-
        !            58:  * tion for all address families, or can be restricted to a specific address
        !            59:  * family by specifying which one is desired.  There can be more than one
        !            60:  * routing socket open per system. */
        !            61: #endif
        !            62:        if(s < 0) {
        !            63:                syslog(LOG_ERR, "%s socket: %m",
        !            64:                       "OpenAndConfInterfaceWatchSocket");
        !            65:                return -1;
        !            66:        }
        !            67:        if(!set_non_blocking(s)) {
        !            68:                syslog(LOG_WARNING, "%s failed to set socket non blocking : %m",
        !            69:                       "OpenAndConfInterfaceWatchSocket");
        !            70:        }
        !            71: #ifdef __linux__
        !            72:        memset(&addr, 0, sizeof(addr));
        !            73:        addr.nl_family = AF_NETLINK;
        !            74:        addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
        !            75: 
        !            76:        if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        !            77:                syslog(LOG_ERR, "bind(netlink): %m");
        !            78:                close(s);
        !            79:                return -1;
        !            80:        }
        !            81: #endif
        !            82:        return s;
        !            83: }
        !            84: 
        !            85: /**
        !            86:  * Process the message and add/drop multicast membership if needed
        !            87:  */
        !            88: int
        !            89: ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6)
        !            90: {
        !            91:        struct lan_addr_s * lan_addr;
        !            92:        ssize_t len;
        !            93:        char buffer[4096];
        !            94: #ifdef __linux__
        !            95:        struct iovec iov;
        !            96:        struct msghdr hdr;
        !            97:        struct nlmsghdr *nlhdr;
        !            98:        struct ifaddrmsg *ifa;
        !            99:        struct rtattr *rta;
        !           100:        int ifa_len;
        !           101: 
        !           102: #ifndef ENABLE_IPV6
        !           103:        (void)s_ssdp6;
        !           104: #endif
        !           105:        iov.iov_base = buffer;
        !           106:        iov.iov_len = sizeof(buffer);
        !           107: 
        !           108:        memset(&hdr, 0, sizeof(hdr));
        !           109:        hdr.msg_iov = &iov;
        !           110:        hdr.msg_iovlen = 1;
        !           111: 
        !           112:        len = recvmsg(s, &hdr, 0);
        !           113:        if(len < 0) {
        !           114:                syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m");
        !           115:                return -1;
        !           116:        }
        !           117: 
        !           118:        for(nlhdr = (struct nlmsghdr *)buffer;
        !           119:                NLMSG_OK(nlhdr, len);
        !           120:                nlhdr = NLMSG_NEXT(nlhdr, len)) {
        !           121:                int is_del = 0;
        !           122:                char address[48];
        !           123:                char ifname[IFNAMSIZ];
        !           124:                address[0] = '\0';
        !           125:                ifname[0] = '\0';
        !           126:                if(nlhdr->nlmsg_type == NLMSG_DONE)
        !           127:                        break;
        !           128:                switch(nlhdr->nlmsg_type) {
        !           129:                /* case RTM_NEWLINK: */
        !           130:                /* case RTM_DELLINK: */
        !           131:                case RTM_DELADDR:
        !           132:                        is_del = 1;
        !           133:                case RTM_NEWADDR:
        !           134:                        /* http://linux-hacks.blogspot.fr/2009/01/sample-code-to-learn-netlink.html */
        !           135:                        ifa = (struct ifaddrmsg *)NLMSG_DATA(nlhdr);
        !           136:                        rta = (struct rtattr *)IFA_RTA(ifa);
        !           137:                        ifa_len = IFA_PAYLOAD(nlhdr);
        !           138:                        syslog(LOG_DEBUG, "%s %s index=%d fam=%d prefixlen=%d flags=%d scope=%d",
        !           139:                               "ProcessInterfaceWatchNotify", is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
        !           140:                               ifa->ifa_index, ifa->ifa_family, ifa->ifa_prefixlen,
        !           141:                               ifa->ifa_flags, ifa->ifa_scope);
        !           142:                        for(;RTA_OK(rta, ifa_len); rta = RTA_NEXT(rta, ifa_len)) {
        !           143:                                /*RTA_DATA(rta)*/
        !           144:                                /*rta_type : IFA_ADDRESS, IFA_LOCAL, etc. */
        !           145:                                char tmp[128];
        !           146:                                memset(tmp, 0, sizeof(tmp));
        !           147:                                switch(rta->rta_type) {
        !           148:                                case IFA_ADDRESS:
        !           149:                                case IFA_LOCAL:
        !           150:                                case IFA_BROADCAST:
        !           151:                                case IFA_ANYCAST:
        !           152:                                        inet_ntop(ifa->ifa_family, RTA_DATA(rta), tmp, sizeof(tmp));
        !           153:                                        if(rta->rta_type == IFA_ADDRESS)
        !           154:                                                strncpy(address, tmp, sizeof(address));
        !           155:                                        break;
        !           156:                                case IFA_LABEL:
        !           157:                                        strncpy(tmp, RTA_DATA(rta), sizeof(tmp));
        !           158:                                        strncpy(ifname, tmp, sizeof(ifname));
        !           159:                                        break;
        !           160:                                case IFA_CACHEINFO:
        !           161:                                        {
        !           162:                                                struct ifa_cacheinfo *cache_info;
        !           163:                                                cache_info = RTA_DATA(rta);
        !           164:                                                snprintf(tmp, sizeof(tmp), "valid=%u preferred=%u",
        !           165:                                                         cache_info->ifa_valid, cache_info->ifa_prefered);
        !           166:                                        }
        !           167:                                        break;
        !           168:                                default:
        !           169:                                        strncpy(tmp, "*unknown*", sizeof(tmp));
        !           170:                                }
        !           171:                                syslog(LOG_DEBUG, " rta_len=%d rta_type=%d '%s'", rta->rta_len, rta->rta_type, tmp);
        !           172:                        }
        !           173:                        syslog(LOG_INFO, "%s: %s/%d %s",
        !           174:                               is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
        !           175:                               address, ifa->ifa_prefixlen, ifname);
        !           176:                        for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
        !           177: #ifdef ENABLE_IPV6
        !           178:                                if((0 == strcmp(address, lan_addr->str)) ||
        !           179:                                   (0 == strcmp(ifname, lan_addr->ifname)) ||
        !           180:                                   (ifa->ifa_index == lan_addr->index)) {
        !           181: #else
        !           182:                                if((0 == strcmp(address, lan_addr->str)) ||
        !           183:                                   (0 == strcmp(ifname, lan_addr->ifname))) {
        !           184: #endif
        !           185:                                        if(ifa->ifa_family == AF_INET)
        !           186:                                                AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del);
        !           187: #ifdef ENABLE_IPV6
        !           188:                                        else if(ifa->ifa_family == AF_INET6)
        !           189:                                                AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del);
        !           190: #endif
        !           191:                                        break;
        !           192:                                }
        !           193:                        }
        !           194:                        break;
        !           195:                default:
        !           196:                        syslog(LOG_DEBUG, "unknown nlmsg_type=%d", nlhdr->nlmsg_type);
        !           197:                }
        !           198:        }
        !           199: #else /* __linux__ */
        !           200:        struct rt_msghdr * rtm;
        !           201:        struct ifa_msghdr * ifam;
        !           202:        int is_del = 0;
        !           203:        char tmp[64];
        !           204:        char * p;
        !           205:        struct sockaddr * sa;
        !           206:        int addr;
        !           207:        char address[48];
        !           208:        char ifname[IFNAMSIZ];
        !           209:        int family = AF_UNSPEC;
        !           210:        int prefixlen = 0;
        !           211: 
        !           212: #ifndef ENABLE_IPV6
        !           213:        (void)s_ssdp6;
        !           214: #endif
        !           215:        address[0] = '\0';
        !           216:        ifname[0] = '\0';
        !           217: 
        !           218:        len = recv(s, buffer, sizeof(buffer), 0);
        !           219:        if(len < 0) {
        !           220:                syslog(LOG_ERR, "%s recv: %m", "ProcessInterfaceWatchNotify");
        !           221:                return -1;
        !           222:        }
        !           223:        rtm = (struct rt_msghdr *)buffer;
        !           224:        switch(rtm->rtm_type) {
        !           225:        case RTM_DELADDR:
        !           226:                is_del = 1;
        !           227:        case RTM_NEWADDR:
        !           228:                ifam = (struct ifa_msghdr *)buffer;
        !           229:                syslog(LOG_DEBUG, "%s %s len=%d/%hu index=%hu addrs=%x flags=%x",
        !           230:                       "ProcessInterfaceWatchNotify", is_del?"RTM_DELADDR":"RTM_NEWADDR",
        !           231:                       (int)len, ifam->ifam_msglen,
        !           232:                       ifam->ifam_index, ifam->ifam_addrs, ifam->ifam_flags);
        !           233:                p = buffer + sizeof(struct ifa_msghdr);
        !           234:                addr = 1;
        !           235:                while(p < buffer + len) {
        !           236:                        sa = (struct sockaddr *)p;
        !           237:                        while(!(addr & ifam->ifam_addrs) && (addr <= ifam->ifam_addrs))
        !           238:                                addr = addr << 1;
        !           239:                        sockaddr_to_string(sa, tmp, sizeof(tmp));
        !           240:                        syslog(LOG_DEBUG, " %s", tmp);
        !           241:                        switch(addr) {
        !           242:                        case RTA_DST:
        !           243:                        case RTA_GATEWAY:
        !           244:                                break;
        !           245:                        case RTA_NETMASK:
        !           246:                                if(sa->sa_family == AF_INET
        !           247: #if defined(__OpenBSD__)
        !           248:                                   || (sa->sa_family == 0 &&
        !           249:                                       sa->sa_len <= sizeof(struct sockaddr_in))
        !           250: #endif
        !           251:                                   ) {
        !           252:                                        uint32_t sin_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
        !           253:                                        while((prefixlen < 32) &&
        !           254:                                              ((sin_addr & (1 << (31 - prefixlen))) != 0))
        !           255:                                                prefixlen++;
        !           256:                                } else if(sa->sa_family == AF_INET6
        !           257: #if defined(__OpenBSD__)
        !           258:                                          || (sa->sa_family == 0 &&
        !           259:                                              sa->sa_len == sizeof(struct sockaddr_in6))
        !           260: #endif
        !           261:                                          ) {
        !           262:                                        int i = 0;
        !           263:                                        uint8_t * q =  ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
        !           264:                                        while((*q == 0xff) && (i < 16)) {
        !           265:                                                prefixlen += 8;
        !           266:                                                q++; i++;
        !           267:                                        }
        !           268:                                        if(i < 16) {
        !           269:                                                i = 0;
        !           270:                                                while((i < 8) &&
        !           271:                                                      ((*q & (1 << (7 - i))) != 0))
        !           272:                                                        i++;
        !           273:                                                prefixlen += i;
        !           274:                                        }
        !           275:                                }
        !           276:                                break;
        !           277:                        case RTA_GENMASK:
        !           278:                                break;
        !           279:                        case RTA_IFP:
        !           280: #ifdef AF_LINK
        !           281:                                if(sa->sa_family == AF_LINK) {
        !           282:                                        struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa;
        !           283:                                        memset(ifname, 0, sizeof(ifname));
        !           284:                                        memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
        !           285:                                }
        !           286: #endif
        !           287:                                break;
        !           288:                        case RTA_IFA:
        !           289:                                family = sa->sa_family;
        !           290:                                if(sa->sa_family == AF_INET) {
        !           291:                                        inet_ntop(sa->sa_family,
        !           292:                                                  &((struct sockaddr_in *)sa)->sin_addr,
        !           293:                                                  address, sizeof(address));
        !           294:                                } else if(sa->sa_family == AF_INET6) {
        !           295:                                        inet_ntop(sa->sa_family,
        !           296:                                                  &((struct sockaddr_in6 *)sa)->sin6_addr,
        !           297:                                                  address, sizeof(address));
        !           298:                                }
        !           299:                                break;
        !           300:                        case RTA_AUTHOR:
        !           301:                                break;
        !           302:                        case RTA_BRD:
        !           303:                                break;
        !           304:                        }
        !           305: #if 0
        !           306:                        syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x",
        !           307:                               (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3],
        !           308:                               (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3]); 
        !           309:                        syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x",
        !           310:                               (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7],
        !           311:                               (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7]); 
        !           312: #endif
        !           313:                        p += SA_RLEN(sa);
        !           314:                        addr = addr << 1;
        !           315:                }
        !           316:                syslog(LOG_INFO, "%s: %s/%d %s",
        !           317:                       is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
        !           318:                       address, prefixlen, ifname);
        !           319:                for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
        !           320: #ifdef ENABLE_IPV6
        !           321:                        if((0 == strcmp(address, lan_addr->str)) ||
        !           322:                           (0 == strcmp(ifname, lan_addr->ifname)) ||
        !           323:                           (ifam->ifam_index == lan_addr->index)) {
        !           324: #else
        !           325:                        if((0 == strcmp(address, lan_addr->str)) ||
        !           326:                           (0 == strcmp(ifname, lan_addr->ifname))) {
        !           327: #endif
        !           328:                                if(family == AF_INET)
        !           329:                                        AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del);
        !           330: #ifdef ENABLE_IPV6
        !           331:                                else if(family == AF_INET6)
        !           332:                                        AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del);
        !           333: #endif
        !           334:                                break;
        !           335:                        }
        !           336:                }
        !           337:                break;
        !           338:        default:
        !           339:                syslog(LOG_DEBUG, "Unknown RTM message : rtm->rtm_type=%d len=%d",
        !           340:                       rtm->rtm_type, (int)len);
        !           341:        }
        !           342: #endif
        !           343:        return 0;
        !           344: }
        !           345: 

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