1 /* $Id: upnpsoap.c,v 1.87 2011/07/15 07:48:26 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;
60 GetConnectionTypeInfo(struct upnphttp
* h
, const char * action
)
62 static const char resp
[] =
63 "<u:GetConnectionTypeInfoResponse "
64 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
65 "<NewConnectionType>IP_Routed</NewConnectionType>"
66 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
67 "</u:GetConnectionTypeInfoResponse>";
68 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
72 GetTotalBytesSent(struct upnphttp
* h
, const char * action
)
76 static const char resp
[] =
79 "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
86 r
= getifstats(ext_if_name
, &data
);
87 bodylen
= snprintf(body
, sizeof(body
), resp
,
88 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
89 r
<0?0:data
.obytes
, action
);
90 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
94 GetTotalBytesReceived(struct upnphttp
* h
, const char * action
)
98 static const char resp
[] =
101 "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
108 r
= getifstats(ext_if_name
, &data
);
109 bodylen
= snprintf(body
, sizeof(body
), resp
,
110 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
111 r
<0?0:data
.ibytes
, action
);
112 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
116 GetTotalPacketsSent(struct upnphttp
* h
, const char * action
)
120 static const char resp
[] =
123 "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
130 r
= getifstats(ext_if_name
, &data
);
131 bodylen
= snprintf(body
, sizeof(body
), resp
,
132 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
133 r
<0?0:data
.opackets
, action
);
134 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
138 GetTotalPacketsReceived(struct upnphttp
* h
, const char * action
)
142 static const char resp
[] =
145 "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
152 r
= getifstats(ext_if_name
, &data
);
153 bodylen
= snprintf(body
, sizeof(body
), resp
,
154 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
155 r
<0?0:data
.ipackets
, action
);
156 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
160 GetCommonLinkProperties(struct upnphttp
* h
, const char * action
)
162 /* WANAccessType : set depending on the hardware :
163 * DSL, POTS (plain old Telephone service), Cable, Ethernet */
164 static const char resp
[] =
167 /*"<NewWANAccessType>DSL</NewWANAccessType>"*/
168 "<NewWANAccessType>Cable</NewWANAccessType>"
169 "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
170 "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
171 "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
177 const char * status
= "Up"; /* Up, Down (Required),
178 * Initializing, Unavailable (Optional) */
179 char ext_ip_addr
[INET_ADDRSTRLEN
];
181 if((downstream_bitrate
== 0) || (upstream_bitrate
== 0))
183 if(getifstats(ext_if_name
, &data
) >= 0)
185 if(downstream_bitrate
== 0) downstream_bitrate
= data
.baudrate
;
186 if(upstream_bitrate
== 0) upstream_bitrate
= data
.baudrate
;
189 if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
) < 0) {
192 bodylen
= snprintf(body
, sizeof(body
), resp
,
193 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
194 upstream_bitrate
, downstream_bitrate
,
196 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
200 GetStatusInfo(struct upnphttp
* h
, const char * action
)
202 static const char resp
[] =
205 "<NewConnectionStatus>%s</NewConnectionStatus>"
206 "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
207 "<NewUptime>%ld</NewUptime>"
214 /* ConnectionStatus possible values :
215 * Unconfigured, Connecting, Connected, PendingDisconnect,
216 * Disconnecting, Disconnected */
218 status
= get_wan_connection_status_str(ext_if_name
);
219 uptime
= (time(NULL
) - startup_time
);
220 bodylen
= snprintf(body
, sizeof(body
), resp
,
221 action
, SERVICE_TYPE_WANIPC
,
222 status
, (long)uptime
, action
);
223 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
227 GetNATRSIPStatus(struct upnphttp
* h
, const char * action
)
229 static const char resp
[] =
230 "<u:GetNATRSIPStatusResponse "
231 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
232 "<NewRSIPAvailable>0</NewRSIPAvailable>"
233 "<NewNATEnabled>1</NewNATEnabled>"
234 "</u:GetNATRSIPStatusResponse>";
235 /* 2.2.9. RSIPAvailable
236 * This variable indicates if Realm-specific IP (RSIP) is available
237 * as a feature on the InternetGatewayDevice. RSIP is being defined
238 * in the NAT working group in the IETF to allow host-NATing using
239 * a standard set of message exchanges. It also allows end-to-end
240 * applications that otherwise break if NAT is introduced
241 * (e.g. IPsec-based VPNs).
242 * A gateway that does not support RSIP should set this variable to 0. */
243 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
247 GetExternalIPAddress(struct upnphttp
* h
, const char * action
)
249 static const char resp
[] =
252 "<NewExternalIPAddress>%s</NewExternalIPAddress>"
257 char ext_ip_addr
[INET_ADDRSTRLEN
];
258 /* Does that method need to work with IPv6 ?
259 * There is usually no NAT with IPv6 */
261 #ifndef MULTIPLE_EXTERNAL_IP
264 strncpy(ext_ip_addr
, use_ext_ip_addr
, INET_ADDRSTRLEN
);
266 else if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
) < 0)
268 syslog(LOG_ERR
, "Failed to get ip address for interface %s",
270 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
273 struct lan_addr_s
* lan_addr
;
274 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
275 for(lan_addr
= lan_addrs
.lh_first
; lan_addr
!= NULL
; lan_addr
= lan_addr
->list
.le_next
)
277 if( (h
->clientaddr
.s_addr
& lan_addr
->mask
.s_addr
)
278 == (lan_addr
->addr
.s_addr
& lan_addr
->mask
.s_addr
))
280 strncpy(ext_ip_addr
, lan_addr
->ext_ip_str
, INET_ADDRSTRLEN
);
285 bodylen
= snprintf(body
, sizeof(body
), resp
,
286 action
, SERVICE_TYPE_WANIPC
,
287 ext_ip_addr
, action
);
288 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
291 /* AddPortMapping method of WANIPConnection Service
292 * Ignored argument : NewEnabled */
294 AddPortMapping(struct upnphttp
* h
, const char * action
)
298 static const char resp
[] =
299 "<u:AddPortMappingResponse "
300 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\"/>";
302 struct NameValueParserData data
;
303 char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
304 char * leaseduration_str
;
305 unsigned int leaseduration
;
307 unsigned short iport
, eport
;
309 struct hostent
*hp
; /* getbyhostname() */
310 char ** ptr
; /* getbyhostname() */
311 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
313 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
314 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
317 ClearNameValueList(&data
);
318 SoapError(h
, 402, "Invalid Args");
322 /* IGD 2 MUST support both wildcard and specific IP address values
323 * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
324 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
325 #ifndef SUPPORT_REMOTEHOST
327 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
329 ClearNameValueList(&data
);
330 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
336 /* if ip not valid assume hostname and convert */
337 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
339 hp
= gethostbyname(int_ip
);
340 if(hp
&& hp
->h_addrtype
== AF_INET
)
342 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
344 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
345 result_ip
= *((struct in_addr
*) *ptr
);
346 /* TODO : deal with more than one ip per hostname */
352 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
353 ClearNameValueList(&data
);
354 SoapError(h
, 402, "Invalid Args");
359 /* check if NewInternalAddress is the client address */
360 if(GETFLAG(SECUREMODEMASK
))
362 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
364 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
365 inet_ntoa(h
->clientaddr
), int_ip
);
366 ClearNameValueList(&data
);
367 SoapError(h
, 718, "ConflictInMappingEntry");
372 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
373 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
374 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
375 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
376 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
378 if (!int_port
|| !ext_port
|| !protocol
)
380 ClearNameValueList(&data
);
381 SoapError(h
, 402, "Invalid Args");
385 eport
= (unsigned short)atoi(ext_port
);
386 iport
= (unsigned short)atoi(int_port
);
388 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
390 /* PortMappingLeaseDuration can be either a value between 1 and
391 * 604800 seconds or the zero value (for infinite lease time).
392 * Note that an infinite lease time can be only set by out-of-band
393 * mechanisms like WWW-administration, remote management or local
395 * If a control point uses the value 0 to indicate an infinite lease
396 * time mapping, it is REQUIRED that gateway uses the maximum value
397 * instead (e.g. 604800 seconds) */
398 if(leaseduration
== 0 || leaseduration
> 604800)
399 leaseduration
= 604800;
402 syslog(LOG_INFO
, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
403 action
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
, r_host
);
405 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
407 ClearNameValueList(&data
);
409 /* possible error codes for AddPortMapping :
411 * 501 - Action Failed
412 * 715 - Wildcard not permited in SrcAddr
413 * 716 - Wildcard not permited in ExtPort
414 * 718 - ConflictInMappingEntry
415 * 724 - SamePortValuesRequired (deprecated in IGD v2)
416 * 725 - OnlyPermanentLeasesSupported
417 The NAT implementation only supports permanent lease times on
418 port mappings (deprecated in IGD v2)
419 * 726 - RemoteHostOnlySupportsWildcard
420 RemoteHost must be a wildcard and cannot be a specific IP
421 address or DNS name (deprecated in IGD v2)
422 * 727 - ExternalPortOnlySupportsWildcard
423 ExternalPort must be a wildcard and cannot be a specific port
424 value (deprecated in IGD v2)
425 * 728 - NoPortMapsAvailable
426 There are not enough free prots available to complete the mapping
428 * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
431 case 0: /* success */
432 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
434 case -2: /* already redirected */
435 case -3: /* not permitted */
436 SoapError(h
, 718, "ConflictInMappingEntry");
439 SoapError(h
, 501, "ActionFailed");
443 /* AddAnyPortMapping was added in WANIPConnection v2 */
445 AddAnyPortMapping(struct upnphttp
* h
, const char * action
)
448 static const char resp
[] =
451 "<NewReservedPort>%hu</NewReservedPort>"
457 struct NameValueParserData data
;
458 const char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
460 unsigned short iport
, eport
;
461 const char * leaseduration_str
;
462 unsigned int leaseduration
;
464 struct hostent
*hp
; /* getbyhostname() */
465 char ** ptr
; /* getbyhostname() */
466 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
468 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
469 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
470 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
471 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
472 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
473 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
475 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
476 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
478 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
479 if(leaseduration
== 0)
480 leaseduration
= 604800;
482 eport
= (unsigned short)atoi(ext_port
);
483 iport
= (unsigned short)atoi(int_port
);
487 ClearNameValueList(&data
);
488 SoapError(h
, 402, "Invalid Args");
491 #ifndef SUPPORT_REMOTEHOST
493 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
495 ClearNameValueList(&data
);
496 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
502 /* if ip not valid assume hostname and convert */
503 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
505 hp
= gethostbyname(int_ip
);
506 if(hp
&& hp
->h_addrtype
== AF_INET
)
508 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
510 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
511 result_ip
= *((struct in_addr
*) *ptr
);
512 /* TODO : deal with more than one ip per hostname */
518 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
519 ClearNameValueList(&data
);
520 SoapError(h
, 402, "Invalid Args");
525 /* check if NewInternalAddress is the client address */
526 if(GETFLAG(SECUREMODEMASK
))
528 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
530 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
531 inet_ntoa(h
->clientaddr
), int_ip
);
532 ClearNameValueList(&data
);
533 SoapError(h
, 606, "Action not authorized");
538 /* TODO : accept a different external port
539 * have some smart strategy to choose the port */
541 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
542 if(r
==-2 && eport
< 65535) {
549 ClearNameValueList(&data
);
553 case 0: /* success */
554 bodylen
= snprintf(body
, sizeof(body
), resp
,
555 action
, SERVICE_TYPE_WANIPC
,
557 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
559 case -2: /* already redirected */
560 SoapError(h
, 718, "ConflictInMappingEntry");
562 case -3: /* not permitted */
563 SoapError(h
, 606, "Action not authorized");
566 SoapError(h
, 501, "ActionFailed");
571 GetSpecificPortMappingEntry(struct upnphttp
* h
, const char * action
)
575 static const char resp
[] =
578 "<NewInternalPort>%u</NewInternalPort>"
579 "<NewInternalClient>%s</NewInternalClient>"
580 "<NewEnabled>1</NewEnabled>"
581 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
582 "<NewLeaseDuration>%u</NewLeaseDuration>"
587 struct NameValueParserData data
;
588 const char * r_host
, * ext_port
, * protocol
;
589 unsigned short eport
, iport
;
592 unsigned int leaseduration
= 0;
594 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
595 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
596 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
597 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
599 if(!ext_port
|| !protocol
)
601 ClearNameValueList(&data
);
602 SoapError(h
, 402, "Invalid Args");
605 #ifndef SUPPORT_REMOTEHOST
607 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
609 ClearNameValueList(&data
);
610 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
616 eport
= (unsigned short)atoi(ext_port
);
618 /* TODO : add r_host as an input parameter ...
619 * We prevent several Port Mapping with same external port
620 * but different remoteHost to be set up, so that is not
622 r
= upnp_get_redirection_infos(eport
, protocol
, &iport
,
623 int_ip
, sizeof(int_ip
),
630 SoapError(h
, 714, "NoSuchEntryInArray");
634 syslog(LOG_INFO
, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
636 r_host
, ext_port
, protocol
, int_ip
, (unsigned int)iport
, desc
);
637 bodylen
= snprintf(body
, sizeof(body
), resp
,
638 action
, SERVICE_TYPE_WANIPC
,
639 (unsigned int)iport
, int_ip
, desc
, leaseduration
,
641 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
644 ClearNameValueList(&data
);
648 DeletePortMapping(struct upnphttp
* h
, const char * action
)
652 static const char resp
[] =
653 "<u:DeletePortMappingResponse "
654 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
655 "</u:DeletePortMappingResponse>";
657 struct NameValueParserData data
;
658 const char * r_host
, * ext_port
, * protocol
;
659 unsigned short eport
;
661 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
662 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
663 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
664 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
666 if(!ext_port
|| !protocol
)
668 ClearNameValueList(&data
);
669 SoapError(h
, 402, "Invalid Args");
672 #ifndef SUPPORT_REMOTEHOST
674 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
676 ClearNameValueList(&data
);
677 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
683 eport
= (unsigned short)atoi(ext_port
);
685 /* TODO : if in secure mode, check the IP
686 * Removing a redirection is not a security threat,
687 * just an annoyance for the user using it. So this is not
690 syslog(LOG_INFO
, "%s: external port: %hu, protocol: %s",
691 action
, eport
, protocol
);
693 r
= upnp_delete_redirection(eport
, protocol
);
697 SoapError(h
, 714, "NoSuchEntryInArray");
701 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
704 ClearNameValueList(&data
);
707 /* DeletePortMappingRange was added in IGD spec v2 */
709 DeletePortMappingRange(struct upnphttp
* h
, const char * action
)
712 static const char resp
[] =
713 "<u:DeletePortMappingRangeResponse "
714 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
715 "</u:DeletePortMappingRangeResponse>";
716 struct NameValueParserData data
;
717 const char * protocol
;
718 unsigned short startport
, endport
;
720 unsigned short * port_list
;
721 unsigned int i
, number
= 0;
723 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
724 startport
= (unsigned short)atoi(GetValueFromNameValueList(&data
, "NewStartPort"));
725 endport
= (unsigned short)atoi(GetValueFromNameValueList(&data
, "NewEndPort"));
726 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
727 manage
= atoi(GetValueFromNameValueList(&data
, "NewManage"));
730 606 - Action not authorized
731 730 - PortMappingNotFound
732 733 - InconsistentParameter
734 if(startport
> endport
)
736 SoapError(h
, 733, "InconsistentParameter");
737 ClearNameValueList(&data
);
741 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
743 for(i
= 0; i
< number
; i
++)
745 r
= upnp_delete_redirection(port_list
[i
], protocol
);
746 /* TODO : check return value for errors */
749 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
751 ClearNameValueList(&data
);
755 GetGenericPortMappingEntry(struct upnphttp
* h
, const char * action
)
759 static const char resp
[] =
762 "<NewRemoteHost>%s</NewRemoteHost>"
763 "<NewExternalPort>%u</NewExternalPort>"
764 "<NewProtocol>%s</NewProtocol>"
765 "<NewInternalPort>%u</NewInternalPort>"
766 "<NewInternalClient>%s</NewInternalClient>"
767 "<NewEnabled>1</NewEnabled>"
768 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
769 "<NewLeaseDuration>%u</NewLeaseDuration>"
773 unsigned short eport
, iport
;
774 const char * m_index
;
775 char protocol
[4], iaddr
[32];
778 unsigned int leaseduration
= 0;
779 struct NameValueParserData data
;
781 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
782 m_index
= GetValueFromNameValueList(&data
, "NewPortMappingIndex");
786 ClearNameValueList(&data
);
787 SoapError(h
, 402, "Invalid Args");
791 index
= (int)atoi(m_index
);
793 syslog(LOG_INFO
, "%s: index=%d", action
, index
);
796 r
= upnp_get_redirection_infos_by_index(index
, &eport
, protocol
, &iport
,
797 iaddr
, sizeof(iaddr
),
799 rhost
, sizeof(rhost
),
804 SoapError(h
, 713, "SpecifiedArrayIndexInvalid");
810 bodylen
= snprintf(body
, sizeof(body
), resp
,
811 action
, SERVICE_TYPE_WANIPC
, rhost
,
812 (unsigned int)eport
, protocol
, (unsigned int)iport
, iaddr
, desc
,
813 leaseduration
, action
);
814 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
817 ClearNameValueList(&data
);
820 /* GetListOfPortMappings was added in the IGD v2 specification */
822 GetListOfPortMappings(struct upnphttp
* h
, const char * action
)
824 static const char resp_start
[] =
827 "<NewPortListing><![CDATA[";
828 static const char resp_end
[] =
829 "]]></NewPortListing>"
832 static const char list_start
[] =
833 "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
834 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
835 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
836 " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
837 static const char list_end
[] =
838 "</p:PortMappingList>";
840 static const char entry
[] =
841 "<p:PortMappingEntry>"
842 "<p:NewRemoteHost>%s</p:NewRemoteHost>"
843 "<p:NewExternalPort>%hu</p:NewExternalPort>"
844 "<p:NewProtocol>%s</p:NewProtocol>"
845 "<p:NewInternalPort>%hu</p:NewInternalPort>"
846 "<p:NewInternalClient>%s</p:NewInternalClient>"
847 "<p:NewEnabled>1</p:NewEnabled>"
848 "<p:NewDescription>%s</p:NewDescription>"
849 "<p:NewLeaseTime>%u</p:NewLeaseTime>"
850 "</p:PortMappingEntry>";
857 unsigned short iport
;
861 unsigned int leaseduration
= 0;
863 struct NameValueParserData data
;
864 unsigned short startport
, endport
;
865 const char * protocol
;
868 unsigned short * port_list
;
869 unsigned int i
, list_size
= 0;
871 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
872 startport
= (unsigned short)atoi(GetValueFromNameValueList(&data
, "NewStartPort"));
873 endport
= (unsigned short)atoi(GetValueFromNameValueList(&data
, "NewEndPort"));
874 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
875 manage
= atoi(GetValueFromNameValueList(&data
, "NewManage"));
876 number
= atoi(GetValueFromNameValueList(&data
, "NewNumberOfPorts"));
877 if(number
== 0) number
= 1000; /* return up to 1000 mappings by default */
879 if(startport
> endport
)
881 SoapError(h
, 733, "InconsistentParameter");
882 ClearNameValueList(&data
);
886 build the PortMappingList xml document :
888 <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
889 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
890 xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
891 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
893 <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
894 <p:NewExternalPort>2345</p:NewExternalPort>
895 <p:NewProtocol>TCP</p:NewProtocol>
896 <p:NewInternalPort>2345</p:NewInternalPort>
897 <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
898 <p:NewEnabled>1</p:NewEnabled>
899 <p:NewDescription>dooom</p:NewDescription>
900 <p:NewLeaseTime>345</p:NewLeaseTime>
901 </p:PortMappingEntry>
905 body
= malloc(bodyalloc
);
908 ClearNameValueList(&data
);
909 SoapError(h
, 501, "ActionFailed");
912 bodylen
= snprintf(body
, bodyalloc
, resp_start
,
913 action
, SERVICE_TYPE_WANIPC
);
914 memcpy(body
+bodylen
, list_start
, sizeof(list_start
));
915 bodylen
+= (sizeof(list_start
) - 1);
917 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
918 protocol
, &list_size
);
919 /* loop through port mappings */
920 for(i
= 0; number
> 0 && i
< list_size
; i
++)
922 /* have a margin of 1024 bytes to store the new entry */
923 if(bodylen
+ 1024 > bodyalloc
)
926 body
= realloc(body
, bodyalloc
);
929 ClearNameValueList(&data
);
930 SoapError(h
, 501, "ActionFailed");
936 r
= upnp_get_redirection_infos(port_list
[i
], protocol
, &iport
,
937 int_ip
, sizeof(int_ip
),
939 rhost
, sizeof(rhost
),
943 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, entry
,
944 rhost
, port_list
[i
], protocol
,
945 iport
, int_ip
, desc
, leaseduration
);
952 memcpy(body
+bodylen
, list_end
, sizeof(list_end
));
953 bodylen
+= (sizeof(list_end
) - 1);
954 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, resp_end
,
956 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
959 ClearNameValueList(&data
);
962 #ifdef ENABLE_L3F_SERVICE
964 SetDefaultConnectionService(struct upnphttp
* h
, const char * action
)
966 static const char resp
[] =
967 "<u:SetDefaultConnectionServiceResponse "
968 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
969 "</u:SetDefaultConnectionServiceResponse>";
970 struct NameValueParserData data
;
972 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
973 p
= GetValueFromNameValueList(&data
, "NewDefaultConnectionService");
975 syslog(LOG_INFO
, "%s(%s) : Ignored", action
, p
);
977 ClearNameValueList(&data
);
978 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
982 GetDefaultConnectionService(struct upnphttp
* h
, const char * action
)
984 static const char resp
[] =
986 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
987 "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
988 SERVICE_ID_WANIPC
"</NewDefaultConnectionService>"
990 /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
991 * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
992 * urn:upnp-org:serviceId:WANPPPConn1 */
996 bodylen
= snprintf(body
, sizeof(body
), resp
,
997 action
, uuidvalue
, action
);
998 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1002 /* Added for compliance with WANIPConnection v2 */
1004 SetConnectionType(struct upnphttp
* h
, const char * action
)
1006 const char * connection_type
;
1007 struct NameValueParserData data
;
1009 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1010 connection_type
= GetValueFromNameValueList(&data
, "NewConnectionType");
1011 /* Unconfigured, IP_Routed, IP_Bridged */
1012 ClearNameValueList(&data
);
1013 /* always return a ReadOnly error */
1014 SoapError(h
, 731, "ReadOnly");
1017 /* Added for compliance with WANIPConnection v2 */
1019 RequestConnection(struct upnphttp
* h
, const char * action
)
1021 SoapError(h
, 606, "Action not authorized");
1024 /* Added for compliance with WANIPConnection v2 */
1026 ForceTermination(struct upnphttp
* h
, const char * action
)
1028 SoapError(h
, 606, "Action not authorized");
1032 If a control point calls QueryStateVariable on a state variable that is not
1033 buffered in memory within (or otherwise available from) the service,
1034 the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1036 QueryStateVariable remains useful as a limited test tool but may not be
1037 part of some future versions of UPnP.
1040 QueryStateVariable(struct upnphttp
* h
, const char * action
)
1042 static const char resp
[] =
1045 "<return>%s</return>"
1050 struct NameValueParserData data
;
1051 const char * var_name
;
1053 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1054 /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1055 /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1056 var_name
= GetValueFromNameValueList(&data
, "varName");
1058 /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1062 SoapError(h
, 402, "Invalid Args");
1064 else if(strcmp(var_name
, "ConnectionStatus") == 0)
1066 const char * status
;
1068 status
= get_wan_connection_status_str(ext_if_name
);
1069 bodylen
= snprintf(body
, sizeof(body
), resp
,
1070 action
, "urn:schemas-upnp-org:control-1-0",
1072 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1076 else if(strcmp(var_name
, "ConnectionType") == 0)
1078 bodylen
= snprintf(body
, sizeof(body
), resp
, "IP_Routed");
1079 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1081 else if(strcmp(var_name
, "LastConnectionError") == 0)
1083 bodylen
= snprintf(body
, sizeof(body
), resp
, "ERROR_NONE");
1084 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1087 else if(strcmp(var_name
, "PortMappingNumberOfEntries") == 0)
1090 snprintf(strn
, sizeof(strn
), "%i",
1091 upnp_get_portmapping_number_of_entries());
1092 bodylen
= snprintf(body
, sizeof(body
), resp
,
1093 action
, "urn:schemas-upnp-org:control-1-0",
1095 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1099 syslog(LOG_NOTICE
, "%s: Unknown: %s", action
, var_name
?var_name
:"");
1100 SoapError(h
, 404, "Invalid Var");
1103 ClearNameValueList(&data
);
1106 #ifdef ENABLE_6FC_SERVICE
1108 #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1110 /* WANIPv6FirewallControl actions */
1112 GetFirewallStatus(struct upnphttp
* h
, const char * action
)
1114 static const char resp
[] =
1117 "<FirewallEnabled>%d</FirewallEnabled>"
1118 "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1124 bodylen
= snprintf(body
, sizeof(body
), resp
,
1125 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1126 ipv6fc_firewall_enabled
, ipv6fc_inbound_pinhole_allowed
, action
);
1127 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1131 CheckStatus(struct upnphttp
* h
)
1133 if (!ipv6fc_firewall_enabled
)
1135 SoapError(h
, 702, "FirewallDisabed");
1138 else if(!ipv6fc_inbound_pinhole_allowed
)
1140 SoapError(h
, 703, "InboundPinholeNotAllowed");
1148 DataVerification(struct upnphttp
* h
, char * int_ip
, unsigned short * int_port
, const char * protocol
, char * leaseTime
)
1151 // ** Internal IP can't be wildcarded
1154 SoapError(h
, 708, "WildCardNotPermittedInSrcIP");
1158 if (!strchr(int_ip
, ':'))
1160 SoapError(h
, 402, "Invalid Args");
1164 // ** Internal port can't be wilcarded.
1165 // printf("\tint_port: *%d*\n", *int_port);
1168 SoapError(h
, 706, "InternalPortWilcardingNotAllowed");
1172 // ** Protocol can't be wilcarded and can't be an unknown port (here deal with only UDP, TCP, UDPLITE)
1173 // printf("\tprotocol: *%s*\n", protocol);
1174 if (atoi(protocol
) == 65535)
1176 SoapError(h
, 707, "ProtocolWilcardingNotAllowed");
1179 else if (atoi(protocol
) != IPPROTO_UDP
1180 && atoi(protocol
) != IPPROTO_TCP
1181 #ifdef IPPROTO_UDPITE
1182 && atoi(protocol
) != IPPROTO_UDPLITE
1186 SoapError(h
, 705, "ProtocolNotSupported");
1190 // ** Lease Time can't be wilcarded nor >86400.
1191 // printf("\tlease time: %s\n", leaseTime);
1192 if(!leaseTime
|| !atoi(leaseTime
) || atoi(leaseTime
)>86400)
1194 /* lease duration is never infinite, nor wilcarded. In this case, use default value */
1195 syslog(LOG_WARNING
, "LeaseTime=%s not supported, (ip=%s)", leaseTime
, int_ip
);
1196 SoapError(h
, 402, "Invalid Args");
1204 static int connecthostport(const char * host
, unsigned short port
, char * result
)
1207 char hostname
[INET6_ADDRSTRLEN
];
1208 char port_str
[8], ifname
[8], tmp
[4];
1209 struct addrinfo
*ai
, *p
;
1210 struct addrinfo hints
;
1212 memset(&hints
, 0, sizeof(hints
));
1213 /* hints.ai_flags = AI_ADDRCONFIG; */
1214 #ifdef AI_NUMERICSERV
1215 hints
.ai_flags
= AI_NUMERICSERV
;
1217 hints
.ai_socktype
= SOCK_STREAM
;
1218 hints
.ai_family
= AF_UNSPEC
; /* AF_INET, AF_INET6 or AF_UNSPEC */
1219 /* hints.ai_protocol = IPPROTO_TCP; */
1220 snprintf(port_str
, sizeof(port_str
), "%hu", port
);
1221 strcpy(hostname
, host
);
1222 if(!strncmp(host
, "fe80", 4))
1224 printf("Using an linklocal address\n");
1225 strcpy(ifname
, "%");
1226 snprintf(tmp
, sizeof(tmp
), "%d", linklocal_index
);
1227 strcat(ifname
, tmp
);
1228 strcat(hostname
, ifname
);
1229 printf("host: %s\n", hostname
);
1231 n
= getaddrinfo(hostname
, port_str
, &hints
, &ai
);
1234 fprintf(stderr
, "getaddrinfo() error : %s\n", gai_strerror(n
));
1238 for(p
= ai
; p
; p
= p
->ai_next
)
1242 char tmp_service
[256];
1243 printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1244 p
->ai_family
, p
->ai_socktype
, p
->ai_protocol
, p
->ai_addrlen
);
1245 getnameinfo(p
->ai_addr
, p
->ai_addrlen
, tmp_host
, sizeof(tmp_host
),
1246 tmp_service
, sizeof(tmp_service
),
1247 NI_NUMERICHOST
| NI_NUMERICSERV
);
1248 printf(" host=%s service=%s\n", tmp_host
, tmp_service
);
1250 inet_ntop(AF_INET6
, &(((struct sockaddr_in6
*)p
->ai_addr
)->sin6_addr
), result
, INET6_ADDRSTRLEN
);
1257 /* Check the security policy right */
1259 PinholeVerification(struct upnphttp
* h
, char * int_ip
, unsigned short * int_port
)
1262 /* Pinhole InternalClient address must correspond to the action sender */
1263 syslog(LOG_INFO
, "Checking internal IP@ and port (Security policy purpose)");
1264 char senderAddr
[INET6_ADDRSTRLEN
]="";
1265 //char str[INET6_ADDRSTRLEN]="";
1266 //connecthostport(int_ip, *int_port, str);
1267 //printf("int_ip: %s / str: %s\n", int_ip, str);
1269 struct addrinfo hints
, *ai
, *p
;
1270 struct in6_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */ //IPv6 Modification
1272 hints
.ai_socktype
= SOCK_STREAM
;
1273 hints
.ai_family
= AF_UNSPEC
;
1275 /* if ip not valid assume hostname and convert */
1276 if (inet_pton(AF_INET6
, int_ip
, &result_ip
) <= 0) //IPv6 Modification
1279 n
= getaddrinfo(int_ip
, NULL
, &hints
, &ai
);//hp = gethostbyname(int_ip);
1280 if(!n
&& ai
->ai_family
== AF_INET6
) //IPv6 Modification
1282 for(p
= ai
; p
; p
= p
->ai_next
)//ptr = hp->h_addr_list; ptr && *ptr; ptr++)
1284 inet_ntop(AF_INET6
, (struct in6_addr
*) p
, int_ip
, sizeof(struct in6_addr
)); ///IPv6 Modification
1285 result_ip
= *((struct in6_addr
*) p
);
1286 fprintf(stderr
, "upnpsoap / AddPinhole: assuming int addr = %s", int_ip
);
1287 /* TODO : deal with more than one ip per hostname */
1293 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
1294 SoapError(h
, 402, "Invalid Args");
1300 if(inet_ntop(AF_INET6
, &(h
->clientaddr_v6
), senderAddr
, INET6_ADDRSTRLEN
)<=0)
1302 //printf("Failed to inet_ntop\n");
1303 syslog(LOG_ERR
, "inet_ntop: %m");
1306 printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr
, int_ip
);
1308 if(strcmp(senderAddr
, int_ip
) != 0)
1309 if(h
->clientaddr_v6
.s6_addr
!= result_ip
.s6_addr
)
1311 syslog(LOG_INFO
, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1312 senderAddr
, int_ip
);
1313 SoapError(h
, 606, "Action not authorized");
1317 /* Pinhole InternalPort must be greater than or equal to 1024 */
1318 if (*int_port
< 1024)
1320 syslog(LOG_INFO
, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1322 SoapError(h
, 606, "Action not authorized");
1329 AddPinhole(struct upnphttp
* h
, const char * action
)
1332 static const char resp
[] =
1335 "<UniqueID>%d</UniqueID>"
1339 struct NameValueParserData data
;
1340 char * rem_host
, * rem_port
, * int_ip
, * int_port
, * protocol
, * leaseTime
;
1342 unsigned short iport
, rport
;
1344 if(CheckStatus(h
)==0)
1347 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1348 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1349 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1350 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1351 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1352 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1353 leaseTime
= GetValueFromNameValueList(&data
, "LeaseTime");
1355 rport
= (unsigned short)atoi(rem_port
);
1356 iport
= (unsigned short)atoi(int_port
);
1358 // ** As there is no security policy, InternalClient must be equal to the CP's IP address.
1359 if(DataVerification(h
, int_ip
, &iport
, protocol
, leaseTime
) == 0
1360 || PinholeVerification(h
, int_ip
, &iport
) <= 0)
1362 ClearNameValueList(&data
);
1366 // ** RemoteHost can be wilcarded or an IDN.
1367 /*printf("\trem_host: %s\n", rem_host);*/
1368 if (rem_host
!=NULL
&& !strchr(rem_host
, ':'))
1370 ClearNameValueList(&data
);
1371 SoapError(h
, 402, "Invalid Args");
1374 /*printf("\tAddr check passed.\n");*/
1376 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
);
1378 r
= upnp_add_inboundpinhole(rem_host
, rport
, int_ip
, iport
, protocol
, leaseTime
, &uid
);
1382 case 1: /* success */
1383 bodylen
= snprintf(body
, sizeof(body
), resp
, action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", uid
, action
);
1384 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1386 case -1: /* not permitted */
1387 SoapError(h
, 701, "PinholeSpaceExhausted");
1390 SoapError(h
, 501, "ActionFailed");
1393 ClearNameValueList(&data
);
1397 UpdatePinhole(struct upnphttp
* h
, const char * action
)
1400 static const char resp
[] =
1401 "<u:UpdatePinholeResponse "
1402 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1403 "</u:UpdatePinholeResponse>";
1404 struct NameValueParserData data
;
1405 const char * uid
, * leaseTime
;
1406 char iaddr
[40], proto
[6], lt
[12];
1407 unsigned short iport
;
1409 if(CheckStatus(h
)==0)
1412 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1413 uid
= GetValueFromNameValueList(&data
, "UniqueID");
1414 leaseTime
= GetValueFromNameValueList(&data
, "NewLeaseTime");
1416 if(!uid
|| !leaseTime
|| !atoi(leaseTime
) || atoi(leaseTime
) > 86400)
1418 ClearNameValueList(&data
);
1419 SoapError(h
, 402, "Invalid Args");
1423 // Check that client is not deleting an pinhole he doesn't have access to, because of its public access
1424 n
= upnp_get_pinhole_info(0, 0, iaddr
, &iport
, proto
, uid
, lt
);
1427 if(PinholeVerification(h
, iaddr
, &iport
)==0)
1429 ClearNameValueList(&data
);
1434 syslog(LOG_INFO
, "%s: (inbound) updating lease duration to %s for pinhole with ID: %s", action
, leaseTime
, uid
);
1436 r
= upnp_update_inboundpinhole(uid
, leaseTime
);
1440 if(r
== -4 || r
== -1)
1441 SoapError(h
, 704, "NoSuchEntry");
1443 SoapError(h
, 501, "ActionFailed");
1447 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
1449 ClearNameValueList(&data
);
1453 GetOutboundPinholeTimeout(struct upnphttp
* h
, const char * action
)
1455 if (!ipv6fc_firewall_enabled
)
1457 SoapError(h
, 702, "FirewallDisabed");
1462 static const char resp
[] =
1465 "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1470 struct NameValueParserData data
;
1471 char * int_ip
, * int_port
, * rem_host
, * rem_port
, * protocol
;
1473 unsigned short iport
, rport
;
1475 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1476 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1477 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1478 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1479 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1480 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1482 rport
= (unsigned short)atoi(rem_port
);
1483 iport
= (unsigned short)atoi(int_port
);
1484 proto
= atoi(protocol
);
1486 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
);
1488 r
= upnp_check_outbound_pinhole(proto
, &opt
);
1492 case 1: /* success */
1493 bodylen
= snprintf(body
, sizeof(body
), resp
, action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", opt
, action
);
1494 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1496 case -5: /* Protocol not supported */
1497 SoapError(h
, 705, "ProtocolNotSupported");
1500 SoapError(h
, 501, "ActionFailed");
1502 ClearNameValueList(&data
);
1506 DeletePinhole(struct upnphttp
* h
, const char * action
)
1508 if(CheckStatus(h
)==0)
1512 static const char resp
[] =
1513 "<u:DeletePinholeResponse "
1514 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1515 "</u:DeletePinholeResponse>";
1517 struct NameValueParserData data
;
1519 char iaddr
[40], proto
[6], lt
[12];
1520 unsigned short iport
;
1522 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1523 uid
= GetValueFromNameValueList(&data
, "UniqueID");
1527 ClearNameValueList(&data
);
1528 SoapError(h
, 402, "Invalid Args");
1532 // Check that client is not deleting an pinhole he doesn't have access to, because of its public access
1533 n
= upnp_get_pinhole_info(0, 0, iaddr
, &iport
, proto
, uid
, lt
);
1536 if(PinholeVerification(h
, iaddr
, &iport
)==0)
1538 ClearNameValueList(&data
);
1543 syslog(LOG_INFO
, "%s: (inbound) delete pinhole with ID: %s", action
, uid
);
1545 r
= upnp_delete_inboundpinhole(uid
);
1549 syslog(LOG_INFO
, "%s: (inbound) failed to remove pinhole with ID: %s", action
, uid
);
1551 SoapError(h
, 704, "NoSuchEntry");
1553 SoapError(h
, 501, "ActionFailed");
1557 syslog(LOG_INFO
, "%s: (inbound) pinhole successfully removed", action
);
1558 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
1560 ClearNameValueList(&data
);
1564 CheckPinholeWorking(struct upnphttp
* h
, const char * action
)
1566 if(CheckStatus(h
)==0)
1570 static const char resp
[] =
1573 "<IsWorking>%d</IsWorking>"
1578 struct NameValueParserData data
;
1580 char eaddr
[40], iaddr
[40], proto
[6], lt
[12];
1581 unsigned short eport
, iport
;
1584 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1585 uid
= GetValueFromNameValueList(&data
, "UniqueID");
1589 ClearNameValueList(&data
);
1590 SoapError(h
, 402, "Invalid Args");
1594 // Check that client is not checking a pinhole he doesn't have access to, because of its public access
1595 r
= upnp_get_pinhole_info(eaddr
, eport
, iaddr
, &iport
, proto
, uid
, lt
);
1598 if(PinholeVerification(h
, iaddr
, &iport
)==0)
1600 ClearNameValueList(&data
);
1605 int rulenum_used
, rulenum
= 0;
1606 d
= upnp_check_pinhole_working(uid
, eaddr
, iaddr
, &eport
, &iport
, proto
, &rulenum_used
);
1611 syslog(LOG_INFO
, "%s: rule for ID=%s, no trace found for this pinhole", action
, uid
);
1612 SoapError(h
, 709, "NoPacketSent");
1613 ClearNameValueList(&data
);
1618 // d==-5 not same table // d==-6 not same chain // d==-7 not found a rule but policy traced
1620 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"));
1621 bodylen
= snprintf(body
, sizeof(body
), resp
,
1622 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1624 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1629 /*check_rule_from_file(uid, &rulenum);*/
1630 if(rulenum_used
== rulenum
)
1633 syslog(LOG_INFO
, "%s: rule for ID=%s is working properly", action
, uid
);
1638 syslog(LOG_INFO
, "%s: rule for ID=%s is not working", action
, uid
);
1640 bodylen
= snprintf(body
, sizeof(body
), resp
,
1641 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1643 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1647 else if(r
== -4 || r
== -1)
1649 SoapError(h
, 704, "NoSuchEntry");
1653 SoapError(h
, 501, "ActionFailed");
1654 ClearNameValueList(&data
);
1657 ClearNameValueList(&data
);
1661 GetPinholePackets(struct upnphttp
* h
, const char * action
)
1663 if(CheckStatus(h
)==0)
1667 static const char resp
[] =
1670 "<PinholePackets>%d</PinholePackets>"
1675 struct NameValueParserData data
;
1677 char iaddr
[40], proto
[6], lt
[12];
1678 unsigned short iport
;
1679 int pinholePackets
= 0;
1681 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1682 uid
= GetValueFromNameValueList(&data
, "UniqueID");
1686 ClearNameValueList(&data
);
1687 SoapError(h
, 402, "Invalid Args");
1691 // Check that client is not getting infos of a pinhole he doesn't have access to, because of its public access
1692 r
= upnp_get_pinhole_info(0, 0, iaddr
, &iport
, proto
, uid
, lt
);
1695 if(PinholeVerification(h
, iaddr
, &iport
)==0)
1697 ClearNameValueList(&data
);
1702 n
= upnp_get_pinhole_packets(uid
, &pinholePackets
);
1705 bodylen
= snprintf(body
, sizeof(body
), resp
,
1706 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1707 pinholePackets
, action
);
1708 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1710 else if(r
== -4 || r
== -1)
1712 SoapError(h
, 704, "NoSuchEntry");
1716 SoapError(h
, 501, "ActionFailed");
1717 ClearNameValueList(&data
);
1720 ClearNameValueList(&data
);
1725 /* Windows XP as client send the following requests :
1726 * GetConnectionTypeInfo
1728 * ? GetTotalBytesSent - WANCommonInterfaceConfig
1729 * ? GetTotalBytesReceived - idem
1730 * ? GetTotalPacketsSent - idem
1731 * ? GetTotalPacketsReceived - idem
1732 * GetCommonLinkProperties - idem
1733 * GetStatusInfo - WANIPConnection
1734 * GetExternalIPAddress
1735 * QueryStateVariable / ConnectionStatus!
1739 const char * methodName
;
1740 void (*methodImpl
)(struct upnphttp
*, const char *);
1744 /* WANCommonInterfaceConfig */
1745 { "QueryStateVariable", QueryStateVariable
},
1746 { "GetTotalBytesSent", GetTotalBytesSent
},
1747 { "GetTotalBytesReceived", GetTotalBytesReceived
},
1748 { "GetTotalPacketsSent", GetTotalPacketsSent
},
1749 { "GetTotalPacketsReceived", GetTotalPacketsReceived
},
1750 { "GetCommonLinkProperties", GetCommonLinkProperties
},
1751 { "GetStatusInfo", GetStatusInfo
},
1752 /* WANIPConnection */
1753 { "GetConnectionTypeInfo", GetConnectionTypeInfo
},
1754 { "GetNATRSIPStatus", GetNATRSIPStatus
},
1755 { "GetExternalIPAddress", GetExternalIPAddress
},
1756 { "AddPortMapping", AddPortMapping
},
1757 { "DeletePortMapping", DeletePortMapping
},
1758 { "GetGenericPortMappingEntry", GetGenericPortMappingEntry
},
1759 { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry
},
1760 /* Required in WANIPConnection:2 */
1761 { "SetConnectionType", SetConnectionType
},
1762 { "RequestConnection", RequestConnection
},
1763 { "ForceTermination", ForceTermination
},
1764 { "AddAnyPortMapping", AddAnyPortMapping
},
1765 { "DeletePortMappingRange", DeletePortMappingRange
},
1766 { "GetListOfPortMappings", GetListOfPortMappings
},
1767 #ifdef ENABLE_L3F_SERVICE
1768 /* Layer3Forwarding */
1769 { "SetDefaultConnectionService", SetDefaultConnectionService
},
1770 { "GetDefaultConnectionService", GetDefaultConnectionService
},
1772 #ifdef ENABLE_6FC_SERVICE
1773 /* WANIPv6FirewallControl */
1774 { "GetFirewallStatus", GetFirewallStatus
},
1775 { "AddPinhole", AddPinhole
},
1776 { "UpdatePinhole", UpdatePinhole
},
1777 { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout
},
1778 { "DeletePinhole", DeletePinhole
},
1779 { "CheckPinholeWorking", CheckPinholeWorking
},
1780 { "GetPinholePackets", GetPinholePackets
},
1786 ExecuteSoapAction(struct upnphttp
* h
, const char * action
, int n
)
1790 int i
, len
, methodlen
;
1793 p
= strchr(action
, '#');
1798 p2
= strchr(p
, '"');
1802 methodlen
= n
- (p
- action
);
1803 /*syslog(LOG_DEBUG, "SoapMethod: %.*s", methodlen, p);*/
1804 while(soapMethods
[i
].methodName
)
1806 len
= strlen(soapMethods
[i
].methodName
);
1807 if(strncmp(p
, soapMethods
[i
].methodName
, len
) == 0)
1809 soapMethods
[i
].methodImpl(h
, soapMethods
[i
].methodName
);
1815 syslog(LOG_NOTICE
, "SoapMethod: Unknown: %.*s", methodlen
, p
);
1818 SoapError(h
, 401, "Invalid Action");
1823 * errorCode errorDescription Description
1824 * -------- ---------------- -----------
1825 * 401 Invalid Action No action by that name at this service.
1826 * 402 Invalid Args Could be any of the following: not enough in args,
1827 * too many in args, no in arg by that name,
1828 * one or more in args are of the wrong data type.
1829 * 403 Out of Sync Out of synchronization.
1830 * 501 Action Failed May be returned in current state of service
1831 * prevents invoking that action.
1832 * 600-699 TBD Common action errors. Defined by UPnP Forum
1833 * Technical Committee.
1834 * 700-799 TBD Action-specific errors for standard actions.
1835 * Defined by UPnP Forum working committee.
1836 * 800-899 TBD Action-specific errors for non-standard actions.
1837 * Defined by UPnP vendor.
1840 SoapError(struct upnphttp
* h
, int errCode
, const char * errDesc
)
1842 static const char resp
[] =
1844 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
1845 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
1848 "<faultcode>s:Client</faultcode>"
1849 "<faultstring>UPnPError</faultstring>"
1851 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
1852 "<errorCode>%d</errorCode>"
1853 "<errorDescription>%s</errorDescription>"
1863 syslog(LOG_INFO
, "Returning UPnPError %d: %s", errCode
, errDesc
);
1864 bodylen
= snprintf(body
, sizeof(body
), resp
, errCode
, errDesc
);
1865 BuildResp2_upnphttp(h
, 500, "Internal Server Error", body
, bodylen
);
1866 SendResp_upnphttp(h
);