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