Diff for /embedaddon/miniupnpd/upnpsoap.c between versions 1.1.1.2 and 1.1.1.3

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); 
 }  }
   

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>