1 /* $Id: minissdp.c,v 1.83 2015/12/15 11:08:24 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2015 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 struct sockaddr_in6 sockname
;
301 s
= socket(PF_INET6
, SOCK_DGRAM
, 0);
304 syslog(LOG_ERR
, "socket(udp_notify IPv6): %m");
307 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &if_index
, sizeof(if_index
)) < 0)
309 syslog(LOG_ERR
, "setsockopt(udp_notify IPv6, IPV6_MULTICAST_IF, %u): %m", if_index
);
313 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &loop
, sizeof(loop
)) < 0)
315 syslog(LOG_ERR
, "setsockopt(udp_notify, IPV6_MULTICAST_LOOP): %m");
320 /* bind() socket before using sendto() is not mandatory
321 * (sendto() will implicitly bind the socket when called on
323 * but explicit bind permits to set port/scope_id/etc. */
324 memset(&sockname
, 0, sizeof(sockname
));
325 sockname
.sin6_family
= AF_INET6
;
326 sockname
.sin6_addr
= in6addr_any
;
327 /*sockname.sin6_port = htons(port);*/
328 /*sockname.sin6_scope_id = if_index;*/
329 if(bind(s
, (struct sockaddr
*)&sockname
, sizeof(sockname
)) < 0)
331 syslog(LOG_ERR
, "bind(udp_notify IPv6): %m");
341 OpenAndConfSSDPNotifySockets(int * sockets
)
342 /*OpenAndConfSSDPNotifySockets(int * sockets,
343 struct lan_addr_s * lan_addr, int n_lan_addr)*/
346 struct lan_addr_s
* lan_addr
;
348 for(i
=0, lan_addr
= lan_addrs
.lh_first
;
350 lan_addr
= lan_addr
->list
.le_next
)
352 sockets
[i
] = OpenAndConfSSDPNotifySocket(lan_addr
->addr
.s_addr
);
357 if(GETFLAG(IPV6DISABLEDMASK
))
363 sockets
[i
] = OpenAndConfSSDPNotifySocketIPv6(lan_addr
->index
);
381 * response from a LiveBox (Wanadoo)
383 CACHE-CONTROL: max-age=1800
384 DATE: Thu, 01 Jan 1970 04:03:23 GMT
386 LOCATION: http://192.168.0.1:49152/gatedesc.xml
387 SERVER: Linux/2.4.17, UPnP/1.0, Intel SDK for UPnP devices /1.2
389 USN: uuid:75802409-bccb-40e7-8e6c-fa095ecce13e::upnp:rootdevice
391 * response from a Linksys 802.11b :
393 Cache-Control:max-age=120
394 Location:http://192.168.5.1:5678/rootDesc.xml
395 Server:NT/5.0 UPnP/1.0
397 USN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777::upnp:rootdevice
401 /* Responds to a SSDP "M-SEARCH"
404 * st, st_len : ST: header
405 * suffix : suffix for USN: header
406 * host, port : our HTTP host, port
407 * delay : in milli-seconds
410 SendSSDPResponse(int s
, const struct sockaddr
* addr
,
411 const char * st
, int st_len
, const char * suffix
,
412 const char * host
, unsigned short http_port
,
414 unsigned short https_port
,
416 const char * uuidvalue
, unsigned int delay
)
419 char buf
[SSDP_PACKET_MAX_LEN
];
423 #ifdef ENABLE_HTTP_DATE
430 strftime(http_date
, sizeof(http_date
),
431 "%a, %d %b %Y %H:%M:%S GMT", &tm
);
434 st_is_uuid
= (st_len
== (int)strlen(uuidvalue
)) &&
435 (memcmp(uuidvalue
, st
, st_len
) == 0);
437 * follow guideline from document "UPnP Device Architecture 1.0"
438 * uppercase is recommended.
439 * DATE: is recommended
440 * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
441 * - check what to put in the 'Cache-Control' header
443 * have a look at the document "UPnP Device Architecture v1.1 */
444 l
= snprintf(buf
, sizeof(buf
), "HTTP/1.1 200 OK\r\n"
445 "CACHE-CONTROL: max-age=120\r\n"
446 #ifdef ENABLE_HTTP_DATE
450 "USN: %s%s%.*s%s\r\n"
452 "SERVER: " MINIUPNPD_SERVER_STRING
"\r\n"
453 "LOCATION: http://%s:%u" ROOTDESC_PATH
"\r\n"
455 "SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH
"\r\n"
457 "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
458 "01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
459 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
460 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
462 #ifdef ENABLE_HTTP_DATE
466 uuidvalue
, st_is_uuid
? "" : "::",
467 st_is_uuid
? 0 : st_len
, st
, suffix
,
468 host
, (unsigned int)http_port
,
470 host
, (unsigned int)https_port
,
472 upnp_bootid
, upnp_bootid
, upnp_configid
);
475 syslog(LOG_ERR
, "%s: snprintf failed %m",
476 "SendSSDPResponse()");
479 else if((unsigned)l
>=sizeof(buf
))
481 syslog(LOG_WARNING
, "%s: truncated output (%u>=%u)",
482 "SendSSDPResponse()", (unsigned)l
, (unsigned)sizeof(buf
));
485 addrlen
= (addr
->sa_family
== AF_INET6
)
486 ? sizeof(struct sockaddr_in6
) : sizeof(struct sockaddr_in
);
487 n
= sendto_schedule(s
, buf
, l
, 0,
488 addr
, addrlen
, delay
);
489 sockaddr_to_string(addr
, addr_str
, sizeof(addr_str
));
490 syslog(LOG_DEBUG
, "%s: %d bytes to %s ST: %.*s",
491 "SendSSDPResponse()",
492 n
, addr_str
, l
, buf
);
495 syslog(LOG_ERR
, "%s: sendto(udp): %m",
496 "SendSSDPResponse()");
504 } const known_service_types
[] =
506 {"upnp:rootdevice", 0, uuidvalue_igd
},
508 {"urn:schemas-upnp-org:device:InternetGatewayDevice:", 2, uuidvalue_igd
},
509 {"urn:schemas-upnp-org:device:WANConnectionDevice:", 2, uuidvalue_wcd
},
510 {"urn:schemas-upnp-org:device:WANDevice:", 2, uuidvalue_wan
},
511 {"urn:schemas-upnp-org:service:WANIPConnection:", 2, uuidvalue_wcd
},
512 {"urn:schemas-upnp-org:service:DeviceProtection:", 1, uuidvalue_igd
},
513 #ifdef ENABLE_6FC_SERVICE
514 {"urn:schemas-upnp-org:service:WANIPv6FirewallControl:", 1, uuidvalue_wcd
},
518 {"urn:schemas-upnp-org:device:InternetGatewayDevice:", 1, uuidvalue_igd
},
519 {"urn:schemas-upnp-org:device:WANConnectionDevice:", 1, uuidvalue_wcd
},
520 {"urn:schemas-upnp-org:device:WANDevice:", 1, uuidvalue_wan
},
521 {"urn:schemas-upnp-org:service:WANIPConnection:", 1, uuidvalue_wcd
},
523 {"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:", 1, uuidvalue_wan
},
524 #ifdef ADVERTISE_WANPPPCONN
525 /* We use WAN IP Connection, not PPP connection,
526 * but buggy control points may try to use WanPPPConnection
528 {"urn:schemas-upnp-org:service:WANPPPConnection:", 1, uuidvalue_wcd
},
529 #endif /* ADVERTISE_WANPPPCONN */
530 #ifdef ENABLE_L3F_SERVICE
531 {"urn:schemas-upnp-org:service:Layer3Forwarding:", 1, uuidvalue_igd
},
532 #endif /* ENABLE_L3F_SERVICE */
533 /* we might want to support urn:schemas-wifialliance-org:device:WFADevice:1
534 * urn:schemas-wifialliance-org:device:WFADevice:1
539 /* SendSSDPNotify() sends the SSDP NOTIFY to a specific
540 * destination, for a specific UPnP service or device */
542 SendSSDPNotify(int s
, const struct sockaddr
* dest
, socklen_t dest_len
,
543 const char * dest_str
,
544 const char * host
, unsigned short http_port
,
546 unsigned short https_port
,
548 const char * nt
, const char * suffix
,
549 const char * usn1
, const char * usn2
, const char * usn3
,
550 unsigned int lifetime
)
552 char bufr
[SSDP_PACKET_MAX_LEN
];
555 l
= snprintf(bufr
, sizeof(bufr
),
556 "NOTIFY * HTTP/1.1\r\n"
558 "CACHE-CONTROL: max-age=%u\r\n"
559 "LOCATION: http://%s:%u" ROOTDESC_PATH
"\r\n"
561 "SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH
"\r\n"
563 "SERVER: " MINIUPNPD_SERVER_STRING
"\r\n"
566 "NTS: ssdp:alive\r\n"
567 "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
568 "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
569 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
570 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
572 dest_str
, SSDP_PORT
, /* HOST: */
573 lifetime
, /* CACHE-CONTROL: */
574 host
, (unsigned int)http_port
, /* LOCATION: */
576 host
, (unsigned int)https_port
, /* SECURE-LOCATION: */
578 nt
, suffix
, /* NT: */
579 usn1
, usn2
, usn3
, suffix
, /* USN: */
580 upnp_bootid
, /* 01-NLS: */
581 upnp_bootid
, /* BOOTID.UPNP.ORG: */
582 upnp_configid
); /* CONFIGID.UPNP.ORG: */
584 syslog(LOG_ERR
, "%s: snprintf error", "SendSSDPNotify()");
586 } else if((unsigned int)l
>= sizeof(bufr
)) {
587 syslog(LOG_WARNING
, "%s: truncated output (%u>=%u)",
588 "SendSSDPNotify()", (unsigned)l
, (unsigned)sizeof(bufr
));
589 l
= sizeof(bufr
) - 1;
591 n
= sendto_or_schedule(s
, bufr
, l
, 0, dest
, dest_len
);
593 syslog(LOG_ERR
, "sendto(udp_notify=%d, %s): %m", s
,
594 host
? host
: "NULL");
596 syslog(LOG_NOTICE
, "sendto() sent %d out of %d bytes", n
, l
);
598 /* Due to the unreliable nature of UDP, devices SHOULD send the entire
599 * set of discovery messages more than once with some delay between
600 * sets e.g. a few hundred milliseconds. To avoid network congestion
601 * discovery messages SHOULD NOT be sent more than three times. */
602 n
= sendto_schedule(s
, bufr
, l
, 0, dest
, dest_len
, 250);
604 syslog(LOG_ERR
, "sendto(udp_notify=%d, %s): %m", s
,
605 host
? host
: "NULL");
609 /* SendSSDPNotifies() send SSPD NOTIFY for a specific
610 * LAN (network interface) for all devices / services */
613 SendSSDPNotifies(int s
, const char * host
, unsigned short http_port
,
614 unsigned short https_port
,
615 unsigned int lifetime
, int ipv6
)
618 SendSSDPNotifies(int s
, const char * host
, unsigned short http_port
,
619 unsigned int lifetime
, int ipv6
)
623 struct sockaddr_storage sockname
;
624 static struct { const char * p1
, * p2
; } const mcast_addrs
[] =
625 { { LL_SSDP_MCAST_ADDR
, "[" LL_SSDP_MCAST_ADDR
"]" }, /* Link Local */
626 { SL_SSDP_MCAST_ADDR
, "[" SL_SSDP_MCAST_ADDR
"]" }, /* Site Local */
627 { GL_SSDP_MCAST_ADDR
, "[" GL_SSDP_MCAST_ADDR
"]" }, /* Global */
630 #else /* ENABLE_IPV6 */
631 struct sockaddr_in sockname
;
632 #endif /* ENABLE_IPV6 */
633 socklen_t sockname_len
;
634 const char * dest_str
;
639 #endif /* ENABLE_IPV6 */
641 memset(&sockname
, 0, sizeof(sockname
));
643 /* first iterate destinations for this LAN interface (only 1 for IPv4) */
644 for(j
= 0; (mcast_addrs
[j
].p1
!= 0 && ipv6
) || j
< 1; j
++) {
646 struct sockaddr_in6
* p
= (struct sockaddr_in6
*)&sockname
;
647 sockname_len
= sizeof(struct sockaddr_in6
);
648 p
->sin6_family
= AF_INET6
;
649 p
->sin6_port
= htons(SSDP_PORT
);
650 inet_pton(AF_INET6
, mcast_addrs
[j
].p1
, &(p
->sin6_addr
));
651 dest_str
= mcast_addrs
[j
].p2
;
652 /* UPnP Device Architecture 1.1 :
653 * Devices MUST multicast SSDP messages for each of the UPnP-enabled
654 * interfaces. The scope of multicast SSDP messages MUST be
655 * link local FF02::C if the message is sent from a link local address.
656 * If the message is sent from a global address it MUST be multicast
657 * using either global scope FF0E::C or site local scope FF05::C.
658 * In networks with complex topologies and overlapping sites, use of
659 * global scope is RECOMMENDED. */
661 #else /* ENABLE_IPV6 */
663 #endif /* ENABLE_IPV6 */
665 struct sockaddr_in
*p
= (struct sockaddr_in
*)&sockname
;
666 sockname_len
= sizeof(struct sockaddr_in
);
667 p
->sin_family
= AF_INET
;
668 p
->sin_port
= htons(SSDP_PORT
);
669 p
->sin_addr
.s_addr
= inet_addr(SSDP_MCAST_ADDR
);
670 dest_str
= SSDP_MCAST_ADDR
;
673 /* iterate all services / devices */
674 for(i
= 0; known_service_types
[i
].s
; i
++) {
678 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
679 SendSSDPNotify(s
, (struct sockaddr
*)&sockname
, sockname_len
, dest_str
,
684 known_service_types
[i
].s
, ver_str
, /* NT: */
685 known_service_types
[i
].uuid
, "::",
686 known_service_types
[i
].s
, /* ver_str, USN: */
688 /* for devices, also send NOTIFY on the uuid */
689 if(0==memcmp(known_service_types
[i
].s
,
690 "urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1)) {
691 SendSSDPNotify(s
, (struct sockaddr
*)&sockname
, sockname_len
, dest_str
,
696 known_service_types
[i
].uuid
, "", /* NT: */
697 known_service_types
[i
].uuid
, "", "", /* ver_str, USN: */
700 } /* for(i = 0; known_service_types[i].s; i++) */
702 } /* for(j = 0; (mcast_addrs[j].p1 != 0 && ipv6) || j < 1; j++) */
703 #endif /* ENABLE_IPV6 */
706 /* SendSSDPNotifies2() sends SSDP NOTIFY packets on all interfaces
707 * for all destinations, all devices / services */
709 SendSSDPNotifies2(int * sockets
,
710 unsigned short http_port
,
712 unsigned short https_port
,
714 unsigned int lifetime
)
717 struct lan_addr_s
* lan_addr
;
718 for(i
= 0, lan_addr
= lan_addrs
.lh_first
;
720 lan_addr
= lan_addr
->list
.le_next
) {
721 SendSSDPNotifies(sockets
[i
], lan_addr
->str
, http_port
,
728 if(sockets
[i
] >= 0) {
729 SendSSDPNotifies(sockets
[i
], ipv6_addr_for_http_with_brackets
, http_port
,
736 #endif /* ENABLE_IPV6 */
740 /* ProcessSSDPRequest()
741 * process SSDP M-SEARCH requests and responds to them */
744 ProcessSSDPRequest(int s
, unsigned short http_port
, unsigned short https_port
)
746 ProcessSSDPRequest(int s
, unsigned short http_port
)
753 struct sockaddr_storage sendername
;
754 len_r
= sizeof(struct sockaddr_storage
);
756 struct sockaddr_in sendername
;
757 len_r
= sizeof(struct sockaddr_in
);
760 n
= recvfrom(s
, bufr
, sizeof(bufr
), 0,
761 (struct sockaddr
*)&sendername
, &len_r
);
764 /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time)
765 * other errors : log to LOG_ERR */
766 if(errno
!= EAGAIN
&&
767 errno
!= EWOULDBLOCK
&&
770 syslog(LOG_ERR
, "recvfrom(udp): %m");
775 ProcessSSDPData(s
, bufr
, n
, (struct sockaddr
*)&sendername
,
776 http_port
, https_port
);
778 ProcessSSDPData(s
, bufr
, n
, (struct sockaddr
*)&sendername
,
786 ProcessSSDPData(int s
, const char *bufr
, int n
,
787 const struct sockaddr
* sender
,
788 unsigned short http_port
, unsigned short https_port
)
791 ProcessSSDPData(int s
, const char *bufr
, int n
,
792 const struct sockaddr
* sender
,
793 unsigned short http_port
)
797 struct lan_addr_s
* lan_addr
= NULL
;
798 const char * st
= NULL
;
803 const char * announced_host
= NULL
;
806 char announced_host_buf
[64];
809 #if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE)
812 unsigned int delay
= 50; /* Non-zero default delay to prevent flooding */
813 /* UPnP Device Architecture v1.1. 1.3.3 Search response :
814 * Devices responding to a multicast M-SEARCH SHOULD wait a random period
815 * of time between 0 seconds and the number of seconds specified in the
816 * MX field value of the search request before responding, in order to
817 * avoid flooding the requesting control point with search responses
818 * from multiple devices. If the search request results in the need for
819 * a multiple part response from the device, those multiple part
820 * responses SHOULD be spread at random intervals through the time period
821 * from 0 to the number of seconds specified in the MX header field. */
823 /* get the string representation of the sender address */
824 sockaddr_to_string(sender
, sender_str
, sizeof(sender_str
));
825 lan_addr
= get_lan_for_peer(sender
);
828 syslog(LOG_WARNING
, "SSDP packet sender %s not from a LAN, ignoring",
833 if(memcmp(bufr
, "NOTIFY", 6) == 0)
835 /* ignore NOTIFY packets. We could log the sender and device type */
838 else if(memcmp(bufr
, "M-SEARCH", 8) == 0)
843 while((i
< n
- 1) && (bufr
[i
] != '\r' || bufr
[i
+1] != '\n'))
846 if((i
< n
- 3) && (strncasecmp(bufr
+i
, "st:", 3) == 0))
850 while((*st
== ' ' || *st
== '\t') && (st
< bufr
+ n
))
852 while(st
[st_len
]!='\r' && st
[st_len
]!='\n'
853 && (st
+ st_len
< bufr
+ n
))
856 while(l
> 0 && st
[l
-1] != ':')
859 syslog(LOG_DEBUG
, "ST: %.*s (ver=%d)", st_len
, st
, st_ver
);
861 /*while(bufr[i+j]!='\r') j++;*/
862 /*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
864 #if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE)
865 else if((i
< n
- 3) && (strncasecmp(bufr
+i
, "mx:", 3) == 0))
871 while((*mx
== ' ' || *mx
== '\t') && (mx
< bufr
+ n
))
873 while(mx
[mx_len
]!='\r' && mx
[mx_len
]!='\n'
874 && (mx
+ mx_len
< bufr
+ n
))
877 syslog(LOG_DEBUG
, "MX: %.*s (value=%d)", mx_len
, mx
, mx_value
);
882 /* For multicast M-SEARCH requests, if the search request does
883 * not contain an MX header field, the device MUST silently
884 * discard and ignore the search request. */
886 syslog(LOG_INFO
, "ignoring SSDP packet missing MX: header");
888 } else if(mx_value
> 5) {
889 /* If the MX header field specifies a field value greater
890 * than 5, the device SHOULD assume that it contained the
891 * value 5 or less. */
894 #elif defined(DELAY_MSEARCH_RESPONSE)
897 } else if(mx_value
> 5) {
898 /* If the MX header field specifies a field value greater
899 * than 5, the device SHOULD assume that it contained the
900 * value 5 or less. */
904 /*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
906 if(st
&& (st_len
> 0))
908 syslog(LOG_INFO
, "SSDP M-SEARCH from %s ST: %.*s",
909 sender_str
, st_len
, st
);
910 /* find in which sub network the client is */
911 if(sender
->sa_family
== AF_INET
)
913 if (lan_addr
== NULL
)
916 "Can't find in which sub network the client %s is",
920 announced_host
= lan_addr
->str
;
925 /* IPv6 address with brackets */
928 struct in6_addr addr6
;
929 size_t addr6_len
= sizeof(addr6
);
930 /* retrieve the IPv6 address which
931 * will be used locally to reach sender */
932 memset(&addr6
, 0, sizeof(addr6
));
933 if(get_src_for_route_to (sender
, &addr6
, &addr6_len
, &index
) < 0) {
934 syslog(LOG_WARNING
, "get_src_for_route_to() failed, using %s", ipv6_addr_for_http_with_brackets
);
935 announced_host
= ipv6_addr_for_http_with_brackets
;
937 if(inet_ntop(AF_INET6
, &addr6
,
938 announced_host_buf
+1,
939 sizeof(announced_host_buf
) - 2)) {
940 announced_host_buf
[0] = '[';
941 i
= strlen(announced_host_buf
);
942 if(i
< (int)sizeof(announced_host_buf
) - 1) {
943 announced_host_buf
[i
] = ']';
944 announced_host_buf
[i
+1] = '\0';
946 syslog(LOG_NOTICE
, "cannot suffix %s with ']'",
949 announced_host
= announced_host_buf
;
951 syslog(LOG_NOTICE
, "inet_ntop() failed %m");
952 announced_host
= ipv6_addr_for_http_with_brackets
;
956 announced_host
= ipv6_addr_for_http_with_brackets
;
960 /* Responds to request with a device as ST header */
961 for(i
= 0; known_service_types
[i
].s
; i
++)
963 l
= (int)strlen(known_service_types
[i
].s
);
964 if(l
<=st_len
&& (0 == memcmp(st
, known_service_types
[i
].s
, l
))
966 && (st_ver
<= known_service_types
[i
].version
)
967 /* only answer for service version lower or equal of supported one */
971 /* SSDP_RESPOND_SAME_VERSION :
972 * response is urn:schemas-upnp-org:service:WANIPConnection:1 when
973 * M-SEARCH included urn:schemas-upnp-org:service:WANIPConnection:1
974 * else the implemented versions is included in the response
976 * From UPnP Device Architecture v1.1 :
977 * 1.3.2 [...] Updated versions of device and service types
978 * are REQUIRED to be fully backward compatible with
979 * previous versions. Devices MUST respond to M-SEARCH
980 * requests for any supported version. For example, if a
981 * device implements “urn:schemas-upnporg:service:xyz:2”,
982 * it MUST respond to search requests for both that type
983 * and “urn:schemas-upnp-org:service:xyz:1”. The response
984 * MUST specify the same version as was contained in the
985 * search request. [...] */
986 #ifndef SSDP_RESPOND_SAME_VERSION
990 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
992 syslog(LOG_INFO
, "Single search found");
993 #ifdef DELAY_MSEARCH_RESPONSE
994 delay
= random() / (1 + RAND_MAX
/ (1000 * mx_value
));
996 syslog(LOG_DEBUG
, "mx=%dsec delay=%ums", mx_value
, delay
);
999 SendSSDPResponse(s
, sender
,
1000 #ifdef SSDP_RESPOND_SAME_VERSION
1003 known_service_types
[i
].s
, l
, ver_str
,
1005 announced_host
, http_port
,
1009 known_service_types
[i
].uuid
,
1014 /* Responds to request with ST: ssdp:all */
1015 /* strlen("ssdp:all") == 8 */
1016 if(st_len
==8 && (0 == memcmp(st
, "ssdp:all", 8)))
1018 #ifdef DELAY_MSEARCH_RESPONSE
1019 unsigned int delay_increment
= (mx_value
* 1000) / 15;
1021 syslog(LOG_INFO
, "ssdp:all found");
1022 for(i
=0; known_service_types
[i
].s
; i
++)
1024 #ifdef DELAY_MSEARCH_RESPONSE
1025 delay
+= delay_increment
;
1030 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
1031 l
= (int)strlen(known_service_types
[i
].s
);
1032 SendSSDPResponse(s
, sender
,
1033 known_service_types
[i
].s
, l
, ver_str
,
1034 announced_host
, http_port
,
1038 known_service_types
[i
].uuid
,
1041 /* also answer for uuid */
1042 #ifdef DELAY_MSEARCH_RESPONSE
1043 delay
+= delay_increment
;
1045 SendSSDPResponse(s
, sender
, uuidvalue_igd
, strlen(uuidvalue_igd
), "",
1046 announced_host
, http_port
,
1050 uuidvalue_igd
, delay
);
1051 #ifdef DELAY_MSEARCH_RESPONSE
1052 delay
+= delay_increment
;
1054 SendSSDPResponse(s
, sender
, uuidvalue_wan
, strlen(uuidvalue_wan
), "",
1055 announced_host
, http_port
,
1059 uuidvalue_wan
, delay
);
1060 #ifdef DELAY_MSEARCH_RESPONSE
1061 delay
+= delay_increment
;
1063 SendSSDPResponse(s
, sender
, uuidvalue_wcd
, strlen(uuidvalue_wcd
), "",
1064 announced_host
, http_port
,
1068 uuidvalue_wcd
, delay
);
1070 /* responds to request by UUID value */
1071 l
= (int)strlen(uuidvalue_igd
);
1074 #ifdef DELAY_MSEARCH_RESPONSE
1075 delay
= random() / (1 + RAND_MAX
/ (1000 * mx_value
));
1077 if(0 == memcmp(st
, uuidvalue_igd
, l
))
1079 syslog(LOG_INFO
, "ssdp:uuid (IGD) found");
1080 SendSSDPResponse(s
, sender
, st
, st_len
, "",
1081 announced_host
, http_port
,
1085 uuidvalue_igd
, delay
);
1087 else if(0 == memcmp(st
, uuidvalue_wan
, l
))
1089 syslog(LOG_INFO
, "ssdp:uuid (WAN) found");
1090 SendSSDPResponse(s
, sender
, st
, st_len
, "",
1091 announced_host
, http_port
,
1095 uuidvalue_wan
, delay
);
1097 else if(0 == memcmp(st
, uuidvalue_wcd
, l
))
1099 syslog(LOG_INFO
, "ssdp:uuid (WCD) found");
1100 SendSSDPResponse(s
, sender
, st
, st_len
, "",
1101 announced_host
, http_port
,
1105 uuidvalue_wcd
, delay
);
1111 syslog(LOG_INFO
, "Invalid SSDP M-SEARCH from %s", sender_str
);
1116 syslog(LOG_NOTICE
, "Unknown udp packet received from %s", sender_str
);
1121 SendSSDPbyebye(int s
, const struct sockaddr
* dest
, socklen_t destlen
,
1122 const char * dest_str
,
1123 const char * nt
, const char * suffix
,
1124 const char * usn1
, const char * usn2
, const char * usn3
)
1127 char bufr
[SSDP_PACKET_MAX_LEN
];
1129 l
= snprintf(bufr
, sizeof(bufr
),
1130 "NOTIFY * HTTP/1.1\r\n"
1134 "NTS: ssdp:byebye\r\n"
1135 "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
1136 "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
1137 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
1138 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
1140 dest_str
, SSDP_PORT
, /* HOST : */
1141 nt
, suffix
, /* NT: */
1142 usn1
, usn2
, usn3
, suffix
, /* USN: */
1143 upnp_bootid
, upnp_bootid
, upnp_configid
);
1146 syslog(LOG_ERR
, "%s: snprintf error", "SendSSDPbyebye()");
1149 else if((unsigned int)l
>= sizeof(bufr
))
1151 syslog(LOG_WARNING
, "%s: truncated output (%u>=%u)",
1152 "SendSSDPbyebye()", (unsigned)l
, (unsigned)sizeof(bufr
));
1153 l
= sizeof(bufr
) - 1;
1155 n
= sendto_or_schedule(s
, bufr
, l
, 0, dest
, destlen
);
1158 syslog(LOG_ERR
, "sendto(udp_shutdown=%d): %m", s
);
1163 syslog(LOG_NOTICE
, "sendto() sent %d out of %d bytes", n
, l
);
1169 /* This will broadcast ssdp:byebye notifications to inform
1170 * the network that UPnP is going down. */
1172 SendSSDPGoodbye(int * sockets
, int n_sockets
)
1174 struct sockaddr_in sockname4
;
1176 struct sockaddr_in6 sockname6
;
1177 struct sockaddr
* sockname
;
1178 socklen_t socknamelen
;
1184 const char * dest_str
;
1186 memset(&sockname4
, 0, sizeof(struct sockaddr_in
));
1187 sockname4
.sin_family
= AF_INET
;
1188 sockname4
.sin_port
= htons(SSDP_PORT
);
1189 sockname4
.sin_addr
.s_addr
= inet_addr(SSDP_MCAST_ADDR
);
1191 memset(&sockname6
, 0, sizeof(struct sockaddr_in6
));
1192 sockname6
.sin6_family
= AF_INET6
;
1193 sockname6
.sin6_port
= htons(SSDP_PORT
);
1194 inet_pton(AF_INET6
, LL_SSDP_MCAST_ADDR
, &(sockname6
.sin6_addr
));
1196 dest_str
= SSDP_MCAST_ADDR
;
1199 for(j
=0; j
<n_sockets
; j
++)
1206 dest_str
= "[" LL_SSDP_MCAST_ADDR
"]";
1207 sockname
= (struct sockaddr
*)&sockname6
;
1208 socknamelen
= sizeof(struct sockaddr_in6
);
1210 dest_str
= SSDP_MCAST_ADDR
;
1211 sockname
= (struct sockaddr
*)&sockname4
;
1212 socknamelen
= sizeof(struct sockaddr_in
);
1215 for(i
=0; known_service_types
[i
].s
; i
++)
1220 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
1221 ret
+= SendSSDPbyebye(sockets
[j
],
1223 sockname
, socknamelen
,
1225 (struct sockaddr
*)&sockname4
, sizeof(struct sockaddr_in
),
1228 known_service_types
[i
].s
, ver_str
, /* NT: */
1229 known_service_types
[i
].uuid
, "::",
1230 known_service_types
[i
].s
); /* ver_str, USN: */
1231 if(0==memcmp(known_service_types
[i
].s
,
1232 "urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1))
1234 ret
+= SendSSDPbyebye(sockets
[j
],
1236 sockname
, socknamelen
,
1238 (struct sockaddr
*)&sockname4
, sizeof(struct sockaddr_in
),
1241 known_service_types
[i
].uuid
, "", /* NT: */
1242 known_service_types
[i
].uuid
, "", ""); /* ver_str, USN: */
1249 /* SubmitServicesToMiniSSDPD() :
1250 * register services offered by MiniUPnPd to a running instance of
1253 SubmitServicesToMiniSSDPD(const char * host
, unsigned short port
) {
1254 struct sockaddr_un addr
;
1256 unsigned char buffer
[2048];
1262 s
= socket(AF_UNIX
, SOCK_STREAM
, 0);
1264 syslog(LOG_ERR
, "socket(unix): %m");
1267 addr
.sun_family
= AF_UNIX
;
1268 strncpy(addr
.sun_path
, minissdpdsocketpath
, sizeof(addr
.sun_path
));
1269 addr
.sun_path
[sizeof(addr
.sun_path
) - 1] = '\0';
1270 if(connect(s
, (struct sockaddr
*)&addr
, sizeof(struct sockaddr_un
)) < 0) {
1271 syslog(LOG_ERR
, "connect(\"%s\"): %m", minissdpdsocketpath
);
1275 for(i
= 0; known_service_types
[i
].s
; i
++) {
1276 buffer
[0] = 4; /* request type 4 : submit service */
1277 /* 4 strings following : ST (service type), USN, Server, Location */
1279 l
= (int)strlen(known_service_types
[i
].s
);
1283 memcpy(p
, known_service_types
[i
].s
, l
);
1290 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
1291 l
= snprintf(strbuf
, sizeof(strbuf
), "%s::%s%s",
1292 known_service_types
[i
].uuid
, known_service_types
[i
].s
, ver_str
);
1294 syslog(LOG_WARNING
, "SubmitServicesToMiniSSDPD: snprintf %m");
1296 } else if((unsigned)l
>=sizeof(strbuf
)) {
1297 l
= sizeof(strbuf
) - 1;
1300 memcpy(p
, strbuf
, l
);
1302 l
= (int)strlen(MINIUPNPD_SERVER_STRING
);
1304 memcpy(p
, MINIUPNPD_SERVER_STRING
, l
);
1306 l
= snprintf(strbuf
, sizeof(strbuf
), "http://%s:%u" ROOTDESC_PATH
,
1307 host
, (unsigned int)port
);
1309 syslog(LOG_WARNING
, "SubmitServicesToMiniSSDPD: snprintf %m");
1311 } else if((unsigned)l
>=sizeof(strbuf
)) {
1312 l
= sizeof(strbuf
) - 1;
1315 memcpy(p
, strbuf
, l
);
1317 /* now write the encoded data */
1318 n
= p
- buffer
; /* bytes to send */
1319 p
= buffer
; /* start */
1325 syslog(LOG_ERR
, "write(): %m");
1328 } else if (l
== 0) {
1329 syslog(LOG_ERR
, "write() returned 0");