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

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

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