1 /* $Id: upnpsoap.c,v 1.85 2011/06/17 23:24:14 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2011 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
11 #include <sys/socket.h>
14 #include <sys/types.h>
15 #include <arpa/inet.h>
16 #include <netinet/in.h>
20 #include "upnpglobalvars.h"
23 #include "upnpreplyparse.h"
24 #include "upnpredirect.h"
25 #include "getifaddr.h"
26 #include "getifstats.h"
27 #include "getconnstatus.h"
31 BuildSendAndCloseSoapResp(struct upnphttp
* h
,
32 const char * body
, int bodylen
)
34 static const char beforebody
[] =
35 "<?xml version=\"1.0\"?>\r\n"
36 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
37 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
40 static const char afterbody
[] =
44 BuildHeader_upnphttp(h
, 200, "OK", sizeof(beforebody
) - 1
45 + sizeof(afterbody
) - 1 + bodylen
);
47 memcpy(h
->res_buf
+ h
->res_buflen
, beforebody
, sizeof(beforebody
) - 1);
48 h
->res_buflen
+= sizeof(beforebody
) - 1;
50 memcpy(h
->res_buf
+ h
->res_buflen
, body
, bodylen
);
51 h
->res_buflen
+= bodylen
;
53 memcpy(h
->res_buf
+ h
->res_buflen
, afterbody
, sizeof(afterbody
) - 1);
54 h
->res_buflen
+= sizeof(afterbody
) - 1;
57 CloseSocket_upnphttp(h
);
61 GetConnectionTypeInfo(struct upnphttp
* h
, const char * action
)
63 static const char resp
[] =
64 "<u:GetConnectionTypeInfoResponse "
65 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
66 "<NewConnectionType>IP_Routed</NewConnectionType>"
67 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
68 "</u:GetConnectionTypeInfoResponse>";
69 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
73 GetTotalBytesSent(struct upnphttp
* h
, const char * action
)
77 static const char resp
[] =
80 "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
87 r
= getifstats(ext_if_name
, &data
);
88 bodylen
= snprintf(body
, sizeof(body
), resp
,
89 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
90 r
<0?0:data
.obytes
, action
);
91 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
95 GetTotalBytesReceived(struct upnphttp
* h
, const char * action
)
99 static const char resp
[] =
102 "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
109 r
= getifstats(ext_if_name
, &data
);
110 bodylen
= snprintf(body
, sizeof(body
), resp
,
111 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
112 r
<0?0:data
.ibytes
, action
);
113 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
117 GetTotalPacketsSent(struct upnphttp
* h
, const char * action
)
121 static const char resp
[] =
124 "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
131 r
= getifstats(ext_if_name
, &data
);
132 bodylen
= snprintf(body
, sizeof(body
), resp
,
133 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
134 r
<0?0:data
.opackets
, action
);
135 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
139 GetTotalPacketsReceived(struct upnphttp
* h
, const char * action
)
143 static const char resp
[] =
146 "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
153 r
= getifstats(ext_if_name
, &data
);
154 bodylen
= snprintf(body
, sizeof(body
), resp
,
155 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
156 r
<0?0:data
.ipackets
, action
);
157 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
161 GetCommonLinkProperties(struct upnphttp
* h
, const char * action
)
163 /* WANAccessType : set depending on the hardware :
164 * DSL, POTS (plain old Telephone service), Cable, Ethernet */
165 static const char resp
[] =
168 /*"<NewWANAccessType>DSL</NewWANAccessType>"*/
169 "<NewWANAccessType>Cable</NewWANAccessType>"
170 "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
171 "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
172 "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
178 const char * status
= "Up"; /* Up, Down (Required),
179 * Initializing, Unavailable (Optional) */
180 char ext_ip_addr
[INET_ADDRSTRLEN
];
182 if((downstream_bitrate
== 0) || (upstream_bitrate
== 0))
184 if(getifstats(ext_if_name
, &data
) >= 0)
186 if(downstream_bitrate
== 0) downstream_bitrate
= data
.baudrate
;
187 if(upstream_bitrate
== 0) upstream_bitrate
= data
.baudrate
;
190 if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
) < 0) {
193 bodylen
= snprintf(body
, sizeof(body
), resp
,
194 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
195 upstream_bitrate
, downstream_bitrate
,
197 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
201 GetStatusInfo(struct upnphttp
* h
, const char * action
)
203 static const char resp
[] =
206 "<NewConnectionStatus>%s</NewConnectionStatus>"
207 "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
208 "<NewUptime>%ld</NewUptime>"
215 /* ConnectionStatus possible values :
216 * Unconfigured, Connecting, Connected, PendingDisconnect,
217 * Disconnecting, Disconnected */
219 status
= get_wan_connection_status_str(ext_if_name
);
220 uptime
= (time(NULL
) - startup_time
);
221 bodylen
= snprintf(body
, sizeof(body
), resp
,
222 action
, SERVICE_TYPE_WANIPC
,
223 status
, (long)uptime
, action
);
224 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
228 GetNATRSIPStatus(struct upnphttp
* h
, const char * action
)
230 static const char resp
[] =
231 "<u:GetNATRSIPStatusResponse "
232 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
233 "<NewRSIPAvailable>0</NewRSIPAvailable>"
234 "<NewNATEnabled>1</NewNATEnabled>"
235 "</u:GetNATRSIPStatusResponse>";
236 /* 2.2.9. RSIPAvailable
237 * This variable indicates if Realm-specific IP (RSIP) is available
238 * as a feature on the InternetGatewayDevice. RSIP is being defined
239 * in the NAT working group in the IETF to allow host-NATing using
240 * a standard set of message exchanges. It also allows end-to-end
241 * applications that otherwise break if NAT is introduced
242 * (e.g. IPsec-based VPNs).
243 * A gateway that does not support RSIP should set this variable to 0. */
244 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
248 GetExternalIPAddress(struct upnphttp
* h
, const char * action
)
250 static const char resp
[] =
253 "<NewExternalIPAddress>%s</NewExternalIPAddress>"
258 char ext_ip_addr
[INET_ADDRSTRLEN
];
259 /* Does that method need to work with IPv6 ?
260 * There is usually no NAT with IPv6 */
262 #ifndef MULTIPLE_EXTERNAL_IP
265 strncpy(ext_ip_addr
, use_ext_ip_addr
, INET_ADDRSTRLEN
);
267 else if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
) < 0)
269 syslog(LOG_ERR
, "Failed to get ip address for interface %s",
271 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
275 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
276 for(i
= 0; i
<n_lan_addr
; i
++)
278 if( (h
->clientaddr
.s_addr
& lan_addr
[i
].mask
.s_addr
)
279 == (lan_addr
[i
].addr
.s_addr
& lan_addr
[i
].mask
.s_addr
))
281 strncpy(ext_ip_addr
, lan_addr
[i
].ext_ip_str
, INET_ADDRSTRLEN
);
286 bodylen
= snprintf(body
, sizeof(body
), resp
,
287 action
, SERVICE_TYPE_WANIPC
,
288 ext_ip_addr
, action
);
289 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
292 /* AddPortMapping method of WANIPConnection Service
293 * Ignored argument : NewEnabled */
295 AddPortMapping(struct upnphttp
* h
, const char * action
)
299 static const char resp
[] =
300 "<u:AddPortMappingResponse "
301 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\"/>";
303 struct NameValueParserData data
;
304 char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
305 char * leaseduration_str
;
306 unsigned int leaseduration
;
308 unsigned short iport
, eport
;
310 struct hostent
*hp
; /* getbyhostname() */
311 char ** ptr
; /* getbyhostname() */
312 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
314 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
315 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
318 ClearNameValueList(&data
);
319 SoapError(h
, 402, "Invalid Args");
323 /* IGD 2 MUST support both wildcard and specific IP address values
324 * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
325 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
326 #ifndef SUPPORT_REMOTEHOST
328 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
330 ClearNameValueList(&data
);
331 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
337 /* if ip not valid assume hostname and convert */
338 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
340 hp
= gethostbyname(int_ip
);
341 if(hp
&& hp
->h_addrtype
== AF_INET
)
343 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
345 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
346 result_ip
= *((struct in_addr
*) *ptr
);
347 /* TODO : deal with more than one ip per hostname */
353 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
354 ClearNameValueList(&data
);
355 SoapError(h
, 402, "Invalid Args");
360 /* check if NewInternalAddress is the client address */
361 if(GETFLAG(SECUREMODEMASK
))
363 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
365 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
366 inet_ntoa(h
->clientaddr
), int_ip
);
367 ClearNameValueList(&data
);
368 SoapError(h
, 718, "ConflictInMappingEntry");
373 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
374 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
375 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
376 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
377 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
379 if (!int_port
|| !ext_port
|| !protocol
)
381 ClearNameValueList(&data
);
382 SoapError(h
, 402, "Invalid Args");
386 eport
= (unsigned short)atoi(ext_port
);
387 iport
= (unsigned short)atoi(int_port
);
389 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
391 /* PortMappingLeaseDuration can be either a value between 1 and
392 * 604800 seconds or the zero value (for infinite lease time).
393 * Note that an infinite lease time can be only set by out-of-band
394 * mechanisms like WWW-administration, remote management or local
396 * If a control point uses the value 0 to indicate an infinite lease
397 * time mapping, it is REQUIRED that gateway uses the maximum value
398 * instead (e.g. 604800 seconds) */
399 if(leaseduration
== 0 || leaseduration
> 604800)
400 leaseduration
= 604800;
403 syslog(LOG_INFO
, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
404 action
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
, r_host
);
406 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
408 ClearNameValueList(&data
);
410 /* possible error codes for AddPortMapping :
412 * 501 - Action Failed
413 * 715 - Wildcard not permited in SrcAddr
414 * 716 - Wildcard not permited in ExtPort
415 * 718 - ConflictInMappingEntry
416 * 724 - SamePortValuesRequired (deprecated in IGD v2)
417 * 725 - OnlyPermanentLeasesSupported
418 The NAT implementation only supports permanent lease times on
419 port mappings (deprecated in IGD v2)
420 * 726 - RemoteHostOnlySupportsWildcard
421 RemoteHost must be a wildcard and cannot be a specific IP
422 address or DNS name (deprecated in IGD v2)
423 * 727 - ExternalPortOnlySupportsWildcard
424 ExternalPort must be a wildcard and cannot be a specific port
425 value (deprecated in IGD v2)
426 * 728 - NoPortMapsAvailable
427 There are not enough free prots available to complete the mapping
429 * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
432 case 0: /* success */
433 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
435 case -2: /* already redirected */
436 case -3: /* not permitted */
437 SoapError(h
, 718, "ConflictInMappingEntry");
440 SoapError(h
, 501, "ActionFailed");
444 /* AddAnyPortMapping was added in WANIPConnection v2 */
446 AddAnyPortMapping(struct upnphttp
* h
, const char * action
)
449 static const char resp
[] =
452 "<NewReservedPort>%hu</NewReservedPort>"
458 struct NameValueParserData data
;
459 const char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
461 unsigned short iport
, eport
;
462 const char * leaseduration_str
;
463 unsigned int leaseduration
;
465 struct hostent
*hp
; /* getbyhostname() */
466 char ** ptr
; /* getbyhostname() */
467 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
469 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
470 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
471 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
472 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
473 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
474 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
476 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
477 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
479 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
480 if(leaseduration
== 0)
481 leaseduration
= 604800;
483 eport
= (unsigned short)atoi(ext_port
);
484 iport
= (unsigned short)atoi(int_port
);
488 ClearNameValueList(&data
);
489 SoapError(h
, 402, "Invalid Args");
492 #ifndef SUPPORT_REMOTEHOST
494 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
496 ClearNameValueList(&data
);
497 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
503 /* if ip not valid assume hostname and convert */
504 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
506 hp
= gethostbyname(int_ip
);
507 if(hp
&& hp
->h_addrtype
== AF_INET
)
509 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
511 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
512 result_ip
= *((struct in_addr
*) *ptr
);
513 /* TODO : deal with more than one ip per hostname */
519 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
520 ClearNameValueList(&data
);
521 SoapError(h
, 402, "Invalid Args");
526 /* check if NewInternalAddress is the client address */
527 if(GETFLAG(SECUREMODEMASK
))
529 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
531 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
532 inet_ntoa(h
->clientaddr
), int_ip
);
533 ClearNameValueList(&data
);
534 SoapError(h
, 606, "Action not authorized");
539 /* TODO : accept a different external port
540 * have some smart strategy to choose the port */
542 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
543 if(r
==-2 && eport
< 65535) {
550 ClearNameValueList(&data
);
554 case 0: /* success */
555 bodylen
= snprintf(body
, sizeof(body
), resp
,
556 action
, SERVICE_TYPE_WANIPC
,
558 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
560 case -2: /* already redirected */
561 SoapError(h
, 718, "ConflictInMappingEntry");
563 case -3: /* not permitted */
564 SoapError(h
, 606, "Action not authorized");
567 SoapError(h
, 501, "ActionFailed");
572 GetSpecificPortMappingEntry(struct upnphttp
* h
, const char * action
)
576 static const char resp
[] =
579 "<NewInternalPort>%u</NewInternalPort>"
580 "<NewInternalClient>%s</NewInternalClient>"
581 "<NewEnabled>1</NewEnabled>"
582 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
583 "<NewLeaseDuration>%u</NewLeaseDuration>"
588 struct NameValueParserData data
;
589 const char * r_host
, * ext_port
, * protocol
;
590 unsigned short eport
, iport
;
593 unsigned int leaseduration
= 0;
595 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
596 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
597 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
598 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
600 if(!ext_port
|| !protocol
)
602 ClearNameValueList(&data
);
603 SoapError(h
, 402, "Invalid Args");
606 #ifndef SUPPORT_REMOTEHOST
608 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
610 ClearNameValueList(&data
);
611 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
617 eport
= (unsigned short)atoi(ext_port
);
620 r
= upnp_get_redirection_infos(eport
, protocol
, &iport
,
621 int_ip
, sizeof(int_ip
),
627 SoapError(h
, 714, "NoSuchEntryInArray");
631 syslog(LOG_INFO
, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
633 r_host
, ext_port
, protocol
, int_ip
, (unsigned int)iport
, desc
);
634 bodylen
= snprintf(body
, sizeof(body
), resp
,
635 action
, SERVICE_TYPE_WANIPC
,
636 (unsigned int)iport
, int_ip
, desc
, leaseduration
,
638 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
641 ClearNameValueList(&data
);
645 DeletePortMapping(struct upnphttp
* h
, const char * action
)
649 static const char resp
[] =
650 "<u:DeletePortMappingResponse "
651 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
652 "</u:DeletePortMappingResponse>";
654 struct NameValueParserData data
;
655 const char * r_host
, * ext_port
, * protocol
;
656 unsigned short eport
;
658 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
659 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
660 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
661 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
663 if(!ext_port
|| !protocol
)
665 ClearNameValueList(&data
);
666 SoapError(h
, 402, "Invalid Args");
669 #ifndef SUPPORT_REMOTEHOST
671 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
673 ClearNameValueList(&data
);
674 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
680 eport
= (unsigned short)atoi(ext_port
);
682 /* TODO : if in secure mode, check the IP
683 * Removing a redirection is not a security threat,
684 * just an annoyance for the user using it. So this is not
687 syslog(LOG_INFO
, "%s: external port: %hu, protocol: %s",
688 action
, eport
, protocol
);
690 r
= upnp_delete_redirection(eport
, protocol
);
694 SoapError(h
, 714, "NoSuchEntryInArray");
698 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
701 ClearNameValueList(&data
);
704 /* DeletePortMappingRange was added in IGD spec v2 */
706 DeletePortMappingRange(struct upnphttp
* h
, const char * action
)
709 static const char resp
[] =
710 "<u:DeletePortMappingRangeResponse "
711 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
712 "</u:DeletePortMappingRangeResponse>";
713 struct NameValueParserData data
;
714 const char * protocol
;
715 unsigned short startport
, endport
;
717 unsigned short * port_list
;
718 unsigned int i
, number
= 0;
720 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
721 startport
= (unsigned short)atoi(GetValueFromNameValueList(&data
, "NewStartPort"));
722 endport
= (unsigned short)atoi(GetValueFromNameValueList(&data
, "NewEndPort"));
723 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
724 manage
= atoi(GetValueFromNameValueList(&data
, "NewManage"));
727 606 - Action not authorized
728 730 - PortMappingNotFound
729 733 - InconsistentParameter
731 if(startport
> endport
)
733 SoapError(h
, 733, "InconsistentParameter");
734 ClearNameValueList(&data
);
738 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
740 for(i
= 0; i
< number
; i
++)
742 r
= upnp_delete_redirection(port_list
[i
], protocol
);
743 /* TODO : check return value for errors */
746 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
748 ClearNameValueList(&data
);
752 GetGenericPortMappingEntry(struct upnphttp
* h
, const char * action
)
756 static const char resp
[] =
759 "<NewRemoteHost>%s</NewRemoteHost>"
760 "<NewExternalPort>%u</NewExternalPort>"
761 "<NewProtocol>%s</NewProtocol>"
762 "<NewInternalPort>%u</NewInternalPort>"
763 "<NewInternalClient>%s</NewInternalClient>"
764 "<NewEnabled>1</NewEnabled>"
765 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
766 "<NewLeaseDuration>%u</NewLeaseDuration>"
770 unsigned short eport
, iport
;
771 const char * m_index
;
772 char protocol
[4], iaddr
[32];
775 unsigned int leaseduration
= 0;
776 struct NameValueParserData data
;
778 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
779 m_index
= GetValueFromNameValueList(&data
, "NewPortMappingIndex");
783 ClearNameValueList(&data
);
784 SoapError(h
, 402, "Invalid Args");
788 index
= (int)atoi(m_index
);
790 syslog(LOG_INFO
, "%s: index=%d", action
, index
);
793 r
= upnp_get_redirection_infos_by_index(index
, &eport
, protocol
, &iport
,
794 iaddr
, sizeof(iaddr
),
796 rhost
, sizeof(rhost
),
801 SoapError(h
, 713, "SpecifiedArrayIndexInvalid");
807 bodylen
= snprintf(body
, sizeof(body
), resp
,
808 action
, SERVICE_TYPE_WANIPC
, rhost
,
809 (unsigned int)eport
, protocol
, (unsigned int)iport
, iaddr
, desc
,
810 leaseduration
, action
);
811 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
814 ClearNameValueList(&data
);
817 /* GetListOfPortMappings was added in the IGD v2 specification */
819 GetListOfPortMappings(struct upnphttp
* h
, const char * action
)
821 static const char resp_start
[] =
824 "<NewPortListing><![CDATA[";
825 static const char resp_end
[] =
826 "]]></NewPortListing>"
829 static const char list_start
[] =
830 "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
831 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
832 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
833 " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
834 static const char list_end
[] =
835 "</p:PortMappingList>";
837 static const char entry
[] =
838 "<p:PortMappingEntry>"
839 "<p:NewRemoteHost>%s</p:NewRemoteHost>"
840 "<p:NewExternalPort>%hu</p:NewExternalPort>"
841 "<p:NewProtocol>%s</p:NewProtocol>"
842 "<p:NewInternalPort>%hu</p:NewInternalPort>"
843 "<p:NewInternalClient>%s</p:NewInternalClient>"
844 "<p:NewEnabled>1</p:NewEnabled>"
845 "<p:NewDescription>%s</p:NewDescription>"
846 "<p:NewLeaseTime>%u</p:NewLeaseTime>"
847 "</p:PortMappingEntry>";
854 unsigned short iport
;
858 unsigned int leaseduration
= 0;
860 struct NameValueParserData data
;
861 unsigned short startport
, endport
;
862 const char * protocol
;
865 unsigned short * port_list
;
866 unsigned int i
, list_size
= 0;
868 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
869 startport
= (unsigned short)atoi(GetValueFromNameValueList(&data
, "NewStartPort"));
870 endport
= (unsigned short)atoi(GetValueFromNameValueList(&data
, "NewEndPort"));
871 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
872 manage
= atoi(GetValueFromNameValueList(&data
, "NewManage"));
873 number
= atoi(GetValueFromNameValueList(&data
, "NewNumberOfPorts"));
874 if(number
== 0) number
= 1000; /* return up to 1000 mappings by default */
876 if(startport
> endport
)
878 SoapError(h
, 733, "InconsistentParameter");
879 ClearNameValueList(&data
);
883 TODO : build the PortMappingList xml document :
885 <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
886 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
887 xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
888 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
890 <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
891 <p:NewExternalPort>2345</p:NewExternalPort>
892 <p:NewProtocol>TCP</p:NewProtocol>
893 <p:NewInternalPort>2345</p:NewInternalPort>
894 <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
895 <p:NewEnabled>1</p:NewEnabled>
896 <p:NewDescription>dooom</p:NewDescription>
897 <p:NewLeaseTime>345</p:NewLeaseTime>
898 </p:PortMappingEntry>
902 body
= malloc(bodyalloc
);
905 ClearNameValueList(&data
);
906 SoapError(h
, 501, "ActionFailed");
909 bodylen
= snprintf(body
, bodyalloc
, resp_start
,
910 action
, SERVICE_TYPE_WANIPC
);
911 memcpy(body
+bodylen
, list_start
, sizeof(list_start
));
912 bodylen
+= (sizeof(list_start
) - 1);
914 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
915 protocol
, &list_size
);
916 /* loop through port mappings */
917 for(i
= 0; number
> 0 && i
< list_size
; i
++)
919 /* have a margin of 1024 bytes to store the new entry */
920 if(bodylen
+ 1024 > bodyalloc
)
923 body
= realloc(body
, bodyalloc
);
926 ClearNameValueList(&data
);
927 SoapError(h
, 501, "ActionFailed");
932 r
= upnp_get_redirection_infos(port_list
[i
], protocol
, &iport
,
933 int_ip
, sizeof(int_ip
),
934 desc
, sizeof(desc
), &leaseduration
);
939 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, entry
,
940 rhost
, port_list
[i
], protocol
,
941 iport
, int_ip
, desc
, leaseduration
);
948 memcpy(body
+bodylen
, list_end
, sizeof(list_end
));
949 bodylen
+= (sizeof(list_end
) - 1);
950 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, resp_end
,
952 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
955 ClearNameValueList(&data
);
958 #ifdef ENABLE_L3F_SERVICE
960 SetDefaultConnectionService(struct upnphttp
* h
, const char * action
)
962 static const char resp
[] =
963 "<u:SetDefaultConnectionServiceResponse "
964 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
965 "</u:SetDefaultConnectionServiceResponse>";
966 struct NameValueParserData data
;
968 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
969 p
= GetValueFromNameValueList(&data
, "NewDefaultConnectionService");
971 syslog(LOG_INFO
, "%s(%s) : Ignored", action
, p
);
973 ClearNameValueList(&data
);
974 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
978 GetDefaultConnectionService(struct upnphttp
* h
, const char * action
)
980 static const char resp
[] =
982 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
983 "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
984 SERVICE_ID_WANIPC
"</NewDefaultConnectionService>"
986 /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
987 * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
988 * urn:upnp-org:serviceId:WANPPPConn1 */
992 bodylen
= snprintf(body
, sizeof(body
), resp
,
993 action
, uuidvalue
, action
);
994 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
998 /* Added for compliance with WANIPConnection v2 */
1000 SetConnectionType(struct upnphttp
* h
, const char * action
)
1002 const char * connection_type
;
1003 struct NameValueParserData data
;
1005 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1006 connection_type
= GetValueFromNameValueList(&data
, "NewConnectionType");
1007 /* Unconfigured, IP_Routed, IP_Bridged */
1008 ClearNameValueList(&data
);
1009 /* always return a ReadOnly error */
1010 SoapError(h
, 731, "ReadOnly");
1013 /* Added for compliance with WANIPConnection v2 */
1015 RequestConnection(struct upnphttp
* h
, const char * action
)
1017 SoapError(h
, 606, "Action not authorized");
1020 /* Added for compliance with WANIPConnection v2 */
1022 ForceTermination(struct upnphttp
* h
, const char * action
)
1024 SoapError(h
, 606, "Action not authorized");
1028 If a control point calls QueryStateVariable on a state variable that is not
1029 buffered in memory within (or otherwise available from) the service,
1030 the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1032 QueryStateVariable remains useful as a limited test tool but may not be
1033 part of some future versions of UPnP.
1036 QueryStateVariable(struct upnphttp
* h
, const char * action
)
1038 static const char resp
[] =
1041 "<return>%s</return>"
1046 struct NameValueParserData data
;
1047 const char * var_name
;
1049 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1050 /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1051 /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1052 var_name
= GetValueFromNameValueList(&data
, "varName");
1054 /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1058 SoapError(h
, 402, "Invalid Args");
1060 else if(strcmp(var_name
, "ConnectionStatus") == 0)
1062 const char * status
;
1064 status
= get_wan_connection_status_str(ext_if_name
);
1065 bodylen
= snprintf(body
, sizeof(body
), resp
,
1066 action
, "urn:schemas-upnp-org:control-1-0",
1068 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1072 else if(strcmp(var_name
, "ConnectionType") == 0)
1074 bodylen
= snprintf(body
, sizeof(body
), resp
, "IP_Routed");
1075 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1077 else if(strcmp(var_name
, "LastConnectionError") == 0)
1079 bodylen
= snprintf(body
, sizeof(body
), resp
, "ERROR_NONE");
1080 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1083 else if(strcmp(var_name
, "PortMappingNumberOfEntries") == 0)
1086 snprintf(strn
, sizeof(strn
), "%i",
1087 upnp_get_portmapping_number_of_entries());
1088 bodylen
= snprintf(body
, sizeof(body
), resp
,
1089 action
, "urn:schemas-upnp-org:control-1-0",
1091 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1095 syslog(LOG_NOTICE
, "%s: Unknown: %s", action
, var_name
?var_name
:"");
1096 SoapError(h
, 404, "Invalid Var");
1099 ClearNameValueList(&data
);
1102 #ifdef ENABLE_6FC_SERVICE
1104 #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1106 /* WANIPv6FirewallControl actions */
1108 GetFirewallStatus(struct upnphttp
* h
, const char * action
)
1110 static const char resp
[] =
1113 "<FirewallEnabled>%d</FirewallEnabled>"
1114 "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1120 bodylen
= snprintf(body
, sizeof(body
), resp
,
1121 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1122 ipv6fc_firewall_enabled
, ipv6fc_inbound_pinhole_allowed
, action
);
1123 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1127 CheckStatus(struct upnphttp
* h
)
1129 if (!ipv6fc_firewall_enabled
)
1131 SoapError(h
, 702, "FirewallDisabed");
1134 else if(!ipv6fc_inbound_pinhole_allowed
)
1136 SoapError(h
, 703, "InboundPinholeNotAllowed");
1144 DataVerification(struct upnphttp
* h
, char * int_ip
, unsigned short * int_port
, const char * protocol
, char * leaseTime
)
1147 // ** Internal IP can't be wildcarded
1150 SoapError(h
, 708, "WildCardNotPermittedInSrcIP");
1154 if (!strchr(int_ip
, ':'))
1156 SoapError(h
, 402, "Invalid Args");
1160 // ** Internal port can't be wilcarded.
1161 // printf("\tint_port: *%d*\n", *int_port);
1164 SoapError(h
, 706, "InternalPortWilcardingNotAllowed");
1168 // ** Protocol can't be wilcarded and can't be an unknown port (here deal with only UDP, TCP, UDPLITE)
1169 // printf("\tprotocol: *%s*\n", protocol);
1170 if (atoi(protocol
) == 65535)
1172 SoapError(h
, 707, "ProtocolWilcardingNotAllowed");
1175 else if (atoi(protocol
) != IPPROTO_UDP
1176 && atoi(protocol
) != IPPROTO_TCP
1177 #ifdef IPPROTO_UDPITE
1178 && atoi(protocol
) != IPPROTO_UDPLITE
1182 SoapError(h
, 705, "ProtocolNotSupported");
1186 // ** Lease Time can't be wilcarded nor >86400.
1187 // printf("\tlease time: %s\n", leaseTime);
1188 if(!leaseTime
|| !atoi(leaseTime
) || atoi(leaseTime
)>86400)
1190 /* lease duration is never infinite, nor wilcarded. In this case, use default value */
1191 syslog(LOG_WARNING
, "LeaseTime=%s not supported, (ip=%s)", leaseTime
, int_ip
);
1192 SoapError(h
, 402, "Invalid Args");
1200 static int connecthostport(const char * host
, unsigned short port
, char * result
)
1203 char hostname
[INET6_ADDRSTRLEN
];
1204 char port_str
[8], ifname
[8], tmp
[4];
1205 struct addrinfo
*ai
, *p
;
1206 struct addrinfo hints
;
1208 memset(&hints
, 0, sizeof(hints
));
1209 /* hints.ai_flags = AI_ADDRCONFIG; */
1210 #ifdef AI_NUMERICSERV
1211 hints
.ai_flags
= AI_NUMERICSERV
;
1213 hints
.ai_socktype
= SOCK_STREAM
;
1214 hints
.ai_family
= AF_UNSPEC
; /* AF_INET, AF_INET6 or AF_UNSPEC */
1215 /* hints.ai_protocol = IPPROTO_TCP; */
1216 snprintf(port_str
, sizeof(port_str
), "%hu", port
);
1217 strcpy(hostname
, host
);
1218 if(!strncmp(host
, "fe80", 4))
1220 printf("Using an linklocal address\n");
1221 strcpy(ifname
, "%");
1222 snprintf(tmp
, sizeof(tmp
), "%d", linklocal_index
);
1223 strcat(ifname
, tmp
);
1224 strcat(hostname
, ifname
);
1225 printf("host: %s\n", hostname
);
1227 n
= getaddrinfo(hostname
, port_str
, &hints
, &ai
);
1230 fprintf(stderr
, "getaddrinfo() error : %s\n", gai_strerror(n
));
1234 for(p
= ai
; p
; p
= p
->ai_next
)
1238 char tmp_service
[256];
1239 printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1240 p
->ai_family
, p
->ai_socktype
, p
->ai_protocol
, p
->ai_addrlen
);
1241 getnameinfo(p
->ai_addr
, p
->ai_addrlen
, tmp_host
, sizeof(tmp_host
),
1242 tmp_service
, sizeof(tmp_service
),
1243 NI_NUMERICHOST
| NI_NUMERICSERV
);
1244 printf(" host=%s service=%s\n", tmp_host
, tmp_service
);
1246 inet_ntop(AF_INET6
, &(((struct sockaddr_in6
*)p
->ai_addr
)->sin6_addr
), result
, INET6_ADDRSTRLEN
);
1253 /* Check the security policy right */
1255 PinholeVerification(struct upnphttp
* h
, char * int_ip
, unsigned short * int_port
)
1258 /* Pinhole InternalClient address must correspond to the action sender */
1259 syslog(LOG_INFO
, "Checking internal IP@ and port (Security policy purpose)");
1260 char senderAddr
[INET6_ADDRSTRLEN
]="";
1261 //char str[INET6_ADDRSTRLEN]="";
1262 //connecthostport(int_ip, *int_port, str);
1263 //printf("int_ip: %s / str: %s\n", int_ip, str);
1265 struct addrinfo hints
, *ai
, *p
;
1266 struct in6_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */ //IPv6 Modification
1268 hints
.ai_socktype
= SOCK_STREAM
;
1269 hints
.ai_family
= AF_UNSPEC
;
1271 /* if ip not valid assume hostname and convert */
1272 if (inet_pton(AF_INET6
, int_ip
, &result_ip
) <= 0) //IPv6 Modification
1275 n
= getaddrinfo(int_ip
, NULL
, &hints
, &ai
);//hp = gethostbyname(int_ip);
1276 if(!n
&& ai
->ai_family
== AF_INET6
) //IPv6 Modification
1278 for(p
= ai
; p
; p
= p
->ai_next
)//ptr = hp->h_addr_list; ptr && *ptr; ptr++)
1280 inet_ntop(AF_INET6
, (struct in6_addr
*) p
, int_ip
, sizeof(struct in6_addr
)); ///IPv6 Modification
1281 result_ip
= *((struct in6_addr
*) p
);
1282 fprintf(stderr
, "upnpsoap / AddPinhole: assuming int addr = %s", int_ip
);
1283 /* TODO : deal with more than one ip per hostname */
1289 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
1290 SoapError(h
, 402, "Invalid Args");
1296 if(inet_ntop(AF_INET6
, &(h
->clientaddr_v6
), senderAddr
, INET6_ADDRSTRLEN
)<=0)
1298 //printf("Failed to inet_ntop\n");
1299 syslog(LOG_ERR
, "inet_ntop: %m");
1302 printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr
, int_ip
);
1304 if(strcmp(senderAddr
, int_ip
) != 0)
1305 if(h
->clientaddr_v6
.s6_addr
!= result_ip
.s6_addr
)
1307 syslog(LOG_INFO
, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1308 senderAddr
, int_ip
);
1309 SoapError(h
, 606, "Action not authorized");
1313 /* Pinhole InternalPort must be greater than or equal to 1024 */
1314 if (*int_port
< 1024)
1316 syslog(LOG_INFO
, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1318 SoapError(h
, 606, "Action not authorized");
1325 AddPinhole(struct upnphttp
* h
, const char * action
)
1328 static const char resp
[] =
1331 "<UniqueID>%d</UniqueID>"
1335 struct NameValueParserData data
;
1336 char * rem_host
, * rem_port
, * int_ip
, * int_port
, * protocol
, * leaseTime
;
1338 unsigned short iport
, rport
;
1340 if(CheckStatus(h
)==0)
1343 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1344 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1345 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1346 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1347 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1348 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1349 leaseTime
= GetValueFromNameValueList(&data
, "LeaseTime");
1351 rport
= (unsigned short)atoi(rem_port
);
1352 iport
= (unsigned short)atoi(int_port
);
1354 // ** As there is no security policy, InternalClient must be equal to the CP's IP address.
1355 if(DataVerification(h
, int_ip
, &iport
, protocol
, leaseTime
) == 0
1356 || PinholeVerification(h
, int_ip
, &iport
) <= 0)
1358 ClearNameValueList(&data
);
1362 // ** RemoteHost can be wilcarded or an IDN.
1363 /*printf("\trem_host: %s\n", rem_host);*/
1364 if (rem_host
!=NULL
&& !strchr(rem_host
, ':'))
1366 ClearNameValueList(&data
);
1367 SoapError(h
, 402, "Invalid Args");
1370 /*printf("\tAddr check passed.\n");*/
1372 syslog(LOG_INFO
, "%s: (inbound) from [%s]:%hu to [%s]:%hu with protocol %s during %ssec", action
, rem_host
?rem_host
:"anywhere", rport
, int_ip
, iport
, protocol
, leaseTime
);
1374 r
= upnp_add_inboundpinhole(rem_host
, rport
, int_ip
, iport
, protocol
, leaseTime
, &uid
);
1378 case 1: /* success */
1379 bodylen
= snprintf(body
, sizeof(body
), resp
, action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", uid
, action
);
1380 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1382 case -1: /* not permitted */
1383 SoapError(h
, 701, "PinholeSpaceExhausted");
1386 SoapError(h
, 501, "ActionFailed");
1389 ClearNameValueList(&data
);
1393 UpdatePinhole(struct upnphttp
* h
, const char * action
)
1396 static const char resp
[] =
1397 "<u:UpdatePinholeResponse "
1398 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1399 "</u:UpdatePinholeResponse>";
1400 struct NameValueParserData data
;
1401 const char * uid
, * leaseTime
;
1402 char iaddr
[40], proto
[6], lt
[12];
1403 unsigned short iport
;
1405 if(CheckStatus(h
)==0)
1408 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1409 uid
= GetValueFromNameValueList(&data
, "UniqueID");
1410 leaseTime
= GetValueFromNameValueList(&data
, "NewLeaseTime");
1412 if(!uid
|| !leaseTime
|| !atoi(leaseTime
) || atoi(leaseTime
) > 86400)
1414 ClearNameValueList(&data
);
1415 SoapError(h
, 402, "Invalid Args");
1419 // Check that client is not deleting an pinhole he doesn't have access to, because of its public access
1420 n
= upnp_get_pinhole_info(0, 0, iaddr
, &iport
, proto
, uid
, lt
);
1423 if(PinholeVerification(h
, iaddr
, &iport
)==0)
1425 ClearNameValueList(&data
);
1430 syslog(LOG_INFO
, "%s: (inbound) updating lease duration to %s for pinhole with ID: %s", action
, leaseTime
, uid
);
1432 r
= upnp_update_inboundpinhole(uid
, leaseTime
);
1436 if(r
== -4 || r
== -1)
1437 SoapError(h
, 704, "NoSuchEntry");
1439 SoapError(h
, 501, "ActionFailed");
1443 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
1445 ClearNameValueList(&data
);
1449 GetOutboundPinholeTimeout(struct upnphttp
* h
, const char * action
)
1451 if (!ipv6fc_firewall_enabled
)
1453 SoapError(h
, 702, "FirewallDisabed");
1458 static const char resp
[] =
1461 "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1466 struct NameValueParserData data
;
1467 char * int_ip
, * int_port
, * rem_host
, * rem_port
, * protocol
;
1469 unsigned short iport
, rport
;
1471 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1472 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1473 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1474 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1475 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1476 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1478 rport
= (unsigned short)atoi(rem_port
);
1479 iport
= (unsigned short)atoi(int_port
);
1480 proto
= atoi(protocol
);
1482 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
);
1484 r
= upnp_check_outbound_pinhole(proto
, &opt
);
1488 case 1: /* success */
1489 bodylen
= snprintf(body
, sizeof(body
), resp
, action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", opt
, action
);
1490 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1492 case -5: /* Protocol not supported */
1493 SoapError(h
, 705, "ProtocolNotSupported");
1496 SoapError(h
, 501, "ActionFailed");
1498 ClearNameValueList(&data
);
1502 DeletePinhole(struct upnphttp
* h
, const char * action
)
1504 if(CheckStatus(h
)==0)
1508 static const char resp
[] =
1509 "<u:DeletePinholeResponse "
1510 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1511 "</u:DeletePinholeResponse>";
1513 struct NameValueParserData data
;
1515 char iaddr
[40], proto
[6], lt
[12];
1516 unsigned short iport
;
1518 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1519 uid
= GetValueFromNameValueList(&data
, "UniqueID");
1523 ClearNameValueList(&data
);
1524 SoapError(h
, 402, "Invalid Args");
1528 // Check that client is not deleting an pinhole he doesn't have access to, because of its public access
1529 n
= upnp_get_pinhole_info(0, 0, iaddr
, &iport
, proto
, uid
, lt
);
1532 if(PinholeVerification(h
, iaddr
, &iport
)==0)
1534 ClearNameValueList(&data
);
1539 syslog(LOG_INFO
, "%s: (inbound) delete pinhole with ID: %s", action
, uid
);
1541 r
= upnp_delete_inboundpinhole(uid
);
1545 syslog(LOG_INFO
, "%s: (inbound) failed to remove pinhole with ID: %s", action
, uid
);
1547 SoapError(h
, 704, "NoSuchEntry");
1549 SoapError(h
, 501, "ActionFailed");
1553 syslog(LOG_INFO
, "%s: (inbound) pinhole successfully removed", action
);
1554 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
1556 ClearNameValueList(&data
);
1560 CheckPinholeWorking(struct upnphttp
* h
, const char * action
)
1562 if(CheckStatus(h
)==0)
1566 static const char resp
[] =
1569 "<IsWorking>%d</IsWorking>"
1574 struct NameValueParserData data
;
1576 char eaddr
[40], iaddr
[40], proto
[6], lt
[12];
1577 unsigned short eport
, iport
;
1580 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1581 uid
= GetValueFromNameValueList(&data
, "UniqueID");
1585 ClearNameValueList(&data
);
1586 SoapError(h
, 402, "Invalid Args");
1590 // Check that client is not checking a pinhole he doesn't have access to, because of its public access
1591 r
= upnp_get_pinhole_info(eaddr
, eport
, iaddr
, &iport
, proto
, uid
, lt
);
1594 if(PinholeVerification(h
, iaddr
, &iport
)==0)
1596 ClearNameValueList(&data
);
1601 int rulenum_used
, rulenum
= 0;
1602 d
= upnp_check_pinhole_working(uid
, eaddr
, iaddr
, &eport
, &iport
, proto
, &rulenum_used
);
1607 syslog(LOG_INFO
, "%s: rule for ID=%s, no trace found for this pinhole", action
, uid
);
1608 SoapError(h
, 709, "NoPacketSent");
1609 ClearNameValueList(&data
);
1614 // d==-5 not same table // d==-6 not same chain // d==-7 not found a rule but policy traced
1616 syslog(LOG_INFO
, "%s: rule for ID=%s is not working, packet going through %s", action
, uid
, (d
==-5)?"the wrong table":((d
==-6)?"the wrong chain":"a chain policy"));
1617 bodylen
= snprintf(body
, sizeof(body
), resp
,
1618 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1620 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1625 /*check_rule_from_file(uid, &rulenum);*/
1626 if(rulenum_used
== rulenum
)
1629 syslog(LOG_INFO
, "%s: rule for ID=%s is working properly", action
, uid
);
1634 syslog(LOG_INFO
, "%s: rule for ID=%s is not working", action
, uid
);
1636 bodylen
= snprintf(body
, sizeof(body
), resp
,
1637 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1639 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1643 else if(r
== -4 || r
== -1)
1645 SoapError(h
, 704, "NoSuchEntry");
1649 SoapError(h
, 501, "ActionFailed");
1650 ClearNameValueList(&data
);
1653 ClearNameValueList(&data
);
1657 GetPinholePackets(struct upnphttp
* h
, const char * action
)
1659 if(CheckStatus(h
)==0)
1663 static const char resp
[] =
1666 "<PinholePackets>%d</PinholePackets>"
1671 struct NameValueParserData data
;
1673 char iaddr
[40], proto
[6], lt
[12];
1674 unsigned short iport
;
1675 int pinholePackets
= 0;
1677 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1678 uid
= GetValueFromNameValueList(&data
, "UniqueID");
1682 ClearNameValueList(&data
);
1683 SoapError(h
, 402, "Invalid Args");
1687 // Check that client is not getting infos of a pinhole he doesn't have access to, because of its public access
1688 r
= upnp_get_pinhole_info(0, 0, iaddr
, &iport
, proto
, uid
, lt
);
1691 if(PinholeVerification(h
, iaddr
, &iport
)==0)
1693 ClearNameValueList(&data
);
1698 n
= upnp_get_pinhole_packets(uid
, &pinholePackets
);
1701 bodylen
= snprintf(body
, sizeof(body
), resp
,
1702 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1703 pinholePackets
, action
);
1704 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1706 else if(r
== -4 || r
== -1)
1708 SoapError(h
, 704, "NoSuchEntry");
1712 SoapError(h
, 501, "ActionFailed");
1713 ClearNameValueList(&data
);
1716 ClearNameValueList(&data
);
1721 /* Windows XP as client send the following requests :
1722 * GetConnectionTypeInfo
1724 * ? GetTotalBytesSent - WANCommonInterfaceConfig
1725 * ? GetTotalBytesReceived - idem
1726 * ? GetTotalPacketsSent - idem
1727 * ? GetTotalPacketsReceived - idem
1728 * GetCommonLinkProperties - idem
1729 * GetStatusInfo - WANIPConnection
1730 * GetExternalIPAddress
1731 * QueryStateVariable / ConnectionStatus!
1735 const char * methodName
;
1736 void (*methodImpl
)(struct upnphttp
*, const char *);
1740 /* WANCommonInterfaceConfig */
1741 { "QueryStateVariable", QueryStateVariable
},
1742 { "GetTotalBytesSent", GetTotalBytesSent
},
1743 { "GetTotalBytesReceived", GetTotalBytesReceived
},
1744 { "GetTotalPacketsSent", GetTotalPacketsSent
},
1745 { "GetTotalPacketsReceived", GetTotalPacketsReceived
},
1746 { "GetCommonLinkProperties", GetCommonLinkProperties
},
1747 { "GetStatusInfo", GetStatusInfo
},
1748 /* WANIPConnection */
1749 { "GetConnectionTypeInfo", GetConnectionTypeInfo
},
1750 { "GetNATRSIPStatus", GetNATRSIPStatus
},
1751 { "GetExternalIPAddress", GetExternalIPAddress
},
1752 { "AddPortMapping", AddPortMapping
},
1753 { "DeletePortMapping", DeletePortMapping
},
1754 { "GetGenericPortMappingEntry", GetGenericPortMappingEntry
},
1755 { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry
},
1756 /* Required in WANIPConnection:2 */
1757 { "SetConnectionType", SetConnectionType
},
1758 { "RequestConnection", RequestConnection
},
1759 { "ForceTermination", ForceTermination
},
1760 { "AddAnyPortMapping", AddAnyPortMapping
},
1761 { "DeletePortMappingRange", DeletePortMappingRange
},
1762 { "GetListOfPortMappings", GetListOfPortMappings
},
1763 #ifdef ENABLE_L3F_SERVICE
1764 /* Layer3Forwarding */
1765 { "SetDefaultConnectionService", SetDefaultConnectionService
},
1766 { "GetDefaultConnectionService", GetDefaultConnectionService
},
1768 #ifdef ENABLE_6FC_SERVICE
1769 /* WANIPv6FirewallControl */
1770 { "GetFirewallStatus", GetFirewallStatus
},
1771 { "AddPinhole", AddPinhole
},
1772 { "UpdatePinhole", UpdatePinhole
},
1773 { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout
},
1774 { "DeletePinhole", DeletePinhole
},
1775 { "CheckPinholeWorking", CheckPinholeWorking
},
1776 { "GetPinholePackets", GetPinholePackets
},
1782 ExecuteSoapAction(struct upnphttp
* h
, const char * action
, int n
)
1786 int i
, len
, methodlen
;
1789 p
= strchr(action
, '#');
1794 p2
= strchr(p
, '"');
1798 methodlen
= n
- (p
- action
);
1799 /*syslog(LOG_DEBUG, "SoapMethod: %.*s", methodlen, p);*/
1800 while(soapMethods
[i
].methodName
)
1802 len
= strlen(soapMethods
[i
].methodName
);
1803 if(strncmp(p
, soapMethods
[i
].methodName
, len
) == 0)
1805 soapMethods
[i
].methodImpl(h
, soapMethods
[i
].methodName
);
1811 syslog(LOG_NOTICE
, "SoapMethod: Unknown: %.*s", methodlen
, p
);
1814 SoapError(h
, 401, "Invalid Action");
1819 * errorCode errorDescription Description
1820 * -------- ---------------- -----------
1821 * 401 Invalid Action No action by that name at this service.
1822 * 402 Invalid Args Could be any of the following: not enough in args,
1823 * too many in args, no in arg by that name,
1824 * one or more in args are of the wrong data type.
1825 * 403 Out of Sync Out of synchronization.
1826 * 501 Action Failed May be returned in current state of service
1827 * prevents invoking that action.
1828 * 600-699 TBD Common action errors. Defined by UPnP Forum
1829 * Technical Committee.
1830 * 700-799 TBD Action-specific errors for standard actions.
1831 * Defined by UPnP Forum working committee.
1832 * 800-899 TBD Action-specific errors for non-standard actions.
1833 * Defined by UPnP vendor.
1836 SoapError(struct upnphttp
* h
, int errCode
, const char * errDesc
)
1838 static const char resp
[] =
1840 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
1841 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
1844 "<faultcode>s:Client</faultcode>"
1845 "<faultstring>UPnPError</faultstring>"
1847 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
1848 "<errorCode>%d</errorCode>"
1849 "<errorDescription>%s</errorDescription>"
1859 syslog(LOG_INFO
, "Returning UPnPError %d: %s", errCode
, errDesc
);
1860 bodylen
= snprintf(body
, sizeof(body
), resp
, errCode
, errDesc
);
1861 BuildResp2_upnphttp(h
, 500, "Internal Server Error", body
, bodylen
);
1862 SendResp_upnphttp(h
);
1863 CloseSocket_upnphttp(h
);