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

1.1       misho       1: /* $Id: upnpsoap.c,v 1.66 2011/01/01 20:17:44 nanard Exp $ */
                      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"
                     27: 
                     28: static void
                     29: BuildSendAndCloseSoapResp(struct upnphttp * h,
                     30:                           const char * body, int bodylen)
                     31: {
                     32:        static const char beforebody[] =
                     33:                "<?xml version=\"1.0\"?>\r\n"
                     34:                "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
                     35:                "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                     36:                "<s:Body>";
                     37: 
                     38:        static const char afterbody[] =
                     39:                "</s:Body>"
                     40:                "</s:Envelope>\r\n";
                     41: 
                     42:        BuildHeader_upnphttp(h, 200, "OK",  sizeof(beforebody) - 1
                     43:                + sizeof(afterbody) - 1 + bodylen );
                     44: 
                     45:        memcpy(h->res_buf + h->res_buflen, beforebody, sizeof(beforebody) - 1);
                     46:        h->res_buflen += sizeof(beforebody) - 1;
                     47: 
                     48:        memcpy(h->res_buf + h->res_buflen, body, bodylen);
                     49:        h->res_buflen += bodylen;
                     50: 
                     51:        memcpy(h->res_buf + h->res_buflen, afterbody, sizeof(afterbody) - 1);
                     52:        h->res_buflen += sizeof(afterbody) - 1;
                     53: 
                     54:        SendResp_upnphttp(h);
                     55:        CloseSocket_upnphttp(h);
                     56: }
                     57: 
                     58: static void
                     59: GetConnectionTypeInfo(struct upnphttp * h, const char * action)
                     60: {
                     61:        static const char resp[] =
                     62:                "<u:GetConnectionTypeInfoResponse "
                     63:                "xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"
                     64:                "<NewConnectionType>IP_Routed</NewConnectionType>"
                     65:                "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
                     66:                "</u:GetConnectionTypeInfoResponse>";
                     67:        BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                     68: }
                     69: 
                     70: static void
                     71: GetTotalBytesSent(struct upnphttp * h, const char * action)
                     72: {
                     73:        int r;
                     74: 
                     75:        static const char resp[] =
                     76:                "<u:%sResponse "
                     77:                "xmlns:u=\"%s\">"
                     78:                "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
                     79:                "</u:%sResponse>";
                     80: 
                     81:        char body[512];
                     82:        int bodylen;
                     83:        struct ifdata data;
                     84: 
                     85:        r = getifstats(ext_if_name, &data);
                     86:        bodylen = snprintf(body, sizeof(body), resp,
                     87:                 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
                     88:              r<0?0:data.obytes, action);
                     89:        BuildSendAndCloseSoapResp(h, body, bodylen);
                     90: }
                     91: 
                     92: static void
                     93: GetTotalBytesReceived(struct upnphttp * h, const char * action)
                     94: {
                     95:        int r;
                     96: 
                     97:        static const char resp[] =
                     98:                "<u:%sResponse "
                     99:                "xmlns:u=\"%s\">"
                    100:                "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
                    101:                "</u:%sResponse>";
                    102: 
                    103:        char body[512];
                    104:        int bodylen;
                    105:        struct ifdata data;
                    106: 
                    107:        r = getifstats(ext_if_name, &data);
                    108:        bodylen = snprintf(body, sizeof(body), resp,
                    109:                 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
                    110:                 r<0?0:data.ibytes, action);
                    111:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    112: }
                    113: 
                    114: static void
                    115: GetTotalPacketsSent(struct upnphttp * h, const char * action)
                    116: {
                    117:        int r;
                    118: 
                    119:        static const char resp[] =
                    120:                "<u:%sResponse "
                    121:                "xmlns:u=\"%s\">"
                    122:                "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
                    123:                "</u:%sResponse>";
                    124: 
                    125:        char body[512];
                    126:        int bodylen;
                    127:        struct ifdata data;
                    128: 
                    129:        r = getifstats(ext_if_name, &data);
                    130:        bodylen = snprintf(body, sizeof(body), resp,
                    131:                 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
                    132:                 r<0?0:data.opackets, action);
                    133:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    134: }
                    135: 
                    136: static void
                    137: GetTotalPacketsReceived(struct upnphttp * h, const char * action)
                    138: {
                    139:        int r;
                    140: 
                    141:        static const char resp[] =
                    142:                "<u:%sResponse "
                    143:                "xmlns:u=\"%s\">"
                    144:                "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
                    145:                "</u:%sResponse>";
                    146: 
                    147:        char body[512];
                    148:        int bodylen;
                    149:        struct ifdata data;
                    150: 
                    151:        r = getifstats(ext_if_name, &data);
                    152:        bodylen = snprintf(body, sizeof(body), resp,
                    153:                 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
                    154:                 r<0?0:data.ipackets, action);
                    155:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    156: }
                    157: 
                    158: static void
                    159: GetCommonLinkProperties(struct upnphttp * h, const char * action)
                    160: {
                    161:        /* WANAccessType : set depending on the hardware :
                    162:         * DSL, POTS (plain old Telephone service), Cable, Ethernet */
                    163:        static const char resp[] =
                    164:                "<u:%sResponse "
                    165:                "xmlns:u=\"%s\">"
                    166:                /*"<NewWANAccessType>DSL</NewWANAccessType>"*/
                    167:                "<NewWANAccessType>Cable</NewWANAccessType>"
                    168:                "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
                    169:                "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
                    170:                "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
                    171:                "</u:%sResponse>";
                    172: 
                    173:        char body[2048];
                    174:        int bodylen;
                    175:        struct ifdata data;
                    176:        const char * status = "Up";     /* Up, Down (Required),
                    177:                                     * Initializing, Unavailable (Optional) */
                    178:        char ext_ip_addr[INET_ADDRSTRLEN];
                    179: 
                    180:        if((downstream_bitrate == 0) || (upstream_bitrate == 0))
                    181:        {
                    182:                if(getifstats(ext_if_name, &data) >= 0)
                    183:                {
                    184:                        if(downstream_bitrate == 0) downstream_bitrate = data.baudrate;
                    185:                        if(upstream_bitrate == 0) upstream_bitrate = data.baudrate;
                    186:                }
                    187:        }
                    188:        if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0) {
                    189:                status = "Down";
                    190:        }
                    191:        bodylen = snprintf(body, sizeof(body), resp,
                    192:            action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
                    193:                upstream_bitrate, downstream_bitrate,
                    194:            status, action);
                    195:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    196: }
                    197: 
                    198: static void
                    199: GetStatusInfo(struct upnphttp * h, const char * action)
                    200: {
                    201:        static const char resp[] =
                    202:                "<u:%sResponse "
                    203:                "xmlns:u=\"%s\">"
                    204:                "<NewConnectionStatus>%s</NewConnectionStatus>"
                    205:                "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
                    206:                "<NewUptime>%ld</NewUptime>"
                    207:                "</u:%sResponse>";
                    208: 
                    209:        char body[512];
                    210:        int bodylen;
                    211:        time_t uptime;
                    212:        const char * status = "Connected";
                    213:        /* ConnectionStatus possible values :
                    214:         * Unconfigured, Connecting, Connected, PendingDisconnect,
                    215:         * Disconnecting, Disconnected */
                    216:        char ext_ip_addr[INET_ADDRSTRLEN];
                    217: 
                    218:        if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0) {
                    219:                status = "Disconnected";
                    220:        }
                    221:        uptime = (time(NULL) - startup_time);
                    222:        bodylen = snprintf(body, sizeof(body), resp,
                    223:                action, "urn:schemas-upnp-org:service:WANIPConnection:1",
                    224:                status, (long)uptime, action);  
                    225:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    226: }
                    227: 
                    228: static void
                    229: GetNATRSIPStatus(struct upnphttp * h, const char * action)
                    230: {
                    231:        static const char resp[] =
                    232:                "<u:GetNATRSIPStatusResponse "
                    233:                "xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"
                    234:                "<NewRSIPAvailable>0</NewRSIPAvailable>"
                    235:                "<NewNATEnabled>1</NewNATEnabled>"
                    236:                "</u:GetNATRSIPStatusResponse>";
                    237:        /* 2.2.9. RSIPAvailable
                    238:         * This variable indicates if Realm-specific IP (RSIP) is available
                    239:         * as a feature on the InternetGatewayDevice. RSIP is being defined
                    240:         * in the NAT working group in the IETF to allow host-NATing using
                    241:         * a standard set of message exchanges. It also allows end-to-end
                    242:         * applications that otherwise break if NAT is introduced
                    243:         * (e.g. IPsec-based VPNs).
                    244:         * A gateway that does not support RSIP should set this variable to 0. */
                    245:        BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                    246: }
                    247: 
                    248: static void
                    249: GetExternalIPAddress(struct upnphttp * h, const char * action)
                    250: {
                    251:        static const char resp[] =
                    252:                "<u:%sResponse "
                    253:                "xmlns:u=\"%s\">"
                    254:                "<NewExternalIPAddress>%s</NewExternalIPAddress>"
                    255:                "</u:%sResponse>";
                    256: 
                    257:        char body[512];
                    258:        int bodylen;
                    259:        char ext_ip_addr[INET_ADDRSTRLEN];
                    260: 
                    261: #ifndef MULTIPLE_EXTERNAL_IP
                    262:        if(use_ext_ip_addr)
                    263:        {
                    264:                strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN);
                    265:        }
                    266:        else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0)
                    267:        {
                    268:                syslog(LOG_ERR, "Failed to get ip address for interface %s",
                    269:                        ext_if_name);
                    270:                strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
                    271:        }
                    272: #else
                    273:        int i;
                    274:        strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
                    275:        for(i = 0; i<n_lan_addr; i++)
                    276:        {
                    277:                if( (h->clientaddr.s_addr & lan_addr[i].mask.s_addr)
                    278:                   == (lan_addr[i].addr.s_addr & lan_addr[i].mask.s_addr))
                    279:                {
                    280:                        strncpy(ext_ip_addr, lan_addr[i].ext_ip_str, INET_ADDRSTRLEN);
                    281:                        break;
                    282:                }
                    283:        }
                    284: #endif
                    285:        bodylen = snprintf(body, sizeof(body), resp,
                    286:                      action, "urn:schemas-upnp-org:service:WANIPConnection:1",
                    287:                                  ext_ip_addr, action);
                    288:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    289: }
                    290: 
                    291: static void
                    292: AddPortMapping(struct upnphttp * h, const char * action)
                    293: {
                    294:        int r;
                    295: 
                    296:        static const char resp[] =
                    297:                "<u:AddPortMappingResponse "
                    298:                "xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\"/>";
                    299: 
                    300:        struct NameValueParserData data;
                    301:        char * int_ip, * int_port, * ext_port, * protocol, * desc;
                    302:        char * leaseduration;
                    303:        unsigned short iport, eport;
                    304: 
                    305:        struct hostent *hp; /* getbyhostname() */
                    306:        char ** ptr; /* getbyhostname() */
                    307:        struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
                    308: 
                    309:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    310:        int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
                    311: 
                    312:        if (!int_ip)
                    313:        {
                    314:                ClearNameValueList(&data);
                    315:                SoapError(h, 402, "Invalid Args");
                    316:                return;
                    317:        }
                    318: 
                    319:        /* if ip not valid assume hostname and convert */
                    320:        if (inet_pton(AF_INET, int_ip, &result_ip) <= 0) 
                    321:        {
                    322:                hp = gethostbyname(int_ip);
                    323:                if(hp && hp->h_addrtype == AF_INET) 
                    324:                { 
                    325:                        for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
                    326:                        {
                    327:                                int_ip = inet_ntoa(*((struct in_addr *) *ptr));
                    328:                                result_ip = *((struct in_addr *) *ptr);
                    329:                                /* TODO : deal with more than one ip per hostname */
                    330:                                break;
                    331:                        }
                    332:                } 
                    333:                else 
                    334:                {
                    335:                        syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip); 
                    336:                        ClearNameValueList(&data);
                    337:                        SoapError(h, 402, "Invalid Args");
                    338:                        return;
                    339:                }                               
                    340:        }
                    341: 
                    342:        /* check if NewInternalAddress is the client address */
                    343:        if(GETFLAG(SECUREMODEMASK))
                    344:        {
                    345:                if(h->clientaddr.s_addr != result_ip.s_addr)
                    346:                {
                    347:                        syslog(LOG_INFO, "Client %s tried to redirect port to %s",
                    348:                               inet_ntoa(h->clientaddr), int_ip);
                    349:                        ClearNameValueList(&data);
                    350:                        SoapError(h, 718, "ConflictInMappingEntry");
                    351:                        return;
                    352:                }
                    353:        }
                    354: 
                    355:        int_port = GetValueFromNameValueList(&data, "NewInternalPort");
                    356:        ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
                    357:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    358:        desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
                    359:        leaseduration = GetValueFromNameValueList(&data, "NewLeaseDuration");
                    360: 
                    361:        if (!int_port || !ext_port || !protocol)
                    362:        {
                    363:                ClearNameValueList(&data);
                    364:                SoapError(h, 402, "Invalid Args");
                    365:                return;
                    366:        }
                    367: 
                    368:        eport = (unsigned short)atoi(ext_port);
                    369:        iport = (unsigned short)atoi(int_port);
                    370: 
                    371:        if(leaseduration && atoi(leaseduration)) {
                    372:                /* at the moment, lease duration is always infinite */
                    373:                syslog(LOG_WARNING, "NewLeaseDuration=%s not supported, ignored. (ip=%s, desc='%s')", leaseduration, int_ip, desc);
                    374:        }
                    375: 
                    376:        syslog(LOG_INFO, "%s: ext port %hu to %s:%hu protocol %s for: %s",
                    377:                        action, eport, int_ip, iport, protocol, desc);
                    378: 
                    379:        r = upnp_redirect(eport, int_ip, iport, protocol, desc);
                    380: 
                    381:        ClearNameValueList(&data);
                    382: 
                    383:        /* possible error codes for AddPortMapping :
                    384:         * 402 - Invalid Args
                    385:         * 501 - Action Failed
                    386:         * 715 - Wildcard not permited in SrcAddr
                    387:         * 716 - Wildcard not permited in ExtPort
                    388:         * 718 - ConflictInMappingEntry
                    389:         * 724 - SamePortValuesRequired
                    390:      * 725 - OnlyPermanentLeasesSupported
                    391:              The NAT implementation only supports permanent lease times on
                    392:              port mappings
                    393:      * 726 - RemoteHostOnlySupportsWildcard
                    394:              RemoteHost must be a wildcard and cannot be a specific IP
                    395:              address or DNS name
                    396:      * 727 - ExternalPortOnlySupportsWildcard
                    397:              ExternalPort must be a wildcard and cannot be a specific port
                    398:              value
                    399:      * 728 - NoPortMapsAvailable
                    400:              There are not enough free prots available to complete the mapping
                    401:              (added in IGD v2) */
                    402:        switch(r)
                    403:        {
                    404:        case 0: /* success */
                    405:                BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                    406:                break;
                    407:        case -2:        /* already redirected */
                    408:        case -3:        /* not permitted */
                    409:                SoapError(h, 718, "ConflictInMappingEntry");
                    410:                break;
                    411:        default:
                    412:                SoapError(h, 501, "ActionFailed");
                    413:        }
                    414: }
                    415: 
                    416: /* AddAnyPortMapping was added in WANIPConnection v2 */
                    417: static void
                    418: AddAnyPortMapping(struct upnphttp * h, const char * action)
                    419: {
                    420:        int r;
                    421:        static const char resp[] =
                    422:                "<u:%sResponse "
                    423:                "xmlns:u=\"%s\">"
                    424:                "<NewReservedPort>%hu</NewReservedPort>"
                    425:                "</u:%sResponse>";
                    426: 
                    427:        char body[512];
                    428:        int bodylen;
                    429: 
                    430:        struct NameValueParserData data;
                    431:        const char * int_ip, * int_port, * ext_port, * protocol, * desc;
                    432:        const char * r_host;
                    433:        unsigned short iport, eport;
                    434:        unsigned int leaseduration;
                    435: 
                    436:        struct hostent *hp; /* getbyhostname() */
                    437:        char ** ptr; /* getbyhostname() */
                    438:        struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
                    439: 
                    440:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    441:        r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
                    442:        ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
                    443:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    444:        int_port = GetValueFromNameValueList(&data, "NewInternalPort");
                    445:        int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
                    446:        /* NewEnabled */
                    447:        desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
                    448:        leaseduration = atoi(GetValueFromNameValueList(&data, "NewLeaseDuration"));
                    449:        if(leaseduration == 0)
                    450:                leaseduration = 604800;
                    451: 
                    452:        eport = (unsigned short)atoi(ext_port);
                    453:        iport = (unsigned short)atoi(int_port);
                    454: 
                    455:        if (!int_ip)
                    456:        {
                    457:                ClearNameValueList(&data);
                    458:                SoapError(h, 402, "Invalid Args");
                    459:                return;
                    460:        }
                    461: 
                    462:        /* if ip not valid assume hostname and convert */
                    463:        if (inet_pton(AF_INET, int_ip, &result_ip) <= 0) 
                    464:        {
                    465:                hp = gethostbyname(int_ip);
                    466:                if(hp && hp->h_addrtype == AF_INET) 
                    467:                { 
                    468:                        for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
                    469:                        {
                    470:                                int_ip = inet_ntoa(*((struct in_addr *) *ptr));
                    471:                                result_ip = *((struct in_addr *) *ptr);
                    472:                                /* TODO : deal with more than one ip per hostname */
                    473:                                break;
                    474:                        }
                    475:                } 
                    476:                else 
                    477:                {
                    478:                        syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip); 
                    479:                        ClearNameValueList(&data);
                    480:                        SoapError(h, 402, "Invalid Args");
                    481:                        return;
                    482:                }                               
                    483:        }
                    484: 
                    485:        /* check if NewInternalAddress is the client address */
                    486:        if(GETFLAG(SECUREMODEMASK))
                    487:        {
                    488:                if(h->clientaddr.s_addr != result_ip.s_addr)
                    489:                {
                    490:                        syslog(LOG_INFO, "Client %s tried to redirect port to %s",
                    491:                               inet_ntoa(h->clientaddr), int_ip);
                    492:                        ClearNameValueList(&data);
                    493:                        SoapError(h, 606, "Action not authorized");
                    494:                        return;
                    495:                }
                    496:        }
                    497: 
                    498:        /* TODO : accept a different external port */
                    499:        r = upnp_redirect(eport, int_ip, iport, protocol, desc);
                    500: 
                    501:        ClearNameValueList(&data);
                    502: 
                    503:        switch(r)
                    504:        {
                    505:        case 0: /* success */
                    506:                bodylen = snprintf(body, sizeof(body), resp,
                    507:                              action, "urn:schemas-upnp-org:service:WANIPConnection:2",
                    508:                                          eport, action);
                    509:                BuildSendAndCloseSoapResp(h, body, bodylen);
                    510:                break;
                    511:        case -2:        /* already redirected */
                    512:                SoapError(h, 718, "ConflictInMappingEntry");
                    513:                break;
                    514:        case -3:        /* not permitted */
                    515:                SoapError(h, 606, "Action not authorized");
                    516:                break;
                    517:        default:
                    518:                SoapError(h, 501, "ActionFailed");
                    519:        }
                    520: }
                    521: 
                    522: static void
                    523: GetSpecificPortMappingEntry(struct upnphttp * h, const char * action)
                    524: {
                    525:        int r;
                    526: 
                    527:        static const char resp[] =
                    528:                "<u:%sResponse "
                    529:                "xmlns:u=\"%s\">"
                    530:                "<NewInternalPort>%u</NewInternalPort>"
                    531:                "<NewInternalClient>%s</NewInternalClient>"
                    532:                "<NewEnabled>1</NewEnabled>"
                    533:                "<NewPortMappingDescription>%s</NewPortMappingDescription>"
                    534:                "<NewLeaseDuration>0</NewLeaseDuration>"
                    535:                "</u:%sResponse>";
                    536: 
                    537:        char body[1024];
                    538:        int bodylen;
                    539:        struct NameValueParserData data;
                    540:        const char * r_host, * ext_port, * protocol;
                    541:        unsigned short eport, iport;
                    542:        char int_ip[32];
                    543:        char desc[64];
                    544: 
                    545:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    546:        r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
                    547:        ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
                    548:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    549: 
                    550:        if(!ext_port || !protocol)
                    551:        {
                    552:                ClearNameValueList(&data);
                    553:                SoapError(h, 402, "Invalid Args");
                    554:                return;
                    555:        }
                    556: 
                    557:        eport = (unsigned short)atoi(ext_port);
                    558: 
                    559:        r = upnp_get_redirection_infos(eport, protocol, &iport,
                    560:                                       int_ip, sizeof(int_ip),
                    561:                                       desc, sizeof(desc));
                    562: 
                    563:        if(r < 0)
                    564:        {               
                    565:                SoapError(h, 714, "NoSuchEntryInArray");
                    566:        }
                    567:        else
                    568:        {
                    569:                syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
                    570:                       action,
                    571:                       r_host, ext_port, protocol, int_ip, (unsigned int)iport, desc);
                    572:                bodylen = snprintf(body, sizeof(body), resp,
                    573:                                action, "urn:schemas-upnp-org:service:WANIPConnection:1",
                    574:                                (unsigned int)iport, int_ip, desc,
                    575:                                action);
                    576:                BuildSendAndCloseSoapResp(h, body, bodylen);
                    577:        }
                    578: 
                    579:        ClearNameValueList(&data);
                    580: }
                    581: 
                    582: static void
                    583: DeletePortMapping(struct upnphttp * h, const char * action)
                    584: {
                    585:        int r;
                    586: 
                    587:        static const char resp[] =
                    588:                "<u:DeletePortMappingResponse "
                    589:                "xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"
                    590:                "</u:DeletePortMappingResponse>";
                    591: 
                    592:        struct NameValueParserData data;
                    593:        const char * r_host, * ext_port, * protocol;
                    594:        unsigned short eport;
                    595: 
                    596:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    597:        r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
                    598:        ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
                    599:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    600: 
                    601:        if(!ext_port || !protocol)
                    602:        {
                    603:                ClearNameValueList(&data);
                    604:                SoapError(h, 402, "Invalid Args");
                    605:                return;
                    606:        }
                    607: 
                    608:        eport = (unsigned short)atoi(ext_port);
                    609: 
                    610:        /* TODO : if in secure mode, check the IP */
                    611: 
                    612:        syslog(LOG_INFO, "%s: external port: %hu, protocol: %s", 
                    613:                action, eport, protocol);
                    614: 
                    615:        r = upnp_delete_redirection(eport, protocol);
                    616: 
                    617:        if(r < 0)
                    618:        {       
                    619:                SoapError(h, 714, "NoSuchEntryInArray");
                    620:        }
                    621:        else
                    622:        {
                    623:                BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                    624:        }
                    625: 
                    626:        ClearNameValueList(&data);
                    627: }
                    628: 
                    629: /* DeletePortMappingRange was added in IGD spec v2 */
                    630: static void
                    631: DeletePortMappingRange(struct upnphttp * h, const char * action)
                    632: {
                    633:        static const char resp[] =
                    634:                "<u:DeletePortMappingRangeResponse "
                    635:                "xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:2\">"
                    636:                "</u:DeletePortMappingRangeResponse>";
                    637:        struct NameValueParserData data;
                    638:        const char * protocol;
                    639:        unsigned short startport, endport;
                    640:        int manage;
                    641: 
                    642:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    643:        startport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort"));
                    644:        endport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewEndPort"));
                    645:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    646:        manage = atoi(GetValueFromNameValueList(&data, "NewManage"));
                    647: 
                    648:        /* TODO : implement the method ! */
                    649: 
                    650:        /* possible errors :
                    651:           606 - Action not authorized
                    652:           730 - PortMappingNotFound
                    653:           733 - InconsistentParameter
                    654:         */
                    655:        BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                    656: 
                    657:        ClearNameValueList(&data);
                    658: }
                    659: 
                    660: static void
                    661: GetGenericPortMappingEntry(struct upnphttp * h, const char * action)
                    662: {
                    663:        int r;
                    664:        
                    665:        static const char resp[] =
                    666:                "<u:%sResponse "
                    667:                "xmlns:u=\"%s\">"
                    668:                "<NewRemoteHost></NewRemoteHost>"
                    669:                "<NewExternalPort>%u</NewExternalPort>"
                    670:                "<NewProtocol>%s</NewProtocol>"
                    671:                "<NewInternalPort>%u</NewInternalPort>"
                    672:                "<NewInternalClient>%s</NewInternalClient>"
                    673:                "<NewEnabled>1</NewEnabled>"
                    674:                "<NewPortMappingDescription>%s</NewPortMappingDescription>"
                    675:                "<NewLeaseDuration>0</NewLeaseDuration>"
                    676:                "</u:%sResponse>";
                    677: 
                    678:        int index = 0;
                    679:        unsigned short eport, iport;
                    680:        const char * m_index;
                    681:        char protocol[4], iaddr[32];
                    682:        char desc[64];
                    683:        struct NameValueParserData data;
                    684: 
                    685:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    686:        m_index = GetValueFromNameValueList(&data, "NewPortMappingIndex");
                    687: 
                    688:        if(!m_index)
                    689:        {
                    690:                ClearNameValueList(&data);
                    691:                SoapError(h, 402, "Invalid Args");
                    692:                return;
                    693:        }       
                    694: 
                    695:        index = (int)atoi(m_index);
                    696: 
                    697:        syslog(LOG_INFO, "%s: index=%d", action, index);
                    698: 
                    699:        r = upnp_get_redirection_infos_by_index(index, &eport, protocol, &iport,
                    700:                                             iaddr, sizeof(iaddr),
                    701:                                                desc, sizeof(desc));
                    702: 
                    703:        if(r < 0)
                    704:        {
                    705:                SoapError(h, 713, "SpecifiedArrayIndexInvalid");
                    706:        }
                    707:        else
                    708:        {
                    709:                int bodylen;
                    710:                char body[2048];
                    711:                bodylen = snprintf(body, sizeof(body), resp,
                    712:                        action, "urn:schemas-upnp-org:service:WANIPConnection:1",
                    713:                        (unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc,
                    714:                        action);
                    715:                BuildSendAndCloseSoapResp(h, body, bodylen);
                    716:        }
                    717: 
                    718:        ClearNameValueList(&data);
                    719: }
                    720: 
                    721: /* GetListOfPortMappings was added in the IGD v2 specification */
                    722: static void
                    723: GetListOfPortMappings(struct upnphttp * h, const char * action)
                    724: {
                    725:        static const char resp[] =
                    726:                "<u:%sResponse "
                    727:                "xmlns:u=\"%s\">"
                    728:                "<NewPortListing><![CDATA[%s]]</NewPortListing>"
                    729:                "</u:%sResponse>";
                    730: 
                    731:        char body[512];
                    732:        int bodylen;
                    733: 
                    734:        struct NameValueParserData data;
                    735:        unsigned short startport, endport;
                    736:        const char * protocol;
                    737:        int manage;
                    738:        int number;
                    739: 
                    740:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    741:        startport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort"));
                    742:        endport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewEndPort"));
                    743:        protocol = GetValueFromNameValueList(&data, "NewProtocol");
                    744:        manage = atoi(GetValueFromNameValueList(&data, "NewManage"));
                    745:        number = atoi(GetValueFromNameValueList(&data, "NewNumberOfPorts"));
                    746: 
                    747: /*
                    748: TODO : build the PortMappingList xml document :
                    749: 
                    750: <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
                    751: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    752: xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
                    753: http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
                    754: <p:PortMappingEntry>
                    755: <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
                    756: <p:NewExternalPort>2345</p:NewExternalPort>
                    757: <p:NewProtocol>TCP</p:NewProtocol>
                    758: <p:NewInternalPort>2345</p:NewInternalPort>
                    759: <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
                    760: <p:NewEnabled>1</p:NewEnabled>
                    761: <p:NewDescription>dooom</p:NewDescription>
                    762: <p:NewLeaseTime>345</p:NewLeaseTime>
                    763: </p:PortMappingEntry>
                    764: </p:PortMappingList>
                    765: */
                    766:        bodylen = snprintf(body, sizeof(body), resp,
                    767:                      action, "urn:schemas-upnp-org:service:WANIPConnection:2",
                    768:                                  "", action);
                    769:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    770: 
                    771:        ClearNameValueList(&data);
                    772: }
                    773: 
                    774: #ifdef ENABLE_L3F_SERVICE
                    775: static void
                    776: SetDefaultConnectionService(struct upnphttp * h, const char * action)
                    777: {
                    778:        static const char resp[] =
                    779:                "<u:SetDefaultConnectionServiceResponse "
                    780:                "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
                    781:                "</u:SetDefaultConnectionServiceResponse>";
                    782:        struct NameValueParserData data;
                    783:        char * p;
                    784:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    785:        p = GetValueFromNameValueList(&data, "NewDefaultConnectionService");
                    786:        if(p) {
                    787:                syslog(LOG_INFO, "%s(%s) : Ignored", action, p);
                    788:        }
                    789:        ClearNameValueList(&data);
                    790:        BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
                    791: }
                    792: 
                    793: static void
                    794: GetDefaultConnectionService(struct upnphttp * h, const char * action)
                    795: {
                    796:        static const char resp[] =
                    797:                "<u:%sResponse "
                    798:                "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
                    799:                "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
                    800:                "urn:upnp-org:serviceId:WANIPConn1</NewDefaultConnectionService>"
                    801:                "</u:%sResponse>";
                    802:        /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
                    803:         * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
                    804:         * urn:upnp-org:serviceId:WANPPPConn1 */
                    805:        char body[1024];
                    806:        int bodylen;
                    807: 
                    808:        bodylen = snprintf(body, sizeof(body), resp,
                    809:                           action, uuidvalue, action);
                    810:        BuildSendAndCloseSoapResp(h, body, bodylen);
                    811: }
                    812: #endif
                    813: 
                    814: /* Added for compliance with WANIPConnection v2 */
                    815: static void
                    816: SetConnectionType(struct upnphttp * h, const char * action)
                    817: {
                    818:        const char * connection_type;
                    819:        struct NameValueParserData data;
                    820: 
                    821:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    822:        connection_type = GetValueFromNameValueList(&data, "NewConnectionType");
                    823:        /* Unconfigured, IP_Routed, IP_Bridged */
                    824:        ClearNameValueList(&data);
                    825:        /* always return a ReadOnly error */
                    826:        SoapError(h, 731, "ReadOnly");
                    827: }
                    828: 
                    829: /* Added for compliance with WANIPConnection v2 */
                    830: static void
                    831: RequestConnection(struct upnphttp * h, const char * action)
                    832: {
                    833:        SoapError(h, 606, "Action not authorized");
                    834: }
                    835: 
                    836: /* Added for compliance with WANIPConnection v2 */
                    837: static void
                    838: ForceTermination(struct upnphttp * h, const char * action)
                    839: {
                    840:        SoapError(h, 606, "Action not authorized");
                    841: }
                    842: 
                    843: /*
                    844: If a control point calls QueryStateVariable on a state variable that is not
                    845: buffered in memory within (or otherwise available from) the service,
                    846: the service must return a SOAP fault with an errorCode of 404 Invalid Var.
                    847: 
                    848: QueryStateVariable remains useful as a limited test tool but may not be
                    849: part of some future versions of UPnP.
                    850: */
                    851: static void
                    852: QueryStateVariable(struct upnphttp * h, const char * action)
                    853: {
                    854:        static const char resp[] =
                    855:         "<u:%sResponse "
                    856:         "xmlns:u=\"%s\">"
                    857:                "<return>%s</return>"
                    858:         "</u:%sResponse>";
                    859: 
                    860:        char body[512];
                    861:        int bodylen;
                    862:        struct NameValueParserData data;
                    863:        const char * var_name;
                    864: 
                    865:        ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
                    866:        /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
                    867:        /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
                    868:        var_name = GetValueFromNameValueList(&data, "varName");
                    869: 
                    870:        /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
                    871: 
                    872:        if(!var_name)
                    873:        {
                    874:                SoapError(h, 402, "Invalid Args");
                    875:        }
                    876:        else if(strcmp(var_name, "ConnectionStatus") == 0)
                    877:        {       
                    878:                const char * status = "Connected";
                    879:                char ext_ip_addr[INET_ADDRSTRLEN];
                    880:                if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0) {
                    881:                        status = "Disconnected";
                    882:                }
                    883:                bodylen = snprintf(body, sizeof(body), resp,
                    884:                            action, "urn:schemas-upnp-org:control-1-0",
                    885:                                   status, action);
                    886:                BuildSendAndCloseSoapResp(h, body, bodylen);
                    887:        }
                    888: #if 0
                    889:        /* not usefull */
                    890:        else if(strcmp(var_name, "ConnectionType") == 0)
                    891:        {       
                    892:                bodylen = snprintf(body, sizeof(body), resp, "IP_Routed");
                    893:                BuildSendAndCloseSoapResp(h, body, bodylen);
                    894:        }
                    895:        else if(strcmp(var_name, "LastConnectionError") == 0)
                    896:        {       
                    897:                bodylen = snprintf(body, sizeof(body), resp, "ERROR_NONE");
                    898:                BuildSendAndCloseSoapResp(h, body, bodylen);
                    899:        }
                    900: #endif
                    901:        else if(strcmp(var_name, "PortMappingNumberOfEntries") == 0)
                    902:        {
                    903:                char strn[10];
                    904:                snprintf(strn, sizeof(strn), "%i",
                    905:                         upnp_get_portmapping_number_of_entries());
                    906:                bodylen = snprintf(body, sizeof(body), resp,
                    907:                            action, "urn:schemas-upnp-org:control-1-0",
                    908:                                   strn, action);
                    909:                BuildSendAndCloseSoapResp(h, body, bodylen);
                    910:        }
                    911:        else
                    912:        {
                    913:                syslog(LOG_NOTICE, "%s: Unknown: %s", action, var_name?var_name:"");
                    914:                SoapError(h, 404, "Invalid Var");
                    915:        }
                    916: 
                    917:        ClearNameValueList(&data);      
                    918: }
                    919: 
                    920: /* Windows XP as client send the following requests :
                    921:  * GetConnectionTypeInfo
                    922:  * GetNATRSIPStatus
                    923:  * ? GetTotalBytesSent - WANCommonInterfaceConfig
                    924:  * ? GetTotalBytesReceived - idem
                    925:  * ? GetTotalPacketsSent - idem
                    926:  * ? GetTotalPacketsReceived - idem
                    927:  * GetCommonLinkProperties - idem
                    928:  * GetStatusInfo - WANIPConnection
                    929:  * GetExternalIPAddress
                    930:  * QueryStateVariable / ConnectionStatus!
                    931:  */
                    932: static const struct 
                    933: {
                    934:        const char * methodName; 
                    935:        void (*methodImpl)(struct upnphttp *, const char *);
                    936: }
                    937: soapMethods[] =
                    938: {
                    939:        { "GetConnectionTypeInfo", GetConnectionTypeInfo },
                    940:        { "GetNATRSIPStatus", GetNATRSIPStatus},
                    941:        { "GetExternalIPAddress", GetExternalIPAddress},
                    942:        { "AddPortMapping", AddPortMapping},
                    943:        { "DeletePortMapping", DeletePortMapping},
                    944:        { "GetGenericPortMappingEntry", GetGenericPortMappingEntry},
                    945:        { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry},
                    946:        { "QueryStateVariable", QueryStateVariable},
                    947:        { "GetTotalBytesSent", GetTotalBytesSent},
                    948:        { "GetTotalBytesReceived", GetTotalBytesReceived},
                    949:        { "GetTotalPacketsSent", GetTotalPacketsSent},
                    950:        { "GetTotalPacketsReceived", GetTotalPacketsReceived},
                    951:        { "GetCommonLinkProperties", GetCommonLinkProperties},
                    952:        { "GetStatusInfo", GetStatusInfo},
                    953: /* Required in WANIPConnection:2 */
                    954:        { "SetConnectionType", SetConnectionType},
                    955:        { "RequestConnection", RequestConnection},
                    956:        { "ForceTermination", ForceTermination},
                    957:        { "AddAnyPortMapping", AddAnyPortMapping},
                    958:        { "DeletePortMappingRange", DeletePortMappingRange},
                    959:        { "GetListOfPortMappings", GetListOfPortMappings},
                    960: #ifdef ENABLE_L3F_SERVICE
                    961:        { "SetDefaultConnectionService", SetDefaultConnectionService},
                    962:        { "GetDefaultConnectionService", GetDefaultConnectionService},
                    963: #endif
                    964:        { 0, 0 }
                    965: };
                    966: 
                    967: void
                    968: ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
                    969: {
                    970:        char * p;
                    971:        char * p2;
                    972:        int i, len, methodlen;
                    973: 
                    974:        i = 0;
                    975:        p = strchr(action, '#');
                    976: 
                    977:        if(p)
                    978:        {
                    979:                p++;
                    980:                p2 = strchr(p, '"');
                    981:                if(p2)
                    982:                        methodlen = p2 - p;
                    983:                else
                    984:                        methodlen = n - (p - action);
                    985:                /*syslog(LOG_DEBUG, "SoapMethod: %.*s", methodlen, p);*/
                    986:                while(soapMethods[i].methodName)
                    987:                {
                    988:                        len = strlen(soapMethods[i].methodName);
                    989:                        if(strncmp(p, soapMethods[i].methodName, len) == 0)
                    990:                        {
                    991:                                soapMethods[i].methodImpl(h, soapMethods[i].methodName);
                    992:                                return;
                    993:                        }
                    994:                        i++;
                    995:                }
                    996: 
                    997:                syslog(LOG_NOTICE, "SoapMethod: Unknown: %.*s", methodlen, p);
                    998:        }
                    999: 
                   1000:        SoapError(h, 401, "Invalid Action");
                   1001: }
                   1002: 
                   1003: /* Standard Errors:
                   1004:  *
                   1005:  * errorCode errorDescription Description
                   1006:  * --------    ---------------- -----------
                   1007:  * 401                 Invalid Action  No action by that name at this service.
                   1008:  * 402                 Invalid Args    Could be any of the following: not enough in args,
                   1009:  *                                                     too many in args, no in arg by that name, 
                   1010:  *                                                     one or more in args are of the wrong data type.
                   1011:  * 403                 Out of Sync     Out of synchronization.
                   1012:  * 501                 Action Failed   May be returned in current state of service
                   1013:  *                                                     prevents invoking that action.
                   1014:  * 600-699     TBD                     Common action errors. Defined by UPnP Forum
                   1015:  *                                                     Technical Committee.
                   1016:  * 700-799     TBD                     Action-specific errors for standard actions.
                   1017:  *                                                     Defined by UPnP Forum working committee.
                   1018:  * 800-899     TBD                     Action-specific errors for non-standard actions. 
                   1019:  *                                                     Defined by UPnP vendor.
                   1020: */
                   1021: void
                   1022: SoapError(struct upnphttp * h, int errCode, const char * errDesc)
                   1023: {
                   1024:        static const char resp[] = 
                   1025:                "<s:Envelope "
                   1026:                "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
                   1027:                "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                   1028:                "<s:Body>"
                   1029:                "<s:Fault>"
                   1030:                "<faultcode>s:Client</faultcode>"
                   1031:                "<faultstring>UPnPError</faultstring>"
                   1032:                "<detail>"
                   1033:                "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
                   1034:                "<errorCode>%d</errorCode>"
                   1035:                "<errorDescription>%s</errorDescription>"
                   1036:                "</UPnPError>"
                   1037:                "</detail>"
                   1038:                "</s:Fault>"
                   1039:                "</s:Body>"
                   1040:                "</s:Envelope>";
                   1041: 
                   1042:        char body[2048];
                   1043:        int bodylen;
                   1044: 
                   1045:        syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc);
                   1046:        bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc);
                   1047:        BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen);
                   1048:        SendResp_upnphttp(h);
                   1049:        CloseSocket_upnphttp(h);
                   1050: }
                   1051: 

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