1 /* $Id: minissdp.c,v 1.74 2015/04/30 08:59:51 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 /* maximum lenght of SSDP packets we are generating
39 * (reception is done in a 1500byte buffer) */
41 #define SSDP_PACKET_MAX_LEN 768
43 #define SSDP_PACKET_MAX_LEN 512
46 /* AddMulticastMembership()
48 * param ifaddr ip v4 address
51 AddMulticastMembership(int s
, in_addr_t ifaddr
)
53 struct ip_mreq imr
; /* Ip multicast membership */
55 /* setting up imr structure */
56 imr
.imr_multiaddr
.s_addr
= inet_addr(SSDP_MCAST_ADDR
);
57 /*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/
58 imr
.imr_interface
.s_addr
= ifaddr
; /*inet_addr(ifaddr);*/
60 if (setsockopt(s
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (void *)&imr
, sizeof(struct ip_mreq
)) < 0)
62 syslog(LOG_ERR
, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m");
69 /* AddMulticastMembershipIPv6()
70 * param s socket (IPv6)
71 * param ifindex : interface index (0 : All interfaces) */
74 AddMulticastMembershipIPv6(int s
, unsigned int ifindex
)
78 memset(&mr
, 0, sizeof(mr
));
79 mr
.ipv6mr_interface
= ifindex
; /* 0 : all interfaces */
80 #ifndef IPV6_ADD_MEMBERSHIP
81 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
83 inet_pton(AF_INET6
, LL_SSDP_MCAST_ADDR
, &mr
.ipv6mr_multiaddr
);
84 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_ADD_MEMBERSHIP
, &mr
, sizeof(struct ipv6_mreq
)) < 0)
86 syslog(LOG_ERR
, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
89 inet_pton(AF_INET6
, SL_SSDP_MCAST_ADDR
, &mr
.ipv6mr_multiaddr
);
90 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_ADD_MEMBERSHIP
, &mr
, sizeof(struct ipv6_mreq
)) < 0)
92 syslog(LOG_ERR
, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
95 inet_pton(AF_INET6
, GL_SSDP_MCAST_ADDR
, &mr
.ipv6mr_multiaddr
);
96 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_ADD_MEMBERSHIP
, &mr
, sizeof(struct ipv6_mreq
)) < 0)
98 syslog(LOG_ERR
, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
105 /* Open and configure the socket listening for
106 * SSDP udp packets sent on 239.255.255.250 port 1900
107 * SSDP v6 udp packets sent on FF02::C, or FF05::C, port 1900 */
109 OpenAndConfSSDPReceiveSocket(int ipv6
)
112 struct sockaddr_storage sockname
;
113 socklen_t sockname_len
;
114 struct lan_addr_s
* lan_addr
;
117 if( (s
= socket(ipv6
? PF_INET6
: PF_INET
, SOCK_DGRAM
, 0)) < 0)
119 syslog(LOG_ERR
, "%s: socket(udp): %m",
120 "OpenAndConfSSDPReceiveSocket");
124 memset(&sockname
, 0, sizeof(struct sockaddr_storage
));
128 struct sockaddr_in6
* saddr
= (struct sockaddr_in6
*)&sockname
;
129 saddr
->sin6_family
= AF_INET6
;
130 saddr
->sin6_port
= htons(SSDP_PORT
);
131 saddr
->sin6_addr
= ipv6_bind_addr
;
132 sockname_len
= sizeof(struct sockaddr_in6
);
135 #endif /* ENABLE_IPV6 */
137 struct sockaddr_in
* saddr
= (struct sockaddr_in
*)&sockname
;
138 saddr
->sin_family
= AF_INET
;
139 saddr
->sin_port
= htons(SSDP_PORT
);
140 /* NOTE : it seems it doesnt work when binding on the specific address */
141 /*saddr->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/
142 saddr
->sin_addr
.s_addr
= htonl(INADDR_ANY
);
143 /*saddr->sin_addr.s_addr = inet_addr(ifaddr);*/
144 sockname_len
= sizeof(struct sockaddr_in
);
147 if(setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &j
, sizeof(j
)) < 0)
149 syslog(LOG_WARNING
, "setsockopt(udp, SO_REUSEADDR): %m");
152 if(!set_non_blocking(s
))
154 syslog(LOG_WARNING
, "%s: set_non_blocking(): %m",
155 "OpenAndConfSSDPReceiveSocket");
158 if(bind(s
, (struct sockaddr
*)&sockname
, sockname_len
) < 0)
160 syslog(LOG_ERR
, "%s: bind(udp%s): %m",
161 "OpenAndConfSSDPReceiveSocket", ipv6
? "6" : "");
169 for(lan_addr
= lan_addrs
.lh_first
; lan_addr
!= NULL
; lan_addr
= lan_addr
->list
.le_next
)
171 if(AddMulticastMembershipIPv6(s
, lan_addr
->index
) < 0)
174 "Failed to add IPv6 multicast membership for interface %s",
175 lan_addr
->str
? lan_addr
->str
: "NULL");
182 for(lan_addr
= lan_addrs
.lh_first
; lan_addr
!= NULL
; lan_addr
= lan_addr
->list
.le_next
)
184 if(AddMulticastMembership(s
, lan_addr
->addr
.s_addr
) < 0)
187 "Failed to add multicast membership for interface %s",
188 lan_addr
->str
? lan_addr
->str
: "NULL");
196 /* open the UDP socket used to send SSDP notifications to
197 * the multicast group reserved for them */
199 OpenAndConfSSDPNotifySocket(in_addr_t addr
)
202 unsigned char loopchar
= 0;
204 unsigned char ttl
= 2; /* UDA v1.1 says :
205 The TTL for the IP packet SHOULD default to 2 and
206 SHOULD be configurable. */
207 /* TODO: Make TTL be configurable */
208 struct in_addr mc_if
;
209 struct sockaddr_in sockname
;
211 if( (s
= socket(PF_INET
, SOCK_DGRAM
, 0)) < 0)
213 syslog(LOG_ERR
, "socket(udp_notify): %m");
217 mc_if
.s_addr
= addr
; /*inet_addr(addr);*/
219 if(setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (char *)&loopchar
, sizeof(loopchar
)) < 0)
221 syslog(LOG_ERR
, "setsockopt(udp_notify, IP_MULTICAST_LOOP): %m");
226 if(setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *)&mc_if
, sizeof(mc_if
)) < 0)
228 syslog(LOG_ERR
, "setsockopt(udp_notify, IP_MULTICAST_IF): %m");
233 if(setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
)) < 0)
235 syslog(LOG_WARNING
, "setsockopt(udp_notify, IP_MULTICAST_TTL,): %m");
238 if(setsockopt(s
, SOL_SOCKET
, SO_BROADCAST
, &bcast
, sizeof(bcast
)) < 0)
240 syslog(LOG_ERR
, "setsockopt(udp_notify, SO_BROADCAST): %m");
245 /* bind() socket before using sendto() is not mandatory
246 * (sendto() will implicitly bind the socket when called on
248 * here it is used to se a specific sending address */
249 memset(&sockname
, 0, sizeof(struct sockaddr_in
));
250 sockname
.sin_family
= AF_INET
;
251 sockname
.sin_addr
.s_addr
= addr
; /*inet_addr(addr);*/
253 if (bind(s
, (struct sockaddr
*)&sockname
, sizeof(struct sockaddr_in
)) < 0)
255 syslog(LOG_ERR
, "bind(udp_notify): %m");
264 /* open the UDP socket used to send SSDP notifications to
265 * the multicast group reserved for them. IPv6 */
267 OpenAndConfSSDPNotifySocketIPv6(unsigned int if_index
)
270 unsigned int loop
= 0;
271 struct sockaddr_in6 sockname
;
273 s
= socket(PF_INET6
, SOCK_DGRAM
, 0);
276 syslog(LOG_ERR
, "socket(udp_notify IPv6): %m");
279 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &if_index
, sizeof(if_index
)) < 0)
281 syslog(LOG_ERR
, "setsockopt(udp_notify IPv6, IPV6_MULTICAST_IF, %u): %m", if_index
);
285 if(setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &loop
, sizeof(loop
)) < 0)
287 syslog(LOG_ERR
, "setsockopt(udp_notify, IPV6_MULTICAST_LOOP): %m");
292 /* bind() socket before using sendto() is not mandatory
293 * (sendto() will implicitly bind the socket when called on
295 * but explicit bind permits to set port/scope_id/etc. */
296 memset(&sockname
, 0, sizeof(sockname
));
297 sockname
.sin6_family
= AF_INET6
;
298 sockname
.sin6_addr
= in6addr_any
;
299 /*sockname.sin6_port = htons(port);*/
300 /*sockname.sin6_scope_id = if_index;*/
301 if(bind(s
, (struct sockaddr
*)&sockname
, sizeof(sockname
)) < 0)
303 syslog(LOG_ERR
, "bind(udp_notify IPv6): %m");
313 OpenAndConfSSDPNotifySockets(int * sockets
)
314 /*OpenAndConfSSDPNotifySockets(int * sockets,
315 struct lan_addr_s * lan_addr, int n_lan_addr)*/
318 struct lan_addr_s
* lan_addr
;
320 for(i
=0, lan_addr
= lan_addrs
.lh_first
;
322 lan_addr
= lan_addr
->list
.le_next
)
324 sockets
[i
] = OpenAndConfSSDPNotifySocket(lan_addr
->addr
.s_addr
);
329 if(GETFLAG(IPV6DISABLEDMASK
))
335 sockets
[i
] = OpenAndConfSSDPNotifySocketIPv6(lan_addr
->index
);
353 * response from a LiveBox (Wanadoo)
355 CACHE-CONTROL: max-age=1800
356 DATE: Thu, 01 Jan 1970 04:03:23 GMT
358 LOCATION: http://192.168.0.1:49152/gatedesc.xml
359 SERVER: Linux/2.4.17, UPnP/1.0, Intel SDK for UPnP devices /1.2
361 USN: uuid:75802409-bccb-40e7-8e6c-fa095ecce13e::upnp:rootdevice
363 * response from a Linksys 802.11b :
365 Cache-Control:max-age=120
366 Location:http://192.168.5.1:5678/rootDesc.xml
367 Server:NT/5.0 UPnP/1.0
369 USN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777::upnp:rootdevice
373 /* Responds to a SSDP "M-SEARCH"
376 * st, st_len : ST: header
377 * suffix : suffix for USN: header
378 * host, port : our HTTP host, port
379 * delay : in milli-seconds
382 SendSSDPResponse(int s
, const struct sockaddr
* addr
,
383 const char * st
, int st_len
, const char * suffix
,
384 const char * host
, unsigned short http_port
,
386 unsigned short https_port
,
388 const char * uuidvalue
, unsigned int delay
)
391 char buf
[SSDP_PACKET_MAX_LEN
];
395 #ifdef ENABLE_HTTP_DATE
402 strftime(http_date
, sizeof(http_date
),
403 "%a, %d %b %Y %H:%M:%S GMT", &tm
);
406 st_is_uuid
= (st_len
== (int)strlen(uuidvalue
)) &&
407 (memcmp(uuidvalue
, st
, st_len
) == 0);
409 * follow guideline from document "UPnP Device Architecture 1.0"
410 * uppercase is recommended.
411 * DATE: is recommended
412 * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
413 * - check what to put in the 'Cache-Control' header
415 * have a look at the document "UPnP Device Architecture v1.1 */
416 l
= snprintf(buf
, sizeof(buf
), "HTTP/1.1 200 OK\r\n"
417 "CACHE-CONTROL: max-age=120\r\n"
418 #ifdef ENABLE_HTTP_DATE
422 "USN: %s%s%.*s%s\r\n"
424 "SERVER: " MINIUPNPD_SERVER_STRING
"\r\n"
425 "LOCATION: http://%s:%u" ROOTDESC_PATH
"\r\n"
427 "SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH
"\r\n"
429 "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
430 "01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
431 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
432 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
434 #ifdef ENABLE_HTTP_DATE
438 uuidvalue
, st_is_uuid
? "" : "::",
439 st_is_uuid
? 0 : st_len
, st
, suffix
,
440 host
, (unsigned int)http_port
,
442 host
, (unsigned int)https_port
,
444 upnp_bootid
, upnp_bootid
, upnp_configid
);
447 syslog(LOG_ERR
, "%s: snprintf failed %m",
448 "SendSSDPResponse()");
451 else if((unsigned)l
>=sizeof(buf
))
453 syslog(LOG_WARNING
, "%s: truncated output (%u>=%u)",
454 "SendSSDPResponse()", (unsigned)l
, (unsigned)sizeof(buf
));
457 addrlen
= (addr
->sa_family
== AF_INET6
)
458 ? sizeof(struct sockaddr_in6
) : sizeof(struct sockaddr_in
);
459 n
= sendto_schedule(s
, buf
, l
, 0,
460 addr
, addrlen
, delay
);
461 sockaddr_to_string(addr
, addr_str
, sizeof(addr_str
));
462 syslog(LOG_DEBUG
, "%s: %d bytes to %s ST: %.*s",
463 "SendSSDPResponse()",
464 n
, addr_str
, l
, buf
);
467 syslog(LOG_ERR
, "%s: sendto(udp): %m",
468 "SendSSDPResponse()");
484 } const known_service_types
[] =
486 {"upnp:rootdevice", 0, uuidvalue_igd
},
487 {"urn:schemas-upnp-org:device:InternetGatewayDevice:", IGD_VER
, uuidvalue_igd
},
488 {"urn:schemas-upnp-org:device:WANConnectionDevice:", 1, uuidvalue_wcd
},
489 {"urn:schemas-upnp-org:device:WANDevice:", 1, uuidvalue_wan
},
490 {"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:", 1, uuidvalue_wan
},
491 {"urn:schemas-upnp-org:service:WANIPConnection:", WANIPC_VER
, uuidvalue_wcd
},
493 /* We use WAN IP Connection, not PPP connection,
494 * but buggy control points may try to use WanPPPConnection
496 {"urn:schemas-upnp-org:service:WANPPPConnection:", 1, uuidvalue_wcd
},
498 #ifdef ENABLE_L3F_SERVICE
499 {"urn:schemas-upnp-org:service:Layer3Forwarding:", 1, uuidvalue_igd
},
501 #ifdef ENABLE_6FC_SERVICE
502 {"url:schemas-upnp-org:service:WANIPv6FirewallControl:", 1, uuidvalue_wcd
},
504 /* we might want to support urn:schemas-wifialliance-org:device:WFADevice:1
505 * urn:schemas-wifialliance-org:device:WFADevice:1
510 /* SendSSDPNotify() sends the SSDP NOTIFY to a specific
511 * destination, for a specific UPnP service or device */
513 SendSSDPNotify(int s
, const struct sockaddr
* dest
, socklen_t dest_len
,
514 const char * dest_str
,
515 const char * host
, unsigned short http_port
,
517 unsigned short https_port
,
519 const char * nt
, const char * suffix
,
520 const char * usn1
, const char * usn2
, const char * usn3
,
521 unsigned int lifetime
)
523 char bufr
[SSDP_PACKET_MAX_LEN
];
526 l
= snprintf(bufr
, sizeof(bufr
),
527 "NOTIFY * HTTP/1.1\r\n"
529 "CACHE-CONTROL: max-age=%u\r\n"
530 "LOCATION: http://%s:%u" ROOTDESC_PATH
"\r\n"
532 "SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH
"\r\n"
534 "SERVER: " MINIUPNPD_SERVER_STRING
"\r\n"
537 "NTS: ssdp:alive\r\n"
538 "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
539 "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
540 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
541 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
543 dest_str
, SSDP_PORT
, /* HOST: */
544 lifetime
, /* CACHE-CONTROL: */
545 host
, (unsigned int)http_port
, /* LOCATION: */
547 host
, (unsigned int)https_port
, /* SECURE-LOCATION: */
549 nt
, suffix
, /* NT: */
550 usn1
, usn2
, usn3
, suffix
, /* USN: */
551 upnp_bootid
, /* 01-NLS: */
552 upnp_bootid
, /* BOOTID.UPNP.ORG: */
553 upnp_configid
); /* CONFIGID.UPNP.ORG: */
555 syslog(LOG_ERR
, "%s: snprintf error", "SendSSDPNotify()");
557 } else if((unsigned int)l
>= sizeof(bufr
)) {
558 syslog(LOG_WARNING
, "%s: truncated output (%u>=%u)",
559 "SendSSDPNotify()", (unsigned)l
, (unsigned)sizeof(bufr
));
560 l
= sizeof(bufr
) - 1;
562 n
= sendto_or_schedule(s
, bufr
, l
, 0, dest
, dest_len
);
564 syslog(LOG_ERR
, "sendto(udp_notify=%d, %s): %m", s
,
565 host
? host
: "NULL");
567 syslog(LOG_NOTICE
, "sendto() sent %d out of %d bytes", n
, l
);
569 /* Due to the unreliable nature of UDP, devices SHOULD send the entire
570 * set of discovery messages more than once with some delay between
571 * sets e.g. a few hundred milliseconds. To avoid network congestion
572 * discovery messages SHOULD NOT be sent more than three times. */
573 n
= sendto_schedule(s
, bufr
, l
, 0, dest
, dest_len
, 250);
575 syslog(LOG_ERR
, "sendto(udp_notify=%d, %s): %m", s
,
576 host
? host
: "NULL");
580 /* SendSSDPNotifies() send SSPD NOTIFY for a specific
581 * LAN (network interface) for all devices / services */
584 SendSSDPNotifies(int s
, const char * host
, unsigned short http_port
,
585 unsigned short https_port
,
586 unsigned int lifetime
, int ipv6
)
589 SendSSDPNotifies(int s
, const char * host
, unsigned short http_port
,
590 unsigned int lifetime
, int ipv6
)
594 struct sockaddr_storage sockname
;
595 static struct { const char * p1
, * p2
; } const mcast_addrs
[] =
596 { { LL_SSDP_MCAST_ADDR
, "[" LL_SSDP_MCAST_ADDR
"]" }, /* Link Local */
597 { SL_SSDP_MCAST_ADDR
, "[" SL_SSDP_MCAST_ADDR
"]" }, /* Site Local */
598 { GL_SSDP_MCAST_ADDR
, "[" GL_SSDP_MCAST_ADDR
"]" }, /* Global */
601 #else /* ENABLE_IPV6 */
602 struct sockaddr_in sockname
;
603 #endif /* ENABLE_IPV6 */
604 socklen_t sockname_len
;
605 const char * dest_str
;
610 #endif /* ENABLE_IPV6 */
612 memset(&sockname
, 0, sizeof(sockname
));
614 /* first iterate destinations for this LAN interface (only 1 for IPv4) */
615 for(j
= 0; (mcast_addrs
[j
].p1
!= 0 && ipv6
) || j
< 1; j
++) {
617 struct sockaddr_in6
* p
= (struct sockaddr_in6
*)&sockname
;
618 sockname_len
= sizeof(struct sockaddr_in6
);
619 p
->sin6_family
= AF_INET6
;
620 p
->sin6_port
= htons(SSDP_PORT
);
621 inet_pton(AF_INET6
, mcast_addrs
[j
].p1
, &(p
->sin6_addr
));
622 dest_str
= mcast_addrs
[j
].p2
;
623 /* UPnP Device Architecture 1.1 :
624 * Devices MUST multicast SSDP messages for each of the UPnP-enabled
625 * interfaces. The scope of multicast SSDP messages MUST be
626 * link local FF02::C if the message is sent from a link local address.
627 * If the message is sent from a global address it MUST be multicast
628 * using either global scope FF0E::C or site local scope FF05::C.
629 * In networks with complex topologies and overlapping sites, use of
630 * global scope is RECOMMENDED. */
632 #else /* ENABLE_IPV6 */
634 #endif /* ENABLE_IPV6 */
636 struct sockaddr_in
*p
= (struct sockaddr_in
*)&sockname
;
637 sockname_len
= sizeof(struct sockaddr_in
);
638 p
->sin_family
= AF_INET
;
639 p
->sin_port
= htons(SSDP_PORT
);
640 p
->sin_addr
.s_addr
= inet_addr(SSDP_MCAST_ADDR
);
641 dest_str
= SSDP_MCAST_ADDR
;
644 /* iterate all services / devices */
645 for(i
= 0; known_service_types
[i
].s
; i
++) {
649 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
650 SendSSDPNotify(s
, (struct sockaddr
*)&sockname
, sockname_len
, dest_str
,
655 known_service_types
[i
].s
, ver_str
, /* NT: */
656 known_service_types
[i
].uuid
, "::",
657 known_service_types
[i
].s
, /* ver_str, USN: */
659 /* for devices, also send NOTIFY on the uuid */
660 if(0==memcmp(known_service_types
[i
].s
,
661 "urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1)) {
662 SendSSDPNotify(s
, (struct sockaddr
*)&sockname
, sockname_len
, dest_str
,
667 known_service_types
[i
].uuid
, "", /* NT: */
668 known_service_types
[i
].uuid
, "", "", /* ver_str, USN: */
671 } /* for(i = 0; known_service_types[i].s; i++) */
673 } /* for(j = 0; (mcast_addrs[j].p1 != 0 && ipv6) || j < 1; j++) */
674 #endif /* ENABLE_IPV6 */
677 /* SendSSDPNotifies2() sends SSDP NOTIFY packets on all interfaces
678 * for all destinations, all devices / services */
680 SendSSDPNotifies2(int * sockets
,
681 unsigned short http_port
,
683 unsigned short https_port
,
685 unsigned int lifetime
)
688 struct lan_addr_s
* lan_addr
;
689 for(i
= 0, lan_addr
= lan_addrs
.lh_first
;
691 lan_addr
= lan_addr
->list
.le_next
) {
692 SendSSDPNotifies(sockets
[i
], lan_addr
->str
, http_port
,
699 if(sockets
[i
] >= 0) {
700 SendSSDPNotifies(sockets
[i
], ipv6_addr_for_http_with_brackets
, http_port
,
707 #endif /* ENABLE_IPV6 */
711 /* ProcessSSDPRequest()
712 * process SSDP M-SEARCH requests and responds to them */
715 ProcessSSDPRequest(int s
, unsigned short http_port
, unsigned short https_port
)
717 ProcessSSDPRequest(int s
, unsigned short http_port
)
724 struct sockaddr_storage sendername
;
725 len_r
= sizeof(struct sockaddr_storage
);
727 struct sockaddr_in sendername
;
728 len_r
= sizeof(struct sockaddr_in
);
731 n
= recvfrom(s
, bufr
, sizeof(bufr
), 0,
732 (struct sockaddr
*)&sendername
, &len_r
);
735 /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time)
736 * other errors : log to LOG_ERR */
737 if(errno
!= EAGAIN
&&
738 errno
!= EWOULDBLOCK
&&
741 syslog(LOG_ERR
, "recvfrom(udp): %m");
746 ProcessSSDPData(s
, bufr
, n
, (struct sockaddr
*)&sendername
,
747 http_port
, https_port
);
749 ProcessSSDPData(s
, bufr
, n
, (struct sockaddr
*)&sendername
,
757 ProcessSSDPData(int s
, const char *bufr
, int n
,
758 const struct sockaddr
* sender
,
759 unsigned short http_port
, unsigned short https_port
)
762 ProcessSSDPData(int s
, const char *bufr
, int n
,
763 const struct sockaddr
* sender
,
764 unsigned short http_port
)
768 struct lan_addr_s
* lan_addr
= NULL
;
769 const char * st
= NULL
;
774 const char * announced_host
= NULL
;
777 char announced_host_buf
[64];
780 #if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE)
783 unsigned int delay
= 50; /* Non-zero default delay to prevent flooding */
784 /* UPnP Device Architecture v1.1. 1.3.3 Search response :
785 * Devices responding to a multicast M-SEARCH SHOULD wait a random period
786 * of time between 0 seconds and the number of seconds specified in the
787 * MX field value of the search request before responding, in order to
788 * avoid flooding the requesting control point with search responses
789 * from multiple devices. If the search request results in the need for
790 * a multiple part response from the device, those multiple part
791 * responses SHOULD be spread at random intervals through the time period
792 * from 0 to the number of seconds specified in the MX header field. */
794 /* get the string representation of the sender address */
795 sockaddr_to_string(sender
, sender_str
, sizeof(sender_str
));
796 lan_addr
= get_lan_for_peer(sender
);
799 syslog(LOG_WARNING
, "SSDP packet sender %s not from a LAN, ignoring",
804 if(memcmp(bufr
, "NOTIFY", 6) == 0)
806 /* ignore NOTIFY packets. We could log the sender and device type */
809 else if(memcmp(bufr
, "M-SEARCH", 8) == 0)
814 while((i
< n
- 1) && (bufr
[i
] != '\r' || bufr
[i
+1] != '\n'))
817 if((i
< n
- 3) && (strncasecmp(bufr
+i
, "st:", 3) == 0))
821 while((*st
== ' ' || *st
== '\t') && (st
< bufr
+ n
))
823 while(st
[st_len
]!='\r' && st
[st_len
]!='\n'
824 && (st
+ st_len
< bufr
+ n
))
827 while(l
> 0 && st
[l
-1] != ':')
830 syslog(LOG_DEBUG
, "ST: %.*s (ver=%d)", st_len
, st
, st_ver
);
832 /*while(bufr[i+j]!='\r') j++;*/
833 /*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
835 #if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE)
836 else if((i
< n
- 3) && (strncasecmp(bufr
+i
, "mx:", 3) == 0))
842 while((*mx
== ' ' || *mx
== '\t') && (mx
< bufr
+ n
))
844 while(mx
[mx_len
]!='\r' && mx
[mx_len
]!='\n'
845 && (mx
+ mx_len
< bufr
+ n
))
848 syslog(LOG_DEBUG
, "MX: %.*s (value=%d)", mx_len
, mx
, mx_value
);
853 /* For multicast M-SEARCH requests, if the search request does
854 * not contain an MX header field, the device MUST silently
855 * discard and ignore the search request. */
857 syslog(LOG_INFO
, "ignoring SSDP packet missing MX: header");
859 } else if(mx_value
> 5) {
860 /* If the MX header field specifies a field value greater
861 * than 5, the device SHOULD assume that it contained the
862 * value 5 or less. */
865 #elif defined(DELAY_MSEARCH_RESPONSE)
868 } else if(mx_value
> 5) {
869 /* If the MX header field specifies a field value greater
870 * than 5, the device SHOULD assume that it contained the
871 * value 5 or less. */
875 /*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
877 if(st
&& (st_len
> 0))
879 syslog(LOG_INFO
, "SSDP M-SEARCH from %s ST: %.*s",
880 sender_str
, st_len
, st
);
881 /* find in which sub network the client is */
882 if(sender
->sa_family
== AF_INET
)
884 if (lan_addr
== NULL
)
887 "Can't find in which sub network the client %s is",
891 announced_host
= lan_addr
->str
;
896 /* IPv6 address with brackets */
899 struct in6_addr addr6
;
900 size_t addr6_len
= sizeof(addr6
);
901 /* retrieve the IPv6 address which
902 * will be used locally to reach sender */
903 memset(&addr6
, 0, sizeof(addr6
));
904 if(get_src_for_route_to (sender
, &addr6
, &addr6_len
, &index
) < 0) {
905 syslog(LOG_WARNING
, "get_src_for_route_to() failed, using %s", ipv6_addr_for_http_with_brackets
);
906 announced_host
= ipv6_addr_for_http_with_brackets
;
908 if(inet_ntop(AF_INET6
, &addr6
,
909 announced_host_buf
+1,
910 sizeof(announced_host_buf
) - 2)) {
911 announced_host_buf
[0] = '[';
912 i
= strlen(announced_host_buf
);
913 if(i
< (int)sizeof(announced_host_buf
) - 1) {
914 announced_host_buf
[i
] = ']';
915 announced_host_buf
[i
+1] = '\0';
917 syslog(LOG_NOTICE
, "cannot suffix %s with ']'",
920 announced_host
= announced_host_buf
;
922 syslog(LOG_NOTICE
, "inet_ntop() failed %m");
923 announced_host
= ipv6_addr_for_http_with_brackets
;
927 announced_host
= ipv6_addr_for_http_with_brackets
;
931 /* Responds to request with a device as ST header */
932 for(i
= 0; known_service_types
[i
].s
; i
++)
934 l
= (int)strlen(known_service_types
[i
].s
);
935 if(l
<=st_len
&& (0 == memcmp(st
, known_service_types
[i
].s
, l
))
937 && (st_ver
<= known_service_types
[i
].version
)
938 /* only answer for service version lower or equal of supported one */
942 /* SSDP_RESPOND_SAME_VERSION :
943 * response is urn:schemas-upnp-org:service:WANIPConnection:1 when
944 * M-SEARCH included urn:schemas-upnp-org:service:WANIPConnection:1
945 * else the implemented versions is included in the response
947 * From UPnP Device Architecture v1.1 :
948 * 1.3.2 [...] Updated versions of device and service types
949 * are REQUIRED to be fully backward compatible with
950 * previous versions. Devices MUST respond to M-SEARCH
951 * requests for any supported version. For example, if a
952 * device implements “urn:schemas-upnporg:service:xyz:2”,
953 * it MUST respond to search requests for both that type
954 * and “urn:schemas-upnp-org:service:xyz:1”. The response
955 * MUST specify the same version as was contained in the
956 * search request. [...] */
957 #ifndef SSDP_RESPOND_SAME_VERSION
961 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
963 syslog(LOG_INFO
, "Single search found");
964 #ifdef DELAY_MSEARCH_RESPONSE
965 delay
= random() / (1 + RAND_MAX
/ (1000 * mx_value
));
967 syslog(LOG_DEBUG
, "mx=%dsec delay=%ums", mx_value
, delay
);
970 SendSSDPResponse(s
, sender
,
971 #ifdef SSDP_RESPOND_SAME_VERSION
974 known_service_types
[i
].s
, l
, ver_str
,
976 announced_host
, http_port
,
980 known_service_types
[i
].uuid
,
985 /* Responds to request with ST: ssdp:all */
986 /* strlen("ssdp:all") == 8 */
987 if(st_len
==8 && (0 == memcmp(st
, "ssdp:all", 8)))
989 #ifdef DELAY_MSEARCH_RESPONSE
990 unsigned int delay_increment
= (mx_value
* 1000) / 15;
992 syslog(LOG_INFO
, "ssdp:all found");
993 for(i
=0; known_service_types
[i
].s
; i
++)
995 #ifdef DELAY_MSEARCH_RESPONSE
996 delay
+= delay_increment
;
1001 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
1002 l
= (int)strlen(known_service_types
[i
].s
);
1003 SendSSDPResponse(s
, sender
,
1004 known_service_types
[i
].s
, l
, ver_str
,
1005 announced_host
, http_port
,
1009 known_service_types
[i
].uuid
,
1012 /* also answer for uuid */
1013 #ifdef DELAY_MSEARCH_RESPONSE
1014 delay
+= delay_increment
;
1016 SendSSDPResponse(s
, sender
, uuidvalue_igd
, strlen(uuidvalue_igd
), "",
1017 announced_host
, http_port
,
1021 uuidvalue_igd
, delay
);
1022 #ifdef DELAY_MSEARCH_RESPONSE
1023 delay
+= delay_increment
;
1025 SendSSDPResponse(s
, sender
, uuidvalue_wan
, strlen(uuidvalue_wan
), "",
1026 announced_host
, http_port
,
1030 uuidvalue_wan
, delay
);
1031 #ifdef DELAY_MSEARCH_RESPONSE
1032 delay
+= delay_increment
;
1034 SendSSDPResponse(s
, sender
, uuidvalue_wcd
, strlen(uuidvalue_wcd
), "",
1035 announced_host
, http_port
,
1039 uuidvalue_wcd
, delay
);
1041 /* responds to request by UUID value */
1042 l
= (int)strlen(uuidvalue_igd
);
1045 #ifdef DELAY_MSEARCH_RESPONSE
1046 delay
= random() / (1 + RAND_MAX
/ (1000 * mx_value
));
1048 if(0 == memcmp(st
, uuidvalue_igd
, l
))
1050 syslog(LOG_INFO
, "ssdp:uuid (IGD) found");
1051 SendSSDPResponse(s
, sender
, st
, st_len
, "",
1052 announced_host
, http_port
,
1056 uuidvalue_igd
, delay
);
1058 else if(0 == memcmp(st
, uuidvalue_wan
, l
))
1060 syslog(LOG_INFO
, "ssdp:uuid (WAN) found");
1061 SendSSDPResponse(s
, sender
, st
, st_len
, "",
1062 announced_host
, http_port
,
1066 uuidvalue_wan
, delay
);
1068 else if(0 == memcmp(st
, uuidvalue_wcd
, l
))
1070 syslog(LOG_INFO
, "ssdp:uuid (WCD) found");
1071 SendSSDPResponse(s
, sender
, st
, st_len
, "",
1072 announced_host
, http_port
,
1076 uuidvalue_wcd
, delay
);
1082 syslog(LOG_INFO
, "Invalid SSDP M-SEARCH from %s", sender_str
);
1087 syslog(LOG_NOTICE
, "Unknown udp packet received from %s", sender_str
);
1092 SendSSDPbyebye(int s
, const struct sockaddr
* dest
, socklen_t destlen
,
1093 const char * dest_str
,
1094 const char * nt
, const char * suffix
,
1095 const char * usn1
, const char * usn2
, const char * usn3
)
1098 char bufr
[SSDP_PACKET_MAX_LEN
];
1100 l
= snprintf(bufr
, sizeof(bufr
),
1101 "NOTIFY * HTTP/1.1\r\n"
1105 "NTS: ssdp:byebye\r\n"
1106 "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
1107 "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
1108 "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
1109 "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
1111 dest_str
, SSDP_PORT
, /* HOST : */
1112 nt
, suffix
, /* NT: */
1113 usn1
, usn2
, usn3
, suffix
, /* USN: */
1114 upnp_bootid
, upnp_bootid
, upnp_configid
);
1117 syslog(LOG_ERR
, "%s: snprintf error", "SendSSDPbyebye()");
1120 else if((unsigned int)l
>= sizeof(bufr
))
1122 syslog(LOG_WARNING
, "%s: truncated output (%u>=%u)",
1123 "SendSSDPbyebye()", (unsigned)l
, (unsigned)sizeof(bufr
));
1124 l
= sizeof(bufr
) - 1;
1126 n
= sendto_or_schedule(s
, bufr
, l
, 0, dest
, destlen
);
1129 syslog(LOG_ERR
, "sendto(udp_shutdown=%d): %m", s
);
1134 syslog(LOG_NOTICE
, "sendto() sent %d out of %d bytes", n
, l
);
1140 /* This will broadcast ssdp:byebye notifications to inform
1141 * the network that UPnP is going down. */
1143 SendSSDPGoodbye(int * sockets
, int n_sockets
)
1145 struct sockaddr_in sockname4
;
1147 struct sockaddr_in6 sockname6
;
1148 struct sockaddr
* sockname
;
1149 socklen_t socknamelen
;
1155 const char * dest_str
;
1157 memset(&sockname4
, 0, sizeof(struct sockaddr_in
));
1158 sockname4
.sin_family
= AF_INET
;
1159 sockname4
.sin_port
= htons(SSDP_PORT
);
1160 sockname4
.sin_addr
.s_addr
= inet_addr(SSDP_MCAST_ADDR
);
1162 memset(&sockname6
, 0, sizeof(struct sockaddr_in6
));
1163 sockname6
.sin6_family
= AF_INET6
;
1164 sockname6
.sin6_port
= htons(SSDP_PORT
);
1165 inet_pton(AF_INET6
, LL_SSDP_MCAST_ADDR
, &(sockname6
.sin6_addr
));
1167 dest_str
= SSDP_MCAST_ADDR
;
1170 for(j
=0; j
<n_sockets
; j
++)
1177 dest_str
= "[" LL_SSDP_MCAST_ADDR
"]";
1178 sockname
= (struct sockaddr
*)&sockname6
;
1179 socknamelen
= sizeof(struct sockaddr_in6
);
1181 dest_str
= SSDP_MCAST_ADDR
;
1182 sockname
= (struct sockaddr
*)&sockname4
;
1183 socknamelen
= sizeof(struct sockaddr_in
);
1186 for(i
=0; known_service_types
[i
].s
; i
++)
1191 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
1192 ret
+= SendSSDPbyebye(sockets
[j
],
1194 sockname
, socknamelen
,
1196 (struct sockaddr
*)&sockname4
, sizeof(struct sockaddr_in
),
1199 known_service_types
[i
].s
, ver_str
, /* NT: */
1200 known_service_types
[i
].uuid
, "::",
1201 known_service_types
[i
].s
); /* ver_str, USN: */
1202 if(0==memcmp(known_service_types
[i
].s
,
1203 "urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1))
1205 ret
+= SendSSDPbyebye(sockets
[j
],
1207 sockname
, socknamelen
,
1209 (struct sockaddr
*)&sockname4
, sizeof(struct sockaddr_in
),
1212 known_service_types
[i
].uuid
, "", /* NT: */
1213 known_service_types
[i
].uuid
, "", ""); /* ver_str, USN: */
1220 /* SubmitServicesToMiniSSDPD() :
1221 * register services offered by MiniUPnPd to a running instance of
1224 SubmitServicesToMiniSSDPD(const char * host
, unsigned short port
) {
1225 struct sockaddr_un addr
;
1227 unsigned char buffer
[2048];
1233 s
= socket(AF_UNIX
, SOCK_STREAM
, 0);
1235 syslog(LOG_ERR
, "socket(unix): %m");
1238 addr
.sun_family
= AF_UNIX
;
1239 strncpy(addr
.sun_path
, minissdpdsocketpath
, sizeof(addr
.sun_path
));
1240 if(connect(s
, (struct sockaddr
*)&addr
, sizeof(struct sockaddr_un
)) < 0) {
1241 syslog(LOG_ERR
, "connect(\"%s\"): %m", minissdpdsocketpath
);
1245 for(i
= 0; known_service_types
[i
].s
; i
++) {
1246 buffer
[0] = 4; /* request type 4 : submit service */
1247 /* 4 strings following : ST (service type), USN, Server, Location */
1249 l
= (int)strlen(known_service_types
[i
].s
);
1253 memcpy(p
, known_service_types
[i
].s
, l
);
1260 snprintf(ver_str
, sizeof(ver_str
), "%d", known_service_types
[i
].version
);
1261 l
= snprintf(strbuf
, sizeof(strbuf
), "%s::%s%s",
1262 known_service_types
[i
].uuid
, known_service_types
[i
].s
, ver_str
);
1264 syslog(LOG_WARNING
, "SubmitServicesToMiniSSDPD: snprintf %m");
1266 } else if((unsigned)l
>=sizeof(strbuf
)) {
1267 l
= sizeof(strbuf
) - 1;
1270 memcpy(p
, strbuf
, l
);
1272 l
= (int)strlen(MINIUPNPD_SERVER_STRING
);
1274 memcpy(p
, MINIUPNPD_SERVER_STRING
, l
);
1276 l
= snprintf(strbuf
, sizeof(strbuf
), "http://%s:%u" ROOTDESC_PATH
,
1277 host
, (unsigned int)port
);
1279 syslog(LOG_WARNING
, "SubmitServicesToMiniSSDPD: snprintf %m");
1281 } else if((unsigned)l
>=sizeof(strbuf
)) {
1282 l
= sizeof(strbuf
) - 1;
1285 memcpy(p
, strbuf
, l
);
1287 /* now write the encoded data */
1288 n
= p
- buffer
; /* bytes to send */
1289 p
= buffer
; /* start */
1295 syslog(LOG_ERR
, "write(): %m");
1298 } else if (l
== 0) {
1299 syslog(LOG_ERR
, "write() returned 0");