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

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

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


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