TOR: fix compilation
[tomato.git] / release / src / router / miniupnpd / upnpsoap.c
blob7febf2f89c2cb083fe5360554a88c8526dc6e460
1 /* $Id: upnpsoap.c,v 1.147 2016/02/20 19:12:00 nanard Exp $ */
2 /* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2016 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <limits.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <sys/socket.h>
14 #include <unistd.h>
15 #include <syslog.h>
16 #include <sys/types.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <netdb.h>
21 #include "macros.h"
22 #include "config.h"
23 #include "upnpglobalvars.h"
24 #include "upnphttp.h"
25 #include "upnpsoap.h"
26 #include "upnpreplyparse.h"
27 #include "upnpredirect.h"
28 #include "upnppinhole.h"
29 #include "getifaddr.h"
30 #include "getifstats.h"
31 #include "getconnstatus.h"
32 #include "upnpurns.h"
34 /* utility function */
35 static int is_numeric(const char * s)
37 while(*s) {
38 if(*s < '0' || *s > '9') return 0;
39 s++;
41 return 1;
44 static void
45 BuildSendAndCloseSoapResp(struct upnphttp * h,
46 const char * body, int bodylen)
48 static const char beforebody[] =
49 "<?xml version=\"1.0\"?>\r\n"
50 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
51 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
52 "<s:Body>";
54 static const char afterbody[] =
55 "</s:Body>"
56 "</s:Envelope>\r\n";
58 int r = BuildHeader_upnphttp(h, 200, "OK", sizeof(beforebody) - 1
59 + sizeof(afterbody) - 1 + bodylen );
61 if(r >= 0) {
62 memcpy(h->res_buf + h->res_buflen, beforebody, sizeof(beforebody) - 1);
63 h->res_buflen += sizeof(beforebody) - 1;
65 memcpy(h->res_buf + h->res_buflen, body, bodylen);
66 h->res_buflen += bodylen;
68 memcpy(h->res_buf + h->res_buflen, afterbody, sizeof(afterbody) - 1);
69 h->res_buflen += sizeof(afterbody) - 1;
70 } else {
71 BuildResp2_upnphttp(h, 500, "Internal Server Error", NULL, 0);
74 SendRespAndClose_upnphttp(h);
77 static void
78 GetConnectionTypeInfo(struct upnphttp * h, const char * action, const char * ns)
80 #if 0
81 static const char resp[] =
82 "<u:GetConnectionTypeInfoResponse "
83 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
84 "<NewConnectionType>IP_Routed</NewConnectionType>"
85 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
86 "</u:GetConnectionTypeInfoResponse>";
87 #endif
88 static const char resp[] =
89 "<u:%sResponse "
90 "xmlns:u=\"%s\">"
91 "<NewConnectionType>IP_Routed</NewConnectionType>"
92 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
93 "</u:%sResponse>";
94 char body[512];
95 int bodylen;
97 bodylen = snprintf(body, sizeof(body), resp,
98 action, ns, action);
99 BuildSendAndCloseSoapResp(h, body, bodylen);
102 /* maximum value for a UPNP ui4 type variable */
103 #define UPNP_UI4_MAX (4294967295ul)
105 static void
106 GetTotalBytesSent(struct upnphttp * h, const char * action, const char * ns)
108 int r;
110 static const char resp[] =
111 "<u:%sResponse "
112 "xmlns:u=\"%s\">"
113 "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
114 "</u:%sResponse>";
116 char body[512];
117 int bodylen;
118 struct ifdata data;
120 r = getifstats(ext_if_name, &data);
121 bodylen = snprintf(body, sizeof(body), resp,
122 action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
123 #ifdef UPNP_STRICT
124 r<0?0:(data.obytes & UPNP_UI4_MAX), action);
125 #else /* UPNP_STRICT */
126 r<0?0:data.obytes, action);
127 #endif /* UPNP_STRICT */
128 BuildSendAndCloseSoapResp(h, body, bodylen);
131 static void
132 GetTotalBytesReceived(struct upnphttp * h, const char * action, const char * ns)
134 int r;
136 static const char resp[] =
137 "<u:%sResponse "
138 "xmlns:u=\"%s\">"
139 "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
140 "</u:%sResponse>";
142 char body[512];
143 int bodylen;
144 struct ifdata data;
146 r = getifstats(ext_if_name, &data);
147 /* TotalBytesReceived
148 * This variable represents the cumulative counter for total number of
149 * bytes received downstream across all connection service instances on
150 * WANDevice. The count rolls over to 0 after it reaching the maximum
151 * value (2^32)-1. */
152 bodylen = snprintf(body, sizeof(body), resp,
153 action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
154 #ifdef UPNP_STRICT
155 r<0?0:(data.ibytes & UPNP_UI4_MAX), action);
156 #else /* UPNP_STRICT */
157 r<0?0:data.ibytes, action);
158 #endif /* UPNP_STRICT */
159 BuildSendAndCloseSoapResp(h, body, bodylen);
162 static void
163 GetTotalPacketsSent(struct upnphttp * h, const char * action, const char * ns)
165 int r;
167 static const char resp[] =
168 "<u:%sResponse "
169 "xmlns:u=\"%s\">"
170 "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
171 "</u:%sResponse>";
173 char body[512];
174 int bodylen;
175 struct ifdata data;
177 r = getifstats(ext_if_name, &data);
178 bodylen = snprintf(body, sizeof(body), resp,
179 action, ns,/*"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",*/
180 #ifdef UPNP_STRICT
181 r<0?0:(data.opackets & UPNP_UI4_MAX), action);
182 #else /* UPNP_STRICT */
183 r<0?0:data.opackets, action);
184 #endif /* UPNP_STRICT */
185 BuildSendAndCloseSoapResp(h, body, bodylen);
188 static void
189 GetTotalPacketsReceived(struct upnphttp * h, const char * action, const char * ns)
191 int r;
193 static const char resp[] =
194 "<u:%sResponse "
195 "xmlns:u=\"%s\">"
196 "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
197 "</u:%sResponse>";
199 char body[512];
200 int bodylen;
201 struct ifdata data;
203 r = getifstats(ext_if_name, &data);
204 bodylen = snprintf(body, sizeof(body), resp,
205 action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
206 #ifdef UPNP_STRICT
207 r<0?0:(data.ipackets & UPNP_UI4_MAX), action);
208 #else /* UPNP_STRICT */
209 r<0?0:data.ipackets, action);
210 #endif /* UPNP_STRICT */
211 BuildSendAndCloseSoapResp(h, body, bodylen);
214 static void
215 GetCommonLinkProperties(struct upnphttp * h, const char * action, const char * ns)
217 /* WANAccessType : set depending on the hardware :
218 * DSL, POTS (plain old Telephone service), Cable, Ethernet */
219 static const char resp[] =
220 "<u:%sResponse "
221 "xmlns:u=\"%s\">"
222 "<NewWANAccessType>%s</NewWANAccessType>"
223 "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
224 "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
225 "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
226 "</u:%sResponse>";
228 char body[2048];
229 int bodylen;
230 struct ifdata data;
231 const char * status = "Up"; /* Up, Down (Required),
232 * Initializing, Unavailable (Optional) */
233 const char * wan_access_type = "Cable"; /* DSL, POTS, Cable, Ethernet */
234 char ext_ip_addr[INET_ADDRSTRLEN];
236 if((downstream_bitrate == 0) || (upstream_bitrate == 0))
238 if(getifstats(ext_if_name, &data) >= 0)
240 if(downstream_bitrate == 0) downstream_bitrate = data.baudrate;
241 if(upstream_bitrate == 0) upstream_bitrate = data.baudrate;
244 if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, NULL, NULL) < 0) {
245 status = "Down";
247 bodylen = snprintf(body, sizeof(body), resp,
248 action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
249 wan_access_type,
250 upstream_bitrate, downstream_bitrate,
251 status, action);
252 BuildSendAndCloseSoapResp(h, body, bodylen);
255 static void
256 GetStatusInfo(struct upnphttp * h, const char * action, const char * ns)
258 static const char resp[] =
259 "<u:%sResponse "
260 "xmlns:u=\"%s\">"
261 "<NewConnectionStatus>%s</NewConnectionStatus>"
262 "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
263 "<NewUptime>%ld</NewUptime>"
264 "</u:%sResponse>";
266 char body[512];
267 int bodylen;
268 time_t uptime;
269 const char * status;
270 /* ConnectionStatus possible values :
271 * Unconfigured, Connecting, Connected, PendingDisconnect,
272 * Disconnecting, Disconnected */
274 status = get_wan_connection_status_str(ext_if_name);
275 uptime = (time(NULL) - startup_time);
276 bodylen = snprintf(body, sizeof(body), resp,
277 action, ns, /*SERVICE_TYPE_WANIPC,*/
278 status, (long)uptime, action);
279 BuildSendAndCloseSoapResp(h, body, bodylen);
282 static void
283 GetNATRSIPStatus(struct upnphttp * h, const char * action, const char * ns)
285 #if 0
286 static const char resp[] =
287 "<u:GetNATRSIPStatusResponse "
288 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
289 "<NewRSIPAvailable>0</NewRSIPAvailable>"
290 "<NewNATEnabled>1</NewNATEnabled>"
291 "</u:GetNATRSIPStatusResponse>";
292 UNUSED(action);
293 #endif
294 static const char resp[] =
295 "<u:%sResponse "
296 "xmlns:u=\"%s\">"
297 "<NewRSIPAvailable>0</NewRSIPAvailable>"
298 "<NewNATEnabled>1</NewNATEnabled>"
299 "</u:%sResponse>";
300 char body[512];
301 int bodylen;
302 /* 2.2.9. RSIPAvailable
303 * This variable indicates if Realm-specific IP (RSIP) is available
304 * as a feature on the InternetGatewayDevice. RSIP is being defined
305 * in the NAT working group in the IETF to allow host-NATing using
306 * a standard set of message exchanges. It also allows end-to-end
307 * applications that otherwise break if NAT is introduced
308 * (e.g. IPsec-based VPNs).
309 * A gateway that does not support RSIP should set this variable to 0. */
310 bodylen = snprintf(body, sizeof(body), resp,
311 action, ns, /*SERVICE_TYPE_WANIPC,*/
312 action);
313 BuildSendAndCloseSoapResp(h, body, bodylen);
316 static void
317 GetExternalIPAddress(struct upnphttp * h, const char * action, const char * ns)
319 static const char resp[] =
320 "<u:%sResponse "
321 "xmlns:u=\"%s\">"
322 "<NewExternalIPAddress>%s</NewExternalIPAddress>"
323 "</u:%sResponse>";
325 char body[512];
326 int bodylen;
327 char ext_ip_addr[INET_ADDRSTRLEN];
328 /* Does that method need to work with IPv6 ?
329 * There is usually no NAT with IPv6 */
331 #ifndef MULTIPLE_EXTERNAL_IP
332 if(use_ext_ip_addr)
334 strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN);
335 ext_ip_addr[INET_ADDRSTRLEN - 1] = '\0';
337 else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, NULL, NULL) < 0)
339 syslog(LOG_ERR, "Failed to get ip address for interface %s",
340 ext_if_name);
341 strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
343 #else
344 struct lan_addr_s * lan_addr;
345 strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
346 for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
348 if( (h->clientaddr.s_addr & lan_addr->mask.s_addr)
349 == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
351 strncpy(ext_ip_addr, lan_addr->ext_ip_str, INET_ADDRSTRLEN);
352 break;
355 #endif
356 bodylen = snprintf(body, sizeof(body), resp,
357 action, ns, /*SERVICE_TYPE_WANIPC,*/
358 ext_ip_addr, action);
359 BuildSendAndCloseSoapResp(h, body, bodylen);
362 /* AddPortMapping method of WANIPConnection Service
363 * Ignored argument : NewEnabled */
364 static void
365 AddPortMapping(struct upnphttp * h, const char * action, const char * ns)
367 int r;
369 /*static const char resp[] =
370 "<u:AddPortMappingResponse "
371 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";*/
372 static const char resp[] =
373 "<u:%sResponse "
374 "xmlns:u=\"%s\"/>";
376 char body[512];
377 int bodylen;
378 struct NameValueParserData data;
379 char * int_ip, * int_port, * ext_port, * protocol, * desc;
380 char * leaseduration_str;
381 unsigned int leaseduration;
382 char * r_host;
383 unsigned short iport, eport;
385 struct hostent *hp; /* getbyhostname() */
386 char ** ptr; /* getbyhostname() */
387 struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
389 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
390 int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
391 if (!int_ip)
393 ClearNameValueList(&data);
394 SoapError(h, 402, "Invalid Args");
395 return;
398 /* IGD 2 MUST support both wildcard and specific IP address values
399 * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
400 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
401 #ifndef SUPPORT_REMOTEHOST
402 #ifdef UPNP_STRICT
403 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
405 ClearNameValueList(&data);
406 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
407 return;
409 #endif
410 #endif
412 /* if ip not valid assume hostname and convert */
413 if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
415 hp = gethostbyname(int_ip);
416 if(hp && hp->h_addrtype == AF_INET)
418 for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
420 int_ip = inet_ntoa(*((struct in_addr *) *ptr));
421 result_ip = *((struct in_addr *) *ptr);
422 /* TODO : deal with more than one ip per hostname */
423 break;
426 else
428 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
429 ClearNameValueList(&data);
430 SoapError(h, 402, "Invalid Args");
431 return;
435 /* check if NewInternalAddress is the client address */
436 if(GETFLAG(SECUREMODEMASK))
438 if(h->clientaddr.s_addr != result_ip.s_addr)
440 syslog(LOG_INFO, "Client %s tried to redirect port to %s",
441 inet_ntoa(h->clientaddr), int_ip);
442 ClearNameValueList(&data);
443 SoapError(h, 718, "ConflictInMappingEntry");
444 return;
448 int_port = GetValueFromNameValueList(&data, "NewInternalPort");
449 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
450 protocol = GetValueFromNameValueList(&data, "NewProtocol");
451 desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
452 leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
454 if (!int_port || !ext_port || !protocol)
456 ClearNameValueList(&data);
457 SoapError(h, 402, "Invalid Args");
458 return;
461 eport = (unsigned short)atoi(ext_port);
462 iport = (unsigned short)atoi(int_port);
464 if (strcmp(ext_port, "*") == 0 || eport == 0)
466 ClearNameValueList(&data);
467 SoapError(h, 716, "Wildcard not permited in ExtPort");
468 return;
471 leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
472 #ifdef IGD_V2
473 /* PortMappingLeaseDuration can be either a value between 1 and
474 * 604800 seconds or the zero value (for infinite lease time).
475 * Note that an infinite lease time can be only set by out-of-band
476 * mechanisms like WWW-administration, remote management or local
477 * management.
478 * If a control point uses the value 0 to indicate an infinite lease
479 * time mapping, it is REQUIRED that gateway uses the maximum value
480 * instead (e.g. 604800 seconds) */
481 if(leaseduration == 0 || leaseduration > 604800)
482 leaseduration = 604800;
483 #endif
485 syslog(LOG_INFO, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
486 action, eport, int_ip, iport, protocol, desc, leaseduration,
487 r_host ? r_host : "NULL");
489 r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
491 ClearNameValueList(&data);
493 /* possible error codes for AddPortMapping :
494 * 402 - Invalid Args
495 * 501 - Action Failed
496 * 715 - Wildcard not permited in SrcAddr
497 * 716 - Wildcard not permited in ExtPort
498 * 718 - ConflictInMappingEntry
499 * 724 - SamePortValuesRequired (deprecated in IGD v2)
500 * 725 - OnlyPermanentLeasesSupported
501 The NAT implementation only supports permanent lease times on
502 port mappings (deprecated in IGD v2)
503 * 726 - RemoteHostOnlySupportsWildcard
504 RemoteHost must be a wildcard and cannot be a specific IP
505 address or DNS name (deprecated in IGD v2)
506 * 727 - ExternalPortOnlySupportsWildcard
507 ExternalPort must be a wildcard and cannot be a specific port
508 value (deprecated in IGD v2)
509 * 728 - NoPortMapsAvailable
510 There are not enough free ports available to complete the mapping
511 (added in IGD v2)
512 * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
513 switch(r)
515 case 0: /* success */
516 bodylen = snprintf(body, sizeof(body), resp,
517 action, ns/*SERVICE_TYPE_WANIPC*/);
518 BuildSendAndCloseSoapResp(h, body, bodylen);
519 break;
520 case -4:
521 #ifdef IGD_V2
522 SoapError(h, 729, "ConflictWithOtherMechanisms");
523 break;
524 #endif /* IGD_V2 */
525 case -2: /* already redirected */
526 case -3: /* not permitted */
527 SoapError(h, 718, "ConflictInMappingEntry");
528 break;
529 default:
530 SoapError(h, 501, "ActionFailed");
534 /* AddAnyPortMapping was added in WANIPConnection v2 */
535 static void
536 AddAnyPortMapping(struct upnphttp * h, const char * action, const char * ns)
538 int r;
539 static const char resp[] =
540 "<u:%sResponse "
541 "xmlns:u=\"%s\">"
542 "<NewReservedPort>%hu</NewReservedPort>"
543 "</u:%sResponse>";
545 char body[512];
546 int bodylen;
548 struct NameValueParserData data;
549 const char * int_ip, * int_port, * ext_port, * protocol, * desc;
550 const char * r_host;
551 unsigned short iport, eport;
552 const char * leaseduration_str;
553 unsigned int leaseduration;
555 struct hostent *hp; /* getbyhostname() */
556 char ** ptr; /* getbyhostname() */
557 struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
559 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
560 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
561 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
562 protocol = GetValueFromNameValueList(&data, "NewProtocol");
563 int_port = GetValueFromNameValueList(&data, "NewInternalPort");
564 int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
565 /* NewEnabled */
566 desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
567 leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
569 leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
570 if(leaseduration == 0)
571 leaseduration = 604800;
573 if (!int_ip || !ext_port || !int_port)
575 ClearNameValueList(&data);
576 SoapError(h, 402, "Invalid Args");
577 return;
580 eport = (unsigned short)atoi(ext_port);
581 iport = (unsigned short)atoi(int_port);
582 if(iport == 0 || !is_numeric(ext_port)) {
583 ClearNameValueList(&data);
584 SoapError(h, 402, "Invalid Args");
585 return;
587 #ifndef SUPPORT_REMOTEHOST
588 #ifdef UPNP_STRICT
589 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
591 ClearNameValueList(&data);
592 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
593 return;
595 #endif
596 #endif
598 /* if ip not valid assume hostname and convert */
599 if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
601 hp = gethostbyname(int_ip);
602 if(hp && hp->h_addrtype == AF_INET)
604 for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
606 int_ip = inet_ntoa(*((struct in_addr *) *ptr));
607 result_ip = *((struct in_addr *) *ptr);
608 /* TODO : deal with more than one ip per hostname */
609 break;
612 else
614 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
615 ClearNameValueList(&data);
616 SoapError(h, 402, "Invalid Args");
617 return;
621 /* check if NewInternalAddress is the client address */
622 if(GETFLAG(SECUREMODEMASK))
624 if(h->clientaddr.s_addr != result_ip.s_addr)
626 syslog(LOG_INFO, "Client %s tried to redirect port to %s",
627 inet_ntoa(h->clientaddr), int_ip);
628 ClearNameValueList(&data);
629 SoapError(h, 606, "Action not authorized");
630 return;
634 /* TODO : accept a different external port
635 * have some smart strategy to choose the port */
636 for(;;) {
637 r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
638 if(r==-2 && eport < 65535) {
639 eport++;
640 } else {
641 break;
645 ClearNameValueList(&data);
647 switch(r)
649 case 0: /* success */
650 bodylen = snprintf(body, sizeof(body), resp,
651 action, ns, /*SERVICE_TYPE_WANIPC,*/
652 eport, action);
653 BuildSendAndCloseSoapResp(h, body, bodylen);
654 break;
655 case -2: /* already redirected */
656 SoapError(h, 718, "ConflictInMappingEntry");
657 break;
658 case -3: /* not permitted */
659 SoapError(h, 606, "Action not authorized");
660 break;
661 default:
662 SoapError(h, 501, "ActionFailed");
666 static void
667 GetSpecificPortMappingEntry(struct upnphttp * h, const char * action, const char * ns)
669 int r;
671 static const char resp[] =
672 "<u:%sResponse "
673 "xmlns:u=\"%s\">"
674 "<NewInternalPort>%u</NewInternalPort>"
675 "<NewInternalClient>%s</NewInternalClient>"
676 "<NewEnabled>1</NewEnabled>"
677 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
678 "<NewLeaseDuration>%u</NewLeaseDuration>"
679 "</u:%sResponse>";
681 char body[1024];
682 int bodylen;
683 struct NameValueParserData data;
684 const char * r_host, * ext_port, * protocol;
685 unsigned short eport, iport;
686 char int_ip[32];
687 char desc[64];
688 unsigned int leaseduration = 0;
690 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
691 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
692 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
693 protocol = GetValueFromNameValueList(&data, "NewProtocol");
695 #ifdef UPNP_STRICT
696 if(!ext_port || !protocol || !r_host)
697 #else
698 if(!ext_port || !protocol)
699 #endif
701 ClearNameValueList(&data);
702 SoapError(h, 402, "Invalid Args");
703 return;
705 #ifndef SUPPORT_REMOTEHOST
706 #ifdef UPNP_STRICT
707 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
709 ClearNameValueList(&data);
710 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
711 return;
713 #endif
714 #endif
716 eport = (unsigned short)atoi(ext_port);
717 if(eport == 0)
719 ClearNameValueList(&data);
720 SoapError(h, 402, "Invalid Args");
721 return;
724 /* TODO : add r_host as an input parameter ...
725 * We prevent several Port Mapping with same external port
726 * but different remoteHost to be set up, so that is not
727 * a priority. */
728 r = upnp_get_redirection_infos(eport, protocol, &iport,
729 int_ip, sizeof(int_ip),
730 desc, sizeof(desc),
731 NULL, 0,
732 &leaseduration);
734 if(r < 0)
736 SoapError(h, 714, "NoSuchEntryInArray");
738 else
740 syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
741 action,
742 r_host ? r_host : "NULL", ext_port, protocol, int_ip,
743 (unsigned int)iport, desc);
744 bodylen = snprintf(body, sizeof(body), resp,
745 action, ns/*SERVICE_TYPE_WANIPC*/,
746 (unsigned int)iport, int_ip, desc, leaseduration,
747 action);
748 BuildSendAndCloseSoapResp(h, body, bodylen);
751 ClearNameValueList(&data);
754 static void
755 DeletePortMapping(struct upnphttp * h, const char * action, const char * ns)
757 int r;
759 /*static const char resp[] =
760 "<u:DeletePortMappingResponse "
761 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
762 "</u:DeletePortMappingResponse>";*/
763 static const char resp[] =
764 "<u:%sResponse "
765 "xmlns:u=\"%s\">"
766 "</u:%sResponse>";
768 char body[512];
769 int bodylen;
770 struct NameValueParserData data;
771 const char * ext_port, * protocol;
772 unsigned short eport;
773 #ifdef UPNP_STRICT
774 const char * r_host;
775 #endif /* UPNP_STRICT */
777 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
778 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
779 protocol = GetValueFromNameValueList(&data, "NewProtocol");
780 #ifdef UPNP_STRICT
781 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
782 #endif /* UPNP_STRICT */
784 #ifdef UPNP_STRICT
785 if(!ext_port || !protocol || !r_host)
786 #else
787 if(!ext_port || !protocol)
788 #endif /* UPNP_STRICT */
790 ClearNameValueList(&data);
791 SoapError(h, 402, "Invalid Args");
792 return;
794 #ifndef SUPPORT_REMOTEHOST
795 #ifdef UPNP_STRICT
796 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
798 ClearNameValueList(&data);
799 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
800 return;
802 #endif /* UPNP_STRICT */
803 #endif /* SUPPORT_REMOTEHOST */
805 eport = (unsigned short)atoi(ext_port);
806 if(eport == 0)
808 ClearNameValueList(&data);
809 SoapError(h, 402, "Invalid Args");
810 return;
813 syslog(LOG_INFO, "%s: external port: %hu, protocol: %s",
814 action, eport, protocol);
816 /* if in secure mode, check the IP
817 * Removing a redirection is not a security threat,
818 * just an annoyance for the user using it. So this is not
819 * a priority. */
820 if(GETFLAG(SECUREMODEMASK))
822 char int_ip[32];
823 struct in_addr int_ip_addr;
824 unsigned short iport;
825 unsigned int leaseduration = 0;
826 r = upnp_get_redirection_infos(eport, protocol, &iport,
827 int_ip, sizeof(int_ip),
828 NULL, 0, NULL, 0,
829 &leaseduration);
830 if(r >= 0)
832 if(inet_pton(AF_INET, int_ip, &int_ip_addr) > 0)
834 if(h->clientaddr.s_addr != int_ip_addr.s_addr)
836 SoapError(h, 606, "Action not authorized");
837 /*SoapError(h, 714, "NoSuchEntryInArray");*/
838 ClearNameValueList(&data);
839 return;
845 r = upnp_delete_redirection(eport, protocol);
847 if(r < 0)
849 SoapError(h, 714, "NoSuchEntryInArray");
851 else
853 bodylen = snprintf(body, sizeof(body), resp,
854 action, ns, action);
855 BuildSendAndCloseSoapResp(h, body, bodylen);
858 ClearNameValueList(&data);
861 /* DeletePortMappingRange was added in IGD spec v2 */
862 static void
863 DeletePortMappingRange(struct upnphttp * h, const char * action, const char * ns)
865 int r = -1;
866 /*static const char resp[] =
867 "<u:DeletePortMappingRangeResponse "
868 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
869 "</u:DeletePortMappingRangeResponse>";*/
870 static const char resp[] =
871 "<u:%sResponse "
872 "xmlns:u=\"%s\">"
873 "</u:%sResponse>";
874 char body[512];
875 int bodylen;
876 struct NameValueParserData data;
877 const char * protocol;
878 const char * startport_s, * endport_s;
879 unsigned short startport, endport;
880 /*int manage;*/
881 unsigned short * port_list;
882 unsigned int i, number = 0;
884 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
885 startport_s = GetValueFromNameValueList(&data, "NewStartPort");
886 endport_s = GetValueFromNameValueList(&data, "NewEndPort");
887 protocol = GetValueFromNameValueList(&data, "NewProtocol");
888 /*manage = atoi(GetValueFromNameValueList(&data, "NewManage"));*/
889 if(startport_s == NULL || endport_s == NULL || protocol == NULL ||
890 !is_numeric(startport_s) || !is_numeric(endport_s)) {
891 SoapError(h, 402, "Invalid Args");
892 ClearNameValueList(&data);
893 return;
895 startport = (unsigned short)atoi(startport_s);
896 endport = (unsigned short)atoi(endport_s);
898 /* possible errors :
899 606 - Action not authorized
900 730 - PortMappingNotFound
901 733 - InconsistentParameter
903 if(startport > endport)
905 SoapError(h, 733, "InconsistentParameter");
906 ClearNameValueList(&data);
907 return;
910 syslog(LOG_INFO, "%s: deleting external ports: %hu-%hu, protocol: %s",
911 action, startport, endport, protocol);
913 port_list = upnp_get_portmappings_in_range(startport, endport,
914 protocol, &number);
915 if(number == 0)
917 SoapError(h, 730, "PortMappingNotFound");
918 ClearNameValueList(&data);
919 free(port_list);
920 return;
923 for(i = 0; i < number; i++)
925 r = upnp_delete_redirection(port_list[i], protocol);
926 syslog(LOG_INFO, "%s: deleting external port: %hu, protocol: %s: %s",
927 action, port_list[i], protocol, r < 0 ? "failed" : "ok");
929 free(port_list);
930 bodylen = snprintf(body, sizeof(body), resp,
931 action, ns, action);
932 BuildSendAndCloseSoapResp(h, body, bodylen);
934 ClearNameValueList(&data);
937 static void
938 GetGenericPortMappingEntry(struct upnphttp * h, const char * action, const char * ns)
940 int r;
942 static const char resp[] =
943 "<u:%sResponse "
944 "xmlns:u=\"%s\">"
945 "<NewRemoteHost>%s</NewRemoteHost>"
946 "<NewExternalPort>%u</NewExternalPort>"
947 "<NewProtocol>%s</NewProtocol>"
948 "<NewInternalPort>%u</NewInternalPort>"
949 "<NewInternalClient>%s</NewInternalClient>"
950 "<NewEnabled>1</NewEnabled>"
951 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
952 "<NewLeaseDuration>%u</NewLeaseDuration>"
953 "</u:%sResponse>";
955 long int index = 0;
956 unsigned short eport, iport;
957 const char * m_index;
958 char * endptr;
959 char protocol[8], iaddr[32];
960 char desc[64];
961 char rhost[40];
962 unsigned int leaseduration = 0;
963 struct NameValueParserData data;
965 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
966 m_index = GetValueFromNameValueList(&data, "NewPortMappingIndex");
968 if(!m_index)
970 ClearNameValueList(&data);
971 SoapError(h, 402, "Invalid Args");
972 return;
974 errno = 0; /* To distinguish success/failure after call */
975 index = strtol(m_index, &endptr, 10);
976 if((errno == ERANGE && (index == LONG_MAX || index == LONG_MIN))
977 || (errno != 0 && index == 0) || (m_index == endptr))
979 /* should condition (*endptr != '\0') be also an error ? */
980 if(m_index == endptr)
981 syslog(LOG_WARNING, "%s: no digits were found in <%s>",
982 "GetGenericPortMappingEntry", "NewPortMappingIndex");
983 else
984 syslog(LOG_WARNING, "%s: strtol('%s'): %m",
985 "GetGenericPortMappingEntry", m_index);
986 ClearNameValueList(&data);
987 SoapError(h, 402, "Invalid Args");
988 return;
991 syslog(LOG_INFO, "%s: index=%d", action, (int)index);
993 rhost[0] = '\0';
994 r = upnp_get_redirection_infos_by_index((int)index, &eport, protocol, &iport,
995 iaddr, sizeof(iaddr),
996 desc, sizeof(desc),
997 rhost, sizeof(rhost),
998 &leaseduration);
1000 if(r < 0)
1002 SoapError(h, 713, "SpecifiedArrayIndexInvalid");
1004 else
1006 int bodylen;
1007 char body[2048];
1008 bodylen = snprintf(body, sizeof(body), resp,
1009 action, ns, /*SERVICE_TYPE_WANIPC,*/ rhost,
1010 (unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc,
1011 leaseduration, action);
1012 BuildSendAndCloseSoapResp(h, body, bodylen);
1015 ClearNameValueList(&data);
1018 /* GetListOfPortMappings was added in the IGD v2 specification */
1019 static void
1020 GetListOfPortMappings(struct upnphttp * h, const char * action, const char * ns)
1022 static const char resp_start[] =
1023 "<u:%sResponse "
1024 "xmlns:u=\"%s\">"
1025 "<NewPortListing><![CDATA[";
1026 static const char resp_end[] =
1027 "]]></NewPortListing>"
1028 "</u:%sResponse>";
1030 static const char list_start[] =
1031 "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
1032 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
1033 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
1034 " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
1035 static const char list_end[] =
1036 "</p:PortMappingList>";
1038 static const char entry[] =
1039 "<p:PortMappingEntry>"
1040 "<p:NewRemoteHost>%s</p:NewRemoteHost>"
1041 "<p:NewExternalPort>%hu</p:NewExternalPort>"
1042 "<p:NewProtocol>%s</p:NewProtocol>"
1043 "<p:NewInternalPort>%hu</p:NewInternalPort>"
1044 "<p:NewInternalClient>%s</p:NewInternalClient>"
1045 "<p:NewEnabled>1</p:NewEnabled>"
1046 "<p:NewDescription>%s</p:NewDescription>"
1047 "<p:NewLeaseTime>%u</p:NewLeaseTime>"
1048 "</p:PortMappingEntry>";
1050 char * body;
1051 size_t bodyalloc;
1052 int bodylen;
1054 int r = -1;
1055 unsigned short iport;
1056 char int_ip[32];
1057 char desc[64];
1058 char rhost[64];
1059 unsigned int leaseduration = 0;
1061 struct NameValueParserData data;
1062 const char * startport_s, * endport_s;
1063 unsigned short startport, endport;
1064 const char * protocol;
1065 /*int manage;*/
1066 const char * number_s;
1067 int number;
1068 unsigned short * port_list;
1069 unsigned int i, list_size = 0;
1071 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1072 startport_s = GetValueFromNameValueList(&data, "NewStartPort");
1073 endport_s = GetValueFromNameValueList(&data, "NewEndPort");
1074 protocol = GetValueFromNameValueList(&data, "NewProtocol");
1075 /*manage_s = GetValueFromNameValueList(&data, "NewManage");*/
1076 number_s = GetValueFromNameValueList(&data, "NewNumberOfPorts");
1077 if(startport_s == NULL || endport_s == NULL || protocol == NULL ||
1078 number_s == NULL || !is_numeric(number_s) ||
1079 !is_numeric(startport_s) || !is_numeric(endport_s)) {
1080 SoapError(h, 402, "Invalid Args");
1081 ClearNameValueList(&data);
1082 return;
1085 startport = (unsigned short)atoi(startport_s);
1086 endport = (unsigned short)atoi(endport_s);
1087 /*manage = atoi(manage_s);*/
1088 number = atoi(number_s);
1089 if(number == 0) number = 1000; /* return up to 1000 mappings by default */
1091 if(startport > endport)
1093 SoapError(h, 733, "InconsistentParameter");
1094 ClearNameValueList(&data);
1095 return;
1098 build the PortMappingList xml document :
1100 <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
1101 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1102 xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
1103 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
1104 <p:PortMappingEntry>
1105 <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
1106 <p:NewExternalPort>2345</p:NewExternalPort>
1107 <p:NewProtocol>TCP</p:NewProtocol>
1108 <p:NewInternalPort>2345</p:NewInternalPort>
1109 <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
1110 <p:NewEnabled>1</p:NewEnabled>
1111 <p:NewDescription>dooom</p:NewDescription>
1112 <p:NewLeaseTime>345</p:NewLeaseTime>
1113 </p:PortMappingEntry>
1114 </p:PortMappingList>
1116 bodyalloc = 4096;
1117 body = malloc(bodyalloc);
1118 if(!body)
1120 ClearNameValueList(&data);
1121 SoapError(h, 501, "ActionFailed");
1122 return;
1124 bodylen = snprintf(body, bodyalloc, resp_start,
1125 action, ns/*SERVICE_TYPE_WANIPC*/);
1126 if(bodylen < 0)
1128 SoapError(h, 501, "ActionFailed");
1129 free(body);
1130 return;
1132 memcpy(body+bodylen, list_start, sizeof(list_start));
1133 bodylen += (sizeof(list_start) - 1);
1135 port_list = upnp_get_portmappings_in_range(startport, endport,
1136 protocol, &list_size);
1137 /* loop through port mappings */
1138 for(i = 0; number > 0 && i < list_size; i++)
1140 /* have a margin of 1024 bytes to store the new entry */
1141 if((unsigned int)bodylen + 1024 > bodyalloc)
1143 char * body_sav = body;
1144 bodyalloc += 4096;
1145 body = realloc(body, bodyalloc);
1146 if(!body)
1148 syslog(LOG_CRIT, "realloc(%p, %u) FAILED", body_sav, (unsigned)bodyalloc);
1149 ClearNameValueList(&data);
1150 SoapError(h, 501, "ActionFailed");
1151 free(body_sav);
1152 free(port_list);
1153 return;
1156 rhost[0] = '\0';
1157 r = upnp_get_redirection_infos(port_list[i], protocol, &iport,
1158 int_ip, sizeof(int_ip),
1159 desc, sizeof(desc),
1160 rhost, sizeof(rhost),
1161 &leaseduration);
1162 if(r == 0)
1164 bodylen += snprintf(body+bodylen, bodyalloc-bodylen, entry,
1165 rhost, port_list[i], protocol,
1166 iport, int_ip, desc, leaseduration);
1167 number--;
1170 free(port_list);
1171 port_list = NULL;
1173 if((bodylen + sizeof(list_end) + 1024) > bodyalloc)
1175 char * body_sav = body;
1176 bodyalloc += (sizeof(list_end) + 1024);
1177 body = realloc(body, bodyalloc);
1178 if(!body)
1180 syslog(LOG_CRIT, "realloc(%p, %u) FAILED", body_sav, (unsigned)bodyalloc);
1181 ClearNameValueList(&data);
1182 SoapError(h, 501, "ActionFailed");
1183 free(body_sav);
1184 return;
1187 memcpy(body+bodylen, list_end, sizeof(list_end));
1188 bodylen += (sizeof(list_end) - 1);
1189 bodylen += snprintf(body+bodylen, bodyalloc-bodylen, resp_end,
1190 action);
1191 BuildSendAndCloseSoapResp(h, body, bodylen);
1192 free(body);
1194 ClearNameValueList(&data);
1197 #ifdef ENABLE_L3F_SERVICE
1198 static void
1199 SetDefaultConnectionService(struct upnphttp * h, const char * action, const char * ns)
1201 /*static const char resp[] =
1202 "<u:SetDefaultConnectionServiceResponse "
1203 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1204 "</u:SetDefaultConnectionServiceResponse>";*/
1205 static const char resp[] =
1206 "<u:%sResponse "
1207 "xmlns:u=\"%s\">"
1208 "</u:%sResponse>";
1209 char body[512];
1210 int bodylen;
1211 struct NameValueParserData data;
1212 char * p;
1213 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1214 p = GetValueFromNameValueList(&data, "NewDefaultConnectionService");
1215 if(p) {
1216 /* 720 InvalidDeviceUUID
1217 * 721 InvalidServiceID
1218 * 723 InvalidConnServiceSelection */
1219 #ifdef UPNP_STRICT
1220 char * service;
1221 service = strchr(p, ',');
1222 if(0 != memcmp(uuidvalue_wcd, p, sizeof("uuid:00000000-0000-0000-0000-000000000000") - 1)) {
1223 SoapError(h, 720, "InvalidDeviceUUID");
1224 } else if(service == NULL || 0 != strcmp(service+1, SERVICE_ID_WANIPC)) {
1225 SoapError(h, 721, "InvalidServiceID");
1226 } else
1227 #endif
1229 syslog(LOG_INFO, "%s(%s) : Ignored", action, p);
1230 bodylen = snprintf(body, sizeof(body), resp,
1231 action, ns, action);
1232 BuildSendAndCloseSoapResp(h, body, bodylen);
1234 } else {
1235 /* missing argument */
1236 SoapError(h, 402, "Invalid Args");
1238 ClearNameValueList(&data);
1241 static void
1242 GetDefaultConnectionService(struct upnphttp * h, const char * action, const char * ns)
1244 static const char resp[] =
1245 "<u:%sResponse "
1246 "xmlns:u=\"%s\">"
1247 #ifdef IGD_V2
1248 "<NewDefaultConnectionService>%s:WANConnectionDevice:2,"
1249 #else
1250 "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
1251 #endif
1252 SERVICE_ID_WANIPC "</NewDefaultConnectionService>"
1253 "</u:%sResponse>";
1254 /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
1255 * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
1256 * urn:upnp-org:serviceId:WANPPPConn1 */
1257 char body[1024];
1258 int bodylen;
1260 /* namespace : urn:schemas-upnp-org:service:Layer3Forwarding:1 */
1261 bodylen = snprintf(body, sizeof(body), resp,
1262 action, ns, uuidvalue_wcd, action);
1263 BuildSendAndCloseSoapResp(h, body, bodylen);
1265 #endif
1267 /* Added for compliance with WANIPConnection v2 */
1268 static void
1269 SetConnectionType(struct upnphttp * h, const char * action, const char * ns)
1271 #ifdef UPNP_STRICT
1272 const char * connection_type;
1273 #endif /* UPNP_STRICT */
1274 struct NameValueParserData data;
1275 UNUSED(action);
1276 UNUSED(ns);
1278 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1279 #ifdef UPNP_STRICT
1280 connection_type = GetValueFromNameValueList(&data, "NewConnectionType");
1281 if(!connection_type) {
1282 ClearNameValueList(&data);
1283 SoapError(h, 402, "Invalid Args");
1284 return;
1286 #endif /* UPNP_STRICT */
1287 /* Unconfigured, IP_Routed, IP_Bridged */
1288 ClearNameValueList(&data);
1289 /* always return a ReadOnly error */
1290 SoapError(h, 731, "ReadOnly");
1293 /* Added for compliance with WANIPConnection v2 */
1294 static void
1295 RequestConnection(struct upnphttp * h, const char * action, const char * ns)
1297 UNUSED(action);
1298 UNUSED(ns);
1299 SoapError(h, 606, "Action not authorized");
1302 /* Added for compliance with WANIPConnection v2 */
1303 static void
1304 ForceTermination(struct upnphttp * h, const char * action, const char * ns)
1306 UNUSED(action);
1307 UNUSED(ns);
1308 SoapError(h, 606, "Action not authorized");
1312 If a control point calls QueryStateVariable on a state variable that is not
1313 buffered in memory within (or otherwise available from) the service,
1314 the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1316 QueryStateVariable remains useful as a limited test tool but may not be
1317 part of some future versions of UPnP.
1319 static void
1320 QueryStateVariable(struct upnphttp * h, const char * action, const char * ns)
1322 static const char resp[] =
1323 "<u:%sResponse "
1324 "xmlns:u=\"%s\">"
1325 "<return>%s</return>"
1326 "</u:%sResponse>";
1328 char body[512];
1329 int bodylen;
1330 struct NameValueParserData data;
1331 const char * var_name;
1333 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1334 /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1335 /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1336 var_name = GetValueFromNameValueList(&data, "varName");
1338 /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1340 if(!var_name)
1342 SoapError(h, 402, "Invalid Args");
1344 else if(strcmp(var_name, "ConnectionStatus") == 0)
1346 const char * status;
1348 status = get_wan_connection_status_str(ext_if_name);
1349 bodylen = snprintf(body, sizeof(body), resp,
1350 action, ns,/*"urn:schemas-upnp-org:control-1-0",*/
1351 status, action);
1352 BuildSendAndCloseSoapResp(h, body, bodylen);
1354 #if 0
1355 /* not usefull */
1356 else if(strcmp(var_name, "ConnectionType") == 0)
1358 bodylen = snprintf(body, sizeof(body), resp, "IP_Routed");
1359 BuildSendAndCloseSoapResp(h, body, bodylen);
1361 else if(strcmp(var_name, "LastConnectionError") == 0)
1363 bodylen = snprintf(body, sizeof(body), resp, "ERROR_NONE");
1364 BuildSendAndCloseSoapResp(h, body, bodylen);
1366 #endif
1367 else if(strcmp(var_name, "PortMappingNumberOfEntries") == 0)
1369 char strn[10];
1370 snprintf(strn, sizeof(strn), "%i",
1371 upnp_get_portmapping_number_of_entries());
1372 bodylen = snprintf(body, sizeof(body), resp,
1373 action, ns,/*"urn:schemas-upnp-org:control-1-0",*/
1374 strn, action);
1375 BuildSendAndCloseSoapResp(h, body, bodylen);
1377 else
1379 syslog(LOG_NOTICE, "%s: Unknown: %s", action, var_name?var_name:"");
1380 SoapError(h, 404, "Invalid Var");
1383 ClearNameValueList(&data);
1386 #ifdef ENABLE_6FC_SERVICE
1387 #ifndef ENABLE_IPV6
1388 #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1389 #endif
1390 /* WANIPv6FirewallControl actions */
1391 static void
1392 GetFirewallStatus(struct upnphttp * h, const char * action, const char * ns)
1394 static const char resp[] =
1395 "<u:%sResponse "
1396 "xmlns:u=\"%s\">"
1397 "<FirewallEnabled>%d</FirewallEnabled>"
1398 "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1399 "</u:%sResponse>";
1401 char body[512];
1402 int bodylen;
1404 bodylen = snprintf(body, sizeof(body), resp,
1405 action, ns, /*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",*/
1406 GETFLAG(IPV6FCFWDISABLEDMASK) ? 0 : 1,
1407 GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK) ? 0 : 1,
1408 action);
1409 BuildSendAndCloseSoapResp(h, body, bodylen);
1412 static int
1413 CheckStatus(struct upnphttp * h)
1415 if (GETFLAG(IPV6FCFWDISABLEDMASK))
1417 SoapError(h, 702, "FirewallDisabled");
1418 return 0;
1420 else if(GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK))
1422 SoapError(h, 703, "InboundPinholeNotAllowed");
1423 return 0;
1425 else
1426 return 1;
1429 #if 0
1430 static int connecthostport(const char * host, unsigned short port, char * result)
1432 int s, n;
1433 char hostname[INET6_ADDRSTRLEN];
1434 char port_str[8], ifname[8], tmp[4];
1435 struct addrinfo *ai, *p;
1436 struct addrinfo hints;
1438 memset(&hints, 0, sizeof(hints));
1439 /* hints.ai_flags = AI_ADDRCONFIG; */
1440 #ifdef AI_NUMERICSERV
1441 hints.ai_flags = AI_NUMERICSERV;
1442 #endif
1443 hints.ai_socktype = SOCK_STREAM;
1444 hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
1445 /* hints.ai_protocol = IPPROTO_TCP; */
1446 snprintf(port_str, sizeof(port_str), "%hu", port);
1447 strcpy(hostname, host);
1448 if(!strncmp(host, "fe80", 4))
1450 printf("Using an linklocal address\n");
1451 strcpy(ifname, "%");
1452 snprintf(tmp, sizeof(tmp), "%d", linklocal_index);
1453 strcat(ifname, tmp);
1454 strcat(hostname, ifname);
1455 printf("host: %s\n", hostname);
1457 n = getaddrinfo(hostname, port_str, &hints, &ai);
1458 if(n != 0)
1460 fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
1461 return -1;
1463 s = -1;
1464 for(p = ai; p; p = p->ai_next)
1466 #ifdef DEBUG
1467 char tmp_host[256];
1468 char tmp_service[256];
1469 printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1470 p->ai_family, p->ai_socktype, p->ai_protocol, p->ai_addrlen);
1471 getnameinfo(p->ai_addr, p->ai_addrlen, tmp_host, sizeof(tmp_host),
1472 tmp_service, sizeof(tmp_service),
1473 NI_NUMERICHOST | NI_NUMERICSERV);
1474 printf(" host=%s service=%s\n", tmp_host, tmp_service);
1475 #endif
1476 inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr), result, INET6_ADDRSTRLEN);
1477 return 0;
1479 freeaddrinfo(ai);
1481 #endif
1483 /* Check the security policy right */
1484 static int
1485 PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short int_port)
1487 int n;
1488 char senderAddr[INET6_ADDRSTRLEN]="";
1489 struct addrinfo hints, *ai, *p;
1490 struct in6_addr result_ip;
1492 /* Pinhole InternalClient address must correspond to the action sender */
1493 syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)");
1495 hints.ai_socktype = SOCK_STREAM;
1496 hints.ai_family = AF_UNSPEC;
1498 /* if ip not valid assume hostname and convert */
1499 if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0)
1501 n = getaddrinfo(int_ip, NULL, &hints, &ai);
1502 if(!n && ai->ai_family == AF_INET6)
1504 for(p = ai; p; p = p->ai_next)
1506 inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr));
1507 result_ip = *((struct in6_addr *) p);
1508 /* TODO : deal with more than one ip per hostname */
1509 break;
1512 else
1514 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
1515 SoapError(h, 402, "Invalid Args");
1516 return -1;
1518 freeaddrinfo(p);
1521 if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN) == NULL)
1523 syslog(LOG_ERR, "inet_ntop: %m");
1525 #ifdef DEBUG
1526 printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr, int_ip);
1527 #endif
1528 if(strcmp(senderAddr, int_ip) != 0)
1529 if(h->clientaddr_v6.s6_addr != result_ip.s6_addr)
1531 syslog(LOG_INFO, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1532 senderAddr, int_ip);
1533 SoapError(h, 606, "Action not authorized");
1534 return 0;
1537 /* Pinhole InternalPort must be greater than or equal to 1024 */
1538 if (int_port < 1024)
1540 syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1541 senderAddr);
1542 SoapError(h, 606, "Action not authorized");
1543 return 0;
1545 return 1;
1548 static void
1549 AddPinhole(struct upnphttp * h, const char * action, const char * ns)
1551 int r;
1552 static const char resp[] =
1553 "<u:%sResponse "
1554 "xmlns:u=\"%s\">"
1555 "<UniqueID>%d</UniqueID>"
1556 "</u:%sResponse>";
1557 char body[512];
1558 int bodylen;
1559 struct NameValueParserData data;
1560 char * rem_host, * rem_port, * int_ip, * int_port, * protocol, * leaseTime;
1561 int uid = 0;
1562 unsigned short iport, rport;
1563 int ltime;
1564 long proto;
1565 char rem_ip[INET6_ADDRSTRLEN];
1567 if(CheckStatus(h)==0)
1568 return;
1570 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1571 rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1572 rem_port = GetValueFromNameValueList(&data, "RemotePort");
1573 int_ip = GetValueFromNameValueList(&data, "InternalClient");
1574 int_port = GetValueFromNameValueList(&data, "InternalPort");
1575 protocol = GetValueFromNameValueList(&data, "Protocol");
1576 leaseTime = GetValueFromNameValueList(&data, "LeaseTime");
1578 rport = (unsigned short)(rem_port ? atoi(rem_port) : 0);
1579 iport = (unsigned short)(int_port ? atoi(int_port) : 0);
1580 ltime = leaseTime ? atoi(leaseTime) : -1;
1581 errno = 0;
1582 proto = protocol ? strtol(protocol, NULL, 0) : -1;
1583 if(errno != 0 || proto > 65535 || proto < 0)
1585 SoapError(h, 402, "Invalid Args");
1586 goto clear_and_exit;
1588 if(iport == 0)
1590 SoapError(h, 706, "InternalPortWilcardingNotAllowed");
1591 goto clear_and_exit;
1594 /* In particular, [IGD2] RECOMMENDS that unauthenticated and
1595 * unauthorized control points are only allowed to invoke
1596 * this action with:
1597 * - InternalPort value greater than or equal to 1024,
1598 * - InternalClient value equals to the control point's IP address.
1599 * It is REQUIRED that InternalClient cannot be one of IPv6
1600 * addresses used by the gateway. */
1601 if(!int_ip || 0 == strlen(int_ip) || 0 == strcmp(int_ip, "*"))
1603 SoapError(h, 708, "WildCardNotPermittedInSrcIP");
1604 goto clear_and_exit;
1606 /* I guess it is useless to convert int_ip to literal ipv6 address */
1607 /* rem_host should be converted to literal ipv6 : */
1608 if(rem_host && (rem_host[0] != '\0'))
1610 struct addrinfo *ai, *p;
1611 struct addrinfo hints;
1612 int err;
1613 memset(&hints, 0, sizeof(struct addrinfo));
1614 hints.ai_family = AF_INET6;
1615 /*hints.ai_flags = */
1616 /* hints.ai_protocol = proto; */
1617 err = getaddrinfo(rem_host, rem_port, &hints, &ai);
1618 if(err == 0)
1620 /* take the 1st IPv6 address */
1621 for(p = ai; p; p = p->ai_next)
1623 if(p->ai_family == AF_INET6)
1625 inet_ntop(AF_INET6,
1626 &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr),
1627 rem_ip, sizeof(rem_ip));
1628 syslog(LOG_INFO, "resolved '%s' to '%s'", rem_host, rem_ip);
1629 rem_host = rem_ip;
1630 break;
1633 freeaddrinfo(ai);
1635 else
1637 syslog(LOG_WARNING, "AddPinhole : getaddrinfo(%s) : %s",
1638 rem_host, gai_strerror(err));
1639 #if 0
1640 SoapError(h, 402, "Invalid Args");
1641 goto clear_and_exit;
1642 #endif
1646 if(proto == 65535)
1648 SoapError(h, 707, "ProtocolWilcardingNotAllowed");
1649 goto clear_and_exit;
1651 if(proto != IPPROTO_UDP && proto != IPPROTO_TCP
1652 #ifdef IPPROTO_UDPITE
1653 && atoi(protocol) != IPPROTO_UDPLITE
1654 #endif
1657 SoapError(h, 705, "ProtocolNotSupported");
1658 goto clear_and_exit;
1660 if(ltime < 1 || ltime > 86400)
1662 syslog(LOG_WARNING, "%s: LeaseTime=%d not supported, (ip=%s)",
1663 action, ltime, int_ip);
1664 SoapError(h, 402, "Invalid Args");
1665 goto clear_and_exit;
1668 if(PinholeVerification(h, int_ip, iport) <= 0)
1669 goto clear_and_exit;
1671 syslog(LOG_INFO, "%s: (inbound) from [%s]:%hu to [%s]:%hu with proto %ld during %d sec",
1672 action, rem_host?rem_host:"any",
1673 rport, int_ip, iport,
1674 proto, ltime);
1676 /* In cases where the RemoteHost, RemotePort, InternalPort,
1677 * InternalClient and Protocol are the same than an existing pinhole,
1678 * but LeaseTime is different, the device MUST extend the existing
1679 * pinhole's lease time and return the UniqueID of the existing pinhole. */
1680 r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, proto, "IGD2 pinhole", ltime, &uid);
1682 switch(r)
1684 case 1: /* success */
1685 bodylen = snprintf(body, sizeof(body),
1686 resp, action,
1687 ns/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1688 uid, action);
1689 BuildSendAndCloseSoapResp(h, body, bodylen);
1690 break;
1691 case -1: /* not permitted */
1692 SoapError(h, 701, "PinholeSpaceExhausted");
1693 break;
1694 default:
1695 SoapError(h, 501, "ActionFailed");
1696 break;
1698 /* 606 Action not authorized
1699 * 701 PinholeSpaceExhausted
1700 * 702 FirewallDisabled
1701 * 703 InboundPinholeNotAllowed
1702 * 705 ProtocolNotSupported
1703 * 706 InternalPortWildcardingNotAllowed
1704 * 707 ProtocolWildcardingNotAllowed
1705 * 708 WildCardNotPermittedInSrcIP */
1706 clear_and_exit:
1707 ClearNameValueList(&data);
1710 static void
1711 UpdatePinhole(struct upnphttp * h, const char * action, const char * ns)
1713 #if 0
1714 static const char resp[] =
1715 "<u:UpdatePinholeResponse "
1716 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1717 "</u:UpdatePinholeResponse>";
1718 #endif
1719 static const char resp[] =
1720 "<u:%sResponse "
1721 "xmlns:u=\"%s\">"
1722 "</u:%sResponse>";
1723 char body[512];
1724 int bodylen;
1725 struct NameValueParserData data;
1726 const char * uid_str, * leaseTime;
1727 char iaddr[INET6_ADDRSTRLEN];
1728 unsigned short iport;
1729 int ltime;
1730 int uid;
1731 int n;
1733 if(CheckStatus(h)==0)
1734 return;
1736 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1737 uid_str = GetValueFromNameValueList(&data, "UniqueID");
1738 leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime");
1739 uid = uid_str ? atoi(uid_str) : -1;
1740 ltime = leaseTime ? atoi(leaseTime) : -1;
1741 ClearNameValueList(&data);
1743 if(uid < 0 || uid > 65535 || ltime <= 0 || ltime > 86400)
1745 SoapError(h, 402, "Invalid Args");
1746 return;
1749 /* Check that client is not updating an pinhole
1750 * it doesn't have access to, because of its public access */
1751 n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
1752 iaddr, sizeof(iaddr), &iport,
1753 NULL, /* proto */
1754 NULL, 0, /* desc, desclen */
1755 NULL, NULL);
1756 if (n >= 0)
1758 if(PinholeVerification(h, iaddr, iport) <= 0)
1759 return;
1761 else if(n == -2)
1763 SoapError(h, 704, "NoSuchEntry");
1764 return;
1766 else
1768 SoapError(h, 501, "ActionFailed");
1769 return;
1772 syslog(LOG_INFO, "%s: (inbound) updating lease duration to %d for pinhole with ID: %d",
1773 action, ltime, uid);
1775 n = upnp_update_inboundpinhole(uid, ltime);
1776 if(n == -1)
1777 SoapError(h, 704, "NoSuchEntry");
1778 else if(n < 0)
1779 SoapError(h, 501, "ActionFailed");
1780 else {
1781 bodylen = snprintf(body, sizeof(body), resp,
1782 action, ns, action);
1783 BuildSendAndCloseSoapResp(h, body, bodylen);
1787 static void
1788 GetOutboundPinholeTimeout(struct upnphttp * h, const char * action, const char * ns)
1790 int r;
1792 static const char resp[] =
1793 "<u:%sResponse "
1794 "xmlns:u=\"%s\">"
1795 "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1796 "</u:%sResponse>";
1798 char body[512];
1799 int bodylen;
1800 struct NameValueParserData data;
1801 char * int_ip, * int_port, * rem_host, * rem_port, * protocol;
1802 int opt=0;
1803 /*int proto=0;*/
1804 unsigned short iport, rport;
1806 if (GETFLAG(IPV6FCFWDISABLEDMASK))
1808 SoapError(h, 702, "FirewallDisabled");
1809 return;
1812 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1813 int_ip = GetValueFromNameValueList(&data, "InternalClient");
1814 int_port = GetValueFromNameValueList(&data, "InternalPort");
1815 rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1816 rem_port = GetValueFromNameValueList(&data, "RemotePort");
1817 protocol = GetValueFromNameValueList(&data, "Protocol");
1819 rport = (unsigned short)atoi(rem_port);
1820 iport = (unsigned short)atoi(int_port);
1821 /*proto = atoi(protocol);*/
1823 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);
1825 /* TODO */
1826 r = -1;/*upnp_check_outbound_pinhole(proto, &opt);*/
1828 switch(r)
1830 case 1: /* success */
1831 bodylen = snprintf(body, sizeof(body), resp,
1832 action, ns/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1833 opt, action);
1834 BuildSendAndCloseSoapResp(h, body, bodylen);
1835 break;
1836 case -5: /* Protocol not supported */
1837 SoapError(h, 705, "ProtocolNotSupported");
1838 break;
1839 default:
1840 SoapError(h, 501, "ActionFailed");
1842 ClearNameValueList(&data);
1845 static void
1846 DeletePinhole(struct upnphttp * h, const char * action, const char * ns)
1848 int n;
1849 #if 0
1850 static const char resp[] =
1851 "<u:DeletePinholeResponse "
1852 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1853 "</u:DeletePinholeResponse>";
1854 #endif
1855 static const char resp[] =
1856 "<u:%sResponse "
1857 "xmlns:u=\"%s\">"
1858 "</u:%sResponse>";
1859 char body[512];
1860 int bodylen;
1862 struct NameValueParserData data;
1863 const char * uid_str;
1864 char iaddr[INET6_ADDRSTRLEN];
1865 int proto;
1866 unsigned short iport;
1867 unsigned int leasetime;
1868 int uid;
1870 if(CheckStatus(h)==0)
1871 return;
1873 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1874 uid_str = GetValueFromNameValueList(&data, "UniqueID");
1875 uid = uid_str ? atoi(uid_str) : -1;
1876 ClearNameValueList(&data);
1878 if(uid < 0 || uid > 65535)
1880 SoapError(h, 402, "Invalid Args");
1881 return;
1884 /* Check that client is not deleting an pinhole
1885 * it doesn't have access to, because of its public access */
1886 n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
1887 iaddr, sizeof(iaddr), &iport,
1888 &proto,
1889 NULL, 0, /* desc, desclen */
1890 &leasetime, NULL);
1891 if (n >= 0)
1893 if(PinholeVerification(h, iaddr, iport) <= 0)
1894 return;
1896 else if(n == -2)
1898 SoapError(h, 704, "NoSuchEntry");
1899 return;
1901 else
1903 SoapError(h, 501, "ActionFailed");
1904 return;
1907 n = upnp_delete_inboundpinhole(uid);
1908 if(n < 0)
1910 syslog(LOG_INFO, "%s: (inbound) failed to remove pinhole with ID: %d",
1911 action, uid);
1912 SoapError(h, 501, "ActionFailed");
1913 return;
1915 syslog(LOG_INFO, "%s: (inbound) pinhole with ID %d successfully removed",
1916 action, uid);
1917 bodylen = snprintf(body, sizeof(body), resp,
1918 action, ns, action);
1919 BuildSendAndCloseSoapResp(h, body, bodylen);
1922 static void
1923 CheckPinholeWorking(struct upnphttp * h, const char * action, const char * ns)
1925 static const char resp[] =
1926 "<u:%sResponse "
1927 "xmlns:u=\"%s\">"
1928 "<IsWorking>%d</IsWorking>"
1929 "</u:%sResponse>";
1930 char body[512];
1931 int bodylen;
1932 int r;
1933 struct NameValueParserData data;
1934 const char * uid_str;
1935 int uid;
1936 char iaddr[INET6_ADDRSTRLEN];
1937 unsigned short iport;
1938 unsigned int packets;
1940 if(CheckStatus(h)==0)
1941 return;
1943 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1944 uid_str = GetValueFromNameValueList(&data, "UniqueID");
1945 uid = uid_str ? atoi(uid_str) : -1;
1946 ClearNameValueList(&data);
1948 if(uid < 0 || uid > 65535)
1950 SoapError(h, 402, "Invalid Args");
1951 return;
1954 /* Check that client is not checking a pinhole
1955 * it doesn't have access to, because of its public access */
1956 r = upnp_get_pinhole_info(uid,
1957 NULL, 0, NULL,
1958 iaddr, sizeof(iaddr), &iport,
1959 NULL, /* proto */
1960 NULL, 0, /* desc, desclen */
1961 NULL, &packets);
1962 if (r >= 0)
1964 if(PinholeVerification(h, iaddr, iport) <= 0)
1965 return ;
1966 if(packets == 0)
1968 SoapError(h, 709, "NoPacketSent");
1969 return;
1971 bodylen = snprintf(body, sizeof(body), resp,
1972 action, ns/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1973 1, action);
1974 BuildSendAndCloseSoapResp(h, body, bodylen);
1976 else if(r == -2)
1977 SoapError(h, 704, "NoSuchEntry");
1978 else
1979 SoapError(h, 501, "ActionFailed");
1982 static void
1983 GetPinholePackets(struct upnphttp * h, const char * action, const char * ns)
1985 static const char resp[] =
1986 "<u:%sResponse "
1987 "xmlns:u=\"%s\">"
1988 "<PinholePackets>%u</PinholePackets>"
1989 "</u:%sResponse>";
1990 char body[512];
1991 int bodylen;
1992 struct NameValueParserData data;
1993 const char * uid_str;
1994 int n;
1995 char iaddr[INET6_ADDRSTRLEN];
1996 unsigned short iport;
1997 unsigned int packets = 0;
1998 int uid;
1999 int proto;
2000 unsigned int leasetime;
2002 if(CheckStatus(h)==0)
2003 return;
2005 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
2006 uid_str = GetValueFromNameValueList(&data, "UniqueID");
2007 uid = uid_str ? atoi(uid_str) : -1;
2008 ClearNameValueList(&data);
2010 if(uid < 0 || uid > 65535)
2012 SoapError(h, 402, "Invalid Args");
2013 return;
2016 /* Check that client is not getting infos of a pinhole
2017 * it doesn't have access to, because of its public access */
2018 n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
2019 iaddr, sizeof(iaddr), &iport,
2020 &proto,
2021 NULL, 0, /* desc, desclen */
2022 &leasetime, &packets);
2023 if (n >= 0)
2025 if(PinholeVerification(h, iaddr, iport)<=0)
2026 return ;
2028 #if 0
2029 else if(r == -4 || r == -1)
2031 SoapError(h, 704, "NoSuchEntry");
2033 #endif
2035 bodylen = snprintf(body, sizeof(body), resp,
2036 action, ns/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
2037 packets, action);
2038 BuildSendAndCloseSoapResp(h, body, bodylen);
2040 #endif
2042 #ifdef ENABLE_DP_SERVICE
2043 static void
2044 SendSetupMessage(struct upnphttp * h, const char * action, const char * ns)
2046 static const char resp[] =
2047 "<u:%sResponse "
2048 "xmlns:u=\"%s\">"
2049 "<OutMessage>%s</OutMessage>"
2050 "</u:%sResponse>";
2051 char body[1024];
2052 int bodylen;
2053 struct NameValueParserData data;
2054 const char * ProtocolType; /* string */
2055 const char * InMessage; /* base64 */
2056 const char * OutMessage = ""; /* base64 */
2058 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
2059 ProtocolType = GetValueFromNameValueList(&data, "ProtocolType"); /* string */
2060 InMessage = GetValueFromNameValueList(&data, "InMessage"); /* base64 */
2062 if(ProtocolType == NULL || InMessage == NULL)
2064 ClearNameValueList(&data);
2065 SoapError(h, 402, "Invalid Args");
2066 return;
2068 /*if(strcmp(ProtocolType, "DeviceProtection:1") != 0)*/
2069 if(strcmp(ProtocolType, "WPS") != 0)
2071 ClearNameValueList(&data);
2072 SoapError(h, 600, "Argument Value Invalid"); /* 703 ? */
2073 return;
2075 /* TODO : put here code for WPS */
2077 bodylen = snprintf(body, sizeof(body), resp,
2078 action, ns/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2079 OutMessage, action);
2080 BuildSendAndCloseSoapResp(h, body, bodylen);
2081 ClearNameValueList(&data);
2084 static void
2085 GetSupportedProtocols(struct upnphttp * h, const char * action, const char * ns)
2087 static const char resp[] =
2088 "<u:%sResponse "
2089 "xmlns:u=\"%s\">"
2090 "<ProtocolList><![CDATA[%s]]></ProtocolList>"
2091 "</u:%sResponse>";
2092 char body[1024];
2093 int bodylen;
2094 const char * ProtocolList =
2095 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
2096 "<SupportedProtocols xmlns=\"urn:schemas-upnp-org:gw:DeviceProtection\""
2097 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
2098 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:DeviceProtection"
2099 " http://www.upnp.org/schemas/gw/DeviceProtection-v1.xsd\">"
2100 "<Introduction><Name>WPS</Name></Introduction>"
2101 "<Login><Name>PKCS5</Name></Login>"
2102 "</SupportedProtocols>";
2104 bodylen = snprintf(body, sizeof(body), resp,
2105 action, ns/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2106 ProtocolList, action);
2107 BuildSendAndCloseSoapResp(h, body, bodylen);
2110 static void
2111 GetAssignedRoles(struct upnphttp * h, const char * action, const char * ns)
2113 static const char resp[] =
2114 "<u:%sResponse "
2115 "xmlns:u=\"%s\">"
2116 "<RoleList>%s</RoleList>"
2117 "</u:%sResponse>";
2118 char body[1024];
2119 int bodylen;
2120 const char * RoleList = "Public"; /* list of roles separated by spaces */
2122 #ifdef ENABLE_HTTPS
2123 if(h->ssl != NULL) {
2124 /* we should get the Roles of the session (based on client certificate) */
2125 X509 * peercert;
2126 peercert = SSL_get_peer_certificate(h->ssl);
2127 if(peercert != NULL) {
2128 RoleList = "Admin Basic";
2129 X509_free(peercert);
2132 #endif
2134 bodylen = snprintf(body, sizeof(body), resp,
2135 action, ns/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2136 RoleList, action);
2137 BuildSendAndCloseSoapResp(h, body, bodylen);
2139 #endif
2141 /* Windows XP as client send the following requests :
2142 * GetConnectionTypeInfo
2143 * GetNATRSIPStatus
2144 * ? GetTotalBytesSent - WANCommonInterfaceConfig
2145 * ? GetTotalBytesReceived - idem
2146 * ? GetTotalPacketsSent - idem
2147 * ? GetTotalPacketsReceived - idem
2148 * GetCommonLinkProperties - idem
2149 * GetStatusInfo - WANIPConnection
2150 * GetExternalIPAddress
2151 * QueryStateVariable / ConnectionStatus!
2153 static const struct
2155 const char * methodName;
2156 void (*methodImpl)(struct upnphttp *, const char *, const char *);
2158 soapMethods[] =
2160 /* WANCommonInterfaceConfig */
2161 { "QueryStateVariable", QueryStateVariable},
2162 { "GetTotalBytesSent", GetTotalBytesSent},
2163 { "GetTotalBytesReceived", GetTotalBytesReceived},
2164 { "GetTotalPacketsSent", GetTotalPacketsSent},
2165 { "GetTotalPacketsReceived", GetTotalPacketsReceived},
2166 { "GetCommonLinkProperties", GetCommonLinkProperties},
2167 { "GetStatusInfo", GetStatusInfo},
2168 /* WANIPConnection */
2169 { "GetConnectionTypeInfo", GetConnectionTypeInfo },
2170 { "GetNATRSIPStatus", GetNATRSIPStatus},
2171 { "GetExternalIPAddress", GetExternalIPAddress},
2172 { "AddPortMapping", AddPortMapping},
2173 { "DeletePortMapping", DeletePortMapping},
2174 { "GetGenericPortMappingEntry", GetGenericPortMappingEntry},
2175 { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry},
2176 /* Required in WANIPConnection:2 */
2177 { "SetConnectionType", SetConnectionType},
2178 { "RequestConnection", RequestConnection},
2179 { "ForceTermination", ForceTermination},
2180 { "AddAnyPortMapping", AddAnyPortMapping},
2181 { "DeletePortMappingRange", DeletePortMappingRange},
2182 { "GetListOfPortMappings", GetListOfPortMappings},
2183 #ifdef ENABLE_L3F_SERVICE
2184 /* Layer3Forwarding */
2185 { "SetDefaultConnectionService", SetDefaultConnectionService},
2186 { "GetDefaultConnectionService", GetDefaultConnectionService},
2187 #endif
2188 #ifdef ENABLE_6FC_SERVICE
2189 /* WANIPv6FirewallControl */
2190 { "GetFirewallStatus", GetFirewallStatus}, /* Required */
2191 { "AddPinhole", AddPinhole}, /* Required */
2192 { "UpdatePinhole", UpdatePinhole}, /* Required */
2193 { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout}, /* Optional */
2194 { "DeletePinhole", DeletePinhole}, /* Required */
2195 { "CheckPinholeWorking", CheckPinholeWorking}, /* Optional */
2196 { "GetPinholePackets", GetPinholePackets}, /* Required */
2197 #endif
2198 #ifdef ENABLE_DP_SERVICE
2199 /* DeviceProtection */
2200 { "SendSetupMessage", SendSetupMessage}, /* Required */
2201 { "GetSupportedProtocols", GetSupportedProtocols}, /* Required */
2202 { "GetAssignedRoles", GetAssignedRoles}, /* Required */
2203 #endif
2204 { 0, 0 }
2207 void
2208 ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
2210 char * p;
2211 char * p2;
2212 int i, len, methodlen;
2213 char namespace[256];
2215 /* SoapAction example :
2216 * urn:schemas-upnp-org:service:WANIPConnection:1#GetStatusInfo */
2217 p = strchr(action, '#');
2218 if(p && (p - action) < n) {
2219 for(i = 0; i < ((int)sizeof(namespace) - 1) && (action + i) < p; i++)
2220 namespace[i] = action[i];
2221 namespace[i] = '\0';
2222 p++;
2223 p2 = strchr(p, '"');
2224 if(p2 && (p2 - action) <= n)
2225 methodlen = p2 - p;
2226 else
2227 methodlen = n - (p - action);
2228 /*syslog(LOG_DEBUG, "SoapMethod: %.*s %d %d %p %p %d",
2229 methodlen, p, methodlen, n, action, p, (int)(p - action));*/
2230 for(i = 0; soapMethods[i].methodName; i++) {
2231 len = strlen(soapMethods[i].methodName);
2232 if((len == methodlen) && memcmp(p, soapMethods[i].methodName, len) == 0) {
2233 #ifdef DEBUG
2234 syslog(LOG_DEBUG, "Remote Call of SoapMethod '%s' %s",
2235 soapMethods[i].methodName, namespace);
2236 #endif /* DEBUG */
2237 soapMethods[i].methodImpl(h, soapMethods[i].methodName, namespace);
2238 return;
2241 syslog(LOG_NOTICE, "SoapMethod: Unknown: %.*s %s", methodlen, p, namespace);
2242 } else {
2243 syslog(LOG_NOTICE, "cannot parse SoapAction");
2246 SoapError(h, 401, "Invalid Action");
2249 /* Standard Errors:
2251 * errorCode errorDescription Description
2252 * -------- ---------------- -----------
2253 * 401 Invalid Action No action by that name at this service.
2254 * 402 Invalid Args Could be any of the following: not enough in args,
2255 * too many in args, no in arg by that name,
2256 * one or more in args are of the wrong data type.
2257 * 403 Out of Sync Out of synchronization.
2258 * 501 Action Failed May be returned in current state of service
2259 * prevents invoking that action.
2260 * 600-699 TBD Common action errors. Defined by UPnP Forum
2261 * Technical Committee.
2262 * 700-799 TBD Action-specific errors for standard actions.
2263 * Defined by UPnP Forum working committee.
2264 * 800-899 TBD Action-specific errors for non-standard actions.
2265 * Defined by UPnP vendor.
2267 void
2268 SoapError(struct upnphttp * h, int errCode, const char * errDesc)
2270 static const char resp[] =
2271 "<s:Envelope "
2272 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
2273 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
2274 "<s:Body>"
2275 "<s:Fault>"
2276 "<faultcode>s:Client</faultcode>"
2277 "<faultstring>UPnPError</faultstring>"
2278 "<detail>"
2279 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
2280 "<errorCode>%d</errorCode>"
2281 "<errorDescription>%s</errorDescription>"
2282 "</UPnPError>"
2283 "</detail>"
2284 "</s:Fault>"
2285 "</s:Body>"
2286 "</s:Envelope>";
2288 char body[2048];
2289 int bodylen;
2291 syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc);
2292 bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc);
2293 BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen);
2294 SendRespAndClose_upnphttp(h);