Miniupnpd: update to 1.9 (20150430)
[tomato.git] / release / src / router / miniupnpd / upnpsoap.c
blob7d126a1dfa0ca842407f1299725c121c0e271909
1 /* $Id: upnpsoap.c,v 1.136 2015/03/07 15:52:30 nanard Exp $ */
2 /* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2015 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
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 static void
35 BuildSendAndCloseSoapResp(struct upnphttp * h,
36 const char * body, int bodylen)
38 static const char beforebody[] =
39 "<?xml version=\"1.0\"?>\r\n"
40 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
41 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
42 "<s:Body>";
44 static const char afterbody[] =
45 "</s:Body>"
46 "</s:Envelope>\r\n";
48 int r = BuildHeader_upnphttp(h, 200, "OK", sizeof(beforebody) - 1
49 + sizeof(afterbody) - 1 + bodylen );
51 if(r >= 0) {
52 memcpy(h->res_buf + h->res_buflen, beforebody, sizeof(beforebody) - 1);
53 h->res_buflen += sizeof(beforebody) - 1;
55 memcpy(h->res_buf + h->res_buflen, body, bodylen);
56 h->res_buflen += bodylen;
58 memcpy(h->res_buf + h->res_buflen, afterbody, sizeof(afterbody) - 1);
59 h->res_buflen += sizeof(afterbody) - 1;
60 } else {
61 BuildResp2_upnphttp(h, 500, "Internal Server Error", NULL, 0);
64 SendRespAndClose_upnphttp(h);
67 static void
68 GetConnectionTypeInfo(struct upnphttp * h, const char * action)
70 static const char resp[] =
71 "<u:GetConnectionTypeInfoResponse "
72 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
73 "<NewConnectionType>IP_Routed</NewConnectionType>"
74 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
75 "</u:GetConnectionTypeInfoResponse>";
76 UNUSED(action);
78 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
81 static void
82 GetTotalBytesSent(struct upnphttp * h, const char * action)
84 int r;
86 static const char resp[] =
87 "<u:%sResponse "
88 "xmlns:u=\"%s\">"
89 "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
90 "</u:%sResponse>";
92 char body[512];
93 int bodylen;
94 struct ifdata data;
96 r = getifstats(ext_if_name, &data);
97 bodylen = snprintf(body, sizeof(body), resp,
98 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
99 r<0?0:data.obytes, action);
100 BuildSendAndCloseSoapResp(h, body, bodylen);
103 static void
104 GetTotalBytesReceived(struct upnphttp * h, const char * action)
106 int r;
108 static const char resp[] =
109 "<u:%sResponse "
110 "xmlns:u=\"%s\">"
111 "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
112 "</u:%sResponse>";
114 char body[512];
115 int bodylen;
116 struct ifdata data;
118 r = getifstats(ext_if_name, &data);
119 bodylen = snprintf(body, sizeof(body), resp,
120 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
121 r<0?0:data.ibytes, action);
122 BuildSendAndCloseSoapResp(h, body, bodylen);
125 static void
126 GetTotalPacketsSent(struct upnphttp * h, const char * action)
128 int r;
130 static const char resp[] =
131 "<u:%sResponse "
132 "xmlns:u=\"%s\">"
133 "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
134 "</u:%sResponse>";
136 char body[512];
137 int bodylen;
138 struct ifdata data;
140 r = getifstats(ext_if_name, &data);
141 bodylen = snprintf(body, sizeof(body), resp,
142 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
143 r<0?0:data.opackets, action);
144 BuildSendAndCloseSoapResp(h, body, bodylen);
147 static void
148 GetTotalPacketsReceived(struct upnphttp * h, const char * action)
150 int r;
152 static const char resp[] =
153 "<u:%sResponse "
154 "xmlns:u=\"%s\">"
155 "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
156 "</u:%sResponse>";
158 char body[512];
159 int bodylen;
160 struct ifdata data;
162 r = getifstats(ext_if_name, &data);
163 bodylen = snprintf(body, sizeof(body), resp,
164 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
165 r<0?0:data.ipackets, action);
166 BuildSendAndCloseSoapResp(h, body, bodylen);
169 static void
170 GetCommonLinkProperties(struct upnphttp * h, const char * action)
172 /* WANAccessType : set depending on the hardware :
173 * DSL, POTS (plain old Telephone service), Cable, Ethernet */
174 static const char resp[] =
175 "<u:%sResponse "
176 "xmlns:u=\"%s\">"
177 "<NewWANAccessType>%s</NewWANAccessType>"
178 "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
179 "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
180 "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
181 "</u:%sResponse>";
183 char body[2048];
184 int bodylen;
185 struct ifdata data;
186 const char * status = "Up"; /* Up, Down (Required),
187 * Initializing, Unavailable (Optional) */
188 const char * wan_access_type = "Cable"; /* DSL, POTS, Cable, Ethernet */
189 char ext_ip_addr[INET_ADDRSTRLEN];
191 if((downstream_bitrate == 0) || (upstream_bitrate == 0))
193 if(getifstats(ext_if_name, &data) >= 0)
195 if(downstream_bitrate == 0) downstream_bitrate = data.baudrate;
196 if(upstream_bitrate == 0) upstream_bitrate = data.baudrate;
199 if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, NULL, NULL) < 0) {
200 status = "Down";
202 bodylen = snprintf(body, sizeof(body), resp,
203 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
204 wan_access_type,
205 upstream_bitrate, downstream_bitrate,
206 status, action);
207 BuildSendAndCloseSoapResp(h, body, bodylen);
210 static void
211 GetStatusInfo(struct upnphttp * h, const char * action)
213 static const char resp[] =
214 "<u:%sResponse "
215 "xmlns:u=\"%s\">"
216 "<NewConnectionStatus>%s</NewConnectionStatus>"
217 "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
218 "<NewUptime>%ld</NewUptime>"
219 "</u:%sResponse>";
221 char body[512];
222 int bodylen;
223 time_t uptime;
224 const char * status;
225 /* ConnectionStatus possible values :
226 * Unconfigured, Connecting, Connected, PendingDisconnect,
227 * Disconnecting, Disconnected */
229 status = get_wan_connection_status_str(ext_if_name);
230 uptime = (time(NULL) - startup_time);
231 bodylen = snprintf(body, sizeof(body), resp,
232 action, SERVICE_TYPE_WANIPC,
233 status, (long)uptime, action);
234 BuildSendAndCloseSoapResp(h, body, bodylen);
237 static void
238 GetNATRSIPStatus(struct upnphttp * h, const char * action)
240 static const char resp[] =
241 "<u:GetNATRSIPStatusResponse "
242 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
243 "<NewRSIPAvailable>0</NewRSIPAvailable>"
244 "<NewNATEnabled>1</NewNATEnabled>"
245 "</u:GetNATRSIPStatusResponse>";
246 UNUSED(action);
247 /* 2.2.9. RSIPAvailable
248 * This variable indicates if Realm-specific IP (RSIP) is available
249 * as a feature on the InternetGatewayDevice. RSIP is being defined
250 * in the NAT working group in the IETF to allow host-NATing using
251 * a standard set of message exchanges. It also allows end-to-end
252 * applications that otherwise break if NAT is introduced
253 * (e.g. IPsec-based VPNs).
254 * A gateway that does not support RSIP should set this variable to 0. */
255 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
258 static void
259 GetExternalIPAddress(struct upnphttp * h, const char * action)
261 static const char resp[] =
262 "<u:%sResponse "
263 "xmlns:u=\"%s\">"
264 "<NewExternalIPAddress>%s</NewExternalIPAddress>"
265 "</u:%sResponse>";
267 char body[512];
268 int bodylen;
269 char ext_ip_addr[INET_ADDRSTRLEN];
270 /* Does that method need to work with IPv6 ?
271 * There is usually no NAT with IPv6 */
273 #ifndef MULTIPLE_EXTERNAL_IP
274 if(use_ext_ip_addr)
276 strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN);
278 else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, NULL, NULL) < 0)
280 syslog(LOG_ERR, "Failed to get ip address for interface %s",
281 ext_if_name);
282 strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
284 #else
285 struct lan_addr_s * lan_addr;
286 strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
287 for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
289 if( (h->clientaddr.s_addr & lan_addr->mask.s_addr)
290 == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
292 strncpy(ext_ip_addr, lan_addr->ext_ip_str, INET_ADDRSTRLEN);
293 break;
296 #endif
297 bodylen = snprintf(body, sizeof(body), resp,
298 action, SERVICE_TYPE_WANIPC,
299 ext_ip_addr, action);
300 BuildSendAndCloseSoapResp(h, body, bodylen);
303 /* AddPortMapping method of WANIPConnection Service
304 * Ignored argument : NewEnabled */
305 static void
306 AddPortMapping(struct upnphttp * h, const char * action)
308 int r;
310 static const char resp[] =
311 "<u:AddPortMappingResponse "
312 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";
314 struct NameValueParserData data;
315 char * int_ip, * int_port, * ext_port, * protocol, * desc;
316 char * leaseduration_str;
317 unsigned int leaseduration;
318 char * r_host;
319 unsigned short iport, eport;
321 struct hostent *hp; /* getbyhostname() */
322 char ** ptr; /* getbyhostname() */
323 struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
325 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
326 int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
327 if (!int_ip)
329 ClearNameValueList(&data);
330 SoapError(h, 402, "Invalid Args");
331 return;
334 /* IGD 2 MUST support both wildcard and specific IP address values
335 * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
336 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
337 #ifndef SUPPORT_REMOTEHOST
338 #ifdef UPNP_STRICT
339 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
341 ClearNameValueList(&data);
342 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
343 return;
345 #endif
346 #endif
348 /* if ip not valid assume hostname and convert */
349 if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
351 hp = gethostbyname(int_ip);
352 if(hp && hp->h_addrtype == AF_INET)
354 for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
356 int_ip = inet_ntoa(*((struct in_addr *) *ptr));
357 result_ip = *((struct in_addr *) *ptr);
358 /* TODO : deal with more than one ip per hostname */
359 break;
362 else
364 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
365 ClearNameValueList(&data);
366 SoapError(h, 402, "Invalid Args");
367 return;
371 /* check if NewInternalAddress is the client address */
372 if(GETFLAG(SECUREMODEMASK))
374 if(h->clientaddr.s_addr != result_ip.s_addr)
376 syslog(LOG_INFO, "Client %s tried to redirect port to %s",
377 inet_ntoa(h->clientaddr), int_ip);
378 ClearNameValueList(&data);
379 SoapError(h, 718, "ConflictInMappingEntry");
380 return;
384 int_port = GetValueFromNameValueList(&data, "NewInternalPort");
385 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
386 protocol = GetValueFromNameValueList(&data, "NewProtocol");
387 desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
388 leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
390 if (!int_port || !ext_port || !protocol)
392 ClearNameValueList(&data);
393 SoapError(h, 402, "Invalid Args");
394 return;
397 eport = (unsigned short)atoi(ext_port);
398 iport = (unsigned short)atoi(int_port);
400 leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
401 #ifdef IGD_V2
402 /* PortMappingLeaseDuration can be either a value between 1 and
403 * 604800 seconds or the zero value (for infinite lease time).
404 * Note that an infinite lease time can be only set by out-of-band
405 * mechanisms like WWW-administration, remote management or local
406 * management.
407 * If a control point uses the value 0 to indicate an infinite lease
408 * time mapping, it is REQUIRED that gateway uses the maximum value
409 * instead (e.g. 604800 seconds) */
410 if(leaseduration == 0 || leaseduration > 604800)
411 leaseduration = 604800;
412 #endif
414 syslog(LOG_INFO, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
415 action, eport, int_ip, iport, protocol, desc, leaseduration,
416 r_host ? r_host : "NULL");
418 /* TODO : be compliant with IGD spec for updating existing port mappings.
419 See "WANIPConnection:1 Service Template Version 1.01" 2.2.20.PortMappingDescription :
420 Overwriting Previous / Existing Port Mappings:
421 If the RemoteHost, ExternalPort, PortMappingProtocol and InternalClient are
422 exactly the same as an existing mapping, the existing mapping values for InternalPort,
423 PortMappingDescription, PortMappingEnabled and PortMappingLeaseDuration are
424 overwritten.
426 r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
428 ClearNameValueList(&data);
430 /* possible error codes for AddPortMapping :
431 * 402 - Invalid Args
432 * 501 - Action Failed
433 * 715 - Wildcard not permited in SrcAddr
434 * 716 - Wildcard not permited in ExtPort
435 * 718 - ConflictInMappingEntry
436 * 724 - SamePortValuesRequired (deprecated in IGD v2)
437 * 725 - OnlyPermanentLeasesSupported
438 The NAT implementation only supports permanent lease times on
439 port mappings (deprecated in IGD v2)
440 * 726 - RemoteHostOnlySupportsWildcard
441 RemoteHost must be a wildcard and cannot be a specific IP
442 address or DNS name (deprecated in IGD v2)
443 * 727 - ExternalPortOnlySupportsWildcard
444 ExternalPort must be a wildcard and cannot be a specific port
445 value (deprecated in IGD v2)
446 * 728 - NoPortMapsAvailable
447 There are not enough free prots available to complete the mapping
448 (added in IGD v2)
449 * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
450 switch(r)
452 case 0: /* success */
453 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
454 break;
455 case -2: /* already redirected */
456 case -3: /* not permitted */
457 SoapError(h, 718, "ConflictInMappingEntry");
458 break;
459 default:
460 SoapError(h, 501, "ActionFailed");
464 /* AddAnyPortMapping was added in WANIPConnection v2 */
465 static void
466 AddAnyPortMapping(struct upnphttp * h, const char * action)
468 int r;
469 static const char resp[] =
470 "<u:%sResponse "
471 "xmlns:u=\"%s\">"
472 "<NewReservedPort>%hu</NewReservedPort>"
473 "</u:%sResponse>";
475 char body[512];
476 int bodylen;
478 struct NameValueParserData data;
479 const char * int_ip, * int_port, * ext_port, * protocol, * desc;
480 const char * r_host;
481 unsigned short iport, eport;
482 const char * leaseduration_str;
483 unsigned int leaseduration;
485 struct hostent *hp; /* getbyhostname() */
486 char ** ptr; /* getbyhostname() */
487 struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
489 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
490 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
491 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
492 protocol = GetValueFromNameValueList(&data, "NewProtocol");
493 int_port = GetValueFromNameValueList(&data, "NewInternalPort");
494 int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
495 /* NewEnabled */
496 desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
497 leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
499 leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
500 if(leaseduration == 0)
501 leaseduration = 604800;
503 if (!int_ip || !ext_port || !int_port)
505 ClearNameValueList(&data);
506 SoapError(h, 402, "Invalid Args");
507 return;
510 eport = (unsigned short)atoi(ext_port);
511 iport = (unsigned short)atoi(int_port);
512 #ifndef SUPPORT_REMOTEHOST
513 #ifdef UPNP_STRICT
514 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
516 ClearNameValueList(&data);
517 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
518 return;
520 #endif
521 #endif
523 /* if ip not valid assume hostname and convert */
524 if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
526 hp = gethostbyname(int_ip);
527 if(hp && hp->h_addrtype == AF_INET)
529 for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
531 int_ip = inet_ntoa(*((struct in_addr *) *ptr));
532 result_ip = *((struct in_addr *) *ptr);
533 /* TODO : deal with more than one ip per hostname */
534 break;
537 else
539 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
540 ClearNameValueList(&data);
541 SoapError(h, 402, "Invalid Args");
542 return;
546 /* check if NewInternalAddress is the client address */
547 if(GETFLAG(SECUREMODEMASK))
549 if(h->clientaddr.s_addr != result_ip.s_addr)
551 syslog(LOG_INFO, "Client %s tried to redirect port to %s",
552 inet_ntoa(h->clientaddr), int_ip);
553 ClearNameValueList(&data);
554 SoapError(h, 606, "Action not authorized");
555 return;
559 /* TODO : accept a different external port
560 * have some smart strategy to choose the port */
561 for(;;) {
562 r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
563 if(r==-2 && eport < 65535) {
564 eport++;
565 } else {
566 break;
570 ClearNameValueList(&data);
572 switch(r)
574 case 0: /* success */
575 bodylen = snprintf(body, sizeof(body), resp,
576 action, SERVICE_TYPE_WANIPC,
577 eport, action);
578 BuildSendAndCloseSoapResp(h, body, bodylen);
579 break;
580 case -2: /* already redirected */
581 SoapError(h, 718, "ConflictInMappingEntry");
582 break;
583 case -3: /* not permitted */
584 SoapError(h, 606, "Action not authorized");
585 break;
586 default:
587 SoapError(h, 501, "ActionFailed");
591 static void
592 GetSpecificPortMappingEntry(struct upnphttp * h, const char * action)
594 int r;
596 static const char resp[] =
597 "<u:%sResponse "
598 "xmlns:u=\"%s\">"
599 "<NewInternalPort>%u</NewInternalPort>"
600 "<NewInternalClient>%s</NewInternalClient>"
601 "<NewEnabled>1</NewEnabled>"
602 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
603 "<NewLeaseDuration>%u</NewLeaseDuration>"
604 "</u:%sResponse>";
606 char body[1024];
607 int bodylen;
608 struct NameValueParserData data;
609 const char * r_host, * ext_port, * protocol;
610 unsigned short eport, iport;
611 char int_ip[32];
612 char desc[64];
613 unsigned int leaseduration = 0;
615 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
616 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
617 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
618 protocol = GetValueFromNameValueList(&data, "NewProtocol");
620 #ifdef UPNP_STRICT
621 if(!ext_port || !protocol || !r_host)
622 #else
623 if(!ext_port || !protocol)
624 #endif
626 ClearNameValueList(&data);
627 SoapError(h, 402, "Invalid Args");
628 return;
630 #ifndef SUPPORT_REMOTEHOST
631 #ifdef UPNP_STRICT
632 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
634 ClearNameValueList(&data);
635 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
636 return;
638 #endif
639 #endif
641 eport = (unsigned short)atoi(ext_port);
643 /* TODO : add r_host as an input parameter ...
644 * We prevent several Port Mapping with same external port
645 * but different remoteHost to be set up, so that is not
646 * a priority. */
647 r = upnp_get_redirection_infos(eport, protocol, &iport,
648 int_ip, sizeof(int_ip),
649 desc, sizeof(desc),
650 NULL, 0,
651 &leaseduration);
653 if(r < 0)
655 SoapError(h, 714, "NoSuchEntryInArray");
657 else
659 syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
660 action,
661 r_host ? r_host : "NULL", ext_port, protocol, int_ip,
662 (unsigned int)iport, desc);
663 bodylen = snprintf(body, sizeof(body), resp,
664 action, SERVICE_TYPE_WANIPC,
665 (unsigned int)iport, int_ip, desc, leaseduration,
666 action);
667 BuildSendAndCloseSoapResp(h, body, bodylen);
670 ClearNameValueList(&data);
673 static void
674 DeletePortMapping(struct upnphttp * h, const char * action)
676 int r;
678 static const char resp[] =
679 "<u:DeletePortMappingResponse "
680 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
681 "</u:DeletePortMappingResponse>";
683 struct NameValueParserData data;
684 const char * ext_port, * protocol;
685 unsigned short eport;
686 #ifdef UPNP_STRICT
687 const char * r_host;
688 #endif /* UPNP_STRICT */
690 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
691 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
692 protocol = GetValueFromNameValueList(&data, "NewProtocol");
693 #ifdef UPNP_STRICT
694 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
695 #endif /* UPNP_STRICT */
697 #ifdef UPNP_STRICT
698 if(!ext_port || !protocol || !r_host)
699 #else
700 if(!ext_port || !protocol)
701 #endif /* UPNP_STRICT */
703 ClearNameValueList(&data);
704 SoapError(h, 402, "Invalid Args");
705 return;
707 #ifndef SUPPORT_REMOTEHOST
708 #ifdef UPNP_STRICT
709 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
711 ClearNameValueList(&data);
712 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
713 return;
715 #endif /* UPNP_STRICT */
716 #endif /* SUPPORT_REMOTEHOST */
718 eport = (unsigned short)atoi(ext_port);
720 syslog(LOG_INFO, "%s: external port: %hu, protocol: %s",
721 action, eport, protocol);
723 /* if in secure mode, check the IP
724 * Removing a redirection is not a security threat,
725 * just an annoyance for the user using it. So this is not
726 * a priority. */
727 if(GETFLAG(SECUREMODEMASK))
729 char int_ip[32];
730 struct in_addr int_ip_addr;
731 unsigned short iport;
732 unsigned int leaseduration = 0;
733 r = upnp_get_redirection_infos(eport, protocol, &iport,
734 int_ip, sizeof(int_ip),
735 NULL, 0, NULL, 0,
736 &leaseduration);
737 if(r >= 0)
739 if(inet_pton(AF_INET, int_ip, &int_ip_addr) > 0)
741 if(h->clientaddr.s_addr != int_ip_addr.s_addr)
743 SoapError(h, 606, "Action not authorized");
744 /*SoapError(h, 714, "NoSuchEntryInArray");*/
745 ClearNameValueList(&data);
746 return;
752 r = upnp_delete_redirection(eport, protocol);
754 if(r < 0)
756 SoapError(h, 714, "NoSuchEntryInArray");
758 else
760 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
763 ClearNameValueList(&data);
766 /* DeletePortMappingRange was added in IGD spec v2 */
767 static void
768 DeletePortMappingRange(struct upnphttp * h, const char * action)
770 int r = -1;
771 static const char resp[] =
772 "<u:DeletePortMappingRangeResponse "
773 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
774 "</u:DeletePortMappingRangeResponse>";
775 struct NameValueParserData data;
776 const char * protocol;
777 const char * startport_s, * endport_s;
778 unsigned short startport, endport;
779 /*int manage;*/
780 unsigned short * port_list;
781 unsigned int i, number = 0;
782 UNUSED(action);
784 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
785 startport_s = GetValueFromNameValueList(&data, "NewStartPort");
786 endport_s = GetValueFromNameValueList(&data, "NewEndPort");
787 protocol = GetValueFromNameValueList(&data, "NewProtocol");
788 /*manage = atoi(GetValueFromNameValueList(&data, "NewManage"));*/
789 if(startport_s == NULL || endport_s == NULL || protocol == NULL) {
790 SoapError(h, 402, "Invalid Args");
791 ClearNameValueList(&data);
792 return;
794 startport = (unsigned short)atoi(startport_s);
795 endport = (unsigned short)atoi(endport_s);
797 /* possible errors :
798 606 - Action not authorized
799 730 - PortMappingNotFound
800 733 - InconsistentParameter
802 if(startport > endport)
804 SoapError(h, 733, "InconsistentParameter");
805 ClearNameValueList(&data);
806 return;
809 syslog(LOG_INFO, "%s: deleting external ports: %hu-%hu, protocol: %s",
810 action, startport, endport, protocol);
812 port_list = upnp_get_portmappings_in_range(startport, endport,
813 protocol, &number);
814 if(number == 0)
816 SoapError(h, 730, "PortMappingNotFound");
817 ClearNameValueList(&data);
818 return;
821 for(i = 0; i < number; i++)
823 r = upnp_delete_redirection(port_list[i], protocol);
824 syslog(LOG_INFO, "%s: deleting external port: %hu, protocol: %s: %s",
825 action, port_list[i], protocol, r < 0 ? "failed" : "ok");
827 free(port_list);
828 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
830 ClearNameValueList(&data);
833 static void
834 GetGenericPortMappingEntry(struct upnphttp * h, const char * action)
836 int r;
838 static const char resp[] =
839 "<u:%sResponse "
840 "xmlns:u=\"%s\">"
841 "<NewRemoteHost>%s</NewRemoteHost>"
842 "<NewExternalPort>%u</NewExternalPort>"
843 "<NewProtocol>%s</NewProtocol>"
844 "<NewInternalPort>%u</NewInternalPort>"
845 "<NewInternalClient>%s</NewInternalClient>"
846 "<NewEnabled>1</NewEnabled>"
847 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
848 "<NewLeaseDuration>%u</NewLeaseDuration>"
849 "</u:%sResponse>";
851 long int index = 0;
852 unsigned short eport, iport;
853 const char * m_index;
854 char * endptr;
855 char protocol[4], iaddr[32];
856 char desc[64];
857 char rhost[40];
858 unsigned int leaseduration = 0;
859 struct NameValueParserData data;
861 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
862 m_index = GetValueFromNameValueList(&data, "NewPortMappingIndex");
864 if(!m_index)
866 ClearNameValueList(&data);
867 SoapError(h, 402, "Invalid Args");
868 return;
870 errno = 0; /* To distinguish success/failure after call */
871 index = strtol(m_index, &endptr, 10);
872 if((errno == ERANGE && (index == LONG_MAX || index == LONG_MIN))
873 || (errno != 0 && index == 0) || (m_index == endptr))
875 /* should condition (*endptr != '\0') be also an error ? */
876 if(m_index == endptr)
877 syslog(LOG_WARNING, "%s: no digits were found in <%s>",
878 "GetGenericPortMappingEntry", "NewPortMappingIndex");
879 else
880 syslog(LOG_WARNING, "%s: strtol('%s'): %m",
881 "GetGenericPortMappingEntry", m_index);
882 ClearNameValueList(&data);
883 SoapError(h, 402, "Invalid Args");
884 return;
887 syslog(LOG_INFO, "%s: index=%d", action, (int)index);
889 rhost[0] = '\0';
890 r = upnp_get_redirection_infos_by_index((int)index, &eport, protocol, &iport,
891 iaddr, sizeof(iaddr),
892 desc, sizeof(desc),
893 rhost, sizeof(rhost),
894 &leaseduration);
896 if(r < 0)
898 SoapError(h, 713, "SpecifiedArrayIndexInvalid");
900 else
902 int bodylen;
903 char body[2048];
904 bodylen = snprintf(body, sizeof(body), resp,
905 action, SERVICE_TYPE_WANIPC, rhost,
906 (unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc,
907 leaseduration, action);
908 BuildSendAndCloseSoapResp(h, body, bodylen);
911 ClearNameValueList(&data);
914 /* GetListOfPortMappings was added in the IGD v2 specification */
915 static void
916 GetListOfPortMappings(struct upnphttp * h, const char * action)
918 static const char resp_start[] =
919 "<u:%sResponse "
920 "xmlns:u=\"%s\">"
921 "<NewPortListing><![CDATA[";
922 static const char resp_end[] =
923 "]]></NewPortListing>"
924 "</u:%sResponse>";
926 static const char list_start[] =
927 "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
928 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
929 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
930 " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
931 static const char list_end[] =
932 "</p:PortMappingList>";
934 static const char entry[] =
935 "<p:PortMappingEntry>"
936 "<p:NewRemoteHost>%s</p:NewRemoteHost>"
937 "<p:NewExternalPort>%hu</p:NewExternalPort>"
938 "<p:NewProtocol>%s</p:NewProtocol>"
939 "<p:NewInternalPort>%hu</p:NewInternalPort>"
940 "<p:NewInternalClient>%s</p:NewInternalClient>"
941 "<p:NewEnabled>1</p:NewEnabled>"
942 "<p:NewDescription>%s</p:NewDescription>"
943 "<p:NewLeaseTime>%u</p:NewLeaseTime>"
944 "</p:PortMappingEntry>";
946 char * body;
947 size_t bodyalloc;
948 int bodylen;
950 int r = -1;
951 unsigned short iport;
952 char int_ip[32];
953 char desc[64];
954 char rhost[64];
955 unsigned int leaseduration = 0;
957 struct NameValueParserData data;
958 const char * startport_s, * endport_s;
959 unsigned short startport, endport;
960 const char * protocol;
961 /*int manage;*/
962 const char * number_s;
963 int number;
964 unsigned short * port_list;
965 unsigned int i, list_size = 0;
967 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
968 startport_s = GetValueFromNameValueList(&data, "NewStartPort");
969 endport_s = GetValueFromNameValueList(&data, "NewEndPort");
970 protocol = GetValueFromNameValueList(&data, "NewProtocol");
971 /*manage_s = GetValueFromNameValueList(&data, "NewManage");*/
972 number_s = GetValueFromNameValueList(&data, "NewNumberOfPorts");
973 if(startport_s == NULL || endport_s == NULL || protocol == NULL ||
974 number_s == NULL) {
975 SoapError(h, 402, "Invalid Args");
976 ClearNameValueList(&data);
977 return;
980 startport = (unsigned short)atoi(startport_s);
981 endport = (unsigned short)atoi(endport_s);
982 /*manage = atoi(manage_s);*/
983 number = atoi(number_s);
984 if(number == 0) number = 1000; /* return up to 1000 mappings by default */
986 if(startport > endport)
988 SoapError(h, 733, "InconsistentParameter");
989 ClearNameValueList(&data);
990 return;
993 build the PortMappingList xml document :
995 <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
996 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
997 xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
998 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
999 <p:PortMappingEntry>
1000 <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
1001 <p:NewExternalPort>2345</p:NewExternalPort>
1002 <p:NewProtocol>TCP</p:NewProtocol>
1003 <p:NewInternalPort>2345</p:NewInternalPort>
1004 <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
1005 <p:NewEnabled>1</p:NewEnabled>
1006 <p:NewDescription>dooom</p:NewDescription>
1007 <p:NewLeaseTime>345</p:NewLeaseTime>
1008 </p:PortMappingEntry>
1009 </p:PortMappingList>
1011 bodyalloc = 4096;
1012 body = malloc(bodyalloc);
1013 if(!body)
1015 ClearNameValueList(&data);
1016 SoapError(h, 501, "ActionFailed");
1017 return;
1019 bodylen = snprintf(body, bodyalloc, resp_start,
1020 action, SERVICE_TYPE_WANIPC);
1021 if(bodylen < 0)
1023 SoapError(h, 501, "ActionFailed");
1024 free(body);
1025 return;
1027 memcpy(body+bodylen, list_start, sizeof(list_start));
1028 bodylen += (sizeof(list_start) - 1);
1030 port_list = upnp_get_portmappings_in_range(startport, endport,
1031 protocol, &list_size);
1032 /* loop through port mappings */
1033 for(i = 0; number > 0 && i < list_size; i++)
1035 /* have a margin of 1024 bytes to store the new entry */
1036 if((unsigned int)bodylen + 1024 > bodyalloc)
1038 char * body_sav = body;
1039 bodyalloc += 4096;
1040 body = realloc(body, bodyalloc);
1041 if(!body)
1043 syslog(LOG_CRIT, "realloc(%p, %u) FAILED", body_sav, (unsigned)bodyalloc);
1044 ClearNameValueList(&data);
1045 SoapError(h, 501, "ActionFailed");
1046 free(body_sav);
1047 free(port_list);
1048 return;
1051 rhost[0] = '\0';
1052 r = upnp_get_redirection_infos(port_list[i], protocol, &iport,
1053 int_ip, sizeof(int_ip),
1054 desc, sizeof(desc),
1055 rhost, sizeof(rhost),
1056 &leaseduration);
1057 if(r == 0)
1059 bodylen += snprintf(body+bodylen, bodyalloc-bodylen, entry,
1060 rhost, port_list[i], protocol,
1061 iport, int_ip, desc, leaseduration);
1062 number--;
1065 free(port_list);
1066 port_list = NULL;
1068 if((bodylen + sizeof(list_end) + 1024) > bodyalloc)
1070 char * body_sav = body;
1071 bodyalloc += (sizeof(list_end) + 1024);
1072 body = realloc(body, bodyalloc);
1073 if(!body)
1075 syslog(LOG_CRIT, "realloc(%p, %u) FAILED", body_sav, (unsigned)bodyalloc);
1076 ClearNameValueList(&data);
1077 SoapError(h, 501, "ActionFailed");
1078 free(body_sav);
1079 return;
1082 memcpy(body+bodylen, list_end, sizeof(list_end));
1083 bodylen += (sizeof(list_end) - 1);
1084 bodylen += snprintf(body+bodylen, bodyalloc-bodylen, resp_end,
1085 action);
1086 BuildSendAndCloseSoapResp(h, body, bodylen);
1087 free(body);
1089 ClearNameValueList(&data);
1092 #ifdef ENABLE_L3F_SERVICE
1093 static void
1094 SetDefaultConnectionService(struct upnphttp * h, const char * action)
1096 static const char resp[] =
1097 "<u:SetDefaultConnectionServiceResponse "
1098 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1099 "</u:SetDefaultConnectionServiceResponse>";
1100 struct NameValueParserData data;
1101 char * p;
1102 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1103 p = GetValueFromNameValueList(&data, "NewDefaultConnectionService");
1104 if(p) {
1105 /* 720 InvalidDeviceUUID
1106 * 721 InvalidServiceID
1107 * 723 InvalidConnServiceSelection */
1108 #ifdef UPNP_STRICT
1109 char * service;
1110 service = strchr(p, ',');
1111 if(0 != memcmp(uuidvalue_wcd, p, sizeof("uuid:00000000-0000-0000-0000-000000000000") - 1)) {
1112 SoapError(h, 720, "InvalidDeviceUUID");
1113 } else if(service == NULL || 0 != strcmp(service+1, SERVICE_ID_WANIPC)) {
1114 SoapError(h, 721, "InvalidServiceID");
1115 } else
1116 #endif
1118 syslog(LOG_INFO, "%s(%s) : Ignored", action, p);
1119 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
1121 } else {
1122 /* missing argument */
1123 SoapError(h, 402, "Invalid Args");
1125 ClearNameValueList(&data);
1128 static void
1129 GetDefaultConnectionService(struct upnphttp * h, const char * action)
1131 static const char resp[] =
1132 "<u:%sResponse "
1133 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1134 "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
1135 SERVICE_ID_WANIPC "</NewDefaultConnectionService>"
1136 "</u:%sResponse>";
1137 /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
1138 * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
1139 * urn:upnp-org:serviceId:WANPPPConn1 */
1140 char body[1024];
1141 int bodylen;
1143 bodylen = snprintf(body, sizeof(body), resp,
1144 action, uuidvalue_wcd, action);
1145 BuildSendAndCloseSoapResp(h, body, bodylen);
1147 #endif
1149 /* Added for compliance with WANIPConnection v2 */
1150 static void
1151 SetConnectionType(struct upnphttp * h, const char * action)
1153 #ifdef UPNP_STRICT
1154 const char * connection_type;
1155 #endif /* UPNP_STRICT */
1156 struct NameValueParserData data;
1157 UNUSED(action);
1159 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1160 #ifdef UPNP_STRICT
1161 connection_type = GetValueFromNameValueList(&data, "NewConnectionType");
1162 if(!connection_type) {
1163 ClearNameValueList(&data);
1164 SoapError(h, 402, "Invalid Args");
1165 return;
1167 #endif /* UPNP_STRICT */
1168 /* Unconfigured, IP_Routed, IP_Bridged */
1169 ClearNameValueList(&data);
1170 /* always return a ReadOnly error */
1171 SoapError(h, 731, "ReadOnly");
1174 /* Added for compliance with WANIPConnection v2 */
1175 static void
1176 RequestConnection(struct upnphttp * h, const char * action)
1178 UNUSED(action);
1179 SoapError(h, 606, "Action not authorized");
1182 /* Added for compliance with WANIPConnection v2 */
1183 static void
1184 ForceTermination(struct upnphttp * h, const char * action)
1186 UNUSED(action);
1187 SoapError(h, 606, "Action not authorized");
1191 If a control point calls QueryStateVariable on a state variable that is not
1192 buffered in memory within (or otherwise available from) the service,
1193 the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1195 QueryStateVariable remains useful as a limited test tool but may not be
1196 part of some future versions of UPnP.
1198 static void
1199 QueryStateVariable(struct upnphttp * h, const char * action)
1201 static const char resp[] =
1202 "<u:%sResponse "
1203 "xmlns:u=\"%s\">"
1204 "<return>%s</return>"
1205 "</u:%sResponse>";
1207 char body[512];
1208 int bodylen;
1209 struct NameValueParserData data;
1210 const char * var_name;
1212 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1213 /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1214 /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1215 var_name = GetValueFromNameValueList(&data, "varName");
1217 /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1219 if(!var_name)
1221 SoapError(h, 402, "Invalid Args");
1223 else if(strcmp(var_name, "ConnectionStatus") == 0)
1225 const char * status;
1227 status = get_wan_connection_status_str(ext_if_name);
1228 bodylen = snprintf(body, sizeof(body), resp,
1229 action, "urn:schemas-upnp-org:control-1-0",
1230 status, action);
1231 BuildSendAndCloseSoapResp(h, body, bodylen);
1233 #if 0
1234 /* not usefull */
1235 else if(strcmp(var_name, "ConnectionType") == 0)
1237 bodylen = snprintf(body, sizeof(body), resp, "IP_Routed");
1238 BuildSendAndCloseSoapResp(h, body, bodylen);
1240 else if(strcmp(var_name, "LastConnectionError") == 0)
1242 bodylen = snprintf(body, sizeof(body), resp, "ERROR_NONE");
1243 BuildSendAndCloseSoapResp(h, body, bodylen);
1245 #endif
1246 else if(strcmp(var_name, "PortMappingNumberOfEntries") == 0)
1248 char strn[10];
1249 snprintf(strn, sizeof(strn), "%i",
1250 upnp_get_portmapping_number_of_entries());
1251 bodylen = snprintf(body, sizeof(body), resp,
1252 action, "urn:schemas-upnp-org:control-1-0",
1253 strn, action);
1254 BuildSendAndCloseSoapResp(h, body, bodylen);
1256 else
1258 syslog(LOG_NOTICE, "%s: Unknown: %s", action, var_name?var_name:"");
1259 SoapError(h, 404, "Invalid Var");
1262 ClearNameValueList(&data);
1265 #ifdef ENABLE_6FC_SERVICE
1266 #ifndef ENABLE_IPV6
1267 #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1268 #endif
1269 /* WANIPv6FirewallControl actions */
1270 static void
1271 GetFirewallStatus(struct upnphttp * h, const char * action)
1273 static const char resp[] =
1274 "<u:%sResponse "
1275 "xmlns:u=\"%s\">"
1276 "<FirewallEnabled>%d</FirewallEnabled>"
1277 "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1278 "</u:%sResponse>";
1280 char body[512];
1281 int bodylen;
1283 bodylen = snprintf(body, sizeof(body), resp,
1284 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1285 GETFLAG(IPV6FCFWDISABLEDMASK) ? 0 : 1,
1286 GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK) ? 0 : 1,
1287 action);
1288 BuildSendAndCloseSoapResp(h, body, bodylen);
1291 static int
1292 CheckStatus(struct upnphttp * h)
1294 if (GETFLAG(IPV6FCFWDISABLEDMASK))
1296 SoapError(h, 702, "FirewallDisabled");
1297 return 0;
1299 else if(GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK))
1301 SoapError(h, 703, "InboundPinholeNotAllowed");
1302 return 0;
1304 else
1305 return 1;
1308 #if 0
1309 static int connecthostport(const char * host, unsigned short port, char * result)
1311 int s, n;
1312 char hostname[INET6_ADDRSTRLEN];
1313 char port_str[8], ifname[8], tmp[4];
1314 struct addrinfo *ai, *p;
1315 struct addrinfo hints;
1317 memset(&hints, 0, sizeof(hints));
1318 /* hints.ai_flags = AI_ADDRCONFIG; */
1319 #ifdef AI_NUMERICSERV
1320 hints.ai_flags = AI_NUMERICSERV;
1321 #endif
1322 hints.ai_socktype = SOCK_STREAM;
1323 hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
1324 /* hints.ai_protocol = IPPROTO_TCP; */
1325 snprintf(port_str, sizeof(port_str), "%hu", port);
1326 strcpy(hostname, host);
1327 if(!strncmp(host, "fe80", 4))
1329 printf("Using an linklocal address\n");
1330 strcpy(ifname, "%");
1331 snprintf(tmp, sizeof(tmp), "%d", linklocal_index);
1332 strcat(ifname, tmp);
1333 strcat(hostname, ifname);
1334 printf("host: %s\n", hostname);
1336 n = getaddrinfo(hostname, port_str, &hints, &ai);
1337 if(n != 0)
1339 fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
1340 return -1;
1342 s = -1;
1343 for(p = ai; p; p = p->ai_next)
1345 #ifdef DEBUG
1346 char tmp_host[256];
1347 char tmp_service[256];
1348 printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1349 p->ai_family, p->ai_socktype, p->ai_protocol, p->ai_addrlen);
1350 getnameinfo(p->ai_addr, p->ai_addrlen, tmp_host, sizeof(tmp_host),
1351 tmp_service, sizeof(tmp_service),
1352 NI_NUMERICHOST | NI_NUMERICSERV);
1353 printf(" host=%s service=%s\n", tmp_host, tmp_service);
1354 #endif
1355 inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr), result, INET6_ADDRSTRLEN);
1356 return 0;
1358 freeaddrinfo(ai);
1360 #endif
1362 /* Check the security policy right */
1363 static int
1364 PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short int_port)
1366 int n;
1367 char senderAddr[INET6_ADDRSTRLEN]="";
1368 struct addrinfo hints, *ai, *p;
1369 struct in6_addr result_ip;
1371 /* Pinhole InternalClient address must correspond to the action sender */
1372 syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)");
1374 hints.ai_socktype = SOCK_STREAM;
1375 hints.ai_family = AF_UNSPEC;
1377 /* if ip not valid assume hostname and convert */
1378 if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0)
1380 n = getaddrinfo(int_ip, NULL, &hints, &ai);
1381 if(!n && ai->ai_family == AF_INET6)
1383 for(p = ai; p; p = p->ai_next)
1385 inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr));
1386 result_ip = *((struct in6_addr *) p);
1387 /* TODO : deal with more than one ip per hostname */
1388 break;
1391 else
1393 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
1394 SoapError(h, 402, "Invalid Args");
1395 return -1;
1397 freeaddrinfo(p);
1400 if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN) == NULL)
1402 syslog(LOG_ERR, "inet_ntop: %m");
1404 #ifdef DEBUG
1405 printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr, int_ip);
1406 #endif
1407 if(strcmp(senderAddr, int_ip) != 0)
1408 if(h->clientaddr_v6.s6_addr != result_ip.s6_addr)
1410 syslog(LOG_INFO, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1411 senderAddr, int_ip);
1412 SoapError(h, 606, "Action not authorized");
1413 return 0;
1416 /* Pinhole InternalPort must be greater than or equal to 1024 */
1417 if (int_port < 1024)
1419 syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1420 senderAddr);
1421 SoapError(h, 606, "Action not authorized");
1422 return 0;
1424 return 1;
1427 static void
1428 AddPinhole(struct upnphttp * h, const char * action)
1430 int r;
1431 static const char resp[] =
1432 "<u:%sResponse "
1433 "xmlns:u=\"%s\">"
1434 "<UniqueID>%d</UniqueID>"
1435 "</u:%sResponse>";
1436 char body[512];
1437 int bodylen;
1438 struct NameValueParserData data;
1439 char * rem_host, * rem_port, * int_ip, * int_port, * protocol, * leaseTime;
1440 int uid = 0;
1441 unsigned short iport, rport;
1442 int ltime;
1443 long proto;
1444 char rem_ip[INET6_ADDRSTRLEN];
1446 if(CheckStatus(h)==0)
1447 return;
1449 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1450 rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1451 rem_port = GetValueFromNameValueList(&data, "RemotePort");
1452 int_ip = GetValueFromNameValueList(&data, "InternalClient");
1453 int_port = GetValueFromNameValueList(&data, "InternalPort");
1454 protocol = GetValueFromNameValueList(&data, "Protocol");
1455 leaseTime = GetValueFromNameValueList(&data, "LeaseTime");
1457 rport = (unsigned short)(rem_port ? atoi(rem_port) : 0);
1458 iport = (unsigned short)(int_port ? atoi(int_port) : 0);
1459 ltime = leaseTime ? atoi(leaseTime) : -1;
1460 errno = 0;
1461 proto = protocol ? strtol(protocol, NULL, 0) : -1;
1462 if(errno != 0 || proto > 65535 || proto < 0)
1464 SoapError(h, 402, "Invalid Args");
1465 goto clear_and_exit;
1467 if(iport == 0)
1469 SoapError(h, 706, "InternalPortWilcardingNotAllowed");
1470 goto clear_and_exit;
1473 /* In particular, [IGD2] RECOMMENDS that unauthenticated and
1474 * unauthorized control points are only allowed to invoke
1475 * this action with:
1476 * - InternalPort value greater than or equal to 1024,
1477 * - InternalClient value equals to the control point's IP address.
1478 * It is REQUIRED that InternalClient cannot be one of IPv6
1479 * addresses used by the gateway. */
1480 if(!int_ip || 0 == strlen(int_ip) || 0 == strcmp(int_ip, "*"))
1482 SoapError(h, 708, "WildCardNotPermittedInSrcIP");
1483 goto clear_and_exit;
1485 /* I guess it is useless to convert int_ip to literal ipv6 address */
1486 /* rem_host should be converted to literal ipv6 : */
1487 if(rem_host && (rem_host[0] != '\0'))
1489 struct addrinfo *ai, *p;
1490 struct addrinfo hints;
1491 int err;
1492 memset(&hints, 0, sizeof(struct addrinfo));
1493 hints.ai_family = AF_INET6;
1494 /*hints.ai_flags = */
1495 /* hints.ai_protocol = proto; */
1496 err = getaddrinfo(rem_host, rem_port, &hints, &ai);
1497 if(err == 0)
1499 /* take the 1st IPv6 address */
1500 for(p = ai; p; p = p->ai_next)
1502 if(p->ai_family == AF_INET6)
1504 inet_ntop(AF_INET6,
1505 &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr),
1506 rem_ip, sizeof(rem_ip));
1507 syslog(LOG_INFO, "resolved '%s' to '%s'", rem_host, rem_ip);
1508 rem_host = rem_ip;
1509 break;
1512 freeaddrinfo(ai);
1514 else
1516 syslog(LOG_WARNING, "AddPinhole : getaddrinfo(%s) : %s",
1517 rem_host, gai_strerror(err));
1518 #if 0
1519 SoapError(h, 402, "Invalid Args");
1520 goto clear_and_exit;
1521 #endif
1525 if(proto == 65535)
1527 SoapError(h, 707, "ProtocolWilcardingNotAllowed");
1528 goto clear_and_exit;
1530 if(proto != IPPROTO_UDP && proto != IPPROTO_TCP
1531 #ifdef IPPROTO_UDPITE
1532 && atoi(protocol) != IPPROTO_UDPLITE
1533 #endif
1536 SoapError(h, 705, "ProtocolNotSupported");
1537 goto clear_and_exit;
1539 if(ltime < 1 || ltime > 86400)
1541 syslog(LOG_WARNING, "%s: LeaseTime=%d not supported, (ip=%s)",
1542 action, ltime, int_ip);
1543 SoapError(h, 402, "Invalid Args");
1544 goto clear_and_exit;
1547 if(PinholeVerification(h, int_ip, iport) <= 0)
1548 goto clear_and_exit;
1550 syslog(LOG_INFO, "%s: (inbound) from [%s]:%hu to [%s]:%hu with proto %ld during %d sec",
1551 action, rem_host?rem_host:"any",
1552 rport, int_ip, iport,
1553 proto, ltime);
1555 /* In cases where the RemoteHost, RemotePort, InternalPort,
1556 * InternalClient and Protocol are the same than an existing pinhole,
1557 * but LeaseTime is different, the device MUST extend the existing
1558 * pinhole's lease time and return the UniqueID of the existing pinhole. */
1559 r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, proto, "IGD2 pinhole", ltime, &uid);
1561 switch(r)
1563 case 1: /* success */
1564 bodylen = snprintf(body, sizeof(body),
1565 resp, action,
1566 "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1567 uid, action);
1568 BuildSendAndCloseSoapResp(h, body, bodylen);
1569 break;
1570 case -1: /* not permitted */
1571 SoapError(h, 701, "PinholeSpaceExhausted");
1572 break;
1573 default:
1574 SoapError(h, 501, "ActionFailed");
1575 break;
1577 /* 606 Action not authorized
1578 * 701 PinholeSpaceExhausted
1579 * 702 FirewallDisabled
1580 * 703 InboundPinholeNotAllowed
1581 * 705 ProtocolNotSupported
1582 * 706 InternalPortWildcardingNotAllowed
1583 * 707 ProtocolWildcardingNotAllowed
1584 * 708 WildCardNotPermittedInSrcIP */
1585 clear_and_exit:
1586 ClearNameValueList(&data);
1589 static void
1590 UpdatePinhole(struct upnphttp * h, const char * action)
1592 static const char resp[] =
1593 "<u:UpdatePinholeResponse "
1594 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1595 "</u:UpdatePinholeResponse>";
1596 struct NameValueParserData data;
1597 const char * uid_str, * leaseTime;
1598 char iaddr[INET6_ADDRSTRLEN];
1599 unsigned short iport;
1600 int ltime;
1601 int uid;
1602 int n;
1604 if(CheckStatus(h)==0)
1605 return;
1607 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1608 uid_str = GetValueFromNameValueList(&data, "UniqueID");
1609 leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime");
1610 uid = uid_str ? atoi(uid_str) : -1;
1611 ltime = leaseTime ? atoi(leaseTime) : -1;
1612 ClearNameValueList(&data);
1614 if(uid < 0 || uid > 65535 || ltime <= 0 || ltime > 86400)
1616 SoapError(h, 402, "Invalid Args");
1617 return;
1620 /* Check that client is not updating an pinhole
1621 * it doesn't have access to, because of its public access */
1622 n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
1623 iaddr, sizeof(iaddr), &iport,
1624 NULL, /* proto */
1625 NULL, 0, /* desc, desclen */
1626 NULL, NULL);
1627 if (n >= 0)
1629 if(PinholeVerification(h, iaddr, iport) <= 0)
1630 return;
1632 else if(n == -2)
1634 SoapError(h, 704, "NoSuchEntry");
1635 return;
1637 else
1639 SoapError(h, 501, "ActionFailed");
1640 return;
1643 syslog(LOG_INFO, "%s: (inbound) updating lease duration to %d for pinhole with ID: %d",
1644 action, ltime, uid);
1646 n = upnp_update_inboundpinhole(uid, ltime);
1647 if(n == -1)
1648 SoapError(h, 704, "NoSuchEntry");
1649 else if(n < 0)
1650 SoapError(h, 501, "ActionFailed");
1651 else
1652 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
1655 static void
1656 GetOutboundPinholeTimeout(struct upnphttp * h, const char * action)
1658 int r;
1660 static const char resp[] =
1661 "<u:%sResponse "
1662 "xmlns:u=\"%s\">"
1663 "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1664 "</u:%sResponse>";
1666 char body[512];
1667 int bodylen;
1668 struct NameValueParserData data;
1669 char * int_ip, * int_port, * rem_host, * rem_port, * protocol;
1670 int opt=0, proto=0;
1671 unsigned short iport, rport;
1673 if (GETFLAG(IPV6FCFWDISABLEDMASK))
1675 SoapError(h, 702, "FirewallDisabled");
1676 return;
1679 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1680 int_ip = GetValueFromNameValueList(&data, "InternalClient");
1681 int_port = GetValueFromNameValueList(&data, "InternalPort");
1682 rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1683 rem_port = GetValueFromNameValueList(&data, "RemotePort");
1684 protocol = GetValueFromNameValueList(&data, "Protocol");
1686 rport = (unsigned short)atoi(rem_port);
1687 iport = (unsigned short)atoi(int_port);
1688 proto = atoi(protocol);
1690 syslog(LOG_INFO, "%s: retrieving timeout for outbound pinhole from [%s]:%hu to [%s]:%hu protocol %s", action, int_ip, iport,rem_host, rport, protocol);
1692 /* TODO */
1693 r = -1;/*upnp_check_outbound_pinhole(proto, &opt);*/
1695 switch(r)
1697 case 1: /* success */
1698 bodylen = snprintf(body, sizeof(body), resp,
1699 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1700 opt, action);
1701 BuildSendAndCloseSoapResp(h, body, bodylen);
1702 break;
1703 case -5: /* Protocol not supported */
1704 SoapError(h, 705, "ProtocolNotSupported");
1705 break;
1706 default:
1707 SoapError(h, 501, "ActionFailed");
1709 ClearNameValueList(&data);
1712 static void
1713 DeletePinhole(struct upnphttp * h, const char * action)
1715 int n;
1717 static const char resp[] =
1718 "<u:DeletePinholeResponse "
1719 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1720 "</u:DeletePinholeResponse>";
1722 struct NameValueParserData data;
1723 const char * uid_str;
1724 char iaddr[INET6_ADDRSTRLEN];
1725 int proto;
1726 unsigned short iport;
1727 unsigned int leasetime;
1728 int uid;
1730 if(CheckStatus(h)==0)
1731 return;
1733 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1734 uid_str = GetValueFromNameValueList(&data, "UniqueID");
1735 uid = uid_str ? atoi(uid_str) : -1;
1736 ClearNameValueList(&data);
1738 if(uid < 0 || uid > 65535)
1740 SoapError(h, 402, "Invalid Args");
1741 return;
1744 /* Check that client is not deleting an pinhole
1745 * it doesn't have access to, because of its public access */
1746 n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
1747 iaddr, sizeof(iaddr), &iport,
1748 &proto,
1749 NULL, 0, /* desc, desclen */
1750 &leasetime, NULL);
1751 if (n >= 0)
1753 if(PinholeVerification(h, iaddr, iport) <= 0)
1754 return;
1756 else if(n == -2)
1758 SoapError(h, 704, "NoSuchEntry");
1759 return;
1761 else
1763 SoapError(h, 501, "ActionFailed");
1764 return;
1767 n = upnp_delete_inboundpinhole(uid);
1768 if(n < 0)
1770 syslog(LOG_INFO, "%s: (inbound) failed to remove pinhole with ID: %d",
1771 action, uid);
1772 SoapError(h, 501, "ActionFailed");
1773 return;
1775 syslog(LOG_INFO, "%s: (inbound) pinhole with ID %d successfully removed",
1776 action, uid);
1777 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
1780 static void
1781 CheckPinholeWorking(struct upnphttp * h, const char * action)
1783 static const char resp[] =
1784 "<u:%sResponse "
1785 "xmlns:u=\"%s\">"
1786 "<IsWorking>%d</IsWorking>"
1787 "</u:%sResponse>";
1788 char body[512];
1789 int bodylen;
1790 int r;
1791 struct NameValueParserData data;
1792 const char * uid_str;
1793 int uid;
1794 char iaddr[INET6_ADDRSTRLEN];
1795 unsigned short iport;
1796 unsigned int packets;
1798 if(CheckStatus(h)==0)
1799 return;
1801 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1802 uid_str = GetValueFromNameValueList(&data, "UniqueID");
1803 uid = uid_str ? atoi(uid_str) : -1;
1804 ClearNameValueList(&data);
1806 if(uid < 0 || uid > 65535)
1808 SoapError(h, 402, "Invalid Args");
1809 return;
1812 /* Check that client is not checking a pinhole
1813 * it doesn't have access to, because of its public access */
1814 r = upnp_get_pinhole_info(uid,
1815 NULL, 0, NULL,
1816 iaddr, sizeof(iaddr), &iport,
1817 NULL, /* proto */
1818 NULL, 0, /* desc, desclen */
1819 NULL, &packets);
1820 if (r >= 0)
1822 if(PinholeVerification(h, iaddr, iport) <= 0)
1823 return ;
1824 if(packets == 0)
1826 SoapError(h, 709, "NoPacketSent");
1827 return;
1829 bodylen = snprintf(body, sizeof(body), resp,
1830 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1831 1, action);
1832 BuildSendAndCloseSoapResp(h, body, bodylen);
1834 else if(r == -2)
1835 SoapError(h, 704, "NoSuchEntry");
1836 else
1837 SoapError(h, 501, "ActionFailed");
1840 static void
1841 GetPinholePackets(struct upnphttp * h, const char * action)
1843 static const char resp[] =
1844 "<u:%sResponse "
1845 "xmlns:u=\"%s\">"
1846 "<PinholePackets>%u</PinholePackets>"
1847 "</u:%sResponse>";
1848 char body[512];
1849 int bodylen;
1850 struct NameValueParserData data;
1851 const char * uid_str;
1852 int n;
1853 char iaddr[INET6_ADDRSTRLEN];
1854 unsigned short iport;
1855 unsigned int packets = 0;
1856 int uid;
1857 int proto;
1858 unsigned int leasetime;
1860 if(CheckStatus(h)==0)
1861 return;
1863 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1864 uid_str = GetValueFromNameValueList(&data, "UniqueID");
1865 uid = uid_str ? atoi(uid_str) : -1;
1866 ClearNameValueList(&data);
1868 if(uid < 0 || uid > 65535)
1870 SoapError(h, 402, "Invalid Args");
1871 return;
1874 /* Check that client is not getting infos of a pinhole
1875 * it doesn't have access to, because of its public access */
1876 n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
1877 iaddr, sizeof(iaddr), &iport,
1878 &proto,
1879 NULL, 0, /* desc, desclen */
1880 &leasetime, &packets);
1881 if (n >= 0)
1883 if(PinholeVerification(h, iaddr, iport)<=0)
1884 return ;
1886 #if 0
1887 else if(r == -4 || r == -1)
1889 SoapError(h, 704, "NoSuchEntry");
1891 #endif
1893 bodylen = snprintf(body, sizeof(body), resp,
1894 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1895 packets, action);
1896 BuildSendAndCloseSoapResp(h, body, bodylen);
1898 #endif
1900 #ifdef ENABLE_DP_SERVICE
1901 static void
1902 SendSetupMessage(struct upnphttp * h, const char * action)
1904 static const char resp[] =
1905 "<u:%sResponse "
1906 "xmlns:u=\"%s\">"
1907 "<NewOutMessage>%s</NewOutMessage>"
1908 "</u:%sResponse>";
1909 char body[1024];
1910 int bodylen;
1911 struct NameValueParserData data;
1912 const char * ProtocolType; /* string */
1913 const char * InMessage; /* base64 */
1914 const char * OutMessage = ""; /* base64 */
1916 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1917 ProtocolType = GetValueFromNameValueList(&data, "NewProtocolType"); /* string */
1918 InMessage = GetValueFromNameValueList(&data, "NewInMessage"); /* base64 */
1920 if(ProtocolType == NULL || InMessage == NULL)
1922 ClearNameValueList(&data);
1923 SoapError(h, 402, "Invalid Args");
1924 return;
1926 /*if(strcmp(ProtocolType, "DeviceProtection:1") != 0)*/
1927 if(strcmp(ProtocolType, "WPS") != 0)
1929 ClearNameValueList(&data);
1930 SoapError(h, 600, "Argument Value Invalid"); /* 703 ? */
1931 return;
1933 /* TODO : put here code for WPS */
1935 bodylen = snprintf(body, sizeof(body), resp,
1936 action, "urn:schemas-upnp-org:service:DeviceProtection:1",
1937 OutMessage, action);
1938 BuildSendAndCloseSoapResp(h, body, bodylen);
1939 ClearNameValueList(&data);
1942 static void
1943 GetSupportedProtocols(struct upnphttp * h, const char * action)
1945 static const char resp[] =
1946 "<u:%sResponse "
1947 "xmlns:u=\"%s\">"
1948 "<NewProtocolList>%s</NewProtocolList>"
1949 "</u:%sResponse>";
1950 char body[1024];
1951 int bodylen;
1952 const char * ProtocolList =
1953 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1954 "<SupportedProtocols xmlns=\"urn:schemas-upnp-org:gw:DeviceProtection\""
1955 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
1956 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:DeviceProtection"
1957 " http://www.upnp.org/schemas/gw/DeviceProtection-v1.xsd\">"
1958 "<Introduction><Name>WPS</Name></Introduction>"
1959 "<Login><Name>PKCS5</Name></Login>"
1960 "</SupportedProtocols>";
1962 bodylen = snprintf(body, sizeof(body), resp,
1963 action, "urn:schemas-upnp-org:service:DeviceProtection:1",
1964 ProtocolList, action);
1965 BuildSendAndCloseSoapResp(h, body, bodylen);
1968 static void
1969 GetAssignedRoles(struct upnphttp * h, const char * action)
1971 static const char resp[] =
1972 "<u:%sResponse "
1973 "xmlns:u=\"%s\">"
1974 "<NewRoleList>%s</NewRoleList>"
1975 "</u:%sResponse>";
1976 char body[1024];
1977 int bodylen;
1978 const char * RoleList = "Public"; /* list of roles separated by spaces */
1980 #ifdef ENABLE_HTTPS
1981 if(h->ssl != NULL) {
1982 /* we should get the Roles of the session (based on client certificate) */
1983 X509 * peercert;
1984 peercert = SSL_get_peer_certificate(h->ssl);
1985 if(peercert != NULL) {
1986 RoleList = "Admin Basic";
1987 X509_free(peercert);
1990 #endif
1992 bodylen = snprintf(body, sizeof(body), resp,
1993 action, "urn:schemas-upnp-org:service:DeviceProtection:1",
1994 RoleList, action);
1995 BuildSendAndCloseSoapResp(h, body, bodylen);
1997 #endif
1999 /* Windows XP as client send the following requests :
2000 * GetConnectionTypeInfo
2001 * GetNATRSIPStatus
2002 * ? GetTotalBytesSent - WANCommonInterfaceConfig
2003 * ? GetTotalBytesReceived - idem
2004 * ? GetTotalPacketsSent - idem
2005 * ? GetTotalPacketsReceived - idem
2006 * GetCommonLinkProperties - idem
2007 * GetStatusInfo - WANIPConnection
2008 * GetExternalIPAddress
2009 * QueryStateVariable / ConnectionStatus!
2011 static const struct
2013 const char * methodName;
2014 void (*methodImpl)(struct upnphttp *, const char *);
2016 soapMethods[] =
2018 /* WANCommonInterfaceConfig */
2019 { "QueryStateVariable", QueryStateVariable},
2020 { "GetTotalBytesSent", GetTotalBytesSent},
2021 { "GetTotalBytesReceived", GetTotalBytesReceived},
2022 { "GetTotalPacketsSent", GetTotalPacketsSent},
2023 { "GetTotalPacketsReceived", GetTotalPacketsReceived},
2024 { "GetCommonLinkProperties", GetCommonLinkProperties},
2025 { "GetStatusInfo", GetStatusInfo},
2026 /* WANIPConnection */
2027 { "GetConnectionTypeInfo", GetConnectionTypeInfo },
2028 { "GetNATRSIPStatus", GetNATRSIPStatus},
2029 { "GetExternalIPAddress", GetExternalIPAddress},
2030 { "AddPortMapping", AddPortMapping},
2031 { "DeletePortMapping", DeletePortMapping},
2032 { "GetGenericPortMappingEntry", GetGenericPortMappingEntry},
2033 { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry},
2034 /* Required in WANIPConnection:2 */
2035 { "SetConnectionType", SetConnectionType},
2036 { "RequestConnection", RequestConnection},
2037 { "ForceTermination", ForceTermination},
2038 { "AddAnyPortMapping", AddAnyPortMapping},
2039 { "DeletePortMappingRange", DeletePortMappingRange},
2040 { "GetListOfPortMappings", GetListOfPortMappings},
2041 #ifdef ENABLE_L3F_SERVICE
2042 /* Layer3Forwarding */
2043 { "SetDefaultConnectionService", SetDefaultConnectionService},
2044 { "GetDefaultConnectionService", GetDefaultConnectionService},
2045 #endif
2046 #ifdef ENABLE_6FC_SERVICE
2047 /* WANIPv6FirewallControl */
2048 { "GetFirewallStatus", GetFirewallStatus}, /* Required */
2049 { "AddPinhole", AddPinhole}, /* Required */
2050 { "UpdatePinhole", UpdatePinhole}, /* Required */
2051 { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout}, /* Optional */
2052 { "DeletePinhole", DeletePinhole}, /* Required */
2053 { "CheckPinholeWorking", CheckPinholeWorking}, /* Optional */
2054 { "GetPinholePackets", GetPinholePackets}, /* Required */
2055 #endif
2056 #ifdef ENABLE_DP_SERVICE
2057 /* DeviceProtection */
2058 { "SendSetupMessage", SendSetupMessage}, /* Required */
2059 { "GetSupportedProtocols", GetSupportedProtocols}, /* Required */
2060 { "GetAssignedRoles", GetAssignedRoles}, /* Required */
2061 #endif
2062 { 0, 0 }
2065 void
2066 ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
2068 char * p;
2069 char * p2;
2070 int i, len, methodlen;
2072 /* SoapAction example :
2073 * urn:schemas-upnp-org:service:WANIPConnection:1#GetStatusInfo */
2074 p = strchr(action, '#');
2075 if(p && (p - action) < n) {
2076 p++;
2077 p2 = strchr(p, '"');
2078 if(p2 && (p2 - action) <= n)
2079 methodlen = p2 - p;
2080 else
2081 methodlen = n - (p - action);
2082 /*syslog(LOG_DEBUG, "SoapMethod: %.*s %d %d %p %p %d",
2083 methodlen, p, methodlen, n, action, p, (int)(p - action));*/
2084 for(i = 0; soapMethods[i].methodName; i++) {
2085 len = strlen(soapMethods[i].methodName);
2086 if((len == methodlen) && memcmp(p, soapMethods[i].methodName, len) == 0) {
2087 #ifdef DEBUG
2088 syslog(LOG_DEBUG, "Remote Call of SoapMethod '%s'",
2089 soapMethods[i].methodName);
2090 #endif /* DEBUG */
2091 soapMethods[i].methodImpl(h, soapMethods[i].methodName);
2092 return;
2095 syslog(LOG_NOTICE, "SoapMethod: Unknown: %.*s", methodlen, p);
2096 } else {
2097 syslog(LOG_NOTICE, "cannot parse SoapAction");
2100 SoapError(h, 401, "Invalid Action");
2103 /* Standard Errors:
2105 * errorCode errorDescription Description
2106 * -------- ---------------- -----------
2107 * 401 Invalid Action No action by that name at this service.
2108 * 402 Invalid Args Could be any of the following: not enough in args,
2109 * too many in args, no in arg by that name,
2110 * one or more in args are of the wrong data type.
2111 * 403 Out of Sync Out of synchronization.
2112 * 501 Action Failed May be returned in current state of service
2113 * prevents invoking that action.
2114 * 600-699 TBD Common action errors. Defined by UPnP Forum
2115 * Technical Committee.
2116 * 700-799 TBD Action-specific errors for standard actions.
2117 * Defined by UPnP Forum working committee.
2118 * 800-899 TBD Action-specific errors for non-standard actions.
2119 * Defined by UPnP vendor.
2121 void
2122 SoapError(struct upnphttp * h, int errCode, const char * errDesc)
2124 static const char resp[] =
2125 "<s:Envelope "
2126 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
2127 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
2128 "<s:Body>"
2129 "<s:Fault>"
2130 "<faultcode>s:Client</faultcode>"
2131 "<faultstring>UPnPError</faultstring>"
2132 "<detail>"
2133 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
2134 "<errorCode>%d</errorCode>"
2135 "<errorDescription>%s</errorDescription>"
2136 "</UPnPError>"
2137 "</detail>"
2138 "</s:Fault>"
2139 "</s:Body>"
2140 "</s:Envelope>";
2142 char body[2048];
2143 int bodylen;
2145 syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc);
2146 bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc);
2147 BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen);
2148 SendRespAndClose_upnphttp(h);