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

version 1.1, 2012/02/21 23:16:02 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 "upnpurns.h"
   
 static void  static void
 BuildSendAndCloseSoapResp(struct upnphttp * h,  BuildSendAndCloseSoapResp(struct upnphttp * h,
Line 51  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 60  GetConnectionTypeInfo(struct upnphttp * h, const char  Line 64  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>";
           UNUSED(action);
   
         BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);          BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
 }  }
   
Line 209  GetStatusInfo(struct upnphttp * h, const char * action Line 215  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 233  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>";
           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 257  GetExternalIPAddress(struct upnphttp * h, const char * Line 261  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 276  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 303  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 318  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 325  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)
         {          {
                 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 329  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 356  AddPortMapping(struct upnphttp * h, const char * actio Line 379  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 391  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_host : "NULL");
   
        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 419  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 465  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 480  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;
   
           if (!int_ip || !ext_port || !int_port)
           {
                   ClearNameValueList(&data);
                   SoapError(h, 402, "Invalid Args");
                   return;
           }
   
         eport = (unsigned short)atoi(ext_port);          eport = (unsigned short)atoi(ext_port);
         iport = (unsigned short)atoi(int_port);          iport = (unsigned short)atoi(int_port);
#ifndef SUPPORT_REMOTEHOST
        if (!int_ip)#ifdef UPNP_STRICT
         if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
         {          {
                 ClearNameValueList(&data);                  ClearNameValueList(&data);
                SoapError(h, 402, "Invalid Args");                SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
                 return;                  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)
         {          {
                 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 472  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 495  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
        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 559  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 586  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 596  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");
         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");
                 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)
        {                       {
                 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, "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 663  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 598  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");
                 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);
   
         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 630  DeletePortMapping(struct upnphttp * h, const char * ac Line 724  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;
           const char * startport_s, * endport_s;
         unsigned short startport, endport;          unsigned short startport, endport;
        int manage;        /*int manage;*/
         unsigned short * port_list;
         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);
   
         /* 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 661  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\">"
                "<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 799  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 690  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);
   
         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 833  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 846  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;
           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 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(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 939  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);
         if(bodylen < 0)
         {
                 SoapError(h, 501, "ActionFailed");
                 free(body);
                 return;
         }
         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((unsigned int)bodylen + 1024 > bodyalloc)
                 {
                         char * body_sav = body;
                         bodyalloc += 4096;
                         body = realloc(body, bodyalloc);
                         if(!body)
                         {
                                 ClearNameValueList(&data);
                                 SoapError(h, 501, "ActionFailed");
                                 free(body_sav);
                                 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 784  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 797  GetDefaultConnectionService(struct upnphttp * h, const Line 1044  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 817  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 830  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 837  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 874  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 = "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 888  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 914  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
   #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, "FirewallDisabled");
                   return 0;
           }
           else if(!ipv6fc_inbound_pinhole_allowed)
           {
                   SoapError(h, 703, "InboundPinholeNotAllowed");
                   return 0;
           }
           else
                   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;
           char senderAddr[INET6_ADDRSTRLEN]="";
           struct addrinfo hints, *ai, *p;
           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_family = AF_UNSPEC;
   
           /* if ip not valid assume hostname and convert */
           if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0)
           {
                   n = getaddrinfo(int_ip, NULL, &hints, &ai);
                   if(!n && ai->ai_family == AF_INET6)
                   {
                           for(p = ai; p; p = p->ai_next)
                           {
                                   inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr));
                                   result_ip = *((struct in6_addr *) p);
                                   /* 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) == NULL)
           {
                   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;
           int ltime;
           long proto;
           char rem_ip[INET6_ADDRSTRLEN];
   
           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)(rem_port ? atoi(rem_port) : 0);
           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;
           }
   
           /* In particular, [IGD2] RECOMMENDS that unauthenticated and
            * unauthorized control points are only allowed to invoke
            * 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, "*"))
           {
                   SoapError(h, 708, "WildCardNotPermittedInSrcIP");
                   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
                   }
           }
   
           if(proto == 65535)
           {
                   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");
                   goto clear_and_exit;
           }
   
           if(PinholeVerification(h, int_ip, iport) <= 0)
                   goto clear_and_exit;
   
           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)
           {
                   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;
           }
           /* 606 Action not authorized
            * 701 PinholeSpaceExhausted
            * 702 FirewallDisabled
            * 703 InboundPinholeNotAllowed
            * 705 ProtocolNotSupported
            * 706 InternalPortWildcardingNotAllowed
            * 707 ProtocolWildcardingNotAllowed
            * 708 WildCardNotPermittedInSrcIP */
   clear_and_exit:
           ClearNameValueList(&data);
   }
   
   static void
   UpdatePinhole(struct upnphttp * h, const char * action)
   {
           static const char resp[] =
                   "<u:UpdatePinholeResponse "
                   "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
                   "</u:UpdatePinholeResponse>";
           struct NameValueParserData data;
           const char * uid_str, * leaseTime;
           char iaddr[INET6_ADDRSTRLEN];
           unsigned short iport;
           int ltime;
           int uid;
           int n;
   
           if(CheckStatus(h)==0)
                   return;
   
           ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
           uid_str = GetValueFromNameValueList(&data, "UniqueID");
           leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime");
           uid = uid_str ? atoi(uid_str) : -1;
           ltime = leaseTime ? atoi(leaseTime) : -1;
           ClearNameValueList(&data);
   
           if(uid < 0 || uid > 65535 || ltime <= 0 || ltime > 86400)
           {
                   SoapError(h, 402, "Invalid Args");
                   return;
           }
   
           /* Check that client is not updating an pinhole
            * it doesn't have access to, because of its public access */
           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)
                           return;
           }
           else if(n == -2)
           {
                   SoapError(h, 704, "NoSuchEntry");
                   return;
           }
           else
           {
                   SoapError(h, 501, "ActionFailed");
                   return;
           }
   
           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
   GetOutboundPinholeTimeout(struct upnphttp * h, const char * action)
   {
           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;
   
           if (!ipv6fc_firewall_enabled)
           {
                   SoapError(h, 702, "FirewallDisabled");
                   return;
           }
   
           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);
   
           /* TODO */
           r = -1;/*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)
   {
           int n;
   
           static const char resp[] =
                   "<u:DeletePinholeResponse "
                   "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
                   "</u:DeletePinholeResponse>";
   
           struct NameValueParserData data;
           const char * uid_str;
           char iaddr[INET6_ADDRSTRLEN];
           int proto;
           unsigned short iport;
           unsigned int leasetime;
           int uid;
   
           if(CheckStatus(h)==0)
                   return;
   
           ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
           uid_str = GetValueFromNameValueList(&data, "UniqueID");
           uid = uid_str ? atoi(uid_str) : -1;
           ClearNameValueList(&data);
   
           if(uid < 0 || uid > 65535)
           {
                   SoapError(h, 402, "Invalid Args");
                   return;
           }
   
           /* Check that client is not deleting an pinhole
            * it doesn't have access to, because of its public access */
           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)
                           return;
           }
           else if(n == -2)
           {
                   SoapError(h, 704, "NoSuchEntry");
                   return;
           }
           else
           {
                   SoapError(h, 501, "ActionFailed");
                   return;
           }
   
           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
   CheckPinholeWorking(struct upnphttp * h, const char * action)
   {
           static const char resp[] =
                   "<u:%sResponse "
                   "xmlns:u=\"%s\">"
                   "<IsWorking>%d</IsWorking>"
                   "</u:%sResponse>";
           char body[512];
           int bodylen;
           int r;
           struct NameValueParserData data;
           const char * uid_str;
           int uid;
           char iaddr[INET6_ADDRSTRLEN];
           unsigned short iport;
           unsigned int packets;
   
           if(CheckStatus(h)==0)
                   return;
   
           ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
           uid_str = GetValueFromNameValueList(&data, "UniqueID");
           uid = uid_str ? atoi(uid_str) : -1;
           ClearNameValueList(&data);
   
           if(uid < 0 || uid > 65535)
           {
                   SoapError(h, 402, "Invalid Args");
                   return;
           }
   
           /* Check that client is not checking a pinhole
            * it doesn't have access to, because of its public access */
           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)
                           return ;
                   if(packets == 0)
                   {
                           SoapError(h, 709, "NoPacketSent");
                           return;
                   }
                   bodylen = snprintf(body, sizeof(body), resp,
                                                   action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
                                                   1, action);
                   BuildSendAndCloseSoapResp(h, body, bodylen);
           }
           else if(r == -2)
                   SoapError(h, 704, "NoSuchEntry");
           else
                   SoapError(h, 501, "ActionFailed");
   }
   
   static void
   GetPinholePackets(struct upnphttp * h, const char * action)
   {
           static const char resp[] =
                   "<u:%sResponse "
                   "xmlns:u=\"%s\">"
                   "<PinholePackets>%u</PinholePackets>"
                   "</u:%sResponse>";
           char body[512];
           int bodylen;
           struct NameValueParserData data;
           const char * uid_str;
           int n;
           char iaddr[INET6_ADDRSTRLEN];
           unsigned short iport;
           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);
           uid_str = GetValueFromNameValueList(&data, "UniqueID");
           uid = uid_str ? atoi(uid_str) : -1;
           ClearNameValueList(&data);
   
           if(uid < 0 || uid > 65535)
           {
                   SoapError(h, 402, "Invalid Args");
                   return;
           }
   
           /* Check that client is not getting infos of a pinhole
            * it doesn't have access to, because of its public access */
           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)
                           return ;
           }
   #if 0
           else if(r == -4 || r == -1)
           {
                   SoapError(h, 704, "NoSuchEntry");
           }
   #endif
   
           bodylen = snprintf(body, sizeof(body), resp,
                           action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
                           packets, action);
           BuildSendAndCloseSoapResp(h, body, bodylen);
   }
   #endif
   
   
 /* Windows XP as client send the following requests :  /* Windows XP as client send the following requests :
  * GetConnectionTypeInfo   * GetConnectionTypeInfo
  * GetNATRSIPStatus   * GetNATRSIPStatus
Line 929  QueryStateVariable(struct upnphttp * h, const char * a Line 1810  QueryStateVariable(struct upnphttp * h, const char * a
  * 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[] =
 {  {
        { "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 1825  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 1841  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  #endif
   #ifdef ENABLE_6FC_SERVICE
           /* WANIPv6FirewallControl */
           { "GetFirewallStatus", GetFirewallStatus},      /* Required */
           { "AddPinhole", AddPinhole},                            /* Required */
           { "UpdatePinhole", UpdatePinhole},                      /* Required */
           { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout},      /* Optional */
           { "DeletePinhole", DeletePinhole},                      /* Required */
           { "CheckPinholeWorking", CheckPinholeWorking},  /* Optional */
           { "GetPinholePackets", GetPinholePackets},      /* Required */
   #endif
         { 0, 0 }          { 0, 0 }
 };  };
   
Line 1006  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 1015  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 1045  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  
changed lines
  Added in v.1.1.1.3


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