|
version 1.1.1.2, 2012/05/29 12:55:57
|
version 1.1.1.3, 2013/07/22 00:32:35
|
|
Line 1
|
Line 1
|
| /* $Id$ */ |
/* $Id$ */ |
| /* MiniUPnP project |
/* MiniUPnP project |
| * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ |
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ |
| * (c) 2006-2011 Thomas Bernard | * (c) 2006-2012 Thomas Bernard |
| * This software is subject to the conditions detailed |
* This software is subject to the conditions detailed |
| * in the LICENCE file provided within the distribution */ |
* in the LICENCE file provided within the distribution */ |
| |
|
| #include <stdio.h> |
#include <stdio.h> |
| #include <stdlib.h> |
#include <stdlib.h> |
| #include <string.h> |
#include <string.h> |
| |
#include <errno.h> |
| #include <sys/socket.h> |
#include <sys/socket.h> |
| #include <unistd.h> |
#include <unistd.h> |
| #include <syslog.h> |
#include <syslog.h> |
| #include <sys/types.h> |
#include <sys/types.h> |
| #include <arpa/inet.h> |
|
| #include <netinet/in.h> |
#include <netinet/in.h> |
| |
#include <arpa/inet.h> |
| #include <netdb.h> |
#include <netdb.h> |
| |
|
| |
#include "macros.h" |
| #include "config.h" |
#include "config.h" |
| #include "upnpglobalvars.h" |
#include "upnpglobalvars.h" |
| #include "upnphttp.h" |
#include "upnphttp.h" |
| #include "upnpsoap.h" |
#include "upnpsoap.h" |
| #include "upnpreplyparse.h" |
#include "upnpreplyparse.h" |
| #include "upnpredirect.h" |
#include "upnpredirect.h" |
| |
#include "upnppinhole.h" |
| #include "getifaddr.h" |
#include "getifaddr.h" |
| #include "getifstats.h" |
#include "getifstats.h" |
| #include "getconnstatus.h" |
#include "getconnstatus.h" |
|
Line 53 BuildSendAndCloseSoapResp(struct upnphttp * h,
|
Line 56 BuildSendAndCloseSoapResp(struct upnphttp * h,
|
| memcpy(h->res_buf + h->res_buflen, afterbody, sizeof(afterbody) - 1); |
memcpy(h->res_buf + h->res_buflen, afterbody, sizeof(afterbody) - 1); |
| h->res_buflen += sizeof(afterbody) - 1; |
h->res_buflen += sizeof(afterbody) - 1; |
| |
|
| SendResp_upnphttp(h); | SendRespAndClose_upnphttp(h); |
| CloseSocket_upnphttp(h); | |
| } |
} |
| |
|
| static void |
static void |
|
Line 66 GetConnectionTypeInfo(struct upnphttp * h, const char
|
Line 68 GetConnectionTypeInfo(struct upnphttp * h, const char
|
| "<NewConnectionType>IP_Routed</NewConnectionType>" |
"<NewConnectionType>IP_Routed</NewConnectionType>" |
| "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>" |
"<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>" |
| "</u:GetConnectionTypeInfoResponse>"; |
"</u:GetConnectionTypeInfoResponse>"; |
| |
UNUSED(action); |
| |
|
| BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); |
BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); |
| } |
} |
| |
|
|
Line 220 GetStatusInfo(struct upnphttp * h, const char * action
|
Line 224 GetStatusInfo(struct upnphttp * h, const char * action
|
| uptime = (time(NULL) - startup_time); |
uptime = (time(NULL) - startup_time); |
| bodylen = snprintf(body, sizeof(body), resp, |
bodylen = snprintf(body, sizeof(body), resp, |
| action, SERVICE_TYPE_WANIPC, |
action, SERVICE_TYPE_WANIPC, |
| status, (long)uptime, action); | status, (long)uptime, action); |
| BuildSendAndCloseSoapResp(h, body, bodylen); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
| } |
} |
| |
|
|
Line 233 GetNATRSIPStatus(struct upnphttp * h, const char * act
|
Line 237 GetNATRSIPStatus(struct upnphttp * h, const char * act
|
| "<NewRSIPAvailable>0</NewRSIPAvailable>" |
"<NewRSIPAvailable>0</NewRSIPAvailable>" |
| "<NewNATEnabled>1</NewNATEnabled>" |
"<NewNATEnabled>1</NewNATEnabled>" |
| "</u:GetNATRSIPStatusResponse>"; |
"</u:GetNATRSIPStatusResponse>"; |
| |
UNUSED(action); |
| /* 2.2.9. RSIPAvailable |
/* 2.2.9. RSIPAvailable |
| * This variable indicates if Realm-specific IP (RSIP) is available |
* This variable indicates if Realm-specific IP (RSIP) is available |
| * as a feature on the InternetGatewayDevice. RSIP is being defined |
* as a feature on the InternetGatewayDevice. RSIP is being defined |
|
Line 335 AddPortMapping(struct upnphttp * h, const char * actio
|
Line 340 AddPortMapping(struct upnphttp * h, const char * actio
|
| #endif |
#endif |
| |
|
| /* if ip not valid assume hostname and convert */ |
/* if ip not valid assume hostname and convert */ |
| if (inet_pton(AF_INET, int_ip, &result_ip) <= 0) | if (inet_pton(AF_INET, int_ip, &result_ip) <= 0) |
| { |
{ |
| hp = gethostbyname(int_ip); |
hp = gethostbyname(int_ip); |
| if(hp && hp->h_addrtype == AF_INET) | if(hp && hp->h_addrtype == AF_INET) |
| { | { |
| for(ptr = hp->h_addr_list; ptr && *ptr; ptr++) |
for(ptr = hp->h_addr_list; ptr && *ptr; ptr++) |
| { |
{ |
| int_ip = inet_ntoa(*((struct in_addr *) *ptr)); |
int_ip = inet_ntoa(*((struct in_addr *) *ptr)); |
|
Line 347 AddPortMapping(struct upnphttp * h, const char * actio
|
Line 352 AddPortMapping(struct upnphttp * h, const char * actio
|
| /* TODO : deal with more than one ip per hostname */ |
/* TODO : deal with more than one ip per hostname */ |
| break; |
break; |
| } |
} |
| } | } |
| else | else |
| { |
{ |
| syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip); | syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip); |
| ClearNameValueList(&data); |
ClearNameValueList(&data); |
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
| return; |
return; |
| } | } |
| } |
} |
| |
|
| /* check if NewInternalAddress is the client address */ |
/* check if NewInternalAddress is the client address */ |
|
Line 401 AddPortMapping(struct upnphttp * h, const char * actio
|
Line 406 AddPortMapping(struct upnphttp * h, const char * actio
|
| #endif |
#endif |
| |
|
| syslog(LOG_INFO, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s", |
syslog(LOG_INFO, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s", |
| action, eport, int_ip, iport, protocol, desc, leaseduration, r_host); | action, eport, int_ip, iport, protocol, desc, leaseduration, |
| | r_host ? r_host : "NULL"); |
| |
|
| r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration); |
r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration); |
| |
|
|
Line 480 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
Line 486 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
| if(leaseduration == 0) |
if(leaseduration == 0) |
| leaseduration = 604800; |
leaseduration = 604800; |
| |
|
| eport = (unsigned short)atoi(ext_port); | if (!int_ip || !ext_port || !int_port) |
| iport = (unsigned short)atoi(int_port); | |
| |
| if (!int_ip) | |
| { |
{ |
| ClearNameValueList(&data); |
ClearNameValueList(&data); |
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
| return; |
return; |
| } |
} |
| |
|
| |
eport = (unsigned short)atoi(ext_port); |
| |
iport = (unsigned short)atoi(int_port); |
| #ifndef SUPPORT_REMOTEHOST |
#ifndef SUPPORT_REMOTEHOST |
| #ifdef UPNP_STRICT |
#ifdef UPNP_STRICT |
| if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*"))) |
if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*"))) |
|
Line 501 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
Line 507 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
| #endif |
#endif |
| |
|
| /* if ip not valid assume hostname and convert */ |
/* if ip not valid assume hostname and convert */ |
| if (inet_pton(AF_INET, int_ip, &result_ip) <= 0) | if (inet_pton(AF_INET, int_ip, &result_ip) <= 0) |
| { |
{ |
| hp = gethostbyname(int_ip); |
hp = gethostbyname(int_ip); |
| if(hp && hp->h_addrtype == AF_INET) | if(hp && hp->h_addrtype == AF_INET) |
| { | { |
| for(ptr = hp->h_addr_list; ptr && *ptr; ptr++) |
for(ptr = hp->h_addr_list; ptr && *ptr; ptr++) |
| { |
{ |
| int_ip = inet_ntoa(*((struct in_addr *) *ptr)); |
int_ip = inet_ntoa(*((struct in_addr *) *ptr)); |
|
Line 513 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
Line 519 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
| /* TODO : deal with more than one ip per hostname */ |
/* TODO : deal with more than one ip per hostname */ |
| break; |
break; |
| } |
} |
| } | } |
| else | else |
| { |
{ |
| syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip); | syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip); |
| ClearNameValueList(&data); |
ClearNameValueList(&data); |
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
| return; |
return; |
| } | } |
| } |
} |
| |
|
| /* check if NewInternalAddress is the client address */ |
/* check if NewInternalAddress is the client address */ |
|
Line 536 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
Line 542 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
| } |
} |
| } |
} |
| |
|
| /* TODO : accept a different external port | /* TODO : accept a different external port |
| * have some smart strategy to choose the port */ |
* have some smart strategy to choose the port */ |
| for(;;) { |
for(;;) { |
| r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration); |
r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration); |
|
Line 597 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
Line 603 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
| ext_port = GetValueFromNameValueList(&data, "NewExternalPort"); |
ext_port = GetValueFromNameValueList(&data, "NewExternalPort"); |
| protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
| |
|
| |
#ifdef UPNP_STRICT |
| |
if(!ext_port || !protocol || !r_host) |
| |
#else |
| if(!ext_port || !protocol) |
if(!ext_port || !protocol) |
| |
#endif |
| { |
{ |
| ClearNameValueList(&data); |
ClearNameValueList(&data); |
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
|
Line 627 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
Line 637 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
| &leaseduration); |
&leaseduration); |
| |
|
| if(r < 0) |
if(r < 0) |
| { | { |
| SoapError(h, 714, "NoSuchEntryInArray"); |
SoapError(h, 714, "NoSuchEntryInArray"); |
| } |
} |
| else |
else |
| { |
{ |
| syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s'", |
syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s'", |
| action, |
action, |
| r_host, ext_port, protocol, int_ip, (unsigned int)iport, desc); | r_host ? r_host : "NULL", ext_port, protocol, int_ip, |
| | (unsigned int)iport, desc); |
| bodylen = snprintf(body, sizeof(body), resp, |
bodylen = snprintf(body, sizeof(body), resp, |
| action, SERVICE_TYPE_WANIPC, |
action, SERVICE_TYPE_WANIPC, |
| (unsigned int)iport, int_ip, desc, leaseduration, |
(unsigned int)iport, int_ip, desc, leaseduration, |
|
Line 664 DeletePortMapping(struct upnphttp * h, const char * ac
|
Line 675 DeletePortMapping(struct upnphttp * h, const char * ac
|
| ext_port = GetValueFromNameValueList(&data, "NewExternalPort"); |
ext_port = GetValueFromNameValueList(&data, "NewExternalPort"); |
| protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
| |
|
| |
#ifdef UPNP_STRICT |
| |
if(!ext_port || !protocol || !r_host) |
| |
#else |
| if(!ext_port || !protocol) |
if(!ext_port || !protocol) |
| |
#endif |
| { |
{ |
| ClearNameValueList(&data); |
ClearNameValueList(&data); |
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
|
Line 688 DeletePortMapping(struct upnphttp * h, const char * ac
|
Line 703 DeletePortMapping(struct upnphttp * h, const char * ac
|
| * just an annoyance for the user using it. So this is not |
* just an annoyance for the user using it. So this is not |
| * a priority. */ |
* a priority. */ |
| |
|
| syslog(LOG_INFO, "%s: external port: %hu, protocol: %s", | syslog(LOG_INFO, "%s: external port: %hu, protocol: %s", |
| action, eport, protocol); |
action, eport, protocol); |
| |
|
| r = upnp_delete_redirection(eport, protocol); |
r = upnp_delete_redirection(eport, protocol); |
| |
|
| if(r < 0) |
if(r < 0) |
| { | { |
| SoapError(h, 714, "NoSuchEntryInArray"); |
SoapError(h, 714, "NoSuchEntryInArray"); |
| } |
} |
| else |
else |
|
Line 716 DeletePortMappingRange(struct upnphttp * h, const char
|
Line 731 DeletePortMappingRange(struct upnphttp * h, const char
|
| "</u:DeletePortMappingRangeResponse>"; |
"</u:DeletePortMappingRangeResponse>"; |
| struct NameValueParserData data; |
struct NameValueParserData data; |
| const char * protocol; |
const char * protocol; |
| |
const char * startport_s, * endport_s; |
| unsigned short startport, endport; |
unsigned short startport, endport; |
| int manage; | /*int manage;*/ |
| unsigned short * port_list; |
unsigned short * port_list; |
| unsigned int i, number = 0; |
unsigned int i, number = 0; |
| |
UNUSED(action); |
| |
|
| ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
| startport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort")); | startport_s = GetValueFromNameValueList(&data, "NewStartPort"); |
| endport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewEndPort")); | endport_s = GetValueFromNameValueList(&data, "NewEndPort"); |
| protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
| manage = atoi(GetValueFromNameValueList(&data, "NewManage")); | /*manage = atoi(GetValueFromNameValueList(&data, "NewManage"));*/ |
| | if(startport_s == NULL || endport_s == NULL || protocol == NULL) { |
| | SoapError(h, 402, "Invalid Args"); |
| | ClearNameValueList(&data); |
| | return; |
| | } |
| | startport = (unsigned short)atoi(startport_s); |
| | endport = (unsigned short)atoi(endport_s); |
| |
|
| /* possible errors : |
/* possible errors : |
| 606 - Action not authorized |
606 - Action not authorized |
|
Line 756 static void
|
Line 780 static void
|
| GetGenericPortMappingEntry(struct upnphttp * h, const char * action) |
GetGenericPortMappingEntry(struct upnphttp * h, const char * action) |
| { |
{ |
| int r; |
int r; |
| | |
| static const char resp[] = |
static const char resp[] = |
| "<u:%sResponse " |
"<u:%sResponse " |
| "xmlns:u=\"%s\">" |
"xmlns:u=\"%s\">" |
|
Line 787 GetGenericPortMappingEntry(struct upnphttp * h, const
|
Line 811 GetGenericPortMappingEntry(struct upnphttp * h, const
|
| ClearNameValueList(&data); |
ClearNameValueList(&data); |
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
| return; |
return; |
| } | } |
| |
|
| index = (int)atoi(m_index); |
index = (int)atoi(m_index); |
| |
|
|
Line 862 GetListOfPortMappings(struct upnphttp * h, const char
|
Line 886 GetListOfPortMappings(struct upnphttp * h, const char
|
| unsigned int leaseduration = 0; |
unsigned int leaseduration = 0; |
| |
|
| struct NameValueParserData data; |
struct NameValueParserData data; |
| |
const char * startport_s, * endport_s; |
| unsigned short startport, endport; |
unsigned short startport, endport; |
| const char * protocol; |
const char * protocol; |
| int manage; | /*int manage;*/ |
| | const char * number_s; |
| int number; |
int number; |
| unsigned short * port_list; |
unsigned short * port_list; |
| unsigned int i, list_size = 0; |
unsigned int i, list_size = 0; |
| |
|
| ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
| startport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort")); | startport_s = GetValueFromNameValueList(&data, "NewStartPort"); |
| endport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewEndPort")); | endport_s = GetValueFromNameValueList(&data, "NewEndPort"); |
| protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
| manage = atoi(GetValueFromNameValueList(&data, "NewManage")); | /*manage_s = GetValueFromNameValueList(&data, "NewManage");*/ |
| number = atoi(GetValueFromNameValueList(&data, "NewNumberOfPorts")); | number_s = GetValueFromNameValueList(&data, "NewNumberOfPorts"); |
| | if(startport_s == NULL || endport_s == NULL || protocol == NULL || |
| | number_s == NULL) { |
| | SoapError(h, 402, "Invalid Args"); |
| | ClearNameValueList(&data); |
| | return; |
| | } |
| | |
| | startport = (unsigned short)atoi(startport_s); |
| | endport = (unsigned short)atoi(endport_s); |
| | /*manage = atoi(manage_s);*/ |
| | number = atoi(number_s); |
| if(number == 0) number = 1000; /* return up to 1000 mappings by default */ |
if(number == 0) number = 1000; /* return up to 1000 mappings by default */ |
| |
|
| if(startport > endport) |
if(startport > endport) |
|
Line 912 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd"
|
Line 949 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd"
|
| } |
} |
| bodylen = snprintf(body, bodyalloc, resp_start, |
bodylen = snprintf(body, bodyalloc, resp_start, |
| action, SERVICE_TYPE_WANIPC); |
action, SERVICE_TYPE_WANIPC); |
| |
if(bodylen < 0) |
| |
{ |
| |
SoapError(h, 501, "ActionFailed"); |
| |
free(body); |
| |
return; |
| |
} |
| memcpy(body+bodylen, list_start, sizeof(list_start)); |
memcpy(body+bodylen, list_start, sizeof(list_start)); |
| bodylen += (sizeof(list_start) - 1); |
bodylen += (sizeof(list_start) - 1); |
| |
|
|
Line 921 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd"
|
Line 964 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd"
|
| for(i = 0; number > 0 && i < list_size; i++) |
for(i = 0; number > 0 && i < list_size; i++) |
| { |
{ |
| /* have a margin of 1024 bytes to store the new entry */ |
/* have a margin of 1024 bytes to store the new entry */ |
| if(bodylen + 1024 > bodyalloc) | if((unsigned int)bodylen + 1024 > bodyalloc) |
| { |
{ |
| |
char * body_sav = body; |
| bodyalloc += 4096; |
bodyalloc += 4096; |
| body = realloc(body, bodyalloc); |
body = realloc(body, bodyalloc); |
| if(!body) |
if(!body) |
| { |
{ |
| ClearNameValueList(&data); |
ClearNameValueList(&data); |
| SoapError(h, 501, "ActionFailed"); |
SoapError(h, 501, "ActionFailed"); |
| |
free(body_sav); |
| free(port_list); |
free(port_list); |
| return; |
return; |
| } |
} |
|
Line 973 SetDefaultConnectionService(struct upnphttp * h, const
|
Line 1018 SetDefaultConnectionService(struct upnphttp * h, const
|
| ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
| p = GetValueFromNameValueList(&data, "NewDefaultConnectionService"); |
p = GetValueFromNameValueList(&data, "NewDefaultConnectionService"); |
| if(p) { |
if(p) { |
| syslog(LOG_INFO, "%s(%s) : Ignored", action, p); | /* 720 InvalidDeviceUUID |
| | * 721 InvalidServiceID |
| | * 723 InvalidConnServiceSelection */ |
| | #ifdef UPNP_STRICT |
| | if(0 != memcmp(uuidvalue, p, sizeof("uuid:00000000-0000-0000-0000-000000000000") - 1)) { |
| | SoapError(h, 720, "InvalidDeviceUUID"); |
| | } else |
| | #endif |
| | { |
| | syslog(LOG_INFO, "%s(%s) : Ignored", action, p); |
| | BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); |
| | } |
| | } else { |
| | /* missing argument */ |
| | SoapError(h, 402, "Invalid Args"); |
| } |
} |
| ClearNameValueList(&data); |
ClearNameValueList(&data); |
| BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); |
|
| } |
} |
| |
|
| static void |
static void |
|
Line 1006 SetConnectionType(struct upnphttp * h, const char * ac
|
Line 1064 SetConnectionType(struct upnphttp * h, const char * ac
|
| { |
{ |
| const char * connection_type; |
const char * connection_type; |
| struct NameValueParserData data; |
struct NameValueParserData data; |
| |
UNUSED(action); |
| |
|
| ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
| connection_type = GetValueFromNameValueList(&data, "NewConnectionType"); |
connection_type = GetValueFromNameValueList(&data, "NewConnectionType"); |
| |
#ifdef UPNP_STRICT |
| |
if(!connection_type) { |
| |
ClearNameValueList(&data); |
| |
SoapError(h, 402, "Invalid Args"); |
| |
return; |
| |
} |
| |
#endif |
| /* Unconfigured, IP_Routed, IP_Bridged */ |
/* Unconfigured, IP_Routed, IP_Bridged */ |
| ClearNameValueList(&data); |
ClearNameValueList(&data); |
| /* always return a ReadOnly error */ |
/* always return a ReadOnly error */ |
|
Line 1019 SetConnectionType(struct upnphttp * h, const char * ac
|
Line 1085 SetConnectionType(struct upnphttp * h, const char * ac
|
| static void |
static void |
| RequestConnection(struct upnphttp * h, const char * action) |
RequestConnection(struct upnphttp * h, const char * action) |
| { |
{ |
| |
UNUSED(action); |
| SoapError(h, 606, "Action not authorized"); |
SoapError(h, 606, "Action not authorized"); |
| } |
} |
| |
|
|
Line 1026 RequestConnection(struct upnphttp * h, const char * ac
|
Line 1093 RequestConnection(struct upnphttp * h, const char * ac
|
| static void |
static void |
| ForceTermination(struct upnphttp * h, const char * action) |
ForceTermination(struct upnphttp * h, const char * action) |
| { |
{ |
| |
UNUSED(action); |
| SoapError(h, 606, "Action not authorized"); |
SoapError(h, 606, "Action not authorized"); |
| } |
} |
| |
|
|
Line 1063 QueryStateVariable(struct upnphttp * h, const char * a
|
Line 1131 QueryStateVariable(struct upnphttp * h, const char * a
|
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
| } |
} |
| else if(strcmp(var_name, "ConnectionStatus") == 0) |
else if(strcmp(var_name, "ConnectionStatus") == 0) |
| { | { |
| const char * status; |
const char * status; |
| |
|
| status = get_wan_connection_status_str(ext_if_name); |
status = get_wan_connection_status_str(ext_if_name); |
|
Line 1075 QueryStateVariable(struct upnphttp * h, const char * a
|
Line 1143 QueryStateVariable(struct upnphttp * h, const char * a
|
| #if 0 |
#if 0 |
| /* not usefull */ |
/* not usefull */ |
| else if(strcmp(var_name, "ConnectionType") == 0) |
else if(strcmp(var_name, "ConnectionType") == 0) |
| { | { |
| bodylen = snprintf(body, sizeof(body), resp, "IP_Routed"); |
bodylen = snprintf(body, sizeof(body), resp, "IP_Routed"); |
| BuildSendAndCloseSoapResp(h, body, bodylen); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
| } |
} |
| else if(strcmp(var_name, "LastConnectionError") == 0) |
else if(strcmp(var_name, "LastConnectionError") == 0) |
| { | { |
| bodylen = snprintf(body, sizeof(body), resp, "ERROR_NONE"); |
bodylen = snprintf(body, sizeof(body), resp, "ERROR_NONE"); |
| BuildSendAndCloseSoapResp(h, body, bodylen); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
| } |
} |
|
Line 1101 QueryStateVariable(struct upnphttp * h, const char * a
|
Line 1169 QueryStateVariable(struct upnphttp * h, const char * a
|
| SoapError(h, 404, "Invalid Var"); |
SoapError(h, 404, "Invalid Var"); |
| } |
} |
| |
|
| ClearNameValueList(&data); | ClearNameValueList(&data); |
| } |
} |
| |
|
| #ifdef ENABLE_6FC_SERVICE |
#ifdef ENABLE_6FC_SERVICE |
|
Line 1133 CheckStatus(struct upnphttp * h)
|
Line 1201 CheckStatus(struct upnphttp * h)
|
| { |
{ |
| if (!ipv6fc_firewall_enabled) |
if (!ipv6fc_firewall_enabled) |
| { |
{ |
| SoapError(h, 702, "FirewallDisabed"); | SoapError(h, 702, "FirewallDisabled"); |
| return 0; |
return 0; |
| } |
} |
| else if(!ipv6fc_inbound_pinhole_allowed) |
else if(!ipv6fc_inbound_pinhole_allowed) |
|
Line 1145 CheckStatus(struct upnphttp * h)
|
Line 1213 CheckStatus(struct upnphttp * h)
|
| return 1; |
return 1; |
| } |
} |
| |
|
| static int |
|
| DataVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port, const char * protocol, char * leaseTime) |
|
| { |
|
| //int n; |
|
| // ** Internal IP can't be wildcarded |
|
| if (!int_ip) |
|
| { |
|
| SoapError(h, 708, "WildCardNotPermittedInSrcIP"); |
|
| return 0; |
|
| } |
|
| |
|
| if (!strchr(int_ip, ':')) |
|
| { |
|
| SoapError(h, 402, "Invalid Args"); |
|
| return 0; |
|
| } |
|
| |
|
| // ** Internal port can't be wilcarded. |
|
| // printf("\tint_port: *%d*\n", *int_port); |
|
| if (*int_port == 0) |
|
| { |
|
| SoapError(h, 706, "InternalPortWilcardingNotAllowed"); |
|
| return 0; |
|
| } |
|
| |
|
| // ** Protocol can't be wilcarded and can't be an unknown port (here deal with only UDP, TCP, UDPLITE) |
|
| // printf("\tprotocol: *%s*\n", protocol); |
|
| if (atoi(protocol) == 65535) |
|
| { |
|
| SoapError(h, 707, "ProtocolWilcardingNotAllowed"); |
|
| return 0; |
|
| } |
|
| else if (atoi(protocol) != IPPROTO_UDP |
|
| && atoi(protocol) != IPPROTO_TCP |
|
| #ifdef IPPROTO_UDPITE |
|
| && atoi(protocol) != IPPROTO_UDPLITE |
|
| #endif |
|
| ) |
|
| { |
|
| SoapError(h, 705, "ProtocolNotSupported"); |
|
| return 0; |
|
| } |
|
| |
|
| // ** Lease Time can't be wilcarded nor >86400. |
|
| // printf("\tlease time: %s\n", leaseTime); |
|
| if(!leaseTime || !atoi(leaseTime) || atoi(leaseTime)>86400) |
|
| { |
|
| /* lease duration is never infinite, nor wilcarded. In this case, use default value */ |
|
| syslog(LOG_WARNING, "LeaseTime=%s not supported, (ip=%s)", leaseTime, int_ip); |
|
| SoapError(h, 402, "Invalid Args"); |
|
| return 0; |
|
| } |
|
| |
|
| return 1; |
|
| } |
|
| |
|
| #if 0 |
#if 0 |
| static int connecthostport(const char * host, unsigned short port, char * result) |
static int connecthostport(const char * host, unsigned short port, char * result) |
| { |
{ |
|
Line 1257 static int connecthostport(const char * host, unsigned
|
Line 1269 static int connecthostport(const char * host, unsigned
|
| |
|
| /* Check the security policy right */ |
/* Check the security policy right */ |
| static int |
static int |
| PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port) | PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short int_port) |
| { |
{ |
| int n; |
int n; |
| /* Pinhole InternalClient address must correspond to the action sender */ |
|
| syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)"); |
|
| char senderAddr[INET6_ADDRSTRLEN]=""; |
char senderAddr[INET6_ADDRSTRLEN]=""; |
| //char str[INET6_ADDRSTRLEN]=""; |
|
| //connecthostport(int_ip, *int_port, str); |
|
| //printf("int_ip: %s / str: %s\n", int_ip, str); |
|
| |
|
| struct addrinfo hints, *ai, *p; |
struct addrinfo hints, *ai, *p; |
| struct in6_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */ //IPv6 Modification | struct in6_addr result_ip; |
| |
|
| |
/* Pinhole InternalClient address must correspond to the action sender */ |
| |
syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)"); |
| |
|
| hints.ai_socktype = SOCK_STREAM; |
hints.ai_socktype = SOCK_STREAM; |
| hints.ai_family = AF_UNSPEC; |
hints.ai_family = AF_UNSPEC; |
| |
|
| /* if ip not valid assume hostname and convert */ |
/* if ip not valid assume hostname and convert */ |
| if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0) //IPv6 Modification | if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0) |
| { |
{ |
| n = getaddrinfo(int_ip, NULL, &hints, &ai); |
| n = getaddrinfo(int_ip, NULL, &hints, &ai);//hp = gethostbyname(int_ip); | if(!n && ai->ai_family == AF_INET6) |
| if(!n && ai->ai_family == AF_INET6) //IPv6 Modification | |
| { |
{ |
| for(p = ai; p; p = p->ai_next)//ptr = hp->h_addr_list; ptr && *ptr; ptr++) | for(p = ai; p; p = p->ai_next) |
| { | { |
| inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); ///IPv6 Modification | inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); |
| result_ip = *((struct in6_addr *) p); |
result_ip = *((struct in6_addr *) p); |
| fprintf(stderr, "upnpsoap / AddPinhole: assuming int addr = %s", int_ip); |
|
| /* TODO : deal with more than one ip per hostname */ |
/* TODO : deal with more than one ip per hostname */ |
| break; |
break; |
| } |
} |
|
Line 1298 PinholeVerification(struct upnphttp * h, char * int_ip
|
Line 1305 PinholeVerification(struct upnphttp * h, char * int_ip
|
| freeaddrinfo(p); |
freeaddrinfo(p); |
| } |
} |
| |
|
| if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN)<=0) | if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN) == NULL) |
| { |
{ |
| //printf("Failed to inet_ntop\n"); |
|
| syslog(LOG_ERR, "inet_ntop: %m"); |
syslog(LOG_ERR, "inet_ntop: %m"); |
| } |
} |
| #ifdef DEBUG |
#ifdef DEBUG |
|
Line 1316 PinholeVerification(struct upnphttp * h, char * int_ip
|
Line 1322 PinholeVerification(struct upnphttp * h, char * int_ip
|
| } |
} |
| |
|
| /* Pinhole InternalPort must be greater than or equal to 1024 */ |
/* Pinhole InternalPort must be greater than or equal to 1024 */ |
| if (*int_port < 1024) | if (int_port < 1024) |
| { |
{ |
| syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it", |
syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it", |
| senderAddr); |
senderAddr); |
|
Line 1341 AddPinhole(struct upnphttp * h, const char * action)
|
Line 1347 AddPinhole(struct upnphttp * h, const char * action)
|
| char * rem_host, * rem_port, * int_ip, * int_port, * protocol, * leaseTime; |
char * rem_host, * rem_port, * int_ip, * int_port, * protocol, * leaseTime; |
| int uid = 0; |
int uid = 0; |
| unsigned short iport, rport; |
unsigned short iport, rport; |
| |
int ltime; |
| |
long proto; |
| |
char rem_ip[INET6_ADDRSTRLEN]; |
| |
|
| if(CheckStatus(h)==0) |
if(CheckStatus(h)==0) |
| return; |
return; |
|
Line 1353 AddPinhole(struct upnphttp * h, const char * action)
|
Line 1362 AddPinhole(struct upnphttp * h, const char * action)
|
| protocol = GetValueFromNameValueList(&data, "Protocol"); |
protocol = GetValueFromNameValueList(&data, "Protocol"); |
| leaseTime = GetValueFromNameValueList(&data, "LeaseTime"); |
leaseTime = GetValueFromNameValueList(&data, "LeaseTime"); |
| |
|
| rport = (unsigned short)atoi(rem_port); | rport = (unsigned short)(rem_port ? atoi(rem_port) : 0); |
| iport = (unsigned short)atoi(int_port); | iport = (unsigned short)(int_port ? atoi(int_port) : 0); |
| | ltime = leaseTime ? atoi(leaseTime) : -1; |
| | errno = 0; |
| | proto = protocol ? strtol(protocol, NULL, 0) : -1; |
| | if(errno != 0 || proto > 65535 || proto < 0) |
| | { |
| | SoapError(h, 402, "Invalid Args"); |
| | goto clear_and_exit; |
| | } |
| | if(iport == 0) |
| | { |
| | SoapError(h, 706, "InternalPortWilcardingNotAllowed"); |
| | goto clear_and_exit; |
| | } |
| |
|
| // ** As there is no security policy, InternalClient must be equal to the CP's IP address. | /* In particular, [IGD2] RECOMMENDS that unauthenticated and |
| if(DataVerification(h, int_ip, &iport, protocol, leaseTime) == 0 | * unauthorized control points are only allowed to invoke |
| || PinholeVerification(h, int_ip, &iport) <= 0) | * this action with: |
| | * - InternalPort value greater than or equal to 1024, |
| | * - InternalClient value equals to the control point's IP address. |
| | * It is REQUIRED that InternalClient cannot be one of IPv6 |
| | * addresses used by the gateway. */ |
| | if(!int_ip || 0 == strlen(int_ip) || 0 == strcmp(int_ip, "*")) |
| { |
{ |
| ClearNameValueList(&data); | SoapError(h, 708, "WildCardNotPermittedInSrcIP"); |
| return ; | goto clear_and_exit; |
| } |
} |
| |
/* I guess it is useless to convert int_ip to literal ipv6 address */ |
| |
/* rem_host should be converted to literal ipv6 : */ |
| |
if(rem_host) |
| |
{ |
| |
struct addrinfo *ai, *p; |
| |
struct addrinfo hints; |
| |
int err; |
| |
memset(&hints, 0, sizeof(struct addrinfo)); |
| |
hints.ai_family = AF_INET6; |
| |
/*hints.ai_flags = */ |
| |
/* hints.ai_protocol = proto; */ |
| |
err = getaddrinfo(rem_host, rem_port, &hints, &ai); |
| |
if(err == 0) |
| |
{ |
| |
/* take the 1st IPv6 address */ |
| |
for(p = ai; p; p = p->ai_next) |
| |
{ |
| |
if(p->ai_family == AF_INET6) |
| |
{ |
| |
inet_ntop(AF_INET6, |
| |
&(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr), |
| |
rem_ip, sizeof(rem_ip)); |
| |
syslog(LOG_INFO, "resolved '%s' to '%s'", rem_host, rem_ip); |
| |
rem_host = rem_ip; |
| |
break; |
| |
} |
| |
} |
| |
freeaddrinfo(ai); |
| |
} |
| |
else |
| |
{ |
| |
syslog(LOG_WARNING, "AddPinhole : getaddrinfo(%s) : %s", |
| |
rem_host, gai_strerror(err)); |
| |
#if 0 |
| |
SoapError(h, 402, "Invalid Args"); |
| |
goto clear_and_exit; |
| |
#endif |
| |
} |
| |
} |
| |
|
| // ** RemoteHost can be wilcarded or an IDN. | if(proto == 65535) |
| /*printf("\trem_host: %s\n", rem_host);*/ | |
| if (rem_host!=NULL && !strchr(rem_host, ':')) | |
| { |
{ |
| ClearNameValueList(&data); | SoapError(h, 707, "ProtocolWilcardingNotAllowed"); |
| | goto clear_and_exit; |
| | } |
| | if(proto != IPPROTO_UDP && proto != IPPROTO_TCP |
| | #ifdef IPPROTO_UDPITE |
| | && atoi(protocol) != IPPROTO_UDPLITE |
| | #endif |
| | ) |
| | { |
| | SoapError(h, 705, "ProtocolNotSupported"); |
| | goto clear_and_exit; |
| | } |
| | if(ltime < 1 || ltime > 86400) |
| | { |
| | syslog(LOG_WARNING, "%s: LeaseTime=%d not supported, (ip=%s)", |
| | action, ltime, int_ip); |
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
| return; | goto clear_and_exit; |
| } |
} |
| /*printf("\tAddr check passed.\n");*/ |
|
| |
|
| syslog(LOG_INFO, "%s: (inbound) from [%s]:%hu to [%s]:%hu with protocol %s during %ssec", action, rem_host?rem_host:"anywhere", rport, int_ip, iport, protocol, leaseTime); | if(PinholeVerification(h, int_ip, iport) <= 0) |
| | goto clear_and_exit; |
| |
|
| r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, protocol, leaseTime, &uid); | syslog(LOG_INFO, "%s: (inbound) from [%s]:%hu to [%s]:%hu with proto %ld during %d sec", |
| | action, rem_host?rem_host:"any", |
| | rport, int_ip, iport, |
| | proto, ltime); |
| |
|
| |
/* In cases where the RemoteHost, RemotePort, InternalPort, |
| |
* InternalClient and Protocol are the same than an existing pinhole, |
| |
* but LeaseTime is different, the device MUST extend the existing |
| |
* pinhole's lease time and return the UniqueID of the existing pinhole. */ |
| |
r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, proto, ltime, &uid); |
| |
|
| switch(r) |
switch(r) |
| { |
{ |
| case 1: /* success */ |
case 1: /* success */ |
| bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", uid, action); | bodylen = snprintf(body, sizeof(body), |
| | resp, action, |
| | "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", |
| | uid, action); |
| BuildSendAndCloseSoapResp(h, body, bodylen); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
| break; |
break; |
| case -1: /* not permitted */ |
case -1: /* not permitted */ |
|
Line 1391 AddPinhole(struct upnphttp * h, const char * action)
|
Line 1482 AddPinhole(struct upnphttp * h, const char * action)
|
| SoapError(h, 501, "ActionFailed"); |
SoapError(h, 501, "ActionFailed"); |
| break; |
break; |
| } |
} |
| |
/* 606 Action not authorized |
| |
* 701 PinholeSpaceExhausted |
| |
* 702 FirewallDisabled |
| |
* 703 InboundPinholeNotAllowed |
| |
* 705 ProtocolNotSupported |
| |
* 706 InternalPortWildcardingNotAllowed |
| |
* 707 ProtocolWildcardingNotAllowed |
| |
* 708 WildCardNotPermittedInSrcIP */ |
| |
clear_and_exit: |
| ClearNameValueList(&data); |
ClearNameValueList(&data); |
| } |
} |
| |
|
| static void |
static void |
| UpdatePinhole(struct upnphttp * h, const char * action) |
UpdatePinhole(struct upnphttp * h, const char * action) |
| { |
{ |
| int r, n; |
|
| static const char resp[] = |
static const char resp[] = |
| "<u:UpdatePinholeResponse " |
"<u:UpdatePinholeResponse " |
| "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">" |
"xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">" |
| "</u:UpdatePinholeResponse>"; |
"</u:UpdatePinholeResponse>"; |
| struct NameValueParserData data; |
struct NameValueParserData data; |
| const char * uid, * leaseTime; | const char * uid_str, * leaseTime; |
| char iaddr[40], proto[6], lt[12]; | char iaddr[INET6_ADDRSTRLEN]; |
| unsigned short iport; |
unsigned short iport; |
| |
int ltime; |
| |
int uid; |
| |
int n; |
| |
|
| if(CheckStatus(h)==0) |
if(CheckStatus(h)==0) |
| return; |
return; |
| |
|
| ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
| uid = GetValueFromNameValueList(&data, "UniqueID"); | uid_str = GetValueFromNameValueList(&data, "UniqueID"); |
| leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime"); |
leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime"); |
| |
uid = uid_str ? atoi(uid_str) : -1; |
| |
ltime = leaseTime ? atoi(leaseTime) : -1; |
| |
ClearNameValueList(&data); |
| |
|
| if(!uid || !leaseTime || !atoi(leaseTime) || atoi(leaseTime) > 86400) | if(uid < 0 || uid > 65535 || ltime <= 0 || ltime > 86400) |
| { |
{ |
| ClearNameValueList(&data); |
|
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
| return; |
return; |
| } |
} |
| |
|
| // Check that client is not deleting an pinhole he doesn't have access to, because of its public access | /* Check that client is not updating an pinhole |
| n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt); | * it doesn't have access to, because of its public access */ |
| if (n > 0) | n = upnp_get_pinhole_info(uid, NULL, 0, NULL, |
| | iaddr, sizeof(iaddr), &iport, |
| | NULL, NULL, NULL); |
| | if (n >= 0) |
| { |
{ |
| if(PinholeVerification(h, iaddr, &iport)==0) | if(PinholeVerification(h, iaddr, iport) <= 0) |
| { | return; |
| ClearNameValueList(&data); | |
| return ; | |
| } | |
| } |
} |
| else if(n == -2) |
| syslog(LOG_INFO, "%s: (inbound) updating lease duration to %s for pinhole with ID: %s", action, leaseTime, uid); | |
| |
| r = upnp_update_inboundpinhole(uid, leaseTime); | |
| |
| if(r < 0) | |
| { |
{ |
| if(r == -4 || r == -1) | SoapError(h, 704, "NoSuchEntry"); |
| SoapError(h, 704, "NoSuchEntry"); | return; |
| else | |
| SoapError(h, 501, "ActionFailed"); | |
| } |
} |
| else |
else |
| { |
{ |
| BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); | SoapError(h, 501, "ActionFailed"); |
| | return; |
| } |
} |
| ClearNameValueList(&data); | |
| | syslog(LOG_INFO, "%s: (inbound) updating lease duration to %d for pinhole with ID: %d", |
| | action, ltime, uid); |
| | |
| | n = upnp_update_inboundpinhole(uid, ltime); |
| | if(n == -1) |
| | SoapError(h, 704, "NoSuchEntry"); |
| | else if(n < 0) |
| | SoapError(h, 501, "ActionFailed"); |
| | else |
| | BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); |
| } |
} |
| |
|
| static void |
static void |
| GetOutboundPinholeTimeout(struct upnphttp * h, const char * action) |
GetOutboundPinholeTimeout(struct upnphttp * h, const char * action) |
| { |
{ |
| if (!ipv6fc_firewall_enabled) |
|
| { |
|
| SoapError(h, 702, "FirewallDisabed"); |
|
| return; |
|
| } |
|
| int r; |
int r; |
| |
|
| static const char resp[] = |
static const char resp[] = |
|
Line 1473 GetOutboundPinholeTimeout(struct upnphttp * h, const c
|
Line 1576 GetOutboundPinholeTimeout(struct upnphttp * h, const c
|
| int opt=0, proto=0; |
int opt=0, proto=0; |
| unsigned short iport, rport; |
unsigned short iport, rport; |
| |
|
| |
if (!ipv6fc_firewall_enabled) |
| |
{ |
| |
SoapError(h, 702, "FirewallDisabled"); |
| |
return; |
| |
} |
| |
|
| ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
| int_ip = GetValueFromNameValueList(&data, "InternalClient"); |
int_ip = GetValueFromNameValueList(&data, "InternalClient"); |
| int_port = GetValueFromNameValueList(&data, "InternalPort"); |
int_port = GetValueFromNameValueList(&data, "InternalPort"); |
|
Line 1486 GetOutboundPinholeTimeout(struct upnphttp * h, const c
|
Line 1595 GetOutboundPinholeTimeout(struct upnphttp * h, const c
|
| |
|
| syslog(LOG_INFO, "%s: retrieving timeout for outbound pinhole from [%s]:%hu to [%s]:%hu protocol %s", action, int_ip, iport,rem_host, rport, protocol); |
syslog(LOG_INFO, "%s: retrieving timeout for outbound pinhole from [%s]:%hu to [%s]:%hu protocol %s", action, int_ip, iport,rem_host, rport, protocol); |
| |
|
| r = upnp_check_outbound_pinhole(proto, &opt); | /* TODO */ |
| | r = -1;/*upnp_check_outbound_pinhole(proto, &opt);*/ |
| |
|
| switch(r) |
switch(r) |
| { |
{ |
| case 1: /* success */ |
case 1: /* success */ |
| bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", opt, action); | bodylen = snprintf(body, sizeof(body), resp, |
| | action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", |
| | opt, action); |
| BuildSendAndCloseSoapResp(h, body, bodylen); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
| break; |
break; |
| case -5: /* Protocol not supported */ |
case -5: /* Protocol not supported */ |
|
Line 1506 GetOutboundPinholeTimeout(struct upnphttp * h, const c
|
Line 1618 GetOutboundPinholeTimeout(struct upnphttp * h, const c
|
| static void |
static void |
| DeletePinhole(struct upnphttp * h, const char * action) |
DeletePinhole(struct upnphttp * h, const char * action) |
| { |
{ |
| if(CheckStatus(h)==0) | int n; |
| return; | |
| int r, n; | |
| |
|
| static const char resp[] = |
static const char resp[] = |
| "<u:DeletePinholeResponse " |
"<u:DeletePinholeResponse " |
|
Line 1516 DeletePinhole(struct upnphttp * h, const char * action
|
Line 1626 DeletePinhole(struct upnphttp * h, const char * action
|
| "</u:DeletePinholeResponse>"; |
"</u:DeletePinholeResponse>"; |
| |
|
| struct NameValueParserData data; |
struct NameValueParserData data; |
| const char * uid; | const char * uid_str; |
| char iaddr[40], proto[6], lt[12]; | char iaddr[INET6_ADDRSTRLEN]; |
| | int proto; |
| unsigned short iport; |
unsigned short iport; |
| |
unsigned int leasetime; |
| |
int uid; |
| |
|
| |
if(CheckStatus(h)==0) |
| |
return; |
| |
|
| ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
| uid = GetValueFromNameValueList(&data, "UniqueID"); | uid_str = GetValueFromNameValueList(&data, "UniqueID"); |
| | uid = uid_str ? atoi(uid_str) : -1; |
| | ClearNameValueList(&data); |
| |
|
| if(!uid) | if(uid < 0 || uid > 65535) |
| { |
{ |
| ClearNameValueList(&data); |
|
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
| return; |
return; |
| } |
} |
| |
|
| // Check that client is not deleting an pinhole he doesn't have access to, because of its public access | /* Check that client is not deleting an pinhole |
| n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt); | * it doesn't have access to, because of its public access */ |
| if (n > 0) | n = upnp_get_pinhole_info(uid, NULL, 0, NULL, |
| | iaddr, sizeof(iaddr), &iport, |
| | &proto, &leasetime, NULL); |
| | if (n >= 0) |
| { |
{ |
| if(PinholeVerification(h, iaddr, &iport)==0) | if(PinholeVerification(h, iaddr, iport) <= 0) |
| { | return; |
| ClearNameValueList(&data); | |
| return ; | |
| } | |
| } |
} |
| else if(n == -2) |
| syslog(LOG_INFO, "%s: (inbound) delete pinhole with ID: %s", action, uid); | |
| |
| r = upnp_delete_inboundpinhole(uid); | |
| |
| if(r <= 0) | |
| { |
{ |
| syslog(LOG_INFO, "%s: (inbound) failed to remove pinhole with ID: %s", action, uid); | SoapError(h, 704, "NoSuchEntry"); |
| if(r==-4) | return; |
| SoapError(h, 704, "NoSuchEntry"); | |
| else | |
| SoapError(h, 501, "ActionFailed"); | |
| } |
} |
| else |
else |
| { |
{ |
| syslog(LOG_INFO, "%s: (inbound) pinhole successfully removed", action); | SoapError(h, 501, "ActionFailed"); |
| BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); | return; |
| } |
} |
| ClearNameValueList(&data); | |
| | n = upnp_delete_inboundpinhole(uid); |
| | if(n < 0) |
| | { |
| | syslog(LOG_INFO, "%s: (inbound) failed to remove pinhole with ID: %d", |
| | action, uid); |
| | SoapError(h, 501, "ActionFailed"); |
| | return; |
| | } |
| | syslog(LOG_INFO, "%s: (inbound) pinhole with ID %d successfully removed", |
| | action, uid); |
| | BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); |
| } |
} |
| |
|
| static void |
static void |
| CheckPinholeWorking(struct upnphttp * h, const char * action) |
CheckPinholeWorking(struct upnphttp * h, const char * action) |
| { |
{ |
| if(CheckStatus(h)==0) |
|
| return; |
|
| int r, d; |
|
| |
|
| static const char resp[] = |
static const char resp[] = |
| "<u:%sResponse " |
"<u:%sResponse " |
| "xmlns:u=\"%s\">" |
"xmlns:u=\"%s\">" |
| "<IsWorking>%d</IsWorking>" |
"<IsWorking>%d</IsWorking>" |
| "</u:%sResponse>"; |
"</u:%sResponse>"; |
| |
|
| char body[512]; |
char body[512]; |
| int bodylen; |
int bodylen; |
| |
int r; |
| struct NameValueParserData data; |
struct NameValueParserData data; |
| const char * uid; | const char * uid_str; |
| char eaddr[40], iaddr[40], proto[6], lt[12]; | int uid; |
| unsigned short eport, iport; | char iaddr[INET6_ADDRSTRLEN]; |
| int isWorking = 0; | unsigned short iport; |
| | unsigned int packets; |
| |
|
| |
if(CheckStatus(h)==0) |
| |
return; |
| |
|
| ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
| uid = GetValueFromNameValueList(&data, "UniqueID"); | uid_str = GetValueFromNameValueList(&data, "UniqueID"); |
| | uid = uid_str ? atoi(uid_str) : -1; |
| | ClearNameValueList(&data); |
| |
|
| if(!uid) | if(uid < 0 || uid > 65535) |
| { |
{ |
| ClearNameValueList(&data); |
|
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
| return; |
return; |
| } |
} |
| |
|
| // Check that client is not checking a pinhole he doesn't have access to, because of its public access | /* Check that client is not checking a pinhole |
| r = upnp_get_pinhole_info(eaddr, eport, iaddr, &iport, proto, uid, lt); | * it doesn't have access to, because of its public access */ |
| if (r > 0) | r = upnp_get_pinhole_info(uid, |
| | NULL, 0, NULL, |
| | iaddr, sizeof(iaddr), &iport, |
| | NULL, NULL, &packets); |
| | if (r >= 0) |
| { |
{ |
| if(PinholeVerification(h, iaddr, &iport)==0) | if(PinholeVerification(h, iaddr, iport) <= 0) |
| { | |
| ClearNameValueList(&data); | |
| return ; |
return ; |
| } | if(packets == 0) |
| else | |
| { |
{ |
| int rulenum_used, rulenum = 0; | SoapError(h, 709, "NoPacketSent"); |
| d = upnp_check_pinhole_working(uid, eaddr, iaddr, &eport, &iport, proto, &rulenum_used); | return; |
| if(d < 0) | |
| { | |
| if(d == -4) | |
| { | |
| syslog(LOG_INFO, "%s: rule for ID=%s, no trace found for this pinhole", action, uid); | |
| SoapError(h, 709, "NoPacketSent"); | |
| ClearNameValueList(&data); | |
| return ; | |
| } | |
| else | |
| { | |
| // d==-5 not same table // d==-6 not same chain // d==-7 not found a rule but policy traced | |
| isWorking=0; | |
| syslog(LOG_INFO, "%s: rule for ID=%s is not working, packet going through %s", action, uid, (d==-5)?"the wrong table":((d==-6)?"the wrong chain":"a chain policy")); | |
| bodylen = snprintf(body, sizeof(body), resp, | |
| action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", | |
| isWorking, action); | |
| BuildSendAndCloseSoapResp(h, body, bodylen); | |
| } | |
| } | |
| else | |
| { | |
| /*check_rule_from_file(uid, &rulenum);*/ | |
| if(rulenum_used == rulenum) | |
| { | |
| isWorking=1; | |
| syslog(LOG_INFO, "%s: rule for ID=%s is working properly", action, uid); | |
| } | |
| else | |
| { | |
| isWorking=0; | |
| syslog(LOG_INFO, "%s: rule for ID=%s is not working", action, uid); | |
| } | |
| bodylen = snprintf(body, sizeof(body), resp, | |
| action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", | |
| isWorking, action); | |
| BuildSendAndCloseSoapResp(h, body, bodylen); | |
| } | |
| } |
} |
| |
bodylen = snprintf(body, sizeof(body), resp, |
| |
action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", |
| |
1, action); |
| |
BuildSendAndCloseSoapResp(h, body, bodylen); |
| } |
} |
| else if(r == -4 || r == -1) | else if(r == -2) |
| { | |
| SoapError(h, 704, "NoSuchEntry"); |
SoapError(h, 704, "NoSuchEntry"); |
| } |
|
| else |
else |
| { |
|
| SoapError(h, 501, "ActionFailed"); |
SoapError(h, 501, "ActionFailed"); |
| ClearNameValueList(&data); |
|
| return ; |
|
| } |
|
| ClearNameValueList(&data); |
|
| } |
} |
| |
|
| static void |
static void |
| GetPinholePackets(struct upnphttp * h, const char * action) |
GetPinholePackets(struct upnphttp * h, const char * action) |
| { |
{ |
| if(CheckStatus(h)==0) |
|
| return; |
|
| int r, n; |
|
| |
|
| static const char resp[] = |
static const char resp[] = |
| "<u:%sResponse " |
"<u:%sResponse " |
| "xmlns:u=\"%s\">" |
"xmlns:u=\"%s\">" |
| "<PinholePackets>%d</PinholePackets>" | "<PinholePackets>%u</PinholePackets>" |
| "</u:%sResponse>"; |
"</u:%sResponse>"; |
| |
|
| char body[512]; |
char body[512]; |
| int bodylen; |
int bodylen; |
| struct NameValueParserData data; |
struct NameValueParserData data; |
| const char * uid; | const char * uid_str; |
| char iaddr[40], proto[6], lt[12]; | int n; |
| | char iaddr[INET6_ADDRSTRLEN]; |
| unsigned short iport; |
unsigned short iport; |
| int pinholePackets = 0; | unsigned int packets = 0; |
| | int uid; |
| | int proto; |
| | unsigned int leasetime; |
| |
|
| |
if(CheckStatus(h)==0) |
| |
return; |
| |
|
| ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
| uid = GetValueFromNameValueList(&data, "UniqueID"); | uid_str = GetValueFromNameValueList(&data, "UniqueID"); |
| | uid = uid_str ? atoi(uid_str) : -1; |
| | ClearNameValueList(&data); |
| |
|
| if(!uid) | if(uid < 0 || uid > 65535) |
| { |
{ |
| ClearNameValueList(&data); |
|
| SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
| return; |
return; |
| } |
} |
| |
|
| // Check that client is not getting infos of a pinhole he doesn't have access to, because of its public access | /* Check that client is not getting infos of a pinhole |
| r = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt); | * it doesn't have access to, because of its public access */ |
| if (r > 0) | n = upnp_get_pinhole_info(uid, NULL, 0, NULL, |
| | iaddr, sizeof(iaddr), &iport, |
| | &proto, &leasetime, &packets); |
| | if (n >= 0) |
| { |
{ |
| if(PinholeVerification(h, iaddr, &iport)==0) | if(PinholeVerification(h, iaddr, iport)<=0) |
| { | |
| ClearNameValueList(&data); | |
| return ; |
return ; |
| } |
|
| } |
} |
| #if 0 |
| n = upnp_get_pinhole_packets(uid, &pinholePackets); | |
| if(n > 0) | |
| { | |
| bodylen = snprintf(body, sizeof(body), resp, | |
| action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", | |
| pinholePackets, action); | |
| BuildSendAndCloseSoapResp(h, body, bodylen); | |
| } | |
| else if(r == -4 || r == -1) |
else if(r == -4 || r == -1) |
| { |
{ |
| SoapError(h, 704, "NoSuchEntry"); |
SoapError(h, 704, "NoSuchEntry"); |
| } |
} |
| else | #endif |
| { | |
| SoapError(h, 501, "ActionFailed"); | bodylen = snprintf(body, sizeof(body), resp, |
| ClearNameValueList(&data); | action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", |
| return ; | packets, action); |
| } | BuildSendAndCloseSoapResp(h, body, bodylen); |
| ClearNameValueList(&data); | |
| } |
} |
| #endif |
#endif |
| |
|
|
Line 1735 GetPinholePackets(struct upnphttp * h, const char * ac
|
Line 1810 GetPinholePackets(struct upnphttp * h, const char * ac
|
| * GetExternalIPAddress |
* GetExternalIPAddress |
| * QueryStateVariable / ConnectionStatus! |
* QueryStateVariable / ConnectionStatus! |
| */ |
*/ |
| static const struct | static const struct |
| { |
{ |
| const char * methodName; | const char * methodName; |
| void (*methodImpl)(struct upnphttp *, const char *); |
void (*methodImpl)(struct upnphttp *, const char *); |
| } |
} |
| soapMethods[] = |
soapMethods[] = |
|
Line 1772 soapMethods[] =
|
Line 1847 soapMethods[] =
|
| #endif |
#endif |
| #ifdef ENABLE_6FC_SERVICE |
#ifdef ENABLE_6FC_SERVICE |
| /* WANIPv6FirewallControl */ |
/* WANIPv6FirewallControl */ |
| { "GetFirewallStatus", GetFirewallStatus}, | { "GetFirewallStatus", GetFirewallStatus}, /* Required */ |
| { "AddPinhole", AddPinhole}, | { "AddPinhole", AddPinhole}, /* Required */ |
| { "UpdatePinhole", UpdatePinhole}, | { "UpdatePinhole", UpdatePinhole}, /* Required */ |
| { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout}, | { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout}, /* Optional */ |
| { "DeletePinhole", DeletePinhole}, | { "DeletePinhole", DeletePinhole}, /* Required */ |
| { "CheckPinholeWorking", CheckPinholeWorking}, | { "CheckPinholeWorking", CheckPinholeWorking}, /* Optional */ |
| { "GetPinholePackets", GetPinholePackets}, | { "GetPinholePackets", GetPinholePackets}, /* Required */ |
| #endif |
#endif |
| { 0, 0 } |
{ 0, 0 } |
| }; |
}; |
|
Line 1825 ExecuteSoapAction(struct upnphttp * h, const char * ac
|
Line 1900 ExecuteSoapAction(struct upnphttp * h, const char * ac
|
| * -------- ---------------- ----------- |
* -------- ---------------- ----------- |
| * 401 Invalid Action No action by that name at this service. |
* 401 Invalid Action No action by that name at this service. |
| * 402 Invalid Args Could be any of the following: not enough in args, |
* 402 Invalid Args Could be any of the following: not enough in args, |
| * too many in args, no in arg by that name, | * too many in args, no in arg by that name, |
| * one or more in args are of the wrong data type. |
* one or more in args are of the wrong data type. |
| * 403 Out of Sync Out of synchronization. |
* 403 Out of Sync Out of synchronization. |
| * 501 Action Failed May be returned in current state of service |
* 501 Action Failed May be returned in current state of service |
|
Line 1834 ExecuteSoapAction(struct upnphttp * h, const char * ac
|
Line 1909 ExecuteSoapAction(struct upnphttp * h, const char * ac
|
| * Technical Committee. |
* Technical Committee. |
| * 700-799 TBD Action-specific errors for standard actions. |
* 700-799 TBD Action-specific errors for standard actions. |
| * Defined by UPnP Forum working committee. |
* Defined by UPnP Forum working committee. |
| * 800-899 TBD Action-specific errors for non-standard actions. | * 800-899 TBD Action-specific errors for non-standard actions. |
| * Defined by UPnP vendor. |
* Defined by UPnP vendor. |
| */ |
*/ |
| void |
void |
| SoapError(struct upnphttp * h, int errCode, const char * errDesc) |
SoapError(struct upnphttp * h, int errCode, const char * errDesc) |
| { |
{ |
| static const char resp[] = | static const char resp[] = |
| "<s:Envelope " |
"<s:Envelope " |
| "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" " |
"xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" " |
| "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" |
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" |
|
Line 1864 SoapError(struct upnphttp * h, int errCode, const char
|
Line 1939 SoapError(struct upnphttp * h, int errCode, const char
|
| syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc); |
syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc); |
| bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc); |
bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc); |
| BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen); |
BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen); |
| SendResp_upnphttp(h); | SendRespAndClose_upnphttp(h); |
| CloseSocket_upnphttp(h); | |
| } |
} |
| |
|