1 /* $Id: upnpsoap.c,v 1.136 2015/03/07 15:52:30 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
)
70 static const char resp
[] =
71 "<u:GetConnectionTypeInfoResponse "
72 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
73 "<NewConnectionType>IP_Routed</NewConnectionType>"
74 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
75 "</u:GetConnectionTypeInfoResponse>";
78 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
82 GetTotalBytesSent(struct upnphttp
* h
, const char * action
)
86 static const char resp
[] =
89 "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
96 r
= getifstats(ext_if_name
, &data
);
97 bodylen
= snprintf(body
, sizeof(body
), resp
,
98 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
99 r
<0?0:data
.obytes
, action
);
100 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
104 GetTotalBytesReceived(struct upnphttp
* h
, const char * action
)
108 static const char resp
[] =
111 "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
118 r
= getifstats(ext_if_name
, &data
);
119 bodylen
= snprintf(body
, sizeof(body
), resp
,
120 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
121 r
<0?0:data
.ibytes
, action
);
122 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
126 GetTotalPacketsSent(struct upnphttp
* h
, const char * action
)
130 static const char resp
[] =
133 "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
140 r
= getifstats(ext_if_name
, &data
);
141 bodylen
= snprintf(body
, sizeof(body
), resp
,
142 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
143 r
<0?0:data
.opackets
, action
);
144 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
148 GetTotalPacketsReceived(struct upnphttp
* h
, const char * action
)
152 static const char resp
[] =
155 "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
162 r
= getifstats(ext_if_name
, &data
);
163 bodylen
= snprintf(body
, sizeof(body
), resp
,
164 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
165 r
<0?0:data
.ipackets
, action
);
166 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
170 GetCommonLinkProperties(struct upnphttp
* h
, const char * action
)
172 /* WANAccessType : set depending on the hardware :
173 * DSL, POTS (plain old Telephone service), Cable, Ethernet */
174 static const char resp
[] =
177 "<NewWANAccessType>%s</NewWANAccessType>"
178 "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
179 "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
180 "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
186 const char * status
= "Up"; /* Up, Down (Required),
187 * Initializing, Unavailable (Optional) */
188 const char * wan_access_type
= "Cable"; /* DSL, POTS, Cable, Ethernet */
189 char ext_ip_addr
[INET_ADDRSTRLEN
];
191 if((downstream_bitrate
== 0) || (upstream_bitrate
== 0))
193 if(getifstats(ext_if_name
, &data
) >= 0)
195 if(downstream_bitrate
== 0) downstream_bitrate
= data
.baudrate
;
196 if(upstream_bitrate
== 0) upstream_bitrate
= data
.baudrate
;
199 if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
, NULL
, NULL
) < 0) {
202 bodylen
= snprintf(body
, sizeof(body
), resp
,
203 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
205 upstream_bitrate
, downstream_bitrate
,
207 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
211 GetStatusInfo(struct upnphttp
* h
, const char * action
)
213 static const char resp
[] =
216 "<NewConnectionStatus>%s</NewConnectionStatus>"
217 "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
218 "<NewUptime>%ld</NewUptime>"
225 /* ConnectionStatus possible values :
226 * Unconfigured, Connecting, Connected, PendingDisconnect,
227 * Disconnecting, Disconnected */
229 status
= get_wan_connection_status_str(ext_if_name
);
230 uptime
= (time(NULL
) - startup_time
);
231 bodylen
= snprintf(body
, sizeof(body
), resp
,
232 action
, SERVICE_TYPE_WANIPC
,
233 status
, (long)uptime
, action
);
234 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
238 GetNATRSIPStatus(struct upnphttp
* h
, const char * action
)
240 static const char resp
[] =
241 "<u:GetNATRSIPStatusResponse "
242 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
243 "<NewRSIPAvailable>0</NewRSIPAvailable>"
244 "<NewNATEnabled>1</NewNATEnabled>"
245 "</u:GetNATRSIPStatusResponse>";
247 /* 2.2.9. RSIPAvailable
248 * This variable indicates if Realm-specific IP (RSIP) is available
249 * as a feature on the InternetGatewayDevice. RSIP is being defined
250 * in the NAT working group in the IETF to allow host-NATing using
251 * a standard set of message exchanges. It also allows end-to-end
252 * applications that otherwise break if NAT is introduced
253 * (e.g. IPsec-based VPNs).
254 * A gateway that does not support RSIP should set this variable to 0. */
255 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
259 GetExternalIPAddress(struct upnphttp
* h
, const char * action
)
261 static const char resp
[] =
264 "<NewExternalIPAddress>%s</NewExternalIPAddress>"
269 char ext_ip_addr
[INET_ADDRSTRLEN
];
270 /* Does that method need to work with IPv6 ?
271 * There is usually no NAT with IPv6 */
273 #ifndef MULTIPLE_EXTERNAL_IP
276 strncpy(ext_ip_addr
, use_ext_ip_addr
, INET_ADDRSTRLEN
);
278 else if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
, NULL
, NULL
) < 0)
280 syslog(LOG_ERR
, "Failed to get ip address for interface %s",
282 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
285 struct lan_addr_s
* lan_addr
;
286 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
287 for(lan_addr
= lan_addrs
.lh_first
; lan_addr
!= NULL
; lan_addr
= lan_addr
->list
.le_next
)
289 if( (h
->clientaddr
.s_addr
& lan_addr
->mask
.s_addr
)
290 == (lan_addr
->addr
.s_addr
& lan_addr
->mask
.s_addr
))
292 strncpy(ext_ip_addr
, lan_addr
->ext_ip_str
, INET_ADDRSTRLEN
);
297 bodylen
= snprintf(body
, sizeof(body
), resp
,
298 action
, SERVICE_TYPE_WANIPC
,
299 ext_ip_addr
, action
);
300 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
303 /* AddPortMapping method of WANIPConnection Service
304 * Ignored argument : NewEnabled */
306 AddPortMapping(struct upnphttp
* h
, const char * action
)
310 static const char resp
[] =
311 "<u:AddPortMappingResponse "
312 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\"/>";
314 struct NameValueParserData data
;
315 char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
316 char * leaseduration_str
;
317 unsigned int leaseduration
;
319 unsigned short iport
, eport
;
321 struct hostent
*hp
; /* getbyhostname() */
322 char ** ptr
; /* getbyhostname() */
323 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
325 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
326 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
329 ClearNameValueList(&data
);
330 SoapError(h
, 402, "Invalid Args");
334 /* IGD 2 MUST support both wildcard and specific IP address values
335 * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
336 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
337 #ifndef SUPPORT_REMOTEHOST
339 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
341 ClearNameValueList(&data
);
342 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
348 /* if ip not valid assume hostname and convert */
349 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
351 hp
= gethostbyname(int_ip
);
352 if(hp
&& hp
->h_addrtype
== AF_INET
)
354 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
356 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
357 result_ip
= *((struct in_addr
*) *ptr
);
358 /* TODO : deal with more than one ip per hostname */
364 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
365 ClearNameValueList(&data
);
366 SoapError(h
, 402, "Invalid Args");
371 /* check if NewInternalAddress is the client address */
372 if(GETFLAG(SECUREMODEMASK
))
374 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
376 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
377 inet_ntoa(h
->clientaddr
), int_ip
);
378 ClearNameValueList(&data
);
379 SoapError(h
, 718, "ConflictInMappingEntry");
384 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
385 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
386 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
387 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
388 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
390 if (!int_port
|| !ext_port
|| !protocol
)
392 ClearNameValueList(&data
);
393 SoapError(h
, 402, "Invalid Args");
397 eport
= (unsigned short)atoi(ext_port
);
398 iport
= (unsigned short)atoi(int_port
);
400 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
402 /* PortMappingLeaseDuration can be either a value between 1 and
403 * 604800 seconds or the zero value (for infinite lease time).
404 * Note that an infinite lease time can be only set by out-of-band
405 * mechanisms like WWW-administration, remote management or local
407 * If a control point uses the value 0 to indicate an infinite lease
408 * time mapping, it is REQUIRED that gateway uses the maximum value
409 * instead (e.g. 604800 seconds) */
410 if(leaseduration
== 0 || leaseduration
> 604800)
411 leaseduration
= 604800;
414 syslog(LOG_INFO
, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
415 action
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
,
416 r_host
? r_host
: "NULL");
418 /* TODO : be compliant with IGD spec for updating existing port mappings.
419 See "WANIPConnection:1 Service Template Version 1.01" 2.2.20.PortMappingDescription :
420 Overwriting Previous / Existing Port Mappings:
421 If the RemoteHost, ExternalPort, PortMappingProtocol and InternalClient are
422 exactly the same as an existing mapping, the existing mapping values for InternalPort,
423 PortMappingDescription, PortMappingEnabled and PortMappingLeaseDuration are
426 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
428 ClearNameValueList(&data
);
430 /* possible error codes for AddPortMapping :
432 * 501 - Action Failed
433 * 715 - Wildcard not permited in SrcAddr
434 * 716 - Wildcard not permited in ExtPort
435 * 718 - ConflictInMappingEntry
436 * 724 - SamePortValuesRequired (deprecated in IGD v2)
437 * 725 - OnlyPermanentLeasesSupported
438 The NAT implementation only supports permanent lease times on
439 port mappings (deprecated in IGD v2)
440 * 726 - RemoteHostOnlySupportsWildcard
441 RemoteHost must be a wildcard and cannot be a specific IP
442 address or DNS name (deprecated in IGD v2)
443 * 727 - ExternalPortOnlySupportsWildcard
444 ExternalPort must be a wildcard and cannot be a specific port
445 value (deprecated in IGD v2)
446 * 728 - NoPortMapsAvailable
447 There are not enough free prots available to complete the mapping
449 * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
452 case 0: /* success */
453 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
455 case -2: /* already redirected */
456 case -3: /* not permitted */
457 SoapError(h
, 718, "ConflictInMappingEntry");
460 SoapError(h
, 501, "ActionFailed");
464 /* AddAnyPortMapping was added in WANIPConnection v2 */
466 AddAnyPortMapping(struct upnphttp
* h
, const char * action
)
469 static const char resp
[] =
472 "<NewReservedPort>%hu</NewReservedPort>"
478 struct NameValueParserData data
;
479 const char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
481 unsigned short iport
, eport
;
482 const char * leaseduration_str
;
483 unsigned int leaseduration
;
485 struct hostent
*hp
; /* getbyhostname() */
486 char ** ptr
; /* getbyhostname() */
487 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
489 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
490 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
491 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
492 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
493 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
494 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
496 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
497 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
499 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
500 if(leaseduration
== 0)
501 leaseduration
= 604800;
503 if (!int_ip
|| !ext_port
|| !int_port
)
505 ClearNameValueList(&data
);
506 SoapError(h
, 402, "Invalid Args");
510 eport
= (unsigned short)atoi(ext_port
);
511 iport
= (unsigned short)atoi(int_port
);
512 #ifndef SUPPORT_REMOTEHOST
514 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
516 ClearNameValueList(&data
);
517 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
523 /* if ip not valid assume hostname and convert */
524 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
526 hp
= gethostbyname(int_ip
);
527 if(hp
&& hp
->h_addrtype
== AF_INET
)
529 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
531 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
532 result_ip
= *((struct in_addr
*) *ptr
);
533 /* TODO : deal with more than one ip per hostname */
539 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
540 ClearNameValueList(&data
);
541 SoapError(h
, 402, "Invalid Args");
546 /* check if NewInternalAddress is the client address */
547 if(GETFLAG(SECUREMODEMASK
))
549 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
551 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
552 inet_ntoa(h
->clientaddr
), int_ip
);
553 ClearNameValueList(&data
);
554 SoapError(h
, 606, "Action not authorized");
559 /* TODO : accept a different external port
560 * have some smart strategy to choose the port */
562 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
563 if(r
==-2 && eport
< 65535) {
570 ClearNameValueList(&data
);
574 case 0: /* success */
575 bodylen
= snprintf(body
, sizeof(body
), resp
,
576 action
, SERVICE_TYPE_WANIPC
,
578 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
580 case -2: /* already redirected */
581 SoapError(h
, 718, "ConflictInMappingEntry");
583 case -3: /* not permitted */
584 SoapError(h
, 606, "Action not authorized");
587 SoapError(h
, 501, "ActionFailed");
592 GetSpecificPortMappingEntry(struct upnphttp
* h
, const char * action
)
596 static const char resp
[] =
599 "<NewInternalPort>%u</NewInternalPort>"
600 "<NewInternalClient>%s</NewInternalClient>"
601 "<NewEnabled>1</NewEnabled>"
602 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
603 "<NewLeaseDuration>%u</NewLeaseDuration>"
608 struct NameValueParserData data
;
609 const char * r_host
, * ext_port
, * protocol
;
610 unsigned short eport
, iport
;
613 unsigned int leaseduration
= 0;
615 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
616 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
617 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
618 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
621 if(!ext_port
|| !protocol
|| !r_host
)
623 if(!ext_port
|| !protocol
)
626 ClearNameValueList(&data
);
627 SoapError(h
, 402, "Invalid Args");
630 #ifndef SUPPORT_REMOTEHOST
632 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
634 ClearNameValueList(&data
);
635 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
641 eport
= (unsigned short)atoi(ext_port
);
643 /* TODO : add r_host as an input parameter ...
644 * We prevent several Port Mapping with same external port
645 * but different remoteHost to be set up, so that is not
647 r
= upnp_get_redirection_infos(eport
, protocol
, &iport
,
648 int_ip
, sizeof(int_ip
),
655 SoapError(h
, 714, "NoSuchEntryInArray");
659 syslog(LOG_INFO
, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
661 r_host
? r_host
: "NULL", ext_port
, protocol
, int_ip
,
662 (unsigned int)iport
, desc
);
663 bodylen
= snprintf(body
, sizeof(body
), resp
,
664 action
, SERVICE_TYPE_WANIPC
,
665 (unsigned int)iport
, int_ip
, desc
, leaseduration
,
667 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
670 ClearNameValueList(&data
);
674 DeletePortMapping(struct upnphttp
* h
, const char * action
)
678 static const char resp
[] =
679 "<u:DeletePortMappingResponse "
680 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
681 "</u:DeletePortMappingResponse>";
683 struct NameValueParserData data
;
684 const char * ext_port
, * protocol
;
685 unsigned short eport
;
688 #endif /* UPNP_STRICT */
690 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
691 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
692 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
694 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
695 #endif /* UPNP_STRICT */
698 if(!ext_port
|| !protocol
|| !r_host
)
700 if(!ext_port
|| !protocol
)
701 #endif /* UPNP_STRICT */
703 ClearNameValueList(&data
);
704 SoapError(h
, 402, "Invalid Args");
707 #ifndef SUPPORT_REMOTEHOST
709 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
711 ClearNameValueList(&data
);
712 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
715 #endif /* UPNP_STRICT */
716 #endif /* SUPPORT_REMOTEHOST */
718 eport
= (unsigned short)atoi(ext_port
);
720 syslog(LOG_INFO
, "%s: external port: %hu, protocol: %s",
721 action
, eport
, protocol
);
723 /* if in secure mode, check the IP
724 * Removing a redirection is not a security threat,
725 * just an annoyance for the user using it. So this is not
727 if(GETFLAG(SECUREMODEMASK
))
730 struct in_addr int_ip_addr
;
731 unsigned short iport
;
732 unsigned int leaseduration
= 0;
733 r
= upnp_get_redirection_infos(eport
, protocol
, &iport
,
734 int_ip
, sizeof(int_ip
),
739 if(inet_pton(AF_INET
, int_ip
, &int_ip_addr
) > 0)
741 if(h
->clientaddr
.s_addr
!= int_ip_addr
.s_addr
)
743 SoapError(h
, 606, "Action not authorized");
744 /*SoapError(h, 714, "NoSuchEntryInArray");*/
745 ClearNameValueList(&data
);
752 r
= upnp_delete_redirection(eport
, protocol
);
756 SoapError(h
, 714, "NoSuchEntryInArray");
760 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
763 ClearNameValueList(&data
);
766 /* DeletePortMappingRange was added in IGD spec v2 */
768 DeletePortMappingRange(struct upnphttp
* h
, const char * action
)
771 static const char resp
[] =
772 "<u:DeletePortMappingRangeResponse "
773 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
774 "</u:DeletePortMappingRangeResponse>";
775 struct NameValueParserData data
;
776 const char * protocol
;
777 const char * startport_s
, * endport_s
;
778 unsigned short startport
, endport
;
780 unsigned short * port_list
;
781 unsigned int i
, number
= 0;
784 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
785 startport_s
= GetValueFromNameValueList(&data
, "NewStartPort");
786 endport_s
= GetValueFromNameValueList(&data
, "NewEndPort");
787 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
788 /*manage = atoi(GetValueFromNameValueList(&data, "NewManage"));*/
789 if(startport_s
== NULL
|| endport_s
== NULL
|| protocol
== NULL
) {
790 SoapError(h
, 402, "Invalid Args");
791 ClearNameValueList(&data
);
794 startport
= (unsigned short)atoi(startport_s
);
795 endport
= (unsigned short)atoi(endport_s
);
798 606 - Action not authorized
799 730 - PortMappingNotFound
800 733 - InconsistentParameter
802 if(startport
> endport
)
804 SoapError(h
, 733, "InconsistentParameter");
805 ClearNameValueList(&data
);
809 syslog(LOG_INFO
, "%s: deleting external ports: %hu-%hu, protocol: %s",
810 action
, startport
, endport
, protocol
);
812 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
816 SoapError(h
, 730, "PortMappingNotFound");
817 ClearNameValueList(&data
);
821 for(i
= 0; i
< number
; i
++)
823 r
= upnp_delete_redirection(port_list
[i
], protocol
);
824 syslog(LOG_INFO
, "%s: deleting external port: %hu, protocol: %s: %s",
825 action
, port_list
[i
], protocol
, r
< 0 ? "failed" : "ok");
828 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
830 ClearNameValueList(&data
);
834 GetGenericPortMappingEntry(struct upnphttp
* h
, const char * action
)
838 static const char resp
[] =
841 "<NewRemoteHost>%s</NewRemoteHost>"
842 "<NewExternalPort>%u</NewExternalPort>"
843 "<NewProtocol>%s</NewProtocol>"
844 "<NewInternalPort>%u</NewInternalPort>"
845 "<NewInternalClient>%s</NewInternalClient>"
846 "<NewEnabled>1</NewEnabled>"
847 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
848 "<NewLeaseDuration>%u</NewLeaseDuration>"
852 unsigned short eport
, iport
;
853 const char * m_index
;
855 char protocol
[4], iaddr
[32];
858 unsigned int leaseduration
= 0;
859 struct NameValueParserData data
;
861 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
862 m_index
= GetValueFromNameValueList(&data
, "NewPortMappingIndex");
866 ClearNameValueList(&data
);
867 SoapError(h
, 402, "Invalid Args");
870 errno
= 0; /* To distinguish success/failure after call */
871 index
= strtol(m_index
, &endptr
, 10);
872 if((errno
== ERANGE
&& (index
== LONG_MAX
|| index
== LONG_MIN
))
873 || (errno
!= 0 && index
== 0) || (m_index
== endptr
))
875 /* should condition (*endptr != '\0') be also an error ? */
876 if(m_index
== endptr
)
877 syslog(LOG_WARNING
, "%s: no digits were found in <%s>",
878 "GetGenericPortMappingEntry", "NewPortMappingIndex");
880 syslog(LOG_WARNING
, "%s: strtol('%s'): %m",
881 "GetGenericPortMappingEntry", m_index
);
882 ClearNameValueList(&data
);
883 SoapError(h
, 402, "Invalid Args");
887 syslog(LOG_INFO
, "%s: index=%d", action
, (int)index
);
890 r
= upnp_get_redirection_infos_by_index((int)index
, &eport
, protocol
, &iport
,
891 iaddr
, sizeof(iaddr
),
893 rhost
, sizeof(rhost
),
898 SoapError(h
, 713, "SpecifiedArrayIndexInvalid");
904 bodylen
= snprintf(body
, sizeof(body
), resp
,
905 action
, SERVICE_TYPE_WANIPC
, rhost
,
906 (unsigned int)eport
, protocol
, (unsigned int)iport
, iaddr
, desc
,
907 leaseduration
, action
);
908 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
911 ClearNameValueList(&data
);
914 /* GetListOfPortMappings was added in the IGD v2 specification */
916 GetListOfPortMappings(struct upnphttp
* h
, const char * action
)
918 static const char resp_start
[] =
921 "<NewPortListing><![CDATA[";
922 static const char resp_end
[] =
923 "]]></NewPortListing>"
926 static const char list_start
[] =
927 "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
928 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
929 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
930 " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
931 static const char list_end
[] =
932 "</p:PortMappingList>";
934 static const char entry
[] =
935 "<p:PortMappingEntry>"
936 "<p:NewRemoteHost>%s</p:NewRemoteHost>"
937 "<p:NewExternalPort>%hu</p:NewExternalPort>"
938 "<p:NewProtocol>%s</p:NewProtocol>"
939 "<p:NewInternalPort>%hu</p:NewInternalPort>"
940 "<p:NewInternalClient>%s</p:NewInternalClient>"
941 "<p:NewEnabled>1</p:NewEnabled>"
942 "<p:NewDescription>%s</p:NewDescription>"
943 "<p:NewLeaseTime>%u</p:NewLeaseTime>"
944 "</p:PortMappingEntry>";
951 unsigned short iport
;
955 unsigned int leaseduration
= 0;
957 struct NameValueParserData data
;
958 const char * startport_s
, * endport_s
;
959 unsigned short startport
, endport
;
960 const char * protocol
;
962 const char * number_s
;
964 unsigned short * port_list
;
965 unsigned int i
, list_size
= 0;
967 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
968 startport_s
= GetValueFromNameValueList(&data
, "NewStartPort");
969 endport_s
= GetValueFromNameValueList(&data
, "NewEndPort");
970 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
971 /*manage_s = GetValueFromNameValueList(&data, "NewManage");*/
972 number_s
= GetValueFromNameValueList(&data
, "NewNumberOfPorts");
973 if(startport_s
== NULL
|| endport_s
== NULL
|| protocol
== NULL
||
975 SoapError(h
, 402, "Invalid Args");
976 ClearNameValueList(&data
);
980 startport
= (unsigned short)atoi(startport_s
);
981 endport
= (unsigned short)atoi(endport_s
);
982 /*manage = atoi(manage_s);*/
983 number
= atoi(number_s
);
984 if(number
== 0) number
= 1000; /* return up to 1000 mappings by default */
986 if(startport
> endport
)
988 SoapError(h
, 733, "InconsistentParameter");
989 ClearNameValueList(&data
);
993 build the PortMappingList xml document :
995 <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
996 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
997 xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
998 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
1000 <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
1001 <p:NewExternalPort>2345</p:NewExternalPort>
1002 <p:NewProtocol>TCP</p:NewProtocol>
1003 <p:NewInternalPort>2345</p:NewInternalPort>
1004 <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
1005 <p:NewEnabled>1</p:NewEnabled>
1006 <p:NewDescription>dooom</p:NewDescription>
1007 <p:NewLeaseTime>345</p:NewLeaseTime>
1008 </p:PortMappingEntry>
1009 </p:PortMappingList>
1012 body
= malloc(bodyalloc
);
1015 ClearNameValueList(&data
);
1016 SoapError(h
, 501, "ActionFailed");
1019 bodylen
= snprintf(body
, bodyalloc
, resp_start
,
1020 action
, SERVICE_TYPE_WANIPC
);
1023 SoapError(h
, 501, "ActionFailed");
1027 memcpy(body
+bodylen
, list_start
, sizeof(list_start
));
1028 bodylen
+= (sizeof(list_start
) - 1);
1030 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
1031 protocol
, &list_size
);
1032 /* loop through port mappings */
1033 for(i
= 0; number
> 0 && i
< list_size
; i
++)
1035 /* have a margin of 1024 bytes to store the new entry */
1036 if((unsigned int)bodylen
+ 1024 > bodyalloc
)
1038 char * body_sav
= body
;
1040 body
= realloc(body
, bodyalloc
);
1043 syslog(LOG_CRIT
, "realloc(%p, %u) FAILED", body_sav
, (unsigned)bodyalloc
);
1044 ClearNameValueList(&data
);
1045 SoapError(h
, 501, "ActionFailed");
1052 r
= upnp_get_redirection_infos(port_list
[i
], protocol
, &iport
,
1053 int_ip
, sizeof(int_ip
),
1055 rhost
, sizeof(rhost
),
1059 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, entry
,
1060 rhost
, port_list
[i
], protocol
,
1061 iport
, int_ip
, desc
, leaseduration
);
1068 if((bodylen
+ sizeof(list_end
) + 1024) > bodyalloc
)
1070 char * body_sav
= body
;
1071 bodyalloc
+= (sizeof(list_end
) + 1024);
1072 body
= realloc(body
, bodyalloc
);
1075 syslog(LOG_CRIT
, "realloc(%p, %u) FAILED", body_sav
, (unsigned)bodyalloc
);
1076 ClearNameValueList(&data
);
1077 SoapError(h
, 501, "ActionFailed");
1082 memcpy(body
+bodylen
, list_end
, sizeof(list_end
));
1083 bodylen
+= (sizeof(list_end
) - 1);
1084 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, resp_end
,
1086 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1089 ClearNameValueList(&data
);
1092 #ifdef ENABLE_L3F_SERVICE
1094 SetDefaultConnectionService(struct upnphttp
* h
, const char * action
)
1096 static const char resp
[] =
1097 "<u:SetDefaultConnectionServiceResponse "
1098 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1099 "</u:SetDefaultConnectionServiceResponse>";
1100 struct NameValueParserData data
;
1102 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1103 p
= GetValueFromNameValueList(&data
, "NewDefaultConnectionService");
1105 /* 720 InvalidDeviceUUID
1106 * 721 InvalidServiceID
1107 * 723 InvalidConnServiceSelection */
1110 service
= strchr(p
, ',');
1111 if(0 != memcmp(uuidvalue_wcd
, p
, sizeof("uuid:00000000-0000-0000-0000-000000000000") - 1)) {
1112 SoapError(h
, 720, "InvalidDeviceUUID");
1113 } else if(service
== NULL
|| 0 != strcmp(service
+1, SERVICE_ID_WANIPC
)) {
1114 SoapError(h
, 721, "InvalidServiceID");
1118 syslog(LOG_INFO
, "%s(%s) : Ignored", action
, p
);
1119 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
1122 /* missing argument */
1123 SoapError(h
, 402, "Invalid Args");
1125 ClearNameValueList(&data
);
1129 GetDefaultConnectionService(struct upnphttp
* h
, const char * action
)
1131 static const char resp
[] =
1133 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1134 "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
1135 SERVICE_ID_WANIPC
"</NewDefaultConnectionService>"
1137 /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
1138 * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
1139 * urn:upnp-org:serviceId:WANPPPConn1 */
1143 bodylen
= snprintf(body
, sizeof(body
), resp
,
1144 action
, uuidvalue_wcd
, action
);
1145 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1149 /* Added for compliance with WANIPConnection v2 */
1151 SetConnectionType(struct upnphttp
* h
, const char * action
)
1154 const char * connection_type
;
1155 #endif /* UPNP_STRICT */
1156 struct NameValueParserData data
;
1159 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1161 connection_type
= GetValueFromNameValueList(&data
, "NewConnectionType");
1162 if(!connection_type
) {
1163 ClearNameValueList(&data
);
1164 SoapError(h
, 402, "Invalid Args");
1167 #endif /* UPNP_STRICT */
1168 /* Unconfigured, IP_Routed, IP_Bridged */
1169 ClearNameValueList(&data
);
1170 /* always return a ReadOnly error */
1171 SoapError(h
, 731, "ReadOnly");
1174 /* Added for compliance with WANIPConnection v2 */
1176 RequestConnection(struct upnphttp
* h
, const char * action
)
1179 SoapError(h
, 606, "Action not authorized");
1182 /* Added for compliance with WANIPConnection v2 */
1184 ForceTermination(struct upnphttp
* h
, const char * action
)
1187 SoapError(h
, 606, "Action not authorized");
1191 If a control point calls QueryStateVariable on a state variable that is not
1192 buffered in memory within (or otherwise available from) the service,
1193 the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1195 QueryStateVariable remains useful as a limited test tool but may not be
1196 part of some future versions of UPnP.
1199 QueryStateVariable(struct upnphttp
* h
, const char * action
)
1201 static const char resp
[] =
1204 "<return>%s</return>"
1209 struct NameValueParserData data
;
1210 const char * var_name
;
1212 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1213 /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1214 /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1215 var_name
= GetValueFromNameValueList(&data
, "varName");
1217 /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1221 SoapError(h
, 402, "Invalid Args");
1223 else if(strcmp(var_name
, "ConnectionStatus") == 0)
1225 const char * status
;
1227 status
= get_wan_connection_status_str(ext_if_name
);
1228 bodylen
= snprintf(body
, sizeof(body
), resp
,
1229 action
, "urn:schemas-upnp-org:control-1-0",
1231 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1235 else if(strcmp(var_name
, "ConnectionType") == 0)
1237 bodylen
= snprintf(body
, sizeof(body
), resp
, "IP_Routed");
1238 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1240 else if(strcmp(var_name
, "LastConnectionError") == 0)
1242 bodylen
= snprintf(body
, sizeof(body
), resp
, "ERROR_NONE");
1243 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1246 else if(strcmp(var_name
, "PortMappingNumberOfEntries") == 0)
1249 snprintf(strn
, sizeof(strn
), "%i",
1250 upnp_get_portmapping_number_of_entries());
1251 bodylen
= snprintf(body
, sizeof(body
), resp
,
1252 action
, "urn:schemas-upnp-org:control-1-0",
1254 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1258 syslog(LOG_NOTICE
, "%s: Unknown: %s", action
, var_name
?var_name
:"");
1259 SoapError(h
, 404, "Invalid Var");
1262 ClearNameValueList(&data
);
1265 #ifdef ENABLE_6FC_SERVICE
1267 #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1269 /* WANIPv6FirewallControl actions */
1271 GetFirewallStatus(struct upnphttp
* h
, const char * action
)
1273 static const char resp
[] =
1276 "<FirewallEnabled>%d</FirewallEnabled>"
1277 "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1283 bodylen
= snprintf(body
, sizeof(body
), resp
,
1284 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1285 GETFLAG(IPV6FCFWDISABLEDMASK
) ? 0 : 1,
1286 GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK
) ? 0 : 1,
1288 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1292 CheckStatus(struct upnphttp
* h
)
1294 if (GETFLAG(IPV6FCFWDISABLEDMASK
))
1296 SoapError(h
, 702, "FirewallDisabled");
1299 else if(GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK
))
1301 SoapError(h
, 703, "InboundPinholeNotAllowed");
1309 static int connecthostport(const char * host
, unsigned short port
, char * result
)
1312 char hostname
[INET6_ADDRSTRLEN
];
1313 char port_str
[8], ifname
[8], tmp
[4];
1314 struct addrinfo
*ai
, *p
;
1315 struct addrinfo hints
;
1317 memset(&hints
, 0, sizeof(hints
));
1318 /* hints.ai_flags = AI_ADDRCONFIG; */
1319 #ifdef AI_NUMERICSERV
1320 hints
.ai_flags
= AI_NUMERICSERV
;
1322 hints
.ai_socktype
= SOCK_STREAM
;
1323 hints
.ai_family
= AF_UNSPEC
; /* AF_INET, AF_INET6 or AF_UNSPEC */
1324 /* hints.ai_protocol = IPPROTO_TCP; */
1325 snprintf(port_str
, sizeof(port_str
), "%hu", port
);
1326 strcpy(hostname
, host
);
1327 if(!strncmp(host
, "fe80", 4))
1329 printf("Using an linklocal address\n");
1330 strcpy(ifname
, "%");
1331 snprintf(tmp
, sizeof(tmp
), "%d", linklocal_index
);
1332 strcat(ifname
, tmp
);
1333 strcat(hostname
, ifname
);
1334 printf("host: %s\n", hostname
);
1336 n
= getaddrinfo(hostname
, port_str
, &hints
, &ai
);
1339 fprintf(stderr
, "getaddrinfo() error : %s\n", gai_strerror(n
));
1343 for(p
= ai
; p
; p
= p
->ai_next
)
1347 char tmp_service
[256];
1348 printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1349 p
->ai_family
, p
->ai_socktype
, p
->ai_protocol
, p
->ai_addrlen
);
1350 getnameinfo(p
->ai_addr
, p
->ai_addrlen
, tmp_host
, sizeof(tmp_host
),
1351 tmp_service
, sizeof(tmp_service
),
1352 NI_NUMERICHOST
| NI_NUMERICSERV
);
1353 printf(" host=%s service=%s\n", tmp_host
, tmp_service
);
1355 inet_ntop(AF_INET6
, &(((struct sockaddr_in6
*)p
->ai_addr
)->sin6_addr
), result
, INET6_ADDRSTRLEN
);
1362 /* Check the security policy right */
1364 PinholeVerification(struct upnphttp
* h
, char * int_ip
, unsigned short int_port
)
1367 char senderAddr
[INET6_ADDRSTRLEN
]="";
1368 struct addrinfo hints
, *ai
, *p
;
1369 struct in6_addr result_ip
;
1371 /* Pinhole InternalClient address must correspond to the action sender */
1372 syslog(LOG_INFO
, "Checking internal IP@ and port (Security policy purpose)");
1374 hints
.ai_socktype
= SOCK_STREAM
;
1375 hints
.ai_family
= AF_UNSPEC
;
1377 /* if ip not valid assume hostname and convert */
1378 if (inet_pton(AF_INET6
, int_ip
, &result_ip
) <= 0)
1380 n
= getaddrinfo(int_ip
, NULL
, &hints
, &ai
);
1381 if(!n
&& ai
->ai_family
== AF_INET6
)
1383 for(p
= ai
; p
; p
= p
->ai_next
)
1385 inet_ntop(AF_INET6
, (struct in6_addr
*) p
, int_ip
, sizeof(struct in6_addr
));
1386 result_ip
= *((struct in6_addr
*) p
);
1387 /* TODO : deal with more than one ip per hostname */
1393 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
1394 SoapError(h
, 402, "Invalid Args");
1400 if(inet_ntop(AF_INET6
, &(h
->clientaddr_v6
), senderAddr
, INET6_ADDRSTRLEN
) == NULL
)
1402 syslog(LOG_ERR
, "inet_ntop: %m");
1405 printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr
, int_ip
);
1407 if(strcmp(senderAddr
, int_ip
) != 0)
1408 if(h
->clientaddr_v6
.s6_addr
!= result_ip
.s6_addr
)
1410 syslog(LOG_INFO
, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1411 senderAddr
, int_ip
);
1412 SoapError(h
, 606, "Action not authorized");
1416 /* Pinhole InternalPort must be greater than or equal to 1024 */
1417 if (int_port
< 1024)
1419 syslog(LOG_INFO
, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1421 SoapError(h
, 606, "Action not authorized");
1428 AddPinhole(struct upnphttp
* h
, const char * action
)
1431 static const char resp
[] =
1434 "<UniqueID>%d</UniqueID>"
1438 struct NameValueParserData data
;
1439 char * rem_host
, * rem_port
, * int_ip
, * int_port
, * protocol
, * leaseTime
;
1441 unsigned short iport
, rport
;
1444 char rem_ip
[INET6_ADDRSTRLEN
];
1446 if(CheckStatus(h
)==0)
1449 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1450 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1451 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1452 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1453 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1454 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1455 leaseTime
= GetValueFromNameValueList(&data
, "LeaseTime");
1457 rport
= (unsigned short)(rem_port
? atoi(rem_port
) : 0);
1458 iport
= (unsigned short)(int_port
? atoi(int_port
) : 0);
1459 ltime
= leaseTime
? atoi(leaseTime
) : -1;
1461 proto
= protocol
? strtol(protocol
, NULL
, 0) : -1;
1462 if(errno
!= 0 || proto
> 65535 || proto
< 0)
1464 SoapError(h
, 402, "Invalid Args");
1465 goto clear_and_exit
;
1469 SoapError(h
, 706, "InternalPortWilcardingNotAllowed");
1470 goto clear_and_exit
;
1473 /* In particular, [IGD2] RECOMMENDS that unauthenticated and
1474 * unauthorized control points are only allowed to invoke
1476 * - InternalPort value greater than or equal to 1024,
1477 * - InternalClient value equals to the control point's IP address.
1478 * It is REQUIRED that InternalClient cannot be one of IPv6
1479 * addresses used by the gateway. */
1480 if(!int_ip
|| 0 == strlen(int_ip
) || 0 == strcmp(int_ip
, "*"))
1482 SoapError(h
, 708, "WildCardNotPermittedInSrcIP");
1483 goto clear_and_exit
;
1485 /* I guess it is useless to convert int_ip to literal ipv6 address */
1486 /* rem_host should be converted to literal ipv6 : */
1487 if(rem_host
&& (rem_host
[0] != '\0'))
1489 struct addrinfo
*ai
, *p
;
1490 struct addrinfo hints
;
1492 memset(&hints
, 0, sizeof(struct addrinfo
));
1493 hints
.ai_family
= AF_INET6
;
1494 /*hints.ai_flags = */
1495 /* hints.ai_protocol = proto; */
1496 err
= getaddrinfo(rem_host
, rem_port
, &hints
, &ai
);
1499 /* take the 1st IPv6 address */
1500 for(p
= ai
; p
; p
= p
->ai_next
)
1502 if(p
->ai_family
== AF_INET6
)
1505 &(((struct sockaddr_in6
*)p
->ai_addr
)->sin6_addr
),
1506 rem_ip
, sizeof(rem_ip
));
1507 syslog(LOG_INFO
, "resolved '%s' to '%s'", rem_host
, rem_ip
);
1516 syslog(LOG_WARNING
, "AddPinhole : getaddrinfo(%s) : %s",
1517 rem_host
, gai_strerror(err
));
1519 SoapError(h
, 402, "Invalid Args");
1520 goto clear_and_exit
;
1527 SoapError(h
, 707, "ProtocolWilcardingNotAllowed");
1528 goto clear_and_exit
;
1530 if(proto
!= IPPROTO_UDP
&& proto
!= IPPROTO_TCP
1531 #ifdef IPPROTO_UDPITE
1532 && atoi(protocol
) != IPPROTO_UDPLITE
1536 SoapError(h
, 705, "ProtocolNotSupported");
1537 goto clear_and_exit
;
1539 if(ltime
< 1 || ltime
> 86400)
1541 syslog(LOG_WARNING
, "%s: LeaseTime=%d not supported, (ip=%s)",
1542 action
, ltime
, int_ip
);
1543 SoapError(h
, 402, "Invalid Args");
1544 goto clear_and_exit
;
1547 if(PinholeVerification(h
, int_ip
, iport
) <= 0)
1548 goto clear_and_exit
;
1550 syslog(LOG_INFO
, "%s: (inbound) from [%s]:%hu to [%s]:%hu with proto %ld during %d sec",
1551 action
, rem_host
?rem_host
:"any",
1552 rport
, int_ip
, iport
,
1555 /* In cases where the RemoteHost, RemotePort, InternalPort,
1556 * InternalClient and Protocol are the same than an existing pinhole,
1557 * but LeaseTime is different, the device MUST extend the existing
1558 * pinhole's lease time and return the UniqueID of the existing pinhole. */
1559 r
= upnp_add_inboundpinhole(rem_host
, rport
, int_ip
, iport
, proto
, "IGD2 pinhole", ltime
, &uid
);
1563 case 1: /* success */
1564 bodylen
= snprintf(body
, sizeof(body
),
1566 "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1568 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1570 case -1: /* not permitted */
1571 SoapError(h
, 701, "PinholeSpaceExhausted");
1574 SoapError(h
, 501, "ActionFailed");
1577 /* 606 Action not authorized
1578 * 701 PinholeSpaceExhausted
1579 * 702 FirewallDisabled
1580 * 703 InboundPinholeNotAllowed
1581 * 705 ProtocolNotSupported
1582 * 706 InternalPortWildcardingNotAllowed
1583 * 707 ProtocolWildcardingNotAllowed
1584 * 708 WildCardNotPermittedInSrcIP */
1586 ClearNameValueList(&data
);
1590 UpdatePinhole(struct upnphttp
* h
, const char * action
)
1592 static const char resp
[] =
1593 "<u:UpdatePinholeResponse "
1594 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1595 "</u:UpdatePinholeResponse>";
1596 struct NameValueParserData data
;
1597 const char * uid_str
, * leaseTime
;
1598 char iaddr
[INET6_ADDRSTRLEN
];
1599 unsigned short iport
;
1604 if(CheckStatus(h
)==0)
1607 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1608 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1609 leaseTime
= GetValueFromNameValueList(&data
, "NewLeaseTime");
1610 uid
= uid_str
? atoi(uid_str
) : -1;
1611 ltime
= leaseTime
? atoi(leaseTime
) : -1;
1612 ClearNameValueList(&data
);
1614 if(uid
< 0 || uid
> 65535 || ltime
<= 0 || ltime
> 86400)
1616 SoapError(h
, 402, "Invalid Args");
1620 /* Check that client is not updating an pinhole
1621 * it doesn't have access to, because of its public access */
1622 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
1623 iaddr
, sizeof(iaddr
), &iport
,
1625 NULL
, 0, /* desc, desclen */
1629 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1634 SoapError(h
, 704, "NoSuchEntry");
1639 SoapError(h
, 501, "ActionFailed");
1643 syslog(LOG_INFO
, "%s: (inbound) updating lease duration to %d for pinhole with ID: %d",
1644 action
, ltime
, uid
);
1646 n
= upnp_update_inboundpinhole(uid
, ltime
);
1648 SoapError(h
, 704, "NoSuchEntry");
1650 SoapError(h
, 501, "ActionFailed");
1652 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
1656 GetOutboundPinholeTimeout(struct upnphttp
* h
, const char * action
)
1660 static const char resp
[] =
1663 "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1668 struct NameValueParserData data
;
1669 char * int_ip
, * int_port
, * rem_host
, * rem_port
, * protocol
;
1671 unsigned short iport
, rport
;
1673 if (GETFLAG(IPV6FCFWDISABLEDMASK
))
1675 SoapError(h
, 702, "FirewallDisabled");
1679 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1680 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1681 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1682 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1683 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1684 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1686 rport
= (unsigned short)atoi(rem_port
);
1687 iport
= (unsigned short)atoi(int_port
);
1688 proto
= atoi(protocol
);
1690 syslog(LOG_INFO
, "%s: retrieving timeout for outbound pinhole from [%s]:%hu to [%s]:%hu protocol %s", action
, int_ip
, iport
,rem_host
, rport
, protocol
);
1693 r
= -1;/*upnp_check_outbound_pinhole(proto, &opt);*/
1697 case 1: /* success */
1698 bodylen
= snprintf(body
, sizeof(body
), resp
,
1699 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1701 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1703 case -5: /* Protocol not supported */
1704 SoapError(h
, 705, "ProtocolNotSupported");
1707 SoapError(h
, 501, "ActionFailed");
1709 ClearNameValueList(&data
);
1713 DeletePinhole(struct upnphttp
* h
, const char * action
)
1717 static const char resp
[] =
1718 "<u:DeletePinholeResponse "
1719 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1720 "</u:DeletePinholeResponse>";
1722 struct NameValueParserData data
;
1723 const char * uid_str
;
1724 char iaddr
[INET6_ADDRSTRLEN
];
1726 unsigned short iport
;
1727 unsigned int leasetime
;
1730 if(CheckStatus(h
)==0)
1733 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1734 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1735 uid
= uid_str
? atoi(uid_str
) : -1;
1736 ClearNameValueList(&data
);
1738 if(uid
< 0 || uid
> 65535)
1740 SoapError(h
, 402, "Invalid Args");
1744 /* Check that client is not deleting an pinhole
1745 * it doesn't have access to, because of its public access */
1746 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
1747 iaddr
, sizeof(iaddr
), &iport
,
1749 NULL
, 0, /* desc, desclen */
1753 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1758 SoapError(h
, 704, "NoSuchEntry");
1763 SoapError(h
, 501, "ActionFailed");
1767 n
= upnp_delete_inboundpinhole(uid
);
1770 syslog(LOG_INFO
, "%s: (inbound) failed to remove pinhole with ID: %d",
1772 SoapError(h
, 501, "ActionFailed");
1775 syslog(LOG_INFO
, "%s: (inbound) pinhole with ID %d successfully removed",
1777 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
1781 CheckPinholeWorking(struct upnphttp
* h
, const char * action
)
1783 static const char resp
[] =
1786 "<IsWorking>%d</IsWorking>"
1791 struct NameValueParserData data
;
1792 const char * uid_str
;
1794 char iaddr
[INET6_ADDRSTRLEN
];
1795 unsigned short iport
;
1796 unsigned int packets
;
1798 if(CheckStatus(h
)==0)
1801 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1802 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1803 uid
= uid_str
? atoi(uid_str
) : -1;
1804 ClearNameValueList(&data
);
1806 if(uid
< 0 || uid
> 65535)
1808 SoapError(h
, 402, "Invalid Args");
1812 /* Check that client is not checking a pinhole
1813 * it doesn't have access to, because of its public access */
1814 r
= upnp_get_pinhole_info(uid
,
1816 iaddr
, sizeof(iaddr
), &iport
,
1818 NULL
, 0, /* desc, desclen */
1822 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1826 SoapError(h
, 709, "NoPacketSent");
1829 bodylen
= snprintf(body
, sizeof(body
), resp
,
1830 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1832 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1835 SoapError(h
, 704, "NoSuchEntry");
1837 SoapError(h
, 501, "ActionFailed");
1841 GetPinholePackets(struct upnphttp
* h
, const char * action
)
1843 static const char resp
[] =
1846 "<PinholePackets>%u</PinholePackets>"
1850 struct NameValueParserData data
;
1851 const char * uid_str
;
1853 char iaddr
[INET6_ADDRSTRLEN
];
1854 unsigned short iport
;
1855 unsigned int packets
= 0;
1858 unsigned int leasetime
;
1860 if(CheckStatus(h
)==0)
1863 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1864 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1865 uid
= uid_str
? atoi(uid_str
) : -1;
1866 ClearNameValueList(&data
);
1868 if(uid
< 0 || uid
> 65535)
1870 SoapError(h
, 402, "Invalid Args");
1874 /* Check that client is not getting infos of a pinhole
1875 * it doesn't have access to, because of its public access */
1876 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
1877 iaddr
, sizeof(iaddr
), &iport
,
1879 NULL
, 0, /* desc, desclen */
1880 &leasetime
, &packets
);
1883 if(PinholeVerification(h
, iaddr
, iport
)<=0)
1887 else if(r
== -4 || r
== -1)
1889 SoapError(h
, 704, "NoSuchEntry");
1893 bodylen
= snprintf(body
, sizeof(body
), resp
,
1894 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1896 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1900 #ifdef ENABLE_DP_SERVICE
1902 SendSetupMessage(struct upnphttp
* h
, const char * action
)
1904 static const char resp
[] =
1907 "<NewOutMessage>%s</NewOutMessage>"
1911 struct NameValueParserData data
;
1912 const char * ProtocolType
; /* string */
1913 const char * InMessage
; /* base64 */
1914 const char * OutMessage
= ""; /* base64 */
1916 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1917 ProtocolType
= GetValueFromNameValueList(&data
, "NewProtocolType"); /* string */
1918 InMessage
= GetValueFromNameValueList(&data
, "NewInMessage"); /* base64 */
1920 if(ProtocolType
== NULL
|| InMessage
== NULL
)
1922 ClearNameValueList(&data
);
1923 SoapError(h
, 402, "Invalid Args");
1926 /*if(strcmp(ProtocolType, "DeviceProtection:1") != 0)*/
1927 if(strcmp(ProtocolType
, "WPS") != 0)
1929 ClearNameValueList(&data
);
1930 SoapError(h
, 600, "Argument Value Invalid"); /* 703 ? */
1933 /* TODO : put here code for WPS */
1935 bodylen
= snprintf(body
, sizeof(body
), resp
,
1936 action
, "urn:schemas-upnp-org:service:DeviceProtection:1",
1937 OutMessage
, action
);
1938 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1939 ClearNameValueList(&data
);
1943 GetSupportedProtocols(struct upnphttp
* h
, const char * action
)
1945 static const char resp
[] =
1948 "<NewProtocolList>%s</NewProtocolList>"
1952 const char * ProtocolList
=
1953 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1954 "<SupportedProtocols xmlns=\"urn:schemas-upnp-org:gw:DeviceProtection\""
1955 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
1956 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:DeviceProtection"
1957 " http://www.upnp.org/schemas/gw/DeviceProtection-v1.xsd\">"
1958 "<Introduction><Name>WPS</Name></Introduction>"
1959 "<Login><Name>PKCS5</Name></Login>"
1960 "</SupportedProtocols>";
1962 bodylen
= snprintf(body
, sizeof(body
), resp
,
1963 action
, "urn:schemas-upnp-org:service:DeviceProtection:1",
1964 ProtocolList
, action
);
1965 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1969 GetAssignedRoles(struct upnphttp
* h
, const char * action
)
1971 static const char resp
[] =
1974 "<NewRoleList>%s</NewRoleList>"
1978 const char * RoleList
= "Public"; /* list of roles separated by spaces */
1981 if(h
->ssl
!= NULL
) {
1982 /* we should get the Roles of the session (based on client certificate) */
1984 peercert
= SSL_get_peer_certificate(h
->ssl
);
1985 if(peercert
!= NULL
) {
1986 RoleList
= "Admin Basic";
1987 X509_free(peercert
);
1992 bodylen
= snprintf(body
, sizeof(body
), resp
,
1993 action
, "urn:schemas-upnp-org:service:DeviceProtection:1",
1995 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1999 /* Windows XP as client send the following requests :
2000 * GetConnectionTypeInfo
2002 * ? GetTotalBytesSent - WANCommonInterfaceConfig
2003 * ? GetTotalBytesReceived - idem
2004 * ? GetTotalPacketsSent - idem
2005 * ? GetTotalPacketsReceived - idem
2006 * GetCommonLinkProperties - idem
2007 * GetStatusInfo - WANIPConnection
2008 * GetExternalIPAddress
2009 * QueryStateVariable / ConnectionStatus!
2013 const char * methodName
;
2014 void (*methodImpl
)(struct upnphttp
*, const char *);
2018 /* WANCommonInterfaceConfig */
2019 { "QueryStateVariable", QueryStateVariable
},
2020 { "GetTotalBytesSent", GetTotalBytesSent
},
2021 { "GetTotalBytesReceived", GetTotalBytesReceived
},
2022 { "GetTotalPacketsSent", GetTotalPacketsSent
},
2023 { "GetTotalPacketsReceived", GetTotalPacketsReceived
},
2024 { "GetCommonLinkProperties", GetCommonLinkProperties
},
2025 { "GetStatusInfo", GetStatusInfo
},
2026 /* WANIPConnection */
2027 { "GetConnectionTypeInfo", GetConnectionTypeInfo
},
2028 { "GetNATRSIPStatus", GetNATRSIPStatus
},
2029 { "GetExternalIPAddress", GetExternalIPAddress
},
2030 { "AddPortMapping", AddPortMapping
},
2031 { "DeletePortMapping", DeletePortMapping
},
2032 { "GetGenericPortMappingEntry", GetGenericPortMappingEntry
},
2033 { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry
},
2034 /* Required in WANIPConnection:2 */
2035 { "SetConnectionType", SetConnectionType
},
2036 { "RequestConnection", RequestConnection
},
2037 { "ForceTermination", ForceTermination
},
2038 { "AddAnyPortMapping", AddAnyPortMapping
},
2039 { "DeletePortMappingRange", DeletePortMappingRange
},
2040 { "GetListOfPortMappings", GetListOfPortMappings
},
2041 #ifdef ENABLE_L3F_SERVICE
2042 /* Layer3Forwarding */
2043 { "SetDefaultConnectionService", SetDefaultConnectionService
},
2044 { "GetDefaultConnectionService", GetDefaultConnectionService
},
2046 #ifdef ENABLE_6FC_SERVICE
2047 /* WANIPv6FirewallControl */
2048 { "GetFirewallStatus", GetFirewallStatus
}, /* Required */
2049 { "AddPinhole", AddPinhole
}, /* Required */
2050 { "UpdatePinhole", UpdatePinhole
}, /* Required */
2051 { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout
}, /* Optional */
2052 { "DeletePinhole", DeletePinhole
}, /* Required */
2053 { "CheckPinholeWorking", CheckPinholeWorking
}, /* Optional */
2054 { "GetPinholePackets", GetPinholePackets
}, /* Required */
2056 #ifdef ENABLE_DP_SERVICE
2057 /* DeviceProtection */
2058 { "SendSetupMessage", SendSetupMessage
}, /* Required */
2059 { "GetSupportedProtocols", GetSupportedProtocols
}, /* Required */
2060 { "GetAssignedRoles", GetAssignedRoles
}, /* Required */
2066 ExecuteSoapAction(struct upnphttp
* h
, const char * action
, int n
)
2070 int i
, len
, methodlen
;
2072 /* SoapAction example :
2073 * urn:schemas-upnp-org:service:WANIPConnection:1#GetStatusInfo */
2074 p
= strchr(action
, '#');
2075 if(p
&& (p
- action
) < n
) {
2077 p2
= strchr(p
, '"');
2078 if(p2
&& (p2
- action
) <= n
)
2081 methodlen
= n
- (p
- action
);
2082 /*syslog(LOG_DEBUG, "SoapMethod: %.*s %d %d %p %p %d",
2083 methodlen, p, methodlen, n, action, p, (int)(p - action));*/
2084 for(i
= 0; soapMethods
[i
].methodName
; i
++) {
2085 len
= strlen(soapMethods
[i
].methodName
);
2086 if((len
== methodlen
) && memcmp(p
, soapMethods
[i
].methodName
, len
) == 0) {
2088 syslog(LOG_DEBUG
, "Remote Call of SoapMethod '%s'",
2089 soapMethods
[i
].methodName
);
2091 soapMethods
[i
].methodImpl(h
, soapMethods
[i
].methodName
);
2095 syslog(LOG_NOTICE
, "SoapMethod: Unknown: %.*s", methodlen
, p
);
2097 syslog(LOG_NOTICE
, "cannot parse SoapAction");
2100 SoapError(h
, 401, "Invalid Action");
2105 * errorCode errorDescription Description
2106 * -------- ---------------- -----------
2107 * 401 Invalid Action No action by that name at this service.
2108 * 402 Invalid Args Could be any of the following: not enough in args,
2109 * too many in args, no in arg by that name,
2110 * one or more in args are of the wrong data type.
2111 * 403 Out of Sync Out of synchronization.
2112 * 501 Action Failed May be returned in current state of service
2113 * prevents invoking that action.
2114 * 600-699 TBD Common action errors. Defined by UPnP Forum
2115 * Technical Committee.
2116 * 700-799 TBD Action-specific errors for standard actions.
2117 * Defined by UPnP Forum working committee.
2118 * 800-899 TBD Action-specific errors for non-standard actions.
2119 * Defined by UPnP vendor.
2122 SoapError(struct upnphttp
* h
, int errCode
, const char * errDesc
)
2124 static const char resp
[] =
2126 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
2127 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
2130 "<faultcode>s:Client</faultcode>"
2131 "<faultstring>UPnPError</faultstring>"
2133 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
2134 "<errorCode>%d</errorCode>"
2135 "<errorDescription>%s</errorDescription>"
2145 syslog(LOG_INFO
, "Returning UPnPError %d: %s", errCode
, errDesc
);
2146 bodylen
= snprintf(body
, sizeof(body
), resp
, errCode
, errDesc
);
2147 BuildResp2_upnphttp(h
, 500, "Internal Server Error", body
, bodylen
);
2148 SendRespAndClose_upnphttp(h
);