version 1.1.1.1, 2012/02/21 23:16:02
|
version 1.1.1.2, 2012/05/29 12:55:57
|
Line 24
|
Line 24
|
#include "upnpredirect.h" |
#include "upnpredirect.h" |
#include "getifaddr.h" |
#include "getifaddr.h" |
#include "getifstats.h" |
#include "getifstats.h" |
|
#include "getconnstatus.h" |
|
#include "upnpurns.h" |
|
|
static void |
static void |
BuildSendAndCloseSoapResp(struct upnphttp * h, |
BuildSendAndCloseSoapResp(struct upnphttp * h, |
Line 60 GetConnectionTypeInfo(struct upnphttp * h, const char
|
Line 62 GetConnectionTypeInfo(struct upnphttp * h, const char
|
{ |
{ |
static const char resp[] = |
static const char resp[] = |
"<u:GetConnectionTypeInfoResponse " |
"<u:GetConnectionTypeInfoResponse " |
"xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" | "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">" |
"<NewConnectionType>IP_Routed</NewConnectionType>" |
"<NewConnectionType>IP_Routed</NewConnectionType>" |
"<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>" |
"<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>" |
"</u:GetConnectionTypeInfoResponse>"; |
"</u:GetConnectionTypeInfoResponse>"; |
Line 209 GetStatusInfo(struct upnphttp * h, const char * action
|
Line 211 GetStatusInfo(struct upnphttp * h, const char * action
|
char body[512]; |
char body[512]; |
int bodylen; |
int bodylen; |
time_t uptime; |
time_t uptime; |
const char * status = "Connected"; | const char * status; |
/* ConnectionStatus possible values : |
/* ConnectionStatus possible values : |
* Unconfigured, Connecting, Connected, PendingDisconnect, |
* Unconfigured, Connecting, Connected, PendingDisconnect, |
* Disconnecting, Disconnected */ |
* Disconnecting, Disconnected */ |
char ext_ip_addr[INET_ADDRSTRLEN]; |
|
|
|
if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0) { | status = get_wan_connection_status_str(ext_if_name); |
status = "Disconnected"; | |
} | |
uptime = (time(NULL) - startup_time); |
uptime = (time(NULL) - startup_time); |
bodylen = snprintf(body, sizeof(body), resp, |
bodylen = snprintf(body, sizeof(body), resp, |
action, "urn:schemas-upnp-org:service:WANIPConnection:1", | action, SERVICE_TYPE_WANIPC, |
status, (long)uptime, action); |
status, (long)uptime, action); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
} |
} |
Line 230 GetNATRSIPStatus(struct upnphttp * h, const char * act
|
Line 229 GetNATRSIPStatus(struct upnphttp * h, const char * act
|
{ |
{ |
static const char resp[] = |
static const char resp[] = |
"<u:GetNATRSIPStatusResponse " |
"<u:GetNATRSIPStatusResponse " |
"xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" | "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">" |
"<NewRSIPAvailable>0</NewRSIPAvailable>" |
"<NewRSIPAvailable>0</NewRSIPAvailable>" |
"<NewNATEnabled>1</NewNATEnabled>" |
"<NewNATEnabled>1</NewNATEnabled>" |
"</u:GetNATRSIPStatusResponse>"; |
"</u:GetNATRSIPStatusResponse>"; |
Line 257 GetExternalIPAddress(struct upnphttp * h, const char *
|
Line 256 GetExternalIPAddress(struct upnphttp * h, const char *
|
char body[512]; |
char body[512]; |
int bodylen; |
int bodylen; |
char ext_ip_addr[INET_ADDRSTRLEN]; |
char ext_ip_addr[INET_ADDRSTRLEN]; |
|
/* Does that method need to work with IPv6 ? |
|
* There is usually no NAT with IPv6 */ |
|
|
#ifndef MULTIPLE_EXTERNAL_IP |
#ifndef MULTIPLE_EXTERNAL_IP |
if(use_ext_ip_addr) |
if(use_ext_ip_addr) |
Line 270 GetExternalIPAddress(struct upnphttp * h, const char *
|
Line 271 GetExternalIPAddress(struct upnphttp * h, const char *
|
strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN); |
strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN); |
} |
} |
#else |
#else |
int i; | struct lan_addr_s * lan_addr; |
strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN); |
strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN); |
for(i = 0; i<n_lan_addr; i++) | for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) |
{ |
{ |
if( (h->clientaddr.s_addr & lan_addr[i].mask.s_addr) | if( (h->clientaddr.s_addr & lan_addr->mask.s_addr) |
== (lan_addr[i].addr.s_addr & lan_addr[i].mask.s_addr)) | == (lan_addr->addr.s_addr & lan_addr->mask.s_addr)) |
{ |
{ |
strncpy(ext_ip_addr, lan_addr[i].ext_ip_str, INET_ADDRSTRLEN); | strncpy(ext_ip_addr, lan_addr->ext_ip_str, INET_ADDRSTRLEN); |
break; |
break; |
} |
} |
} |
} |
#endif |
#endif |
bodylen = snprintf(body, sizeof(body), resp, |
bodylen = snprintf(body, sizeof(body), resp, |
action, "urn:schemas-upnp-org:service:WANIPConnection:1", | action, SERVICE_TYPE_WANIPC, |
ext_ip_addr, action); |
ext_ip_addr, action); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
} |
} |
|
|
|
/* AddPortMapping method of WANIPConnection Service |
|
* Ignored argument : NewEnabled */ |
static void |
static void |
AddPortMapping(struct upnphttp * h, const char * action) |
AddPortMapping(struct upnphttp * h, const char * action) |
{ |
{ |
Line 295 AddPortMapping(struct upnphttp * h, const char * actio
|
Line 298 AddPortMapping(struct upnphttp * h, const char * actio
|
|
|
static const char resp[] = |
static const char resp[] = |
"<u:AddPortMappingResponse " |
"<u:AddPortMappingResponse " |
"xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\"/>"; | "xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>"; |
|
|
struct NameValueParserData data; |
struct NameValueParserData data; |
char * int_ip, * int_port, * ext_port, * protocol, * desc; |
char * int_ip, * int_port, * ext_port, * protocol, * desc; |
char * leaseduration; | char * leaseduration_str; |
| unsigned int leaseduration; |
| char * r_host; |
unsigned short iport, eport; |
unsigned short iport, eport; |
|
|
struct hostent *hp; /* getbyhostname() */ |
struct hostent *hp; /* getbyhostname() */ |
Line 308 AddPortMapping(struct upnphttp * h, const char * actio
|
Line 313 AddPortMapping(struct upnphttp * h, const char * actio
|
|
|
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, "NewInternalClient"); |
int_ip = GetValueFromNameValueList(&data, "NewInternalClient"); |
|
|
if (!int_ip) |
if (!int_ip) |
{ |
{ |
ClearNameValueList(&data); |
ClearNameValueList(&data); |
Line 316 AddPortMapping(struct upnphttp * h, const char * actio
|
Line 320 AddPortMapping(struct upnphttp * h, const char * actio
|
return; |
return; |
} |
} |
|
|
|
/* IGD 2 MUST support both wildcard and specific IP address values |
|
* for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */ |
|
r_host = GetValueFromNameValueList(&data, "NewRemoteHost"); |
|
#ifndef SUPPORT_REMOTEHOST |
|
#ifdef UPNP_STRICT |
|
if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*"))) |
|
{ |
|
ClearNameValueList(&data); |
|
SoapError(h, 726, "RemoteHostOnlySupportsWildcard"); |
|
return; |
|
} |
|
#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) |
{ |
{ |
Line 356 AddPortMapping(struct upnphttp * h, const char * actio
|
Line 374 AddPortMapping(struct upnphttp * h, const char * actio
|
ext_port = GetValueFromNameValueList(&data, "NewExternalPort"); |
ext_port = GetValueFromNameValueList(&data, "NewExternalPort"); |
protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
desc = GetValueFromNameValueList(&data, "NewPortMappingDescription"); |
desc = GetValueFromNameValueList(&data, "NewPortMappingDescription"); |
leaseduration = GetValueFromNameValueList(&data, "NewLeaseDuration"); | leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration"); |
|
|
if (!int_port || !ext_port || !protocol) |
if (!int_port || !ext_port || !protocol) |
{ |
{ |
Line 368 AddPortMapping(struct upnphttp * h, const char * actio
|
Line 386 AddPortMapping(struct upnphttp * h, const char * actio
|
eport = (unsigned short)atoi(ext_port); |
eport = (unsigned short)atoi(ext_port); |
iport = (unsigned short)atoi(int_port); |
iport = (unsigned short)atoi(int_port); |
|
|
if(leaseduration && atoi(leaseduration)) { | leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0; |
/* at the moment, lease duration is always infinite */ | #ifdef IGD_V2 |
syslog(LOG_WARNING, "NewLeaseDuration=%s not supported, ignored. (ip=%s, desc='%s')", leaseduration, int_ip, desc); | /* PortMappingLeaseDuration can be either a value between 1 and |
} | * 604800 seconds or the zero value (for infinite lease time). |
| * Note that an infinite lease time can be only set by out-of-band |
| * mechanisms like WWW-administration, remote management or local |
| * management. |
| * If a control point uses the value 0 to indicate an infinite lease |
| * time mapping, it is REQUIRED that gateway uses the maximum value |
| * instead (e.g. 604800 seconds) */ |
| if(leaseduration == 0 || leaseduration > 604800) |
| leaseduration = 604800; |
| #endif |
|
|
syslog(LOG_INFO, "%s: ext port %hu to %s:%hu protocol %s for: %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); | action, eport, int_ip, iport, protocol, desc, leaseduration, r_host); |
|
|
r = upnp_redirect(eport, int_ip, iport, protocol, desc); | r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration); |
|
|
ClearNameValueList(&data); |
ClearNameValueList(&data); |
|
|
Line 386 AddPortMapping(struct upnphttp * h, const char * actio
|
Line 413 AddPortMapping(struct upnphttp * h, const char * actio
|
* 715 - Wildcard not permited in SrcAddr |
* 715 - Wildcard not permited in SrcAddr |
* 716 - Wildcard not permited in ExtPort |
* 716 - Wildcard not permited in ExtPort |
* 718 - ConflictInMappingEntry |
* 718 - ConflictInMappingEntry |
* 724 - SamePortValuesRequired | * 724 - SamePortValuesRequired (deprecated in IGD v2) |
* 725 - OnlyPermanentLeasesSupported |
* 725 - OnlyPermanentLeasesSupported |
The NAT implementation only supports permanent lease times on |
The NAT implementation only supports permanent lease times on |
port mappings | port mappings (deprecated in IGD v2) |
* 726 - RemoteHostOnlySupportsWildcard |
* 726 - RemoteHostOnlySupportsWildcard |
RemoteHost must be a wildcard and cannot be a specific IP |
RemoteHost must be a wildcard and cannot be a specific IP |
address or DNS name | address or DNS name (deprecated in IGD v2) |
* 727 - ExternalPortOnlySupportsWildcard |
* 727 - ExternalPortOnlySupportsWildcard |
ExternalPort must be a wildcard and cannot be a specific port |
ExternalPort must be a wildcard and cannot be a specific port |
value | value (deprecated in IGD v2) |
* 728 - NoPortMapsAvailable |
* 728 - NoPortMapsAvailable |
There are not enough free prots available to complete the mapping |
There are not enough free prots available to complete the mapping |
(added in IGD v2) */ | (added in IGD v2) |
| * 729 - ConflictWithOtherMechanisms (added in IGD v2) */ |
switch(r) |
switch(r) |
{ |
{ |
case 0: /* success */ |
case 0: /* success */ |
Line 431 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
Line 459 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
const char * int_ip, * int_port, * ext_port, * protocol, * desc; |
const char * int_ip, * int_port, * ext_port, * protocol, * desc; |
const char * r_host; |
const char * r_host; |
unsigned short iport, eport; |
unsigned short iport, eport; |
|
const char * leaseduration_str; |
unsigned int leaseduration; |
unsigned int leaseduration; |
|
|
struct hostent *hp; /* getbyhostname() */ |
struct hostent *hp; /* getbyhostname() */ |
Line 445 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
Line 474 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
int_ip = GetValueFromNameValueList(&data, "NewInternalClient"); |
int_ip = GetValueFromNameValueList(&data, "NewInternalClient"); |
/* NewEnabled */ |
/* NewEnabled */ |
desc = GetValueFromNameValueList(&data, "NewPortMappingDescription"); |
desc = GetValueFromNameValueList(&data, "NewPortMappingDescription"); |
leaseduration = atoi(GetValueFromNameValueList(&data, "NewLeaseDuration")); | leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration"); |
| |
| leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0; |
if(leaseduration == 0) |
if(leaseduration == 0) |
leaseduration = 604800; |
leaseduration = 604800; |
|
|
Line 458 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
Line 489 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
return; |
return; |
} |
} |
|
#ifndef SUPPORT_REMOTEHOST |
|
#ifdef UPNP_STRICT |
|
if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*"))) |
|
{ |
|
ClearNameValueList(&data); |
|
SoapError(h, 726, "RemoteHostOnlySupportsWildcard"); |
|
return; |
|
} |
|
#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) |
Line 495 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
Line 536 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
} |
} |
} |
} |
|
|
/* TODO : accept a different external port */ | /* TODO : accept a different external port |
r = upnp_redirect(eport, int_ip, iport, protocol, desc); | * have some smart strategy to choose the port */ |
| for(;;) { |
| r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration); |
| if(r==-2 && eport < 65535) { |
| eport++; |
| } else { |
| break; |
| } |
| } |
|
|
ClearNameValueList(&data); |
ClearNameValueList(&data); |
|
|
Line 504 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
Line 553 AddAnyPortMapping(struct upnphttp * h, const char * ac
|
{ |
{ |
case 0: /* success */ |
case 0: /* success */ |
bodylen = snprintf(body, sizeof(body), resp, |
bodylen = snprintf(body, sizeof(body), resp, |
action, "urn:schemas-upnp-org:service:WANIPConnection:2", | action, SERVICE_TYPE_WANIPC, |
eport, action); |
eport, action); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
break; |
break; |
Line 531 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
Line 580 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
"<NewInternalClient>%s</NewInternalClient>" |
"<NewInternalClient>%s</NewInternalClient>" |
"<NewEnabled>1</NewEnabled>" |
"<NewEnabled>1</NewEnabled>" |
"<NewPortMappingDescription>%s</NewPortMappingDescription>" |
"<NewPortMappingDescription>%s</NewPortMappingDescription>" |
"<NewLeaseDuration>0</NewLeaseDuration>" | "<NewLeaseDuration>%u</NewLeaseDuration>" |
"</u:%sResponse>"; |
"</u:%sResponse>"; |
|
|
char body[1024]; |
char body[1024]; |
Line 541 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
Line 590 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
unsigned short eport, iport; |
unsigned short eport, iport; |
char int_ip[32]; |
char int_ip[32]; |
char desc[64]; |
char desc[64]; |
|
unsigned int leaseduration = 0; |
|
|
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
r_host = GetValueFromNameValueList(&data, "NewRemoteHost"); |
r_host = GetValueFromNameValueList(&data, "NewRemoteHost"); |
Line 553 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
Line 603 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
return; |
return; |
} |
} |
|
#ifndef SUPPORT_REMOTEHOST |
|
#ifdef UPNP_STRICT |
|
if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*"))) |
|
{ |
|
ClearNameValueList(&data); |
|
SoapError(h, 726, "RemoteHostOnlySupportsWildcard"); |
|
return; |
|
} |
|
#endif |
|
#endif |
|
|
eport = (unsigned short)atoi(ext_port); |
eport = (unsigned short)atoi(ext_port); |
|
|
|
/* TODO : add r_host as an input parameter ... |
|
* We prevent several Port Mapping with same external port |
|
* but different remoteHost to be set up, so that is not |
|
* a priority. */ |
r = upnp_get_redirection_infos(eport, protocol, &iport, |
r = upnp_get_redirection_infos(eport, protocol, &iport, |
int_ip, sizeof(int_ip), |
int_ip, sizeof(int_ip), |
desc, sizeof(desc)); | desc, sizeof(desc), |
| NULL, 0, |
| &leaseduration); |
|
|
if(r < 0) |
if(r < 0) |
{ |
{ |
Line 570 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
Line 636 GetSpecificPortMappingEntry(struct upnphttp * h, const
|
action, |
action, |
r_host, ext_port, protocol, int_ip, (unsigned int)iport, desc); |
r_host, ext_port, protocol, int_ip, (unsigned int)iport, desc); |
bodylen = snprintf(body, sizeof(body), resp, |
bodylen = snprintf(body, sizeof(body), resp, |
action, "urn:schemas-upnp-org:service:WANIPConnection:1", | action, SERVICE_TYPE_WANIPC, |
(unsigned int)iport, int_ip, desc, | (unsigned int)iport, int_ip, desc, leaseduration, |
action); |
action); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
} |
} |
Line 586 DeletePortMapping(struct upnphttp * h, const char * ac
|
Line 652 DeletePortMapping(struct upnphttp * h, const char * ac
|
|
|
static const char resp[] = |
static const char resp[] = |
"<u:DeletePortMappingResponse " |
"<u:DeletePortMappingResponse " |
"xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" | "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">" |
"</u:DeletePortMappingResponse>"; |
"</u:DeletePortMappingResponse>"; |
|
|
struct NameValueParserData data; |
struct NameValueParserData data; |
Line 604 DeletePortMapping(struct upnphttp * h, const char * ac
|
Line 670 DeletePortMapping(struct upnphttp * h, const char * ac
|
SoapError(h, 402, "Invalid Args"); |
SoapError(h, 402, "Invalid Args"); |
return; |
return; |
} |
} |
|
#ifndef SUPPORT_REMOTEHOST |
|
#ifdef UPNP_STRICT |
|
if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*"))) |
|
{ |
|
ClearNameValueList(&data); |
|
SoapError(h, 726, "RemoteHostOnlySupportsWildcard"); |
|
return; |
|
} |
|
#endif |
|
#endif |
|
|
eport = (unsigned short)atoi(ext_port); |
eport = (unsigned short)atoi(ext_port); |
|
|
/* TODO : if in secure mode, check the IP */ | /* TODO : if in secure mode, check the IP |
| * Removing a redirection is not a security threat, |
| * just an annoyance for the user using it. So this is not |
| * 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); |
Line 630 DeletePortMapping(struct upnphttp * h, const char * ac
|
Line 709 DeletePortMapping(struct upnphttp * h, const char * ac
|
static void |
static void |
DeletePortMappingRange(struct upnphttp * h, const char * action) |
DeletePortMappingRange(struct upnphttp * h, const char * action) |
{ |
{ |
|
int r = -1; |
static const char resp[] = |
static const char resp[] = |
"<u:DeletePortMappingRangeResponse " |
"<u:DeletePortMappingRangeResponse " |
"xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:2\">" | "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">" |
"</u:DeletePortMappingRangeResponse>"; |
"</u:DeletePortMappingRangeResponse>"; |
struct NameValueParserData data; |
struct NameValueParserData data; |
const char * protocol; |
const char * protocol; |
unsigned short startport, endport; |
unsigned short startport, endport; |
int manage; |
int manage; |
|
unsigned short * port_list; |
|
unsigned int i, number = 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 = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort")); |
Line 645 DeletePortMappingRange(struct upnphttp * h, const char
|
Line 727 DeletePortMappingRange(struct upnphttp * h, const char
|
protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
manage = atoi(GetValueFromNameValueList(&data, "NewManage")); |
manage = atoi(GetValueFromNameValueList(&data, "NewManage")); |
|
|
/* TODO : implement the method ! */ |
|
|
|
/* possible errors : |
/* possible errors : |
606 - Action not authorized |
606 - Action not authorized |
730 - PortMappingNotFound |
730 - PortMappingNotFound |
733 - InconsistentParameter |
733 - InconsistentParameter |
*/ |
*/ |
|
if(startport > endport) |
|
{ |
|
SoapError(h, 733, "InconsistentParameter"); |
|
ClearNameValueList(&data); |
|
return; |
|
} |
|
|
|
port_list = upnp_get_portmappings_in_range(startport, endport, |
|
protocol, &number); |
|
for(i = 0; i < number; i++) |
|
{ |
|
r = upnp_delete_redirection(port_list[i], protocol); |
|
/* TODO : check return value for errors */ |
|
} |
|
free(port_list); |
BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); |
BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); |
|
|
ClearNameValueList(&data); |
ClearNameValueList(&data); |
Line 665 GetGenericPortMappingEntry(struct upnphttp * h, const
|
Line 760 GetGenericPortMappingEntry(struct upnphttp * h, const
|
static const char resp[] = |
static const char resp[] = |
"<u:%sResponse " |
"<u:%sResponse " |
"xmlns:u=\"%s\">" |
"xmlns:u=\"%s\">" |
"<NewRemoteHost></NewRemoteHost>" | "<NewRemoteHost>%s</NewRemoteHost>" |
"<NewExternalPort>%u</NewExternalPort>" |
"<NewExternalPort>%u</NewExternalPort>" |
"<NewProtocol>%s</NewProtocol>" |
"<NewProtocol>%s</NewProtocol>" |
"<NewInternalPort>%u</NewInternalPort>" |
"<NewInternalPort>%u</NewInternalPort>" |
"<NewInternalClient>%s</NewInternalClient>" |
"<NewInternalClient>%s</NewInternalClient>" |
"<NewEnabled>1</NewEnabled>" |
"<NewEnabled>1</NewEnabled>" |
"<NewPortMappingDescription>%s</NewPortMappingDescription>" |
"<NewPortMappingDescription>%s</NewPortMappingDescription>" |
"<NewLeaseDuration>0</NewLeaseDuration>" | "<NewLeaseDuration>%u</NewLeaseDuration>" |
"</u:%sResponse>"; |
"</u:%sResponse>"; |
|
|
int index = 0; |
int index = 0; |
Line 680 GetGenericPortMappingEntry(struct upnphttp * h, const
|
Line 775 GetGenericPortMappingEntry(struct upnphttp * h, const
|
const char * m_index; |
const char * m_index; |
char protocol[4], iaddr[32]; |
char protocol[4], iaddr[32]; |
char desc[64]; |
char desc[64]; |
|
char rhost[40]; |
|
unsigned int leaseduration = 0; |
struct NameValueParserData data; |
struct NameValueParserData data; |
|
|
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
Line 696 GetGenericPortMappingEntry(struct upnphttp * h, const
|
Line 793 GetGenericPortMappingEntry(struct upnphttp * h, const
|
|
|
syslog(LOG_INFO, "%s: index=%d", action, index); |
syslog(LOG_INFO, "%s: index=%d", action, index); |
|
|
|
rhost[0] = '\0'; |
r = upnp_get_redirection_infos_by_index(index, &eport, protocol, &iport, |
r = upnp_get_redirection_infos_by_index(index, &eport, protocol, &iport, |
iaddr, sizeof(iaddr), |
iaddr, sizeof(iaddr), |
desc, sizeof(desc)); | desc, sizeof(desc), |
| rhost, sizeof(rhost), |
| &leaseduration); |
|
|
if(r < 0) |
if(r < 0) |
{ |
{ |
Line 709 GetGenericPortMappingEntry(struct upnphttp * h, const
|
Line 809 GetGenericPortMappingEntry(struct upnphttp * h, const
|
int bodylen; |
int bodylen; |
char body[2048]; |
char body[2048]; |
bodylen = snprintf(body, sizeof(body), resp, |
bodylen = snprintf(body, sizeof(body), resp, |
action, "urn:schemas-upnp-org:service:WANIPConnection:1", | action, SERVICE_TYPE_WANIPC, rhost, |
(unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc, |
(unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc, |
action); | leaseduration, action); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
} |
} |
|
|
Line 722 GetGenericPortMappingEntry(struct upnphttp * h, const
|
Line 822 GetGenericPortMappingEntry(struct upnphttp * h, const
|
static void |
static void |
GetListOfPortMappings(struct upnphttp * h, const char * action) |
GetListOfPortMappings(struct upnphttp * h, const char * action) |
{ |
{ |
static const char resp[] = | static const char resp_start[] = |
"<u:%sResponse " |
"<u:%sResponse " |
"xmlns:u=\"%s\">" |
"xmlns:u=\"%s\">" |
"<NewPortListing><![CDATA[%s]]</NewPortListing>" | "<NewPortListing><![CDATA["; |
| static const char resp_end[] = |
| "]]></NewPortListing>" |
"</u:%sResponse>"; |
"</u:%sResponse>"; |
|
|
char body[512]; | static const char list_start[] = |
| "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\"" |
| " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" |
| " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection" |
| " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">"; |
| static const char list_end[] = |
| "</p:PortMappingList>"; |
| |
| static const char entry[] = |
| "<p:PortMappingEntry>" |
| "<p:NewRemoteHost>%s</p:NewRemoteHost>" |
| "<p:NewExternalPort>%hu</p:NewExternalPort>" |
| "<p:NewProtocol>%s</p:NewProtocol>" |
| "<p:NewInternalPort>%hu</p:NewInternalPort>" |
| "<p:NewInternalClient>%s</p:NewInternalClient>" |
| "<p:NewEnabled>1</p:NewEnabled>" |
| "<p:NewDescription>%s</p:NewDescription>" |
| "<p:NewLeaseTime>%u</p:NewLeaseTime>" |
| "</p:PortMappingEntry>"; |
| |
| char * body; |
| size_t bodyalloc; |
int bodylen; |
int bodylen; |
|
|
|
int r = -1; |
|
unsigned short iport; |
|
char int_ip[32]; |
|
char desc[64]; |
|
char rhost[64]; |
|
unsigned int leaseduration = 0; |
|
|
struct NameValueParserData data; |
struct NameValueParserData data; |
unsigned short startport, endport; |
unsigned short startport, endport; |
const char * protocol; |
const char * protocol; |
int manage; |
int manage; |
int number; |
int number; |
|
unsigned short * port_list; |
|
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 = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort")); |
Line 743 GetListOfPortMappings(struct upnphttp * h, const char
|
Line 875 GetListOfPortMappings(struct upnphttp * h, const char
|
protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
protocol = GetValueFromNameValueList(&data, "NewProtocol"); |
manage = atoi(GetValueFromNameValueList(&data, "NewManage")); |
manage = atoi(GetValueFromNameValueList(&data, "NewManage")); |
number = atoi(GetValueFromNameValueList(&data, "NewNumberOfPorts")); |
number = atoi(GetValueFromNameValueList(&data, "NewNumberOfPorts")); |
|
if(number == 0) number = 1000; /* return up to 1000 mappings by default */ |
|
|
|
if(startport > endport) |
|
{ |
|
SoapError(h, 733, "InconsistentParameter"); |
|
ClearNameValueList(&data); |
|
return; |
|
} |
/* |
/* |
TODO : build the PortMappingList xml document : | build the PortMappingList xml document : |
|
|
<p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection" |
<p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection" |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
Line 763 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd"
|
Line 902 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd"
|
</p:PortMappingEntry> |
</p:PortMappingEntry> |
</p:PortMappingList> |
</p:PortMappingList> |
*/ |
*/ |
bodylen = snprintf(body, sizeof(body), resp, | bodyalloc = 4096; |
action, "urn:schemas-upnp-org:service:WANIPConnection:2", | body = malloc(bodyalloc); |
"", action); | if(!body) |
| { |
| ClearNameValueList(&data); |
| SoapError(h, 501, "ActionFailed"); |
| return; |
| } |
| bodylen = snprintf(body, bodyalloc, resp_start, |
| action, SERVICE_TYPE_WANIPC); |
| memcpy(body+bodylen, list_start, sizeof(list_start)); |
| bodylen += (sizeof(list_start) - 1); |
| |
| port_list = upnp_get_portmappings_in_range(startport, endport, |
| protocol, &list_size); |
| /* loop through port mappings */ |
| for(i = 0; number > 0 && i < list_size; i++) |
| { |
| /* have a margin of 1024 bytes to store the new entry */ |
| if(bodylen + 1024 > bodyalloc) |
| { |
| bodyalloc += 4096; |
| body = realloc(body, bodyalloc); |
| if(!body) |
| { |
| ClearNameValueList(&data); |
| SoapError(h, 501, "ActionFailed"); |
| free(port_list); |
| return; |
| } |
| } |
| rhost[0] = '\0'; |
| r = upnp_get_redirection_infos(port_list[i], protocol, &iport, |
| int_ip, sizeof(int_ip), |
| desc, sizeof(desc), |
| rhost, sizeof(rhost), |
| &leaseduration); |
| if(r == 0) |
| { |
| bodylen += snprintf(body+bodylen, bodyalloc-bodylen, entry, |
| rhost, port_list[i], protocol, |
| iport, int_ip, desc, leaseduration); |
| number--; |
| } |
| } |
| free(port_list); |
| port_list = NULL; |
| |
| memcpy(body+bodylen, list_end, sizeof(list_end)); |
| bodylen += (sizeof(list_end) - 1); |
| bodylen += snprintf(body+bodylen, bodyalloc-bodylen, resp_end, |
| action); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
BuildSendAndCloseSoapResp(h, body, bodylen); |
|
free(body); |
|
|
ClearNameValueList(&data); |
ClearNameValueList(&data); |
} |
} |
Line 797 GetDefaultConnectionService(struct upnphttp * h, const
|
Line 986 GetDefaultConnectionService(struct upnphttp * h, const
|
"<u:%sResponse " |
"<u:%sResponse " |
"xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">" |
"xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">" |
"<NewDefaultConnectionService>%s:WANConnectionDevice:1," |
"<NewDefaultConnectionService>%s:WANConnectionDevice:1," |
"urn:upnp-org:serviceId:WANIPConn1</NewDefaultConnectionService>" | SERVICE_ID_WANIPC "</NewDefaultConnectionService>" |
"</u:%sResponse>"; |
"</u:%sResponse>"; |
/* example from UPnP_IGD_Layer3Forwarding 1.0.pdf : |
/* example from UPnP_IGD_Layer3Forwarding 1.0.pdf : |
* uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1, |
* uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1, |
Line 875 QueryStateVariable(struct upnphttp * h, const char * a
|
Line 1064 QueryStateVariable(struct upnphttp * h, const char * a
|
} |
} |
else if(strcmp(var_name, "ConnectionStatus") == 0) |
else if(strcmp(var_name, "ConnectionStatus") == 0) |
{ |
{ |
const char * status = "Connected"; | const char * status; |
char ext_ip_addr[INET_ADDRSTRLEN]; | |
if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0) { | status = get_wan_connection_status_str(ext_if_name); |
status = "Disconnected"; | |
} | |
bodylen = snprintf(body, sizeof(body), resp, |
bodylen = snprintf(body, sizeof(body), resp, |
action, "urn:schemas-upnp-org:control-1-0", |
action, "urn:schemas-upnp-org:control-1-0", |
status, action); |
status, action); |
Line 917 QueryStateVariable(struct upnphttp * h, const char * a
|
Line 1104 QueryStateVariable(struct upnphttp * h, const char * a
|
ClearNameValueList(&data); |
ClearNameValueList(&data); |
} |
} |
|
|
|
#ifdef ENABLE_6FC_SERVICE |
|
#ifndef ENABLE_IPV6 |
|
#error "ENABLE_6FC_SERVICE needs ENABLE_IPV6" |
|
#endif |
|
/* WANIPv6FirewallControl actions */ |
|
static void |
|
GetFirewallStatus(struct upnphttp * h, const char * action) |
|
{ |
|
static const char resp[] = |
|
"<u:%sResponse " |
|
"xmlns:u=\"%s\">" |
|
"<FirewallEnabled>%d</FirewallEnabled>" |
|
"<InboundPinholeAllowed>%d</InboundPinholeAllowed>" |
|
"</u:%sResponse>"; |
|
|
|
char body[512]; |
|
int bodylen; |
|
|
|
bodylen = snprintf(body, sizeof(body), resp, |
|
action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", |
|
ipv6fc_firewall_enabled, ipv6fc_inbound_pinhole_allowed, action); |
|
BuildSendAndCloseSoapResp(h, body, bodylen); |
|
} |
|
|
|
static int |
|
CheckStatus(struct upnphttp * h) |
|
{ |
|
if (!ipv6fc_firewall_enabled) |
|
{ |
|
SoapError(h, 702, "FirewallDisabed"); |
|
return 0; |
|
} |
|
else if(!ipv6fc_inbound_pinhole_allowed) |
|
{ |
|
SoapError(h, 703, "InboundPinholeNotAllowed"); |
|
return 0; |
|
} |
|
else |
|
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 |
|
static int connecthostport(const char * host, unsigned short port, char * result) |
|
{ |
|
int s, n; |
|
char hostname[INET6_ADDRSTRLEN]; |
|
char port_str[8], ifname[8], tmp[4]; |
|
struct addrinfo *ai, *p; |
|
struct addrinfo hints; |
|
|
|
memset(&hints, 0, sizeof(hints)); |
|
/* hints.ai_flags = AI_ADDRCONFIG; */ |
|
#ifdef AI_NUMERICSERV |
|
hints.ai_flags = AI_NUMERICSERV; |
|
#endif |
|
hints.ai_socktype = SOCK_STREAM; |
|
hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */ |
|
/* hints.ai_protocol = IPPROTO_TCP; */ |
|
snprintf(port_str, sizeof(port_str), "%hu", port); |
|
strcpy(hostname, host); |
|
if(!strncmp(host, "fe80", 4)) |
|
{ |
|
printf("Using an linklocal address\n"); |
|
strcpy(ifname, "%"); |
|
snprintf(tmp, sizeof(tmp), "%d", linklocal_index); |
|
strcat(ifname, tmp); |
|
strcat(hostname, ifname); |
|
printf("host: %s\n", hostname); |
|
} |
|
n = getaddrinfo(hostname, port_str, &hints, &ai); |
|
if(n != 0) |
|
{ |
|
fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n)); |
|
return -1; |
|
} |
|
s = -1; |
|
for(p = ai; p; p = p->ai_next) |
|
{ |
|
#ifdef DEBUG |
|
char tmp_host[256]; |
|
char tmp_service[256]; |
|
printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ", |
|
p->ai_family, p->ai_socktype, p->ai_protocol, p->ai_addrlen); |
|
getnameinfo(p->ai_addr, p->ai_addrlen, tmp_host, sizeof(tmp_host), |
|
tmp_service, sizeof(tmp_service), |
|
NI_NUMERICHOST | NI_NUMERICSERV); |
|
printf(" host=%s service=%s\n", tmp_host, tmp_service); |
|
#endif |
|
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr), result, INET6_ADDRSTRLEN); |
|
return 0; |
|
} |
|
freeaddrinfo(ai); |
|
} |
|
#endif |
|
|
|
/* Check the security policy right */ |
|
static int |
|
PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port) |
|
{ |
|
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 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 in6_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */ //IPv6 Modification |
|
|
|
hints.ai_socktype = SOCK_STREAM; |
|
hints.ai_family = AF_UNSPEC; |
|
|
|
/* if ip not valid assume hostname and convert */ |
|
if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0) //IPv6 Modification |
|
{ |
|
|
|
n = getaddrinfo(int_ip, NULL, &hints, &ai);//hp = gethostbyname(int_ip); |
|
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++) |
|
{ |
|
inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); ///IPv6 Modification |
|
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 */ |
|
break; |
|
} |
|
} |
|
else |
|
{ |
|
syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip); |
|
SoapError(h, 402, "Invalid Args"); |
|
return -1; |
|
} |
|
freeaddrinfo(p); |
|
} |
|
|
|
if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN)<=0) |
|
{ |
|
//printf("Failed to inet_ntop\n"); |
|
syslog(LOG_ERR, "inet_ntop: %m"); |
|
} |
|
#ifdef DEBUG |
|
printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr, int_ip); |
|
#endif |
|
if(strcmp(senderAddr, int_ip) != 0) |
|
if(h->clientaddr_v6.s6_addr != result_ip.s6_addr) |
|
{ |
|
syslog(LOG_INFO, "Client %s tried to access pinhole for internal %s and is not authorized to do it", |
|
senderAddr, int_ip); |
|
SoapError(h, 606, "Action not authorized"); |
|
return 0; |
|
} |
|
|
|
/* Pinhole InternalPort must be greater than or equal to 1024 */ |
|
if (*int_port < 1024) |
|
{ |
|
syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it", |
|
senderAddr); |
|
SoapError(h, 606, "Action not authorized"); |
|
return 0; |
|
} |
|
return 1; |
|
} |
|
|
|
static void |
|
AddPinhole(struct upnphttp * h, const char * action) |
|
{ |
|
int r; |
|
static const char resp[] = |
|
"<u:%sResponse " |
|
"xmlns:u=\"%s\">" |
|
"<UniqueID>%d</UniqueID>" |
|
"</u:%sResponse>"; |
|
char body[512]; |
|
int bodylen; |
|
struct NameValueParserData data; |
|
char * rem_host, * rem_port, * int_ip, * int_port, * protocol, * leaseTime; |
|
int uid = 0; |
|
unsigned short iport, rport; |
|
|
|
if(CheckStatus(h)==0) |
|
return; |
|
|
|
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
|
rem_host = GetValueFromNameValueList(&data, "RemoteHost"); |
|
rem_port = GetValueFromNameValueList(&data, "RemotePort"); |
|
int_ip = GetValueFromNameValueList(&data, "InternalClient"); |
|
int_port = GetValueFromNameValueList(&data, "InternalPort"); |
|
protocol = GetValueFromNameValueList(&data, "Protocol"); |
|
leaseTime = GetValueFromNameValueList(&data, "LeaseTime"); |
|
|
|
rport = (unsigned short)atoi(rem_port); |
|
iport = (unsigned short)atoi(int_port); |
|
|
|
// ** As there is no security policy, InternalClient must be equal to the CP's IP address. |
|
if(DataVerification(h, int_ip, &iport, protocol, leaseTime) == 0 |
|
|| PinholeVerification(h, int_ip, &iport) <= 0) |
|
{ |
|
ClearNameValueList(&data); |
|
return ; |
|
} |
|
|
|
// ** RemoteHost can be wilcarded or an IDN. |
|
/*printf("\trem_host: %s\n", rem_host);*/ |
|
if (rem_host!=NULL && !strchr(rem_host, ':')) |
|
{ |
|
ClearNameValueList(&data); |
|
SoapError(h, 402, "Invalid Args"); |
|
return; |
|
} |
|
/*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); |
|
|
|
r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, protocol, leaseTime, &uid); |
|
|
|
switch(r) |
|
{ |
|
case 1: /* success */ |
|
bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", uid, action); |
|
BuildSendAndCloseSoapResp(h, body, bodylen); |
|
break; |
|
case -1: /* not permitted */ |
|
SoapError(h, 701, "PinholeSpaceExhausted"); |
|
break; |
|
default: |
|
SoapError(h, 501, "ActionFailed"); |
|
break; |
|
} |
|
ClearNameValueList(&data); |
|
} |
|
|
|
static void |
|
UpdatePinhole(struct upnphttp * h, const char * action) |
|
{ |
|
int r, n; |
|
static const char resp[] = |
|
"<u:UpdatePinholeResponse " |
|
"xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">" |
|
"</u:UpdatePinholeResponse>"; |
|
struct NameValueParserData data; |
|
const char * uid, * leaseTime; |
|
char iaddr[40], proto[6], lt[12]; |
|
unsigned short iport; |
|
|
|
if(CheckStatus(h)==0) |
|
return; |
|
|
|
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
|
uid = GetValueFromNameValueList(&data, "UniqueID"); |
|
leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime"); |
|
|
|
if(!uid || !leaseTime || !atoi(leaseTime) || atoi(leaseTime) > 86400) |
|
{ |
|
ClearNameValueList(&data); |
|
SoapError(h, 402, "Invalid Args"); |
|
return; |
|
} |
|
|
|
// Check that client is not deleting an pinhole he doesn't have access to, because of its public access |
|
n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt); |
|
if (n > 0) |
|
{ |
|
if(PinholeVerification(h, iaddr, &iport)==0) |
|
{ |
|
ClearNameValueList(&data); |
|
return ; |
|
} |
|
} |
|
|
|
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"); |
|
else |
|
SoapError(h, 501, "ActionFailed"); |
|
} |
|
else |
|
{ |
|
BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); |
|
} |
|
ClearNameValueList(&data); |
|
} |
|
|
|
static void |
|
GetOutboundPinholeTimeout(struct upnphttp * h, const char * action) |
|
{ |
|
if (!ipv6fc_firewall_enabled) |
|
{ |
|
SoapError(h, 702, "FirewallDisabed"); |
|
return; |
|
} |
|
int r; |
|
|
|
static const char resp[] = |
|
"<u:%sResponse " |
|
"xmlns:u=\"%s\">" |
|
"<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>" |
|
"</u:%sResponse>"; |
|
|
|
char body[512]; |
|
int bodylen; |
|
struct NameValueParserData data; |
|
char * int_ip, * int_port, * rem_host, * rem_port, * protocol; |
|
int opt=0, proto=0; |
|
unsigned short iport, rport; |
|
|
|
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
|
int_ip = GetValueFromNameValueList(&data, "InternalClient"); |
|
int_port = GetValueFromNameValueList(&data, "InternalPort"); |
|
rem_host = GetValueFromNameValueList(&data, "RemoteHost"); |
|
rem_port = GetValueFromNameValueList(&data, "RemotePort"); |
|
protocol = GetValueFromNameValueList(&data, "Protocol"); |
|
|
|
rport = (unsigned short)atoi(rem_port); |
|
iport = (unsigned short)atoi(int_port); |
|
proto = atoi(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); |
|
|
|
switch(r) |
|
{ |
|
case 1: /* success */ |
|
bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", opt, action); |
|
BuildSendAndCloseSoapResp(h, body, bodylen); |
|
break; |
|
case -5: /* Protocol not supported */ |
|
SoapError(h, 705, "ProtocolNotSupported"); |
|
break; |
|
default: |
|
SoapError(h, 501, "ActionFailed"); |
|
} |
|
ClearNameValueList(&data); |
|
} |
|
|
|
static void |
|
DeletePinhole(struct upnphttp * h, const char * action) |
|
{ |
|
if(CheckStatus(h)==0) |
|
return; |
|
int r, n; |
|
|
|
static const char resp[] = |
|
"<u:DeletePinholeResponse " |
|
"xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">" |
|
"</u:DeletePinholeResponse>"; |
|
|
|
struct NameValueParserData data; |
|
const char * uid; |
|
char iaddr[40], proto[6], lt[12]; |
|
unsigned short iport; |
|
|
|
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
|
uid = GetValueFromNameValueList(&data, "UniqueID"); |
|
|
|
if(!uid) |
|
{ |
|
ClearNameValueList(&data); |
|
SoapError(h, 402, "Invalid Args"); |
|
return; |
|
} |
|
|
|
// Check that client is not deleting an pinhole he doesn't have access to, because of its public access |
|
n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt); |
|
if (n > 0) |
|
{ |
|
if(PinholeVerification(h, iaddr, &iport)==0) |
|
{ |
|
ClearNameValueList(&data); |
|
return ; |
|
} |
|
} |
|
|
|
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); |
|
if(r==-4) |
|
SoapError(h, 704, "NoSuchEntry"); |
|
else |
|
SoapError(h, 501, "ActionFailed"); |
|
} |
|
else |
|
{ |
|
syslog(LOG_INFO, "%s: (inbound) pinhole successfully removed", action); |
|
BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1); |
|
} |
|
ClearNameValueList(&data); |
|
} |
|
|
|
static void |
|
CheckPinholeWorking(struct upnphttp * h, const char * action) |
|
{ |
|
if(CheckStatus(h)==0) |
|
return; |
|
int r, d; |
|
|
|
static const char resp[] = |
|
"<u:%sResponse " |
|
"xmlns:u=\"%s\">" |
|
"<IsWorking>%d</IsWorking>" |
|
"</u:%sResponse>"; |
|
|
|
char body[512]; |
|
int bodylen; |
|
struct NameValueParserData data; |
|
const char * uid; |
|
char eaddr[40], iaddr[40], proto[6], lt[12]; |
|
unsigned short eport, iport; |
|
int isWorking = 0; |
|
|
|
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
|
uid = GetValueFromNameValueList(&data, "UniqueID"); |
|
|
|
if(!uid) |
|
{ |
|
ClearNameValueList(&data); |
|
SoapError(h, 402, "Invalid Args"); |
|
return; |
|
} |
|
|
|
// Check that client is not checking a pinhole he doesn't have access to, because of its public access |
|
r = upnp_get_pinhole_info(eaddr, eport, iaddr, &iport, proto, uid, lt); |
|
if (r > 0) |
|
{ |
|
if(PinholeVerification(h, iaddr, &iport)==0) |
|
{ |
|
ClearNameValueList(&data); |
|
return ; |
|
} |
|
else |
|
{ |
|
int rulenum_used, rulenum = 0; |
|
d = upnp_check_pinhole_working(uid, eaddr, iaddr, &eport, &iport, proto, &rulenum_used); |
|
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); |
|
} |
|
} |
|
} |
|
else if(r == -4 || r == -1) |
|
{ |
|
SoapError(h, 704, "NoSuchEntry"); |
|
} |
|
else |
|
{ |
|
SoapError(h, 501, "ActionFailed"); |
|
ClearNameValueList(&data); |
|
return ; |
|
} |
|
ClearNameValueList(&data); |
|
} |
|
|
|
static void |
|
GetPinholePackets(struct upnphttp * h, const char * action) |
|
{ |
|
if(CheckStatus(h)==0) |
|
return; |
|
int r, n; |
|
|
|
static const char resp[] = |
|
"<u:%sResponse " |
|
"xmlns:u=\"%s\">" |
|
"<PinholePackets>%d</PinholePackets>" |
|
"</u:%sResponse>"; |
|
|
|
char body[512]; |
|
int bodylen; |
|
struct NameValueParserData data; |
|
const char * uid; |
|
char iaddr[40], proto[6], lt[12]; |
|
unsigned short iport; |
|
int pinholePackets = 0; |
|
|
|
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); |
|
uid = GetValueFromNameValueList(&data, "UniqueID"); |
|
|
|
if(!uid) |
|
{ |
|
ClearNameValueList(&data); |
|
SoapError(h, 402, "Invalid Args"); |
|
return; |
|
} |
|
|
|
// Check that client is not getting infos of a pinhole he doesn't have access to, because of its public access |
|
r = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt); |
|
if (r > 0) |
|
{ |
|
if(PinholeVerification(h, iaddr, &iport)==0) |
|
{ |
|
ClearNameValueList(&data); |
|
return ; |
|
} |
|
} |
|
|
|
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) |
|
{ |
|
SoapError(h, 704, "NoSuchEntry"); |
|
} |
|
else |
|
{ |
|
SoapError(h, 501, "ActionFailed"); |
|
ClearNameValueList(&data); |
|
return ; |
|
} |
|
ClearNameValueList(&data); |
|
} |
|
#endif |
|
|
|
|
/* Windows XP as client send the following requests : |
/* Windows XP as client send the following requests : |
* GetConnectionTypeInfo |
* GetConnectionTypeInfo |
* GetNATRSIPStatus |
* GetNATRSIPStatus |
Line 936 static const struct
|
Line 1742 static const struct
|
} |
} |
soapMethods[] = |
soapMethods[] = |
{ |
{ |
{ "GetConnectionTypeInfo", GetConnectionTypeInfo }, | /* WANCommonInterfaceConfig */ |
{ "GetNATRSIPStatus", GetNATRSIPStatus}, | |
{ "GetExternalIPAddress", GetExternalIPAddress}, | |
{ "AddPortMapping", AddPortMapping}, | |
{ "DeletePortMapping", DeletePortMapping}, | |
{ "GetGenericPortMappingEntry", GetGenericPortMappingEntry}, | |
{ "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry}, | |
{ "QueryStateVariable", QueryStateVariable}, |
{ "QueryStateVariable", QueryStateVariable}, |
{ "GetTotalBytesSent", GetTotalBytesSent}, |
{ "GetTotalBytesSent", GetTotalBytesSent}, |
{ "GetTotalBytesReceived", GetTotalBytesReceived}, |
{ "GetTotalBytesReceived", GetTotalBytesReceived}, |
Line 950 soapMethods[] =
|
Line 1750 soapMethods[] =
|
{ "GetTotalPacketsReceived", GetTotalPacketsReceived}, |
{ "GetTotalPacketsReceived", GetTotalPacketsReceived}, |
{ "GetCommonLinkProperties", GetCommonLinkProperties}, |
{ "GetCommonLinkProperties", GetCommonLinkProperties}, |
{ "GetStatusInfo", GetStatusInfo}, |
{ "GetStatusInfo", GetStatusInfo}, |
|
/* WANIPConnection */ |
|
{ "GetConnectionTypeInfo", GetConnectionTypeInfo }, |
|
{ "GetNATRSIPStatus", GetNATRSIPStatus}, |
|
{ "GetExternalIPAddress", GetExternalIPAddress}, |
|
{ "AddPortMapping", AddPortMapping}, |
|
{ "DeletePortMapping", DeletePortMapping}, |
|
{ "GetGenericPortMappingEntry", GetGenericPortMappingEntry}, |
|
{ "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry}, |
/* Required in WANIPConnection:2 */ |
/* Required in WANIPConnection:2 */ |
{ "SetConnectionType", SetConnectionType}, |
{ "SetConnectionType", SetConnectionType}, |
{ "RequestConnection", RequestConnection}, |
{ "RequestConnection", RequestConnection}, |
Line 958 soapMethods[] =
|
Line 1766 soapMethods[] =
|
{ "DeletePortMappingRange", DeletePortMappingRange}, |
{ "DeletePortMappingRange", DeletePortMappingRange}, |
{ "GetListOfPortMappings", GetListOfPortMappings}, |
{ "GetListOfPortMappings", GetListOfPortMappings}, |
#ifdef ENABLE_L3F_SERVICE |
#ifdef ENABLE_L3F_SERVICE |
|
/* Layer3Forwarding */ |
{ "SetDefaultConnectionService", SetDefaultConnectionService}, |
{ "SetDefaultConnectionService", SetDefaultConnectionService}, |
{ "GetDefaultConnectionService", GetDefaultConnectionService}, |
{ "GetDefaultConnectionService", GetDefaultConnectionService}, |
|
#endif |
|
#ifdef ENABLE_6FC_SERVICE |
|
/* WANIPv6FirewallControl */ |
|
{ "GetFirewallStatus", GetFirewallStatus}, |
|
{ "AddPinhole", AddPinhole}, |
|
{ "UpdatePinhole", UpdatePinhole}, |
|
{ "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout}, |
|
{ "DeletePinhole", DeletePinhole}, |
|
{ "CheckPinholeWorking", CheckPinholeWorking}, |
|
{ "GetPinholePackets", GetPinholePackets}, |
#endif |
#endif |
{ 0, 0 } |
{ 0, 0 } |
}; |
}; |