miniupnpd/upnphttp.c: Support for multiple URL in Callback: header (SUBSCRIBE)

This commit is contained in:
Thomas Bernard 2014-03-15 10:52:39 +01:00
parent 19261b6fef
commit 76170e5413
2 changed files with 53 additions and 21 deletions

View File

@ -2,6 +2,7 @@ $Id: Changelog.txt,v 1.365 2014/03/14 21:26:34 nanard Exp $
2014/03/14: 2014/03/14:
reject renewal of subscribtion that already timeouted reject renewal of subscribtion that already timeouted
Support for multiple URL in Callback: header (SUBSCRIBE)
2014/03/13: 2014/03/13:
fix getifaddr_in6() (used for PCP) fix getifaddr_in6() (used for PCP)

View File

@ -1,8 +1,8 @@
/* $Id: upnphttp.c,v 1.86 2013/02/07 10:26:07 nanard Exp $ */ /* $Id: upnphttp.c,v 1.87 2014/03/14 21:26:01 nanard Exp $ */
/* 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-2012 Thomas Bernard * Copyright (c) 2005-2014 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.
* */ * */
@ -162,14 +162,22 @@ ParseHttpHeaders(struct upnphttp * h)
#ifdef ENABLE_EVENTS #ifdef ENABLE_EVENTS
else if(strncasecmp(line, "Callback", 8)==0) else if(strncasecmp(line, "Callback", 8)==0)
{ {
/* The Callback can contain several urls :
* If there is more than one URL, when the service sends
* events, it will try these URLs in order until one
* succeeds. One or more URLs each enclosed by angle
* brackets ("<" and ">") */
p = colon; p = colon;
while(*p != '<' && *p != '\r' ) while(*p != '<' && *p != '\r' )
p++; p++;
n = 0; n = 0;
while(p[n] != '>' && p[n] != '\r' ) while(p[n] != '\r')
n++; n++;
h->req_CallbackOff = p + 1 - h->req_buf; while(n > 0 && p[n] != '>')
h->req_CallbackLen = MAX(0, n - 1); n--;
/* found last > character */
h->req_CallbackOff = p - h->req_buf;
h->req_CallbackLen = MAX(0, n + 1);
} }
else if(strncasecmp(line, "SID", 3)==0) else if(strncasecmp(line, "SID", 3)==0)
{ {
@ -374,6 +382,9 @@ ProcessHTTPPOST_upnphttp(struct upnphttp * h)
#ifdef ENABLE_EVENTS #ifdef ENABLE_EVENTS
/** /**
* checkCallbackURL()
* check that url is on originating IP
* extract first correct URL
* returns 0 if the callback header value is not valid * returns 0 if the callback header value is not valid
* 1 if it is valid. * 1 if it is valid.
*/ */
@ -385,56 +396,76 @@ checkCallbackURL(struct upnphttp * h)
const char * p; const char * p;
unsigned int i; unsigned int i;
if(h->req_CallbackOff <= 0 || h->req_CallbackLen < 8) start_again:
if(h->req_CallbackOff <= 0 || h->req_CallbackLen < 10)
return 0; return 0;
if(memcmp(h->req_buf + h->req_CallbackOff, "http://", 7) != 0) if(memcmp(h->req_buf + h->req_CallbackOff, "<http://", 8) != 0) {
return 0; p = h->req_buf + h->req_CallbackOff + 1;
ipv6 = 0; goto invalid;
}
/* extract host from url to addrstr[] */
i = 0; i = 0;
p = h->req_buf + h->req_CallbackOff + 7; p = h->req_buf + h->req_CallbackOff + 8;
if(*p == '[') { if(*p == '[') {
p++; p++;
ipv6 = 1; ipv6 = 1;
while(*p != ']' && i < (sizeof(addrstr)-1) while(*p != ']' && *p != '>' && i < (sizeof(addrstr)-1)
&& p < (h->req_buf + h->req_CallbackOff + h->req_CallbackLen)) && p < (h->req_buf + h->req_CallbackOff + h->req_CallbackLen))
addrstr[i++] = *(p++); addrstr[i++] = *(p++);
} else { } else {
while(*p != '/' && *p != ':' && i < (sizeof(addrstr)-1) ipv6 = 0;
while(*p != '/' && *p != ':' && *p != '>' && i < (sizeof(addrstr)-1)
&& p < (h->req_buf + h->req_CallbackOff + h->req_CallbackLen)) && p < (h->req_buf + h->req_CallbackOff + h->req_CallbackLen))
addrstr[i++] = *(p++); addrstr[i++] = *(p++);
} }
addrstr[i] = '\0'; addrstr[i] = '\0';
/* check addrstr */
if(ipv6) { if(ipv6) {
#ifdef ENABLE_IPV6
struct in6_addr addr; struct in6_addr addr;
if(inet_pton(AF_INET6, addrstr, &addr) <= 0) if(inet_pton(AF_INET6, addrstr, &addr) <= 0)
return 0; goto invalid;
#ifdef ENABLE_IPV6
if(!h->ipv6 if(!h->ipv6
|| (0!=memcmp(&addr, &(h->clientaddr_v6), sizeof(struct in6_addr)))) || (0!=memcmp(&addr, &(h->clientaddr_v6), sizeof(struct in6_addr))))
return 0; goto invalid;
#else #else
return 0; goto invalid;
#endif #endif
} else { } else {
struct in_addr addr; struct in_addr addr;
if(inet_pton(AF_INET, addrstr, &addr) <= 0) if(inet_pton(AF_INET, addrstr, &addr) <= 0)
return 0; goto invalid;
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
if(h->ipv6) { if(h->ipv6) {
if(!IN6_IS_ADDR_V4MAPPED(&(h->clientaddr_v6))) if(!IN6_IS_ADDR_V4MAPPED(&(h->clientaddr_v6)))
return 0; goto invalid;
if(0!=memcmp(&addr, ((const char *)&(h->clientaddr_v6) + 12), 4)) if(0!=memcmp(&addr, ((const char *)&(h->clientaddr_v6) + 12), 4))
return 0; goto invalid;
} else { } else {
if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr))) if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
return 0; goto invalid;
} }
#else #else
if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr))) if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
return 0; goto invalid;
#endif #endif
} }
/* select only the good callback url */
while(p < h->req_buf + h->req_CallbackOff + h->req_CallbackLen && *p != '>')
p++;
h->req_CallbackOff++; /* skip initial '<' */
h->req_CallbackLen = (int)(p - h->req_buf - h->req_CallbackOff);
return 1; return 1;
invalid:
while(p < h->req_buf + h->req_CallbackOff + h->req_CallbackLen && *p != '>')
p++;
if(*p != '>') return 0;
while(p < h->req_buf + h->req_CallbackOff + h->req_CallbackLen && *p != '<')
p++;
if(*p != '<') return 0;
h->req_CallbackLen -= (int)(p - h->req_buf - h->req_CallbackOff);
h->req_CallbackOff = (int)(p - h->req_buf);
goto start_again;
} }
static void static void