1 /* $Id: upnpsoap.c,v 1.114 2013/02/06 12:40:25 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2012 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
12 #include <sys/socket.h>
15 #include <sys/types.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
22 #include "upnpglobalvars.h"
25 #include "upnpreplyparse.h"
26 #include "upnpredirect.h"
27 #include "upnppinhole.h"
28 #include "getifaddr.h"
29 #include "getifstats.h"
30 #include "getconnstatus.h"
34 BuildSendAndCloseSoapResp(struct upnphttp
* h
,
35 const char * body
, int bodylen
)
37 static const char beforebody
[] =
38 "<?xml version=\"1.0\"?>\r\n"
39 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
40 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
43 static const char afterbody
[] =
47 BuildHeader_upnphttp(h
, 200, "OK", sizeof(beforebody
) - 1
48 + sizeof(afterbody
) - 1 + bodylen
);
50 memcpy(h
->res_buf
+ h
->res_buflen
, beforebody
, sizeof(beforebody
) - 1);
51 h
->res_buflen
+= sizeof(beforebody
) - 1;
53 memcpy(h
->res_buf
+ h
->res_buflen
, body
, bodylen
);
54 h
->res_buflen
+= bodylen
;
56 memcpy(h
->res_buf
+ h
->res_buflen
, afterbody
, sizeof(afterbody
) - 1);
57 h
->res_buflen
+= sizeof(afterbody
) - 1;
59 SendRespAndClose_upnphttp(h
);
63 GetConnectionTypeInfo(struct upnphttp
* h
, const char * action
)
65 static const char resp
[] =
66 "<u:GetConnectionTypeInfoResponse "
67 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
68 "<NewConnectionType>IP_Routed</NewConnectionType>"
69 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
70 "</u:GetConnectionTypeInfoResponse>";
73 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
77 GetTotalBytesSent(struct upnphttp
* h
, const char * action
)
81 static const char resp
[] =
84 "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
91 r
= getifstats(ext_if_name
, &data
);
92 bodylen
= snprintf(body
, sizeof(body
), resp
,
93 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
94 r
<0?0:data
.obytes
, action
);
95 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
99 GetTotalBytesReceived(struct upnphttp
* h
, const char * action
)
103 static const char resp
[] =
106 "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
113 r
= getifstats(ext_if_name
, &data
);
114 bodylen
= snprintf(body
, sizeof(body
), resp
,
115 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
116 r
<0?0:data
.ibytes
, action
);
117 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
121 GetTotalPacketsSent(struct upnphttp
* h
, const char * action
)
125 static const char resp
[] =
128 "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
135 r
= getifstats(ext_if_name
, &data
);
136 bodylen
= snprintf(body
, sizeof(body
), resp
,
137 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
138 r
<0?0:data
.opackets
, action
);
139 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
143 GetTotalPacketsReceived(struct upnphttp
* h
, const char * action
)
147 static const char resp
[] =
150 "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
157 r
= getifstats(ext_if_name
, &data
);
158 bodylen
= snprintf(body
, sizeof(body
), resp
,
159 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
160 r
<0?0:data
.ipackets
, action
);
161 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
165 GetCommonLinkProperties(struct upnphttp
* h
, const char * action
)
167 /* WANAccessType : set depending on the hardware :
168 * DSL, POTS (plain old Telephone service), Cable, Ethernet */
169 static const char resp
[] =
172 /*"<NewWANAccessType>DSL</NewWANAccessType>"*/
173 "<NewWANAccessType>Cable</NewWANAccessType>"
174 "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
175 "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
176 "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
182 const char * status
= "Up"; /* Up, Down (Required),
183 * Initializing, Unavailable (Optional) */
184 char ext_ip_addr
[INET_ADDRSTRLEN
];
186 if((downstream_bitrate
== 0) || (upstream_bitrate
== 0))
188 if(getifstats(ext_if_name
, &data
) >= 0)
190 if(downstream_bitrate
== 0) downstream_bitrate
= data
.baudrate
;
191 if(upstream_bitrate
== 0) upstream_bitrate
= data
.baudrate
;
194 if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
) < 0) {
197 bodylen
= snprintf(body
, sizeof(body
), resp
,
198 action
, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
199 upstream_bitrate
, downstream_bitrate
,
201 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
205 GetStatusInfo(struct upnphttp
* h
, const char * action
)
207 static const char resp
[] =
210 "<NewConnectionStatus>%s</NewConnectionStatus>"
211 "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
212 "<NewUptime>%ld</NewUptime>"
219 /* ConnectionStatus possible values :
220 * Unconfigured, Connecting, Connected, PendingDisconnect,
221 * Disconnecting, Disconnected */
223 status
= get_wan_connection_status_str(ext_if_name
);
224 uptime
= (time(NULL
) - startup_time
);
225 bodylen
= snprintf(body
, sizeof(body
), resp
,
226 action
, SERVICE_TYPE_WANIPC
,
227 status
, (long)uptime
, action
);
228 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
232 GetNATRSIPStatus(struct upnphttp
* h
, const char * action
)
234 static const char resp
[] =
235 "<u:GetNATRSIPStatusResponse "
236 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
237 "<NewRSIPAvailable>0</NewRSIPAvailable>"
238 "<NewNATEnabled>1</NewNATEnabled>"
239 "</u:GetNATRSIPStatusResponse>";
241 /* 2.2.9. RSIPAvailable
242 * This variable indicates if Realm-specific IP (RSIP) is available
243 * as a feature on the InternetGatewayDevice. RSIP is being defined
244 * in the NAT working group in the IETF to allow host-NATing using
245 * a standard set of message exchanges. It also allows end-to-end
246 * applications that otherwise break if NAT is introduced
247 * (e.g. IPsec-based VPNs).
248 * A gateway that does not support RSIP should set this variable to 0. */
249 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
253 GetExternalIPAddress(struct upnphttp
* h
, const char * action
)
255 static const char resp
[] =
258 "<NewExternalIPAddress>%s</NewExternalIPAddress>"
263 char ext_ip_addr
[INET_ADDRSTRLEN
];
264 /* Does that method need to work with IPv6 ?
265 * There is usually no NAT with IPv6 */
267 #ifndef MULTIPLE_EXTERNAL_IP
270 strncpy(ext_ip_addr
, use_ext_ip_addr
, INET_ADDRSTRLEN
);
272 else if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
) < 0)
274 syslog(LOG_ERR
, "Failed to get ip address for interface %s",
276 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
279 struct lan_addr_s
* lan_addr
;
280 strncpy(ext_ip_addr
, "0.0.0.0", INET_ADDRSTRLEN
);
281 for(lan_addr
= lan_addrs
.lh_first
; lan_addr
!= NULL
; lan_addr
= lan_addr
->list
.le_next
)
283 if( (h
->clientaddr
.s_addr
& lan_addr
->mask
.s_addr
)
284 == (lan_addr
->addr
.s_addr
& lan_addr
->mask
.s_addr
))
286 strncpy(ext_ip_addr
, lan_addr
->ext_ip_str
, INET_ADDRSTRLEN
);
291 bodylen
= snprintf(body
, sizeof(body
), resp
,
292 action
, SERVICE_TYPE_WANIPC
,
293 ext_ip_addr
, action
);
294 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
297 /* AddPortMapping method of WANIPConnection Service
298 * Ignored argument : NewEnabled */
300 AddPortMapping(struct upnphttp
* h
, const char * action
)
304 static const char resp
[] =
305 "<u:AddPortMappingResponse "
306 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\"/>";
308 struct NameValueParserData data
;
309 char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
310 char * leaseduration_str
;
311 unsigned int leaseduration
;
313 unsigned short iport
, eport
;
315 struct hostent
*hp
; /* getbyhostname() */
316 char ** ptr
; /* getbyhostname() */
317 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
319 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
320 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
323 ClearNameValueList(&data
);
324 SoapError(h
, 402, "Invalid Args");
328 /* IGD 2 MUST support both wildcard and specific IP address values
329 * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
330 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
331 #ifndef SUPPORT_REMOTEHOST
333 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
335 ClearNameValueList(&data
);
336 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
342 /* if ip not valid assume hostname and convert */
343 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
345 hp
= gethostbyname(int_ip
);
346 if(hp
&& hp
->h_addrtype
== AF_INET
)
348 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
350 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
351 result_ip
= *((struct in_addr
*) *ptr
);
352 /* TODO : deal with more than one ip per hostname */
358 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
359 ClearNameValueList(&data
);
360 SoapError(h
, 402, "Invalid Args");
365 /* check if NewInternalAddress is the client address */
366 if(GETFLAG(SECUREMODEMASK
))
368 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
370 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
371 inet_ntoa(h
->clientaddr
), int_ip
);
372 ClearNameValueList(&data
);
373 SoapError(h
, 718, "ConflictInMappingEntry");
378 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
379 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
380 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
381 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
382 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
384 if (!int_port
|| !ext_port
|| !protocol
)
386 ClearNameValueList(&data
);
387 SoapError(h
, 402, "Invalid Args");
391 eport
= (unsigned short)atoi(ext_port
);
392 iport
= (unsigned short)atoi(int_port
);
394 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
396 /* PortMappingLeaseDuration can be either a value between 1 and
397 * 604800 seconds or the zero value (for infinite lease time).
398 * Note that an infinite lease time can be only set by out-of-band
399 * mechanisms like WWW-administration, remote management or local
401 * If a control point uses the value 0 to indicate an infinite lease
402 * time mapping, it is REQUIRED that gateway uses the maximum value
403 * instead (e.g. 604800 seconds) */
404 if(leaseduration
== 0 || leaseduration
> 604800)
405 leaseduration
= 604800;
408 syslog(LOG_INFO
, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
409 action
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
,
410 r_host
? r_host
: "NULL");
412 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
414 ClearNameValueList(&data
);
416 /* possible error codes for AddPortMapping :
418 * 501 - Action Failed
419 * 715 - Wildcard not permited in SrcAddr
420 * 716 - Wildcard not permited in ExtPort
421 * 718 - ConflictInMappingEntry
422 * 724 - SamePortValuesRequired (deprecated in IGD v2)
423 * 725 - OnlyPermanentLeasesSupported
424 The NAT implementation only supports permanent lease times on
425 port mappings (deprecated in IGD v2)
426 * 726 - RemoteHostOnlySupportsWildcard
427 RemoteHost must be a wildcard and cannot be a specific IP
428 address or DNS name (deprecated in IGD v2)
429 * 727 - ExternalPortOnlySupportsWildcard
430 ExternalPort must be a wildcard and cannot be a specific port
431 value (deprecated in IGD v2)
432 * 728 - NoPortMapsAvailable
433 There are not enough free prots available to complete the mapping
435 * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
438 case 0: /* success */
439 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
441 case -2: /* already redirected */
442 case -3: /* not permitted */
443 SoapError(h
, 718, "ConflictInMappingEntry");
446 SoapError(h
, 501, "ActionFailed");
450 /* AddAnyPortMapping was added in WANIPConnection v2 */
452 AddAnyPortMapping(struct upnphttp
* h
, const char * action
)
455 static const char resp
[] =
458 "<NewReservedPort>%hu</NewReservedPort>"
464 struct NameValueParserData data
;
465 const char * int_ip
, * int_port
, * ext_port
, * protocol
, * desc
;
467 unsigned short iport
, eport
;
468 const char * leaseduration_str
;
469 unsigned int leaseduration
;
471 struct hostent
*hp
; /* getbyhostname() */
472 char ** ptr
; /* getbyhostname() */
473 struct in_addr result_ip
;/*unsigned char result_ip[16];*/ /* inet_pton() */
475 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
476 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
477 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
478 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
479 int_port
= GetValueFromNameValueList(&data
, "NewInternalPort");
480 int_ip
= GetValueFromNameValueList(&data
, "NewInternalClient");
482 desc
= GetValueFromNameValueList(&data
, "NewPortMappingDescription");
483 leaseduration_str
= GetValueFromNameValueList(&data
, "NewLeaseDuration");
485 leaseduration
= leaseduration_str
? atoi(leaseduration_str
) : 0;
486 if(leaseduration
== 0)
487 leaseduration
= 604800;
489 if (!int_ip
|| !ext_port
|| !int_port
)
491 ClearNameValueList(&data
);
492 SoapError(h
, 402, "Invalid Args");
496 eport
= (unsigned short)atoi(ext_port
);
497 iport
= (unsigned short)atoi(int_port
);
498 #ifndef SUPPORT_REMOTEHOST
500 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
502 ClearNameValueList(&data
);
503 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
509 /* if ip not valid assume hostname and convert */
510 if (inet_pton(AF_INET
, int_ip
, &result_ip
) <= 0)
512 hp
= gethostbyname(int_ip
);
513 if(hp
&& hp
->h_addrtype
== AF_INET
)
515 for(ptr
= hp
->h_addr_list
; ptr
&& *ptr
; ptr
++)
517 int_ip
= inet_ntoa(*((struct in_addr
*) *ptr
));
518 result_ip
= *((struct in_addr
*) *ptr
);
519 /* TODO : deal with more than one ip per hostname */
525 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
526 ClearNameValueList(&data
);
527 SoapError(h
, 402, "Invalid Args");
532 /* check if NewInternalAddress is the client address */
533 if(GETFLAG(SECUREMODEMASK
))
535 if(h
->clientaddr
.s_addr
!= result_ip
.s_addr
)
537 syslog(LOG_INFO
, "Client %s tried to redirect port to %s",
538 inet_ntoa(h
->clientaddr
), int_ip
);
539 ClearNameValueList(&data
);
540 SoapError(h
, 606, "Action not authorized");
545 /* TODO : accept a different external port
546 * have some smart strategy to choose the port */
548 r
= upnp_redirect(r_host
, eport
, int_ip
, iport
, protocol
, desc
, leaseduration
);
549 if(r
==-2 && eport
< 65535) {
556 ClearNameValueList(&data
);
560 case 0: /* success */
561 bodylen
= snprintf(body
, sizeof(body
), resp
,
562 action
, SERVICE_TYPE_WANIPC
,
564 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
566 case -2: /* already redirected */
567 SoapError(h
, 718, "ConflictInMappingEntry");
569 case -3: /* not permitted */
570 SoapError(h
, 606, "Action not authorized");
573 SoapError(h
, 501, "ActionFailed");
578 GetSpecificPortMappingEntry(struct upnphttp
* h
, const char * action
)
582 static const char resp
[] =
585 "<NewInternalPort>%u</NewInternalPort>"
586 "<NewInternalClient>%s</NewInternalClient>"
587 "<NewEnabled>1</NewEnabled>"
588 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
589 "<NewLeaseDuration>%u</NewLeaseDuration>"
594 struct NameValueParserData data
;
595 const char * r_host
, * ext_port
, * protocol
;
596 unsigned short eport
, iport
;
599 unsigned int leaseduration
= 0;
601 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
602 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
603 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
604 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
607 if(!ext_port
|| !protocol
|| !r_host
)
609 if(!ext_port
|| !protocol
)
612 ClearNameValueList(&data
);
613 SoapError(h
, 402, "Invalid Args");
616 #ifndef SUPPORT_REMOTEHOST
618 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
620 ClearNameValueList(&data
);
621 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
627 eport
= (unsigned short)atoi(ext_port
);
629 /* TODO : add r_host as an input parameter ...
630 * We prevent several Port Mapping with same external port
631 * but different remoteHost to be set up, so that is not
633 r
= upnp_get_redirection_infos(eport
, protocol
, &iport
,
634 int_ip
, sizeof(int_ip
),
641 SoapError(h
, 714, "NoSuchEntryInArray");
645 syslog(LOG_INFO
, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
647 r_host
? r_host
: "NULL", ext_port
, protocol
, int_ip
,
648 (unsigned int)iport
, desc
);
649 bodylen
= snprintf(body
, sizeof(body
), resp
,
650 action
, SERVICE_TYPE_WANIPC
,
651 (unsigned int)iport
, int_ip
, desc
, leaseduration
,
653 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
656 ClearNameValueList(&data
);
660 DeletePortMapping(struct upnphttp
* h
, const char * action
)
664 static const char resp
[] =
665 "<u:DeletePortMappingResponse "
666 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
667 "</u:DeletePortMappingResponse>";
669 struct NameValueParserData data
;
670 const char * r_host
, * ext_port
, * protocol
;
671 unsigned short eport
;
673 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
674 r_host
= GetValueFromNameValueList(&data
, "NewRemoteHost");
675 ext_port
= GetValueFromNameValueList(&data
, "NewExternalPort");
676 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
679 if(!ext_port
|| !protocol
|| !r_host
)
681 if(!ext_port
|| !protocol
)
684 ClearNameValueList(&data
);
685 SoapError(h
, 402, "Invalid Args");
688 #ifndef SUPPORT_REMOTEHOST
690 if (r_host
&& (strlen(r_host
) > 0) && (0 != strcmp(r_host
, "*")))
692 ClearNameValueList(&data
);
693 SoapError(h
, 726, "RemoteHostOnlySupportsWildcard");
699 eport
= (unsigned short)atoi(ext_port
);
701 /* TODO : if in secure mode, check the IP
702 * Removing a redirection is not a security threat,
703 * just an annoyance for the user using it. So this is not
706 syslog(LOG_INFO
, "%s: external port: %hu, protocol: %s",
707 action
, eport
, protocol
);
709 r
= upnp_delete_redirection(eport
, protocol
);
713 SoapError(h
, 714, "NoSuchEntryInArray");
717 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
720 ClearNameValueList(&data
);
723 /* DeletePortMappingRange was added in IGD spec v2 */
725 DeletePortMappingRange(struct upnphttp
* h
, const char * action
)
728 static const char resp
[] =
729 "<u:DeletePortMappingRangeResponse "
730 "xmlns:u=\"" SERVICE_TYPE_WANIPC
"\">"
731 "</u:DeletePortMappingRangeResponse>";
732 struct NameValueParserData data
;
733 const char * protocol
;
734 const char * startport_s
, * endport_s
;
735 unsigned short startport
, endport
;
737 unsigned short * port_list
;
738 unsigned int i
, number
= 0;
741 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
742 startport_s
= GetValueFromNameValueList(&data
, "NewStartPort");
743 endport_s
= GetValueFromNameValueList(&data
, "NewEndPort");
744 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
745 /*manage = atoi(GetValueFromNameValueList(&data, "NewManage"));*/
746 if(startport_s
== NULL
|| endport_s
== NULL
|| protocol
== NULL
) {
747 SoapError(h
, 402, "Invalid Args");
748 ClearNameValueList(&data
);
751 startport
= (unsigned short)atoi(startport_s
);
752 endport
= (unsigned short)atoi(endport_s
);
755 606 - Action not authorized
756 730 - PortMappingNotFound
757 733 - InconsistentParameter
759 if(startport
> endport
)
761 SoapError(h
, 733, "InconsistentParameter");
762 ClearNameValueList(&data
);
766 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
768 for(i
= 0; i
< number
; i
++)
770 r
= upnp_delete_redirection(port_list
[i
], protocol
);
771 /* TODO : check return value for errors */
774 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
776 ClearNameValueList(&data
);
780 GetGenericPortMappingEntry(struct upnphttp
* h
, const char * action
)
784 static const char resp
[] =
787 "<NewRemoteHost>%s</NewRemoteHost>"
788 "<NewExternalPort>%u</NewExternalPort>"
789 "<NewProtocol>%s</NewProtocol>"
790 "<NewInternalPort>%u</NewInternalPort>"
791 "<NewInternalClient>%s</NewInternalClient>"
792 "<NewEnabled>1</NewEnabled>"
793 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
794 "<NewLeaseDuration>%u</NewLeaseDuration>"
798 unsigned short eport
, iport
;
799 const char * m_index
;
800 char protocol
[4], iaddr
[32];
803 unsigned int leaseduration
= 0;
804 struct NameValueParserData data
;
806 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
807 m_index
= GetValueFromNameValueList(&data
, "NewPortMappingIndex");
811 ClearNameValueList(&data
);
812 SoapError(h
, 402, "Invalid Args");
816 index
= (int)atoi(m_index
);
818 syslog(LOG_INFO
, "%s: index=%d", action
, index
);
821 r
= upnp_get_redirection_infos_by_index(index
, &eport
, protocol
, &iport
,
822 iaddr
, sizeof(iaddr
),
824 rhost
, sizeof(rhost
),
829 SoapError(h
, 713, "SpecifiedArrayIndexInvalid");
835 bodylen
= snprintf(body
, sizeof(body
), resp
,
836 action
, SERVICE_TYPE_WANIPC
, rhost
,
837 (unsigned int)eport
, protocol
, (unsigned int)iport
, iaddr
, desc
,
838 leaseduration
, action
);
839 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
842 ClearNameValueList(&data
);
845 /* GetListOfPortMappings was added in the IGD v2 specification */
847 GetListOfPortMappings(struct upnphttp
* h
, const char * action
)
849 static const char resp_start
[] =
852 "<NewPortListing><![CDATA[";
853 static const char resp_end
[] =
854 "]]></NewPortListing>"
857 static const char list_start
[] =
858 "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
859 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
860 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
861 " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
862 static const char list_end
[] =
863 "</p:PortMappingList>";
865 static const char entry
[] =
866 "<p:PortMappingEntry>"
867 "<p:NewRemoteHost>%s</p:NewRemoteHost>"
868 "<p:NewExternalPort>%hu</p:NewExternalPort>"
869 "<p:NewProtocol>%s</p:NewProtocol>"
870 "<p:NewInternalPort>%hu</p:NewInternalPort>"
871 "<p:NewInternalClient>%s</p:NewInternalClient>"
872 "<p:NewEnabled>1</p:NewEnabled>"
873 "<p:NewDescription>%s</p:NewDescription>"
874 "<p:NewLeaseTime>%u</p:NewLeaseTime>"
875 "</p:PortMappingEntry>";
882 unsigned short iport
;
886 unsigned int leaseduration
= 0;
888 struct NameValueParserData data
;
889 const char * startport_s
, * endport_s
;
890 unsigned short startport
, endport
;
891 const char * protocol
;
893 const char * number_s
;
895 unsigned short * port_list
;
896 unsigned int i
, list_size
= 0;
898 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
899 startport_s
= GetValueFromNameValueList(&data
, "NewStartPort");
900 endport_s
= GetValueFromNameValueList(&data
, "NewEndPort");
901 protocol
= GetValueFromNameValueList(&data
, "NewProtocol");
902 /*manage_s = GetValueFromNameValueList(&data, "NewManage");*/
903 number_s
= GetValueFromNameValueList(&data
, "NewNumberOfPorts");
904 if(startport_s
== NULL
|| endport_s
== NULL
|| protocol
== NULL
||
906 SoapError(h
, 402, "Invalid Args");
907 ClearNameValueList(&data
);
911 startport
= (unsigned short)atoi(startport_s
);
912 endport
= (unsigned short)atoi(endport_s
);
913 /*manage = atoi(manage_s);*/
914 number
= atoi(number_s
);
915 if(number
== 0) number
= 1000; /* return up to 1000 mappings by default */
917 if(startport
> endport
)
919 SoapError(h
, 733, "InconsistentParameter");
920 ClearNameValueList(&data
);
924 build the PortMappingList xml document :
926 <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
927 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
928 xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
929 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
931 <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
932 <p:NewExternalPort>2345</p:NewExternalPort>
933 <p:NewProtocol>TCP</p:NewProtocol>
934 <p:NewInternalPort>2345</p:NewInternalPort>
935 <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
936 <p:NewEnabled>1</p:NewEnabled>
937 <p:NewDescription>dooom</p:NewDescription>
938 <p:NewLeaseTime>345</p:NewLeaseTime>
939 </p:PortMappingEntry>
943 body
= malloc(bodyalloc
);
946 ClearNameValueList(&data
);
947 SoapError(h
, 501, "ActionFailed");
950 bodylen
= snprintf(body
, bodyalloc
, resp_start
,
951 action
, SERVICE_TYPE_WANIPC
);
954 SoapError(h
, 501, "ActionFailed");
958 memcpy(body
+bodylen
, list_start
, sizeof(list_start
));
959 bodylen
+= (sizeof(list_start
) - 1);
961 port_list
= upnp_get_portmappings_in_range(startport
, endport
,
962 protocol
, &list_size
);
963 /* loop through port mappings */
964 for(i
= 0; number
> 0 && i
< list_size
; i
++)
966 /* have a margin of 1024 bytes to store the new entry */
967 if((unsigned int)bodylen
+ 1024 > bodyalloc
)
969 char * body_sav
= body
;
971 body
= realloc(body
, bodyalloc
);
974 ClearNameValueList(&data
);
975 SoapError(h
, 501, "ActionFailed");
982 r
= upnp_get_redirection_infos(port_list
[i
], protocol
, &iport
,
983 int_ip
, sizeof(int_ip
),
985 rhost
, sizeof(rhost
),
989 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, entry
,
990 rhost
, port_list
[i
], protocol
,
991 iport
, int_ip
, desc
, leaseduration
);
998 memcpy(body
+bodylen
, list_end
, sizeof(list_end
));
999 bodylen
+= (sizeof(list_end
) - 1);
1000 bodylen
+= snprintf(body
+bodylen
, bodyalloc
-bodylen
, resp_end
,
1002 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1005 ClearNameValueList(&data
);
1008 #ifdef ENABLE_L3F_SERVICE
1010 SetDefaultConnectionService(struct upnphttp
* h
, const char * action
)
1012 static const char resp
[] =
1013 "<u:SetDefaultConnectionServiceResponse "
1014 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1015 "</u:SetDefaultConnectionServiceResponse>";
1016 struct NameValueParserData data
;
1018 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1019 p
= GetValueFromNameValueList(&data
, "NewDefaultConnectionService");
1021 /* 720 InvalidDeviceUUID
1022 * 721 InvalidServiceID
1023 * 723 InvalidConnServiceSelection */
1025 if(0 != memcmp(uuidvalue
, p
, sizeof("uuid:00000000-0000-0000-0000-000000000000") - 1)) {
1026 SoapError(h
, 720, "InvalidDeviceUUID");
1030 syslog(LOG_INFO
, "%s(%s) : Ignored", action
, p
);
1031 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
1034 /* missing argument */
1035 SoapError(h
, 402, "Invalid Args");
1037 ClearNameValueList(&data
);
1041 GetDefaultConnectionService(struct upnphttp
* h
, const char * action
)
1043 static const char resp
[] =
1045 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1046 "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
1047 SERVICE_ID_WANIPC
"</NewDefaultConnectionService>"
1049 /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
1050 * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
1051 * urn:upnp-org:serviceId:WANPPPConn1 */
1055 bodylen
= snprintf(body
, sizeof(body
), resp
,
1056 action
, uuidvalue
, action
);
1057 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1061 /* Added for compliance with WANIPConnection v2 */
1063 SetConnectionType(struct upnphttp
* h
, const char * action
)
1065 const char * connection_type
;
1066 struct NameValueParserData data
;
1069 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1070 connection_type
= GetValueFromNameValueList(&data
, "NewConnectionType");
1072 if(!connection_type
) {
1073 ClearNameValueList(&data
);
1074 SoapError(h
, 402, "Invalid Args");
1078 /* Unconfigured, IP_Routed, IP_Bridged */
1079 ClearNameValueList(&data
);
1080 /* always return a ReadOnly error */
1081 SoapError(h
, 731, "ReadOnly");
1084 /* Added for compliance with WANIPConnection v2 */
1086 RequestConnection(struct upnphttp
* h
, const char * action
)
1089 SoapError(h
, 606, "Action not authorized");
1092 /* Added for compliance with WANIPConnection v2 */
1094 ForceTermination(struct upnphttp
* h
, const char * action
)
1097 SoapError(h
, 606, "Action not authorized");
1101 If a control point calls QueryStateVariable on a state variable that is not
1102 buffered in memory within (or otherwise available from) the service,
1103 the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1105 QueryStateVariable remains useful as a limited test tool but may not be
1106 part of some future versions of UPnP.
1109 QueryStateVariable(struct upnphttp
* h
, const char * action
)
1111 static const char resp
[] =
1114 "<return>%s</return>"
1119 struct NameValueParserData data
;
1120 const char * var_name
;
1122 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1123 /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1124 /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1125 var_name
= GetValueFromNameValueList(&data
, "varName");
1127 /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1131 SoapError(h
, 402, "Invalid Args");
1133 else if(strcmp(var_name
, "ConnectionStatus") == 0)
1135 const char * status
;
1137 status
= get_wan_connection_status_str(ext_if_name
);
1138 bodylen
= snprintf(body
, sizeof(body
), resp
,
1139 action
, "urn:schemas-upnp-org:control-1-0",
1141 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1145 else if(strcmp(var_name
, "ConnectionType") == 0)
1147 bodylen
= snprintf(body
, sizeof(body
), resp
, "IP_Routed");
1148 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1150 else if(strcmp(var_name
, "LastConnectionError") == 0)
1152 bodylen
= snprintf(body
, sizeof(body
), resp
, "ERROR_NONE");
1153 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1156 else if(strcmp(var_name
, "PortMappingNumberOfEntries") == 0)
1159 snprintf(strn
, sizeof(strn
), "%i",
1160 upnp_get_portmapping_number_of_entries());
1161 bodylen
= snprintf(body
, sizeof(body
), resp
,
1162 action
, "urn:schemas-upnp-org:control-1-0",
1164 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1168 syslog(LOG_NOTICE
, "%s: Unknown: %s", action
, var_name
?var_name
:"");
1169 SoapError(h
, 404, "Invalid Var");
1172 ClearNameValueList(&data
);
1175 #ifdef ENABLE_6FC_SERVICE
1177 #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1179 /* WANIPv6FirewallControl actions */
1181 GetFirewallStatus(struct upnphttp
* h
, const char * action
)
1183 static const char resp
[] =
1186 "<FirewallEnabled>%d</FirewallEnabled>"
1187 "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1193 bodylen
= snprintf(body
, sizeof(body
), resp
,
1194 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1195 ipv6fc_firewall_enabled
, ipv6fc_inbound_pinhole_allowed
, action
);
1196 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1200 CheckStatus(struct upnphttp
* h
)
1202 if (!ipv6fc_firewall_enabled
)
1204 SoapError(h
, 702, "FirewallDisabled");
1207 else if(!ipv6fc_inbound_pinhole_allowed
)
1209 SoapError(h
, 703, "InboundPinholeNotAllowed");
1217 static int connecthostport(const char * host
, unsigned short port
, char * result
)
1220 char hostname
[INET6_ADDRSTRLEN
];
1221 char port_str
[8], ifname
[8], tmp
[4];
1222 struct addrinfo
*ai
, *p
;
1223 struct addrinfo hints
;
1225 memset(&hints
, 0, sizeof(hints
));
1226 /* hints.ai_flags = AI_ADDRCONFIG; */
1227 #ifdef AI_NUMERICSERV
1228 hints
.ai_flags
= AI_NUMERICSERV
;
1230 hints
.ai_socktype
= SOCK_STREAM
;
1231 hints
.ai_family
= AF_UNSPEC
; /* AF_INET, AF_INET6 or AF_UNSPEC */
1232 /* hints.ai_protocol = IPPROTO_TCP; */
1233 snprintf(port_str
, sizeof(port_str
), "%hu", port
);
1234 strcpy(hostname
, host
);
1235 if(!strncmp(host
, "fe80", 4))
1237 printf("Using an linklocal address\n");
1238 strcpy(ifname
, "%");
1239 snprintf(tmp
, sizeof(tmp
), "%d", linklocal_index
);
1240 strcat(ifname
, tmp
);
1241 strcat(hostname
, ifname
);
1242 printf("host: %s\n", hostname
);
1244 n
= getaddrinfo(hostname
, port_str
, &hints
, &ai
);
1247 fprintf(stderr
, "getaddrinfo() error : %s\n", gai_strerror(n
));
1251 for(p
= ai
; p
; p
= p
->ai_next
)
1255 char tmp_service
[256];
1256 printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1257 p
->ai_family
, p
->ai_socktype
, p
->ai_protocol
, p
->ai_addrlen
);
1258 getnameinfo(p
->ai_addr
, p
->ai_addrlen
, tmp_host
, sizeof(tmp_host
),
1259 tmp_service
, sizeof(tmp_service
),
1260 NI_NUMERICHOST
| NI_NUMERICSERV
);
1261 printf(" host=%s service=%s\n", tmp_host
, tmp_service
);
1263 inet_ntop(AF_INET6
, &(((struct sockaddr_in6
*)p
->ai_addr
)->sin6_addr
), result
, INET6_ADDRSTRLEN
);
1270 /* Check the security policy right */
1272 PinholeVerification(struct upnphttp
* h
, char * int_ip
, unsigned short int_port
)
1275 char senderAddr
[INET6_ADDRSTRLEN
]="";
1276 struct addrinfo hints
, *ai
, *p
;
1277 struct in6_addr result_ip
;
1279 /* Pinhole InternalClient address must correspond to the action sender */
1280 syslog(LOG_INFO
, "Checking internal IP@ and port (Security policy purpose)");
1282 hints
.ai_socktype
= SOCK_STREAM
;
1283 hints
.ai_family
= AF_UNSPEC
;
1285 /* if ip not valid assume hostname and convert */
1286 if (inet_pton(AF_INET6
, int_ip
, &result_ip
) <= 0)
1288 n
= getaddrinfo(int_ip
, NULL
, &hints
, &ai
);
1289 if(!n
&& ai
->ai_family
== AF_INET6
)
1291 for(p
= ai
; p
; p
= p
->ai_next
)
1293 inet_ntop(AF_INET6
, (struct in6_addr
*) p
, int_ip
, sizeof(struct in6_addr
));
1294 result_ip
= *((struct in6_addr
*) p
);
1295 /* TODO : deal with more than one ip per hostname */
1301 syslog(LOG_ERR
, "Failed to convert hostname '%s' to ip address", int_ip
);
1302 SoapError(h
, 402, "Invalid Args");
1308 if(inet_ntop(AF_INET6
, &(h
->clientaddr_v6
), senderAddr
, INET6_ADDRSTRLEN
) == NULL
)
1310 syslog(LOG_ERR
, "inet_ntop: %m");
1313 printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr
, int_ip
);
1315 if(strcmp(senderAddr
, int_ip
) != 0)
1316 if(h
->clientaddr_v6
.s6_addr
!= result_ip
.s6_addr
)
1318 syslog(LOG_INFO
, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1319 senderAddr
, int_ip
);
1320 SoapError(h
, 606, "Action not authorized");
1324 /* Pinhole InternalPort must be greater than or equal to 1024 */
1325 if (int_port
< 1024)
1327 syslog(LOG_INFO
, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1329 SoapError(h
, 606, "Action not authorized");
1336 AddPinhole(struct upnphttp
* h
, const char * action
)
1339 static const char resp
[] =
1342 "<UniqueID>%d</UniqueID>"
1346 struct NameValueParserData data
;
1347 char * rem_host
, * rem_port
, * int_ip
, * int_port
, * protocol
, * leaseTime
;
1349 unsigned short iport
, rport
;
1352 char rem_ip
[INET6_ADDRSTRLEN
];
1354 if(CheckStatus(h
)==0)
1357 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1358 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1359 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1360 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1361 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1362 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1363 leaseTime
= GetValueFromNameValueList(&data
, "LeaseTime");
1365 rport
= (unsigned short)(rem_port
? atoi(rem_port
) : 0);
1366 iport
= (unsigned short)(int_port
? atoi(int_port
) : 0);
1367 ltime
= leaseTime
? atoi(leaseTime
) : -1;
1369 proto
= protocol
? strtol(protocol
, NULL
, 0) : -1;
1370 if(errno
!= 0 || proto
> 65535 || proto
< 0)
1372 SoapError(h
, 402, "Invalid Args");
1373 goto clear_and_exit
;
1377 SoapError(h
, 706, "InternalPortWilcardingNotAllowed");
1378 goto clear_and_exit
;
1381 /* In particular, [IGD2] RECOMMENDS that unauthenticated and
1382 * unauthorized control points are only allowed to invoke
1384 * - InternalPort value greater than or equal to 1024,
1385 * - InternalClient value equals to the control point's IP address.
1386 * It is REQUIRED that InternalClient cannot be one of IPv6
1387 * addresses used by the gateway. */
1388 if(!int_ip
|| 0 == strlen(int_ip
) || 0 == strcmp(int_ip
, "*"))
1390 SoapError(h
, 708, "WildCardNotPermittedInSrcIP");
1391 goto clear_and_exit
;
1393 /* I guess it is useless to convert int_ip to literal ipv6 address */
1394 /* rem_host should be converted to literal ipv6 : */
1397 struct addrinfo
*ai
, *p
;
1398 struct addrinfo hints
;
1400 memset(&hints
, 0, sizeof(struct addrinfo
));
1401 hints
.ai_family
= AF_INET6
;
1402 /*hints.ai_flags = */
1403 /* hints.ai_protocol = proto; */
1404 err
= getaddrinfo(rem_host
, rem_port
, &hints
, &ai
);
1407 /* take the 1st IPv6 address */
1408 for(p
= ai
; p
; p
= p
->ai_next
)
1410 if(p
->ai_family
== AF_INET6
)
1413 &(((struct sockaddr_in6
*)p
->ai_addr
)->sin6_addr
),
1414 rem_ip
, sizeof(rem_ip
));
1415 syslog(LOG_INFO
, "resolved '%s' to '%s'", rem_host
, rem_ip
);
1424 syslog(LOG_WARNING
, "AddPinhole : getaddrinfo(%s) : %s",
1425 rem_host
, gai_strerror(err
));
1427 SoapError(h
, 402, "Invalid Args");
1428 goto clear_and_exit
;
1435 SoapError(h
, 707, "ProtocolWilcardingNotAllowed");
1436 goto clear_and_exit
;
1438 if(proto
!= IPPROTO_UDP
&& proto
!= IPPROTO_TCP
1439 #ifdef IPPROTO_UDPITE
1440 && atoi(protocol
) != IPPROTO_UDPLITE
1444 SoapError(h
, 705, "ProtocolNotSupported");
1445 goto clear_and_exit
;
1447 if(ltime
< 1 || ltime
> 86400)
1449 syslog(LOG_WARNING
, "%s: LeaseTime=%d not supported, (ip=%s)",
1450 action
, ltime
, int_ip
);
1451 SoapError(h
, 402, "Invalid Args");
1452 goto clear_and_exit
;
1455 if(PinholeVerification(h
, int_ip
, iport
) <= 0)
1456 goto clear_and_exit
;
1458 syslog(LOG_INFO
, "%s: (inbound) from [%s]:%hu to [%s]:%hu with proto %ld during %d sec",
1459 action
, rem_host
?rem_host
:"any",
1460 rport
, int_ip
, iport
,
1463 /* In cases where the RemoteHost, RemotePort, InternalPort,
1464 * InternalClient and Protocol are the same than an existing pinhole,
1465 * but LeaseTime is different, the device MUST extend the existing
1466 * pinhole's lease time and return the UniqueID of the existing pinhole. */
1467 r
= upnp_add_inboundpinhole(rem_host
, rport
, int_ip
, iport
, proto
, ltime
, &uid
);
1471 case 1: /* success */
1472 bodylen
= snprintf(body
, sizeof(body
),
1474 "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1476 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1478 case -1: /* not permitted */
1479 SoapError(h
, 701, "PinholeSpaceExhausted");
1482 SoapError(h
, 501, "ActionFailed");
1485 /* 606 Action not authorized
1486 * 701 PinholeSpaceExhausted
1487 * 702 FirewallDisabled
1488 * 703 InboundPinholeNotAllowed
1489 * 705 ProtocolNotSupported
1490 * 706 InternalPortWildcardingNotAllowed
1491 * 707 ProtocolWildcardingNotAllowed
1492 * 708 WildCardNotPermittedInSrcIP */
1494 ClearNameValueList(&data
);
1498 UpdatePinhole(struct upnphttp
* h
, const char * action
)
1500 static const char resp
[] =
1501 "<u:UpdatePinholeResponse "
1502 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1503 "</u:UpdatePinholeResponse>";
1504 struct NameValueParserData data
;
1505 const char * uid_str
, * leaseTime
;
1506 char iaddr
[INET6_ADDRSTRLEN
];
1507 unsigned short iport
;
1512 if(CheckStatus(h
)==0)
1515 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1516 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1517 leaseTime
= GetValueFromNameValueList(&data
, "NewLeaseTime");
1518 uid
= uid_str
? atoi(uid_str
) : -1;
1519 ltime
= leaseTime
? atoi(leaseTime
) : -1;
1520 ClearNameValueList(&data
);
1522 if(uid
< 0 || uid
> 65535 || ltime
<= 0 || ltime
> 86400)
1524 SoapError(h
, 402, "Invalid Args");
1528 /* Check that client is not updating an pinhole
1529 * it doesn't have access to, because of its public access */
1530 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
1531 iaddr
, sizeof(iaddr
), &iport
,
1535 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1540 SoapError(h
, 704, "NoSuchEntry");
1545 SoapError(h
, 501, "ActionFailed");
1549 syslog(LOG_INFO
, "%s: (inbound) updating lease duration to %d for pinhole with ID: %d",
1550 action
, ltime
, uid
);
1552 n
= upnp_update_inboundpinhole(uid
, ltime
);
1554 SoapError(h
, 704, "NoSuchEntry");
1556 SoapError(h
, 501, "ActionFailed");
1558 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
1562 GetOutboundPinholeTimeout(struct upnphttp
* h
, const char * action
)
1566 static const char resp
[] =
1569 "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1574 struct NameValueParserData data
;
1575 char * int_ip
, * int_port
, * rem_host
, * rem_port
, * protocol
;
1577 unsigned short iport
, rport
;
1579 if (!ipv6fc_firewall_enabled
)
1581 SoapError(h
, 702, "FirewallDisabled");
1585 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1586 int_ip
= GetValueFromNameValueList(&data
, "InternalClient");
1587 int_port
= GetValueFromNameValueList(&data
, "InternalPort");
1588 rem_host
= GetValueFromNameValueList(&data
, "RemoteHost");
1589 rem_port
= GetValueFromNameValueList(&data
, "RemotePort");
1590 protocol
= GetValueFromNameValueList(&data
, "Protocol");
1592 rport
= (unsigned short)atoi(rem_port
);
1593 iport
= (unsigned short)atoi(int_port
);
1594 proto
= atoi(protocol
);
1596 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
);
1599 r
= -1;/*upnp_check_outbound_pinhole(proto, &opt);*/
1603 case 1: /* success */
1604 bodylen
= snprintf(body
, sizeof(body
), resp
,
1605 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1607 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1609 case -5: /* Protocol not supported */
1610 SoapError(h
, 705, "ProtocolNotSupported");
1613 SoapError(h
, 501, "ActionFailed");
1615 ClearNameValueList(&data
);
1619 DeletePinhole(struct upnphttp
* h
, const char * action
)
1623 static const char resp
[] =
1624 "<u:DeletePinholeResponse "
1625 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1626 "</u:DeletePinholeResponse>";
1628 struct NameValueParserData data
;
1629 const char * uid_str
;
1630 char iaddr
[INET6_ADDRSTRLEN
];
1632 unsigned short iport
;
1633 unsigned int leasetime
;
1636 if(CheckStatus(h
)==0)
1639 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1640 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1641 uid
= uid_str
? atoi(uid_str
) : -1;
1642 ClearNameValueList(&data
);
1644 if(uid
< 0 || uid
> 65535)
1646 SoapError(h
, 402, "Invalid Args");
1650 /* Check that client is not deleting an pinhole
1651 * it doesn't have access to, because of its public access */
1652 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
1653 iaddr
, sizeof(iaddr
), &iport
,
1654 &proto
, &leasetime
, NULL
);
1657 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1662 SoapError(h
, 704, "NoSuchEntry");
1667 SoapError(h
, 501, "ActionFailed");
1671 n
= upnp_delete_inboundpinhole(uid
);
1674 syslog(LOG_INFO
, "%s: (inbound) failed to remove pinhole with ID: %d",
1676 SoapError(h
, 501, "ActionFailed");
1679 syslog(LOG_INFO
, "%s: (inbound) pinhole with ID %d successfully removed",
1681 BuildSendAndCloseSoapResp(h
, resp
, sizeof(resp
)-1);
1685 CheckPinholeWorking(struct upnphttp
* h
, const char * action
)
1687 static const char resp
[] =
1690 "<IsWorking>%d</IsWorking>"
1695 struct NameValueParserData data
;
1696 const char * uid_str
;
1698 char iaddr
[INET6_ADDRSTRLEN
];
1699 unsigned short iport
;
1700 unsigned int packets
;
1702 if(CheckStatus(h
)==0)
1705 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1706 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1707 uid
= uid_str
? atoi(uid_str
) : -1;
1708 ClearNameValueList(&data
);
1710 if(uid
< 0 || uid
> 65535)
1712 SoapError(h
, 402, "Invalid Args");
1716 /* Check that client is not checking a pinhole
1717 * it doesn't have access to, because of its public access */
1718 r
= upnp_get_pinhole_info(uid
,
1720 iaddr
, sizeof(iaddr
), &iport
,
1721 NULL
, NULL
, &packets
);
1724 if(PinholeVerification(h
, iaddr
, iport
) <= 0)
1728 SoapError(h
, 709, "NoPacketSent");
1731 bodylen
= snprintf(body
, sizeof(body
), resp
,
1732 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1734 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1737 SoapError(h
, 704, "NoSuchEntry");
1739 SoapError(h
, 501, "ActionFailed");
1743 GetPinholePackets(struct upnphttp
* h
, const char * action
)
1745 static const char resp
[] =
1748 "<PinholePackets>%u</PinholePackets>"
1752 struct NameValueParserData data
;
1753 const char * uid_str
;
1755 char iaddr
[INET6_ADDRSTRLEN
];
1756 unsigned short iport
;
1757 unsigned int packets
= 0;
1760 unsigned int leasetime
;
1762 if(CheckStatus(h
)==0)
1765 ParseNameValue(h
->req_buf
+ h
->req_contentoff
, h
->req_contentlen
, &data
);
1766 uid_str
= GetValueFromNameValueList(&data
, "UniqueID");
1767 uid
= uid_str
? atoi(uid_str
) : -1;
1768 ClearNameValueList(&data
);
1770 if(uid
< 0 || uid
> 65535)
1772 SoapError(h
, 402, "Invalid Args");
1776 /* Check that client is not getting infos of a pinhole
1777 * it doesn't have access to, because of its public access */
1778 n
= upnp_get_pinhole_info(uid
, NULL
, 0, NULL
,
1779 iaddr
, sizeof(iaddr
), &iport
,
1780 &proto
, &leasetime
, &packets
);
1783 if(PinholeVerification(h
, iaddr
, iport
)<=0)
1787 else if(r
== -4 || r
== -1)
1789 SoapError(h
, 704, "NoSuchEntry");
1793 bodylen
= snprintf(body
, sizeof(body
), resp
,
1794 action
, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1796 BuildSendAndCloseSoapResp(h
, body
, bodylen
);
1801 /* Windows XP as client send the following requests :
1802 * GetConnectionTypeInfo
1804 * ? GetTotalBytesSent - WANCommonInterfaceConfig
1805 * ? GetTotalBytesReceived - idem
1806 * ? GetTotalPacketsSent - idem
1807 * ? GetTotalPacketsReceived - idem
1808 * GetCommonLinkProperties - idem
1809 * GetStatusInfo - WANIPConnection
1810 * GetExternalIPAddress
1811 * QueryStateVariable / ConnectionStatus!
1815 const char * methodName
;
1816 void (*methodImpl
)(struct upnphttp
*, const char *);
1820 /* WANCommonInterfaceConfig */
1821 { "QueryStateVariable", QueryStateVariable
},
1822 { "GetTotalBytesSent", GetTotalBytesSent
},
1823 { "GetTotalBytesReceived", GetTotalBytesReceived
},
1824 { "GetTotalPacketsSent", GetTotalPacketsSent
},
1825 { "GetTotalPacketsReceived", GetTotalPacketsReceived
},
1826 { "GetCommonLinkProperties", GetCommonLinkProperties
},
1827 { "GetStatusInfo", GetStatusInfo
},
1828 /* WANIPConnection */
1829 { "GetConnectionTypeInfo", GetConnectionTypeInfo
},
1830 { "GetNATRSIPStatus", GetNATRSIPStatus
},
1831 { "GetExternalIPAddress", GetExternalIPAddress
},
1832 { "AddPortMapping", AddPortMapping
},
1833 { "DeletePortMapping", DeletePortMapping
},
1834 { "GetGenericPortMappingEntry", GetGenericPortMappingEntry
},
1835 { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry
},
1836 /* Required in WANIPConnection:2 */
1837 { "SetConnectionType", SetConnectionType
},
1838 { "RequestConnection", RequestConnection
},
1839 { "ForceTermination", ForceTermination
},
1840 { "AddAnyPortMapping", AddAnyPortMapping
},
1841 { "DeletePortMappingRange", DeletePortMappingRange
},
1842 { "GetListOfPortMappings", GetListOfPortMappings
},
1843 #ifdef ENABLE_L3F_SERVICE
1844 /* Layer3Forwarding */
1845 { "SetDefaultConnectionService", SetDefaultConnectionService
},
1846 { "GetDefaultConnectionService", GetDefaultConnectionService
},
1848 #ifdef ENABLE_6FC_SERVICE
1849 /* WANIPv6FirewallControl */
1850 { "GetFirewallStatus", GetFirewallStatus
}, /* Required */
1851 { "AddPinhole", AddPinhole
}, /* Required */
1852 { "UpdatePinhole", UpdatePinhole
}, /* Required */
1853 { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout
}, /* Optional */
1854 { "DeletePinhole", DeletePinhole
}, /* Required */
1855 { "CheckPinholeWorking", CheckPinholeWorking
}, /* Optional */
1856 { "GetPinholePackets", GetPinholePackets
}, /* Required */
1862 ExecuteSoapAction(struct upnphttp
* h
, const char * action
, int n
)
1866 int i
, len
, methodlen
;
1869 p
= strchr(action
, '#');
1874 p2
= strchr(p
, '"');
1878 methodlen
= n
- (p
- action
);
1879 /*syslog(LOG_DEBUG, "SoapMethod: %.*s", methodlen, p);*/
1880 while(soapMethods
[i
].methodName
)
1882 len
= strlen(soapMethods
[i
].methodName
);
1883 if(strncmp(p
, soapMethods
[i
].methodName
, len
) == 0)
1885 soapMethods
[i
].methodImpl(h
, soapMethods
[i
].methodName
);
1891 syslog(LOG_NOTICE
, "SoapMethod: Unknown: %.*s", methodlen
, p
);
1894 SoapError(h
, 401, "Invalid Action");
1899 * errorCode errorDescription Description
1900 * -------- ---------------- -----------
1901 * 401 Invalid Action No action by that name at this service.
1902 * 402 Invalid Args Could be any of the following: not enough in args,
1903 * too many in args, no in arg by that name,
1904 * one or more in args are of the wrong data type.
1905 * 403 Out of Sync Out of synchronization.
1906 * 501 Action Failed May be returned in current state of service
1907 * prevents invoking that action.
1908 * 600-699 TBD Common action errors. Defined by UPnP Forum
1909 * Technical Committee.
1910 * 700-799 TBD Action-specific errors for standard actions.
1911 * Defined by UPnP Forum working committee.
1912 * 800-899 TBD Action-specific errors for non-standard actions.
1913 * Defined by UPnP vendor.
1916 SoapError(struct upnphttp
* h
, int errCode
, const char * errDesc
)
1918 static const char resp
[] =
1920 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
1921 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
1924 "<faultcode>s:Client</faultcode>"
1925 "<faultstring>UPnPError</faultstring>"
1927 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
1928 "<errorCode>%d</errorCode>"
1929 "<errorDescription>%s</errorDescription>"
1939 syslog(LOG_INFO
, "Returning UPnPError %d: %s", errCode
, errDesc
);
1940 bodylen
= snprintf(body
, sizeof(body
), resp
, errCode
, errDesc
);
1941 BuildResp2_upnphttp(h
, 500, "Internal Server Error", body
, bodylen
);
1942 SendRespAndClose_upnphttp(h
);