From 593dc2660889540a860b18722918837c00ececcf Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 6 Apr 2012 19:30:19 +0200 Subject: [PATCH] Send SSDP NOTIFY ssdp:alive and ssdp:goodbye in IPv6 too --- miniupnpd/Changelog.txt | 2 + miniupnpd/minissdp.c | 144 ++++++++++++++++++++++++++++++++-------- miniupnpd/miniupnpd.c | 18 ++++- 3 files changed, 134 insertions(+), 30 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index e242875..77011fd 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,6 +1,8 @@ $Id: Changelog.txt,v 1.267 2012/04/06 17:24:36 nanard Exp $ 2012/04/06: + Implementing IPv6 support : + Send SSDP NOTIFY ssdp:alive and ssdp:goodbye messages in IPv6. Use UPnP/1.1 in SERVER: string as required in UPnP Device architecture 1.1. Allow LAN interface to be given as interface names, instead of interface IP addresses. It will allow IPv6 operations. diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index 85177a1..ab337d8 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -1,4 +1,4 @@ -/* $Id: minissdp.c,v 1.29 2012/02/09 20:15:24 nanard Exp $ */ +/* $Id: minissdp.c,v 1.31 2012/04/06 17:24:37 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2012 Thomas Bernard @@ -26,8 +26,8 @@ /* SSDP ip/port */ #define SSDP_PORT (1900) #define SSDP_MCAST_ADDR ("239.255.255.250") -#define LL_SSDP_MCAST_ADDR ("FF02::C") -#define SL_SSDP_MCAST_ADDR ("FF05::C") +#define LL_SSDP_MCAST_ADDR "FF02::C" +#define SL_SSDP_MCAST_ADDR "FF05::C" /* AddMulticastMembership() * param s socket @@ -216,28 +216,68 @@ OpenAndConfSSDPNotifySocket(in_addr_t addr) return s; } +#ifdef ENABLE_IPV6 +/* open the UDP socket used to send SSDP notifications to + * the multicast group reserved for them. IPv6 */ +static int +OpenAndConfSSDPNotifySocketIPv6(unsigned int if_index) +{ + int s; + unsigned int loop = 0; + + s = socket(PF_INET6, SOCK_DGRAM, 0); + if(s < 0) + { + syslog(LOG_ERR, "socket(udp_notify IPv6): %m"); + return -1; + } + if(setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_index, sizeof(if_index)) < 0) + { + syslog(LOG_ERR, "setsockopt(udp_notify IPv6, IPV6_MULTICAST_IF, %u): %m", if_index); + close(s); + return -1; + } + if(setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) + { + syslog(LOG_ERR, "setsockopt(udp_notify, IPV6_MULTICAST_LOOP): %m"); + close(s); + return -1; + } + return s; +} +#endif + int OpenAndConfSSDPNotifySockets(int * sockets) /*OpenAndConfSSDPNotifySockets(int * sockets, struct lan_addr_s * lan_addr, int n_lan_addr)*/ { - int i, j; + int i; struct lan_addr_s * lan_addr; - for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++) + for(i=0, lan_addr = lan_addrs.lh_first; + lan_addr != NULL; + lan_addr = lan_addr->list.le_next) { sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr->addr.s_addr); if(sockets[i] < 0) - { - for(j=0; jindex); + if(sockets[i] < 0) + goto error; + i++; +#endif } return 0; +error: + while(--i >= 0) + { + close(sockets[i]); + sockets[i] = -1; + } + return -1; } /* @@ -288,7 +328,7 @@ SendSSDPAnnounce2(int s, const struct sockaddr * addr, "EXT:\r\n" "SERVER: " MINIUPNPD_SERVER_STRING "\r\n" "LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n" - "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */ + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */ "01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */ "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ @@ -332,16 +372,35 @@ static const char * const known_service_types[] = static void SendSSDPNotifies(int s, const char * host, unsigned short port, - unsigned int lifetime) + unsigned int lifetime, int ipv6) { +#ifdef ENABLE_IPV6 + struct sockaddr_storage sockname; +#else struct sockaddr_in sockname; +#endif int l, n, i=0; char bufr[512]; - memset(&sockname, 0, sizeof(struct sockaddr_in)); - sockname.sin_family = AF_INET; - sockname.sin_port = htons(SSDP_PORT); - sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); + memset(&sockname, 0, sizeof(sockname)); +#ifdef ENABLE_IPV6 + if(ipv6) + { + struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockname; + p->sin6_family = AF_INET6; + p->sin6_port = htons(SSDP_PORT); + inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &(p->sin6_addr)); + } + else + { +#endif + struct sockaddr_in *p = (struct sockaddr_in *)&sockname; + p->sin_family = AF_INET; + p->sin_port = htons(SSDP_PORT); + p->sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); +#ifdef ENABLE_IPV6 + } +#endif while(known_service_types[i]) { @@ -354,12 +413,13 @@ SendSSDPNotifies(int s, const char * host, unsigned short port, "NT: %s%s\r\n" "USN: %s::%s%s\r\n" "NTS: ssdp:alive\r\n" - "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\r\n" /* UDA v1.1 */ + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */ "01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */ "BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ "CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */ "\r\n", - SSDP_MCAST_ADDR, SSDP_PORT, + ipv6 ? "[" LL_SSDP_MCAST_ADDR "]" : SSDP_MCAST_ADDR, + SSDP_PORT, lifetime, host, port, known_service_types[i], (i==0?"":"1"), @@ -371,7 +431,13 @@ SendSSDPNotifies(int s, const char * host, unsigned short port, l = sizeof(bufr); } n = sendto(s, bufr, l, 0, - (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) ); + (struct sockaddr *)&sockname, +#ifdef ENABLE_IPV6 + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in) +#else + sizeof(struct sockaddr_in) +#endif + ); if(n < 0) { /* XXX handle EINTR, EAGAIN, EWOULDBLOCK */ @@ -388,9 +454,18 @@ SendSSDPNotifies2(int * sockets, { int i; struct lan_addr_s * lan_addr; - for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++) + for(i=0, lan_addr = lan_addrs.lh_first; + lan_addr != NULL; + lan_addr = lan_addr->list.le_next) { - SendSSDPNotifies(sockets[i], lan_addr->str, port, lifetime); + SendSSDPNotifies(sockets[i], lan_addr->str, port, + lifetime, 0); + i++; +#ifdef ENABLE_IPV6 + SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, port, + lifetime, 1); + i++; +#endif } } @@ -553,18 +628,31 @@ int SendSSDPGoodbye(int * sockets, int n_sockets) { struct sockaddr_in sockname; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 sockname6; +#endif int n, l; int i, j; char bufr[512]; int ret = 0; + int ipv6 = 0; memset(&sockname, 0, sizeof(struct sockaddr_in)); sockname.sin_family = AF_INET; sockname.sin_port = htons(SSDP_PORT); sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); +#ifdef ENABLE_IPV6 + memset(&sockname6, 0, sizeof(struct sockaddr_in6)); + sockname6.sin6_family = AF_INET6; + sockname6.sin6_port = htons(SSDP_PORT); + inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &(sockname6.sin6_addr)); +#endif for(j=0; jlist.le_next) addr_count++; if(addr_count > 0) { +#ifndef ENABLE_IPV6 snotify = calloc(addr_count, sizeof(int)); +#else + /* one for IPv4, one for IPv6 */ + snotify = calloc(addr_count * 2, sizeof(int)); +#endif } #ifdef ENABLE_NATPMP if(addr_count > 0) { @@ -1725,14 +1730,21 @@ shutdown: } #endif - /*if(SendSSDPGoodbye(snotify, v.n_lan_addr) < 0)*/ if (GETFLAG(ENABLEUPNPMASK)) { +#ifndef ENABLE_IPV6 if(SendSSDPGoodbye(snotify, addr_count) < 0) +#else + if(SendSSDPGoodbye(snotify, addr_count * 2) < 0) +#endif { syslog(LOG_ERR, "Failed to broadcast good-bye notifications"); } - for(i=0; i