1 /* $Id: minissdp.c,v 1.84 2016/02/20 19:08:40 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2016 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
12 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
20 #include "upnpdescstrings.h"
21 #include "miniupnpdpath.h"
23 #include "upnpglobalvars.h"
25 #include "upnputils.h"
27 #include "asyncsendto.h"
28 #include "codelength.h"
32 #define SSDP_PORT (1900)
33 #define SSDP_MCAST_ADDR ("239.255.255.250")
34 #define LL_SSDP_MCAST_ADDR "FF02::C"
35 #define SL_SSDP_MCAST_ADDR "FF05::C"
36 #define GL_SSDP_MCAST_ADDR "FF0E::C"
38 /* AddMulticastMembership()
40 * param lan_addr lan address
43 AddMulticastMembership(int s
, struct lan_addr_s
* lan_addr
)
46 /* The ip_mreqn structure appeared in Linux 2.4. */
47 struct ip_mreq imr
; /* Ip multicast membership */
48 #else /* HAVE_IP_MREQN */
49 struct ip_mreqn imr
; /* Ip multicast membership */
50 #endif /* HAVE_IP_MREQN */
52 /* setting up imr structure */
53 imr
.imr_multiaddr
.s_addr
= inet_addr(SSDP_MCAST_ADDR
);
54 /*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/
56 imr
.imr_interface
.s_addr
= lan_addr
->addr
.s_addr
;
57 #else /* HAVE_IP_MREQN */
58 imr
.imr_address
.s_addr
= lan_addr
->addr
.s_addr
;
59 #ifndef MULTIPLE_EXTERNAL_IP
61 imr
.imr_ifindex
= lan_addr
->index
;
62 #else /* ENABLE_IPV6 */
63 imr
.imr_ifindex
= if_nametoindex(lan_addr
->ifname
);
64 #endif /* ENABLE_IPV6 */
65 #else /* MULTIPLE_EXTERNAL_IP */
67 #endif /* MULTIPLE_EXTERNAL_IP */
68 #endif /* HAVE_IP_MREQN */
71 if (setsockopt(s
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (void *)&imr
, sizeof(struct ip_mreq
)) < 0)
72 #else /* HAVE_IP_MREQN */
73 if (setsockopt(s
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (void *)&imr
, sizeof(struct ip_mreqn
)) < 0)
74 #endif /* HAVE_IP_MREQN */
76 syslog(LOG_ERR
, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m");
83 /* AddMulticastMembershipIPv6()
84 * param s socket (IPv6)
85 * param ifindex : interface index (0 : All interfaces) */
88 AddMulticastMembershipIPv6(int s
, unsigned int ifindex
)
92 memset(&mr
, 0, sizeof(mr
));
93 mr
.ipv6mr_interface
= ifindex
; /* 0 : all interfaces */
94 #ifndef IPV6_ADD_MEMBERSHIP
95 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
97 inet_pton(AF_INET6
, LL_SSDP_MCAST_ADDR
, &mr
.ipv6mr_multiaddr
);
98 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_ADD_MEMBERSHIP
, &mr
, sizeof(struct ipv6_mreq
)) < 0)
100 syslog(LOG_ERR
, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
103 inet_pton(AF_INET6
, SL_SSDP_MCAST_ADDR
, &mr
.ipv6mr_multiaddr
);
104 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_ADD_MEMBERSHIP
, &mr
, sizeof(struct ipv6_mreq
)) < 0)
106 syslog(LOG_ERR
, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
109 inet_pton(AF_INET6
, GL_SSDP_MCAST_ADDR
, &mr
.ipv6mr_multiaddr
);
110 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_ADD_MEMBERSHIP
, &mr
, sizeof(struct ipv6_mreq
)) < 0)
112 syslog(LOG_ERR
, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
119 /* Open and configure the socket listening for
120 * SSDP udp packets sent on 239.255.255.250 port 1900
121 * SSDP v6 udp packets sent on FF02::C, or FF05::C, port 1900 */
123 OpenAndConfSSDPReceiveSocket(int ipv6
)
126 struct sockaddr_storage sockname
;
127 socklen_t sockname_len
;
128 struct lan_addr_s
* lan_addr
;
131 if( (s
= socket(ipv6
? PF_INET6
: PF_INET
, SOCK_DGRAM
, 0)) < 0)
133 syslog(LOG_ERR
, "%s: socket(udp): %m",
134 "OpenAndConfSSDPReceiveSocket");
138 memset(&sockname
, 0, sizeof(struct sockaddr_storage
));
142 struct sockaddr_in6
* saddr
= (struct sockaddr_in6
*)&sockname
;
143 saddr
->sin6_family
= AF_INET6
;
144 saddr
->sin6_port
= htons(SSDP_PORT
);
145 saddr
->sin6_addr
= ipv6_bind_addr
;
146 sockname_len
= sizeof(struct sockaddr_in6
);
149 #endif /* ENABLE_IPV6 */
151 struct sockaddr_in
* saddr
= (struct sockaddr_in
*)&sockname
;
152 saddr
->sin_family
= AF_INET
;
153 saddr
->sin_port
= htons(SSDP_PORT
);
154 /* NOTE : it seems it doesnt work when binding on the specific address */
155 /*saddr->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/
156 saddr
->sin_addr
.s_addr
= htonl(INADDR_ANY
);
157 /*saddr->sin_addr.s_addr = inet_addr(ifaddr);*/
158 sockname_len
= sizeof(struct sockaddr_in
);
161 if(setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &j
, sizeof(j
)) < 0)
163 syslog(LOG_WARNING
, "setsockopt(udp, SO_REUSEADDR): %m");
166 if(!set_non_blocking(s
))
168 syslog(LOG_WARNING
, "%s: set_non_blocking(): %m",
169 "OpenAndConfSSDPReceiveSocket");
172 #if defined(SO_BINDTODEVICE) && !defined(MULTIPLE_EXTERNAL_IP)
173 /* One and only one LAN interface */
174 if(lan_addrs
.lh_first
!= NULL
&& lan_addrs
.lh_first
->list
.le_next
== NULL
175 && strlen(lan_addrs
.lh_first
->ifname
) > 0)
177 if(setsockopt(s
, SOL_SOCKET
, SO_BINDTODEVICE
,
178 lan_addrs
.lh_first
->ifname
,
179 strlen(lan_addrs
.lh_first
->ifname
)) < 0)
180 syslog(LOG_WARNING
, "%s: setsockopt(udp%s, SO_BINDTODEVICE, %s): %m",
181 "OpenAndConfSSDPReceiveSocket", ipv6
? "6" : "",
182 lan_addrs
.lh_first
->ifname
);
184 #endif /* defined(SO_BINDTODEVICE) && !defined(MULTIPLE_EXTERNAL_IP) */
186 if(bind(s
, (struct sockaddr
*)&sockname
, sockname_len
) < 0)
188 syslog(LOG_ERR
, "%s: bind(udp%s): %m",
189 "OpenAndConfSSDPReceiveSocket", ipv6
? "6" : "");
197 for(lan_addr
= lan_addrs
.lh_first
; lan_addr
!= NULL
; lan_addr
= lan_addr
->list
.le_next
)
199 if(AddMulticastMembershipIPv6(s
, lan_addr
->index
) < 0)
202 "Failed to add IPv6 multicast membership for interface %s",
203 lan_addr
->str
? lan_addr
->str
: "NULL");
210 for(lan_addr
= lan_addrs
.lh_first
; lan_addr
!= NULL
; lan_addr
= lan_addr
->list
.le_next
)
212 if(AddMulticastMembership(s
, lan_addr
) < 0)
215 "Failed to add multicast membership for interface %s",
216 strlen(lan_addr
->str
) ? lan_addr
->str
: "NULL");
224 /* open the UDP socket used to send SSDP notifications to
225 * the multicast group reserved for them */
227 OpenAndConfSSDPNotifySocket(in_addr_t addr
)
230 unsigned char loopchar
= 0;
232 unsigned char ttl
= 2; /* UDA v1.1 says :
233 The TTL for the IP packet SHOULD default to 2 and
234 SHOULD be configurable. */
235 /* TODO: Make TTL be configurable */
236 struct in_addr mc_if
;
237 struct sockaddr_in sockname
;
239 if( (s
= socket(PF_INET
, SOCK_DGRAM
, 0)) < 0)
241 syslog(LOG_ERR
, "socket(udp_notify): %m");
245 mc_if
.s_addr
= addr
; /*inet_addr(addr);*/
247 if(setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (char *)&loopchar
, sizeof(loopchar
)) < 0)
249 syslog(LOG_ERR
, "setsockopt(udp_notify, IP_MULTICAST_LOOP): %m");
254 if(setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *)&mc_if
, sizeof(mc_if
)) < 0)
256 syslog(LOG_ERR
, "setsockopt(udp_notify, IP_MULTICAST_IF): %m");
261 if(setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
)) < 0)
263 syslog(LOG_WARNING
, "setsockopt(udp_notify, IP_MULTICAST_TTL,): %m");
266 if(setsockopt(s
, SOL_SOCKET
, SO_BROADCAST
, &bcast
, sizeof(bcast
)) < 0)
268 syslog(LOG_ERR
, "setsockopt(udp_notify, SO_BROADCAST): %m");
273 /* bind() socket before using sendto() is not mandatory
274 * (sendto() will implicitly bind the socket when called on
276 * here it is used to se a specific sending address */
277 memset(&sockname
, 0, sizeof(struct sockaddr_in
));
278 sockname
.sin_family
= AF_INET
;
279 sockname
.sin_addr
.s_addr
= addr
; /*inet_addr(addr);*/
281 if (bind(s
, (struct sockaddr
*)&sockname
, sizeof(struct sockaddr_in
)) < 0)
283 syslog(LOG_ERR
, "bind(udp_notify): %m");
292 /* open the UDP socket used to send SSDP notifications to
293 * the multicast group reserved for them. IPv6 */
295 OpenAndConfSSDPNotifySocketIPv6(unsigned int if_index
)
298 unsigned int loop
= 0;
299 /* UDA 2.0 : The hop limit of each IP packet for a Site-Local scope
300 * multicast message SHALL be configurable and SHOULD default to 10 */
302 struct sockaddr_in6 sockname
;
304 s
= socket(PF_INET6
, SOCK_DGRAM
, 0);
307 syslog(LOG_ERR
, "socket(udp_notify IPv6): %m");
310 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &if_index
, sizeof(if_index
)) < 0)
312 syslog(LOG_ERR
, "setsockopt(udp_notify IPv6, IPV6_MULTICAST_IF, %u): %m", if_index
);
316 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &loop
, sizeof(loop
)) < 0)
318 syslog(LOG_ERR
, "setsockopt(udp_notify, IPV6_MULTICAST_LOOP): %m");
322 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &hop_limit
, sizeof(hop_limit
)) < 0)
324 syslog(LOG_ERR
, "setsockopt(udp_notify, IPV6_MULTICAST_HOPS): %m");
329 /* bind() socket before using sendto() is not mandatory
330 * (sendto() will implicitly bind the socket when called on
332 * but explicit bind permits to set port/scope_id/etc. */
333 memset(&sockname
, 0, sizeof(sockname
));
334 sockname
.sin6_family
= AF_INET6
;
335 sockname
.sin6_addr
= in6addr_any
;
336 /*sockname.sin6_port = htons(port);*/
337 /*sockname.sin6_scope_id = if_index;*/
338 if(bind(s
, (struct sockaddr
*)&sockname
, sizeof(sockname
)) < 0)
340 syslog(LOG_ERR
, "bind(udp_notify IPv6): %m");
350 OpenAndConfSSDPNotifySockets(int * sockets
)
351 /*OpenAndConfSSDPNotifySockets(int * sockets,
352 struct lan_addr_s * lan_addr, int n_lan_addr)*/
355 struct lan_addr_s
* lan_addr
;
357 for(i
=0, lan_addr
= lan_addrs
.lh_first
;
359 lan_addr
= lan_addr
->list
.le_next
)
361 sockets
[i
] = OpenAndConfSSDPNotifySocket(lan_addr
->addr
.s_addr
);
366 if(GETFLAG(IPV6DISABLEDMASK
))
372 sockets
[i
] = OpenAndConfSSDPNotifySocketIPv6(lan_addr
->index
);
390 * response from a LiveBox (Wanadoo)
392 CACHE-CONTROL: max-age=1800
393 DATE: Thu, 01 Jan 1970 04:03:23 GMT
395 LOCATION: http://192.168.0.1:49152/gatedesc.xml
396 SERVER: Linux/2.4.17, UPnP/1.0, Intel SDK for UPnP devices /1.2
398 USN: uuid:75802409-bccb-40e7-8e6c-fa095ecce13e::upnp:rootdevice
400 * response from a Linksys 802.11b :
402 Cache-Control:max-age=120
403 Location:http://192.168.5.1:5678/rootDesc.xml
404 Server:NT/5.0 UPnP/1.0
406 USN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777::upnp:rootdevice
410 /* Responds to a SSDP "M-SEARCH"
413 * st, st_len : ST: header
414 * suffix : suffix for USN: header
415 * host, port : our HTTP host, port
416 * delay : in milli-seconds
419 SendSSDPResponse(int s
, const struct sockaddr
* addr
,
420 const char * st
, int st_len
, const char * suffix
,
421 const char * host
, unsigned short http_port
,
423 unsigned short https_port
,
425 const char * uuidvalue
, unsigned int delay
)
428 char buf
[SSDP_PACKET_MAX_LEN
];
432 #ifdef ENABLE_HTTP_DATE
439 strftime(http_date
, sizeof(http_date
),
440 "%a, %d %b %Y %H:%M:%S GMT", &tm
);
443 st_is_uuid
= (st_len
== (int)strlen(uuidvalue
)) &&
444 (memcmp(uuidvalue
, st
, st_len
) == 0);
446 * follow guideline from document "UPnP Device Architecture 1.0"
447 * uppercase is recommended.
448 * DATE: is recommended
449 * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
450 * - check what to put in the 'Cache-Control' header
452 * have a look at the document "UPnP Device Architecture v1.1 */
453 l
= snprintf(buf
, sizeof(buf
), "HTTP/1.1 200 OK\r\n"
454 "CACHE-CONTROL: max-age=120\r\n"
455 #ifdef ENABLE_HTTP_DATE
459 "USN: %s%s%.*s%s\r\n"
461 "SERVER: " MINIUPNPD_SERVER_STRING
"\r\n"
462 "LOCATION: http://%s:%u" ROOTDESC_PATH
"\r\n"
464 "SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH
"\r\n"
466 "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
467 "01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
468 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
469 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
471 #ifdef ENABLE_HTTP_DATE
475 uuidvalue
, st_is_uuid
? "" : "::",
476 st_is_uuid
? 0 : st_len
, st
, suffix
,
477 host
, (unsigned int)http_port
,
479 host
, (unsigned int)https_port
,
481 upnp_bootid
, upnp_bootid
, upnp_configid
);
484 syslog(LOG_ERR
, "%s: snprintf failed %m",
485 "SendSSDPResponse()");
488 else if((unsigned)l
>=sizeof(buf
))
490 syslog(LOG_WARNING
, "%s: truncated output (%u>=%u)",
491 "SendSSDPResponse()", (unsigned)l
, (unsigned)sizeof(buf
));
494 addrlen
= (addr
->sa_family
== AF_INET6
)
495 ? sizeof(struct sockaddr_in6
) : sizeof(struct sockaddr_in
);
496 n
= sendto_schedule(s
, buf
, l
, 0,
497 addr
, addrlen
, delay
);
498 sockaddr_to_string(addr
, addr_str
, sizeof(addr_str
));
499 syslog(LOG_DEBUG
, "%s: %d bytes to %s ST: %.*s",
500 "SendSSDPResponse()",
501 n
, addr_str
, l
, buf
);
504 syslog(LOG_ERR
, "%s: sendto(udp): %m",
505 "SendSSDPResponse()");
513 } const known_service_types
[] =
515 {"upnp:rootdevice", 0, uuidvalue_igd
},
517 {"urn:schemas-upnp-org:device:InternetGatewayDevice:", 2, uuidvalue_igd
},
518 {"urn:schemas-upnp-org:device:WANConnectionDevice:", 2, uuidvalue_wcd
},
519 {"urn:schemas-upnp-org:device:WANDevice:", 2, uuidvalue_wan
},
520 {"urn:schemas-upnp-org:service:WANIPConnection:", 2, uuidvalue_wcd
},
521 {"urn:schemas-upnp-org:service:DeviceProtection:", 1, uuidvalue_igd
},
522 #ifdef ENABLE_6FC_SERVICE
523 {"urn:schemas-upnp-org:service:WANIPv6FirewallControl:", 1, uuidvalue_wcd
},
527 {"urn:schemas-upnp-org:device:InternetGatewayDevice:", 1, uuidvalue_igd
},
528 {"urn:schemas-upnp-org:device:WANConnectionDevice:", 1, uuidvalue_wcd
},
529 {"urn:schemas-upnp-org:device:WANDevice:", 1, uuidvalue_wan
},
530 {"urn:schemas-upnp-org:service:WANIPConnection:", 1, uuidvalue_wcd
},
532 {"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:", 1, uuidvalue_wan
},
533 #ifdef ADVERTISE_WANPPPCONN
534 /* We use WAN IP Connection, not PPP connection,
535 * but buggy control points may try to use WanPPPConnection
537 {"urn:schemas-upnp-org:service:WANPPPConnection:", 1, uuidvalue_wcd
},
538 #endif /* ADVERTISE_WANPPPCONN */
539 #ifdef ENABLE_L3F_SERVICE
540 {"urn:schemas-upnp-org:service:Layer3Forwarding:", 1, uuidvalue_igd
},
541 #endif /* ENABLE_L3F_SERVICE */
542 /* we might want to support urn:schemas-wifialliance-org:device:WFADevice:1
543 * urn:schemas-wifialliance-org:device:WFADevice:1
548 /* SendSSDPNotify() sends the SSDP NOTIFY to a specific
549 * destination, for a specific UPnP service or device */
551 SendSSDPNotify(int s
, const struct sockaddr
* dest
, socklen_t dest_len
,
552 const char * dest_str
,
553 const char * host
, unsigned short http_port
,
555 unsigned short https_port
,
557 const char * nt
, const char * suffix
,
558 const char * usn1
, const char * usn2
, const char * usn3
,
559 unsigned int lifetime
)
561 char bufr
[SSDP_PACKET_MAX_LEN
];
564 l
= snprintf(bufr
, sizeof(bufr
),
565 "NOTIFY * HTTP/1.1\r\n"
567 "CACHE-CONTROL: max-age=%u\r\n"
568 "LOCATION: http://%s:%u" ROOTDESC_PATH
"\r\n"
570 "SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH
"\r\n"
572 "SERVER: " MINIUPNPD_SERVER_STRING
"\r\n"
575 "NTS: ssdp:alive\r\n"
576 "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
577 "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
578 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
579 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
581 dest_str
, SSDP_PORT
, /* HOST: */
582 lifetime
, /* CACHE-CONTROL: */
583 host
, (unsigned int)http_port
, /* LOCATION: */
585 host
, (unsigned int)https_port
, /* SECURE-LOCATION: */
587 nt
, suffix
, /* NT: */
588 usn1
, usn2
, usn3
, suffix
, /* USN: */
589 upnp_bootid
, /* 01-NLS: */
590 upnp_bootid
, /* BOOTID.UPNP.ORG: */
591 upnp_configid
); /* CONFIGID.UPNP.ORG: */
593 syslog(LOG_ERR
, "%s: snprintf error", "SendSSDPNotify()");
595 } else if((unsigned int)l
>= sizeof(bufr
)) {
596 syslog(LOG_WARNING
, "%s: truncated output (%u>=%u)",
597 "SendSSDPNotify()", (unsigned)l
, (unsigned)sizeof(bufr
));
598 l
= sizeof(bufr
) - 1;
600 n
= sendto_or_schedule(s
, bufr
, l
, 0, dest
, dest_len
);
602 syslog(LOG_ERR
, "sendto(udp_notify=%d, %s): %m", s
,
603 host
? host
: "NULL");
605 syslog(LOG_NOTICE
, "sendto() sent %d out of %d bytes", n
, l
);
607 /* Due to the unreliable nature of UDP, devices SHOULD send the entire
608 * set of discovery messages more than once with some delay between
609 * sets e.g. a few hundred milliseconds. To avoid network congestion
610 * discovery messages SHOULD NOT be sent more than three times. */
611 n
= sendto_schedule(s
, bufr
, l
, 0, dest
, dest_len
, 250);
613 syslog(LOG_ERR
, "sendto(udp_notify=%d, %s): %m", s
,
614 host
? host
: "NULL");
618 /* SendSSDPNotifies() send SSPD NOTIFY for a specific
619 * LAN (network interface) for all devices / services */
622 SendSSDPNotifies(int s
, const char * host
, unsigned short http_port
,
623 unsigned short https_port
,
624 unsigned int lifetime
, int ipv6
)
627 SendSSDPNotifies(int s
, const char * host
, unsigned short http_port
,
628 unsigned int lifetime
, int ipv6
)
632 struct sockaddr_storage sockname
;
633 /* UDA 1.1 AnnexA and UDA 2.0 only allow/define the use of
634 * Link-Local and Site-Local multicast scopes */
635 static struct { const char * p1
, * p2
; } const mcast_addrs
[] =
636 { { LL_SSDP_MCAST_ADDR
, "[" LL_SSDP_MCAST_ADDR
"]" }, /* Link Local */
637 { SL_SSDP_MCAST_ADDR
, "[" SL_SSDP_MCAST_ADDR
"]" }, /* Site Local */
639 { GL_SSDP_MCAST_ADDR
, "[" GL_SSDP_MCAST_ADDR
"]" }, /* Global */
640 #endif /* ! UPNP_STRICT */
643 #else /* ENABLE_IPV6 */
644 struct sockaddr_in sockname
;
645 #endif /* ENABLE_IPV6 */
646 socklen_t sockname_len
;
647 const char * dest_str
;
652 #endif /* ENABLE_IPV6 */
654 memset(&sockname
, 0, sizeof(sockname
));
656 /* first iterate destinations for this LAN interface (only 1 for IPv4) */
657 for(j
= 0; (mcast_addrs
[j
].p1
!= 0 && ipv6
) || j
< 1; j
++) {
659 struct sockaddr_in6
* p
= (struct sockaddr_in6
*)&sockname
;
660 sockname_len
= sizeof(struct sockaddr_in6
);
661 p
->sin6_family
= AF_INET6
;
662 p
->sin6_port
= htons(SSDP_PORT
);
663 inet_pton(AF_INET6
, mcast_addrs
[j
].p1
, &(p
->sin6_addr
));
664 dest_str
= mcast_addrs
[j
].p2
;
665 /* UPnP Device Architecture 1.1 :
666 * Devices MUST multicast SSDP messages for each of the UPnP-enabled
667 * interfaces. The scope of multicast SSDP messages MUST be
668 * link local FF02::C if the message is sent from a link local address.
669 * If the message is sent from a global address it MUST be multicast
670 * using either global scope FF0E::C or site local scope FF05::C.
671 * In networks with complex topologies and overlapping sites, use of
672 * global scope is RECOMMENDED. */
674 #else /* ENABLE_IPV6 */
676 #endif /* ENABLE_IPV6 */
678 struct sockaddr_in
*p
= (struct sockaddr_in
*)&sockname
;
679 sockname_len
= sizeof(struct sockaddr_in
);
680 p
->sin_family
= AF_INET
;
681 p
->sin_port
= htons(SSDP_PORT
);
682 p
->sin_addr
.s_addr
= inet_addr(SSDP_MCAST_ADDR
);
683 dest_str
= SSDP_MCAST_ADDR
;
686 /* iterate all services / devices */
687 for(i
= 0; known_service_types
[i
].s
; i
++) {
691 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
692 SendSSDPNotify(s
, (struct sockaddr
*)&sockname
, sockname_len
, dest_str
,
697 known_service_types
[i
].s
, ver_str
, /* NT: */
698 known_service_types
[i
].uuid
, "::",
699 known_service_types
[i
].s
, /* ver_str, USN: */
701 /* for devices, also send NOTIFY on the uuid */
702 if(0==memcmp(known_service_types
[i
].s
,
703 "urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1)) {
704 SendSSDPNotify(s
, (struct sockaddr
*)&sockname
, sockname_len
, dest_str
,
709 known_service_types
[i
].uuid
, "", /* NT: */
710 known_service_types
[i
].uuid
, "", "", /* ver_str, USN: */
713 } /* for(i = 0; known_service_types[i].s; i++) */
715 } /* for(j = 0; (mcast_addrs[j].p1 != 0 && ipv6) || j < 1; j++) */
716 #endif /* ENABLE_IPV6 */
719 /* SendSSDPNotifies2() sends SSDP NOTIFY packets on all interfaces
720 * for all destinations, all devices / services */
722 SendSSDPNotifies2(int * sockets
,
723 unsigned short http_port
,
725 unsigned short https_port
,
727 unsigned int lifetime
)
730 struct lan_addr_s
* lan_addr
;
731 for(i
= 0, lan_addr
= lan_addrs
.lh_first
;
733 lan_addr
= lan_addr
->list
.le_next
) {
734 SendSSDPNotifies(sockets
[i
], lan_addr
->str
, http_port
,
741 if(sockets
[i
] >= 0) {
742 SendSSDPNotifies(sockets
[i
], ipv6_addr_for_http_with_brackets
, http_port
,
749 #endif /* ENABLE_IPV6 */
753 /* ProcessSSDPRequest()
754 * process SSDP M-SEARCH requests and responds to them */
757 ProcessSSDPRequest(int s
, unsigned short http_port
, unsigned short https_port
)
759 ProcessSSDPRequest(int s
, unsigned short http_port
)
766 struct sockaddr_storage sendername
;
767 len_r
= sizeof(struct sockaddr_storage
);
769 struct sockaddr_in sendername
;
770 len_r
= sizeof(struct sockaddr_in
);
773 n
= recvfrom(s
, bufr
, sizeof(bufr
), 0,
774 (struct sockaddr
*)&sendername
, &len_r
);
777 /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time)
778 * other errors : log to LOG_ERR */
779 if(errno
!= EAGAIN
&&
780 errno
!= EWOULDBLOCK
&&
783 syslog(LOG_ERR
, "recvfrom(udp): %m");
788 ProcessSSDPData(s
, bufr
, n
, (struct sockaddr
*)&sendername
,
789 http_port
, https_port
);
791 ProcessSSDPData(s
, bufr
, n
, (struct sockaddr
*)&sendername
,
799 ProcessSSDPData(int s
, const char *bufr
, int n
,
800 const struct sockaddr
* sender
,
801 unsigned short http_port
, unsigned short https_port
)
804 ProcessSSDPData(int s
, const char *bufr
, int n
,
805 const struct sockaddr
* sender
,
806 unsigned short http_port
)
810 struct lan_addr_s
* lan_addr
= NULL
;
811 const char * st
= NULL
;
816 const char * announced_host
= NULL
;
819 char announced_host_buf
[64];
822 #if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE)
825 unsigned int delay
= 50; /* Non-zero default delay to prevent flooding */
826 /* UPnP Device Architecture v1.1. 1.3.3 Search response :
827 * Devices responding to a multicast M-SEARCH SHOULD wait a random period
828 * of time between 0 seconds and the number of seconds specified in the
829 * MX field value of the search request before responding, in order to
830 * avoid flooding the requesting control point with search responses
831 * from multiple devices. If the search request results in the need for
832 * a multiple part response from the device, those multiple part
833 * responses SHOULD be spread at random intervals through the time period
834 * from 0 to the number of seconds specified in the MX header field. */
836 /* get the string representation of the sender address */
837 sockaddr_to_string(sender
, sender_str
, sizeof(sender_str
));
838 lan_addr
= get_lan_for_peer(sender
);
841 syslog(LOG_WARNING
, "SSDP packet sender %s not from a LAN, ignoring",
846 if(memcmp(bufr
, "NOTIFY", 6) == 0)
848 /* ignore NOTIFY packets. We could log the sender and device type */
851 else if(memcmp(bufr
, "M-SEARCH", 8) == 0)
856 while((i
< n
- 1) && (bufr
[i
] != '\r' || bufr
[i
+1] != '\n'))
859 if((i
< n
- 3) && (strncasecmp(bufr
+i
, "st:", 3) == 0))
863 while((*st
== ' ' || *st
== '\t') && (st
< bufr
+ n
))
865 while(st
[st_len
]!='\r' && st
[st_len
]!='\n'
866 && (st
+ st_len
< bufr
+ n
))
869 while(l
> 0 && st
[l
-1] != ':')
872 syslog(LOG_DEBUG
, "ST: %.*s (ver=%d)", st_len
, st
, st_ver
);
874 /*while(bufr[i+j]!='\r') j++;*/
875 /*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
877 #if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE)
878 else if((i
< n
- 3) && (strncasecmp(bufr
+i
, "mx:", 3) == 0))
884 while((*mx
== ' ' || *mx
== '\t') && (mx
< bufr
+ n
))
886 while(mx
[mx_len
]!='\r' && mx
[mx_len
]!='\n'
887 && (mx
+ mx_len
< bufr
+ n
))
890 syslog(LOG_DEBUG
, "MX: %.*s (value=%d)", mx_len
, mx
, mx_value
);
895 /* For multicast M-SEARCH requests, if the search request does
896 * not contain an MX header field, the device MUST silently
897 * discard and ignore the search request. */
899 syslog(LOG_INFO
, "ignoring SSDP packet missing MX: header");
901 } else if(mx_value
> 5) {
902 /* If the MX header field specifies a field value greater
903 * than 5, the device SHOULD assume that it contained the
904 * value 5 or less. */
907 #elif defined(DELAY_MSEARCH_RESPONSE)
910 } else if(mx_value
> 5) {
911 /* If the MX header field specifies a field value greater
912 * than 5, the device SHOULD assume that it contained the
913 * value 5 or less. */
917 /*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
919 if(st
&& (st_len
> 0))
921 syslog(LOG_INFO
, "SSDP M-SEARCH from %s ST: %.*s",
922 sender_str
, st_len
, st
);
923 /* find in which sub network the client is */
924 if(sender
->sa_family
== AF_INET
)
926 if (lan_addr
== NULL
)
929 "Can't find in which sub network the client %s is",
933 announced_host
= lan_addr
->str
;
938 /* IPv6 address with brackets */
941 struct in6_addr addr6
;
942 size_t addr6_len
= sizeof(addr6
);
943 /* retrieve the IPv6 address which
944 * will be used locally to reach sender */
945 memset(&addr6
, 0, sizeof(addr6
));
946 if(get_src_for_route_to (sender
, &addr6
, &addr6_len
, &index
) < 0) {
947 syslog(LOG_WARNING
, "get_src_for_route_to() failed, using %s", ipv6_addr_for_http_with_brackets
);
948 announced_host
= ipv6_addr_for_http_with_brackets
;
950 if(inet_ntop(AF_INET6
, &addr6
,
951 announced_host_buf
+1,
952 sizeof(announced_host_buf
) - 2)) {
953 announced_host_buf
[0] = '[';
954 i
= strlen(announced_host_buf
);
955 if(i
< (int)sizeof(announced_host_buf
) - 1) {
956 announced_host_buf
[i
] = ']';
957 announced_host_buf
[i
+1] = '\0';
959 syslog(LOG_NOTICE
, "cannot suffix %s with ']'",
962 announced_host
= announced_host_buf
;
964 syslog(LOG_NOTICE
, "inet_ntop() failed %m");
965 announced_host
= ipv6_addr_for_http_with_brackets
;
969 announced_host
= ipv6_addr_for_http_with_brackets
;
973 /* Responds to request with a device as ST header */
974 for(i
= 0; known_service_types
[i
].s
; i
++)
976 l
= (int)strlen(known_service_types
[i
].s
);
977 if(l
<=st_len
&& (0 == memcmp(st
, known_service_types
[i
].s
, l
))
979 && (st_ver
<= known_service_types
[i
].version
)
980 /* only answer for service version lower or equal of supported one */
984 /* SSDP_RESPOND_SAME_VERSION :
985 * response is urn:schemas-upnp-org:service:WANIPConnection:1 when
986 * M-SEARCH included urn:schemas-upnp-org:service:WANIPConnection:1
987 * else the implemented versions is included in the response
989 * From UPnP Device Architecture v1.1 :
990 * 1.3.2 [...] Updated versions of device and service types
991 * are REQUIRED to be fully backward compatible with
992 * previous versions. Devices MUST respond to M-SEARCH
993 * requests for any supported version. For example, if a
994 * device implements “urn:schemas-upnporg:service:xyz:2”,
995 * it MUST respond to search requests for both that type
996 * and “urn:schemas-upnp-org:service:xyz:1”. The response
997 * MUST specify the same version as was contained in the
998 * search request. [...] */
999 #ifndef SSDP_RESPOND_SAME_VERSION
1003 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
1005 syslog(LOG_INFO
, "Single search found");
1006 #ifdef DELAY_MSEARCH_RESPONSE
1007 delay
= random() / (1 + RAND_MAX
/ (1000 * mx_value
));
1009 syslog(LOG_DEBUG
, "mx=%dsec delay=%ums", mx_value
, delay
);
1012 SendSSDPResponse(s
, sender
,
1013 #ifdef SSDP_RESPOND_SAME_VERSION
1016 known_service_types
[i
].s
, l
, ver_str
,
1018 announced_host
, http_port
,
1022 known_service_types
[i
].uuid
,
1027 /* Responds to request with ST: ssdp:all */
1028 /* strlen("ssdp:all") == 8 */
1029 if(st_len
==8 && (0 == memcmp(st
, "ssdp:all", 8)))
1031 #ifdef DELAY_MSEARCH_RESPONSE
1032 unsigned int delay_increment
= (mx_value
* 1000) / 15;
1034 syslog(LOG_INFO
, "ssdp:all found");
1035 for(i
=0; known_service_types
[i
].s
; i
++)
1037 #ifdef DELAY_MSEARCH_RESPONSE
1038 delay
+= delay_increment
;
1043 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
1044 l
= (int)strlen(known_service_types
[i
].s
);
1045 SendSSDPResponse(s
, sender
,
1046 known_service_types
[i
].s
, l
, ver_str
,
1047 announced_host
, http_port
,
1051 known_service_types
[i
].uuid
,
1054 /* also answer for uuid */
1055 #ifdef DELAY_MSEARCH_RESPONSE
1056 delay
+= delay_increment
;
1058 SendSSDPResponse(s
, sender
, uuidvalue_igd
, strlen(uuidvalue_igd
), "",
1059 announced_host
, http_port
,
1063 uuidvalue_igd
, delay
);
1064 #ifdef DELAY_MSEARCH_RESPONSE
1065 delay
+= delay_increment
;
1067 SendSSDPResponse(s
, sender
, uuidvalue_wan
, strlen(uuidvalue_wan
), "",
1068 announced_host
, http_port
,
1072 uuidvalue_wan
, delay
);
1073 #ifdef DELAY_MSEARCH_RESPONSE
1074 delay
+= delay_increment
;
1076 SendSSDPResponse(s
, sender
, uuidvalue_wcd
, strlen(uuidvalue_wcd
), "",
1077 announced_host
, http_port
,
1081 uuidvalue_wcd
, delay
);
1083 /* responds to request by UUID value */
1084 l
= (int)strlen(uuidvalue_igd
);
1087 #ifdef DELAY_MSEARCH_RESPONSE
1088 delay
= random() / (1 + RAND_MAX
/ (1000 * mx_value
));
1090 if(0 == memcmp(st
, uuidvalue_igd
, l
))
1092 syslog(LOG_INFO
, "ssdp:uuid (IGD) found");
1093 SendSSDPResponse(s
, sender
, st
, st_len
, "",
1094 announced_host
, http_port
,
1098 uuidvalue_igd
, delay
);
1100 else if(0 == memcmp(st
, uuidvalue_wan
, l
))
1102 syslog(LOG_INFO
, "ssdp:uuid (WAN) found");
1103 SendSSDPResponse(s
, sender
, st
, st_len
, "",
1104 announced_host
, http_port
,
1108 uuidvalue_wan
, delay
);
1110 else if(0 == memcmp(st
, uuidvalue_wcd
, l
))
1112 syslog(LOG_INFO
, "ssdp:uuid (WCD) found");
1113 SendSSDPResponse(s
, sender
, st
, st_len
, "",
1114 announced_host
, http_port
,
1118 uuidvalue_wcd
, delay
);
1124 syslog(LOG_INFO
, "Invalid SSDP M-SEARCH from %s", sender_str
);
1129 syslog(LOG_NOTICE
, "Unknown udp packet received from %s", sender_str
);
1134 SendSSDPbyebye(int s
, const struct sockaddr
* dest
, socklen_t destlen
,
1135 const char * dest_str
,
1136 const char * nt
, const char * suffix
,
1137 const char * usn1
, const char * usn2
, const char * usn3
)
1140 char bufr
[SSDP_PACKET_MAX_LEN
];
1142 l
= snprintf(bufr
, sizeof(bufr
),
1143 "NOTIFY * HTTP/1.1\r\n"
1147 "NTS: ssdp:byebye\r\n"
1148 "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
1149 "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
1150 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
1151 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
1153 dest_str
, SSDP_PORT
, /* HOST : */
1154 nt
, suffix
, /* NT: */
1155 usn1
, usn2
, usn3
, suffix
, /* USN: */
1156 upnp_bootid
, upnp_bootid
, upnp_configid
);
1159 syslog(LOG_ERR
, "%s: snprintf error", "SendSSDPbyebye()");
1162 else if((unsigned int)l
>= sizeof(bufr
))
1164 syslog(LOG_WARNING
, "%s: truncated output (%u>=%u)",
1165 "SendSSDPbyebye()", (unsigned)l
, (unsigned)sizeof(bufr
));
1166 l
= sizeof(bufr
) - 1;
1168 n
= sendto_or_schedule(s
, bufr
, l
, 0, dest
, destlen
);
1171 syslog(LOG_ERR
, "sendto(udp_shutdown=%d): %m", s
);
1176 syslog(LOG_NOTICE
, "sendto() sent %d out of %d bytes", n
, l
);
1182 /* This will broadcast ssdp:byebye notifications to inform
1183 * the network that UPnP is going down. */
1185 SendSSDPGoodbye(int * sockets
, int n_sockets
)
1187 struct sockaddr_in sockname4
;
1189 struct sockaddr_in6 sockname6
;
1190 struct sockaddr
* sockname
;
1191 socklen_t socknamelen
;
1197 const char * dest_str
;
1199 memset(&sockname4
, 0, sizeof(struct sockaddr_in
));
1200 sockname4
.sin_family
= AF_INET
;
1201 sockname4
.sin_port
= htons(SSDP_PORT
);
1202 sockname4
.sin_addr
.s_addr
= inet_addr(SSDP_MCAST_ADDR
);
1204 memset(&sockname6
, 0, sizeof(struct sockaddr_in6
));
1205 sockname6
.sin6_family
= AF_INET6
;
1206 sockname6
.sin6_port
= htons(SSDP_PORT
);
1207 inet_pton(AF_INET6
, LL_SSDP_MCAST_ADDR
, &(sockname6
.sin6_addr
));
1209 dest_str
= SSDP_MCAST_ADDR
;
1212 for(j
=0; j
<n_sockets
; j
++)
1219 dest_str
= "[" LL_SSDP_MCAST_ADDR
"]";
1220 sockname
= (struct sockaddr
*)&sockname6
;
1221 socknamelen
= sizeof(struct sockaddr_in6
);
1223 dest_str
= SSDP_MCAST_ADDR
;
1224 sockname
= (struct sockaddr
*)&sockname4
;
1225 socknamelen
= sizeof(struct sockaddr_in
);
1228 for(i
=0; known_service_types
[i
].s
; i
++)
1233 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
1234 ret
+= SendSSDPbyebye(sockets
[j
],
1236 sockname
, socknamelen
,
1238 (struct sockaddr
*)&sockname4
, sizeof(struct sockaddr_in
),
1241 known_service_types
[i
].s
, ver_str
, /* NT: */
1242 known_service_types
[i
].uuid
, "::",
1243 known_service_types
[i
].s
); /* ver_str, USN: */
1244 if(0==memcmp(known_service_types
[i
].s
,
1245 "urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1))
1247 ret
+= SendSSDPbyebye(sockets
[j
],
1249 sockname
, socknamelen
,
1251 (struct sockaddr
*)&sockname4
, sizeof(struct sockaddr_in
),
1254 known_service_types
[i
].uuid
, "", /* NT: */
1255 known_service_types
[i
].uuid
, "", ""); /* ver_str, USN: */
1262 /* SubmitServicesToMiniSSDPD() :
1263 * register services offered by MiniUPnPd to a running instance of
1266 SubmitServicesToMiniSSDPD(const char * host
, unsigned short port
) {
1267 struct sockaddr_un addr
;
1269 unsigned char buffer
[2048];
1275 s
= socket(AF_UNIX
, SOCK_STREAM
, 0);
1277 syslog(LOG_ERR
, "socket(unix): %m");
1280 addr
.sun_family
= AF_UNIX
;
1281 strncpy(addr
.sun_path
, minissdpdsocketpath
, sizeof(addr
.sun_path
));
1282 addr
.sun_path
[sizeof(addr
.sun_path
) - 1] = '\0';
1283 if(connect(s
, (struct sockaddr
*)&addr
, sizeof(struct sockaddr_un
)) < 0) {
1284 syslog(LOG_ERR
, "connect(\"%s\"): %m", minissdpdsocketpath
);
1288 for(i
= 0; known_service_types
[i
].s
; i
++) {
1289 buffer
[0] = 4; /* request type 4 : submit service */
1290 /* 4 strings following : ST (service type), USN, Server, Location */
1292 l
= (int)strlen(known_service_types
[i
].s
);
1296 memcpy(p
, known_service_types
[i
].s
, l
);
1303 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
1304 l
= snprintf(strbuf
, sizeof(strbuf
), "%s::%s%s",
1305 known_service_types
[i
].uuid
, known_service_types
[i
].s
, ver_str
);
1307 syslog(LOG_WARNING
, "SubmitServicesToMiniSSDPD: snprintf %m");
1309 } else if((unsigned)l
>=sizeof(strbuf
)) {
1310 l
= sizeof(strbuf
) - 1;
1313 memcpy(p
, strbuf
, l
);
1315 l
= (int)strlen(MINIUPNPD_SERVER_STRING
);
1317 memcpy(p
, MINIUPNPD_SERVER_STRING
, l
);
1319 l
= snprintf(strbuf
, sizeof(strbuf
), "http://%s:%u" ROOTDESC_PATH
,
1320 host
, (unsigned int)port
);
1322 syslog(LOG_WARNING
, "SubmitServicesToMiniSSDPD: snprintf %m");
1324 } else if((unsigned)l
>=sizeof(strbuf
)) {
1325 l
= sizeof(strbuf
) - 1;
1328 memcpy(p
, strbuf
, l
);
1330 /* now write the encoded data */
1331 n
= p
- buffer
; /* bytes to send */
1332 p
= buffer
; /* start */
1338 syslog(LOG_ERR
, "write(): %m");
1341 } else if (l
== 0) {
1342 syslog(LOG_ERR
, "write() returned 0");