1 /* $Id: upnpsoap.c,v 1.147 2016/02/20 19:12:00 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2016 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
13 #include <sys/socket.h>
16 #include <sys/types.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
23 #include "upnpglobalvars.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"
34 /* utility function */
35 static int is_numeric(const char * s
)
38 if(*s
< '0' || *s
> '9') return 0;
45 BuildSendAndCloseSoapResp(struct upnphttp
* h
,
46 const char * body
, int bodylen
)
48 static const char beforebody
[] =
49 "<?xml version=\"1.0\"?>\r\n"
50 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
51 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
54 static const char afterbody
[] =
58 int r
= BuildHeader_upnphttp(h
, 200, "OK", sizeof(beforebody
) - 1
59 + sizeof(afterbody
) - 1 + bodylen
);
62 memcpy(h
->res_buf
+ h
->res_buflen
, beforebody
, sizeof(beforebody
) - 1);
63 h
->res_buflen
+= sizeof(beforebody
) - 1;
65 memcpy(h
->res_buf
+ h
->res_buflen
, body
, bodylen
);
66 h
->res_buflen
+= bodylen
;
68 memcpy(h
->res_buf
+ h
->res_buflen
, afterbody
, sizeof(afterbody
) - 1);
69 h
->res_buflen
+= sizeof(afterbody
) - 1;
71 BuildResp2_upnphttp(h
, 500, "Internal Server Error", NULL
, 0);
74 SendRespAndClose_upnphttp(h
);
78 GetConnectionTypeInfo(struct upnphttp
* h
, const char * action
, const char * ns
)
81 static const char resp
[] =
82 "<u:GetConnectionTypeInfoResponse "
83 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
84 "<NewConnectionType>IP_Routed</NewConnectionType>"
85 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
86 "</u:GetConnectionTypeInfoResponse>";
88 static const char resp
[] =
91 "<NewConnectionType>IP_Routed</NewConnectionType>"
92 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
97 bodylen
= snprintf(body
, sizeof(body
), resp
,
99 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
102 /* maximum value for a UPNP ui4 type variable */
103 #define UPNP_UI4_MAX (4294967295ul)
106 GetTotalBytesSent(struct upnphttp
* h
, const char * action
, const char * ns
)
110 static const char resp
[] =
113 "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
120 r
= getifstats(ext_if_name
, &data
);
121 bodylen
= snprintf(body
, sizeof(body
), resp
,
122 action
, ns
, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
124 r
<0?0:(data
.obytes
& UPNP_UI4_MAX
), action
);
125 #else /* UPNP_STRICT */
126 r
<0?0:data
.obytes
, action
);
127 #endif /* UPNP_STRICT */
128 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
132 GetTotalBytesReceived(struct upnphttp
* h
, const char * action
, const char * ns
)
136 static const char resp
[] =
139 "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
146 r
= getifstats(ext_if_name
, &data
);
147 /* TotalBytesReceived
148 * This variable represents the cumulative counter for total number of
149 * bytes received downstream across all connection service instances on
150 * WANDevice. The count rolls over to 0 after it reaching the maximum
152 bodylen
= snprintf(body
, sizeof(body
), resp
,
153 action
, ns
, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
155 r
<0?0:(data
.ibytes
& UPNP_UI4_MAX
), action
);
156 #else /* UPNP_STRICT */
157 r
<0?0:data
.ibytes
, action
);
158 #endif /* UPNP_STRICT */
159 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
163 GetTotalPacketsSent(struct upnphttp
* h
, const char * action
, const char * ns
)
167 static const char resp
[] =
170 "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
177 r
= getifstats(ext_if_name
, &data
);
178 bodylen
= snprintf(body
, sizeof(body
), resp
,
179 action
, ns
,/*"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",*/
181 r
<0?0:(data
.opackets
& UPNP_UI4_MAX
), action
);
182 #else /* UPNP_STRICT */
183 r
<0?0:data
.opackets
, action
);
184 #endif /* UPNP_STRICT */
185 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
189 GetTotalPacketsReceived(struct upnphttp
* h
, const char * action
, const char * ns
)
193 static const char resp
[] =
196 "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
203 r
= getifstats(ext_if_name
, &data
);
204 bodylen
= snprintf(body
, sizeof(body
), resp
,
205 action
, ns
, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
207 r
<0?0:(data
.ipackets
& UPNP_UI4_MAX
), action
);
208 #else /* UPNP_STRICT */
209 r
<0?0:data
.ipackets
, action
);
210 #endif /* UPNP_STRICT */
211 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
215 GetCommonLinkProperties(struct upnphttp
* h
, const char * action
, const char * ns
)
217 /* WANAccessType : set depending on the hardware :
218 * DSL, POTS (plain old Telephone service), Cable, Ethernet */
219 static const char resp
[] =
222 "<NewWANAccessType>%s</NewWANAccessType>"
223 "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
224 "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
225 "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
231 const char * status
= "Up"; /* Up, Down (Required),
232 * Initializing, Unavailable (Optional) */
233 const char * wan_access_type
= "Cable"; /* DSL, POTS, Cable, Ethernet */
234 char ext_ip_addr
[INET_ADDRSTRLEN
];
236 if((downstream_bitrate
== 0) || (upstream_bitrate
== 0))
238 if(getifstats(ext_if_name
, &data
) >= 0)
240 if(downstream_bitrate
== 0) downstream_bitrate
= data
.baudrate
;
241 if(upstream_bitrate
== 0) upstream_bitrate
= data
.baudrate
;
244 if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
, NULL
, NULL
) < 0) {
247 bodylen
= snprintf(body
, sizeof(body
), resp
,
248 action
, ns
, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
250 upstream_bitrate
, downstream_bitrate
,
252 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
256 GetStatusInfo(struct upnphttp
* h
, const char * action
, const char * ns
)
258 static const char resp
[] =
261 "<NewConnectionStatus>%s</NewConnectionStatus>"
262 "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
263 "<NewUptime>%ld</NewUptime>"
270 /* ConnectionStatus possible values :
271 * Unconfigured, Connecting, Connected, PendingDisconnect,
272 * Disconnecting, Disconnected */
274 status
= get_wan_connection_status_str(ext_if_name
);
275 uptime
= (time(NULL
) - startup_time
);
276 bodylen
= snprintf(body
, sizeof(body
), resp
,
277 action
, ns
, /*SERVICE_TYPE_WANIPC,*/
278 status
, (long)uptime
, action
);
279 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
283 GetNATRSIPStatus(struct upnphttp
* h
, const char * action
, const char * ns
)
286 static const char resp
[] =
287 "<u:GetNATRSIPStatusResponse "
288 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
289 "<NewRSIPAvailable>0</NewRSIPAvailable>"
290 "<NewNATEnabled>1</NewNATEnabled>"
291 "</u:GetNATRSIPStatusResponse>";
294 static const char resp
[] =
297 "<NewRSIPAvailable>0</NewRSIPAvailable>"
298 "<NewNATEnabled>1</NewNATEnabled>"
302 /* 2.2.9. RSIPAvailable
303 * This variable indicates if Realm-specific IP (RSIP) is available
304 * as a feature on the InternetGatewayDevice. RSIP is being defined
305 * in the NAT working group in the IETF to allow host-NATing using
306 * a standard set of message exchanges. It also allows end-to-end
307 * applications that otherwise break if NAT is introduced
308 * (e.g. IPsec-based VPNs).
309 * A gateway that does not support RSIP should set this variable to 0. */
310 bodylen
= snprintf(body
, sizeof(body
), resp
,
311 action
, ns
, /*SERVICE_TYPE_WANIPC,*/
313 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
317 GetExternalIPAddress(struct upnphttp
* h
, const char * action
, const char * ns
)
319 static const char resp
[] =
322 "<NewExternalIPAddress>%s</NewExternalIPAddress>"
327 char ext_ip_addr
[INET_ADDRSTRLEN
];
328 /* Does that method need to work with IPv6 ?
329 * There is usually no NAT with IPv6 */
331 #ifndef MULTIPLE_EXTERNAL_IP
334 strncpy(ext_ip_addr
, use_ext_ip_addr
, INET_ADDRSTRLEN
);
335 ext_ip_addr
[INET_ADDRSTRLEN
- 1] = '\0';
337 else if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
, NULL
, NULL
) < 0)
339 syslog(LOG_ERR
, "Failed to get ip address for interface %s",
341 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
344 struct lan_addr_s
* lan_addr
;
345 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
346 for(lan_addr
= lan_addrs
.lh_first
; lan_addr
!= NULL
; lan_addr
= lan_addr
->list
.le_next
)
348 if( (h
->clientaddr
.s_addr
& lan_addr
->mask
.s_addr
)
349 == (lan_addr
->addr
.s_addr
& lan_addr
->mask
.s_addr
))
351 strncpy(ext_ip_addr
, lan_addr
->ext_ip_str
, INET_ADDRSTRLEN
);
356 bodylen
= snprintf(body
, sizeof(body
), resp
,
357 action
, ns
, /*SERVICE_TYPE_WANIPC,*/
358 ext_ip_addr
, action
);
359 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
362 /* AddPortMapping method of WANIPConnection Service
363 * Ignored argument : NewEnabled */
365 AddPortMapping(struct upnphttp
* h
, const char * action
, const char * ns
)
369 /*static const char resp[] =
370 "<u:AddPortMappingResponse "
371 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";*/
372 static const char resp
[] =
378 struct NameValueParserData data
;
379 char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
380 char * leaseduration_str
;
381 unsigned int leaseduration
;
383 unsigned short iport
, eport
;
385 struct hostent
*hp
; /* getbyhostname() */
386 char ** ptr
; /* getbyhostname() */
387 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
389 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
390 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
393 ClearNameValueList(&data
);
394 SoapError(h
, 402, "Invalid Args");
398 /* IGD 2 MUST support both wildcard and specific IP address values
399 * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
400 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
401 #ifndef SUPPORT_REMOTEHOST
403 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
405 ClearNameValueList(&data
);
406 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
412 /* if ip not valid assume hostname and convert */
413 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
415 hp
= gethostbyname(int_ip
);
416 if(hp
&& hp
->h_addrtype
== AF_INET
)
418 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
420 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
421 result_ip
= *((struct in_addr
*) *ptr
);
422 /* TODO : deal with more than one ip per hostname */
428 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
429 ClearNameValueList(&data
);
430 SoapError(h
, 402, "Invalid Args");
435 /* check if NewInternalAddress is the client address */
436 if(GETFLAG(SECUREMODEMASK
))
438 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
440 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
441 inet_ntoa(h
->clientaddr
), int_ip
);
442 ClearNameValueList(&data
);
443 SoapError(h
, 718, "ConflictInMappingEntry");
448 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
449 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
450 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
451 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
452 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
454 if (!int_port
|| !ext_port
|| !protocol
)
456 ClearNameValueList(&data
);
457 SoapError(h
, 402, "Invalid Args");
461 eport
= (unsigned short)atoi(ext_port
);
462 iport
= (unsigned short)atoi(int_port
);
464 if (strcmp(ext_port
, "*") == 0 || eport
== 0)
466 ClearNameValueList(&data
);
467 SoapError(h
, 716, "Wildcard not permited in ExtPort");
471 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
473 /* PortMappingLeaseDuration can be either a value between 1 and
474 * 604800 seconds or the zero value (for infinite lease time).
475 * Note that an infinite lease time can be only set by out-of-band
476 * mechanisms like WWW-administration, remote management or local
478 * If a control point uses the value 0 to indicate an infinite lease
479 * time mapping, it is REQUIRED that gateway uses the maximum value
480 * instead (e.g. 604800 seconds) */
481 if(leaseduration
== 0 || leaseduration
> 604800)
482 leaseduration
= 604800;
485 syslog(LOG_INFO
, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
486 action
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
,
487 r_host
? r_host
: "NULL");
489 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
491 ClearNameValueList(&data
);
493 /* possible error codes for AddPortMapping :
495 * 501 - Action Failed
496 * 715 - Wildcard not permited in SrcAddr
497 * 716 - Wildcard not permited in ExtPort
498 * 718 - ConflictInMappingEntry
499 * 724 - SamePortValuesRequired (deprecated in IGD v2)
500 * 725 - OnlyPermanentLeasesSupported
501 The NAT implementation only supports permanent lease times on
502 port mappings (deprecated in IGD v2)
503 * 726 - RemoteHostOnlySupportsWildcard
504 RemoteHost must be a wildcard and cannot be a specific IP
505 address or DNS name (deprecated in IGD v2)
506 * 727 - ExternalPortOnlySupportsWildcard
507 ExternalPort must be a wildcard and cannot be a specific port
508 value (deprecated in IGD v2)
509 * 728 - NoPortMapsAvailable
510 There are not enough free ports available to complete the mapping
512 * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
515 case 0: /* success */
516 bodylen
= snprintf(body
, sizeof(body
), resp
,
517 action
, ns
/*SERVICE_TYPE_WANIPC*/);
518 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
522 SoapError(h
, 729, "ConflictWithOtherMechanisms");
525 case -2: /* already redirected */
526 case -3: /* not permitted */
527 SoapError(h
, 718, "ConflictInMappingEntry");
530 SoapError(h
, 501, "ActionFailed");
534 /* AddAnyPortMapping was added in WANIPConnection v2 */
536 AddAnyPortMapping(struct upnphttp
* h
, const char * action
, const char * ns
)
539 static const char resp
[] =
542 "<NewReservedPort>%hu</NewReservedPort>"
548 struct NameValueParserData data
;
549 const char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
551 unsigned short iport
, eport
;
552 const char * leaseduration_str
;
553 unsigned int leaseduration
;
555 struct hostent
*hp
; /* getbyhostname() */
556 char ** ptr
; /* getbyhostname() */
557 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
559 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
560 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
561 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
562 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
563 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
564 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
566 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
567 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
569 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
570 if(leaseduration
== 0)
571 leaseduration
= 604800;
573 if (!int_ip
|| !ext_port
|| !int_port
)
575 ClearNameValueList(&data
);
576 SoapError(h
, 402, "Invalid Args");
580 eport
= (unsigned short)atoi(ext_port
);
581 iport
= (unsigned short)atoi(int_port
);
582 if(iport
== 0 || !is_numeric(ext_port
)) {
583 ClearNameValueList(&data
);
584 SoapError(h
, 402, "Invalid Args");
587 #ifndef SUPPORT_REMOTEHOST
589 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
591 ClearNameValueList(&data
);
592 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
598 /* if ip not valid assume hostname and convert */
599 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
601 hp
= gethostbyname(int_ip
);
602 if(hp
&& hp
->h_addrtype
== AF_INET
)
604 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
606 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
607 result_ip
= *((struct in_addr
*) *ptr
);
608 /* TODO : deal with more than one ip per hostname */
614 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
615 ClearNameValueList(&data
);
616 SoapError(h
, 402, "Invalid Args");
621 /* check if NewInternalAddress is the client address */
622 if(GETFLAG(SECUREMODEMASK
))
624 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
626 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
627 inet_ntoa(h
->clientaddr
), int_ip
);
628 ClearNameValueList(&data
);
629 SoapError(h
, 606, "Action not authorized");
634 /* TODO : accept a different external port
635 * have some smart strategy to choose the port */
637 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
638 if(r
==-2 && eport
< 65535) {
645 ClearNameValueList(&data
);
649 case 0: /* success */
650 bodylen
= snprintf(body
, sizeof(body
), resp
,
651 action
, ns
, /*SERVICE_TYPE_WANIPC,*/
653 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
655 case -2: /* already redirected */
656 SoapError(h
, 718, "ConflictInMappingEntry");
658 case -3: /* not permitted */
659 SoapError(h
, 606, "Action not authorized");
662 SoapError(h
, 501, "ActionFailed");
667 GetSpecificPortMappingEntry(struct upnphttp
* h
, const char * action
, const char * ns
)
671 static const char resp
[] =
674 "<NewInternalPort>%u</NewInternalPort>"
675 "<NewInternalClient>%s</NewInternalClient>"
676 "<NewEnabled>1</NewEnabled>"
677 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
678 "<NewLeaseDuration>%u</NewLeaseDuration>"
683 struct NameValueParserData data
;
684 const char * r_host
, * ext_port
, * protocol
;
685 unsigned short eport
, iport
;
688 unsigned int leaseduration
= 0;
690 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
691 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
692 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
693 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
696 if(!ext_port
|| !protocol
|| !r_host
)
698 if(!ext_port
|| !protocol
)
701 ClearNameValueList(&data
);
702 SoapError(h
, 402, "Invalid Args");
705 #ifndef SUPPORT_REMOTEHOST
707 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
709 ClearNameValueList(&data
);
710 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
716 eport
= (unsigned short)atoi(ext_port
);
719 ClearNameValueList(&data
);
720 SoapError(h
, 402, "Invalid Args");
724 /* TODO : add r_host as an input parameter ...
725 * We prevent several Port Mapping with same external port
726 * but different remoteHost to be set up, so that is not
728 r
= upnp_get_redirection_infos(eport
, protocol
, &iport
,
729 int_ip
, sizeof(int_ip
),
736 SoapError(h
, 714, "NoSuchEntryInArray");
740 syslog(LOG_INFO
, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
742 r_host
? r_host
: "NULL", ext_port
, protocol
, int_ip
,
743 (unsigned int)iport
, desc
);
744 bodylen
= snprintf(body
, sizeof(body
), resp
,
745 action
, ns
/*SERVICE_TYPE_WANIPC*/,
746 (unsigned int)iport
, int_ip
, desc
, leaseduration
,
748 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
751 ClearNameValueList(&data
);
755 DeletePortMapping(struct upnphttp
* h
, const char * action
, const char * ns
)
759 /*static const char resp[] =
760 "<u:DeletePortMappingResponse "
761 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
762 "</u:DeletePortMappingResponse>";*/
763 static const char resp
[] =
770 struct NameValueParserData data
;
771 const char * ext_port
, * protocol
;
772 unsigned short eport
;
775 #endif /* UPNP_STRICT */
777 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
778 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
779 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
781 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
782 #endif /* UPNP_STRICT */
785 if(!ext_port
|| !protocol
|| !r_host
)
787 if(!ext_port
|| !protocol
)
788 #endif /* UPNP_STRICT */
790 ClearNameValueList(&data
);
791 SoapError(h
, 402, "Invalid Args");
794 #ifndef SUPPORT_REMOTEHOST
796 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
798 ClearNameValueList(&data
);
799 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
802 #endif /* UPNP_STRICT */
803 #endif /* SUPPORT_REMOTEHOST */
805 eport
= (unsigned short)atoi(ext_port
);
808 ClearNameValueList(&data
);
809 SoapError(h
, 402, "Invalid Args");
813 syslog(LOG_INFO
, "%s: external port: %hu, protocol: %s",
814 action
, eport
, protocol
);
816 /* if in secure mode, check the IP
817 * Removing a redirection is not a security threat,
818 * just an annoyance for the user using it. So this is not
820 if(GETFLAG(SECUREMODEMASK
))
823 struct in_addr int_ip_addr
;
824 unsigned short iport
;
825 unsigned int leaseduration
= 0;
826 r
= upnp_get_redirection_infos(eport
, protocol
, &iport
,
827 int_ip
, sizeof(int_ip
),
832 if(inet_pton(AF_INET
, int_ip
, &int_ip_addr
) > 0)
834 if(h
->clientaddr
.s_addr
!= int_ip_addr
.s_addr
)
836 SoapError(h
, 606, "Action not authorized");
837 /*SoapError(h, 714, "NoSuchEntryInArray");*/
838 ClearNameValueList(&data
);
845 r
= upnp_delete_redirection(eport
, protocol
);
849 SoapError(h
, 714, "NoSuchEntryInArray");
853 bodylen
= snprintf(body
, sizeof(body
), resp
,
855 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
858 ClearNameValueList(&data
);
861 /* DeletePortMappingRange was added in IGD spec v2 */
863 DeletePortMappingRange(struct upnphttp
* h
, const char * action
, const char * ns
)
866 /*static const char resp[] =
867 "<u:DeletePortMappingRangeResponse "
868 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
869 "</u:DeletePortMappingRangeResponse>";*/
870 static const char resp
[] =
876 struct NameValueParserData data
;
877 const char * protocol
;
878 const char * startport_s
, * endport_s
;
879 unsigned short startport
, endport
;
881 unsigned short * port_list
;
882 unsigned int i
, number
= 0;
884 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
885 startport_s
= GetValueFromNameValueList(&data
, "NewStartPort");
886 endport_s
= GetValueFromNameValueList(&data
, "NewEndPort");
887 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
888 /*manage = atoi(GetValueFromNameValueList(&data, "NewManage"));*/
889 if(startport_s
== NULL
|| endport_s
== NULL
|| protocol
== NULL
||
890 !is_numeric(startport_s
) || !is_numeric(endport_s
)) {
891 SoapError(h
, 402, "Invalid Args");
892 ClearNameValueList(&data
);
895 startport
= (unsigned short)atoi(startport_s
);
896 endport
= (unsigned short)atoi(endport_s
);
899 606 - Action not authorized
900 730 - PortMappingNotFound
901 733 - InconsistentParameter
903 if(startport
> endport
)
905 SoapError(h
, 733, "InconsistentParameter");
906 ClearNameValueList(&data
);
910 syslog(LOG_INFO
, "%s: deleting external ports: %hu-%hu, protocol: %s",
911 action
, startport
, endport
, protocol
);
913 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
917 SoapError(h
, 730, "PortMappingNotFound");
918 ClearNameValueList(&data
);
923 for(i
= 0; i
< number
; i
++)
925 r
= upnp_delete_redirection(port_list
[i
], protocol
);
926 syslog(LOG_INFO
, "%s: deleting external port: %hu, protocol: %s: %s",
927 action
, port_list
[i
], protocol
, r
< 0 ? "failed" : "ok");
930 bodylen
= snprintf(body
, sizeof(body
), resp
,
932 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
934 ClearNameValueList(&data
);
938 GetGenericPortMappingEntry(struct upnphttp
* h
, const char * action
, const char * ns
)
942 static const char resp
[] =
945 "<NewRemoteHost>%s</NewRemoteHost>"
946 "<NewExternalPort>%u</NewExternalPort>"
947 "<NewProtocol>%s</NewProtocol>"
948 "<NewInternalPort>%u</NewInternalPort>"
949 "<NewInternalClient>%s</NewInternalClient>"
950 "<NewEnabled>1</NewEnabled>"
951 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
952 "<NewLeaseDuration>%u</NewLeaseDuration>"
956 unsigned short eport
, iport
;
957 const char * m_index
;
959 char protocol
[8], iaddr
[32];
962 unsigned int leaseduration
= 0;
963 struct NameValueParserData data
;
965 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
966 m_index
= GetValueFromNameValueList(&data
, "NewPortMappingIndex");
970 ClearNameValueList(&data
);
971 SoapError(h
, 402, "Invalid Args");
974 errno
= 0; /* To distinguish success/failure after call */
975 index
= strtol(m_index
, &endptr
, 10);
976 if((errno
== ERANGE
&& (index
== LONG_MAX
|| index
== LONG_MIN
))
977 || (errno
!= 0 && index
== 0) || (m_index
== endptr
))
979 /* should condition (*endptr != '\0') be also an error ? */
980 if(m_index
== endptr
)
981 syslog(LOG_WARNING
, "%s: no digits were found in <%s>",
982 "GetGenericPortMappingEntry", "NewPortMappingIndex");
984 syslog(LOG_WARNING
, "%s: strtol('%s'): %m",
985 "GetGenericPortMappingEntry", m_index
);
986 ClearNameValueList(&data
);
987 SoapError(h
, 402, "Invalid Args");
991 syslog(LOG_INFO
, "%s: index=%d", action
, (int)index
);
994 r
= upnp_get_redirection_infos_by_index((int)index
, &eport
, protocol
, &iport
,
995 iaddr
, sizeof(iaddr
),
997 rhost
, sizeof(rhost
),
1002 SoapError(h
, 713, "SpecifiedArrayIndexInvalid");
1008 bodylen
= snprintf(body
, sizeof(body
), resp
,
1009 action
, ns
, /*SERVICE_TYPE_WANIPC,*/ rhost
,
1010 (unsigned int)eport
, protocol
, (unsigned int)iport
, iaddr
, desc
,
1011 leaseduration
, action
);
1012 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1015 ClearNameValueList(&data
);
1018 /* GetListOfPortMappings was added in the IGD v2 specification */
1020 GetListOfPortMappings(struct upnphttp
* h
, const char * action
, const char * ns
)
1022 static const char resp_start
[] =
1025 "<NewPortListing><![CDATA[";
1026 static const char resp_end
[] =
1027 "]]></NewPortListing>"
1030 static const char list_start
[] =
1031 "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
1032 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
1033 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
1034 " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
1035 static const char list_end
[] =
1036 "</p:PortMappingList>";
1038 static const char entry
[] =
1039 "<p:PortMappingEntry>"
1040 "<p:NewRemoteHost>%s</p:NewRemoteHost>"
1041 "<p:NewExternalPort>%hu</p:NewExternalPort>"
1042 "<p:NewProtocol>%s</p:NewProtocol>"
1043 "<p:NewInternalPort>%hu</p:NewInternalPort>"
1044 "<p:NewInternalClient>%s</p:NewInternalClient>"
1045 "<p:NewEnabled>1</p:NewEnabled>"
1046 "<p:NewDescription>%s</p:NewDescription>"
1047 "<p:NewLeaseTime>%u</p:NewLeaseTime>"
1048 "</p:PortMappingEntry>";
1055 unsigned short iport
;
1059 unsigned int leaseduration
= 0;
1061 struct NameValueParserData data
;
1062 const char * startport_s
, * endport_s
;
1063 unsigned short startport
, endport
;
1064 const char * protocol
;
1066 const char * number_s
;
1068 unsigned short * port_list
;
1069 unsigned int i
, list_size
= 0;
1071 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1072 startport_s
= GetValueFromNameValueList(&data
, "NewStartPort");
1073 endport_s
= GetValueFromNameValueList(&data
, "NewEndPort");
1074 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
1075 /*manage_s = GetValueFromNameValueList(&data, "NewManage");*/
1076 number_s
= GetValueFromNameValueList(&data
, "NewNumberOfPorts");
1077 if(startport_s
== NULL
|| endport_s
== NULL
|| protocol
== NULL
||
1078 number_s
== NULL
|| !is_numeric(number_s
) ||
1079 !is_numeric(startport_s
) || !is_numeric(endport_s
)) {
1080 SoapError(h
, 402, "Invalid Args");
1081 ClearNameValueList(&data
);
1085 startport
= (unsigned short)atoi(startport_s
);
1086 endport
= (unsigned short)atoi(endport_s
);
1087 /*manage = atoi(manage_s);*/
1088 number
= atoi(number_s
);
1089 if(number
== 0) number
= 1000; /* return up to 1000 mappings by default */
1091 if(startport
> endport
)
1093 SoapError(h
, 733, "InconsistentParameter");
1094 ClearNameValueList(&data
);
1098 build the PortMappingList xml document :
1100 <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
1101 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1102 xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
1103 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
1104 <p:PortMappingEntry>
1105 <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
1106 <p:NewExternalPort>2345</p:NewExternalPort>
1107 <p:NewProtocol>TCP</p:NewProtocol>
1108 <p:NewInternalPort>2345</p:NewInternalPort>
1109 <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
1110 <p:NewEnabled>1</p:NewEnabled>
1111 <p:NewDescription>dooom</p:NewDescription>
1112 <p:NewLeaseTime>345</p:NewLeaseTime>
1113 </p:PortMappingEntry>
1114 </p:PortMappingList>
1117 body
= malloc(bodyalloc
);
1120 ClearNameValueList(&data
);
1121 SoapError(h
, 501, "ActionFailed");
1124 bodylen
= snprintf(body
, bodyalloc
, resp_start
,
1125 action
, ns
/*SERVICE_TYPE_WANIPC*/);
1128 SoapError(h
, 501, "ActionFailed");
1132 memcpy(body
+bodylen
, list_start
, sizeof(list_start
));
1133 bodylen
+= (sizeof(list_start
) - 1);
1135 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
1136 protocol
, &list_size
);
1137 /* loop through port mappings */
1138 for(i
= 0; number
> 0 && i
< list_size
; i
++)
1140 /* have a margin of 1024 bytes to store the new entry */
1141 if((unsigned int)bodylen
+ 1024 > bodyalloc
)
1143 char * body_sav
= body
;
1145 body
= realloc(body
, bodyalloc
);
1148 syslog(LOG_CRIT
, "realloc(%p, %u) FAILED", body_sav
, (unsigned)bodyalloc
);
1149 ClearNameValueList(&data
);
1150 SoapError(h
, 501, "ActionFailed");
1157 r
= upnp_get_redirection_infos(port_list
[i
], protocol
, &iport
,
1158 int_ip
, sizeof(int_ip
),
1160 rhost
, sizeof(rhost
),
1164 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, entry
,
1165 rhost
, port_list
[i
], protocol
,
1166 iport
, int_ip
, desc
, leaseduration
);
1173 if((bodylen
+ sizeof(list_end
) + 1024) > bodyalloc
)
1175 char * body_sav
= body
;
1176 bodyalloc
+= (sizeof(list_end
) + 1024);
1177 body
= realloc(body
, bodyalloc
);
1180 syslog(LOG_CRIT
, "realloc(%p, %u) FAILED", body_sav
, (unsigned)bodyalloc
);
1181 ClearNameValueList(&data
);
1182 SoapError(h
, 501, "ActionFailed");
1187 memcpy(body
+bodylen
, list_end
, sizeof(list_end
));
1188 bodylen
+= (sizeof(list_end
) - 1);
1189 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, resp_end
,
1191 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1194 ClearNameValueList(&data
);
1197 #ifdef ENABLE_L3F_SERVICE
1199 SetDefaultConnectionService(struct upnphttp
* h
, const char * action
, const char * ns
)
1201 /*static const char resp[] =
1202 "<u:SetDefaultConnectionServiceResponse "
1203 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1204 "</u:SetDefaultConnectionServiceResponse>";*/
1205 static const char resp
[] =
1211 struct NameValueParserData data
;
1213 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1214 p
= GetValueFromNameValueList(&data
, "NewDefaultConnectionService");
1216 /* 720 InvalidDeviceUUID
1217 * 721 InvalidServiceID
1218 * 723 InvalidConnServiceSelection */
1221 service
= strchr(p
, ',');
1222 if(0 != memcmp(uuidvalue_wcd
, p
, sizeof("uuid:00000000-0000-0000-0000-000000000000") - 1)) {
1223 SoapError(h
, 720, "InvalidDeviceUUID");
1224 } else if(service
== NULL
|| 0 != strcmp(service
+1, SERVICE_ID_WANIPC
)) {
1225 SoapError(h
, 721, "InvalidServiceID");
1229 syslog(LOG_INFO
, "%s(%s) : Ignored", action
, p
);
1230 bodylen
= snprintf(body
, sizeof(body
), resp
,
1231 action
, ns
, action
);
1232 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1235 /* missing argument */
1236 SoapError(h
, 402, "Invalid Args");
1238 ClearNameValueList(&data
);
1242 GetDefaultConnectionService(struct upnphttp
* h
, const char * action
, const char * ns
)
1244 static const char resp
[] =
1248 "<NewDefaultConnectionService>%s:WANConnectionDevice:2,"
1250 "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
1252 SERVICE_ID_WANIPC
"</NewDefaultConnectionService>"
1254 /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
1255 * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
1256 * urn:upnp-org:serviceId:WANPPPConn1 */
1260 /* namespace : urn:schemas-upnp-org:service:Layer3Forwarding:1 */
1261 bodylen
= snprintf(body
, sizeof(body
), resp
,
1262 action
, ns
, uuidvalue_wcd
, action
);
1263 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1267 /* Added for compliance with WANIPConnection v2 */
1269 SetConnectionType(struct upnphttp
* h
, const char * action
, const char * ns
)
1272 const char * connection_type
;
1273 #endif /* UPNP_STRICT */
1274 struct NameValueParserData data
;
1278 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1280 connection_type
= GetValueFromNameValueList(&data
, "NewConnectionType");
1281 if(!connection_type
) {
1282 ClearNameValueList(&data
);
1283 SoapError(h
, 402, "Invalid Args");
1286 #endif /* UPNP_STRICT */
1287 /* Unconfigured, IP_Routed, IP_Bridged */
1288 ClearNameValueList(&data
);
1289 /* always return a ReadOnly error */
1290 SoapError(h
, 731, "ReadOnly");
1293 /* Added for compliance with WANIPConnection v2 */
1295 RequestConnection(struct upnphttp
* h
, const char * action
, const char * ns
)
1299 SoapError(h
, 606, "Action not authorized");
1302 /* Added for compliance with WANIPConnection v2 */
1304 ForceTermination(struct upnphttp
* h
, const char * action
, const char * ns
)
1308 SoapError(h
, 606, "Action not authorized");
1312 If a control point calls QueryStateVariable on a state variable that is not
1313 buffered in memory within (or otherwise available from) the service,
1314 the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1316 QueryStateVariable remains useful as a limited test tool but may not be
1317 part of some future versions of UPnP.
1320 QueryStateVariable(struct upnphttp
* h
, const char * action
, const char * ns
)
1322 static const char resp
[] =
1325 "<return>%s</return>"
1330 struct NameValueParserData data
;
1331 const char * var_name
;
1333 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1334 /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1335 /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1336 var_name
= GetValueFromNameValueList(&data
, "varName");
1338 /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1342 SoapError(h
, 402, "Invalid Args");
1344 else if(strcmp(var_name
, "ConnectionStatus") == 0)
1346 const char * status
;
1348 status
= get_wan_connection_status_str(ext_if_name
);
1349 bodylen
= snprintf(body
, sizeof(body
), resp
,
1350 action
, ns
,/*"urn:schemas-upnp-org:control-1-0",*/
1352 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1356 else if(strcmp(var_name
, "ConnectionType") == 0)
1358 bodylen
= snprintf(body
, sizeof(body
), resp
, "IP_Routed");
1359 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1361 else if(strcmp(var_name
, "LastConnectionError") == 0)
1363 bodylen
= snprintf(body
, sizeof(body
), resp
, "ERROR_NONE");
1364 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1367 else if(strcmp(var_name
, "PortMappingNumberOfEntries") == 0)
1370 snprintf(strn
, sizeof(strn
), "%i",
1371 upnp_get_portmapping_number_of_entries());
1372 bodylen
= snprintf(body
, sizeof(body
), resp
,
1373 action
, ns
,/*"urn:schemas-upnp-org:control-1-0",*/
1375 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1379 syslog(LOG_NOTICE
, "%s: Unknown: %s", action
, var_name
?var_name
:"");
1380 SoapError(h
, 404, "Invalid Var");
1383 ClearNameValueList(&data
);
1386 #ifdef ENABLE_6FC_SERVICE
1388 #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1390 /* WANIPv6FirewallControl actions */
1392 GetFirewallStatus(struct upnphttp
* h
, const char * action
, const char * ns
)
1394 static const char resp
[] =
1397 "<FirewallEnabled>%d</FirewallEnabled>"
1398 "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1404 bodylen
= snprintf(body
, sizeof(body
), resp
,
1405 action
, ns
, /*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",*/
1406 GETFLAG(IPV6FCFWDISABLEDMASK
) ? 0 : 1,
1407 GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK
) ? 0 : 1,
1409 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1413 CheckStatus(struct upnphttp
* h
)
1415 if (GETFLAG(IPV6FCFWDISABLEDMASK
))
1417 SoapError(h
, 702, "FirewallDisabled");
1420 else if(GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK
))
1422 SoapError(h
, 703, "InboundPinholeNotAllowed");
1430 static int connecthostport(const char * host
, unsigned short port
, char * result
)
1433 char hostname
[INET6_ADDRSTRLEN
];
1434 char port_str
[8], ifname
[8], tmp
[4];
1435 struct addrinfo
*ai
, *p
;
1436 struct addrinfo hints
;
1438 memset(&hints
, 0, sizeof(hints
));
1439 /* hints.ai_flags = AI_ADDRCONFIG; */
1440 #ifdef AI_NUMERICSERV
1441 hints
.ai_flags
= AI_NUMERICSERV
;
1443 hints
.ai_socktype
= SOCK_STREAM
;
1444 hints
.ai_family
= AF_UNSPEC
; /* AF_INET, AF_INET6 or AF_UNSPEC */
1445 /* hints.ai_protocol = IPPROTO_TCP; */
1446 snprintf(port_str
, sizeof(port_str
), "%hu", port
);
1447 strcpy(hostname
, host
);
1448 if(!strncmp(host
, "fe80", 4))
1450 printf("Using an linklocal address\n");
1451 strcpy(ifname
, "%");
1452 snprintf(tmp
, sizeof(tmp
), "%d", linklocal_index
);
1453 strcat(ifname
, tmp
);
1454 strcat(hostname
, ifname
);
1455 printf("host: %s\n", hostname
);
1457 n
= getaddrinfo(hostname
, port_str
, &hints
, &ai
);
1460 fprintf(stderr
, "getaddrinfo() error : %s\n", gai_strerror(n
));
1464 for(p
= ai
; p
; p
= p
->ai_next
)
1468 char tmp_service
[256];
1469 printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1470 p
->ai_family
, p
->ai_socktype
, p
->ai_protocol
, p
->ai_addrlen
);
1471 getnameinfo(p
->ai_addr
, p
->ai_addrlen
, tmp_host
, sizeof(tmp_host
),
1472 tmp_service
, sizeof(tmp_service
),
1473 NI_NUMERICHOST
| NI_NUMERICSERV
);
1474 printf(" host=%s service=%s\n", tmp_host
, tmp_service
);
1476 inet_ntop(AF_INET6
, &(((struct sockaddr_in6
*)p
->ai_addr
)->sin6_addr
), result
, INET6_ADDRSTRLEN
);
1483 /* Check the security policy right */
1485 PinholeVerification(struct upnphttp
* h
, char * int_ip
, unsigned short int_port
)
1488 char senderAddr
[INET6_ADDRSTRLEN
]="";
1489 struct addrinfo hints
, *ai
, *p
;
1490 struct in6_addr result_ip
;
1492 /* Pinhole InternalClient address must correspond to the action sender */
1493 syslog(LOG_INFO
, "Checking internal IP@ and port (Security policy purpose)");
1495 hints
.ai_socktype
= SOCK_STREAM
;
1496 hints
.ai_family
= AF_UNSPEC
;
1498 /* if ip not valid assume hostname and convert */
1499 if (inet_pton(AF_INET6
, int_ip
, &result_ip
) <= 0)
1501 n
= getaddrinfo(int_ip
, NULL
, &hints
, &ai
);
1502 if(!n
&& ai
->ai_family
== AF_INET6
)
1504 for(p
= ai
; p
; p
= p
->ai_next
)
1506 inet_ntop(AF_INET6
, (struct in6_addr
*) p
, int_ip
, sizeof(struct in6_addr
));
1507 result_ip
= *((struct in6_addr
*) p
);
1508 /* TODO : deal with more than one ip per hostname */
1514 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
1515 SoapError(h
, 402, "Invalid Args");
1521 if(inet_ntop(AF_INET6
, &(h
->clientaddr_v6
), senderAddr
, INET6_ADDRSTRLEN
) == NULL
)
1523 syslog(LOG_ERR
, "inet_ntop: %m");
1526 printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr
, int_ip
);
1528 if(strcmp(senderAddr
, int_ip
) != 0)
1529 if(h
->clientaddr_v6
.s6_addr
!= result_ip
.s6_addr
)
1531 syslog(LOG_INFO
, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1532 senderAddr
, int_ip
);
1533 SoapError(h
, 606, "Action not authorized");
1537 /* Pinhole InternalPort must be greater than or equal to 1024 */
1538 if (int_port
< 1024)
1540 syslog(LOG_INFO
, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1542 SoapError(h
, 606, "Action not authorized");
1549 AddPinhole(struct upnphttp
* h
, const char * action
, const char * ns
)
1552 static const char resp
[] =
1555 "<UniqueID>%d</UniqueID>"
1559 struct NameValueParserData data
;
1560 char * rem_host
, * rem_port
, * int_ip
, * int_port
, * protocol
, * leaseTime
;
1562 unsigned short iport
, rport
;
1565 char rem_ip
[INET6_ADDRSTRLEN
];
1567 if(CheckStatus(h
)==0)
1570 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1571 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1572 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1573 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1574 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1575 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1576 leaseTime
= GetValueFromNameValueList(&data
, "LeaseTime");
1578 rport
= (unsigned short)(rem_port
? atoi(rem_port
) : 0);
1579 iport
= (unsigned short)(int_port
? atoi(int_port
) : 0);
1580 ltime
= leaseTime
? atoi(leaseTime
) : -1;
1582 proto
= protocol
? strtol(protocol
, NULL
, 0) : -1;
1583 if(errno
!= 0 || proto
> 65535 || proto
< 0)
1585 SoapError(h
, 402, "Invalid Args");
1586 goto clear_and_exit
;
1590 SoapError(h
, 706, "InternalPortWilcardingNotAllowed");
1591 goto clear_and_exit
;
1594 /* In particular, [IGD2] RECOMMENDS that unauthenticated and
1595 * unauthorized control points are only allowed to invoke
1597 * - InternalPort value greater than or equal to 1024,
1598 * - InternalClient value equals to the control point's IP address.
1599 * It is REQUIRED that InternalClient cannot be one of IPv6
1600 * addresses used by the gateway. */
1601 if(!int_ip
|| 0 == strlen(int_ip
) || 0 == strcmp(int_ip
, "*"))
1603 SoapError(h
, 708, "WildCardNotPermittedInSrcIP");
1604 goto clear_and_exit
;
1606 /* I guess it is useless to convert int_ip to literal ipv6 address */
1607 /* rem_host should be converted to literal ipv6 : */
1608 if(rem_host
&& (rem_host
[0] != '\0'))
1610 struct addrinfo
*ai
, *p
;
1611 struct addrinfo hints
;
1613 memset(&hints
, 0, sizeof(struct addrinfo
));
1614 hints
.ai_family
= AF_INET6
;
1615 /*hints.ai_flags = */
1616 /* hints.ai_protocol = proto; */
1617 err
= getaddrinfo(rem_host
, rem_port
, &hints
, &ai
);
1620 /* take the 1st IPv6 address */
1621 for(p
= ai
; p
; p
= p
->ai_next
)
1623 if(p
->ai_family
== AF_INET6
)
1626 &(((struct sockaddr_in6
*)p
->ai_addr
)->sin6_addr
),
1627 rem_ip
, sizeof(rem_ip
));
1628 syslog(LOG_INFO
, "resolved '%s' to '%s'", rem_host
, rem_ip
);
1637 syslog(LOG_WARNING
, "AddPinhole : getaddrinfo(%s) : %s",
1638 rem_host
, gai_strerror(err
));
1640 SoapError(h
, 402, "Invalid Args");
1641 goto clear_and_exit
;
1648 SoapError(h
, 707, "ProtocolWilcardingNotAllowed");
1649 goto clear_and_exit
;
1651 if(proto
!= IPPROTO_UDP
&& proto
!= IPPROTO_TCP
1652 #ifdef IPPROTO_UDPITE
1653 && atoi(protocol
) != IPPROTO_UDPLITE
1657 SoapError(h
, 705, "ProtocolNotSupported");
1658 goto clear_and_exit
;
1660 if(ltime
< 1 || ltime
> 86400)
1662 syslog(LOG_WARNING
, "%s: LeaseTime=%d not supported, (ip=%s)",
1663 action
, ltime
, int_ip
);
1664 SoapError(h
, 402, "Invalid Args");
1665 goto clear_and_exit
;
1668 if(PinholeVerification(h
, int_ip
, iport
) <= 0)
1669 goto clear_and_exit
;
1671 syslog(LOG_INFO
, "%s: (inbound) from [%s]:%hu to [%s]:%hu with proto %ld during %d sec",
1672 action
, rem_host
?rem_host
:"any",
1673 rport
, int_ip
, iport
,
1676 /* In cases where the RemoteHost, RemotePort, InternalPort,
1677 * InternalClient and Protocol are the same than an existing pinhole,
1678 * but LeaseTime is different, the device MUST extend the existing
1679 * pinhole's lease time and return the UniqueID of the existing pinhole. */
1680 r
= upnp_add_inboundpinhole(rem_host
, rport
, int_ip
, iport
, proto
, "IGD2 pinhole", ltime
, &uid
);
1684 case 1: /* success */
1685 bodylen
= snprintf(body
, sizeof(body
),
1687 ns
/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1689 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1691 case -1: /* not permitted */
1692 SoapError(h
, 701, "PinholeSpaceExhausted");
1695 SoapError(h
, 501, "ActionFailed");
1698 /* 606 Action not authorized
1699 * 701 PinholeSpaceExhausted
1700 * 702 FirewallDisabled
1701 * 703 InboundPinholeNotAllowed
1702 * 705 ProtocolNotSupported
1703 * 706 InternalPortWildcardingNotAllowed
1704 * 707 ProtocolWildcardingNotAllowed
1705 * 708 WildCardNotPermittedInSrcIP */
1707 ClearNameValueList(&data
);
1711 UpdatePinhole(struct upnphttp
* h
, const char * action
, const char * ns
)
1714 static const char resp
[] =
1715 "<u:UpdatePinholeResponse "
1716 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1717 "</u:UpdatePinholeResponse>";
1719 static const char resp
[] =
1725 struct NameValueParserData data
;
1726 const char * uid_str
, * leaseTime
;
1727 char iaddr
[INET6_ADDRSTRLEN
];
1728 unsigned short iport
;
1733 if(CheckStatus(h
)==0)
1736 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1737 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1738 leaseTime
= GetValueFromNameValueList(&data
, "NewLeaseTime");
1739 uid
= uid_str
? atoi(uid_str
) : -1;
1740 ltime
= leaseTime
? atoi(leaseTime
) : -1;
1741 ClearNameValueList(&data
);
1743 if(uid
< 0 || uid
> 65535 || ltime
<= 0 || ltime
> 86400)
1745 SoapError(h
, 402, "Invalid Args");
1749 /* Check that client is not updating an pinhole
1750 * it doesn't have access to, because of its public access */
1751 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
1752 iaddr
, sizeof(iaddr
), &iport
,
1754 NULL
, 0, /* desc, desclen */
1758 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1763 SoapError(h
, 704, "NoSuchEntry");
1768 SoapError(h
, 501, "ActionFailed");
1772 syslog(LOG_INFO
, "%s: (inbound) updating lease duration to %d for pinhole with ID: %d",
1773 action
, ltime
, uid
);
1775 n
= upnp_update_inboundpinhole(uid
, ltime
);
1777 SoapError(h
, 704, "NoSuchEntry");
1779 SoapError(h
, 501, "ActionFailed");
1781 bodylen
= snprintf(body
, sizeof(body
), resp
,
1782 action
, ns
, action
);
1783 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1788 GetOutboundPinholeTimeout(struct upnphttp
* h
, const char * action
, const char * ns
)
1792 static const char resp
[] =
1795 "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1800 struct NameValueParserData data
;
1801 char * int_ip
, * int_port
, * rem_host
, * rem_port
, * protocol
;
1804 unsigned short iport
, rport
;
1806 if (GETFLAG(IPV6FCFWDISABLEDMASK
))
1808 SoapError(h
, 702, "FirewallDisabled");
1812 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1813 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1814 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1815 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1816 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1817 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1819 rport
= (unsigned short)atoi(rem_port
);
1820 iport
= (unsigned short)atoi(int_port
);
1821 /*proto = atoi(protocol);*/
1823 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
);
1826 r
= -1;/*upnp_check_outbound_pinhole(proto, &opt);*/
1830 case 1: /* success */
1831 bodylen
= snprintf(body
, sizeof(body
), resp
,
1832 action
, ns
/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1834 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1836 case -5: /* Protocol not supported */
1837 SoapError(h
, 705, "ProtocolNotSupported");
1840 SoapError(h
, 501, "ActionFailed");
1842 ClearNameValueList(&data
);
1846 DeletePinhole(struct upnphttp
* h
, const char * action
, const char * ns
)
1850 static const char resp
[] =
1851 "<u:DeletePinholeResponse "
1852 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1853 "</u:DeletePinholeResponse>";
1855 static const char resp
[] =
1862 struct NameValueParserData data
;
1863 const char * uid_str
;
1864 char iaddr
[INET6_ADDRSTRLEN
];
1866 unsigned short iport
;
1867 unsigned int leasetime
;
1870 if(CheckStatus(h
)==0)
1873 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1874 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1875 uid
= uid_str
? atoi(uid_str
) : -1;
1876 ClearNameValueList(&data
);
1878 if(uid
< 0 || uid
> 65535)
1880 SoapError(h
, 402, "Invalid Args");
1884 /* Check that client is not deleting an pinhole
1885 * it doesn't have access to, because of its public access */
1886 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
1887 iaddr
, sizeof(iaddr
), &iport
,
1889 NULL
, 0, /* desc, desclen */
1893 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1898 SoapError(h
, 704, "NoSuchEntry");
1903 SoapError(h
, 501, "ActionFailed");
1907 n
= upnp_delete_inboundpinhole(uid
);
1910 syslog(LOG_INFO
, "%s: (inbound) failed to remove pinhole with ID: %d",
1912 SoapError(h
, 501, "ActionFailed");
1915 syslog(LOG_INFO
, "%s: (inbound) pinhole with ID %d successfully removed",
1917 bodylen
= snprintf(body
, sizeof(body
), resp
,
1918 action
, ns
, action
);
1919 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1923 CheckPinholeWorking(struct upnphttp
* h
, const char * action
, const char * ns
)
1925 static const char resp
[] =
1928 "<IsWorking>%d</IsWorking>"
1933 struct NameValueParserData data
;
1934 const char * uid_str
;
1936 char iaddr
[INET6_ADDRSTRLEN
];
1937 unsigned short iport
;
1938 unsigned int packets
;
1940 if(CheckStatus(h
)==0)
1943 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1944 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1945 uid
= uid_str
? atoi(uid_str
) : -1;
1946 ClearNameValueList(&data
);
1948 if(uid
< 0 || uid
> 65535)
1950 SoapError(h
, 402, "Invalid Args");
1954 /* Check that client is not checking a pinhole
1955 * it doesn't have access to, because of its public access */
1956 r
= upnp_get_pinhole_info(uid
,
1958 iaddr
, sizeof(iaddr
), &iport
,
1960 NULL
, 0, /* desc, desclen */
1964 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1968 SoapError(h
, 709, "NoPacketSent");
1971 bodylen
= snprintf(body
, sizeof(body
), resp
,
1972 action
, ns
/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1974 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1977 SoapError(h
, 704, "NoSuchEntry");
1979 SoapError(h
, 501, "ActionFailed");
1983 GetPinholePackets(struct upnphttp
* h
, const char * action
, const char * ns
)
1985 static const char resp
[] =
1988 "<PinholePackets>%u</PinholePackets>"
1992 struct NameValueParserData data
;
1993 const char * uid_str
;
1995 char iaddr
[INET6_ADDRSTRLEN
];
1996 unsigned short iport
;
1997 unsigned int packets
= 0;
2000 unsigned int leasetime
;
2002 if(CheckStatus(h
)==0)
2005 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
2006 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
2007 uid
= uid_str
? atoi(uid_str
) : -1;
2008 ClearNameValueList(&data
);
2010 if(uid
< 0 || uid
> 65535)
2012 SoapError(h
, 402, "Invalid Args");
2016 /* Check that client is not getting infos of a pinhole
2017 * it doesn't have access to, because of its public access */
2018 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
2019 iaddr
, sizeof(iaddr
), &iport
,
2021 NULL
, 0, /* desc, desclen */
2022 &leasetime
, &packets
);
2025 if(PinholeVerification(h
, iaddr
, iport
)<=0)
2029 else if(r
== -4 || r
== -1)
2031 SoapError(h
, 704, "NoSuchEntry");
2035 bodylen
= snprintf(body
, sizeof(body
), resp
,
2036 action
, ns
/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
2038 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
2042 #ifdef ENABLE_DP_SERVICE
2044 SendSetupMessage(struct upnphttp
* h
, const char * action
, const char * ns
)
2046 static const char resp
[] =
2049 "<OutMessage>%s</OutMessage>"
2053 struct NameValueParserData data
;
2054 const char * ProtocolType
; /* string */
2055 const char * InMessage
; /* base64 */
2056 const char * OutMessage
= ""; /* base64 */
2058 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
2059 ProtocolType
= GetValueFromNameValueList(&data
, "ProtocolType"); /* string */
2060 InMessage
= GetValueFromNameValueList(&data
, "InMessage"); /* base64 */
2062 if(ProtocolType
== NULL
|| InMessage
== NULL
)
2064 ClearNameValueList(&data
);
2065 SoapError(h
, 402, "Invalid Args");
2068 /*if(strcmp(ProtocolType, "DeviceProtection:1") != 0)*/
2069 if(strcmp(ProtocolType
, "WPS") != 0)
2071 ClearNameValueList(&data
);
2072 SoapError(h
, 600, "Argument Value Invalid"); /* 703 ? */
2075 /* TODO : put here code for WPS */
2077 bodylen
= snprintf(body
, sizeof(body
), resp
,
2078 action
, ns
/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2079 OutMessage
, action
);
2080 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
2081 ClearNameValueList(&data
);
2085 GetSupportedProtocols(struct upnphttp
* h
, const char * action
, const char * ns
)
2087 static const char resp
[] =
2090 "<ProtocolList><![CDATA[%s]]></ProtocolList>"
2094 const char * ProtocolList
=
2095 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
2096 "<SupportedProtocols xmlns=\"urn:schemas-upnp-org:gw:DeviceProtection\""
2097 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
2098 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:DeviceProtection"
2099 " http://www.upnp.org/schemas/gw/DeviceProtection-v1.xsd\">"
2100 "<Introduction><Name>WPS</Name></Introduction>"
2101 "<Login><Name>PKCS5</Name></Login>"
2102 "</SupportedProtocols>";
2104 bodylen
= snprintf(body
, sizeof(body
), resp
,
2105 action
, ns
/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2106 ProtocolList
, action
);
2107 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
2111 GetAssignedRoles(struct upnphttp
* h
, const char * action
, const char * ns
)
2113 static const char resp
[] =
2116 "<RoleList>%s</RoleList>"
2120 const char * RoleList
= "Public"; /* list of roles separated by spaces */
2123 if(h
->ssl
!= NULL
) {
2124 /* we should get the Roles of the session (based on client certificate) */
2126 peercert
= SSL_get_peer_certificate(h
->ssl
);
2127 if(peercert
!= NULL
) {
2128 RoleList
= "Admin Basic";
2129 X509_free(peercert
);
2134 bodylen
= snprintf(body
, sizeof(body
), resp
,
2135 action
, ns
/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2137 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
2141 /* Windows XP as client send the following requests :
2142 * GetConnectionTypeInfo
2144 * ? GetTotalBytesSent - WANCommonInterfaceConfig
2145 * ? GetTotalBytesReceived - idem
2146 * ? GetTotalPacketsSent - idem
2147 * ? GetTotalPacketsReceived - idem
2148 * GetCommonLinkProperties - idem
2149 * GetStatusInfo - WANIPConnection
2150 * GetExternalIPAddress
2151 * QueryStateVariable / ConnectionStatus!
2155 const char * methodName
;
2156 void (*methodImpl
)(struct upnphttp
*, const char *, const char *);
2160 /* WANCommonInterfaceConfig */
2161 { "QueryStateVariable", QueryStateVariable
},
2162 { "GetTotalBytesSent", GetTotalBytesSent
},
2163 { "GetTotalBytesReceived", GetTotalBytesReceived
},
2164 { "GetTotalPacketsSent", GetTotalPacketsSent
},
2165 { "GetTotalPacketsReceived", GetTotalPacketsReceived
},
2166 { "GetCommonLinkProperties", GetCommonLinkProperties
},
2167 { "GetStatusInfo", GetStatusInfo
},
2168 /* WANIPConnection */
2169 { "GetConnectionTypeInfo", GetConnectionTypeInfo
},
2170 { "GetNATRSIPStatus", GetNATRSIPStatus
},
2171 { "GetExternalIPAddress", GetExternalIPAddress
},
2172 { "AddPortMapping", AddPortMapping
},
2173 { "DeletePortMapping", DeletePortMapping
},
2174 { "GetGenericPortMappingEntry", GetGenericPortMappingEntry
},
2175 { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry
},
2176 /* Required in WANIPConnection:2 */
2177 { "SetConnectionType", SetConnectionType
},
2178 { "RequestConnection", RequestConnection
},
2179 { "ForceTermination", ForceTermination
},
2180 { "AddAnyPortMapping", AddAnyPortMapping
},
2181 { "DeletePortMappingRange", DeletePortMappingRange
},
2182 { "GetListOfPortMappings", GetListOfPortMappings
},
2183 #ifdef ENABLE_L3F_SERVICE
2184 /* Layer3Forwarding */
2185 { "SetDefaultConnectionService", SetDefaultConnectionService
},
2186 { "GetDefaultConnectionService", GetDefaultConnectionService
},
2188 #ifdef ENABLE_6FC_SERVICE
2189 /* WANIPv6FirewallControl */
2190 { "GetFirewallStatus", GetFirewallStatus
}, /* Required */
2191 { "AddPinhole", AddPinhole
}, /* Required */
2192 { "UpdatePinhole", UpdatePinhole
}, /* Required */
2193 { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout
}, /* Optional */
2194 { "DeletePinhole", DeletePinhole
}, /* Required */
2195 { "CheckPinholeWorking", CheckPinholeWorking
}, /* Optional */
2196 { "GetPinholePackets", GetPinholePackets
}, /* Required */
2198 #ifdef ENABLE_DP_SERVICE
2199 /* DeviceProtection */
2200 { "SendSetupMessage", SendSetupMessage
}, /* Required */
2201 { "GetSupportedProtocols", GetSupportedProtocols
}, /* Required */
2202 { "GetAssignedRoles", GetAssignedRoles
}, /* Required */
2208 ExecuteSoapAction(struct upnphttp
* h
, const char * action
, int n
)
2212 int i
, len
, methodlen
;
2213 char namespace[256];
2215 /* SoapAction example :
2216 * urn:schemas-upnp-org:service:WANIPConnection:1#GetStatusInfo */
2217 p
= strchr(action
, '#');
2218 if(p
&& (p
- action
) < n
) {
2219 for(i
= 0; i
< ((int)sizeof(namespace) - 1) && (action
+ i
) < p
; i
++)
2220 namespace[i
] = action
[i
];
2221 namespace[i
] = '\0';
2223 p2
= strchr(p
, '"');
2224 if(p2
&& (p2
- action
) <= n
)
2227 methodlen
= n
- (p
- action
);
2228 /*syslog(LOG_DEBUG, "SoapMethod: %.*s %d %d %p %p %d",
2229 methodlen, p, methodlen, n, action, p, (int)(p - action));*/
2230 for(i
= 0; soapMethods
[i
].methodName
; i
++) {
2231 len
= strlen(soapMethods
[i
].methodName
);
2232 if((len
== methodlen
) && memcmp(p
, soapMethods
[i
].methodName
, len
) == 0) {
2234 syslog(LOG_DEBUG
, "Remote Call of SoapMethod '%s' %s",
2235 soapMethods
[i
].methodName
, namespace);
2237 soapMethods
[i
].methodImpl(h
, soapMethods
[i
].methodName
, namespace);
2241 syslog(LOG_NOTICE
, "SoapMethod: Unknown: %.*s %s", methodlen
, p
, namespace);
2243 syslog(LOG_NOTICE
, "cannot parse SoapAction");
2246 SoapError(h
, 401, "Invalid Action");
2251 * errorCode errorDescription Description
2252 * -------- ---------------- -----------
2253 * 401 Invalid Action No action by that name at this service.
2254 * 402 Invalid Args Could be any of the following: not enough in args,
2255 * too many in args, no in arg by that name,
2256 * one or more in args are of the wrong data type.
2257 * 403 Out of Sync Out of synchronization.
2258 * 501 Action Failed May be returned in current state of service
2259 * prevents invoking that action.
2260 * 600-699 TBD Common action errors. Defined by UPnP Forum
2261 * Technical Committee.
2262 * 700-799 TBD Action-specific errors for standard actions.
2263 * Defined by UPnP Forum working committee.
2264 * 800-899 TBD Action-specific errors for non-standard actions.
2265 * Defined by UPnP vendor.
2268 SoapError(struct upnphttp
* h
, int errCode
, const char * errDesc
)
2270 static const char resp
[] =
2272 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
2273 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
2276 "<faultcode>s:Client</faultcode>"
2277 "<faultstring>UPnPError</faultstring>"
2279 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
2280 "<errorCode>%d</errorCode>"
2281 "<errorDescription>%s</errorDescription>"
2291 syslog(LOG_INFO
, "Returning UPnPError %d: %s", errCode
, errDesc
);
2292 bodylen
= snprintf(body
, sizeof(body
), resp
, errCode
, errDesc
);
2293 BuildResp2_upnphttp(h
, 500, "Internal Server Error", body
, bodylen
);
2294 SendRespAndClose_upnphttp(h
);