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