File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / minissdpd / openssdpsocket.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:25:11 2023 UTC (14 months, 4 weeks ago) by misho
Branches: miniupnpd, MAIN
CVS tags: v2_3_3p0, HEAD
Version 2.3.3p0

    1: /* $Id: openssdpsocket.c,v 1.1.1.1 2023/09/27 11:25:11 misho 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>