|
|
| version 1.1.1.1, 2012/02/21 23:16:02 | version 1.1.1.2, 2012/05/29 12:55:57 |
|---|---|
| Line 2 | Line 2 |
| /* Project : miniupnp | /* Project : miniupnp |
| * Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ | * Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ |
| * Author : Thomas Bernard | * Author : Thomas Bernard |
| * Copyright (c) 2005-2008 Thomas Bernard | * Copyright (c) 2005-2011 Thomas Bernard |
| * This software is subject to the conditions detailed in the | * This software is subject to the conditions detailed in the |
| * LICENCE file included in this distribution. | * LICENCE file included in this distribution. |
| * */ | * */ |
| Line 13 | Line 13 |
| #include <sys/types.h> | #include <sys/types.h> |
| #include <sys/socket.h> | #include <sys/socket.h> |
| #include <sys/param.h> | #include <sys/param.h> |
| #include <arpa/inet.h> | |
| #include <syslog.h> | #include <syslog.h> |
| #include <ctype.h> | #include <ctype.h> |
| #include "config.h" | #include "config.h" |
| Line 303 ProcessHTTPPOST_upnphttp(struct upnphttp * h) | Line 304 ProcessHTTPPOST_upnphttp(struct upnphttp * h) |
| } | } |
| #ifdef ENABLE_EVENTS | #ifdef ENABLE_EVENTS |
| /** | |
| * returns 0 if the callback header value is not valid | |
| * 1 if it is valid. | |
| */ | |
| static int | |
| checkCallbackURL(struct upnphttp * h) | |
| { | |
| char addrstr[48]; | |
| int ipv6; | |
| const char * p; | |
| int i; | |
| if(!h->req_Callback || h->req_CallbackLen < 8) | |
| return 0; | |
| if(memcmp(h->req_Callback, "http://", 7) != 0) | |
| return 0; | |
| ipv6 = 0; | |
| i = 0; | |
| p = h->req_Callback + 7; | |
| if(*p == '[') { | |
| p++; | |
| ipv6 = 1; | |
| while(*p != ']' && i < (sizeof(addrstr)-1) | |
| && p < (h->req_Callback + h->req_CallbackLen)) | |
| addrstr[i++] = *(p++); | |
| } else { | |
| while(*p != '/' && *p != ':' && i < (sizeof(addrstr)-1) | |
| && p < (h->req_Callback + h->req_CallbackLen)) | |
| addrstr[i++] = *(p++); | |
| } | |
| addrstr[i] = '\0'; | |
| if(ipv6) { | |
| struct in6_addr addr; | |
| if(inet_pton(AF_INET6, addrstr, &addr) <= 0) | |
| return 0; | |
| #ifdef ENABLE_IPV6 | |
| if(!h->ipv6 | |
| || (0!=memcmp(&addr, &(h->clientaddr_v6), sizeof(struct in6_addr)))) | |
| return 0; | |
| #else | |
| return 0; | |
| #endif | |
| } else { | |
| struct in_addr addr; | |
| if(inet_pton(AF_INET, addrstr, &addr) <= 0) | |
| return 0; | |
| #ifdef ENABLE_IPV6 | |
| if(h->ipv6) { | |
| if(!IN6_IS_ADDR_V4MAPPED(&(h->clientaddr_v6))) | |
| return 0; | |
| if(0!=memcmp(&addr, ((const char *)&(h->clientaddr_v6) + 12), 4)) | |
| return 0; | |
| } else { | |
| if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr))) | |
| return 0; | |
| } | |
| #else | |
| if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr))) | |
| return 0; | |
| #endif | |
| } | |
| return 1; | |
| } | |
| static void | static void |
| ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path) | ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path) |
| { | { |
| Line 323 ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, con | Line 388 ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, con |
| * - respond HTTP/x.x 200 OK | * - respond HTTP/x.x 200 OK |
| * - Send the initial event message */ | * - Send the initial event message */ |
| /* Server:, SID:; Timeout: Second-(xx|infinite) */ | /* Server:, SID:; Timeout: Second-(xx|infinite) */ |
| /* Check that the callback URL is on the same IP as | |
| * the request, and not on the internet, nor on ourself (DOS attack ?) */ | |
| if(h->req_Callback) { | if(h->req_Callback) { |
| sid = upnpevents_addSubscriber(path, h->req_Callback, | if(checkCallbackURL(h)) { |
| h->req_CallbackLen, h->req_Timeout); | sid = upnpevents_addSubscriber(path, h->req_Callback, |
| h->respflags = FLAG_TIMEOUT; | h->req_CallbackLen, h->req_Timeout); |
| if(sid) { | h->respflags = FLAG_TIMEOUT; |
| syslog(LOG_DEBUG, "generated sid=%s", sid); | if(sid) { |
| h->respflags |= FLAG_SID; | syslog(LOG_DEBUG, "generated sid=%s", sid); |
| h->req_SID = sid; | h->respflags |= FLAG_SID; |
| h->req_SIDLen = strlen(sid); | h->req_SID = sid; |
| h->req_SIDLen = strlen(sid); | |
| } | |
| BuildResp_upnphttp(h, 0, 0); | |
| } else { | |
| syslog(LOG_WARNING, "Invalid Callback in SUBSCRIBE %.*s", | |
| h->req_CallbackLen, h->req_Callback); | |
| BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); | |
| } | } |
| BuildResp_upnphttp(h, 0, 0); | |
| } else { | } else { |
| /* subscription renew */ | /* subscription renew */ |
| /* Invalid SID | /* Invalid SID |
| Line 343 with HTTP error 412 Precondition Failed. */ | Line 416 with HTTP error 412 Precondition Failed. */ |
| if(renewSubscription(h->req_SID, h->req_SIDLen, h->req_Timeout) < 0) { | if(renewSubscription(h->req_SID, h->req_SIDLen, h->req_Timeout) < 0) { |
| BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); | BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); |
| } else { | } else { |
| h->respflags = FLAG_TIMEOUT; | |
| BuildResp_upnphttp(h, 0, 0); | BuildResp_upnphttp(h, 0, 0); |
| } | } |
| } | } |
| Line 429 ProcessHttpQuery_upnphttp(struct upnphttp * h) | Line 503 ProcessHttpQuery_upnphttp(struct upnphttp * h) |
| sendXMLdesc(h, genL3F); | sendXMLdesc(h, genL3F); |
| } | } |
| #endif | #endif |
| #ifdef ENABLE_6FC_SERVICE | |
| else if(strcasecmp(WANIP6FC_PATH, HttpUrl) == 0) | |
| { | |
| sendXMLdesc(h, gen6FC); | |
| } | |
| #endif | |
| #ifdef ENABLE_DP_SERVICE | |
| else if(strcasecmp(DP_PATH, HttpUrl) == 0) | |
| { | |
| sendXMLdesc(h, genDP); | |
| } | |
| #endif | |
| else | else |
| { | { |
| syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl); | syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl); |
| Line 535 static const char httpresphead[] = | Line 621 static const char httpresphead[] = |
| "Content-Type: %s\r\n" | "Content-Type: %s\r\n" |
| "Connection: close\r\n" | "Connection: close\r\n" |
| "Content-Length: %d\r\n" | "Content-Length: %d\r\n" |
| /*"Server: miniupnpd/1.0 UPnP/1.0\r\n"*/ | |
| "Server: " MINIUPNPD_SERVER_STRING "\r\n" | "Server: " MINIUPNPD_SERVER_STRING "\r\n" |
| ; /*"\r\n";*/ | ; /*"\r\n";*/ |
| /* | /* |
| Line 560 BuildHeader_upnphttp(struct upnphttp * h, int respcode | Line 645 BuildHeader_upnphttp(struct upnphttp * h, int respcode |
| { | { |
| templen = sizeof(httpresphead) + 128 + bodylen; | templen = sizeof(httpresphead) + 128 + bodylen; |
| h->res_buf = (char *)malloc(templen); | h->res_buf = (char *)malloc(templen); |
| if(!h->res_buf) | |
| { | |
| syslog(LOG_ERR, "malloc error in BuildHeader_upnphttp()"); | |
| return; | |
| } | |
| h->res_buf_alloclen = templen; | h->res_buf_alloclen = templen; |
| } | } |
| h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen, | h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen, |
| Line 593 BuildHeader_upnphttp(struct upnphttp * h, int respcode | Line 683 BuildHeader_upnphttp(struct upnphttp * h, int respcode |
| h->res_buf[h->res_buflen++] = '\n'; | h->res_buf[h->res_buflen++] = '\n'; |
| if(h->res_buf_alloclen < (h->res_buflen + bodylen)) | if(h->res_buf_alloclen < (h->res_buflen + bodylen)) |
| { | { |
| h->res_buf = (char *)realloc(h->res_buf, (h->res_buflen + bodylen)); | char * tmp; |
| h->res_buf_alloclen = h->res_buflen + bodylen; | tmp = (char *)realloc(h->res_buf, (h->res_buflen + bodylen)); |
| if(tmp) | |
| { | |
| h->res_buf = tmp; | |
| h->res_buf_alloclen = h->res_buflen + bodylen; | |
| } | |
| else | |
| { | |
| syslog(LOG_ERR, "realloc error in BuildHeader_upnphttp()"); | |
| } | |
| } | } |
| } | } |
| Line 620 BuildResp_upnphttp(struct upnphttp * h, | Line 719 BuildResp_upnphttp(struct upnphttp * h, |
| void | void |
| SendResp_upnphttp(struct upnphttp * h) | SendResp_upnphttp(struct upnphttp * h) |
| { | { |
| int n; | char * p; |
| n = send(h->socket, h->res_buf, h->res_buflen, 0); | ssize_t n; |
| if(n<0) | size_t len; |
| p = h->res_buf; | |
| len = h->res_buflen; | |
| while (len > 0) | |
| { | { |
| syslog(LOG_ERR, "send(res_buf): %m"); | n = send(h->socket, p, len, 0); |
| } | if(n<0) |
| else if(n < h->res_buflen) | { |
| { | syslog(LOG_ERR, "send(res_buf): %m"); |
| /* TODO : handle correctly this case */ | } |
| syslog(LOG_ERR, "send(res_buf): %d bytes sent (out of %d)", | else if(n == 0) |
| n, h->res_buflen); | { |
| syslog(LOG_ERR, "send(res_buf): %zd bytes sent (out of %zu)", | |
| n, len); | |
| break; | |
| } | |
| else | |
| { | |
| p += n; | |
| len -= n; | |
| } | |
| } | } |
| } | } |