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