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>