miniupnpd 1.9 (20160113)
[tomato.git] / release / src / router / miniupnpd / upnpsoap.c
blob1eb64e6779c5b03c03f5c755224a067414c00b3f
1 /* $Id: upnpsoap.c,v 1.142 2015/12/15 11:12:37 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, const char * ns)
70 #if 0
71 static const char resp[] =
72 "<u:GetConnectionTypeInfoResponse "
73 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
74 "<NewConnectionType>IP_Routed</NewConnectionType>"
75 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
76 "</u:GetConnectionTypeInfoResponse>";
77 #endif
78 static const char resp[] =
79 "<u:%sResponse "
80 "xmlns:u=\"%s\">"
81 "<NewConnectionType>IP_Routed</NewConnectionType>"
82 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
83 "</u:%sResponse>";
84 char body[512];
85 int bodylen;
87 bodylen = snprintf(body, sizeof(body), resp,
88 action, ns, action);
89 BuildSendAndCloseSoapResp(h, body, bodylen);
92 static void
93 GetTotalBytesSent(struct upnphttp * h, const char * action, const char * ns)
95 int r;
97 static const char resp[] =
98 "<u:%sResponse "
99 "xmlns:u=\"%s\">"
100 "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
101 "</u:%sResponse>";
103 char body[512];
104 int bodylen;
105 struct ifdata data;
107 r = getifstats(ext_if_name, &data);
108 bodylen = snprintf(body, sizeof(body), resp,
109 action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
110 r<0?0:data.obytes, action);
111 BuildSendAndCloseSoapResp(h, body, bodylen);
114 static void
115 GetTotalBytesReceived(struct upnphttp * h, const char * action, const char * ns)
117 int r;
119 static const char resp[] =
120 "<u:%sResponse "
121 "xmlns:u=\"%s\">"
122 "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
123 "</u:%sResponse>";
125 char body[512];
126 int bodylen;
127 struct ifdata data;
129 r = getifstats(ext_if_name, &data);
130 bodylen = snprintf(body, sizeof(body), resp,
131 action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
132 r<0?0:data.ibytes, action);
133 BuildSendAndCloseSoapResp(h, body, bodylen);
136 static void
137 GetTotalPacketsSent(struct upnphttp * h, const char * action, const char * ns)
139 int r;
141 static const char resp[] =
142 "<u:%sResponse "
143 "xmlns:u=\"%s\">"
144 "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
145 "</u:%sResponse>";
147 char body[512];
148 int bodylen;
149 struct ifdata data;
151 r = getifstats(ext_if_name, &data);
152 bodylen = snprintf(body, sizeof(body), resp,
153 action, ns,/*"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",*/
154 r<0?0:data.opackets, action);
155 BuildSendAndCloseSoapResp(h, body, bodylen);
158 static void
159 GetTotalPacketsReceived(struct upnphttp * h, const char * action, const char * ns)
161 int r;
163 static const char resp[] =
164 "<u:%sResponse "
165 "xmlns:u=\"%s\">"
166 "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
167 "</u:%sResponse>";
169 char body[512];
170 int bodylen;
171 struct ifdata data;
173 r = getifstats(ext_if_name, &data);
174 bodylen = snprintf(body, sizeof(body), resp,
175 action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
176 r<0?0:data.ipackets, action);
177 BuildSendAndCloseSoapResp(h, body, bodylen);
180 static void
181 GetCommonLinkProperties(struct upnphttp * h, const char * action, const char * ns)
183 /* WANAccessType : set depending on the hardware :
184 * DSL, POTS (plain old Telephone service), Cable, Ethernet */
185 static const char resp[] =
186 "<u:%sResponse "
187 "xmlns:u=\"%s\">"
188 "<NewWANAccessType>%s</NewWANAccessType>"
189 "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
190 "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
191 "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
192 "</u:%sResponse>";
194 char body[2048];
195 int bodylen;
196 struct ifdata data;
197 const char * status = "Up"; /* Up, Down (Required),
198 * Initializing, Unavailable (Optional) */
199 const char * wan_access_type = "Cable"; /* DSL, POTS, Cable, Ethernet */
200 char ext_ip_addr[INET_ADDRSTRLEN];
202 if((downstream_bitrate == 0) || (upstream_bitrate == 0))
204 if(getifstats(ext_if_name, &data) >= 0)
206 if(downstream_bitrate == 0) downstream_bitrate = data.baudrate;
207 if(upstream_bitrate == 0) upstream_bitrate = data.baudrate;
210 if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, NULL, NULL) < 0) {
211 status = "Down";
213 bodylen = snprintf(body, sizeof(body), resp,
214 action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
215 wan_access_type,
216 upstream_bitrate, downstream_bitrate,
217 status, action);
218 BuildSendAndCloseSoapResp(h, body, bodylen);
221 static void
222 GetStatusInfo(struct upnphttp * h, const char * action, const char * ns)
224 static const char resp[] =
225 "<u:%sResponse "
226 "xmlns:u=\"%s\">"
227 "<NewConnectionStatus>%s</NewConnectionStatus>"
228 "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
229 "<NewUptime>%ld</NewUptime>"
230 "</u:%sResponse>";
232 char body[512];
233 int bodylen;
234 time_t uptime;
235 const char * status;
236 /* ConnectionStatus possible values :
237 * Unconfigured, Connecting, Connected, PendingDisconnect,
238 * Disconnecting, Disconnected */
240 status = get_wan_connection_status_str(ext_if_name);
241 uptime = (time(NULL) - startup_time);
242 bodylen = snprintf(body, sizeof(body), resp,
243 action, ns, /*SERVICE_TYPE_WANIPC,*/
244 status, (long)uptime, action);
245 BuildSendAndCloseSoapResp(h, body, bodylen);
248 static void
249 GetNATRSIPStatus(struct upnphttp * h, const char * action, const char * ns)
251 #if 0
252 static const char resp[] =
253 "<u:GetNATRSIPStatusResponse "
254 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
255 "<NewRSIPAvailable>0</NewRSIPAvailable>"
256 "<NewNATEnabled>1</NewNATEnabled>"
257 "</u:GetNATRSIPStatusResponse>";
258 UNUSED(action);
259 #endif
260 static const char resp[] =
261 "<u:%sResponse "
262 "xmlns:u=\"%s\">"
263 "<NewRSIPAvailable>0</NewRSIPAvailable>"
264 "<NewNATEnabled>1</NewNATEnabled>"
265 "</u:%sResponse>";
266 char body[512];
267 int bodylen;
268 /* 2.2.9. RSIPAvailable
269 * This variable indicates if Realm-specific IP (RSIP) is available
270 * as a feature on the InternetGatewayDevice. RSIP is being defined
271 * in the NAT working group in the IETF to allow host-NATing using
272 * a standard set of message exchanges. It also allows end-to-end
273 * applications that otherwise break if NAT is introduced
274 * (e.g. IPsec-based VPNs).
275 * A gateway that does not support RSIP should set this variable to 0. */
276 bodylen = snprintf(body, sizeof(body), resp,
277 action, ns, /*SERVICE_TYPE_WANIPC,*/
278 action);
279 BuildSendAndCloseSoapResp(h, body, bodylen);
282 static void
283 GetExternalIPAddress(struct upnphttp * h, const char * action, const char * ns)
285 static const char resp[] =
286 "<u:%sResponse "
287 "xmlns:u=\"%s\">"
288 "<NewExternalIPAddress>%s</NewExternalIPAddress>"
289 "</u:%sResponse>";
291 char body[512];
292 int bodylen;
293 char ext_ip_addr[INET_ADDRSTRLEN];
294 /* Does that method need to work with IPv6 ?
295 * There is usually no NAT with IPv6 */
297 #ifndef MULTIPLE_EXTERNAL_IP
298 if(use_ext_ip_addr)
300 strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN);
301 ext_ip_addr[INET_ADDRSTRLEN - 1] = '\0';
303 else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, NULL, NULL) < 0)
305 syslog(LOG_ERR, "Failed to get ip address for interface %s",
306 ext_if_name);
307 strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
309 #else
310 struct lan_addr_s * lan_addr;
311 strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
312 for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
314 if( (h->clientaddr.s_addr & lan_addr->mask.s_addr)
315 == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
317 strncpy(ext_ip_addr, lan_addr->ext_ip_str, INET_ADDRSTRLEN);
318 break;
321 #endif
322 bodylen = snprintf(body, sizeof(body), resp,
323 action, ns, /*SERVICE_TYPE_WANIPC,*/
324 ext_ip_addr, action);
325 BuildSendAndCloseSoapResp(h, body, bodylen);
328 /* AddPortMapping method of WANIPConnection Service
329 * Ignored argument : NewEnabled */
330 static void
331 AddPortMapping(struct upnphttp * h, const char * action, const char * ns)
333 int r;
335 /*static const char resp[] =
336 "<u:AddPortMappingResponse "
337 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";*/
338 static const char resp[] =
339 "<u:%sResponse "
340 "xmlns:u=\"%s\"/>";
342 char body[512];
343 int bodylen;
344 struct NameValueParserData data;
345 char * int_ip, * int_port, * ext_port, * protocol, * desc;
346 char * leaseduration_str;
347 unsigned int leaseduration;
348 char * r_host;
349 unsigned short iport, eport;
351 struct hostent *hp; /* getbyhostname() */
352 char ** ptr; /* getbyhostname() */
353 struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
355 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
356 int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
357 if (!int_ip)
359 ClearNameValueList(&data);
360 SoapError(h, 402, "Invalid Args");
361 return;
364 /* IGD 2 MUST support both wildcard and specific IP address values
365 * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
366 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
367 #ifndef SUPPORT_REMOTEHOST
368 #ifdef UPNP_STRICT
369 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
371 ClearNameValueList(&data);
372 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
373 return;
375 #endif
376 #endif
378 /* if ip not valid assume hostname and convert */
379 if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
381 hp = gethostbyname(int_ip);
382 if(hp && hp->h_addrtype == AF_INET)
384 for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
386 int_ip = inet_ntoa(*((struct in_addr *) *ptr));
387 result_ip = *((struct in_addr *) *ptr);
388 /* TODO : deal with more than one ip per hostname */
389 break;
392 else
394 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
395 ClearNameValueList(&data);
396 SoapError(h, 402, "Invalid Args");
397 return;
401 /* check if NewInternalAddress is the client address */
402 if(GETFLAG(SECUREMODEMASK))
404 if(h->clientaddr.s_addr != result_ip.s_addr)
406 syslog(LOG_INFO, "Client %s tried to redirect port to %s",
407 inet_ntoa(h->clientaddr), int_ip);
408 ClearNameValueList(&data);
409 SoapError(h, 718, "ConflictInMappingEntry");
410 return;
414 int_port = GetValueFromNameValueList(&data, "NewInternalPort");
415 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
416 protocol = GetValueFromNameValueList(&data, "NewProtocol");
417 desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
418 leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
420 if (!int_port || !ext_port || !protocol)
422 ClearNameValueList(&data);
423 SoapError(h, 402, "Invalid Args");
424 return;
427 eport = (unsigned short)atoi(ext_port);
428 iport = (unsigned short)atoi(int_port);
430 leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
431 #ifdef IGD_V2
432 /* PortMappingLeaseDuration can be either a value between 1 and
433 * 604800 seconds or the zero value (for infinite lease time).
434 * Note that an infinite lease time can be only set by out-of-band
435 * mechanisms like WWW-administration, remote management or local
436 * management.
437 * If a control point uses the value 0 to indicate an infinite lease
438 * time mapping, it is REQUIRED that gateway uses the maximum value
439 * instead (e.g. 604800 seconds) */
440 if(leaseduration == 0 || leaseduration > 604800)
441 leaseduration = 604800;
442 #endif
444 syslog(LOG_INFO, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
445 action, eport, int_ip, iport, protocol, desc, leaseduration,
446 r_host ? r_host : "NULL");
448 /* TODO : be compliant with IGD spec for updating existing port mappings.
449 See "WANIPConnection:1 Service Template Version 1.01" 2.2.20.PortMappingDescription :
450 Overwriting Previous / Existing Port Mappings:
451 If the RemoteHost, ExternalPort, PortMappingProtocol and InternalClient are
452 exactly the same as an existing mapping, the existing mapping values for InternalPort,
453 PortMappingDescription, PortMappingEnabled and PortMappingLeaseDuration are
454 overwritten.
456 r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
458 ClearNameValueList(&data);
460 /* possible error codes for AddPortMapping :
461 * 402 - Invalid Args
462 * 501 - Action Failed
463 * 715 - Wildcard not permited in SrcAddr
464 * 716 - Wildcard not permited in ExtPort
465 * 718 - ConflictInMappingEntry
466 * 724 - SamePortValuesRequired (deprecated in IGD v2)
467 * 725 - OnlyPermanentLeasesSupported
468 The NAT implementation only supports permanent lease times on
469 port mappings (deprecated in IGD v2)
470 * 726 - RemoteHostOnlySupportsWildcard
471 RemoteHost must be a wildcard and cannot be a specific IP
472 address or DNS name (deprecated in IGD v2)
473 * 727 - ExternalPortOnlySupportsWildcard
474 ExternalPort must be a wildcard and cannot be a specific port
475 value (deprecated in IGD v2)
476 * 728 - NoPortMapsAvailable
477 There are not enough free prots available to complete the mapping
478 (added in IGD v2)
479 * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
480 switch(r)
482 case 0: /* success */
483 bodylen = snprintf(body, sizeof(body), resp,
484 action, ns/*SERVICE_TYPE_WANIPC*/);
485 BuildSendAndCloseSoapResp(h, body, bodylen);
486 break;
487 case -2: /* already redirected */
488 case -3: /* not permitted */
489 SoapError(h, 718, "ConflictInMappingEntry");
490 break;
491 default:
492 SoapError(h, 501, "ActionFailed");
496 /* AddAnyPortMapping was added in WANIPConnection v2 */
497 static void
498 AddAnyPortMapping(struct upnphttp * h, const char * action, const char * ns)
500 int r;
501 static const char resp[] =
502 "<u:%sResponse "
503 "xmlns:u=\"%s\">"
504 "<NewReservedPort>%hu</NewReservedPort>"
505 "</u:%sResponse>";
507 char body[512];
508 int bodylen;
510 struct NameValueParserData data;
511 const char * int_ip, * int_port, * ext_port, * protocol, * desc;
512 const char * r_host;
513 unsigned short iport, eport;
514 const char * leaseduration_str;
515 unsigned int leaseduration;
517 struct hostent *hp; /* getbyhostname() */
518 char ** ptr; /* getbyhostname() */
519 struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
521 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
522 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
523 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
524 protocol = GetValueFromNameValueList(&data, "NewProtocol");
525 int_port = GetValueFromNameValueList(&data, "NewInternalPort");
526 int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
527 /* NewEnabled */
528 desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
529 leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
531 leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
532 if(leaseduration == 0)
533 leaseduration = 604800;
535 if (!int_ip || !ext_port || !int_port)
537 ClearNameValueList(&data);
538 SoapError(h, 402, "Invalid Args");
539 return;
542 eport = (unsigned short)atoi(ext_port);
543 iport = (unsigned short)atoi(int_port);
544 #ifndef SUPPORT_REMOTEHOST
545 #ifdef UPNP_STRICT
546 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
548 ClearNameValueList(&data);
549 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
550 return;
552 #endif
553 #endif
555 /* if ip not valid assume hostname and convert */
556 if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
558 hp = gethostbyname(int_ip);
559 if(hp && hp->h_addrtype == AF_INET)
561 for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
563 int_ip = inet_ntoa(*((struct in_addr *) *ptr));
564 result_ip = *((struct in_addr *) *ptr);
565 /* TODO : deal with more than one ip per hostname */
566 break;
569 else
571 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
572 ClearNameValueList(&data);
573 SoapError(h, 402, "Invalid Args");
574 return;
578 /* check if NewInternalAddress is the client address */
579 if(GETFLAG(SECUREMODEMASK))
581 if(h->clientaddr.s_addr != result_ip.s_addr)
583 syslog(LOG_INFO, "Client %s tried to redirect port to %s",
584 inet_ntoa(h->clientaddr), int_ip);
585 ClearNameValueList(&data);
586 SoapError(h, 606, "Action not authorized");
587 return;
591 /* TODO : accept a different external port
592 * have some smart strategy to choose the port */
593 for(;;) {
594 r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
595 if(r==-2 && eport < 65535) {
596 eport++;
597 } else {
598 break;
602 ClearNameValueList(&data);
604 switch(r)
606 case 0: /* success */
607 bodylen = snprintf(body, sizeof(body), resp,
608 action, ns, /*SERVICE_TYPE_WANIPC,*/
609 eport, action);
610 BuildSendAndCloseSoapResp(h, body, bodylen);
611 break;
612 case -2: /* already redirected */
613 SoapError(h, 718, "ConflictInMappingEntry");
614 break;
615 case -3: /* not permitted */
616 SoapError(h, 606, "Action not authorized");
617 break;
618 default:
619 SoapError(h, 501, "ActionFailed");
623 static void
624 GetSpecificPortMappingEntry(struct upnphttp * h, const char * action, const char * ns)
626 int r;
628 static const char resp[] =
629 "<u:%sResponse "
630 "xmlns:u=\"%s\">"
631 "<NewInternalPort>%u</NewInternalPort>"
632 "<NewInternalClient>%s</NewInternalClient>"
633 "<NewEnabled>1</NewEnabled>"
634 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
635 "<NewLeaseDuration>%u</NewLeaseDuration>"
636 "</u:%sResponse>";
638 char body[1024];
639 int bodylen;
640 struct NameValueParserData data;
641 const char * r_host, * ext_port, * protocol;
642 unsigned short eport, iport;
643 char int_ip[32];
644 char desc[64];
645 unsigned int leaseduration = 0;
647 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
648 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
649 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
650 protocol = GetValueFromNameValueList(&data, "NewProtocol");
652 #ifdef UPNP_STRICT
653 if(!ext_port || !protocol || !r_host)
654 #else
655 if(!ext_port || !protocol)
656 #endif
658 ClearNameValueList(&data);
659 SoapError(h, 402, "Invalid Args");
660 return;
662 #ifndef SUPPORT_REMOTEHOST
663 #ifdef UPNP_STRICT
664 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
666 ClearNameValueList(&data);
667 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
668 return;
670 #endif
671 #endif
673 eport = (unsigned short)atoi(ext_port);
675 /* TODO : add r_host as an input parameter ...
676 * We prevent several Port Mapping with same external port
677 * but different remoteHost to be set up, so that is not
678 * a priority. */
679 r = upnp_get_redirection_infos(eport, protocol, &iport,
680 int_ip, sizeof(int_ip),
681 desc, sizeof(desc),
682 NULL, 0,
683 &leaseduration);
685 if(r < 0)
687 SoapError(h, 714, "NoSuchEntryInArray");
689 else
691 syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
692 action,
693 r_host ? r_host : "NULL", ext_port, protocol, int_ip,
694 (unsigned int)iport, desc);
695 bodylen = snprintf(body, sizeof(body), resp,
696 action, ns/*SERVICE_TYPE_WANIPC*/,
697 (unsigned int)iport, int_ip, desc, leaseduration,
698 action);
699 BuildSendAndCloseSoapResp(h, body, bodylen);
702 ClearNameValueList(&data);
705 static void
706 DeletePortMapping(struct upnphttp * h, const char * action, const char * ns)
708 int r;
710 /*static const char resp[] =
711 "<u:DeletePortMappingResponse "
712 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
713 "</u:DeletePortMappingResponse>";*/
714 static const char resp[] =
715 "<u:%sResponse "
716 "xmlns:u=\"%s\">"
717 "</u:%sResponse>";
719 char body[512];
720 int bodylen;
721 struct NameValueParserData data;
722 const char * ext_port, * protocol;
723 unsigned short eport;
724 #ifdef UPNP_STRICT
725 const char * r_host;
726 #endif /* UPNP_STRICT */
728 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
729 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
730 protocol = GetValueFromNameValueList(&data, "NewProtocol");
731 #ifdef UPNP_STRICT
732 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
733 #endif /* UPNP_STRICT */
735 #ifdef UPNP_STRICT
736 if(!ext_port || !protocol || !r_host)
737 #else
738 if(!ext_port || !protocol)
739 #endif /* UPNP_STRICT */
741 ClearNameValueList(&data);
742 SoapError(h, 402, "Invalid Args");
743 return;
745 #ifndef SUPPORT_REMOTEHOST
746 #ifdef UPNP_STRICT
747 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
749 ClearNameValueList(&data);
750 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
751 return;
753 #endif /* UPNP_STRICT */
754 #endif /* SUPPORT_REMOTEHOST */
756 eport = (unsigned short)atoi(ext_port);
758 syslog(LOG_INFO, "%s: external port: %hu, protocol: %s",
759 action, eport, protocol);
761 /* if in secure mode, check the IP
762 * Removing a redirection is not a security threat,
763 * just an annoyance for the user using it. So this is not
764 * a priority. */
765 if(GETFLAG(SECUREMODEMASK))
767 char int_ip[32];
768 struct in_addr int_ip_addr;
769 unsigned short iport;
770 unsigned int leaseduration = 0;
771 r = upnp_get_redirection_infos(eport, protocol, &iport,
772 int_ip, sizeof(int_ip),
773 NULL, 0, NULL, 0,
774 &leaseduration);
775 if(r >= 0)
777 if(inet_pton(AF_INET, int_ip, &int_ip_addr) > 0)
779 if(h->clientaddr.s_addr != int_ip_addr.s_addr)
781 SoapError(h, 606, "Action not authorized");
782 /*SoapError(h, 714, "NoSuchEntryInArray");*/
783 ClearNameValueList(&data);
784 return;
790 r = upnp_delete_redirection(eport, protocol);
792 if(r < 0)
794 SoapError(h, 714, "NoSuchEntryInArray");
796 else
798 bodylen = snprintf(body, sizeof(body), resp,
799 action, ns, action);
800 BuildSendAndCloseSoapResp(h, body, bodylen);
803 ClearNameValueList(&data);
806 /* DeletePortMappingRange was added in IGD spec v2 */
807 static void
808 DeletePortMappingRange(struct upnphttp * h, const char * action, const char * ns)
810 int r = -1;
811 /*static const char resp[] =
812 "<u:DeletePortMappingRangeResponse "
813 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
814 "</u:DeletePortMappingRangeResponse>";*/
815 static const char resp[] =
816 "<u:%sResponse "
817 "xmlns:u=\"%s\">"
818 "</u:%sResponse>";
819 char body[512];
820 int bodylen;
821 struct NameValueParserData data;
822 const char * protocol;
823 const char * startport_s, * endport_s;
824 unsigned short startport, endport;
825 /*int manage;*/
826 unsigned short * port_list;
827 unsigned int i, number = 0;
829 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
830 startport_s = GetValueFromNameValueList(&data, "NewStartPort");
831 endport_s = GetValueFromNameValueList(&data, "NewEndPort");
832 protocol = GetValueFromNameValueList(&data, "NewProtocol");
833 /*manage = atoi(GetValueFromNameValueList(&data, "NewManage"));*/
834 if(startport_s == NULL || endport_s == NULL || protocol == NULL) {
835 SoapError(h, 402, "Invalid Args");
836 ClearNameValueList(&data);
837 return;
839 startport = (unsigned short)atoi(startport_s);
840 endport = (unsigned short)atoi(endport_s);
842 /* possible errors :
843 606 - Action not authorized
844 730 - PortMappingNotFound
845 733 - InconsistentParameter
847 if(startport > endport)
849 SoapError(h, 733, "InconsistentParameter");
850 ClearNameValueList(&data);
851 return;
854 syslog(LOG_INFO, "%s: deleting external ports: %hu-%hu, protocol: %s",
855 action, startport, endport, protocol);
857 port_list = upnp_get_portmappings_in_range(startport, endport,
858 protocol, &number);
859 if(number == 0)
861 SoapError(h, 730, "PortMappingNotFound");
862 ClearNameValueList(&data);
863 free(port_list);
864 return;
867 for(i = 0; i < number; i++)
869 r = upnp_delete_redirection(port_list[i], protocol);
870 syslog(LOG_INFO, "%s: deleting external port: %hu, protocol: %s: %s",
871 action, port_list[i], protocol, r < 0 ? "failed" : "ok");
873 free(port_list);
874 bodylen = snprintf(body, sizeof(body), resp,
875 action, ns, action);
876 BuildSendAndCloseSoapResp(h, body, bodylen);
878 ClearNameValueList(&data);
881 static void
882 GetGenericPortMappingEntry(struct upnphttp * h, const char * action, const char * ns)
884 int r;
886 static const char resp[] =
887 "<u:%sResponse "
888 "xmlns:u=\"%s\">"
889 "<NewRemoteHost>%s</NewRemoteHost>"
890 "<NewExternalPort>%u</NewExternalPort>"
891 "<NewProtocol>%s</NewProtocol>"
892 "<NewInternalPort>%u</NewInternalPort>"
893 "<NewInternalClient>%s</NewInternalClient>"
894 "<NewEnabled>1</NewEnabled>"
895 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
896 "<NewLeaseDuration>%u</NewLeaseDuration>"
897 "</u:%sResponse>";
899 long int index = 0;
900 unsigned short eport, iport;
901 const char * m_index;
902 char * endptr;
903 char protocol[4], iaddr[32];
904 char desc[64];
905 char rhost[40];
906 unsigned int leaseduration = 0;
907 struct NameValueParserData data;
909 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
910 m_index = GetValueFromNameValueList(&data, "NewPortMappingIndex");
912 if(!m_index)
914 ClearNameValueList(&data);
915 SoapError(h, 402, "Invalid Args");
916 return;
918 errno = 0; /* To distinguish success/failure after call */
919 index = strtol(m_index, &endptr, 10);
920 if((errno == ERANGE && (index == LONG_MAX || index == LONG_MIN))
921 || (errno != 0 && index == 0) || (m_index == endptr))
923 /* should condition (*endptr != '\0') be also an error ? */
924 if(m_index == endptr)
925 syslog(LOG_WARNING, "%s: no digits were found in <%s>",
926 "GetGenericPortMappingEntry", "NewPortMappingIndex");
927 else
928 syslog(LOG_WARNING, "%s: strtol('%s'): %m",
929 "GetGenericPortMappingEntry", m_index);
930 ClearNameValueList(&data);
931 SoapError(h, 402, "Invalid Args");
932 return;
935 syslog(LOG_INFO, "%s: index=%d", action, (int)index);
937 rhost[0] = '\0';
938 r = upnp_get_redirection_infos_by_index((int)index, &eport, protocol, &iport,
939 iaddr, sizeof(iaddr),
940 desc, sizeof(desc),
941 rhost, sizeof(rhost),
942 &leaseduration);
944 if(r < 0)
946 SoapError(h, 713, "SpecifiedArrayIndexInvalid");
948 else
950 int bodylen;
951 char body[2048];
952 bodylen = snprintf(body, sizeof(body), resp,
953 action, ns, /*SERVICE_TYPE_WANIPC,*/ rhost,
954 (unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc,
955 leaseduration, action);
956 BuildSendAndCloseSoapResp(h, body, bodylen);
959 ClearNameValueList(&data);
962 /* GetListOfPortMappings was added in the IGD v2 specification */
963 static void
964 GetListOfPortMappings(struct upnphttp * h, const char * action, const char * ns)
966 static const char resp_start[] =
967 "<u:%sResponse "
968 "xmlns:u=\"%s\">"
969 "<NewPortListing><![CDATA[";
970 static const char resp_end[] =
971 "]]></NewPortListing>"
972 "</u:%sResponse>";
974 static const char list_start[] =
975 "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
976 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
977 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
978 " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
979 static const char list_end[] =
980 "</p:PortMappingList>";
982 static const char entry[] =
983 "<p:PortMappingEntry>"
984 "<p:NewRemoteHost>%s</p:NewRemoteHost>"
985 "<p:NewExternalPort>%hu</p:NewExternalPort>"
986 "<p:NewProtocol>%s</p:NewProtocol>"
987 "<p:NewInternalPort>%hu</p:NewInternalPort>"
988 "<p:NewInternalClient>%s</p:NewInternalClient>"
989 "<p:NewEnabled>1</p:NewEnabled>"
990 "<p:NewDescription>%s</p:NewDescription>"
991 "<p:NewLeaseTime>%u</p:NewLeaseTime>"
992 "</p:PortMappingEntry>";
994 char * body;
995 size_t bodyalloc;
996 int bodylen;
998 int r = -1;
999 unsigned short iport;
1000 char int_ip[32];
1001 char desc[64];
1002 char rhost[64];
1003 unsigned int leaseduration = 0;
1005 struct NameValueParserData data;
1006 const char * startport_s, * endport_s;
1007 unsigned short startport, endport;
1008 const char * protocol;
1009 /*int manage;*/
1010 const char * number_s;
1011 int number;
1012 unsigned short * port_list;
1013 unsigned int i, list_size = 0;
1015 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1016 startport_s = GetValueFromNameValueList(&data, "NewStartPort");
1017 endport_s = GetValueFromNameValueList(&data, "NewEndPort");
1018 protocol = GetValueFromNameValueList(&data, "NewProtocol");
1019 /*manage_s = GetValueFromNameValueList(&data, "NewManage");*/
1020 number_s = GetValueFromNameValueList(&data, "NewNumberOfPorts");
1021 if(startport_s == NULL || endport_s == NULL || protocol == NULL ||
1022 number_s == NULL) {
1023 SoapError(h, 402, "Invalid Args");
1024 ClearNameValueList(&data);
1025 return;
1028 startport = (unsigned short)atoi(startport_s);
1029 endport = (unsigned short)atoi(endport_s);
1030 /*manage = atoi(manage_s);*/
1031 number = atoi(number_s);
1032 if(number == 0) number = 1000; /* return up to 1000 mappings by default */
1034 if(startport > endport)
1036 SoapError(h, 733, "InconsistentParameter");
1037 ClearNameValueList(&data);
1038 return;
1041 build the PortMappingList xml document :
1043 <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
1044 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1045 xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
1046 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
1047 <p:PortMappingEntry>
1048 <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
1049 <p:NewExternalPort>2345</p:NewExternalPort>
1050 <p:NewProtocol>TCP</p:NewProtocol>
1051 <p:NewInternalPort>2345</p:NewInternalPort>
1052 <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
1053 <p:NewEnabled>1</p:NewEnabled>
1054 <p:NewDescription>dooom</p:NewDescription>
1055 <p:NewLeaseTime>345</p:NewLeaseTime>
1056 </p:PortMappingEntry>
1057 </p:PortMappingList>
1059 bodyalloc = 4096;
1060 body = malloc(bodyalloc);
1061 if(!body)
1063 ClearNameValueList(&data);
1064 SoapError(h, 501, "ActionFailed");
1065 return;
1067 bodylen = snprintf(body, bodyalloc, resp_start,
1068 action, ns/*SERVICE_TYPE_WANIPC*/);
1069 if(bodylen < 0)
1071 SoapError(h, 501, "ActionFailed");
1072 free(body);
1073 return;
1075 memcpy(body+bodylen, list_start, sizeof(list_start));
1076 bodylen += (sizeof(list_start) - 1);
1078 port_list = upnp_get_portmappings_in_range(startport, endport,
1079 protocol, &list_size);
1080 /* loop through port mappings */
1081 for(i = 0; number > 0 && i < list_size; i++)
1083 /* have a margin of 1024 bytes to store the new entry */
1084 if((unsigned int)bodylen + 1024 > bodyalloc)
1086 char * body_sav = body;
1087 bodyalloc += 4096;
1088 body = realloc(body, bodyalloc);
1089 if(!body)
1091 syslog(LOG_CRIT, "realloc(%p, %u) FAILED", body_sav, (unsigned)bodyalloc);
1092 ClearNameValueList(&data);
1093 SoapError(h, 501, "ActionFailed");
1094 free(body_sav);
1095 free(port_list);
1096 return;
1099 rhost[0] = '\0';
1100 r = upnp_get_redirection_infos(port_list[i], protocol, &iport,
1101 int_ip, sizeof(int_ip),
1102 desc, sizeof(desc),
1103 rhost, sizeof(rhost),
1104 &leaseduration);
1105 if(r == 0)
1107 bodylen += snprintf(body+bodylen, bodyalloc-bodylen, entry,
1108 rhost, port_list[i], protocol,
1109 iport, int_ip, desc, leaseduration);
1110 number--;
1113 free(port_list);
1114 port_list = NULL;
1116 if((bodylen + sizeof(list_end) + 1024) > bodyalloc)
1118 char * body_sav = body;
1119 bodyalloc += (sizeof(list_end) + 1024);
1120 body = realloc(body, bodyalloc);
1121 if(!body)
1123 syslog(LOG_CRIT, "realloc(%p, %u) FAILED", body_sav, (unsigned)bodyalloc);
1124 ClearNameValueList(&data);
1125 SoapError(h, 501, "ActionFailed");
1126 free(body_sav);
1127 return;
1130 memcpy(body+bodylen, list_end, sizeof(list_end));
1131 bodylen += (sizeof(list_end) - 1);
1132 bodylen += snprintf(body+bodylen, bodyalloc-bodylen, resp_end,
1133 action);
1134 BuildSendAndCloseSoapResp(h, body, bodylen);
1135 free(body);
1137 ClearNameValueList(&data);
1140 #ifdef ENABLE_L3F_SERVICE
1141 static void
1142 SetDefaultConnectionService(struct upnphttp * h, const char * action, const char * ns)
1144 /*static const char resp[] =
1145 "<u:SetDefaultConnectionServiceResponse "
1146 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1147 "</u:SetDefaultConnectionServiceResponse>";*/
1148 static const char resp[] =
1149 "<u:%sResponse "
1150 "xmlns:u=\"%s\">"
1151 "</u:%sResponse>";
1152 char body[512];
1153 int bodylen;
1154 struct NameValueParserData data;
1155 char * p;
1156 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1157 p = GetValueFromNameValueList(&data, "NewDefaultConnectionService");
1158 if(p) {
1159 /* 720 InvalidDeviceUUID
1160 * 721 InvalidServiceID
1161 * 723 InvalidConnServiceSelection */
1162 #ifdef UPNP_STRICT
1163 char * service;
1164 service = strchr(p, ',');
1165 if(0 != memcmp(uuidvalue_wcd, p, sizeof("uuid:00000000-0000-0000-0000-000000000000") - 1)) {
1166 SoapError(h, 720, "InvalidDeviceUUID");
1167 } else if(service == NULL || 0 != strcmp(service+1, SERVICE_ID_WANIPC)) {
1168 SoapError(h, 721, "InvalidServiceID");
1169 } else
1170 #endif
1172 syslog(LOG_INFO, "%s(%s) : Ignored", action, p);
1173 bodylen = snprintf(body, sizeof(body), resp,
1174 action, ns, action);
1175 BuildSendAndCloseSoapResp(h, body, bodylen);
1177 } else {
1178 /* missing argument */
1179 SoapError(h, 402, "Invalid Args");
1181 ClearNameValueList(&data);
1184 static void
1185 GetDefaultConnectionService(struct upnphttp * h, const char * action, const char * ns)
1187 static const char resp[] =
1188 "<u:%sResponse "
1189 "xmlns:u=\"%s\">"
1190 #ifdef IGD_V2
1191 "<NewDefaultConnectionService>%s:WANConnectionDevice:2,"
1192 #else
1193 "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
1194 #endif
1195 SERVICE_ID_WANIPC "</NewDefaultConnectionService>"
1196 "</u:%sResponse>";
1197 /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
1198 * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
1199 * urn:upnp-org:serviceId:WANPPPConn1 */
1200 char body[1024];
1201 int bodylen;
1203 /* namespace : urn:schemas-upnp-org:service:Layer3Forwarding:1 */
1204 bodylen = snprintf(body, sizeof(body), resp,
1205 action, ns, uuidvalue_wcd, action);
1206 BuildSendAndCloseSoapResp(h, body, bodylen);
1208 #endif
1210 /* Added for compliance with WANIPConnection v2 */
1211 static void
1212 SetConnectionType(struct upnphttp * h, const char * action, const char * ns)
1214 #ifdef UPNP_STRICT
1215 const char * connection_type;
1216 #endif /* UPNP_STRICT */
1217 struct NameValueParserData data;
1218 UNUSED(action);
1219 UNUSED(ns);
1221 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1222 #ifdef UPNP_STRICT
1223 connection_type = GetValueFromNameValueList(&data, "NewConnectionType");
1224 if(!connection_type) {
1225 ClearNameValueList(&data);
1226 SoapError(h, 402, "Invalid Args");
1227 return;
1229 #endif /* UPNP_STRICT */
1230 /* Unconfigured, IP_Routed, IP_Bridged */
1231 ClearNameValueList(&data);
1232 /* always return a ReadOnly error */
1233 SoapError(h, 731, "ReadOnly");
1236 /* Added for compliance with WANIPConnection v2 */
1237 static void
1238 RequestConnection(struct upnphttp * h, const char * action, const char * ns)
1240 UNUSED(action);
1241 UNUSED(ns);
1242 SoapError(h, 606, "Action not authorized");
1245 /* Added for compliance with WANIPConnection v2 */
1246 static void
1247 ForceTermination(struct upnphttp * h, const char * action, const char * ns)
1249 UNUSED(action);
1250 UNUSED(ns);
1251 SoapError(h, 606, "Action not authorized");
1255 If a control point calls QueryStateVariable on a state variable that is not
1256 buffered in memory within (or otherwise available from) the service,
1257 the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1259 QueryStateVariable remains useful as a limited test tool but may not be
1260 part of some future versions of UPnP.
1262 static void
1263 QueryStateVariable(struct upnphttp * h, const char * action, const char * ns)
1265 static const char resp[] =
1266 "<u:%sResponse "
1267 "xmlns:u=\"%s\">"
1268 "<return>%s</return>"
1269 "</u:%sResponse>";
1271 char body[512];
1272 int bodylen;
1273 struct NameValueParserData data;
1274 const char * var_name;
1276 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1277 /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1278 /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1279 var_name = GetValueFromNameValueList(&data, "varName");
1281 /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1283 if(!var_name)
1285 SoapError(h, 402, "Invalid Args");
1287 else if(strcmp(var_name, "ConnectionStatus") == 0)
1289 const char * status;
1291 status = get_wan_connection_status_str(ext_if_name);
1292 bodylen = snprintf(body, sizeof(body), resp,
1293 action, ns,/*"urn:schemas-upnp-org:control-1-0",*/
1294 status, action);
1295 BuildSendAndCloseSoapResp(h, body, bodylen);
1297 #if 0
1298 /* not usefull */
1299 else if(strcmp(var_name, "ConnectionType") == 0)
1301 bodylen = snprintf(body, sizeof(body), resp, "IP_Routed");
1302 BuildSendAndCloseSoapResp(h, body, bodylen);
1304 else if(strcmp(var_name, "LastConnectionError") == 0)
1306 bodylen = snprintf(body, sizeof(body), resp, "ERROR_NONE");
1307 BuildSendAndCloseSoapResp(h, body, bodylen);
1309 #endif
1310 else if(strcmp(var_name, "PortMappingNumberOfEntries") == 0)
1312 char strn[10];
1313 snprintf(strn, sizeof(strn), "%i",
1314 upnp_get_portmapping_number_of_entries());
1315 bodylen = snprintf(body, sizeof(body), resp,
1316 action, ns,/*"urn:schemas-upnp-org:control-1-0",*/
1317 strn, action);
1318 BuildSendAndCloseSoapResp(h, body, bodylen);
1320 else
1322 syslog(LOG_NOTICE, "%s: Unknown: %s", action, var_name?var_name:"");
1323 SoapError(h, 404, "Invalid Var");
1326 ClearNameValueList(&data);
1329 #ifdef ENABLE_6FC_SERVICE
1330 #ifndef ENABLE_IPV6
1331 #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1332 #endif
1333 /* WANIPv6FirewallControl actions */
1334 static void
1335 GetFirewallStatus(struct upnphttp * h, const char * action, const char * ns)
1337 static const char resp[] =
1338 "<u:%sResponse "
1339 "xmlns:u=\"%s\">"
1340 "<FirewallEnabled>%d</FirewallEnabled>"
1341 "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1342 "</u:%sResponse>";
1344 char body[512];
1345 int bodylen;
1347 bodylen = snprintf(body, sizeof(body), resp,
1348 action, ns, /*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",*/
1349 GETFLAG(IPV6FCFWDISABLEDMASK) ? 0 : 1,
1350 GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK) ? 0 : 1,
1351 action);
1352 BuildSendAndCloseSoapResp(h, body, bodylen);
1355 static int
1356 CheckStatus(struct upnphttp * h)
1358 if (GETFLAG(IPV6FCFWDISABLEDMASK))
1360 SoapError(h, 702, "FirewallDisabled");
1361 return 0;
1363 else if(GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK))
1365 SoapError(h, 703, "InboundPinholeNotAllowed");
1366 return 0;
1368 else
1369 return 1;
1372 #if 0
1373 static int connecthostport(const char * host, unsigned short port, char * result)
1375 int s, n;
1376 char hostname[INET6_ADDRSTRLEN];
1377 char port_str[8], ifname[8], tmp[4];
1378 struct addrinfo *ai, *p;
1379 struct addrinfo hints;
1381 memset(&hints, 0, sizeof(hints));
1382 /* hints.ai_flags = AI_ADDRCONFIG; */
1383 #ifdef AI_NUMERICSERV
1384 hints.ai_flags = AI_NUMERICSERV;
1385 #endif
1386 hints.ai_socktype = SOCK_STREAM;
1387 hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
1388 /* hints.ai_protocol = IPPROTO_TCP; */
1389 snprintf(port_str, sizeof(port_str), "%hu", port);
1390 strcpy(hostname, host);
1391 if(!strncmp(host, "fe80", 4))
1393 printf("Using an linklocal address\n");
1394 strcpy(ifname, "%");
1395 snprintf(tmp, sizeof(tmp), "%d", linklocal_index);
1396 strcat(ifname, tmp);
1397 strcat(hostname, ifname);
1398 printf("host: %s\n", hostname);
1400 n = getaddrinfo(hostname, port_str, &hints, &ai);
1401 if(n != 0)
1403 fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
1404 return -1;
1406 s = -1;
1407 for(p = ai; p; p = p->ai_next)
1409 #ifdef DEBUG
1410 char tmp_host[256];
1411 char tmp_service[256];
1412 printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1413 p->ai_family, p->ai_socktype, p->ai_protocol, p->ai_addrlen);
1414 getnameinfo(p->ai_addr, p->ai_addrlen, tmp_host, sizeof(tmp_host),
1415 tmp_service, sizeof(tmp_service),
1416 NI_NUMERICHOST | NI_NUMERICSERV);
1417 printf(" host=%s service=%s\n", tmp_host, tmp_service);
1418 #endif
1419 inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr), result, INET6_ADDRSTRLEN);
1420 return 0;
1422 freeaddrinfo(ai);
1424 #endif
1426 /* Check the security policy right */
1427 static int
1428 PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short int_port)
1430 int n;
1431 char senderAddr[INET6_ADDRSTRLEN]="";
1432 struct addrinfo hints, *ai, *p;
1433 struct in6_addr result_ip;
1435 /* Pinhole InternalClient address must correspond to the action sender */
1436 syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)");
1438 hints.ai_socktype = SOCK_STREAM;
1439 hints.ai_family = AF_UNSPEC;
1441 /* if ip not valid assume hostname and convert */
1442 if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0)
1444 n = getaddrinfo(int_ip, NULL, &hints, &ai);
1445 if(!n && ai->ai_family == AF_INET6)
1447 for(p = ai; p; p = p->ai_next)
1449 inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr));
1450 result_ip = *((struct in6_addr *) p);
1451 /* TODO : deal with more than one ip per hostname */
1452 break;
1455 else
1457 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
1458 SoapError(h, 402, "Invalid Args");
1459 return -1;
1461 freeaddrinfo(p);
1464 if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN) == NULL)
1466 syslog(LOG_ERR, "inet_ntop: %m");
1468 #ifdef DEBUG
1469 printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr, int_ip);
1470 #endif
1471 if(strcmp(senderAddr, int_ip) != 0)
1472 if(h->clientaddr_v6.s6_addr != result_ip.s6_addr)
1474 syslog(LOG_INFO, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1475 senderAddr, int_ip);
1476 SoapError(h, 606, "Action not authorized");
1477 return 0;
1480 /* Pinhole InternalPort must be greater than or equal to 1024 */
1481 if (int_port < 1024)
1483 syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1484 senderAddr);
1485 SoapError(h, 606, "Action not authorized");
1486 return 0;
1488 return 1;
1491 static void
1492 AddPinhole(struct upnphttp * h, const char * action, const char * ns)
1494 int r;
1495 static const char resp[] =
1496 "<u:%sResponse "
1497 "xmlns:u=\"%s\">"
1498 "<UniqueID>%d</UniqueID>"
1499 "</u:%sResponse>";
1500 char body[512];
1501 int bodylen;
1502 struct NameValueParserData data;
1503 char * rem_host, * rem_port, * int_ip, * int_port, * protocol, * leaseTime;
1504 int uid = 0;
1505 unsigned short iport, rport;
1506 int ltime;
1507 long proto;
1508 char rem_ip[INET6_ADDRSTRLEN];
1510 if(CheckStatus(h)==0)
1511 return;
1513 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1514 rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1515 rem_port = GetValueFromNameValueList(&data, "RemotePort");
1516 int_ip = GetValueFromNameValueList(&data, "InternalClient");
1517 int_port = GetValueFromNameValueList(&data, "InternalPort");
1518 protocol = GetValueFromNameValueList(&data, "Protocol");
1519 leaseTime = GetValueFromNameValueList(&data, "LeaseTime");
1521 rport = (unsigned short)(rem_port ? atoi(rem_port) : 0);
1522 iport = (unsigned short)(int_port ? atoi(int_port) : 0);
1523 ltime = leaseTime ? atoi(leaseTime) : -1;
1524 errno = 0;
1525 proto = protocol ? strtol(protocol, NULL, 0) : -1;
1526 if(errno != 0 || proto > 65535 || proto < 0)
1528 SoapError(h, 402, "Invalid Args");
1529 goto clear_and_exit;
1531 if(iport == 0)
1533 SoapError(h, 706, "InternalPortWilcardingNotAllowed");
1534 goto clear_and_exit;
1537 /* In particular, [IGD2] RECOMMENDS that unauthenticated and
1538 * unauthorized control points are only allowed to invoke
1539 * this action with:
1540 * - InternalPort value greater than or equal to 1024,
1541 * - InternalClient value equals to the control point's IP address.
1542 * It is REQUIRED that InternalClient cannot be one of IPv6
1543 * addresses used by the gateway. */
1544 if(!int_ip || 0 == strlen(int_ip) || 0 == strcmp(int_ip, "*"))
1546 SoapError(h, 708, "WildCardNotPermittedInSrcIP");
1547 goto clear_and_exit;
1549 /* I guess it is useless to convert int_ip to literal ipv6 address */
1550 /* rem_host should be converted to literal ipv6 : */
1551 if(rem_host && (rem_host[0] != '\0'))
1553 struct addrinfo *ai, *p;
1554 struct addrinfo hints;
1555 int err;
1556 memset(&hints, 0, sizeof(struct addrinfo));
1557 hints.ai_family = AF_INET6;
1558 /*hints.ai_flags = */
1559 /* hints.ai_protocol = proto; */
1560 err = getaddrinfo(rem_host, rem_port, &hints, &ai);
1561 if(err == 0)
1563 /* take the 1st IPv6 address */
1564 for(p = ai; p; p = p->ai_next)
1566 if(p->ai_family == AF_INET6)
1568 inet_ntop(AF_INET6,
1569 &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr),
1570 rem_ip, sizeof(rem_ip));
1571 syslog(LOG_INFO, "resolved '%s' to '%s'", rem_host, rem_ip);
1572 rem_host = rem_ip;
1573 break;
1576 freeaddrinfo(ai);
1578 else
1580 syslog(LOG_WARNING, "AddPinhole : getaddrinfo(%s) : %s",
1581 rem_host, gai_strerror(err));
1582 #if 0
1583 SoapError(h, 402, "Invalid Args");
1584 goto clear_and_exit;
1585 #endif
1589 if(proto == 65535)
1591 SoapError(h, 707, "ProtocolWilcardingNotAllowed");
1592 goto clear_and_exit;
1594 if(proto != IPPROTO_UDP && proto != IPPROTO_TCP
1595 #ifdef IPPROTO_UDPITE
1596 && atoi(protocol) != IPPROTO_UDPLITE
1597 #endif
1600 SoapError(h, 705, "ProtocolNotSupported");
1601 goto clear_and_exit;
1603 if(ltime < 1 || ltime > 86400)
1605 syslog(LOG_WARNING, "%s: LeaseTime=%d not supported, (ip=%s)",
1606 action, ltime, int_ip);
1607 SoapError(h, 402, "Invalid Args");
1608 goto clear_and_exit;
1611 if(PinholeVerification(h, int_ip, iport) <= 0)
1612 goto clear_and_exit;
1614 syslog(LOG_INFO, "%s: (inbound) from [%s]:%hu to [%s]:%hu with proto %ld during %d sec",
1615 action, rem_host?rem_host:"any",
1616 rport, int_ip, iport,
1617 proto, ltime);
1619 /* In cases where the RemoteHost, RemotePort, InternalPort,
1620 * InternalClient and Protocol are the same than an existing pinhole,
1621 * but LeaseTime is different, the device MUST extend the existing
1622 * pinhole's lease time and return the UniqueID of the existing pinhole. */
1623 r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, proto, "IGD2 pinhole", ltime, &uid);
1625 switch(r)
1627 case 1: /* success */
1628 bodylen = snprintf(body, sizeof(body),
1629 resp, action,
1630 ns/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1631 uid, action);
1632 BuildSendAndCloseSoapResp(h, body, bodylen);
1633 break;
1634 case -1: /* not permitted */
1635 SoapError(h, 701, "PinholeSpaceExhausted");
1636 break;
1637 default:
1638 SoapError(h, 501, "ActionFailed");
1639 break;
1641 /* 606 Action not authorized
1642 * 701 PinholeSpaceExhausted
1643 * 702 FirewallDisabled
1644 * 703 InboundPinholeNotAllowed
1645 * 705 ProtocolNotSupported
1646 * 706 InternalPortWildcardingNotAllowed
1647 * 707 ProtocolWildcardingNotAllowed
1648 * 708 WildCardNotPermittedInSrcIP */
1649 clear_and_exit:
1650 ClearNameValueList(&data);
1653 static void
1654 UpdatePinhole(struct upnphttp * h, const char * action, const char * ns)
1656 #if 0
1657 static const char resp[] =
1658 "<u:UpdatePinholeResponse "
1659 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1660 "</u:UpdatePinholeResponse>";
1661 #endif
1662 static const char resp[] =
1663 "<u:%sResponse "
1664 "xmlns:u=\"%s\">"
1665 "</u:%sResponse>";
1666 char body[512];
1667 int bodylen;
1668 struct NameValueParserData data;
1669 const char * uid_str, * leaseTime;
1670 char iaddr[INET6_ADDRSTRLEN];
1671 unsigned short iport;
1672 int ltime;
1673 int uid;
1674 int n;
1676 if(CheckStatus(h)==0)
1677 return;
1679 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1680 uid_str = GetValueFromNameValueList(&data, "UniqueID");
1681 leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime");
1682 uid = uid_str ? atoi(uid_str) : -1;
1683 ltime = leaseTime ? atoi(leaseTime) : -1;
1684 ClearNameValueList(&data);
1686 if(uid < 0 || uid > 65535 || ltime <= 0 || ltime > 86400)
1688 SoapError(h, 402, "Invalid Args");
1689 return;
1692 /* Check that client is not updating an pinhole
1693 * it doesn't have access to, because of its public access */
1694 n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
1695 iaddr, sizeof(iaddr), &iport,
1696 NULL, /* proto */
1697 NULL, 0, /* desc, desclen */
1698 NULL, NULL);
1699 if (n >= 0)
1701 if(PinholeVerification(h, iaddr, iport) <= 0)
1702 return;
1704 else if(n == -2)
1706 SoapError(h, 704, "NoSuchEntry");
1707 return;
1709 else
1711 SoapError(h, 501, "ActionFailed");
1712 return;
1715 syslog(LOG_INFO, "%s: (inbound) updating lease duration to %d for pinhole with ID: %d",
1716 action, ltime, uid);
1718 n = upnp_update_inboundpinhole(uid, ltime);
1719 if(n == -1)
1720 SoapError(h, 704, "NoSuchEntry");
1721 else if(n < 0)
1722 SoapError(h, 501, "ActionFailed");
1723 else {
1724 bodylen = snprintf(body, sizeof(body), resp,
1725 action, ns, action);
1726 BuildSendAndCloseSoapResp(h, body, bodylen);
1730 static void
1731 GetOutboundPinholeTimeout(struct upnphttp * h, const char * action, const char * ns)
1733 int r;
1735 static const char resp[] =
1736 "<u:%sResponse "
1737 "xmlns:u=\"%s\">"
1738 "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1739 "</u:%sResponse>";
1741 char body[512];
1742 int bodylen;
1743 struct NameValueParserData data;
1744 char * int_ip, * int_port, * rem_host, * rem_port, * protocol;
1745 int opt=0;
1746 /*int proto=0;*/
1747 unsigned short iport, rport;
1749 if (GETFLAG(IPV6FCFWDISABLEDMASK))
1751 SoapError(h, 702, "FirewallDisabled");
1752 return;
1755 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1756 int_ip = GetValueFromNameValueList(&data, "InternalClient");
1757 int_port = GetValueFromNameValueList(&data, "InternalPort");
1758 rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1759 rem_port = GetValueFromNameValueList(&data, "RemotePort");
1760 protocol = GetValueFromNameValueList(&data, "Protocol");
1762 rport = (unsigned short)atoi(rem_port);
1763 iport = (unsigned short)atoi(int_port);
1764 /*proto = atoi(protocol);*/
1766 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);
1768 /* TODO */
1769 r = -1;/*upnp_check_outbound_pinhole(proto, &opt);*/
1771 switch(r)
1773 case 1: /* success */
1774 bodylen = snprintf(body, sizeof(body), resp,
1775 action, ns/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1776 opt, action);
1777 BuildSendAndCloseSoapResp(h, body, bodylen);
1778 break;
1779 case -5: /* Protocol not supported */
1780 SoapError(h, 705, "ProtocolNotSupported");
1781 break;
1782 default:
1783 SoapError(h, 501, "ActionFailed");
1785 ClearNameValueList(&data);
1788 static void
1789 DeletePinhole(struct upnphttp * h, const char * action, const char * ns)
1791 int n;
1792 #if 0
1793 static const char resp[] =
1794 "<u:DeletePinholeResponse "
1795 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1796 "</u:DeletePinholeResponse>";
1797 #endif
1798 static const char resp[] =
1799 "<u:%sResponse "
1800 "xmlns:u=\"%s\">"
1801 "</u:%sResponse>";
1802 char body[512];
1803 int bodylen;
1805 struct NameValueParserData data;
1806 const char * uid_str;
1807 char iaddr[INET6_ADDRSTRLEN];
1808 int proto;
1809 unsigned short iport;
1810 unsigned int leasetime;
1811 int uid;
1813 if(CheckStatus(h)==0)
1814 return;
1816 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1817 uid_str = GetValueFromNameValueList(&data, "UniqueID");
1818 uid = uid_str ? atoi(uid_str) : -1;
1819 ClearNameValueList(&data);
1821 if(uid < 0 || uid > 65535)
1823 SoapError(h, 402, "Invalid Args");
1824 return;
1827 /* Check that client is not deleting an pinhole
1828 * it doesn't have access to, because of its public access */
1829 n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
1830 iaddr, sizeof(iaddr), &iport,
1831 &proto,
1832 NULL, 0, /* desc, desclen */
1833 &leasetime, NULL);
1834 if (n >= 0)
1836 if(PinholeVerification(h, iaddr, iport) <= 0)
1837 return;
1839 else if(n == -2)
1841 SoapError(h, 704, "NoSuchEntry");
1842 return;
1844 else
1846 SoapError(h, 501, "ActionFailed");
1847 return;
1850 n = upnp_delete_inboundpinhole(uid);
1851 if(n < 0)
1853 syslog(LOG_INFO, "%s: (inbound) failed to remove pinhole with ID: %d",
1854 action, uid);
1855 SoapError(h, 501, "ActionFailed");
1856 return;
1858 syslog(LOG_INFO, "%s: (inbound) pinhole with ID %d successfully removed",
1859 action, uid);
1860 bodylen = snprintf(body, sizeof(body), resp,
1861 action, ns, action);
1862 BuildSendAndCloseSoapResp(h, body, bodylen);
1865 static void
1866 CheckPinholeWorking(struct upnphttp * h, const char * action, const char * ns)
1868 static const char resp[] =
1869 "<u:%sResponse "
1870 "xmlns:u=\"%s\">"
1871 "<IsWorking>%d</IsWorking>"
1872 "</u:%sResponse>";
1873 char body[512];
1874 int bodylen;
1875 int r;
1876 struct NameValueParserData data;
1877 const char * uid_str;
1878 int uid;
1879 char iaddr[INET6_ADDRSTRLEN];
1880 unsigned short iport;
1881 unsigned int packets;
1883 if(CheckStatus(h)==0)
1884 return;
1886 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1887 uid_str = GetValueFromNameValueList(&data, "UniqueID");
1888 uid = uid_str ? atoi(uid_str) : -1;
1889 ClearNameValueList(&data);
1891 if(uid < 0 || uid > 65535)
1893 SoapError(h, 402, "Invalid Args");
1894 return;
1897 /* Check that client is not checking a pinhole
1898 * it doesn't have access to, because of its public access */
1899 r = upnp_get_pinhole_info(uid,
1900 NULL, 0, NULL,
1901 iaddr, sizeof(iaddr), &iport,
1902 NULL, /* proto */
1903 NULL, 0, /* desc, desclen */
1904 NULL, &packets);
1905 if (r >= 0)
1907 if(PinholeVerification(h, iaddr, iport) <= 0)
1908 return ;
1909 if(packets == 0)
1911 SoapError(h, 709, "NoPacketSent");
1912 return;
1914 bodylen = snprintf(body, sizeof(body), resp,
1915 action, ns/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1916 1, action);
1917 BuildSendAndCloseSoapResp(h, body, bodylen);
1919 else if(r == -2)
1920 SoapError(h, 704, "NoSuchEntry");
1921 else
1922 SoapError(h, 501, "ActionFailed");
1925 static void
1926 GetPinholePackets(struct upnphttp * h, const char * action, const char * ns)
1928 static const char resp[] =
1929 "<u:%sResponse "
1930 "xmlns:u=\"%s\">"
1931 "<PinholePackets>%u</PinholePackets>"
1932 "</u:%sResponse>";
1933 char body[512];
1934 int bodylen;
1935 struct NameValueParserData data;
1936 const char * uid_str;
1937 int n;
1938 char iaddr[INET6_ADDRSTRLEN];
1939 unsigned short iport;
1940 unsigned int packets = 0;
1941 int uid;
1942 int proto;
1943 unsigned int leasetime;
1945 if(CheckStatus(h)==0)
1946 return;
1948 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1949 uid_str = GetValueFromNameValueList(&data, "UniqueID");
1950 uid = uid_str ? atoi(uid_str) : -1;
1951 ClearNameValueList(&data);
1953 if(uid < 0 || uid > 65535)
1955 SoapError(h, 402, "Invalid Args");
1956 return;
1959 /* Check that client is not getting infos of a pinhole
1960 * it doesn't have access to, because of its public access */
1961 n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
1962 iaddr, sizeof(iaddr), &iport,
1963 &proto,
1964 NULL, 0, /* desc, desclen */
1965 &leasetime, &packets);
1966 if (n >= 0)
1968 if(PinholeVerification(h, iaddr, iport)<=0)
1969 return ;
1971 #if 0
1972 else if(r == -4 || r == -1)
1974 SoapError(h, 704, "NoSuchEntry");
1976 #endif
1978 bodylen = snprintf(body, sizeof(body), resp,
1979 action, ns/*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"*/,
1980 packets, action);
1981 BuildSendAndCloseSoapResp(h, body, bodylen);
1983 #endif
1985 #ifdef ENABLE_DP_SERVICE
1986 static void
1987 SendSetupMessage(struct upnphttp * h, const char * action, const char * ns)
1989 static const char resp[] =
1990 "<u:%sResponse "
1991 "xmlns:u=\"%s\">"
1992 "<OutMessage>%s</OutMessage>"
1993 "</u:%sResponse>";
1994 char body[1024];
1995 int bodylen;
1996 struct NameValueParserData data;
1997 const char * ProtocolType; /* string */
1998 const char * InMessage; /* base64 */
1999 const char * OutMessage = ""; /* base64 */
2001 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
2002 ProtocolType = GetValueFromNameValueList(&data, "ProtocolType"); /* string */
2003 InMessage = GetValueFromNameValueList(&data, "InMessage"); /* base64 */
2005 if(ProtocolType == NULL || InMessage == NULL)
2007 ClearNameValueList(&data);
2008 SoapError(h, 402, "Invalid Args");
2009 return;
2011 /*if(strcmp(ProtocolType, "DeviceProtection:1") != 0)*/
2012 if(strcmp(ProtocolType, "WPS") != 0)
2014 ClearNameValueList(&data);
2015 SoapError(h, 600, "Argument Value Invalid"); /* 703 ? */
2016 return;
2018 /* TODO : put here code for WPS */
2020 bodylen = snprintf(body, sizeof(body), resp,
2021 action, ns/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2022 OutMessage, action);
2023 BuildSendAndCloseSoapResp(h, body, bodylen);
2024 ClearNameValueList(&data);
2027 static void
2028 GetSupportedProtocols(struct upnphttp * h, const char * action, const char * ns)
2030 static const char resp[] =
2031 "<u:%sResponse "
2032 "xmlns:u=\"%s\">"
2033 "<ProtocolList><![CDATA[%s]]></ProtocolList>"
2034 "</u:%sResponse>";
2035 char body[1024];
2036 int bodylen;
2037 const char * ProtocolList =
2038 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
2039 "<SupportedProtocols xmlns=\"urn:schemas-upnp-org:gw:DeviceProtection\""
2040 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
2041 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:DeviceProtection"
2042 " http://www.upnp.org/schemas/gw/DeviceProtection-v1.xsd\">"
2043 "<Introduction><Name>WPS</Name></Introduction>"
2044 "<Login><Name>PKCS5</Name></Login>"
2045 "</SupportedProtocols>";
2047 bodylen = snprintf(body, sizeof(body), resp,
2048 action, ns/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2049 ProtocolList, action);
2050 BuildSendAndCloseSoapResp(h, body, bodylen);
2053 static void
2054 GetAssignedRoles(struct upnphttp * h, const char * action, const char * ns)
2056 static const char resp[] =
2057 "<u:%sResponse "
2058 "xmlns:u=\"%s\">"
2059 "<RoleList>%s</RoleList>"
2060 "</u:%sResponse>";
2061 char body[1024];
2062 int bodylen;
2063 const char * RoleList = "Public"; /* list of roles separated by spaces */
2065 #ifdef ENABLE_HTTPS
2066 if(h->ssl != NULL) {
2067 /* we should get the Roles of the session (based on client certificate) */
2068 X509 * peercert;
2069 peercert = SSL_get_peer_certificate(h->ssl);
2070 if(peercert != NULL) {
2071 RoleList = "Admin Basic";
2072 X509_free(peercert);
2075 #endif
2077 bodylen = snprintf(body, sizeof(body), resp,
2078 action, ns/*"urn:schemas-upnp-org:service:DeviceProtection:1"*/,
2079 RoleList, action);
2080 BuildSendAndCloseSoapResp(h, body, bodylen);
2082 #endif
2084 /* Windows XP as client send the following requests :
2085 * GetConnectionTypeInfo
2086 * GetNATRSIPStatus
2087 * ? GetTotalBytesSent - WANCommonInterfaceConfig
2088 * ? GetTotalBytesReceived - idem
2089 * ? GetTotalPacketsSent - idem
2090 * ? GetTotalPacketsReceived - idem
2091 * GetCommonLinkProperties - idem
2092 * GetStatusInfo - WANIPConnection
2093 * GetExternalIPAddress
2094 * QueryStateVariable / ConnectionStatus!
2096 static const struct
2098 const char * methodName;
2099 void (*methodImpl)(struct upnphttp *, const char *, const char *);
2101 soapMethods[] =
2103 /* WANCommonInterfaceConfig */
2104 { "QueryStateVariable", QueryStateVariable},
2105 { "GetTotalBytesSent", GetTotalBytesSent},
2106 { "GetTotalBytesReceived", GetTotalBytesReceived},
2107 { "GetTotalPacketsSent", GetTotalPacketsSent},
2108 { "GetTotalPacketsReceived", GetTotalPacketsReceived},
2109 { "GetCommonLinkProperties", GetCommonLinkProperties},
2110 { "GetStatusInfo", GetStatusInfo},
2111 /* WANIPConnection */
2112 { "GetConnectionTypeInfo", GetConnectionTypeInfo },
2113 { "GetNATRSIPStatus", GetNATRSIPStatus},
2114 { "GetExternalIPAddress", GetExternalIPAddress},
2115 { "AddPortMapping", AddPortMapping},
2116 { "DeletePortMapping", DeletePortMapping},
2117 { "GetGenericPortMappingEntry", GetGenericPortMappingEntry},
2118 { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry},
2119 /* Required in WANIPConnection:2 */
2120 { "SetConnectionType", SetConnectionType},
2121 { "RequestConnection", RequestConnection},
2122 { "ForceTermination", ForceTermination},
2123 { "AddAnyPortMapping", AddAnyPortMapping},
2124 { "DeletePortMappingRange", DeletePortMappingRange},
2125 { "GetListOfPortMappings", GetListOfPortMappings},
2126 #ifdef ENABLE_L3F_SERVICE
2127 /* Layer3Forwarding */
2128 { "SetDefaultConnectionService", SetDefaultConnectionService},
2129 { "GetDefaultConnectionService", GetDefaultConnectionService},
2130 #endif
2131 #ifdef ENABLE_6FC_SERVICE
2132 /* WANIPv6FirewallControl */
2133 { "GetFirewallStatus", GetFirewallStatus}, /* Required */
2134 { "AddPinhole", AddPinhole}, /* Required */
2135 { "UpdatePinhole", UpdatePinhole}, /* Required */
2136 { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout}, /* Optional */
2137 { "DeletePinhole", DeletePinhole}, /* Required */
2138 { "CheckPinholeWorking", CheckPinholeWorking}, /* Optional */
2139 { "GetPinholePackets", GetPinholePackets}, /* Required */
2140 #endif
2141 #ifdef ENABLE_DP_SERVICE
2142 /* DeviceProtection */
2143 { "SendSetupMessage", SendSetupMessage}, /* Required */
2144 { "GetSupportedProtocols", GetSupportedProtocols}, /* Required */
2145 { "GetAssignedRoles", GetAssignedRoles}, /* Required */
2146 #endif
2147 { 0, 0 }
2150 void
2151 ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
2153 char * p;
2154 char * p2;
2155 int i, len, methodlen;
2156 char namespace[256];
2158 /* SoapAction example :
2159 * urn:schemas-upnp-org:service:WANIPConnection:1#GetStatusInfo */
2160 p = strchr(action, '#');
2161 if(p && (p - action) < n) {
2162 for(i = 0; i < ((int)sizeof(namespace) - 1) && (action + i) < p; i++)
2163 namespace[i] = action[i];
2164 namespace[i] = '\0';
2165 p++;
2166 p2 = strchr(p, '"');
2167 if(p2 && (p2 - action) <= n)
2168 methodlen = p2 - p;
2169 else
2170 methodlen = n - (p - action);
2171 /*syslog(LOG_DEBUG, "SoapMethod: %.*s %d %d %p %p %d",
2172 methodlen, p, methodlen, n, action, p, (int)(p - action));*/
2173 for(i = 0; soapMethods[i].methodName; i++) {
2174 len = strlen(soapMethods[i].methodName);
2175 if((len == methodlen) && memcmp(p, soapMethods[i].methodName, len) == 0) {
2176 #ifdef DEBUG
2177 syslog(LOG_DEBUG, "Remote Call of SoapMethod '%s' %s",
2178 soapMethods[i].methodName, namespace);
2179 #endif /* DEBUG */
2180 soapMethods[i].methodImpl(h, soapMethods[i].methodName, namespace);
2181 return;
2184 syslog(LOG_NOTICE, "SoapMethod: Unknown: %.*s %s", methodlen, p, namespace);
2185 } else {
2186 syslog(LOG_NOTICE, "cannot parse SoapAction");
2189 SoapError(h, 401, "Invalid Action");
2192 /* Standard Errors:
2194 * errorCode errorDescription Description
2195 * -------- ---------------- -----------
2196 * 401 Invalid Action No action by that name at this service.
2197 * 402 Invalid Args Could be any of the following: not enough in args,
2198 * too many in args, no in arg by that name,
2199 * one or more in args are of the wrong data type.
2200 * 403 Out of Sync Out of synchronization.
2201 * 501 Action Failed May be returned in current state of service
2202 * prevents invoking that action.
2203 * 600-699 TBD Common action errors. Defined by UPnP Forum
2204 * Technical Committee.
2205 * 700-799 TBD Action-specific errors for standard actions.
2206 * Defined by UPnP Forum working committee.
2207 * 800-899 TBD Action-specific errors for non-standard actions.
2208 * Defined by UPnP vendor.
2210 void
2211 SoapError(struct upnphttp * h, int errCode, const char * errDesc)
2213 static const char resp[] =
2214 "<s:Envelope "
2215 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
2216 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
2217 "<s:Body>"
2218 "<s:Fault>"
2219 "<faultcode>s:Client</faultcode>"
2220 "<faultstring>UPnPError</faultstring>"
2221 "<detail>"
2222 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
2223 "<errorCode>%d</errorCode>"
2224 "<errorDescription>%s</errorDescription>"
2225 "</UPnPError>"
2226 "</detail>"
2227 "</s:Fault>"
2228 "</s:Body>"
2229 "</s:Envelope>";
2231 char body[2048];
2232 int bodylen;
2234 syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc);
2235 bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc);
2236 BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen);
2237 SendRespAndClose_upnphttp(h);