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

1.1     ! misho       1: /* $Id: openssdpsocket.c,v 1.17 2015/08/06 14:05:37 nanard Exp $ */
        !             2: /* MiniUPnP project
        !             3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
        !             4:  * (c) 2006-2018 Thomas Bernard
        !             5:  * This software is subject to the conditions detailed
        !             6:  * in the LICENCE file provided within the distribution */
        !             7: 
        !             8: #include "config.h"
        !             9: 
        !            10: #include <string.h>
        !            11: #include <unistd.h>
        !            12: #include <sys/ioctl.h>
        !            13: #include <sys/socket.h>
        !            14: #include <netinet/in.h>
        !            15: #include <arpa/inet.h>
        !            16: #include <net/if.h>
        !            17: #include <syslog.h>
        !            18: 
        !            19: #include "openssdpsocket.h"
        !            20: #include "upnputils.h"
        !            21: #include "minissdpdtypes.h"
        !            22: 
        !            23: extern struct lan_addr_list lan_addrs;
        !            24: 
        !            25: /* SSDP ip/port */
        !            26: #define SSDP_PORT (1900)
        !            27: #define SSDP_MCAST_ADDR ("239.255.255.250")
        !            28: /* Link Local and Site Local SSDP IPv6 multicast addresses */
        !            29: #define LL_SSDP_MCAST_ADDR ("FF02::C")
        !            30: #define SL_SSDP_MCAST_ADDR ("FF05::C")
        !            31: 
        !            32: /**
        !            33:  * Add the multicast membership for SSDP on the interface
        !            34:  * @param s    the socket
        !            35:  * @param ifaddr       the IPv4 address or interface name
        !            36:  * @param ipv6 IPv6 or IPv4
        !            37:  * return -1 on error, 0 on success */
        !            38: int
        !            39: AddDropMulticastMembership(int s, struct lan_addr_s * lan_addr, int ipv6, int drop)
        !            40: {
        !            41:        int ret = 0;
        !            42:        struct ip_mreq imr;     /* Ip multicast membership */
        !            43: #ifdef ENABLE_IPV6
        !            44:        struct ipv6_mreq mr;
        !            45: #else  /* ENABLE_IPV6 */
        !            46:        (void)ipv6;
        !            47: #endif /* ENABLE_IPV6 */
        !            48: 
        !            49:        if(s <= 0)
        !            50:                return -1;      /* nothing to do */
        !            51: #ifdef ENABLE_IPV6
        !            52:        if(ipv6)
        !            53:        {
        !            54:                memset(&mr, 0, sizeof(mr));
        !            55:                inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
        !            56:                mr.ipv6mr_interface = lan_addr->index;
        !            57:                if(setsockopt(s, IPPROTO_IPV6, drop ? IPV6_LEAVE_GROUP : IPV6_JOIN_GROUP,
        !            58:                   &mr, sizeof(struct ipv6_mreq)) < 0)
        !            59:                {
        !            60:                        syslog(LOG_ERR, "setsockopt(s=%d, %s)(%s, %s): %m",
        !            61:                               s, drop ? "IPV6_LEAVE_GROUP" : "IPV6_JOIN_GROUP",
        !            62:                               LL_SSDP_MCAST_ADDR,
        !            63:                               lan_addr->ifname);
        !            64:                        ret = -1;
        !            65:                }
        !            66:                inet_pton(AF_INET6, SL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
        !            67:                if(setsockopt(s, IPPROTO_IPV6, drop ? IPV6_LEAVE_GROUP : IPV6_JOIN_GROUP,
        !            68:                   &mr, sizeof(struct ipv6_mreq)) < 0)
        !            69:                {
        !            70:                        syslog(LOG_ERR, "setsockopt(s=%d, %s)(%s, %s): %m",
        !            71:                               s, drop ? "IPV6_LEAVE_GROUP" : "IPV6_JOIN_GROUP",
        !            72:                               SL_SSDP_MCAST_ADDR,
        !            73:                               lan_addr->ifname);
        !            74:                        ret = -1;
        !            75:                }
        !            76:        }
        !            77:        else
        !            78:        {
        !            79: #endif /* ENABLE_IPV6 */
        !            80:                /* setting up imr structure */
        !            81:                imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR);
        !            82:                imr.imr_interface.s_addr = lan_addr->addr.s_addr;
        !            83:                if(imr.imr_interface.s_addr == INADDR_NONE)
        !            84:                {
        !            85:                        syslog(LOG_ERR, "no IPv4 address for interface %s",
        !            86:                               lan_addr->ifname);
        !            87:                        return -1;
        !            88:                }
        !            89: 
        !            90:                if (setsockopt(s, IPPROTO_IP, drop ? IP_DROP_MEMBERSHIP : IP_ADD_MEMBERSHIP,
        !            91:                    (void *)&imr, sizeof(struct ip_mreq)) < 0)
        !            92:                {
        !            93:                        syslog(LOG_ERR, "setsockopt(s=%d, %s)(%s): %m",
        !            94:                               s, drop ? "IP_DROP_MEMBERSHIP" : "IP_ADD_MEMBERSHIP",
        !            95:                               lan_addr->ifname);
        !            96:                        return -1;
        !            97:                }
        !            98: #ifdef ENABLE_IPV6
        !            99:        }
        !           100: #endif /* ENABLE_IPV6 */
        !           101: 
        !           102:        return ret;
        !           103: }
        !           104: 
        !           105: int
        !           106: OpenAndConfSSDPReceiveSocket(int ipv6, unsigned char ttl)
        !           107: {
        !           108:        int s;
        !           109:        int opt = 1;
        !           110:        unsigned char loopchar = 0;
        !           111: #ifdef ENABLE_IPV6
        !           112:        struct sockaddr_storage sockname;
        !           113: #else /* ENABLE_IPV6 */
        !           114:        struct sockaddr_in sockname;
        !           115: #endif /* ENABLE_IPV6 */
        !           116:        socklen_t sockname_len;
        !           117:        struct lan_addr_s * lan_addr;
        !           118: 
        !           119: #ifndef ENABLE_IPV6
        !           120:        if(ipv6) {
        !           121:                syslog(LOG_ERR, "%s: please compile with ENABLE_IPV6 to allow ipv6=1", __func__);
        !           122:                return -1;
        !           123:        }
        !           124: #endif /* ENABLE_IPV6 */
        !           125: 
        !           126: #ifdef ENABLE_IPV6
        !           127:        if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
        !           128: #else /* ENABLE_IPV6 */
        !           129:        if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
        !           130: #endif /* ENABLE_IPV6 */
        !           131:        {
        !           132:                syslog(LOG_ERR, "socket(udp): %m");
        !           133:                return -1;
        !           134:        }
        !           135: 
        !           136:        if(!set_non_blocking(s)) {
        !           137:                syslog(LOG_WARNING, "Failed to set SSDP socket non blocking : %m");
        !           138:        }
        !           139: 
        !           140: #ifdef ENABLE_IPV6
        !           141:        memset(&sockname, 0, sizeof(struct sockaddr_storage));
        !           142:        if(ipv6)
        !           143:        {
        !           144: #ifdef IPV6_V6ONLY
        !           145:                if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
        !           146:                              (char *)&opt, sizeof(opt)) < 0)
        !           147:                {
        !           148:                        syslog(LOG_WARNING, "setsockopt(IPV6_V6ONLY): %m");
        !           149:                }
        !           150: #endif /* IPV6_V6ONLY */
        !           151:                struct sockaddr_in6 * sa = (struct sockaddr_in6 *)&sockname;
        !           152:                sa->sin6_family = AF_INET6;
        !           153:                sa->sin6_port = htons(SSDP_PORT);
        !           154:                sa->sin6_addr = in6addr_any;
        !           155:                sockname_len = sizeof(struct sockaddr_in6);
        !           156:        }
        !           157:        else
        !           158:        {
        !           159:                struct sockaddr_in * sa = (struct sockaddr_in *)&sockname;
        !           160:                sa->sin_family = AF_INET;
        !           161:                sa->sin_port = htons(SSDP_PORT);
        !           162: #ifdef SSDP_LISTEN_ON_SPECIFIC_ADDR
        !           163:                if(lan_addrs.lh_first != NULL && lan_addrs.lh_first->list.le_next == NULL)
        !           164:                {
        !           165:                        sa->sin_addr.s_addr = lan_addrs.lh_first->addr.s_addr;
        !           166:                        if(sa->sin_addr.s_addr == INADDR_NONE)
        !           167:                        {
        !           168:                                syslog(LOG_ERR, "no IPv4 address for interface %s",
        !           169:                                       lan_addrs.lh_first->ifname);
        !           170:                                close(s);
        !           171:                                return -1;
        !           172:                        }
        !           173:                }
        !           174:                else
        !           175: #endif /* SSDP_LISTEN_ON_SPECIFIC_ADDR */
        !           176:                        sa->sin_addr.s_addr = htonl(INADDR_ANY);
        !           177:                sockname_len = sizeof(struct sockaddr_in);
        !           178:        }
        !           179: #else /* ENABLE_IPV6 */
        !           180:        memset(&sockname, 0, sizeof(struct sockaddr_in));
        !           181:     sockname.sin_family = AF_INET;
        !           182:     sockname.sin_port = htons(SSDP_PORT);
        !           183: #ifdef SSDP_LISTEN_ON_SPECIFIC_ADDR
        !           184:        if(lan_addrs.lh_first != NULL && lan_addrs.lh_first->list.le_next == NULL)
        !           185:        {
        !           186:                sockname.sin_addr.s_addr = lan_addrs.lh_first->addr.s_addr;
        !           187:                if(sockname.sin_addr.s_addr == INADDR_NONE)
        !           188:                {
        !           189:                        syslog(LOG_ERR, "no IPv4 address for interface %s",
        !           190:                               lan_addrs.lh_first->ifname);
        !           191:                        close(s);
        !           192:                        return -1;
        !           193:                }
        !           194:        }
        !           195:        else
        !           196: #endif /* SSDP_LISTEN_ON_SPECIFIC_ADDR */
        !           197:        sockname.sin_addr.s_addr = htonl(INADDR_ANY);
        !           198:        sockname_len = sizeof(struct sockaddr_in);
        !           199: #endif /* ENABLE_IPV6 */
        !           200: 
        !           201:        if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopchar, sizeof(loopchar)) < 0)
        !           202:        {
        !           203:                syslog(LOG_WARNING, "setsockopt(IP_MULTICAST_LOOP): %m");
        !           204:        }
        !           205: 
        !           206:        if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
        !           207:        {
        !           208:                syslog(LOG_WARNING, "setsockopt(IP_MULTICAST_TTL): %m");
        !           209:        }
        !           210: 
        !           211:        if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
        !           212:        {
        !           213:                syslog(LOG_WARNING, "setsockopt(SO_REUSEADDR): %m");
        !           214:        }
        !           215: 
        !           216:     if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0)
        !           217:        {
        !           218:                syslog(LOG_ERR, "bind(udp%s): %m", ipv6 ? "6" : "");
        !           219:                close(s);
        !           220:                return -1;
        !           221:     }
        !           222: 
        !           223:        for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
        !           224:        {
        !           225:                if(AddDropMulticastMembership(s, lan_addr, ipv6, 0) < 0)
        !           226:                {
        !           227:                        syslog(LOG_WARNING, "Failed to add IPv%d multicast membership for interface %s.",
        !           228:                               ipv6 ? 6 : 4,
        !           229:                               lan_addr->ifname);
        !           230:                }
        !           231:        }
        !           232: 
        !           233:        return s;
        !           234: }

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