--- embedaddon/miniupnpd/minissdp.c 2012/02/21 23:16:02 1.1.1.1 +++ embedaddon/miniupnpd/minissdp.c 2012/05/29 12:55:57 1.1.1.2 @@ -1,7 +1,7 @@ -/* $Id: minissdp.c,v 1.1.1.1 2012/02/21 23:16:02 misho Exp $ */ +/* $Id: minissdp.c,v 1.1.1.2 2012/05/29 12:55:57 misho Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2010 Thomas Bernard + * (c) 2006-2011 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -19,16 +19,19 @@ #include "upnphttp.h" #include "upnpglobalvars.h" #include "minissdp.h" +#include "upnputils.h" #include "codelength.h" /* SSDP ip/port */ #define SSDP_PORT (1900) -/* Prototypes */ -void ProcessSSDPData(int s, char *bufr, struct sockaddr_in sendername, int n, unsigned short port) ; - - #define SSDP_MCAST_ADDR ("239.255.255.250") +#define LL_SSDP_MCAST_ADDR ("FF02::C") +#define SL_SSDP_MCAST_ADDR ("FF05::C") +/* AddMulticastMembership() + * param s socket + * param ifaddr ip v4 address + */ static int AddMulticastMembership(int s, in_addr_t ifaddr) { @@ -48,52 +51,103 @@ AddMulticastMembership(int s, in_addr_t ifaddr) return 0; } +/* AddMulticastMembershipIPv6() + * param s socket (IPv6) + * To be improved to target specific network interfaces */ +#ifdef ENABLE_IPV6 +static int +AddMulticastMembershipIPv6(int s) +{ + struct ipv6_mreq mr; + /*unsigned int ifindex;*/ + + memset(&mr, 0, sizeof(mr)); + inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr); + /*mr.ipv6mr_interface = ifindex;*/ + mr.ipv6mr_interface = 0; /* 0 : all interfaces */ +#ifndef IPV6_ADD_MEMBERSHIP +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif + if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0) + { + syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m"); + return -1; + } + inet_pton(AF_INET6, SL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr); + if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0) + { + syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m"); + return -1; + } + return 0; +} +#endif + /* Open and configure the socket listening for - * SSDP udp packets sent on 239.255.255.250 port 1900 */ + * SSDP udp packets sent on 239.255.255.250 port 1900 + * SSDP v6 udp packets sent on FF02::C, or FF05::C, port 1900 */ int -OpenAndConfSSDPReceiveSocket() +OpenAndConfSSDPReceiveSocket(int ipv6) { int s; - int i; + struct sockaddr_storage sockname; + socklen_t sockname_len; + struct lan_addr_s * lan_addr; int j = 1; - struct sockaddr_in sockname; - - if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) + + if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "socket(udp): %m"); return -1; - } - - memset(&sockname, 0, sizeof(struct sockaddr_in)); - sockname.sin_family = AF_INET; - sockname.sin_port = htons(SSDP_PORT); - /* NOTE : it seems it doesnt work when binding on the specific address */ - /*sockname.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/ - sockname.sin_addr.s_addr = htonl(INADDR_ANY); - /*sockname.sin_addr.s_addr = inet_addr(ifaddr);*/ + } + memset(&sockname, 0, sizeof(struct sockaddr_storage)); + if(ipv6) { + struct sockaddr_in6 * saddr = (struct sockaddr_in6 *)&sockname; + saddr->sin6_family = AF_INET6; + saddr->sin6_port = htons(SSDP_PORT); + saddr->sin6_addr = in6addr_any; + sockname_len = sizeof(struct sockaddr_in6); + } else { + struct sockaddr_in * saddr = (struct sockaddr_in *)&sockname; + saddr->sin_family = AF_INET; + saddr->sin_port = htons(SSDP_PORT); + /* NOTE : it seems it doesnt work when binding on the specific address */ + /*saddr->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/ + saddr->sin_addr.s_addr = htonl(INADDR_ANY); + /*saddr->sin_addr.s_addr = inet_addr(ifaddr);*/ + sockname_len = sizeof(struct sockaddr_in); + } + if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j)) < 0) { syslog(LOG_WARNING, "setsockopt(udp, SO_REUSEADDR): %m"); } - if(bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0) + if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0) { - syslog(LOG_ERR, "bind(udp): %m"); + syslog(LOG_ERR, "bind(udp%s): %m", ipv6 ? "6" : ""); close(s); return -1; - } + } - i = n_lan_addr; - while(i>0) +#ifdef ENABLE_IPV6 + if(ipv6) { - i--; - if(AddMulticastMembership(s, lan_addr[i].addr.s_addr) < 0) + AddMulticastMembershipIPv6(s); + } + else +#endif + { + for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) { - syslog(LOG_WARNING, - "Failed to add multicast membership for address %s", - lan_addr[i].str ); + if(AddMulticastMembership(s, lan_addr->addr.s_addr) < 0) + { + syslog(LOG_WARNING, + "Failed to add multicast membership for interface %s", + lan_addr->str); + } } } @@ -160,9 +214,11 @@ OpenAndConfSSDPNotifySockets(int * sockets) struct lan_addr_s * lan_addr, int n_lan_addr)*/ { int i, j; - for(i=0; ilist.le_next, i++) { - sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr[i].addr.s_addr); + sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr->addr.s_addr); if(sockets[i] < 0) { for(j=0; jsa_family == AF_INET6) + ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); n = sendto(s, buf, l, 0, - (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) ); + addr, addrlen); syslog(LOG_INFO, "SSDP Announce %d bytes to %s:%d ST: %.*s",n, - inet_ntoa(sockname.sin_addr), - ntohs(sockname.sin_port), + inet_ntoa(((const struct sockaddr_in *)addr)->sin_addr), + ntohs(((const struct sockaddr_in *)addr)->sin_port), l, buf); if(n < 0) { @@ -246,7 +311,12 @@ static const char * const known_service_types[] = "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:", "urn:schemas-upnp-org:service:WANIPConnection:", "urn:schemas-upnp-org:service:WANPPPConnection:", +#ifdef ENABLE_L3F_SERVICE "urn:schemas-upnp-org:service:Layer3Forwarding:", +#endif +#ifdef ENABLE_6FC_SERVICE + "url:schemas-upnp-org:service:WANIPv6FirewallControl:", +#endif 0 }; @@ -266,21 +336,25 @@ SendSSDPNotifies(int s, const char * host, unsigned sh while(known_service_types[i]) { l = snprintf(bufr, sizeof(bufr), - "NOTIFY * HTTP/1.1\r\n" - "HOST:%s:%d\r\n" - "Cache-Control:max-age=%u\r\n" - "Location:http://%s:%d" ROOTDESC_PATH"\r\n" - /*"Server:miniupnpd/1.0 UPnP/1.0\r\n"*/ - "Server: " MINIUPNPD_SERVER_STRING "\r\n" - "NT:%s%s\r\n" - "USN:%s::%s%s\r\n" - "NTS:ssdp:alive\r\n" - "\r\n", - SSDP_MCAST_ADDR, SSDP_PORT, - lifetime, - host, port, - known_service_types[i], (i==0?"":"1"), - uuidvalue, known_service_types[i], (i==0?"":"1") ); + "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%d\r\n" + "CACHE-CONTROL: max-age=%u\r\n" + "lOCATION: http://%s:%d" ROOTDESC_PATH"\r\n" + "SERVER: " MINIUPNPD_SERVER_STRING "\r\n" + "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 */ + "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, + lifetime, + host, port, + known_service_types[i], (i==0?"":"1"), + uuidvalue, known_service_types[i], (i==0?"":"1"), + upnp_bootid, upnp_bootid, upnp_configid ); if(l>=sizeof(bufr)) { syslog(LOG_WARNING, "SendSSDPNotifies(): truncated output"); @@ -300,14 +374,12 @@ void SendSSDPNotifies2(int * sockets, unsigned short port, unsigned int lifetime) -/*SendSSDPNotifies2(int * sockets, struct lan_addr_s * lan_addr, int n_lan_addr, - unsigned short port, - unsigned int lifetime)*/ { int i; - for(i=0; ilist.le_next, i++) { - SendSSDPNotifies(sockets[i], lan_addr[i].str, port, lifetime); + SendSSDPNotifies(sockets[i], lan_addr->str, port, lifetime); } } @@ -319,8 +391,13 @@ ProcessSSDPRequest(int s, unsigned short port) int n; char bufr[1500]; socklen_t len_r; +#ifdef ENABLE_IPV6 + struct sockaddr_storage sendername; + len_r = sizeof(struct sockaddr_storage); +#else struct sockaddr_in sendername; len_r = sizeof(struct sockaddr_in); +#endif n = recvfrom(s, bufr, sizeof(bufr), 0, (struct sockaddr *)&sendername, &len_r); @@ -329,16 +406,22 @@ ProcessSSDPRequest(int s, unsigned short port) syslog(LOG_ERR, "recvfrom(udp): %m"); return; } - ProcessSSDPData(s, bufr, sendername, n, port); + ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, port); } -void ProcessSSDPData(int s, char *bufr, struct sockaddr_in sendername, int n, unsigned short port) { +void +ProcessSSDPData(int s, const char *bufr, int n, + const struct sockaddr * sender, unsigned short port) { int i, l; - int lan_addr_index = 0; - char * st = 0; + struct lan_addr_s * lan_addr = NULL; + const char * st = NULL; int st_len = 0; + char sender_str[64]; + const char * announced_host = NULL; + /* get the string representation of the sender address */ + sockaddr_to_string(sender, sender_str, sizeof(sender_str)); if(memcmp(bufr, "NOTIFY", 6) == 0) { @@ -368,26 +451,38 @@ void ProcessSSDPData(int s, char *bufr, struct sockadd /*syslog(LOG_INFO, "%.*s", j, bufr+i);*/ } } - /*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s:%d", - inet_ntoa(sendername.sin_addr), - ntohs(sendername.sin_port) );*/ + /*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s", + sender_str );*/ if(st && (st_len > 0)) { /* TODO : doesnt answer at once but wait for a random time */ - syslog(LOG_INFO, "SSDP M-SEARCH from %s:%d ST: %.*s", - inet_ntoa(sendername.sin_addr), - ntohs(sendername.sin_port), - st_len, st); + syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s", + sender_str, st_len, st); /* find in which sub network the client is */ - for(i = 0; isa_family == AF_INET) { - if( (sendername.sin_addr.s_addr & lan_addr[i].mask.s_addr) - == (lan_addr[i].addr.s_addr & lan_addr[i].mask.s_addr)) + for(lan_addr = lan_addrs.lh_first; + lan_addr != NULL; + lan_addr = lan_addr->list.le_next) { - lan_addr_index = i; - break; + if( (((const struct sockaddr_in *)sender)->sin_addr.s_addr & lan_addr->mask.s_addr) + == (lan_addr->addr.s_addr & lan_addr->mask.s_addr)) + break; } + if (lan_addr == NULL) + { + syslog(LOG_ERR, "Can't find in which sub network the client is"); + return; + } + announced_host = lan_addr->str; } +#ifdef ENABLE_IPV6 + else + { + /* IPv6 address with brackets */ + announced_host = ipv6_addr_for_http_with_brackets; + } +#endif /* Responds to request with a device as ST header */ for(i = 0; known_service_types[i]; i++) { @@ -395,9 +490,9 @@ void ProcessSSDPData(int s, char *bufr, struct sockadd if(l<=st_len && (0 == memcmp(st, known_service_types[i], l))) { syslog(LOG_INFO, "Single search found"); - SendSSDPAnnounce2(s, sendername, + SendSSDPAnnounce2(s, sender, st, st_len, "", - lan_addr[lan_addr_index].str, port); + announced_host, port); break; } } @@ -409,9 +504,9 @@ void ProcessSSDPData(int s, char *bufr, struct sockadd for(i=0; known_service_types[i]; i++) { l = (int)strlen(known_service_types[i]); - SendSSDPAnnounce2(s, sendername, + SendSSDPAnnounce2(s, sender, known_service_types[i], l, i==0?"":"1", - lan_addr[lan_addr_index].str, port); + announced_host, port); } } /* responds to request by UUID value */ @@ -419,20 +514,18 @@ void ProcessSSDPData(int s, char *bufr, struct sockadd if(l==st_len && (0 == memcmp(st, uuidvalue, l))) { syslog(LOG_INFO, "ssdp:uuid found"); - SendSSDPAnnounce2(s, sendername, st, st_len, "", - lan_addr[lan_addr_index].str, port); + SendSSDPAnnounce2(s, sender, st, st_len, "", + announced_host, port); } } else { - syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s:%d", - inet_ntoa(sendername.sin_addr), ntohs(sendername.sin_port)); + syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s", sender_str); } } else { - syslog(LOG_NOTICE, "Unknown udp packet received from %s:%d", - inet_ntoa(sendername.sin_addr), ntohs(sendername.sin_port)); + syslog(LOG_NOTICE, "Unknown udp packet received from %s", sender_str); } } @@ -456,15 +549,20 @@ SendSSDPGoodbye(int * sockets, int n_sockets) for(i=0; known_service_types[i]; i++) { l = snprintf(bufr, sizeof(bufr), - "NOTIFY * HTTP/1.1\r\n" - "HOST:%s:%d\r\n" - "NT:%s%s\r\n" - "USN:%s::%s%s\r\n" - "NTS:ssdp:byebye\r\n" - "\r\n", - SSDP_MCAST_ADDR, SSDP_PORT, - known_service_types[i], (i==0?"":"1"), - uuidvalue, known_service_types[i], (i==0?"":"1")); + "NOTIFY * HTTP/1.1\r\n" + "HOST: %s:%d\r\n" + "NT: %s%s\r\n" + "USN: %s::%s%s\r\n" + "NTS: ssdp:byebye\r\n" + "OPT: \"http://schemas.upnp.org/upnp/1/0/\";\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, + known_service_types[i], (i==0?"":"1"), + uuidvalue, known_service_types[i], (i==0?"":"1"), + upnp_bootid, upnp_bootid, upnp_configid); n = sendto(sockets[j], bufr, l, 0, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) ); if(n < 0)