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>