Annotation of embedaddon/miniupnpd/upnpsoap.c, revision 1.1.1.2

1.1.1.2 ! misho       1: /* $Id: upnpsoap.c,v 1.87 2011/07/15 07:48:26 nanard Exp $ */
1.1       misho       2: /* MiniUPnP project
                      3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
                      4:  * (c) 2006-2011 Thomas Bernard 
                      5:  * This software is subject to the conditions detailed
                      6:  * in the LICENCE file provided within the distribution */
                      7: 
                      8: #include <stdio.h>
                      9: #include <stdlib.h>
                     10: #include <string.h>
                     11: #include <sys/socket.h>
                     12: #include <unistd.h>
                     13: #include <syslog.h>
                     14: #include <sys/types.h>
                     15: #include <arpa/inet.h>
                     16: #include <netinet/in.h>
                     17: #include <netdb.h>
                     18: 
                     19: #include "config.h"
                     20: #include "upnpglobalvars.h"
                     21: #include "upnphttp.h"
                     22: #include "upnpsoap.h"
                     23: #include "upnpreplyparse.h"
                     24: #include "upnpredirect.h"
                     25: #include "getifaddr.h"
                     26: #include "getifstats.h"
1.1.1.2 ! misho      27: #include "getconnstatus.h"
        !            28: #include "upnpurns.h"
1.1       misho      29: 
                     30: static void
                     31: BuildSendAndCloseSoapResp(struct upnphttp * h,
                     32:                           const char * body, int bodylen)
                     33: {
                     34:        static const char beforebody[] =
                     35:                "<?xml version=\"1.0\"?>\r\n"
                     36:                "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
                     37:                "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                     38:                "<s:Body>";
                     39: 
                     40:        static const char afterbody[] =
                     41:                "</s:Body>"
                     42:                "</s:Envelope>\r\n";
                     43: 
                     44:        BuildHeader_upnphttp(h, 200, "OK",  sizeof(beforebody) - 1
                     45:                + sizeof(afterbody) - 1 + bodylen );
                     46: 
                     47:        memcpy(h->res_buf + h->res_buflen, beforebody, sizeof(beforebody) - 1);
                     48:        h->res_buflen += sizeof(beforebody) - 1;
                     49: 
                     50:        memcpy(h->res_buf + h->res_buflen, body, bodylen);
                     51:        h->res_buflen += bodylen;
                     52: 
                     53:        memcpy(h->res_buf + h->res_buflen, afterbody, sizeof(afterbody) - 1);
                     54:        h->res_buflen += sizeof(afterbody) - 1;
                     55: 
                     56:        SendResp_upnphttp(h);
                     57:        CloseSocket_upnphttp(h);
                     58: }
                     59: 
                     60: static void
                     61: GetConnectionTypeInfo(struct upnphttp * h, const char * action)
                     62: {
                     63:        static const char resp[] =
                     64:                "<u:GetConnectionTypeInfoResponse "
1.1.1.2 ! misho      65:                "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
1.1       misho      66:                "<NewConnectionType>IP_Routed</NewConnectionType>"
                     67:                "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
                     68:                "</u:GetConnectionTypeInfoResponse>";
                     69:        BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                     70: }
                     71: 
                     72: static void
                     73: GetTotalBytesSent(struct upnphttp * h, const char * action)
                     74: {
                     75:        int r;
                     76: 
                     77:        static const char resp[] =
                     78:                "<u:%sResponse "
                     79:                "xmlns:u=\"%s\">"
                     80:                "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
                     81:                "</u:%sResponse>";
                     82: 
                     83:        char body[512];
                     84:        int bodylen;
                     85:        struct ifdata data;
                     86: 
                     87:        r = getifstats(ext_if_name, &data);
                     88:        bodylen = snprintf(body, sizeof(body), resp,
                     89:                 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
                     90:              r<0?0:data.obytes, action);
                     91:        BuildSendAndCloseSoapResp(h, body, bodylen);
                     92: }
                     93: 
                     94: static void
                     95: GetTotalBytesReceived(struct upnphttp * h, const char * action)
                     96: {
                     97:        int r;
                     98: 
                     99:        static const char resp[] =
                    100:                "<u:%sResponse "
                    101:                "xmlns:u=\"%s\">"
                    102:                "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
                    103:                "</u:%sResponse>";
                    104: 
                    105:        char body[512];
                    106:        int bodylen;
                    107:        struct ifdata data;
                    108: 
                    109:        r = getifstats(ext_if_name, &data);
                    110:        bodylen = snprintf(body, sizeof(body), resp,
                    111:                 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
                    112:                 r<0?0:data.ibytes, action);
                    113:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    114: }
                    115: 
                    116: static void
                    117: GetTotalPacketsSent(struct upnphttp * h, const char * action)
                    118: {
                    119:        int r;
                    120: 
                    121:        static const char resp[] =
                    122:                "<u:%sResponse "
                    123:                "xmlns:u=\"%s\">"
                    124:                "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
                    125:                "</u:%sResponse>";
                    126: 
                    127:        char body[512];
                    128:        int bodylen;
                    129:        struct ifdata data;
                    130: 
                    131:        r = getifstats(ext_if_name, &data);
                    132:        bodylen = snprintf(body, sizeof(body), resp,
                    133:                 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
                    134:                 r<0?0:data.opackets, action);
                    135:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    136: }
                    137: 
                    138: static void
                    139: GetTotalPacketsReceived(struct upnphttp * h, const char * action)
                    140: {
                    141:        int r;
                    142: 
                    143:        static const char resp[] =
                    144:                "<u:%sResponse "
                    145:                "xmlns:u=\"%s\">"
                    146:                "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
                    147:                "</u:%sResponse>";
                    148: 
                    149:        char body[512];
                    150:        int bodylen;
                    151:        struct ifdata data;
                    152: 
                    153:        r = getifstats(ext_if_name, &data);
                    154:        bodylen = snprintf(body, sizeof(body), resp,
                    155:                 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
                    156:                 r<0?0:data.ipackets, action);
                    157:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    158: }
                    159: 
                    160: static void
                    161: GetCommonLinkProperties(struct upnphttp * h, const char * action)
                    162: {
                    163:        /* WANAccessType : set depending on the hardware :
                    164:         * DSL, POTS (plain old Telephone service), Cable, Ethernet */
                    165:        static const char resp[] =
                    166:                "<u:%sResponse "
                    167:                "xmlns:u=\"%s\">"
                    168:                /*"<NewWANAccessType>DSL</NewWANAccessType>"*/
                    169:                "<NewWANAccessType>Cable</NewWANAccessType>"
                    170:                "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
                    171:                "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
                    172:                "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
                    173:                "</u:%sResponse>";
                    174: 
                    175:        char body[2048];
                    176:        int bodylen;
                    177:        struct ifdata data;
                    178:        const char * status = "Up";     /* Up, Down (Required),
                    179:                                     * Initializing, Unavailable (Optional) */
                    180:        char ext_ip_addr[INET_ADDRSTRLEN];
                    181: 
                    182:        if((downstream_bitrate == 0) || (upstream_bitrate == 0))
                    183:        {
                    184:                if(getifstats(ext_if_name, &data) >= 0)
                    185:                {
                    186:                        if(downstream_bitrate == 0) downstream_bitrate = data.baudrate;
                    187:                        if(upstream_bitrate == 0) upstream_bitrate = data.baudrate;
                    188:                }
                    189:        }
                    190:        if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0) {
                    191:                status = "Down";
                    192:        }
                    193:        bodylen = snprintf(body, sizeof(body), resp,
                    194:            action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
                    195:                upstream_bitrate, downstream_bitrate,
                    196:            status, action);
                    197:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    198: }
                    199: 
                    200: static void
                    201: GetStatusInfo(struct upnphttp * h, const char * action)
                    202: {
                    203:        static const char resp[] =
                    204:                "<u:%sResponse "
                    205:                "xmlns:u=\"%s\">"
                    206:                "<NewConnectionStatus>%s</NewConnectionStatus>"
                    207:                "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
                    208:                "<NewUptime>%ld</NewUptime>"
                    209:                "</u:%sResponse>";
                    210: 
                    211:        char body[512];
                    212:        int bodylen;
                    213:        time_t uptime;
1.1.1.2 ! misho     214:        const char * status;
1.1       misho     215:        /* ConnectionStatus possible values :
                    216:         * Unconfigured, Connecting, Connected, PendingDisconnect,
                    217:         * Disconnecting, Disconnected */
                    218: 
1.1.1.2 ! misho     219:        status = get_wan_connection_status_str(ext_if_name);
1.1       misho     220:        uptime = (time(NULL) - startup_time);
                    221:        bodylen = snprintf(body, sizeof(body), resp,
1.1.1.2 ! misho     222:                action, SERVICE_TYPE_WANIPC,
1.1       misho     223:                status, (long)uptime, action);  
                    224:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    225: }
                    226: 
                    227: static void
                    228: GetNATRSIPStatus(struct upnphttp * h, const char * action)
                    229: {
                    230:        static const char resp[] =
                    231:                "<u:GetNATRSIPStatusResponse "
1.1.1.2 ! misho     232:                "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
1.1       misho     233:                "<NewRSIPAvailable>0</NewRSIPAvailable>"
                    234:                "<NewNATEnabled>1</NewNATEnabled>"
                    235:                "</u:GetNATRSIPStatusResponse>";
                    236:        /* 2.2.9. RSIPAvailable
                    237:         * This variable indicates if Realm-specific IP (RSIP) is available
                    238:         * as a feature on the InternetGatewayDevice. RSIP is being defined
                    239:         * in the NAT working group in the IETF to allow host-NATing using
                    240:         * a standard set of message exchanges. It also allows end-to-end
                    241:         * applications that otherwise break if NAT is introduced
                    242:         * (e.g. IPsec-based VPNs).
                    243:         * A gateway that does not support RSIP should set this variable to 0. */
                    244:        BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                    245: }
                    246: 
                    247: static void
                    248: GetExternalIPAddress(struct upnphttp * h, const char * action)
                    249: {
                    250:        static const char resp[] =
                    251:                "<u:%sResponse "
                    252:                "xmlns:u=\"%s\">"
                    253:                "<NewExternalIPAddress>%s</NewExternalIPAddress>"
                    254:                "</u:%sResponse>";
                    255: 
                    256:        char body[512];
                    257:        int bodylen;
                    258:        char ext_ip_addr[INET_ADDRSTRLEN];
1.1.1.2 ! misho     259:        /* Does that method need to work with IPv6 ?
        !           260:         * There is usually no NAT with IPv6 */
1.1       misho     261: 
                    262: #ifndef MULTIPLE_EXTERNAL_IP
                    263:        if(use_ext_ip_addr)
                    264:        {
                    265:                strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN);
                    266:        }
                    267:        else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0)
                    268:        {
                    269:                syslog(LOG_ERR, "Failed to get ip address for interface %s",
                    270:                        ext_if_name);
                    271:                strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
                    272:        }
                    273: #else
1.1.1.2 ! misho     274:        struct lan_addr_s * lan_addr;
1.1       misho     275:        strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
1.1.1.2 ! misho     276:        for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
1.1       misho     277:        {
1.1.1.2 ! misho     278:                if( (h->clientaddr.s_addr & lan_addr->mask.s_addr)
        !           279:                   == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
1.1       misho     280:                {
1.1.1.2 ! misho     281:                        strncpy(ext_ip_addr, lan_addr->ext_ip_str, INET_ADDRSTRLEN);
1.1       misho     282:                        break;
                    283:                }
                    284:        }
                    285: #endif
                    286:        bodylen = snprintf(body, sizeof(body), resp,
1.1.1.2 ! misho     287:                      action, SERVICE_TYPE_WANIPC,
1.1       misho     288:                                  ext_ip_addr, action);
                    289:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    290: }
                    291: 
1.1.1.2 ! misho     292: /* AddPortMapping method of WANIPConnection Service
        !           293:  * Ignored argument : NewEnabled */
1.1       misho     294: static void
                    295: AddPortMapping(struct upnphttp * h, const char * action)
                    296: {
                    297:        int r;
                    298: 
                    299:        static const char resp[] =
                    300:                "<u:AddPortMappingResponse "
1.1.1.2 ! misho     301:                "xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";
1.1       misho     302: 
                    303:        struct NameValueParserData data;
                    304:        char * int_ip, * int_port, * ext_port, * protocol, * desc;
1.1.1.2 ! misho     305:        char * leaseduration_str;
        !           306:        unsigned int leaseduration;
        !           307:        char * r_host;
1.1       misho     308:        unsigned short iport, eport;
                    309: 
                    310:        struct hostent *hp; /* getbyhostname() */
                    311:        char ** ptr; /* getbyhostname() */
                    312:        struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
                    313: 
                    314:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    315:        int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
                    316:        if (!int_ip)
                    317:        {
                    318:                ClearNameValueList(&data);
                    319:                SoapError(h, 402, "Invalid Args");
                    320:                return;
                    321:        }
                    322: 
1.1.1.2 ! misho     323:        /* IGD 2 MUST support both wildcard and specific IP address values
        !           324:         * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
        !           325:        r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
        !           326: #ifndef SUPPORT_REMOTEHOST
        !           327: #ifdef UPNP_STRICT
        !           328:        if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
        !           329:        {
        !           330:                ClearNameValueList(&data);
        !           331:                SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
        !           332:                return;
        !           333:        }
        !           334: #endif
        !           335: #endif
        !           336: 
1.1       misho     337:        /* if ip not valid assume hostname and convert */
                    338:        if (inet_pton(AF_INET, int_ip, &result_ip) <= 0) 
                    339:        {
                    340:                hp = gethostbyname(int_ip);
                    341:                if(hp && hp->h_addrtype == AF_INET) 
                    342:                { 
                    343:                        for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
                    344:                        {
                    345:                                int_ip = inet_ntoa(*((struct in_addr *) *ptr));
                    346:                                result_ip = *((struct in_addr *) *ptr);
                    347:                                /* TODO : deal with more than one ip per hostname */
                    348:                                break;
                    349:                        }
                    350:                } 
                    351:                else 
                    352:                {
                    353:                        syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip); 
                    354:                        ClearNameValueList(&data);
                    355:                        SoapError(h, 402, "Invalid Args");
                    356:                        return;
                    357:                }                               
                    358:        }
                    359: 
                    360:        /* check if NewInternalAddress is the client address */
                    361:        if(GETFLAG(SECUREMODEMASK))
                    362:        {
                    363:                if(h->clientaddr.s_addr != result_ip.s_addr)
                    364:                {
                    365:                        syslog(LOG_INFO, "Client %s tried to redirect port to %s",
                    366:                               inet_ntoa(h->clientaddr), int_ip);
                    367:                        ClearNameValueList(&data);
                    368:                        SoapError(h, 718, "ConflictInMappingEntry");
                    369:                        return;
                    370:                }
                    371:        }
                    372: 
                    373:        int_port = GetValueFromNameValueList(&data, "NewInternalPort");
                    374:        ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
                    375:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    376:        desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
1.1.1.2 ! misho     377:        leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
1.1       misho     378: 
                    379:        if (!int_port || !ext_port || !protocol)
                    380:        {
                    381:                ClearNameValueList(&data);
                    382:                SoapError(h, 402, "Invalid Args");
                    383:                return;
                    384:        }
                    385: 
                    386:        eport = (unsigned short)atoi(ext_port);
                    387:        iport = (unsigned short)atoi(int_port);
                    388: 
1.1.1.2 ! misho     389:        leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
        !           390: #ifdef IGD_V2
        !           391:        /* PortMappingLeaseDuration can be either a value between 1 and
        !           392:         * 604800 seconds or the zero value (for infinite lease time).
        !           393:         * Note that an infinite lease time can be only set by out-of-band
        !           394:         * mechanisms like WWW-administration, remote management or local
        !           395:         * management.
        !           396:         * If a control point uses the value 0 to indicate an infinite lease
        !           397:         * time mapping, it is REQUIRED that gateway uses the maximum value
        !           398:         * instead (e.g. 604800 seconds) */
        !           399:        if(leaseduration == 0 || leaseduration > 604800)
        !           400:                leaseduration = 604800;
        !           401: #endif
1.1       misho     402: 
1.1.1.2 ! misho     403:        syslog(LOG_INFO, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
        !           404:               action, eport, int_ip, iport, protocol, desc, leaseduration, r_host);
1.1       misho     405: 
1.1.1.2 ! misho     406:        r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
1.1       misho     407: 
                    408:        ClearNameValueList(&data);
                    409: 
                    410:        /* possible error codes for AddPortMapping :
                    411:         * 402 - Invalid Args
                    412:         * 501 - Action Failed
                    413:         * 715 - Wildcard not permited in SrcAddr
                    414:         * 716 - Wildcard not permited in ExtPort
                    415:         * 718 - ConflictInMappingEntry
1.1.1.2 ! misho     416:         * 724 - SamePortValuesRequired (deprecated in IGD v2)
1.1       misho     417:      * 725 - OnlyPermanentLeasesSupported
                    418:              The NAT implementation only supports permanent lease times on
1.1.1.2 ! misho     419:              port mappings (deprecated in IGD v2)
1.1       misho     420:      * 726 - RemoteHostOnlySupportsWildcard
                    421:              RemoteHost must be a wildcard and cannot be a specific IP
1.1.1.2 ! misho     422:              address or DNS name (deprecated in IGD v2)
1.1       misho     423:      * 727 - ExternalPortOnlySupportsWildcard
                    424:              ExternalPort must be a wildcard and cannot be a specific port
1.1.1.2 ! misho     425:              value (deprecated in IGD v2)
1.1       misho     426:      * 728 - NoPortMapsAvailable
                    427:              There are not enough free prots available to complete the mapping
1.1.1.2 ! misho     428:              (added in IGD v2)
        !           429:         * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
1.1       misho     430:        switch(r)
                    431:        {
                    432:        case 0: /* success */
                    433:                BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                    434:                break;
                    435:        case -2:        /* already redirected */
                    436:        case -3:        /* not permitted */
                    437:                SoapError(h, 718, "ConflictInMappingEntry");
                    438:                break;
                    439:        default:
                    440:                SoapError(h, 501, "ActionFailed");
                    441:        }
                    442: }
                    443: 
                    444: /* AddAnyPortMapping was added in WANIPConnection v2 */
                    445: static void
                    446: AddAnyPortMapping(struct upnphttp * h, const char * action)
                    447: {
                    448:        int r;
                    449:        static const char resp[] =
                    450:                "<u:%sResponse "
                    451:                "xmlns:u=\"%s\">"
                    452:                "<NewReservedPort>%hu</NewReservedPort>"
                    453:                "</u:%sResponse>";
                    454: 
                    455:        char body[512];
                    456:        int bodylen;
                    457: 
                    458:        struct NameValueParserData data;
                    459:        const char * int_ip, * int_port, * ext_port, * protocol, * desc;
                    460:        const char * r_host;
                    461:        unsigned short iport, eport;
1.1.1.2 ! misho     462:        const char * leaseduration_str;
1.1       misho     463:        unsigned int leaseduration;
                    464: 
                    465:        struct hostent *hp; /* getbyhostname() */
                    466:        char ** ptr; /* getbyhostname() */
                    467:        struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
                    468: 
                    469:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    470:        r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
                    471:        ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
                    472:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    473:        int_port = GetValueFromNameValueList(&data, "NewInternalPort");
                    474:        int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
                    475:        /* NewEnabled */
                    476:        desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
1.1.1.2 ! misho     477:        leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
        !           478: 
        !           479:        leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
1.1       misho     480:        if(leaseduration == 0)
                    481:                leaseduration = 604800;
                    482: 
                    483:        eport = (unsigned short)atoi(ext_port);
                    484:        iport = (unsigned short)atoi(int_port);
                    485: 
                    486:        if (!int_ip)
                    487:        {
                    488:                ClearNameValueList(&data);
                    489:                SoapError(h, 402, "Invalid Args");
                    490:                return;
                    491:        }
1.1.1.2 ! misho     492: #ifndef SUPPORT_REMOTEHOST
        !           493: #ifdef UPNP_STRICT
        !           494:        if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
        !           495:        {
        !           496:                ClearNameValueList(&data);
        !           497:                SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
        !           498:                return;
        !           499:        }
        !           500: #endif
        !           501: #endif
1.1       misho     502: 
                    503:        /* if ip not valid assume hostname and convert */
                    504:        if (inet_pton(AF_INET, int_ip, &result_ip) <= 0) 
                    505:        {
                    506:                hp = gethostbyname(int_ip);
                    507:                if(hp && hp->h_addrtype == AF_INET) 
                    508:                { 
                    509:                        for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
                    510:                        {
                    511:                                int_ip = inet_ntoa(*((struct in_addr *) *ptr));
                    512:                                result_ip = *((struct in_addr *) *ptr);
                    513:                                /* TODO : deal with more than one ip per hostname */
                    514:                                break;
                    515:                        }
                    516:                } 
                    517:                else 
                    518:                {
                    519:                        syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip); 
                    520:                        ClearNameValueList(&data);
                    521:                        SoapError(h, 402, "Invalid Args");
                    522:                        return;
                    523:                }                               
                    524:        }
                    525: 
                    526:        /* check if NewInternalAddress is the client address */
                    527:        if(GETFLAG(SECUREMODEMASK))
                    528:        {
                    529:                if(h->clientaddr.s_addr != result_ip.s_addr)
                    530:                {
                    531:                        syslog(LOG_INFO, "Client %s tried to redirect port to %s",
                    532:                               inet_ntoa(h->clientaddr), int_ip);
                    533:                        ClearNameValueList(&data);
                    534:                        SoapError(h, 606, "Action not authorized");
                    535:                        return;
                    536:                }
                    537:        }
                    538: 
1.1.1.2 ! misho     539:        /* TODO : accept a different external port 
        !           540:         * have some smart strategy to choose the port */
        !           541:        for(;;) {
        !           542:                r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
        !           543:                if(r==-2 && eport < 65535) {
        !           544:                        eport++;
        !           545:                } else {
        !           546:                        break;
        !           547:                }
        !           548:        }
1.1       misho     549: 
                    550:        ClearNameValueList(&data);
                    551: 
                    552:        switch(r)
                    553:        {
                    554:        case 0: /* success */
                    555:                bodylen = snprintf(body, sizeof(body), resp,
1.1.1.2 ! misho     556:                              action, SERVICE_TYPE_WANIPC,
1.1       misho     557:                                          eport, action);
                    558:                BuildSendAndCloseSoapResp(h, body, bodylen);
                    559:                break;
                    560:        case -2:        /* already redirected */
                    561:                SoapError(h, 718, "ConflictInMappingEntry");
                    562:                break;
                    563:        case -3:        /* not permitted */
                    564:                SoapError(h, 606, "Action not authorized");
                    565:                break;
                    566:        default:
                    567:                SoapError(h, 501, "ActionFailed");
                    568:        }
                    569: }
                    570: 
                    571: static void
                    572: GetSpecificPortMappingEntry(struct upnphttp * h, const char * action)
                    573: {
                    574:        int r;
                    575: 
                    576:        static const char resp[] =
                    577:                "<u:%sResponse "
                    578:                "xmlns:u=\"%s\">"
                    579:                "<NewInternalPort>%u</NewInternalPort>"
                    580:                "<NewInternalClient>%s</NewInternalClient>"
                    581:                "<NewEnabled>1</NewEnabled>"
                    582:                "<NewPortMappingDescription>%s</NewPortMappingDescription>"
1.1.1.2 ! misho     583:                "<NewLeaseDuration>%u</NewLeaseDuration>"
1.1       misho     584:                "</u:%sResponse>";
                    585: 
                    586:        char body[1024];
                    587:        int bodylen;
                    588:        struct NameValueParserData data;
                    589:        const char * r_host, * ext_port, * protocol;
                    590:        unsigned short eport, iport;
                    591:        char int_ip[32];
                    592:        char desc[64];
1.1.1.2 ! misho     593:        unsigned int leaseduration = 0;
1.1       misho     594: 
                    595:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    596:        r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
                    597:        ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
                    598:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    599: 
                    600:        if(!ext_port || !protocol)
                    601:        {
                    602:                ClearNameValueList(&data);
                    603:                SoapError(h, 402, "Invalid Args");
                    604:                return;
                    605:        }
1.1.1.2 ! misho     606: #ifndef SUPPORT_REMOTEHOST
        !           607: #ifdef UPNP_STRICT
        !           608:        if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
        !           609:        {
        !           610:                ClearNameValueList(&data);
        !           611:                SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
        !           612:                return;
        !           613:        }
        !           614: #endif
        !           615: #endif
1.1       misho     616: 
                    617:        eport = (unsigned short)atoi(ext_port);
                    618: 
1.1.1.2 ! misho     619:        /* TODO : add r_host as an input parameter ...
        !           620:         * We prevent several Port Mapping with same external port
        !           621:         * but different remoteHost to be set up, so that is not
        !           622:         * a priority. */
1.1       misho     623:        r = upnp_get_redirection_infos(eport, protocol, &iport,
                    624:                                       int_ip, sizeof(int_ip),
1.1.1.2 ! misho     625:                                       desc, sizeof(desc),
        !           626:                                       NULL, 0,
        !           627:                                       &leaseduration);
1.1       misho     628: 
                    629:        if(r < 0)
                    630:        {               
                    631:                SoapError(h, 714, "NoSuchEntryInArray");
                    632:        }
                    633:        else
                    634:        {
                    635:                syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
                    636:                       action,
                    637:                       r_host, ext_port, protocol, int_ip, (unsigned int)iport, desc);
                    638:                bodylen = snprintf(body, sizeof(body), resp,
1.1.1.2 ! misho     639:                                action, SERVICE_TYPE_WANIPC,
        !           640:                                (unsigned int)iport, int_ip, desc, leaseduration,
1.1       misho     641:                                action);
                    642:                BuildSendAndCloseSoapResp(h, body, bodylen);
                    643:        }
                    644: 
                    645:        ClearNameValueList(&data);
                    646: }
                    647: 
                    648: static void
                    649: DeletePortMapping(struct upnphttp * h, const char * action)
                    650: {
                    651:        int r;
                    652: 
                    653:        static const char resp[] =
                    654:                "<u:DeletePortMappingResponse "
1.1.1.2 ! misho     655:                "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
1.1       misho     656:                "</u:DeletePortMappingResponse>";
                    657: 
                    658:        struct NameValueParserData data;
                    659:        const char * r_host, * ext_port, * protocol;
                    660:        unsigned short eport;
                    661: 
                    662:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    663:        r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
                    664:        ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
                    665:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    666: 
                    667:        if(!ext_port || !protocol)
                    668:        {
                    669:                ClearNameValueList(&data);
                    670:                SoapError(h, 402, "Invalid Args");
                    671:                return;
                    672:        }
1.1.1.2 ! misho     673: #ifndef SUPPORT_REMOTEHOST
        !           674: #ifdef UPNP_STRICT
        !           675:        if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
        !           676:        {
        !           677:                ClearNameValueList(&data);
        !           678:                SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
        !           679:                return;
        !           680:        }
        !           681: #endif
        !           682: #endif
1.1       misho     683: 
                    684:        eport = (unsigned short)atoi(ext_port);
                    685: 
1.1.1.2 ! misho     686:        /* TODO : if in secure mode, check the IP
        !           687:         * Removing a redirection is not a security threat,
        !           688:         * just an annoyance for the user using it. So this is not
        !           689:         * a priority. */
1.1       misho     690: 
                    691:        syslog(LOG_INFO, "%s: external port: %hu, protocol: %s", 
                    692:                action, eport, protocol);
                    693: 
                    694:        r = upnp_delete_redirection(eport, protocol);
                    695: 
                    696:        if(r < 0)
                    697:        {       
                    698:                SoapError(h, 714, "NoSuchEntryInArray");
                    699:        }
                    700:        else
                    701:        {
                    702:                BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                    703:        }
                    704: 
                    705:        ClearNameValueList(&data);
                    706: }
                    707: 
                    708: /* DeletePortMappingRange was added in IGD spec v2 */
                    709: static void
                    710: DeletePortMappingRange(struct upnphttp * h, const char * action)
                    711: {
1.1.1.2 ! misho     712:        int r = -1;
1.1       misho     713:        static const char resp[] =
                    714:                "<u:DeletePortMappingRangeResponse "
1.1.1.2 ! misho     715:                "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
1.1       misho     716:                "</u:DeletePortMappingRangeResponse>";
                    717:        struct NameValueParserData data;
                    718:        const char * protocol;
                    719:        unsigned short startport, endport;
                    720:        int manage;
1.1.1.2 ! misho     721:        unsigned short * port_list;
        !           722:        unsigned int i, number = 0;
1.1       misho     723: 
                    724:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    725:        startport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort"));
                    726:        endport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewEndPort"));
                    727:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    728:        manage = atoi(GetValueFromNameValueList(&data, "NewManage"));
                    729: 
                    730:        /* possible errors :
                    731:           606 - Action not authorized
                    732:           730 - PortMappingNotFound
                    733:           733 - InconsistentParameter
                    734:         */
1.1.1.2 ! misho     735:        if(startport > endport)
        !           736:        {
        !           737:                SoapError(h, 733, "InconsistentParameter");
        !           738:                ClearNameValueList(&data);
        !           739:                return;
        !           740:        }
        !           741: 
        !           742:        port_list = upnp_get_portmappings_in_range(startport, endport,
        !           743:                                                   protocol, &number);
        !           744:        for(i = 0; i < number; i++)
        !           745:        {
        !           746:                r = upnp_delete_redirection(port_list[i], protocol);
        !           747:                /* TODO : check return value for errors */
        !           748:        }
        !           749:        free(port_list);
1.1       misho     750:        BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                    751: 
                    752:        ClearNameValueList(&data);
                    753: }
                    754: 
                    755: static void
                    756: GetGenericPortMappingEntry(struct upnphttp * h, const char * action)
                    757: {
                    758:        int r;
                    759:        
                    760:        static const char resp[] =
                    761:                "<u:%sResponse "
                    762:                "xmlns:u=\"%s\">"
1.1.1.2 ! misho     763:                "<NewRemoteHost>%s</NewRemoteHost>"
1.1       misho     764:                "<NewExternalPort>%u</NewExternalPort>"
                    765:                "<NewProtocol>%s</NewProtocol>"
                    766:                "<NewInternalPort>%u</NewInternalPort>"
                    767:                "<NewInternalClient>%s</NewInternalClient>"
                    768:                "<NewEnabled>1</NewEnabled>"
                    769:                "<NewPortMappingDescription>%s</NewPortMappingDescription>"
1.1.1.2 ! misho     770:                "<NewLeaseDuration>%u</NewLeaseDuration>"
1.1       misho     771:                "</u:%sResponse>";
                    772: 
                    773:        int index = 0;
                    774:        unsigned short eport, iport;
                    775:        const char * m_index;
                    776:        char protocol[4], iaddr[32];
                    777:        char desc[64];
1.1.1.2 ! misho     778:        char rhost[40];
        !           779:        unsigned int leaseduration = 0;
1.1       misho     780:        struct NameValueParserData data;
                    781: 
                    782:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    783:        m_index = GetValueFromNameValueList(&data, "NewPortMappingIndex");
                    784: 
                    785:        if(!m_index)
                    786:        {
                    787:                ClearNameValueList(&data);
                    788:                SoapError(h, 402, "Invalid Args");
                    789:                return;
                    790:        }       
                    791: 
                    792:        index = (int)atoi(m_index);
                    793: 
                    794:        syslog(LOG_INFO, "%s: index=%d", action, index);
                    795: 
1.1.1.2 ! misho     796:        rhost[0] = '\0';
1.1       misho     797:        r = upnp_get_redirection_infos_by_index(index, &eport, protocol, &iport,
                    798:                                             iaddr, sizeof(iaddr),
1.1.1.2 ! misho     799:                                                desc, sizeof(desc),
        !           800:                                                rhost, sizeof(rhost),
        !           801:                                                &leaseduration);
1.1       misho     802: 
                    803:        if(r < 0)
                    804:        {
                    805:                SoapError(h, 713, "SpecifiedArrayIndexInvalid");
                    806:        }
                    807:        else
                    808:        {
                    809:                int bodylen;
                    810:                char body[2048];
                    811:                bodylen = snprintf(body, sizeof(body), resp,
1.1.1.2 ! misho     812:                        action, SERVICE_TYPE_WANIPC, rhost,
1.1       misho     813:                        (unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc,
1.1.1.2 ! misho     814:                    leaseduration, action);
1.1       misho     815:                BuildSendAndCloseSoapResp(h, body, bodylen);
                    816:        }
                    817: 
                    818:        ClearNameValueList(&data);
                    819: }
                    820: 
                    821: /* GetListOfPortMappings was added in the IGD v2 specification */
                    822: static void
                    823: GetListOfPortMappings(struct upnphttp * h, const char * action)
                    824: {
1.1.1.2 ! misho     825:        static const char resp_start[] =
1.1       misho     826:                "<u:%sResponse "
                    827:                "xmlns:u=\"%s\">"
1.1.1.2 ! misho     828:                "<NewPortListing><![CDATA[";
        !           829:        static const char resp_end[] =
        !           830:                "]]></NewPortListing>"
1.1       misho     831:                "</u:%sResponse>";
                    832: 
1.1.1.2 ! misho     833:        static const char list_start[] =
        !           834:                "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
        !           835:                " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
        !           836:                " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
        !           837:                " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
        !           838:        static const char list_end[] =
        !           839:                "</p:PortMappingList>";
        !           840: 
        !           841:        static const char entry[] =
        !           842:                "<p:PortMappingEntry>"
        !           843:                "<p:NewRemoteHost>%s</p:NewRemoteHost>"
        !           844:                "<p:NewExternalPort>%hu</p:NewExternalPort>"
        !           845:                "<p:NewProtocol>%s</p:NewProtocol>"
        !           846:                "<p:NewInternalPort>%hu</p:NewInternalPort>"
        !           847:                "<p:NewInternalClient>%s</p:NewInternalClient>"
        !           848:                "<p:NewEnabled>1</p:NewEnabled>"
        !           849:                "<p:NewDescription>%s</p:NewDescription>"
        !           850:                "<p:NewLeaseTime>%u</p:NewLeaseTime>"
        !           851:                "</p:PortMappingEntry>";
        !           852: 
        !           853:        char * body;
        !           854:        size_t bodyalloc;
1.1       misho     855:        int bodylen;
                    856: 
1.1.1.2 ! misho     857:        int r = -1;
        !           858:        unsigned short iport;
        !           859:        char int_ip[32];
        !           860:        char desc[64];
        !           861:        char rhost[64];
        !           862:        unsigned int leaseduration = 0;
        !           863: 
1.1       misho     864:        struct NameValueParserData data;
                    865:        unsigned short startport, endport;
                    866:        const char * protocol;
                    867:        int manage;
                    868:        int number;
1.1.1.2 ! misho     869:        unsigned short * port_list;
        !           870:        unsigned int i, list_size = 0;
1.1       misho     871: 
                    872:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    873:        startport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort"));
                    874:        endport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewEndPort"));
                    875:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    876:        manage = atoi(GetValueFromNameValueList(&data, "NewManage"));
                    877:        number = atoi(GetValueFromNameValueList(&data, "NewNumberOfPorts"));
1.1.1.2 ! misho     878:        if(number == 0) number = 1000;  /* return up to 1000 mappings by default */
1.1       misho     879: 
1.1.1.2 ! misho     880:        if(startport > endport)
        !           881:        {
        !           882:                SoapError(h, 733, "InconsistentParameter");
        !           883:                ClearNameValueList(&data);
        !           884:                return;
        !           885:        }
1.1       misho     886: /*
1.1.1.2 ! misho     887: build the PortMappingList xml document :
1.1       misho     888: 
                    889: <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
                    890: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    891: xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
                    892: http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
                    893: <p:PortMappingEntry>
                    894: <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
                    895: <p:NewExternalPort>2345</p:NewExternalPort>
                    896: <p:NewProtocol>TCP</p:NewProtocol>
                    897: <p:NewInternalPort>2345</p:NewInternalPort>
                    898: <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
                    899: <p:NewEnabled>1</p:NewEnabled>
                    900: <p:NewDescription>dooom</p:NewDescription>
                    901: <p:NewLeaseTime>345</p:NewLeaseTime>
                    902: </p:PortMappingEntry>
                    903: </p:PortMappingList>
                    904: */
1.1.1.2 ! misho     905:        bodyalloc = 4096;
        !           906:        body = malloc(bodyalloc);
        !           907:        if(!body)
        !           908:        {
        !           909:                ClearNameValueList(&data);
        !           910:                SoapError(h, 501, "ActionFailed");
        !           911:                return;
        !           912:        }
        !           913:        bodylen = snprintf(body, bodyalloc, resp_start,
        !           914:                      action, SERVICE_TYPE_WANIPC);
        !           915:        memcpy(body+bodylen, list_start, sizeof(list_start));
        !           916:        bodylen += (sizeof(list_start) - 1);
        !           917: 
        !           918:        port_list = upnp_get_portmappings_in_range(startport, endport,
        !           919:                                                   protocol, &list_size);
        !           920:        /* loop through port mappings */
        !           921:        for(i = 0; number > 0 && i < list_size; i++)
        !           922:        {
        !           923:                /* have a margin of 1024 bytes to store the new entry */
        !           924:                if(bodylen + 1024 > bodyalloc)
        !           925:                {
        !           926:                        bodyalloc += 4096;
        !           927:                        body = realloc(body, bodyalloc);
        !           928:                        if(!body)
        !           929:                        {
        !           930:                                ClearNameValueList(&data);
        !           931:                                SoapError(h, 501, "ActionFailed");
        !           932:                                free(port_list);
        !           933:                                return;
        !           934:                        }
        !           935:                }
        !           936:                rhost[0] = '\0';
        !           937:                r = upnp_get_redirection_infos(port_list[i], protocol, &iport,
        !           938:                                               int_ip, sizeof(int_ip),
        !           939:                                               desc, sizeof(desc),
        !           940:                                               rhost, sizeof(rhost),
        !           941:                                               &leaseduration);
        !           942:                if(r == 0)
        !           943:                {
        !           944:                        bodylen += snprintf(body+bodylen, bodyalloc-bodylen, entry,
        !           945:                                            rhost, port_list[i], protocol,
        !           946:                                            iport, int_ip, desc, leaseduration);
        !           947:                        number--;
        !           948:                }
        !           949:        }
        !           950:        free(port_list);
        !           951:        port_list = NULL;
        !           952: 
        !           953:        memcpy(body+bodylen, list_end, sizeof(list_end));
        !           954:        bodylen += (sizeof(list_end) - 1);
        !           955:        bodylen += snprintf(body+bodylen, bodyalloc-bodylen, resp_end,
        !           956:                            action);
1.1       misho     957:        BuildSendAndCloseSoapResp(h, body, bodylen);
1.1.1.2 ! misho     958:        free(body);
1.1       misho     959: 
                    960:        ClearNameValueList(&data);
                    961: }
                    962: 
                    963: #ifdef ENABLE_L3F_SERVICE
                    964: static void
                    965: SetDefaultConnectionService(struct upnphttp * h, const char * action)
                    966: {
                    967:        static const char resp[] =
                    968:                "<u:SetDefaultConnectionServiceResponse "
                    969:                "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
                    970:                "</u:SetDefaultConnectionServiceResponse>";
                    971:        struct NameValueParserData data;
                    972:        char * p;
                    973:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    974:        p = GetValueFromNameValueList(&data, "NewDefaultConnectionService");
                    975:        if(p) {
                    976:                syslog(LOG_INFO, "%s(%s) : Ignored", action, p);
                    977:        }
                    978:        ClearNameValueList(&data);
                    979:        BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                    980: }
                    981: 
                    982: static void
                    983: GetDefaultConnectionService(struct upnphttp * h, const char * action)
                    984: {
                    985:        static const char resp[] =
                    986:                "<u:%sResponse "
                    987:                "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
                    988:                "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
1.1.1.2 ! misho     989:                SERVICE_ID_WANIPC "</NewDefaultConnectionService>"
1.1       misho     990:                "</u:%sResponse>";
                    991:        /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
                    992:         * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
                    993:         * urn:upnp-org:serviceId:WANPPPConn1 */
                    994:        char body[1024];
                    995:        int bodylen;
                    996: 
                    997:        bodylen = snprintf(body, sizeof(body), resp,
                    998:                           action, uuidvalue, action);
                    999:        BuildSendAndCloseSoapResp(h, body, bodylen);
                   1000: }
                   1001: #endif
                   1002: 
                   1003: /* Added for compliance with WANIPConnection v2 */
                   1004: static void
                   1005: SetConnectionType(struct upnphttp * h, const char * action)
                   1006: {
                   1007:        const char * connection_type;
                   1008:        struct NameValueParserData data;
                   1009: 
                   1010:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                   1011:        connection_type = GetValueFromNameValueList(&data, "NewConnectionType");
                   1012:        /* Unconfigured, IP_Routed, IP_Bridged */
                   1013:        ClearNameValueList(&data);
                   1014:        /* always return a ReadOnly error */
                   1015:        SoapError(h, 731, "ReadOnly");
                   1016: }
                   1017: 
                   1018: /* Added for compliance with WANIPConnection v2 */
                   1019: static void
                   1020: RequestConnection(struct upnphttp * h, const char * action)
                   1021: {
                   1022:        SoapError(h, 606, "Action not authorized");
                   1023: }
                   1024: 
                   1025: /* Added for compliance with WANIPConnection v2 */
                   1026: static void
                   1027: ForceTermination(struct upnphttp * h, const char * action)
                   1028: {
                   1029:        SoapError(h, 606, "Action not authorized");
                   1030: }
                   1031: 
                   1032: /*
                   1033: If a control point calls QueryStateVariable on a state variable that is not
                   1034: buffered in memory within (or otherwise available from) the service,
                   1035: the service must return a SOAP fault with an errorCode of 404 Invalid Var.
                   1036: 
                   1037: QueryStateVariable remains useful as a limited test tool but may not be
                   1038: part of some future versions of UPnP.
                   1039: */
                   1040: static void
                   1041: QueryStateVariable(struct upnphttp * h, const char * action)
                   1042: {
                   1043:        static const char resp[] =
                   1044:         "<u:%sResponse "
                   1045:         "xmlns:u=\"%s\">"
                   1046:                "<return>%s</return>"
                   1047:         "</u:%sResponse>";
                   1048: 
                   1049:        char body[512];
                   1050:        int bodylen;
                   1051:        struct NameValueParserData data;
                   1052:        const char * var_name;
                   1053: 
                   1054:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                   1055:        /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
                   1056:        /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
                   1057:        var_name = GetValueFromNameValueList(&data, "varName");
                   1058: 
                   1059:        /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
                   1060: 
                   1061:        if(!var_name)
                   1062:        {
                   1063:                SoapError(h, 402, "Invalid Args");
                   1064:        }
                   1065:        else if(strcmp(var_name, "ConnectionStatus") == 0)
                   1066:        {       
1.1.1.2 ! misho    1067:                const char * status;
        !          1068: 
        !          1069:                status = get_wan_connection_status_str(ext_if_name);
1.1       misho    1070:                bodylen = snprintf(body, sizeof(body), resp,
                   1071:                            action, "urn:schemas-upnp-org:control-1-0",
                   1072:                                   status, action);
                   1073:                BuildSendAndCloseSoapResp(h, body, bodylen);
                   1074:        }
                   1075: #if 0
                   1076:        /* not usefull */
                   1077:        else if(strcmp(var_name, "ConnectionType") == 0)
                   1078:        {       
                   1079:                bodylen = snprintf(body, sizeof(body), resp, "IP_Routed");
                   1080:                BuildSendAndCloseSoapResp(h, body, bodylen);
                   1081:        }
                   1082:        else if(strcmp(var_name, "LastConnectionError") == 0)
                   1083:        {       
                   1084:                bodylen = snprintf(body, sizeof(body), resp, "ERROR_NONE");
                   1085:                BuildSendAndCloseSoapResp(h, body, bodylen);
                   1086:        }
                   1087: #endif
                   1088:        else if(strcmp(var_name, "PortMappingNumberOfEntries") == 0)
                   1089:        {
                   1090:                char strn[10];
                   1091:                snprintf(strn, sizeof(strn), "%i",
                   1092:                         upnp_get_portmapping_number_of_entries());
                   1093:                bodylen = snprintf(body, sizeof(body), resp,
                   1094:                            action, "urn:schemas-upnp-org:control-1-0",
                   1095:                                   strn, action);
                   1096:                BuildSendAndCloseSoapResp(h, body, bodylen);
                   1097:        }
                   1098:        else
                   1099:        {
                   1100:                syslog(LOG_NOTICE, "%s: Unknown: %s", action, var_name?var_name:"");
                   1101:                SoapError(h, 404, "Invalid Var");
                   1102:        }
                   1103: 
                   1104:        ClearNameValueList(&data);      
                   1105: }
                   1106: 
1.1.1.2 ! misho    1107: #ifdef ENABLE_6FC_SERVICE
        !          1108: #ifndef ENABLE_IPV6
        !          1109: #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
        !          1110: #endif
        !          1111: /* WANIPv6FirewallControl actions */
        !          1112: static void
        !          1113: GetFirewallStatus(struct upnphttp * h, const char * action)
        !          1114: {
        !          1115:        static const char resp[] =
        !          1116:                "<u:%sResponse "
        !          1117:                "xmlns:u=\"%s\">"
        !          1118:                "<FirewallEnabled>%d</FirewallEnabled>"
        !          1119:                "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
        !          1120:                "</u:%sResponse>";
        !          1121: 
        !          1122:        char body[512];
        !          1123:        int bodylen;
        !          1124: 
        !          1125:        bodylen = snprintf(body, sizeof(body), resp,
        !          1126:                action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
        !          1127:                ipv6fc_firewall_enabled, ipv6fc_inbound_pinhole_allowed, action);
        !          1128:        BuildSendAndCloseSoapResp(h, body, bodylen);
        !          1129: }
        !          1130: 
        !          1131: static int
        !          1132: CheckStatus(struct upnphttp * h)
        !          1133: {
        !          1134:        if (!ipv6fc_firewall_enabled)
        !          1135:        {
        !          1136:                SoapError(h, 702, "FirewallDisabed");
        !          1137:                return 0;
        !          1138:        }
        !          1139:        else if(!ipv6fc_inbound_pinhole_allowed)
        !          1140:        {
        !          1141:                SoapError(h, 703, "InboundPinholeNotAllowed");
        !          1142:                return 0;
        !          1143:        }
        !          1144:        else
        !          1145:                return 1;
        !          1146: }
        !          1147: 
        !          1148: static int
        !          1149: DataVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port, const char * protocol, char * leaseTime)
        !          1150: {
        !          1151:        //int n;
        !          1152:        // **  Internal IP can't be wildcarded
        !          1153:        if (!int_ip)
        !          1154:        {
        !          1155:                SoapError(h, 708, "WildCardNotPermittedInSrcIP");
        !          1156:                return 0;
        !          1157:        }
        !          1158:        
        !          1159:        if (!strchr(int_ip, ':'))
        !          1160:        {
        !          1161:                SoapError(h, 402, "Invalid Args");
        !          1162:                return 0;
        !          1163:        }
        !          1164: 
        !          1165:        // ** Internal port can't be wilcarded. 
        !          1166: //     printf("\tint_port: *%d*\n", *int_port);
        !          1167:        if (*int_port == 0)
        !          1168:        {
        !          1169:                SoapError(h, 706, "InternalPortWilcardingNotAllowed");
        !          1170:                return 0;
        !          1171:        }
        !          1172: 
        !          1173:        // ** Protocol can't be wilcarded and can't be an unknown port (here deal with only UDP, TCP, UDPLITE)
        !          1174: //     printf("\tprotocol: *%s*\n", protocol);
        !          1175:        if (atoi(protocol) == 65535)
        !          1176:        {
        !          1177:                SoapError(h, 707, "ProtocolWilcardingNotAllowed");
        !          1178:                return 0;
        !          1179:        }
        !          1180:        else if (atoi(protocol) != IPPROTO_UDP
        !          1181:                && atoi(protocol) != IPPROTO_TCP
        !          1182: #ifdef IPPROTO_UDPITE
        !          1183:                && atoi(protocol) != IPPROTO_UDPLITE
        !          1184: #endif
        !          1185:                )
        !          1186:        {
        !          1187:                SoapError(h, 705, "ProtocolNotSupported");
        !          1188:                return 0;
        !          1189:        }
        !          1190: 
        !          1191:        // ** Lease Time can't be wilcarded nor >86400.
        !          1192: //     printf("\tlease time: %s\n", leaseTime);
        !          1193:        if(!leaseTime || !atoi(leaseTime) || atoi(leaseTime)>86400)
        !          1194:        {
        !          1195:                /* lease duration is never infinite, nor wilcarded. In this case, use default value */
        !          1196:                syslog(LOG_WARNING, "LeaseTime=%s not supported, (ip=%s)", leaseTime, int_ip);
        !          1197:                SoapError(h, 402, "Invalid Args");
        !          1198:                return 0;
        !          1199:        }
        !          1200: 
        !          1201:        return 1;
        !          1202: }
        !          1203: 
        !          1204: #if 0
        !          1205: static int connecthostport(const char * host, unsigned short port, char * result)
        !          1206: {
        !          1207:        int s, n;
        !          1208:        char hostname[INET6_ADDRSTRLEN];
        !          1209:        char port_str[8], ifname[8], tmp[4];
        !          1210:        struct addrinfo *ai, *p;
        !          1211:        struct addrinfo hints;
        !          1212: 
        !          1213:        memset(&hints, 0, sizeof(hints));
        !          1214:        /* hints.ai_flags = AI_ADDRCONFIG; */
        !          1215: #ifdef AI_NUMERICSERV
        !          1216:        hints.ai_flags = AI_NUMERICSERV;
        !          1217: #endif
        !          1218:        hints.ai_socktype = SOCK_STREAM;
        !          1219:        hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
        !          1220:        /* hints.ai_protocol = IPPROTO_TCP; */
        !          1221:        snprintf(port_str, sizeof(port_str), "%hu", port);
        !          1222:        strcpy(hostname, host);
        !          1223:        if(!strncmp(host, "fe80", 4))
        !          1224:        {
        !          1225:                printf("Using an linklocal address\n");
        !          1226:                strcpy(ifname, "%");
        !          1227:                snprintf(tmp, sizeof(tmp), "%d", linklocal_index);
        !          1228:                strcat(ifname, tmp);
        !          1229:                strcat(hostname, ifname);
        !          1230:                printf("host: %s\n", hostname);
        !          1231:        }
        !          1232:        n = getaddrinfo(hostname, port_str, &hints, &ai);
        !          1233:        if(n != 0)
        !          1234:        {
        !          1235:                fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
        !          1236:                return -1;
        !          1237:        }
        !          1238:        s = -1;
        !          1239:        for(p = ai; p; p = p->ai_next)
        !          1240:        {
        !          1241: #ifdef DEBUG
        !          1242:                char tmp_host[256];
        !          1243:                char tmp_service[256];
        !          1244:                printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
        !          1245:                       p->ai_family, p->ai_socktype, p->ai_protocol, p->ai_addrlen);
        !          1246:                getnameinfo(p->ai_addr, p->ai_addrlen, tmp_host, sizeof(tmp_host),
        !          1247:                            tmp_service, sizeof(tmp_service),
        !          1248:                            NI_NUMERICHOST | NI_NUMERICSERV);
        !          1249:                printf(" host=%s service=%s\n", tmp_host, tmp_service);
        !          1250: #endif
        !          1251:                inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr), result, INET6_ADDRSTRLEN);
        !          1252:                return 0;
        !          1253:        }
        !          1254:        freeaddrinfo(ai);
        !          1255: }
        !          1256: #endif
        !          1257: 
        !          1258: /* Check the security policy right */
        !          1259: static int
        !          1260: PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port)
        !          1261: {
        !          1262:        int n;
        !          1263:        /* Pinhole InternalClient address must correspond to the action sender */
        !          1264:        syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)");
        !          1265:        char senderAddr[INET6_ADDRSTRLEN]="";
        !          1266:        //char str[INET6_ADDRSTRLEN]="";
        !          1267:        //connecthostport(int_ip, *int_port, str);
        !          1268:        //printf("int_ip: %s / str: %s\n", int_ip, str);
        !          1269:        
        !          1270:        struct addrinfo hints, *ai, *p;
        !          1271:        struct in6_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */ //IPv6 Modification
        !          1272: 
        !          1273:        hints.ai_socktype = SOCK_STREAM;
        !          1274:        hints.ai_family = AF_UNSPEC;
        !          1275: 
        !          1276:        /* if ip not valid assume hostname and convert */
        !          1277:        if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0) //IPv6 Modification
        !          1278:        {
        !          1279: 
        !          1280:                n = getaddrinfo(int_ip, NULL, &hints, &ai);//hp = gethostbyname(int_ip);
        !          1281:                if(!n && ai->ai_family == AF_INET6) //IPv6 Modification
        !          1282:                {
        !          1283:                        for(p = ai; p; p = p->ai_next)//ptr = hp->h_addr_list; ptr && *ptr; ptr++)
        !          1284:                        {
        !          1285:                                inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); ///IPv6 Modification
        !          1286:                                result_ip = *((struct in6_addr *) p);
        !          1287:                                fprintf(stderr, "upnpsoap / AddPinhole: assuming int addr = %s", int_ip);
        !          1288:                                /* TODO : deal with more than one ip per hostname */
        !          1289:                                break;
        !          1290:                        }
        !          1291:                }
        !          1292:                else
        !          1293:                {
        !          1294:                        syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
        !          1295:                        SoapError(h, 402, "Invalid Args");
        !          1296:                        return -1;
        !          1297:                }
        !          1298:         freeaddrinfo(p);
        !          1299:        }
        !          1300: 
        !          1301:        if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN)<=0)
        !          1302:        {
        !          1303:                //printf("Failed to inet_ntop\n");
        !          1304:                syslog(LOG_ERR, "inet_ntop: %m");
        !          1305:        }
        !          1306: #ifdef DEBUG
        !          1307:        printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t  to intClient @: %s\n", senderAddr, int_ip);
        !          1308: #endif
        !          1309:        if(strcmp(senderAddr, int_ip) != 0)
        !          1310:        if(h->clientaddr_v6.s6_addr != result_ip.s6_addr)
        !          1311:        {
        !          1312:                syslog(LOG_INFO, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
        !          1313:                       senderAddr, int_ip);
        !          1314:                SoapError(h, 606, "Action not authorized");
        !          1315:                return 0;
        !          1316:        }
        !          1317: 
        !          1318:        /* Pinhole InternalPort must be greater than or equal to 1024 */
        !          1319:        if (*int_port < 1024)
        !          1320:        {
        !          1321:                syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
        !          1322:                       senderAddr);
        !          1323:                SoapError(h, 606, "Action not authorized");
        !          1324:                return 0;
        !          1325:        }
        !          1326:        return 1;
        !          1327: }
        !          1328: 
        !          1329: static void
        !          1330: AddPinhole(struct upnphttp * h, const char * action)
        !          1331: {
        !          1332:        int r;
        !          1333:        static const char resp[] =
        !          1334:                "<u:%sResponse "
        !          1335:                "xmlns:u=\"%s\">"
        !          1336:                "<UniqueID>%d</UniqueID>"
        !          1337:                "</u:%sResponse>";
        !          1338:        char body[512];
        !          1339:        int bodylen;
        !          1340:        struct NameValueParserData data;
        !          1341:        char * rem_host, * rem_port, * int_ip, * int_port, * protocol, * leaseTime;
        !          1342:        int uid = 0;
        !          1343:        unsigned short iport, rport;
        !          1344: 
        !          1345:        if(CheckStatus(h)==0)
        !          1346:                return;
        !          1347: 
        !          1348:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
        !          1349:        rem_host = GetValueFromNameValueList(&data, "RemoteHost");
        !          1350:        rem_port = GetValueFromNameValueList(&data, "RemotePort");
        !          1351:        int_ip = GetValueFromNameValueList(&data, "InternalClient");
        !          1352:        int_port = GetValueFromNameValueList(&data, "InternalPort");
        !          1353:        protocol = GetValueFromNameValueList(&data, "Protocol");
        !          1354:        leaseTime = GetValueFromNameValueList(&data, "LeaseTime");
        !          1355: 
        !          1356:        rport = (unsigned short)atoi(rem_port);
        !          1357:        iport = (unsigned short)atoi(int_port);
        !          1358: 
        !          1359:        // **  As there is no security policy, InternalClient must be equal to the CP's IP address.
        !          1360:        if(DataVerification(h, int_ip, &iport, protocol, leaseTime) == 0
        !          1361:           || PinholeVerification(h, int_ip, &iport) <= 0)
        !          1362:        {
        !          1363:                ClearNameValueList(&data);
        !          1364:                return ;
        !          1365:        }
        !          1366: 
        !          1367:        // ** RemoteHost can be wilcarded or an IDN.
        !          1368:        /*printf("\trem_host: %s\n", rem_host);*/
        !          1369:        if (rem_host!=NULL && !strchr(rem_host, ':'))
        !          1370:        {
        !          1371:                ClearNameValueList(&data);
        !          1372:                SoapError(h, 402, "Invalid Args");
        !          1373:                return;
        !          1374:        }
        !          1375:        /*printf("\tAddr check passed.\n");*/
        !          1376: 
        !          1377:        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);
        !          1378: 
        !          1379:        r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, protocol, leaseTime, &uid);
        !          1380: 
        !          1381:        switch(r)
        !          1382:        {
        !          1383:                case 1:         /* success */
        !          1384:                        bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", uid, action);
        !          1385:                        BuildSendAndCloseSoapResp(h, body, bodylen);
        !          1386:                        break;
        !          1387:                case -1:        /* not permitted */
        !          1388:                        SoapError(h, 701, "PinholeSpaceExhausted");
        !          1389:                        break;
        !          1390:                default:
        !          1391:                        SoapError(h, 501, "ActionFailed");
        !          1392:                        break;
        !          1393:        }
        !          1394:        ClearNameValueList(&data);
        !          1395: }
        !          1396: 
        !          1397: static void
        !          1398: UpdatePinhole(struct upnphttp * h, const char * action)
        !          1399: {
        !          1400:        int r, n;
        !          1401:        static const char resp[] =
        !          1402:                "<u:UpdatePinholeResponse "
        !          1403:                "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
        !          1404:                "</u:UpdatePinholeResponse>";
        !          1405:        struct NameValueParserData data;
        !          1406:        const char * uid, * leaseTime;
        !          1407:        char iaddr[40], proto[6], lt[12];
        !          1408:        unsigned short iport;
        !          1409: 
        !          1410:        if(CheckStatus(h)==0)
        !          1411:                return;
        !          1412: 
        !          1413:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
        !          1414:        uid = GetValueFromNameValueList(&data, "UniqueID");
        !          1415:        leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime");
        !          1416: 
        !          1417:        if(!uid || !leaseTime || !atoi(leaseTime) || atoi(leaseTime) > 86400)
        !          1418:        {
        !          1419:                ClearNameValueList(&data);
        !          1420:                SoapError(h, 402, "Invalid Args");
        !          1421:                return;
        !          1422:        }
        !          1423: 
        !          1424:        // Check that client is not deleting an pinhole he doesn't have access to, because of its public access
        !          1425:        n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
        !          1426:        if (n > 0)
        !          1427:        {
        !          1428:                if(PinholeVerification(h, iaddr, &iport)==0)
        !          1429:                {
        !          1430:                        ClearNameValueList(&data);
        !          1431:                        return ;
        !          1432:                }
        !          1433:        }
        !          1434: 
        !          1435:        syslog(LOG_INFO, "%s: (inbound) updating lease duration to %s for pinhole with ID: %s", action, leaseTime, uid);
        !          1436: 
        !          1437:        r = upnp_update_inboundpinhole(uid, leaseTime);
        !          1438: 
        !          1439:        if(r < 0)
        !          1440:        {
        !          1441:                if(r == -4 || r == -1)
        !          1442:                        SoapError(h, 704, "NoSuchEntry");
        !          1443:                else
        !          1444:                        SoapError(h, 501, "ActionFailed");
        !          1445:        }
        !          1446:        else
        !          1447:        {
        !          1448:                BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
        !          1449:        }
        !          1450:        ClearNameValueList(&data);
        !          1451: }
        !          1452: 
        !          1453: static void
        !          1454: GetOutboundPinholeTimeout(struct upnphttp * h, const char * action)
        !          1455: {
        !          1456:        if (!ipv6fc_firewall_enabled)
        !          1457:        {
        !          1458:                SoapError(h, 702, "FirewallDisabed");
        !          1459:                return;
        !          1460:        }
        !          1461:        int r;
        !          1462: 
        !          1463:        static const char resp[] =
        !          1464:                "<u:%sResponse "
        !          1465:                "xmlns:u=\"%s\">"
        !          1466:                "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
        !          1467:                "</u:%sResponse>";
        !          1468: 
        !          1469:        char body[512];
        !          1470:        int bodylen;
        !          1471:        struct NameValueParserData data;
        !          1472:        char * int_ip, * int_port, * rem_host, * rem_port, * protocol;
        !          1473:        int opt=0, proto=0;
        !          1474:        unsigned short iport, rport;
        !          1475: 
        !          1476:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
        !          1477:        int_ip = GetValueFromNameValueList(&data, "InternalClient");
        !          1478:        int_port = GetValueFromNameValueList(&data, "InternalPort");
        !          1479:        rem_host = GetValueFromNameValueList(&data, "RemoteHost");
        !          1480:        rem_port = GetValueFromNameValueList(&data, "RemotePort");
        !          1481:        protocol = GetValueFromNameValueList(&data, "Protocol");
        !          1482: 
        !          1483:        rport = (unsigned short)atoi(rem_port);
        !          1484:        iport = (unsigned short)atoi(int_port);
        !          1485:        proto = atoi(protocol);
        !          1486: 
        !          1487:        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);
        !          1488: 
        !          1489:        r = upnp_check_outbound_pinhole(proto, &opt);
        !          1490: 
        !          1491:        switch(r)
        !          1492:        {
        !          1493:                case 1: /* success */
        !          1494:                        bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", opt, action);
        !          1495:                        BuildSendAndCloseSoapResp(h, body, bodylen);
        !          1496:                        break;
        !          1497:                case -5:        /* Protocol not supported */
        !          1498:                        SoapError(h, 705, "ProtocolNotSupported");
        !          1499:                        break;
        !          1500:                default:
        !          1501:                        SoapError(h, 501, "ActionFailed");
        !          1502:        }
        !          1503:        ClearNameValueList(&data);
        !          1504: }
        !          1505: 
        !          1506: static void
        !          1507: DeletePinhole(struct upnphttp * h, const char * action)
        !          1508: {
        !          1509:        if(CheckStatus(h)==0)
        !          1510:                return;
        !          1511:        int r, n;
        !          1512: 
        !          1513:        static const char resp[] =
        !          1514:                "<u:DeletePinholeResponse "
        !          1515:                "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
        !          1516:                "</u:DeletePinholeResponse>";
        !          1517: 
        !          1518:        struct NameValueParserData data;
        !          1519:        const char * uid;
        !          1520:        char iaddr[40], proto[6], lt[12];
        !          1521:        unsigned short iport;
        !          1522: 
        !          1523:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
        !          1524:        uid = GetValueFromNameValueList(&data, "UniqueID");
        !          1525: 
        !          1526:        if(!uid)
        !          1527:        {
        !          1528:                ClearNameValueList(&data);
        !          1529:                SoapError(h, 402, "Invalid Args");
        !          1530:                return;
        !          1531:        }
        !          1532: 
        !          1533:        // Check that client is not deleting an pinhole he doesn't have access to, because of its public access
        !          1534:        n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
        !          1535:        if (n > 0)
        !          1536:        {
        !          1537:                if(PinholeVerification(h, iaddr, &iport)==0)
        !          1538:                {
        !          1539:                        ClearNameValueList(&data);
        !          1540:                        return ;
        !          1541:                }
        !          1542:        }
        !          1543: 
        !          1544:        syslog(LOG_INFO, "%s: (inbound) delete pinhole with ID: %s", action, uid);
        !          1545: 
        !          1546:        r = upnp_delete_inboundpinhole(uid);
        !          1547: 
        !          1548:        if(r <= 0)
        !          1549:        {
        !          1550:                syslog(LOG_INFO, "%s: (inbound) failed to remove pinhole with ID: %s", action, uid);
        !          1551:                if(r==-4)
        !          1552:                        SoapError(h, 704, "NoSuchEntry");
        !          1553:                else
        !          1554:                        SoapError(h, 501, "ActionFailed");
        !          1555:        }
        !          1556:        else
        !          1557:        {
        !          1558:                syslog(LOG_INFO, "%s: (inbound) pinhole successfully removed", action);
        !          1559:                BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
        !          1560:        }
        !          1561:        ClearNameValueList(&data);
        !          1562: }
        !          1563: 
        !          1564: static void
        !          1565: CheckPinholeWorking(struct upnphttp * h, const char * action)
        !          1566: {
        !          1567:        if(CheckStatus(h)==0)
        !          1568:                return;
        !          1569:        int r, d;
        !          1570: 
        !          1571:        static const char resp[] =
        !          1572:                "<u:%sResponse "
        !          1573:                "xmlns:u=\"%s\">"
        !          1574:                "<IsWorking>%d</IsWorking>"
        !          1575:                "</u:%sResponse>";
        !          1576: 
        !          1577:        char body[512];
        !          1578:        int bodylen;
        !          1579:        struct NameValueParserData data;
        !          1580:        const char * uid;
        !          1581:        char eaddr[40], iaddr[40], proto[6], lt[12];
        !          1582:        unsigned short eport, iport;
        !          1583:        int isWorking = 0;
        !          1584: 
        !          1585:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
        !          1586:        uid = GetValueFromNameValueList(&data, "UniqueID");
        !          1587: 
        !          1588:        if(!uid)
        !          1589:        {
        !          1590:                ClearNameValueList(&data);
        !          1591:                SoapError(h, 402, "Invalid Args");
        !          1592:                return;
        !          1593:        }
        !          1594: 
        !          1595:        // Check that client is not checking a pinhole he doesn't have access to, because of its public access
        !          1596:        r = upnp_get_pinhole_info(eaddr, eport, iaddr, &iport, proto, uid, lt);
        !          1597:        if (r > 0)
        !          1598:        {
        !          1599:                if(PinholeVerification(h, iaddr, &iport)==0)
        !          1600:                {
        !          1601:                        ClearNameValueList(&data);
        !          1602:                        return ;
        !          1603:                }
        !          1604:                else
        !          1605:                {
        !          1606:                        int rulenum_used, rulenum = 0;
        !          1607:                        d = upnp_check_pinhole_working(uid, eaddr, iaddr, &eport, &iport, proto, &rulenum_used);
        !          1608:                        if(d < 0)
        !          1609:                        {
        !          1610:                                if(d == -4)
        !          1611:                                {
        !          1612:                                        syslog(LOG_INFO, "%s: rule for ID=%s, no trace found for this pinhole", action, uid);
        !          1613:                                        SoapError(h, 709, "NoPacketSent");
        !          1614:                                        ClearNameValueList(&data);
        !          1615:                                        return ;
        !          1616:                                }
        !          1617:                                else
        !          1618:                                {
        !          1619:                                // d==-5 not same table // d==-6 not same chain // d==-7 not found a rule but policy traced
        !          1620:                                        isWorking=0;
        !          1621:                                        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"));
        !          1622:                                        bodylen = snprintf(body, sizeof(body), resp,
        !          1623:                                                action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
        !          1624:                                                isWorking, action);
        !          1625:                                        BuildSendAndCloseSoapResp(h, body, bodylen);
        !          1626:                                }
        !          1627:                        }
        !          1628:                        else
        !          1629:                        {
        !          1630:                                /*check_rule_from_file(uid, &rulenum);*/
        !          1631:                                if(rulenum_used == rulenum)
        !          1632:                                {
        !          1633:                                        isWorking=1;
        !          1634:                                        syslog(LOG_INFO, "%s: rule for ID=%s is working properly", action, uid);
        !          1635:                                }
        !          1636:                                else
        !          1637:                                {
        !          1638:                                        isWorking=0;
        !          1639:                                        syslog(LOG_INFO, "%s: rule for ID=%s is not working", action, uid);
        !          1640:                                }
        !          1641:                                bodylen = snprintf(body, sizeof(body), resp,
        !          1642:                                                action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
        !          1643:                                                isWorking, action);
        !          1644:                                BuildSendAndCloseSoapResp(h, body, bodylen);
        !          1645:                        }
        !          1646:                }
        !          1647:        }
        !          1648:        else if(r == -4 || r == -1)
        !          1649:        {
        !          1650:                SoapError(h, 704, "NoSuchEntry");
        !          1651:        }
        !          1652:        else
        !          1653:        {
        !          1654:                SoapError(h, 501, "ActionFailed");
        !          1655:                ClearNameValueList(&data);
        !          1656:                return ;
        !          1657:        }
        !          1658:        ClearNameValueList(&data);
        !          1659: }
        !          1660: 
        !          1661: static void
        !          1662: GetPinholePackets(struct upnphttp * h, const char * action)
        !          1663: {
        !          1664:        if(CheckStatus(h)==0)
        !          1665:                return;
        !          1666:        int r, n;
        !          1667: 
        !          1668:        static const char resp[] =
        !          1669:                "<u:%sResponse "
        !          1670:                "xmlns:u=\"%s\">"
        !          1671:                "<PinholePackets>%d</PinholePackets>"
        !          1672:                "</u:%sResponse>";
        !          1673: 
        !          1674:        char body[512];
        !          1675:        int bodylen;
        !          1676:        struct NameValueParserData data;
        !          1677:        const char * uid;
        !          1678:        char iaddr[40], proto[6], lt[12];
        !          1679:        unsigned short iport;
        !          1680:        int pinholePackets = 0;
        !          1681: 
        !          1682:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
        !          1683:        uid = GetValueFromNameValueList(&data, "UniqueID");
        !          1684: 
        !          1685:        if(!uid)
        !          1686:        {
        !          1687:                ClearNameValueList(&data);
        !          1688:                SoapError(h, 402, "Invalid Args");
        !          1689:                return;
        !          1690:        }
        !          1691: 
        !          1692:        // Check that client is not getting infos of a pinhole he doesn't have access to, because of its public access
        !          1693:        r = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
        !          1694:        if (r > 0)
        !          1695:        {
        !          1696:                if(PinholeVerification(h, iaddr, &iport)==0)
        !          1697:                {
        !          1698:                        ClearNameValueList(&data);
        !          1699:                        return ;
        !          1700:                }
        !          1701:        }
        !          1702: 
        !          1703:        n = upnp_get_pinhole_packets(uid, &pinholePackets);
        !          1704:        if(n > 0)
        !          1705:        {
        !          1706:                bodylen = snprintf(body, sizeof(body), resp,
        !          1707:                                action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
        !          1708:                                pinholePackets, action);
        !          1709:                BuildSendAndCloseSoapResp(h, body, bodylen);
        !          1710:        }
        !          1711:        else if(r == -4 || r == -1)
        !          1712:        {
        !          1713:                SoapError(h, 704, "NoSuchEntry");
        !          1714:        }
        !          1715:        else
        !          1716:        {
        !          1717:                SoapError(h, 501, "ActionFailed");
        !          1718:                ClearNameValueList(&data);
        !          1719:                return ;
        !          1720:        }
        !          1721:        ClearNameValueList(&data);
        !          1722: }
        !          1723: #endif
        !          1724: 
        !          1725: 
1.1       misho    1726: /* Windows XP as client send the following requests :
                   1727:  * GetConnectionTypeInfo
                   1728:  * GetNATRSIPStatus
                   1729:  * ? GetTotalBytesSent - WANCommonInterfaceConfig
                   1730:  * ? GetTotalBytesReceived - idem
                   1731:  * ? GetTotalPacketsSent - idem
                   1732:  * ? GetTotalPacketsReceived - idem
                   1733:  * GetCommonLinkProperties - idem
                   1734:  * GetStatusInfo - WANIPConnection
                   1735:  * GetExternalIPAddress
                   1736:  * QueryStateVariable / ConnectionStatus!
                   1737:  */
                   1738: static const struct 
                   1739: {
                   1740:        const char * methodName; 
                   1741:        void (*methodImpl)(struct upnphttp *, const char *);
                   1742: }
                   1743: soapMethods[] =
                   1744: {
1.1.1.2 ! misho    1745:        /* WANCommonInterfaceConfig */
1.1       misho    1746:        { "QueryStateVariable", QueryStateVariable},
                   1747:        { "GetTotalBytesSent", GetTotalBytesSent},
                   1748:        { "GetTotalBytesReceived", GetTotalBytesReceived},
                   1749:        { "GetTotalPacketsSent", GetTotalPacketsSent},
                   1750:        { "GetTotalPacketsReceived", GetTotalPacketsReceived},
                   1751:        { "GetCommonLinkProperties", GetCommonLinkProperties},
                   1752:        { "GetStatusInfo", GetStatusInfo},
1.1.1.2 ! misho    1753:        /* WANIPConnection */
        !          1754:        { "GetConnectionTypeInfo", GetConnectionTypeInfo },
        !          1755:        { "GetNATRSIPStatus", GetNATRSIPStatus},
        !          1756:        { "GetExternalIPAddress", GetExternalIPAddress},
        !          1757:        { "AddPortMapping", AddPortMapping},
        !          1758:        { "DeletePortMapping", DeletePortMapping},
        !          1759:        { "GetGenericPortMappingEntry", GetGenericPortMappingEntry},
        !          1760:        { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry},
1.1       misho    1761: /* Required in WANIPConnection:2 */
                   1762:        { "SetConnectionType", SetConnectionType},
                   1763:        { "RequestConnection", RequestConnection},
                   1764:        { "ForceTermination", ForceTermination},
                   1765:        { "AddAnyPortMapping", AddAnyPortMapping},
                   1766:        { "DeletePortMappingRange", DeletePortMappingRange},
                   1767:        { "GetListOfPortMappings", GetListOfPortMappings},
                   1768: #ifdef ENABLE_L3F_SERVICE
1.1.1.2 ! misho    1769:        /* Layer3Forwarding */
1.1       misho    1770:        { "SetDefaultConnectionService", SetDefaultConnectionService},
                   1771:        { "GetDefaultConnectionService", GetDefaultConnectionService},
                   1772: #endif
1.1.1.2 ! misho    1773: #ifdef ENABLE_6FC_SERVICE
        !          1774:        /* WANIPv6FirewallControl */
        !          1775:        { "GetFirewallStatus", GetFirewallStatus},
        !          1776:        { "AddPinhole", AddPinhole},
        !          1777:        { "UpdatePinhole", UpdatePinhole},
        !          1778:        { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout},
        !          1779:        { "DeletePinhole", DeletePinhole},
        !          1780:        { "CheckPinholeWorking", CheckPinholeWorking},
        !          1781:        { "GetPinholePackets", GetPinholePackets},
        !          1782: #endif
1.1       misho    1783:        { 0, 0 }
                   1784: };
                   1785: 
                   1786: void
                   1787: ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
                   1788: {
                   1789:        char * p;
                   1790:        char * p2;
                   1791:        int i, len, methodlen;
                   1792: 
                   1793:        i = 0;
                   1794:        p = strchr(action, '#');
                   1795: 
                   1796:        if(p)
                   1797:        {
                   1798:                p++;
                   1799:                p2 = strchr(p, '"');
                   1800:                if(p2)
                   1801:                        methodlen = p2 - p;
                   1802:                else
                   1803:                        methodlen = n - (p - action);
                   1804:                /*syslog(LOG_DEBUG, "SoapMethod: %.*s", methodlen, p);*/
                   1805:                while(soapMethods[i].methodName)
                   1806:                {
                   1807:                        len = strlen(soapMethods[i].methodName);
                   1808:                        if(strncmp(p, soapMethods[i].methodName, len) == 0)
                   1809:                        {
                   1810:                                soapMethods[i].methodImpl(h, soapMethods[i].methodName);
                   1811:                                return;
                   1812:                        }
                   1813:                        i++;
                   1814:                }
                   1815: 
                   1816:                syslog(LOG_NOTICE, "SoapMethod: Unknown: %.*s", methodlen, p);
                   1817:        }
                   1818: 
                   1819:        SoapError(h, 401, "Invalid Action");
                   1820: }
                   1821: 
                   1822: /* Standard Errors:
                   1823:  *
                   1824:  * errorCode errorDescription Description
                   1825:  * --------    ---------------- -----------
                   1826:  * 401                 Invalid Action  No action by that name at this service.
                   1827:  * 402                 Invalid Args    Could be any of the following: not enough in args,
                   1828:  *                                                     too many in args, no in arg by that name, 
                   1829:  *                                                     one or more in args are of the wrong data type.
                   1830:  * 403                 Out of Sync     Out of synchronization.
                   1831:  * 501                 Action Failed   May be returned in current state of service
                   1832:  *                                                     prevents invoking that action.
                   1833:  * 600-699     TBD                     Common action errors. Defined by UPnP Forum
                   1834:  *                                                     Technical Committee.
                   1835:  * 700-799     TBD                     Action-specific errors for standard actions.
                   1836:  *                                                     Defined by UPnP Forum working committee.
                   1837:  * 800-899     TBD                     Action-specific errors for non-standard actions. 
                   1838:  *                                                     Defined by UPnP vendor.
                   1839: */
                   1840: void
                   1841: SoapError(struct upnphttp * h, int errCode, const char * errDesc)
                   1842: {
                   1843:        static const char resp[] = 
                   1844:                "<s:Envelope "
                   1845:                "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
                   1846:                "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                   1847:                "<s:Body>"
                   1848:                "<s:Fault>"
                   1849:                "<faultcode>s:Client</faultcode>"
                   1850:                "<faultstring>UPnPError</faultstring>"
                   1851:                "<detail>"
                   1852:                "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
                   1853:                "<errorCode>%d</errorCode>"
                   1854:                "<errorDescription>%s</errorDescription>"
                   1855:                "</UPnPError>"
                   1856:                "</detail>"
                   1857:                "</s:Fault>"
                   1858:                "</s:Body>"
                   1859:                "</s:Envelope>";
                   1860: 
                   1861:        char body[2048];
                   1862:        int bodylen;
                   1863: 
                   1864:        syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc);
                   1865:        bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc);
                   1866:        BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen);
                   1867:        SendResp_upnphttp(h);
                   1868:        CloseSocket_upnphttp(h);
                   1869: }
                   1870: 

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