1 /* $Id: upnpsoap.c,v 1.142 2015/12/15 11:12:37 nanard Exp $ */
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 */
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"
35 BuildSendAndCloseSoapResp(struct upnphttp
* h
,
36 const char * body
, int bodylen
)
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/\">"
44 static const char afterbody
[] =
48 int r
= BuildHeader_upnphttp(h
, 200, "OK", sizeof(beforebody
) - 1
49 + sizeof(afterbody
) - 1 + bodylen
);
52 memcpy(h
->res_buf
+ h
->res_buflen
, beforebody
, sizeof(beforebody
) - 1);
53 h
->res_buflen
+= sizeof(beforebody
) - 1;
55 memcpy(h
->res_buf
+ h
->res_buflen
, body
, bodylen
);
56 h
->res_buflen
+= bodylen
;
58 memcpy(h
->res_buf
+ h
->res_buflen
, afterbody
, sizeof(afterbody
) - 1);
59 h
->res_buflen
+= sizeof(afterbody
) - 1;
61 BuildResp2_upnphttp(h
, 500, "Internal Server Error", NULL
, 0);
64 SendRespAndClose_upnphttp(h
);
68 GetConnectionTypeInfo(struct upnphttp
* h
, const char * action
, const char * ns
)
71 static const char resp
[] =
72 "<u:GetConnectionTypeInfoResponse "
73 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
74 "<NewConnectionType>IP_Routed</NewConnectionType>"
75 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
76 "</u:GetConnectionTypeInfoResponse>";
78 static const char resp
[] =
81 "<NewConnectionType>IP_Routed</NewConnectionType>"
82 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
87 bodylen
= snprintf(body
, sizeof(body
), resp
,
89 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
93 GetTotalBytesSent(struct upnphttp
* h
, const char * action
, const char * ns
)
97 static const char resp
[] =
100 "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
107 r
= getifstats(ext_if_name
, &data
);
108 bodylen
= snprintf(body
, sizeof(body
), resp
,
109 action
, ns
, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
110 r
<0?0:data
.obytes
, action
);
111 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
115 GetTotalBytesReceived(struct upnphttp
* h
, const char * action
, const char * ns
)
119 static const char resp
[] =
122 "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
129 r
= getifstats(ext_if_name
, &data
);
130 bodylen
= snprintf(body
, sizeof(body
), resp
,
131 action
, ns
, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
132 r
<0?0:data
.ibytes
, action
);
133 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
137 GetTotalPacketsSent(struct upnphttp
* h
, const char * action
, const char * ns
)
141 static const char resp
[] =
144 "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
151 r
= getifstats(ext_if_name
, &data
);
152 bodylen
= snprintf(body
, sizeof(body
), resp
,
153 action
, ns
,/*"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",*/
154 r
<0?0:data
.opackets
, action
);
155 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
159 GetTotalPacketsReceived(struct upnphttp
* h
, const char * action
, const char * ns
)
163 static const char resp
[] =
166 "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
173 r
= getifstats(ext_if_name
, &data
);
174 bodylen
= snprintf(body
, sizeof(body
), resp
,
175 action
, ns
, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
176 r
<0?0:data
.ipackets
, action
);
177 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
181 GetCommonLinkProperties(struct upnphttp
* h
, const char * action
, const char * ns
)
183 /* WANAccessType : set depending on the hardware :
184 * DSL, POTS (plain old Telephone service), Cable, Ethernet */
185 static const char resp
[] =
188 "<NewWANAccessType>%s</NewWANAccessType>"
189 "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
190 "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
191 "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
197 const char * status
= "Up"; /* Up, Down (Required),
198 * Initializing, Unavailable (Optional) */
199 const char * wan_access_type
= "Cable"; /* DSL, POTS, Cable, Ethernet */
200 char ext_ip_addr
[INET_ADDRSTRLEN
];
202 if((downstream_bitrate
== 0) || (upstream_bitrate
== 0))
204 if(getifstats(ext_if_name
, &data
) >= 0)
206 if(downstream_bitrate
== 0) downstream_bitrate
= data
.baudrate
;
207 if(upstream_bitrate
== 0) upstream_bitrate
= data
.baudrate
;
210 if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
, NULL
, NULL
) < 0) {
213 bodylen
= snprintf(body
, sizeof(body
), resp
,
214 action
, ns
, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
216 upstream_bitrate
, downstream_bitrate
,
218 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
222 GetStatusInfo(struct upnphttp
* h
, const char * action
, const char * ns
)
224 static const char resp
[] =
227 "<NewConnectionStatus>%s</NewConnectionStatus>"
228 "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
229 "<NewUptime>%ld</NewUptime>"
236 /* ConnectionStatus possible values :
237 * Unconfigured, Connecting, Connected, PendingDisconnect,
238 * Disconnecting, Disconnected */
240 status
= get_wan_connection_status_str(ext_if_name
);
241 uptime
= (time(NULL
) - startup_time
);
242 bodylen
= snprintf(body
, sizeof(body
), resp
,
243 action
, ns
, /*SERVICE_TYPE_WANIPC,*/
244 status
, (long)uptime
, action
);
245 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
249 GetNATRSIPStatus(struct upnphttp
* h
, const char * action
, const char * ns
)
252 static const char resp
[] =
253 "<u:GetNATRSIPStatusResponse "
254 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
255 "<NewRSIPAvailable>0</NewRSIPAvailable>"
256 "<NewNATEnabled>1</NewNATEnabled>"
257 "</u:GetNATRSIPStatusResponse>";
260 static const char resp
[] =
263 "<NewRSIPAvailable>0</NewRSIPAvailable>"
264 "<NewNATEnabled>1</NewNATEnabled>"
268 /* 2.2.9. RSIPAvailable
269 * This variable indicates if Realm-specific IP (RSIP) is available
270 * as a feature on the InternetGatewayDevice. RSIP is being defined
271 * in the NAT working group in the IETF to allow host-NATing using
272 * a standard set of message exchanges. It also allows end-to-end
273 * applications that otherwise break if NAT is introduced
274 * (e.g. IPsec-based VPNs).
275 * A gateway that does not support RSIP should set this variable to 0. */
276 bodylen
= snprintf(body
, sizeof(body
), resp
,
277 action
, ns
, /*SERVICE_TYPE_WANIPC,*/
279 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
283 GetExternalIPAddress(struct upnphttp
* h
, const char * action
, const char * ns
)
285 static const char resp
[] =
288 "<NewExternalIPAddress>%s</NewExternalIPAddress>"
293 char ext_ip_addr
[INET_ADDRSTRLEN
];
294 /* Does that method need to work with IPv6 ?
295 * There is usually no NAT with IPv6 */
297 #ifndef MULTIPLE_EXTERNAL_IP
300 strncpy(ext_ip_addr
, use_ext_ip_addr
, INET_ADDRSTRLEN
);
301 ext_ip_addr
[INET_ADDRSTRLEN
- 1] = '\0';
303 else if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
, NULL
, NULL
) < 0)
305 syslog(LOG_ERR
, "Failed to get ip address for interface %s",
307 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
310 struct lan_addr_s
* lan_addr
;
311 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
312 for(lan_addr
= lan_addrs
.lh_first
; lan_addr
!= NULL
; lan_addr
= lan_addr
->list
.le_next
)
314 if( (h
->clientaddr
.s_addr
& lan_addr
->mask
.s_addr
)
315 == (lan_addr
->addr
.s_addr
& lan_addr
->mask
.s_addr
))
317 strncpy(ext_ip_addr
, lan_addr
->ext_ip_str
, INET_ADDRSTRLEN
);
322 bodylen
= snprintf(body
, sizeof(body
), resp
,
323 action
, ns
, /*SERVICE_TYPE_WANIPC,*/
324 ext_ip_addr
, action
);
325 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
328 /* AddPortMapping method of WANIPConnection Service
329 * Ignored argument : NewEnabled */
331 AddPortMapping(struct upnphttp
* h
, const char * action
, const char * ns
)
335 /*static const char resp[] =
336 "<u:AddPortMappingResponse "
337 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";*/
338 static const char resp
[] =
344 struct NameValueParserData data
;
345 char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
346 char * leaseduration_str
;
347 unsigned int leaseduration
;
349 unsigned short iport
, eport
;
351 struct hostent
*hp
; /* getbyhostname() */
352 char ** ptr
; /* getbyhostname() */
353 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
355 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
356 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
359 ClearNameValueList(&data
);
360 SoapError(h
, 402, "Invalid Args");
364 /* IGD 2 MUST support both wildcard and specific IP address values
365 * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
366 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
367 #ifndef SUPPORT_REMOTEHOST
369 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
371 ClearNameValueList(&data
);
372 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
378 /* if ip not valid assume hostname and convert */
379 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
381 hp
= gethostbyname(int_ip
);
382 if(hp
&& hp
->h_addrtype
== AF_INET
)
384 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
386 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
387 result_ip
= *((struct in_addr
*) *ptr
);
388 /* TODO : deal with more than one ip per hostname */
394 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
395 ClearNameValueList(&data
);
396 SoapError(h
, 402, "Invalid Args");
401 /* check if NewInternalAddress is the client address */
402 if(GETFLAG(SECUREMODEMASK
))
404 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
406 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
407 inet_ntoa(h
->clientaddr
), int_ip
);
408 ClearNameValueList(&data
);
409 SoapError(h
, 718, "ConflictInMappingEntry");
414 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
415 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
416 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
417 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
418 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
420 if (!int_port
|| !ext_port
|| !protocol
)
422 ClearNameValueList(&data
);
423 SoapError(h
, 402, "Invalid Args");
427 eport
= (unsigned short)atoi(ext_port
);
428 iport
= (unsigned short)atoi(int_port
);
430 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
432 /* PortMappingLeaseDuration can be either a value between 1 and
433 * 604800 seconds or the zero value (for infinite lease time).
434 * Note that an infinite lease time can be only set by out-of-band
435 * mechanisms like WWW-administration, remote management or local
437 * If a control point uses the value 0 to indicate an infinite lease
438 * time mapping, it is REQUIRED that gateway uses the maximum value
439 * instead (e.g. 604800 seconds) */
440 if(leaseduration
== 0 || leaseduration
> 604800)
441 leaseduration
= 604800;
444 syslog(LOG_INFO
, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
445 action
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
,
446 r_host
? r_host
: "NULL");
448 /* TODO : be compliant with IGD spec for updating existing port mappings.
449 See "WANIPConnection:1 Service Template Version 1.01" 2.2.20.PortMappingDescription :
450 Overwriting Previous / Existing Port Mappings:
451 If the RemoteHost, ExternalPort, PortMappingProtocol and InternalClient are
452 exactly the same as an existing mapping, the existing mapping values for InternalPort,
453 PortMappingDescription, PortMappingEnabled and PortMappingLeaseDuration are
456 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
458 ClearNameValueList(&data
);
460 /* possible error codes for AddPortMapping :
462 * 501 - Action Failed
463 * 715 - Wildcard not permited in SrcAddr
464 * 716 - Wildcard not permited in ExtPort
465 * 718 - ConflictInMappingEntry
466 * 724 - SamePortValuesRequired (deprecated in IGD v2)
467 * 725 - OnlyPermanentLeasesSupported
468 The NAT implementation only supports permanent lease times on
469 port mappings (deprecated in IGD v2)
470 * 726 - RemoteHostOnlySupportsWildcard
471 RemoteHost must be a wildcard and cannot be a specific IP
472 address or DNS name (deprecated in IGD v2)
473 * 727 - ExternalPortOnlySupportsWildcard
474 ExternalPort must be a wildcard and cannot be a specific port
475 value (deprecated in IGD v2)
476 * 728 - NoPortMapsAvailable
477 There are not enough free prots available to complete the mapping
479 * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
482 case 0: /* success */
483 bodylen
= snprintf(body
, sizeof(body
), resp
,
484 action
, ns
/*SERVICE_TYPE_WANIPC*/);
485 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
487 case -2: /* already redirected */
488 case -3: /* not permitted */
489 SoapError(h
, 718, "ConflictInMappingEntry");
492 SoapError(h
, 501, "ActionFailed");
496 /* AddAnyPortMapping was added in WANIPConnection v2 */
498 AddAnyPortMapping(struct upnphttp
* h
, const char * action
, const char * ns
)
501 static const char resp
[] =
504 "<NewReservedPort>%hu</NewReservedPort>"
510 struct NameValueParserData data
;
511 const char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
513 unsigned short iport
, eport
;
514 const char * leaseduration_str
;
515 unsigned int leaseduration
;
517 struct hostent
*hp
; /* getbyhostname() */
518 char ** ptr
; /* getbyhostname() */
519 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
521 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
522 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
523 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
524 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
525 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
526 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
528 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
529 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
531 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
532 if(leaseduration
== 0)
533 leaseduration
= 604800;
535 if (!int_ip
|| !ext_port
|| !int_port
)
537 ClearNameValueList(&data
);
538 SoapError(h
, 402, "Invalid Args");
542 eport
= (unsigned short)atoi(ext_port
);
543 iport
= (unsigned short)atoi(int_port
);
544 #ifndef SUPPORT_REMOTEHOST
546 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
548 ClearNameValueList(&data
);
549 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
555 /* if ip not valid assume hostname and convert */
556 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
558 hp
= gethostbyname(int_ip
);
559 if(hp
&& hp
->h_addrtype
== AF_INET
)
561 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
563 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
564 result_ip
= *((struct in_addr
*) *ptr
);
565 /* TODO : deal with more than one ip per hostname */
571 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
572 ClearNameValueList(&data
);
573 SoapError(h
, 402, "Invalid Args");
578 /* check if NewInternalAddress is the client address */
579 if(GETFLAG(SECUREMODEMASK
))
581 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
583 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
584 inet_ntoa(h
->clientaddr
), int_ip
);
585 ClearNameValueList(&data
);
586 SoapError(h
, 606, "Action not authorized");
591 /* TODO : accept a different external port
592 * have some smart strategy to choose the port */
594 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
595 if(r
==-2 && eport
< 65535) {
602 ClearNameValueList(&data
);
606 case 0: /* success */
607 bodylen
= snprintf(body
, sizeof(body
), resp
,
608 action
, ns
, /*SERVICE_TYPE_WANIPC,*/
610 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
612 case -2: /* already redirected */
613 SoapError(h
, 718, "ConflictInMappingEntry");
615 case -3: /* not permitted */
616 SoapError(h
, 606, "Action not authorized");
619 SoapError(h
, 501, "ActionFailed");
624 GetSpecificPortMappingEntry(struct upnphttp
* h
, const char * action
, const char * ns
)
628 static const char resp
[] =
631 "<NewInternalPort>%u</NewInternalPort>"
632 "<NewInternalClient>%s</NewInternalClient>"
633 "<NewEnabled>1</NewEnabled>"
634 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
635 "<NewLeaseDuration>%u</NewLeaseDuration>"
640 struct NameValueParserData data
;
641 const char * r_host
, * ext_port
, * protocol
;
642 unsigned short eport
, iport
;
645 unsigned int leaseduration
= 0;
647 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
648 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
649 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
650 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
653 if(!ext_port
|| !protocol
|| !r_host
)
655 if(!ext_port
|| !protocol
)
658 ClearNameValueList(&data
);
659 SoapError(h
, 402, "Invalid Args");
662 #ifndef SUPPORT_REMOTEHOST
664 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
666 ClearNameValueList(&data
);
667 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
673 eport
= (unsigned short)atoi(ext_port
);
675 /* TODO : add r_host as an input parameter ...
676 * We prevent several Port Mapping with same external port
677 * but different remoteHost to be set up, so that is not
679 r
= upnp_get_redirection_infos(eport
, protocol
, &iport
,
680 int_ip
, sizeof(int_ip
),
687 SoapError(h
, 714, "NoSuchEntryInArray");
691 syslog(LOG_INFO
, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
693 r_host
? r_host
: "NULL", ext_port
, protocol
, int_ip
,
694 (unsigned int)iport
, desc
);
695 bodylen
= snprintf(body
, sizeof(body
), resp
,
696 action
, ns
/*SERVICE_TYPE_WANIPC*/,
697 (unsigned int)iport
, int_ip
, desc
, leaseduration
,
699 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
702 ClearNameValueList(&data
);
706 DeletePortMapping(struct upnphttp
* h
, const char * action
, const char * ns
)
710 /*static const char resp[] =
711 "<u:DeletePortMappingResponse "
712 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
713 "</u:DeletePortMappingResponse>";*/
714 static const char resp
[] =
721 struct NameValueParserData data
;
722 const char * ext_port
, * protocol
;
723 unsigned short eport
;
726 #endif /* UPNP_STRICT */
728 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
729 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
730 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
732 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
733 #endif /* UPNP_STRICT */
736 if(!ext_port
|| !protocol
|| !r_host
)
738 if(!ext_port
|| !protocol
)
739 #endif /* UPNP_STRICT */
741 ClearNameValueList(&data
);
742 SoapError(h
, 402, "Invalid Args");
745 #ifndef SUPPORT_REMOTEHOST
747 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
749 ClearNameValueList(&data
);
750 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
753 #endif /* UPNP_STRICT */
754 #endif /* SUPPORT_REMOTEHOST */
756 eport
= (unsigned short)atoi(ext_port
);
758 syslog(LOG_INFO
, "%s: external port: %hu, protocol: %s",
759 action
, eport
, protocol
);
761 /* if in secure mode, check the IP
762 * Removing a redirection is not a security threat,
763 * just an annoyance for the user using it. So this is not
765 if(GETFLAG(SECUREMODEMASK
))
768 struct in_addr int_ip_addr
;
769 unsigned short iport
;
770 unsigned int leaseduration
= 0;
771 r
= upnp_get_redirection_infos(eport
, protocol
, &iport
,
772 int_ip
, sizeof(int_ip
),
777 if(inet_pton(AF_INET
, int_ip
, &int_ip_addr
) > 0)
779 if(h
->clientaddr
.s_addr
!= int_ip_addr
.s_addr
)
781 SoapError(h
, 606, "Action not authorized");
782 /*SoapError(h, 714, "NoSuchEntryInArray");*/
783 ClearNameValueList(&data
);
790 r
= upnp_delete_redirection(eport
, protocol
);
794 SoapError(h
, 714, "NoSuchEntryInArray");
798 bodylen
= snprintf(body
, sizeof(body
), resp
,
800 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
803 ClearNameValueList(&data
);
806 /* DeletePortMappingRange was added in IGD spec v2 */
808 DeletePortMappingRange(struct upnphttp
* h
, const char * action
, const char * ns
)
811 /*static const char resp[] =
812 "<u:DeletePortMappingRangeResponse "
813 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
814 "</u:DeletePortMappingRangeResponse>";*/
815 static const char resp
[] =
821 struct NameValueParserData data
;
822 const char * protocol
;
823 const char * startport_s
, * endport_s
;
824 unsigned short startport
, endport
;
826 unsigned short * port_list
;
827 unsigned int i
, number
= 0;
829 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
830 startport_s
= GetValueFromNameValueList(&data
, "NewStartPort");
831 endport_s
= GetValueFromNameValueList(&data
, "NewEndPort");
832 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
833 /*manage = atoi(GetValueFromNameValueList(&data, "NewManage"));*/
834 if(startport_s
== NULL
|| endport_s
== NULL
|| protocol
== NULL
) {
835 SoapError(h
, 402, "Invalid Args");
836 ClearNameValueList(&data
);
839 startport
= (unsigned short)atoi(startport_s
);
840 endport
= (unsigned short)atoi(endport_s
);
843 606 - Action not authorized
844 730 - PortMappingNotFound
845 733 - InconsistentParameter
847 if(startport
> endport
)
849 SoapError(h
, 733, "InconsistentParameter");
850 ClearNameValueList(&data
);
854 syslog(LOG_INFO
, "%s: deleting external ports: %hu-%hu, protocol: %s",
855 action
, startport
, endport
, protocol
);
857 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
861 SoapError(h
, 730, "PortMappingNotFound");
862 ClearNameValueList(&data
);
867 for(i
= 0; i
< number
; i
++)
869 r
= upnp_delete_redirection(port_list
[i
], protocol
);
870 syslog(LOG_INFO
, "%s: deleting external port: %hu, protocol: %s: %s",
871 action
, port_list
[i
], protocol
, r
< 0 ? "failed" : "ok");
874 bodylen
= snprintf(body
, sizeof(body
), resp
,
876 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
878 ClearNameValueList(&data
);
882 GetGenericPortMappingEntry(struct upnphttp
* h
, const char * action
, const char * ns
)
886 static const char resp
[] =
889 "<NewRemoteHost>%s</NewRemoteHost>"
890 "<NewExternalPort>%u</NewExternalPort>"
891 "<NewProtocol>%s</NewProtocol>"
892 "<NewInternalPort>%u</NewInternalPort>"
893 "<NewInternalClient>%s</NewInternalClient>"
894 "<NewEnabled>1</NewEnabled>"
895 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
896 "<NewLeaseDuration>%u</NewLeaseDuration>"
900 unsigned short eport
, iport
;
901 const char * m_index
;
903 char protocol
[4], iaddr
[32];
906 unsigned int leaseduration
= 0;
907 struct NameValueParserData data
;
909 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
910 m_index
= GetValueFromNameValueList(&data
, "NewPortMappingIndex");
914 ClearNameValueList(&data
);
915 SoapError(h
, 402, "Invalid Args");
918 errno
= 0; /* To distinguish success/failure after call */
919 index
= strtol(m_index
, &endptr
, 10);
920 if((errno
== ERANGE
&& (index
== LONG_MAX
|| index
== LONG_MIN
))
921 || (errno
!= 0 && index
== 0) || (m_index
== endptr
))
923 /* should condition (*endptr != '\0') be also an error ? */
924 if(m_index
== endptr
)
925 syslog(LOG_WARNING
, "%s: no digits were found in <%s>",
926 "GetGenericPortMappingEntry", "NewPortMappingIndex");
928 syslog(LOG_WARNING
, "%s: strtol('%s'): %m",
929 "GetGenericPortMappingEntry", m_index
);
930 ClearNameValueList(&data
);
931 SoapError(h
, 402, "Invalid Args");
935 syslog(LOG_INFO
, "%s: index=%d", action
, (int)index
);
938 r
= upnp_get_redirection_infos_by_index((int)index
, &eport
, protocol
, &iport
,
939 iaddr
, sizeof(iaddr
),
941 rhost
, sizeof(rhost
),
946 SoapError(h
, 713, "SpecifiedArrayIndexInvalid");
952 bodylen
= snprintf(body
, sizeof(body
), resp
,
953 action
, ns
, /*SERVICE_TYPE_WANIPC,*/ rhost
,
954 (unsigned int)eport
, protocol
, (unsigned int)iport
, iaddr
, desc
,
955 leaseduration
, action
);
956 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
959 ClearNameValueList(&data
);
962 /* GetListOfPortMappings was added in the IGD v2 specification */
964 GetListOfPortMappings(struct upnphttp
* h
, const char * action
, const char * ns
)
966 static const char resp_start
[] =
969 "<NewPortListing><![CDATA[";
970 static const char resp_end
[] =
971 "]]></NewPortListing>"
974 static const char list_start
[] =
975 "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
976 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
977 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
978 " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
979 static const char list_end
[] =
980 "</p:PortMappingList>";
982 static const char entry
[] =
983 "<p:PortMappingEntry>"
984 "<p:NewRemoteHost>%s</p:NewRemoteHost>"
985 "<p:NewExternalPort>%hu</p:NewExternalPort>"
986 "<p:NewProtocol>%s</p:NewProtocol>"
987 "<p:NewInternalPort>%hu</p:NewInternalPort>"
988 "<p:NewInternalClient>%s</p:NewInternalClient>"
989 "<p:NewEnabled>1</p:NewEnabled>"
990 "<p:NewDescription>%s</p:NewDescription>"
991 "<p:NewLeaseTime>%u</p:NewLeaseTime>"
992 "</p:PortMappingEntry>";
999 unsigned short iport
;
1003 unsigned int leaseduration
= 0;
1005 struct NameValueParserData data
;
1006 const char * startport_s
, * endport_s
;
1007 unsigned short startport
, endport
;
1008 const char * protocol
;
1010 const char * number_s
;
1012 unsigned short * port_list
;
1013 unsigned int i
, list_size
= 0;
1015 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1016 startport_s
= GetValueFromNameValueList(&data
, "NewStartPort");
1017 endport_s
= GetValueFromNameValueList(&data
, "NewEndPort");
1018 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
1019 /*manage_s = GetValueFromNameValueList(&data, "NewManage");*/
1020 number_s
= GetValueFromNameValueList(&data
, "NewNumberOfPorts");
1021 if(startport_s
== NULL
|| endport_s
== NULL
|| protocol
== NULL
||
1023 SoapError(h
, 402, "Invalid Args");
1024 ClearNameValueList(&data
);
1028 startport
= (unsigned short)atoi(startport_s
);
1029 endport
= (unsigned short)atoi(endport_s
);
1030 /*manage = atoi(manage_s);*/
1031 number
= atoi(number_s
);
1032 if(number
== 0) number
= 1000; /* return up to 1000 mappings by default */
1034 if(startport
> endport
)
1036 SoapError(h
, 733, "InconsistentParameter");
1037 ClearNameValueList(&data
);
1041 build the PortMappingList xml document :
1043 <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
1044 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1045 xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
1046 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
1047 <p:PortMappingEntry>
1048 <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
1049 <p:NewExternalPort>2345</p:NewExternalPort>
1050 <p:NewProtocol>TCP</p:NewProtocol>
1051 <p:NewInternalPort>2345</p:NewInternalPort>
1052 <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
1053 <p:NewEnabled>1</p:NewEnabled>
1054 <p:NewDescription>dooom</p:NewDescription>
1055 <p:NewLeaseTime>345</p:NewLeaseTime>
1056 </p:PortMappingEntry>
1057 </p:PortMappingList>
1060 body
= malloc(bodyalloc
);
1063 ClearNameValueList(&data
);
1064 SoapError(h
, 501, "ActionFailed");
1067 bodylen
= snprintf(body
, bodyalloc
, resp_start
,
1068 action
, ns
/*SERVICE_TYPE_WANIPC*/);
1071 SoapError(h
, 501, "ActionFailed");
1075 memcpy(body
+bodylen
, list_start
, sizeof(list_start
));
1076 bodylen
+= (sizeof(list_start
) - 1);
1078 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
1079 protocol
, &list_size
);
1080 /* loop through port mappings */
1081 for(i
= 0; number
> 0 && i
< list_size
; i
++)
1083 /* have a margin of 1024 bytes to store the new entry */
1084 if((unsigned int)bodylen
+ 1024 > bodyalloc
)
1086 char * body_sav
= body
;
1088 body
= realloc(body
, bodyalloc
);
1091 syslog(LOG_CRIT
, "realloc(%p, %u) FAILED", body_sav
, (unsigned)bodyalloc
);
1092 ClearNameValueList(&data
);
1093 SoapError(h
, 501, "ActionFailed");
1100 r
= upnp_get_redirection_infos(port_list
[i
], protocol
, &iport
,
1101 int_ip
, sizeof(int_ip
),
1103 rhost
, sizeof(rhost
),
1107 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, entry
,
1108 rhost
, port_list
[i
], protocol
,
1109 iport
, int_ip
, desc
, leaseduration
);
1116 if((bodylen
+ sizeof(list_end
) + 1024) > bodyalloc
)
1118 char * body_sav
= body
;
1119 bodyalloc
+= (sizeof(list_end
) + 1024);
1120 body
= realloc(body
, bodyalloc
);
1123 syslog(LOG_CRIT
, "realloc(%p, %u) FAILED", body_sav
, (unsigned)bodyalloc
);
1124 ClearNameValueList(&data
);
1125 SoapError(h
, 501, "ActionFailed");
1130 memcpy(body
+bodylen
, list_end
, sizeof(list_end
));
1131 bodylen
+= (sizeof(list_end
) - 1);
1132 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, resp_end
,
1134 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1137 ClearNameValueList(&data
);
1140 #ifdef ENABLE_L3F_SERVICE
1142 SetDefaultConnectionService(struct upnphttp
* h
, const char * action
, const char * ns
)
1144 /*static const char resp[] =
1145 "<u:SetDefaultConnectionServiceResponse "
1146 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1147 "</u:SetDefaultConnectionServiceResponse>";*/
1148 static const char resp
[] =
1154 struct NameValueParserData data
;
1156 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1157 p
= GetValueFromNameValueList(&data
, "NewDefaultConnectionService");
1159 /* 720 InvalidDeviceUUID
1160 * 721 InvalidServiceID
1161 * 723 InvalidConnServiceSelection */
1164 service
= strchr(p
, ',');
1165 if(0 != memcmp(uuidvalue_wcd
, p
, sizeof("uuid:00000000-0000-0000-0000-000000000000") - 1)) {
1166 SoapError(h
, 720, "InvalidDeviceUUID");
1167 } else if(service
== NULL
|| 0 != strcmp(service
+1, SERVICE_ID_WANIPC
)) {
1168 SoapError(h
, 721, "InvalidServiceID");
1172 syslog(LOG_INFO
, "%s(%s) : Ignored", action
, p
);
1173 bodylen
= snprintf(body
, sizeof(body
), resp
,
1174 action
, ns
, action
);
1175 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1178 /* missing argument */
1179 SoapError(h
, 402, "Invalid Args");
1181 ClearNameValueList(&data
);
1185 GetDefaultConnectionService(struct upnphttp
* h
, const char * action
, const char * ns
)
1187 static const char resp
[] =
1191 "<NewDefaultConnectionService>%s:WANConnectionDevice:2,"
1193 "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
1195 SERVICE_ID_WANIPC
"</NewDefaultConnectionService>"
1197 /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
1198 * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
1199 * urn:upnp-org:serviceId:WANPPPConn1 */
1203 /* namespace : urn:schemas-upnp-org:service:Layer3Forwarding:1 */
1204 bodylen
= snprintf(body
, sizeof(body
), resp
,
1205 action
, ns
, uuidvalue_wcd
, action
);
1206 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1210 /* Added for compliance with WANIPConnection v2 */
1212 SetConnectionType(struct upnphttp
* h
, const char * action
, const char * ns
)
1215 const char * connection_type
;
1216 #endif /* UPNP_STRICT */
1217 struct NameValueParserData data
;
1221 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1223 connection_type
= GetValueFromNameValueList(&data
, "NewConnectionType");
1224 if(!connection_type
) {
1225 ClearNameValueList(&data
);
1226 SoapError(h
, 402, "Invalid Args");
1229 #endif /* UPNP_STRICT */
1230 /* Unconfigured, IP_Routed, IP_Bridged */
1231 ClearNameValueList(&data
);
1232 /* always return a ReadOnly error */
1233 SoapError(h
, 731, "ReadOnly");
1236 /* Added for compliance with WANIPConnection v2 */
1238 RequestConnection(struct upnphttp
* h
, const char * action
, const char * ns
)
1242 SoapError(h
, 606, "Action not authorized");
1245 /* Added for compliance with WANIPConnection v2 */
1247 ForceTermination(struct upnphttp
* h
, const char * action
, const char * ns
)
1251 SoapError(h
, 606, "Action not authorized");
1255 If a control point calls QueryStateVariable on a state variable that is not
1256 buffered in memory within (or otherwise available from) the service,
1257 the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1259 QueryStateVariable remains useful as a limited test tool but may not be
1260 part of some future versions of UPnP.
1263 QueryStateVariable(struct upnphttp
* h
, const char * action
, const char * ns
)
1265 static const char resp
[] =
1268 "<return>%s</return>"
1273 struct NameValueParserData data
;
1274 const char * var_name
;
1276 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1277 /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1278 /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1279 var_name
= GetValueFromNameValueList(&data
, "varName");
1281 /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1285 SoapError(h
, 402, "Invalid Args");
1287 else if(strcmp(var_name
, "ConnectionStatus") == 0)
1289 const char * status
;
1291 status
= get_wan_connection_status_str(ext_if_name
);
1292 bodylen
= snprintf(body
, sizeof(body
), resp
,
1293 action
, ns
,/*"urn:schemas-upnp-org:control-1-0",*/
1295 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1299 else if(strcmp(var_name
, "ConnectionType") == 0)
1301 bodylen
= snprintf(body
, sizeof(body
), resp
, "IP_Routed");
1302 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1304 else if(strcmp(var_name
, "LastConnectionError") == 0)
1306 bodylen
= snprintf(body
, sizeof(body
), resp
, "ERROR_NONE");
1307 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1310 else if(strcmp(var_name
, "PortMappingNumberOfEntries") == 0)
1313 snprintf(strn
, sizeof(strn
), "%i",
1314 upnp_get_portmapping_number_of_entries());
1315 bodylen
= snprintf(body
, sizeof(body
), resp
,
1316 action
, ns
,/*"urn:schemas-upnp-org:control-1-0",*/
1318 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1322 syslog(LOG_NOTICE
, "%s: Unknown: %s", action
, var_name
?var_name
:"");
1323 SoapError(h
, 404, "Invalid Var");
1326 ClearNameValueList(&data
);
1329 #ifdef ENABLE_6FC_SERVICE
1331 #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1333 /* WANIPv6FirewallControl actions */
1335 GetFirewallStatus(struct upnphttp
* h
, const char * action
, const char * ns
)
1337 static const char resp
[] =
1340 "<FirewallEnabled>%d</FirewallEnabled>"
1341 "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1347 bodylen
= snprintf(body
, sizeof(body
), resp
,
1348 action
, ns
, /*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",*/
1349 GETFLAG(IPV6FCFWDISABLEDMASK
) ? 0 : 1,
1350 GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK
) ? 0 : 1,
1352 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1356 CheckStatus(struct upnphttp
* h
)
1358 if (GETFLAG(IPV6FCFWDISABLEDMASK
))
1360 SoapError(h
, 702, "FirewallDisabled");
1363 else if(GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK
))
1365 SoapError(h
, 703, "InboundPinholeNotAllowed");
1373 static int connecthostport(const char * host
, unsigned short port
, char * result
)
1376 char hostname
[INET6_ADDRSTRLEN
];
1377 char port_str
[8], ifname
[8], tmp
[4];
1378 struct addrinfo
*ai
, *p
;
1379 struct addrinfo hints
;
1381 memset(&hints
, 0, sizeof(hints
));
1382 /* hints.ai_flags = AI_ADDRCONFIG; */
1383 #ifdef AI_NUMERICSERV
1384 hints
.ai_flags
= AI_NUMERICSERV
;
1386 hints
.ai_socktype
= SOCK_STREAM
;
1387 hints
.ai_family
= AF_UNSPEC
; /* AF_INET, AF_INET6 or AF_UNSPEC */
1388 /* hints.ai_protocol = IPPROTO_TCP; */
1389 snprintf(port_str
, sizeof(port_str
), "%hu", port
);
1390 strcpy(hostname
, host
);
1391 if(!strncmp(host
, "fe80", 4))
1393 printf("Using an linklocal address\n");
1394 strcpy(ifname
, "%");
1395 snprintf(tmp
, sizeof(tmp
), "%d", linklocal_index
);
1396 strcat(ifname
, tmp
);
1397 strcat(hostname
, ifname
);
1398 printf("host: %s\n", hostname
);
1400 n
= getaddrinfo(hostname
, port_str
, &hints
, &ai
);
1403 fprintf(stderr
, "getaddrinfo() error : %s\n", gai_strerror(n
));
1407 for(p
= ai
; p
; p
= p
->ai_next
)
1411 char tmp_service
[256];
1412 printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1413 p
->ai_family
, p
->ai_socktype
, p
->ai_protocol
, p
->ai_addrlen
);
1414 getnameinfo(p
->ai_addr
, p
->ai_addrlen
, tmp_host
, sizeof(tmp_host
),
1415 tmp_service
, sizeof(tmp_service
),
1416 NI_NUMERICHOST
| NI_NUMERICSERV
);
1417 printf(" host=%s service=%s\n", tmp_host
, tmp_service
);
1419 inet_ntop(AF_INET6
, &(((struct sockaddr_in6
*)p
->ai_addr
)->sin6_addr
), result
, INET6_ADDRSTRLEN
);
1426 /* Check the security policy right */
1428 PinholeVerification(struct upnphttp
* h
, char * int_ip
, unsigned short int_port
)
1431 char senderAddr
[INET6_ADDRSTRLEN
]="";
1432 struct addrinfo hints
, *ai
, *p
;
1433 struct in6_addr result_ip
;
1435 /* Pinhole InternalClient address must correspond to the action sender */
1436 syslog(LOG_INFO
, "Checking internal IP@ and port (Security policy purpose)");
1438 hints
.ai_socktype
= SOCK_STREAM
;
1439 hints
.ai_family
= AF_UNSPEC
;
1441 /* if ip not valid assume hostname and convert */
1442 if (inet_pton(AF_INET6
, int_ip
, &result_ip
) <= 0)
1444 n
= getaddrinfo(int_ip
, NULL
, &hints
, &ai
);
1445 if(!n
&& ai
->ai_family
== AF_INET6
)
1447 for(p
= ai
; p
; p
= p
->ai_next
)
1449 inet_ntop(AF_INET6
, (struct in6_addr
*) p
, int_ip
, sizeof(struct in6_addr
));
1450 result_ip
= *((struct in6_addr
*) p
);
1451 /* TODO : deal with more than one ip per hostname */
1457 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
1458 SoapError(h
, 402, "Invalid Args");
1464 if(inet_ntop(AF_INET6
, &(h
->clientaddr_v6
), senderAddr
, INET6_ADDRSTRLEN
) == NULL
)
1466 syslog(LOG_ERR
, "inet_ntop: %m");
1469 printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr
, int_ip
);
1471 if(strcmp(senderAddr
, int_ip
) != 0)
1472 if(h
->clientaddr_v6
.s6_addr
!= result_ip
.s6_addr
)
1474 syslog(LOG_INFO
, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1475 senderAddr
, int_ip
);
1476 SoapError(h
, 606, "Action not authorized");
1480 /* Pinhole InternalPort must be greater than or equal to 1024 */
1481 if (int_port
< 1024)
1483 syslog(LOG_INFO
, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1485 SoapError(h
, 606, "Action not authorized");
1492 AddPinhole(struct upnphttp
* h
, const char * action
, const char * ns
)
1495 static const char resp
[] =
1498 "<UniqueID>%d</UniqueID>"
1502 struct NameValueParserData data
;
1503 char * rem_host
, * rem_port
, * int_ip
, * int_port
, * protocol
, * leaseTime
;
1505 unsigned short iport
, rport
;
1508 char rem_ip
[INET6_ADDRSTRLEN
];
1510 if(CheckStatus(h
)==0)
1513 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1514 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1515 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1516 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1517 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1518 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1519 leaseTime
= GetValueFromNameValueList(&data
, "LeaseTime");
1521 rport
= (unsigned short)(rem_port
? atoi(rem_port
) : 0);
1522 iport
= (unsigned short)(int_port
? atoi(int_port
) : 0);
1523 ltime
= leaseTime
? atoi(leaseTime
) : -1;
1525 proto
= protocol
? strtol(protocol
, NULL
, 0) : -1;
1526 if(errno
!= 0 || proto
> 65535 || proto
< 0)
1528 SoapError(h
, 402, "Invalid Args");
1529 goto clear_and_exit
;
1533 SoapError(h
, 706, "InternalPortWilcardingNotAllowed");
1534 goto clear_and_exit
;
1537 /* In particular, [IGD2] RECOMMENDS that unauthenticated and
1538 * unauthorized control points are only allowed to invoke
1540 * - InternalPort value greater than or equal to 1024,
1541 * - InternalClient value equals to the control point's IP address.
1542 * It is REQUIRED that InternalClient cannot be one of IPv6
1543 * addresses used by the gateway. */
1544 if(!int_ip
|| 0 == strlen(int_ip
) || 0 == strcmp(int_ip
, "*"))
1546 SoapError(h
, 708, "WildCardNotPermittedInSrcIP");
1547 goto clear_and_exit
;
1549 /* I guess it is useless to convert int_ip to literal ipv6 address */
1550 /* rem_host should be converted to literal ipv6 : */
1551 if(rem_host
&& (rem_host
[0] != '\0'))
1553 struct addrinfo
*ai
, *p
;
1554 struct addrinfo hints
;
1556 memset(&hints
, 0, sizeof(struct addrinfo
));
1557 hints
.ai_family
= AF_INET6
;
1558 /*hints.ai_flags = */
1559 /* hints.ai_protocol = proto; */
1560 err
= getaddrinfo(rem_host
, rem_port
, &hints
, &ai
);
1563 /* take the 1st IPv6 address */
1564 for(p
= ai
; p
; p
= p
->ai_next
)
1566 if(p
->ai_family
== AF_INET6
)
1569 &(((struct sockaddr_in6
*)p
->ai_addr
)->sin6_addr
),
1570 rem_ip
, sizeof(rem_ip
));
1571 syslog(LOG_INFO
, "resolved '%s' to '%s'", rem_host
, rem_ip
);
1580 syslog(LOG_WARNING
, "AddPinhole : getaddrinfo(%s) : %s",
1581 rem_host
, gai_strerror(err
));
1583 SoapError(h
, 402, "Invalid Args");
1584 goto clear_and_exit
;
1591 SoapError(h
, 707, "ProtocolWilcardingNotAllowed");
1592 goto clear_and_exit
;
1594 if(proto
!= IPPROTO_UDP
&& proto
!= IPPROTO_TCP
1595 #ifdef IPPROTO_UDPITE
1596 && atoi(protocol
) != IPPROTO_UDPLITE
1600 SoapError(h
, 705, "ProtocolNotSupported");
1601 goto clear_and_exit
;
1603 if(ltime
< 1 || ltime
> 86400)
1605 syslog(LOG_WARNING
, "%s: LeaseTime=%d not supported, (ip=%s)",
1606 action
, ltime
, int_ip
);
1607 SoapError(h
, 402, "Invalid Args");
1608 goto clear_and_exit
;
1611 if(PinholeVerification(h
, int_ip
, iport
) <= 0)
1612 goto clear_and_exit
;
1614 syslog(LOG_INFO
, "%s: (inbound) from [%s]:%hu to [%s]:%hu with proto %ld during %d sec",
1615 action
, rem_host
?rem_host
:"any",
1616 rport
, int_ip
, iport
,
1619 /* In cases where the RemoteHost, RemotePort, InternalPort,
1620 * InternalClient and Protocol are the same than an existing pinhole,
1621 * but LeaseTime is different, the device MUST extend the existing
1622 * pinhole's lease time and return the UniqueID of the existing pinhole. */
1623 r
= upnp_add_inboundpinhole(rem_host
, rport
, int_ip
, iport
, proto
, "IGD2 pinhole", ltime
, &uid
);
1627 case 1: /* success */
1628 bodylen
= snprintf(body
, sizeof(body
),
1630 ns
/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1632 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1634 case -1: /* not permitted */
1635 SoapError(h
, 701, "PinholeSpaceExhausted");
1638 SoapError(h
, 501, "ActionFailed");
1641 /* 606 Action not authorized
1642 * 701 PinholeSpaceExhausted
1643 * 702 FirewallDisabled
1644 * 703 InboundPinholeNotAllowed
1645 * 705 ProtocolNotSupported
1646 * 706 InternalPortWildcardingNotAllowed
1647 * 707 ProtocolWildcardingNotAllowed
1648 * 708 WildCardNotPermittedInSrcIP */
1650 ClearNameValueList(&data
);
1654 UpdatePinhole(struct upnphttp
* h
, const char * action
, const char * ns
)
1657 static const char resp
[] =
1658 "<u:UpdatePinholeResponse "
1659 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1660 "</u:UpdatePinholeResponse>";
1662 static const char resp
[] =
1668 struct NameValueParserData data
;
1669 const char * uid_str
, * leaseTime
;
1670 char iaddr
[INET6_ADDRSTRLEN
];
1671 unsigned short iport
;
1676 if(CheckStatus(h
)==0)
1679 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1680 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1681 leaseTime
= GetValueFromNameValueList(&data
, "NewLeaseTime");
1682 uid
= uid_str
? atoi(uid_str
) : -1;
1683 ltime
= leaseTime
? atoi(leaseTime
) : -1;
1684 ClearNameValueList(&data
);
1686 if(uid
< 0 || uid
> 65535 || ltime
<= 0 || ltime
> 86400)
1688 SoapError(h
, 402, "Invalid Args");
1692 /* Check that client is not updating an pinhole
1693 * it doesn't have access to, because of its public access */
1694 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
1695 iaddr
, sizeof(iaddr
), &iport
,
1697 NULL
, 0, /* desc, desclen */
1701 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1706 SoapError(h
, 704, "NoSuchEntry");
1711 SoapError(h
, 501, "ActionFailed");
1715 syslog(LOG_INFO
, "%s: (inbound) updating lease duration to %d for pinhole with ID: %d",
1716 action
, ltime
, uid
);
1718 n
= upnp_update_inboundpinhole(uid
, ltime
);
1720 SoapError(h
, 704, "NoSuchEntry");
1722 SoapError(h
, 501, "ActionFailed");
1724 bodylen
= snprintf(body
, sizeof(body
), resp
,
1725 action
, ns
, action
);
1726 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1731 GetOutboundPinholeTimeout(struct upnphttp
* h
, const char * action
, const char * ns
)
1735 static const char resp
[] =
1738 "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1743 struct NameValueParserData data
;
1744 char * int_ip
, * int_port
, * rem_host
, * rem_port
, * protocol
;
1747 unsigned short iport
, rport
;
1749 if (GETFLAG(IPV6FCFWDISABLEDMASK
))
1751 SoapError(h
, 702, "FirewallDisabled");
1755 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1756 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1757 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1758 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1759 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1760 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1762 rport
= (unsigned short)atoi(rem_port
);
1763 iport
= (unsigned short)atoi(int_port
);
1764 /*proto = atoi(protocol);*/
1766 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
);
1769 r
= -1;/*upnp_check_outbound_pinhole(proto, &opt);*/
1773 case 1: /* success */
1774 bodylen
= snprintf(body
, sizeof(body
), resp
,
1775 action
, ns
/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1777 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1779 case -5: /* Protocol not supported */
1780 SoapError(h
, 705, "ProtocolNotSupported");
1783 SoapError(h
, 501, "ActionFailed");
1785 ClearNameValueList(&data
);
1789 DeletePinhole(struct upnphttp
* h
, const char * action
, const char * ns
)
1793 static const char resp
[] =
1794 "<u:DeletePinholeResponse "
1795 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1796 "</u:DeletePinholeResponse>";
1798 static const char resp
[] =
1805 struct NameValueParserData data
;
1806 const char * uid_str
;
1807 char iaddr
[INET6_ADDRSTRLEN
];
1809 unsigned short iport
;
1810 unsigned int leasetime
;
1813 if(CheckStatus(h
)==0)
1816 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1817 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1818 uid
= uid_str
? atoi(uid_str
) : -1;
1819 ClearNameValueList(&data
);
1821 if(uid
< 0 || uid
> 65535)
1823 SoapError(h
, 402, "Invalid Args");
1827 /* Check that client is not deleting an pinhole
1828 * it doesn't have access to, because of its public access */
1829 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
1830 iaddr
, sizeof(iaddr
), &iport
,
1832 NULL
, 0, /* desc, desclen */
1836 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1841 SoapError(h
, 704, "NoSuchEntry");
1846 SoapError(h
, 501, "ActionFailed");
1850 n
= upnp_delete_inboundpinhole(uid
);
1853 syslog(LOG_INFO
, "%s: (inbound) failed to remove pinhole with ID: %d",
1855 SoapError(h
, 501, "ActionFailed");
1858 syslog(LOG_INFO
, "%s: (inbound) pinhole with ID %d successfully removed",
1860 bodylen
= snprintf(body
, sizeof(body
), resp
,
1861 action
, ns
, action
);
1862 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1866 CheckPinholeWorking(struct upnphttp
* h
, const char * action
, const char * ns
)
1868 static const char resp
[] =
1871 "<IsWorking>%d</IsWorking>"
1876 struct NameValueParserData data
;
1877 const char * uid_str
;
1879 char iaddr
[INET6_ADDRSTRLEN
];
1880 unsigned short iport
;
1881 unsigned int packets
;
1883 if(CheckStatus(h
)==0)
1886 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1887 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1888 uid
= uid_str
? atoi(uid_str
) : -1;
1889 ClearNameValueList(&data
);
1891 if(uid
< 0 || uid
> 65535)
1893 SoapError(h
, 402, "Invalid Args");
1897 /* Check that client is not checking a pinhole
1898 * it doesn't have access to, because of its public access */
1899 r
= upnp_get_pinhole_info(uid
,
1901 iaddr
, sizeof(iaddr
), &iport
,
1903 NULL
, 0, /* desc, desclen */
1907 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1911 SoapError(h
, 709, "NoPacketSent");
1914 bodylen
= snprintf(body
, sizeof(body
), resp
,
1915 action
, ns
/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1917 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1920 SoapError(h
, 704, "NoSuchEntry");
1922 SoapError(h
, 501, "ActionFailed");
1926 GetPinholePackets(struct upnphttp
* h
, const char * action
, const char * ns
)
1928 static const char resp
[] =
1931 "<PinholePackets>%u</PinholePackets>"
1935 struct NameValueParserData data
;
1936 const char * uid_str
;
1938 char iaddr
[INET6_ADDRSTRLEN
];
1939 unsigned short iport
;
1940 unsigned int packets
= 0;
1943 unsigned int leasetime
;
1945 if(CheckStatus(h
)==0)
1948 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1949 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1950 uid
= uid_str
? atoi(uid_str
) : -1;
1951 ClearNameValueList(&data
);
1953 if(uid
< 0 || uid
> 65535)
1955 SoapError(h
, 402, "Invalid Args");
1959 /* Check that client is not getting infos of a pinhole
1960 * it doesn't have access to, because of its public access */
1961 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
1962 iaddr
, sizeof(iaddr
), &iport
,
1964 NULL
, 0, /* desc, desclen */
1965 &leasetime
, &packets
);
1968 if(PinholeVerification(h
, iaddr
, iport
)<=0)
1972 else if(r
== -4 || r
== -1)
1974 SoapError(h
, 704, "NoSuchEntry");
1978 bodylen
= snprintf(body
, sizeof(body
), resp
,
1979 action
, ns
/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1981 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1985 #ifdef ENABLE_DP_SERVICE
1987 SendSetupMessage(struct upnphttp
* h
, const char * action
, const char * ns
)
1989 static const char resp
[] =
1992 "<OutMessage>%s</OutMessage>"
1996 struct NameValueParserData data
;
1997 const char * ProtocolType
; /* string */
1998 const char * InMessage
; /* base64 */
1999 const char * OutMessage
= ""; /* base64 */
2001 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
2002 ProtocolType
= GetValueFromNameValueList(&data
, "ProtocolType"); /* string */
2003 InMessage
= GetValueFromNameValueList(&data
, "InMessage"); /* base64 */
2005 if(ProtocolType
== NULL
|| InMessage
== NULL
)
2007 ClearNameValueList(&data
);
2008 SoapError(h
, 402, "Invalid Args");
2011 /*if(strcmp(ProtocolType, "DeviceProtection:1") != 0)*/
2012 if(strcmp(ProtocolType
, "WPS") != 0)
2014 ClearNameValueList(&data
);
2015 SoapError(h
, 600, "Argument Value Invalid"); /* 703 ? */
2018 /* TODO : put here code for WPS */
2020 bodylen
= snprintf(body
, sizeof(body
), resp
,
2021 action
, ns
/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2022 OutMessage
, action
);
2023 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
2024 ClearNameValueList(&data
);
2028 GetSupportedProtocols(struct upnphttp
* h
, const char * action
, const char * ns
)
2030 static const char resp
[] =
2033 "<ProtocolList><![CDATA[%s]]></ProtocolList>"
2037 const char * ProtocolList
=
2038 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
2039 "<SupportedProtocols xmlns=\"urn:schemas-upnp-org:gw:DeviceProtection\""
2040 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
2041 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:DeviceProtection"
2042 " http://www.upnp.org/schemas/gw/DeviceProtection-v1.xsd\">"
2043 "<Introduction><Name>WPS</Name></Introduction>"
2044 "<Login><Name>PKCS5</Name></Login>"
2045 "</SupportedProtocols>";
2047 bodylen
= snprintf(body
, sizeof(body
), resp
,
2048 action
, ns
/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2049 ProtocolList
, action
);
2050 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
2054 GetAssignedRoles(struct upnphttp
* h
, const char * action
, const char * ns
)
2056 static const char resp
[] =
2059 "<RoleList>%s</RoleList>"
2063 const char * RoleList
= "Public"; /* list of roles separated by spaces */
2066 if(h
->ssl
!= NULL
) {
2067 /* we should get the Roles of the session (based on client certificate) */
2069 peercert
= SSL_get_peer_certificate(h
->ssl
);
2070 if(peercert
!= NULL
) {
2071 RoleList
= "Admin Basic";
2072 X509_free(peercert
);
2077 bodylen
= snprintf(body
, sizeof(body
), resp
,
2078 action
, ns
/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2080 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
2084 /* Windows XP as client send the following requests :
2085 * GetConnectionTypeInfo
2087 * ? GetTotalBytesSent - WANCommonInterfaceConfig
2088 * ? GetTotalBytesReceived - idem
2089 * ? GetTotalPacketsSent - idem
2090 * ? GetTotalPacketsReceived - idem
2091 * GetCommonLinkProperties - idem
2092 * GetStatusInfo - WANIPConnection
2093 * GetExternalIPAddress
2094 * QueryStateVariable / ConnectionStatus!
2098 const char * methodName
;
2099 void (*methodImpl
)(struct upnphttp
*, const char *, const char *);
2103 /* WANCommonInterfaceConfig */
2104 { "QueryStateVariable", QueryStateVariable
},
2105 { "GetTotalBytesSent", GetTotalBytesSent
},
2106 { "GetTotalBytesReceived", GetTotalBytesReceived
},
2107 { "GetTotalPacketsSent", GetTotalPacketsSent
},
2108 { "GetTotalPacketsReceived", GetTotalPacketsReceived
},
2109 { "GetCommonLinkProperties", GetCommonLinkProperties
},
2110 { "GetStatusInfo", GetStatusInfo
},
2111 /* WANIPConnection */
2112 { "GetConnectionTypeInfo", GetConnectionTypeInfo
},
2113 { "GetNATRSIPStatus", GetNATRSIPStatus
},
2114 { "GetExternalIPAddress", GetExternalIPAddress
},
2115 { "AddPortMapping", AddPortMapping
},
2116 { "DeletePortMapping", DeletePortMapping
},
2117 { "GetGenericPortMappingEntry", GetGenericPortMappingEntry
},
2118 { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry
},
2119 /* Required in WANIPConnection:2 */
2120 { "SetConnectionType", SetConnectionType
},
2121 { "RequestConnection", RequestConnection
},
2122 { "ForceTermination", ForceTermination
},
2123 { "AddAnyPortMapping", AddAnyPortMapping
},
2124 { "DeletePortMappingRange", DeletePortMappingRange
},
2125 { "GetListOfPortMappings", GetListOfPortMappings
},
2126 #ifdef ENABLE_L3F_SERVICE
2127 /* Layer3Forwarding */
2128 { "SetDefaultConnectionService", SetDefaultConnectionService
},
2129 { "GetDefaultConnectionService", GetDefaultConnectionService
},
2131 #ifdef ENABLE_6FC_SERVICE
2132 /* WANIPv6FirewallControl */
2133 { "GetFirewallStatus", GetFirewallStatus
}, /* Required */
2134 { "AddPinhole", AddPinhole
}, /* Required */
2135 { "UpdatePinhole", UpdatePinhole
}, /* Required */
2136 { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout
}, /* Optional */
2137 { "DeletePinhole", DeletePinhole
}, /* Required */
2138 { "CheckPinholeWorking", CheckPinholeWorking
}, /* Optional */
2139 { "GetPinholePackets", GetPinholePackets
}, /* Required */
2141 #ifdef ENABLE_DP_SERVICE
2142 /* DeviceProtection */
2143 { "SendSetupMessage", SendSetupMessage
}, /* Required */
2144 { "GetSupportedProtocols", GetSupportedProtocols
}, /* Required */
2145 { "GetAssignedRoles", GetAssignedRoles
}, /* Required */
2151 ExecuteSoapAction(struct upnphttp
* h
, const char * action
, int n
)
2155 int i
, len
, methodlen
;
2156 char namespace[256];
2158 /* SoapAction example :
2159 * urn:schemas-upnp-org:service:WANIPConnection:1#GetStatusInfo */
2160 p
= strchr(action
, '#');
2161 if(p
&& (p
- action
) < n
) {
2162 for(i
= 0; i
< ((int)sizeof(namespace) - 1) && (action
+ i
) < p
; i
++)
2163 namespace[i
] = action
[i
];
2164 namespace[i
] = '\0';
2166 p2
= strchr(p
, '"');
2167 if(p2
&& (p2
- action
) <= n
)
2170 methodlen
= n
- (p
- action
);
2171 /*syslog(LOG_DEBUG, "SoapMethod: %.*s %d %d %p %p %d",
2172 methodlen, p, methodlen, n, action, p, (int)(p - action));*/
2173 for(i
= 0; soapMethods
[i
].methodName
; i
++) {
2174 len
= strlen(soapMethods
[i
].methodName
);
2175 if((len
== methodlen
) && memcmp(p
, soapMethods
[i
].methodName
, len
) == 0) {
2177 syslog(LOG_DEBUG
, "Remote Call of SoapMethod '%s' %s",
2178 soapMethods
[i
].methodName
, namespace);
2180 soapMethods
[i
].methodImpl(h
, soapMethods
[i
].methodName
, namespace);
2184 syslog(LOG_NOTICE
, "SoapMethod: Unknown: %.*s %s", methodlen
, p
, namespace);
2186 syslog(LOG_NOTICE
, "cannot parse SoapAction");
2189 SoapError(h
, 401, "Invalid Action");
2194 * errorCode errorDescription Description
2195 * -------- ---------------- -----------
2196 * 401 Invalid Action No action by that name at this service.
2197 * 402 Invalid Args Could be any of the following: not enough in args,
2198 * too many in args, no in arg by that name,
2199 * one or more in args are of the wrong data type.
2200 * 403 Out of Sync Out of synchronization.
2201 * 501 Action Failed May be returned in current state of service
2202 * prevents invoking that action.
2203 * 600-699 TBD Common action errors. Defined by UPnP Forum
2204 * Technical Committee.
2205 * 700-799 TBD Action-specific errors for standard actions.
2206 * Defined by UPnP Forum working committee.
2207 * 800-899 TBD Action-specific errors for non-standard actions.
2208 * Defined by UPnP vendor.
2211 SoapError(struct upnphttp
* h
, int errCode
, const char * errDesc
)
2213 static const char resp
[] =
2215 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
2216 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
2219 "<faultcode>s:Client</faultcode>"
2220 "<faultstring>UPnPError</faultstring>"
2222 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
2223 "<errorCode>%d</errorCode>"
2224 "<errorDescription>%s</errorDescription>"
2234 syslog(LOG_INFO
, "Returning UPnPError %d: %s", errCode
, errDesc
);
2235 bodylen
= snprintf(body
, sizeof(body
), resp
, errCode
, errDesc
);
2236 BuildResp2_upnphttp(h
, 500, "Internal Server Error", body
, bodylen
);
2237 SendRespAndClose_upnphttp(h
);