Add PPTP runtime and GUI
[tomato.git] / release / src / router / miniupnpd / upnpsoap.c
blob40a5e255c33ec7c8a398032a25685d323a5bf5f1
1 /* $Id: upnpsoap.c,v 1.87 2011/07/15 07:48:26 nanard Exp $ */
2 /* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2011 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/socket.h>
12 #include <unistd.h>
13 #include <syslog.h>
14 #include <sys/types.h>
15 #include <arpa/inet.h>
16 #include <netinet/in.h>
17 #include <netdb.h>
19 #include "config.h"
20 #include "upnpglobalvars.h"
21 #include "upnphttp.h"
22 #include "upnpsoap.h"
23 #include "upnpreplyparse.h"
24 #include "upnpredirect.h"
25 #include "getifaddr.h"
26 #include "getifstats.h"
27 #include "getconnstatus.h"
28 #include "upnpurns.h"
30 static void
31 BuildSendAndCloseSoapResp(struct upnphttp * h,
32 const char * body, int bodylen)
34 static const char beforebody[] =
35 "<?xml version=\"1.0\"?>\r\n"
36 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
37 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
38 "<s:Body>";
40 static const char afterbody[] =
41 "</s:Body>"
42 "</s:Envelope>\r\n";
44 BuildHeader_upnphttp(h, 200, "OK", sizeof(beforebody) - 1
45 + sizeof(afterbody) - 1 + bodylen );
47 memcpy(h->res_buf + h->res_buflen, beforebody, sizeof(beforebody) - 1);
48 h->res_buflen += sizeof(beforebody) - 1;
50 memcpy(h->res_buf + h->res_buflen, body, bodylen);
51 h->res_buflen += bodylen;
53 memcpy(h->res_buf + h->res_buflen, afterbody, sizeof(afterbody) - 1);
54 h->res_buflen += sizeof(afterbody) - 1;
56 SendResp_upnphttp(h);
59 static void
60 GetConnectionTypeInfo(struct upnphttp * h, const char * action)
62 static const char resp[] =
63 "<u:GetConnectionTypeInfoResponse "
64 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
65 "<NewConnectionType>IP_Routed</NewConnectionType>"
66 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
67 "</u:GetConnectionTypeInfoResponse>";
68 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
71 static void
72 GetTotalBytesSent(struct upnphttp * h, const char * action)
74 int r;
76 static const char resp[] =
77 "<u:%sResponse "
78 "xmlns:u=\"%s\">"
79 "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
80 "</u:%sResponse>";
82 char body[512];
83 int bodylen;
84 struct ifdata data;
86 r = getifstats(ext_if_name, &data);
87 bodylen = snprintf(body, sizeof(body), resp,
88 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
89 r<0?0:data.obytes, action);
90 BuildSendAndCloseSoapResp(h, body, bodylen);
93 static void
94 GetTotalBytesReceived(struct upnphttp * h, const char * action)
96 int r;
98 static const char resp[] =
99 "<u:%sResponse "
100 "xmlns:u=\"%s\">"
101 "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
102 "</u:%sResponse>";
104 char body[512];
105 int bodylen;
106 struct ifdata data;
108 r = getifstats(ext_if_name, &data);
109 bodylen = snprintf(body, sizeof(body), resp,
110 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
111 r<0?0:data.ibytes, action);
112 BuildSendAndCloseSoapResp(h, body, bodylen);
115 static void
116 GetTotalPacketsSent(struct upnphttp * h, const char * action)
118 int r;
120 static const char resp[] =
121 "<u:%sResponse "
122 "xmlns:u=\"%s\">"
123 "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
124 "</u:%sResponse>";
126 char body[512];
127 int bodylen;
128 struct ifdata data;
130 r = getifstats(ext_if_name, &data);
131 bodylen = snprintf(body, sizeof(body), resp,
132 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
133 r<0?0:data.opackets, action);
134 BuildSendAndCloseSoapResp(h, body, bodylen);
137 static void
138 GetTotalPacketsReceived(struct upnphttp * h, const char * action)
140 int r;
142 static const char resp[] =
143 "<u:%sResponse "
144 "xmlns:u=\"%s\">"
145 "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
146 "</u:%sResponse>";
148 char body[512];
149 int bodylen;
150 struct ifdata data;
152 r = getifstats(ext_if_name, &data);
153 bodylen = snprintf(body, sizeof(body), resp,
154 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
155 r<0?0:data.ipackets, action);
156 BuildSendAndCloseSoapResp(h, body, bodylen);
159 static void
160 GetCommonLinkProperties(struct upnphttp * h, const char * action)
162 /* WANAccessType : set depending on the hardware :
163 * DSL, POTS (plain old Telephone service), Cable, Ethernet */
164 static const char resp[] =
165 "<u:%sResponse "
166 "xmlns:u=\"%s\">"
167 /*"<NewWANAccessType>DSL</NewWANAccessType>"*/
168 "<NewWANAccessType>Cable</NewWANAccessType>"
169 "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
170 "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
171 "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
172 "</u:%sResponse>";
174 char body[2048];
175 int bodylen;
176 struct ifdata data;
177 const char * status = "Up"; /* Up, Down (Required),
178 * Initializing, Unavailable (Optional) */
179 char ext_ip_addr[INET_ADDRSTRLEN];
181 if((downstream_bitrate == 0) || (upstream_bitrate == 0))
183 if(getifstats(ext_if_name, &data) >= 0)
185 if(downstream_bitrate == 0) downstream_bitrate = data.baudrate;
186 if(upstream_bitrate == 0) upstream_bitrate = data.baudrate;
189 if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0) {
190 status = "Down";
192 bodylen = snprintf(body, sizeof(body), resp,
193 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
194 upstream_bitrate, downstream_bitrate,
195 status, action);
196 BuildSendAndCloseSoapResp(h, body, bodylen);
199 static void
200 GetStatusInfo(struct upnphttp * h, const char * action)
202 static const char resp[] =
203 "<u:%sResponse "
204 "xmlns:u=\"%s\">"
205 "<NewConnectionStatus>%s</NewConnectionStatus>"
206 "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
207 "<NewUptime>%ld</NewUptime>"
208 "</u:%sResponse>";
210 char body[512];
211 int bodylen;
212 time_t uptime;
213 const char * status;
214 /* ConnectionStatus possible values :
215 * Unconfigured, Connecting, Connected, PendingDisconnect,
216 * Disconnecting, Disconnected */
218 status = get_wan_connection_status_str(ext_if_name);
219 uptime = (time(NULL) - startup_time);
220 bodylen = snprintf(body, sizeof(body), resp,
221 action, SERVICE_TYPE_WANIPC,
222 status, (long)uptime, action);
223 BuildSendAndCloseSoapResp(h, body, bodylen);
226 static void
227 GetNATRSIPStatus(struct upnphttp * h, const char * action)
229 static const char resp[] =
230 "<u:GetNATRSIPStatusResponse "
231 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
232 "<NewRSIPAvailable>0</NewRSIPAvailable>"
233 "<NewNATEnabled>1</NewNATEnabled>"
234 "</u:GetNATRSIPStatusResponse>";
235 /* 2.2.9. RSIPAvailable
236 * This variable indicates if Realm-specific IP (RSIP) is available
237 * as a feature on the InternetGatewayDevice. RSIP is being defined
238 * in the NAT working group in the IETF to allow host-NATing using
239 * a standard set of message exchanges. It also allows end-to-end
240 * applications that otherwise break if NAT is introduced
241 * (e.g. IPsec-based VPNs).
242 * A gateway that does not support RSIP should set this variable to 0. */
243 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
246 static void
247 GetExternalIPAddress(struct upnphttp * h, const char * action)
249 static const char resp[] =
250 "<u:%sResponse "
251 "xmlns:u=\"%s\">"
252 "<NewExternalIPAddress>%s</NewExternalIPAddress>"
253 "</u:%sResponse>";
255 char body[512];
256 int bodylen;
257 char ext_ip_addr[INET_ADDRSTRLEN];
258 /* Does that method need to work with IPv6 ?
259 * There is usually no NAT with IPv6 */
261 #ifndef MULTIPLE_EXTERNAL_IP
262 if(use_ext_ip_addr)
264 strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN);
266 else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0)
268 syslog(LOG_ERR, "Failed to get ip address for interface %s",
269 ext_if_name);
270 strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
272 #else
273 struct lan_addr_s * lan_addr;
274 strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
275 for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
277 if( (h->clientaddr.s_addr & lan_addr->mask.s_addr)
278 == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
280 strncpy(ext_ip_addr, lan_addr->ext_ip_str, INET_ADDRSTRLEN);
281 break;
284 #endif
285 bodylen = snprintf(body, sizeof(body), resp,
286 action, SERVICE_TYPE_WANIPC,
287 ext_ip_addr, action);
288 BuildSendAndCloseSoapResp(h, body, bodylen);
291 /* AddPortMapping method of WANIPConnection Service
292 * Ignored argument : NewEnabled */
293 static void
294 AddPortMapping(struct upnphttp * h, const char * action)
296 int r;
298 static const char resp[] =
299 "<u:AddPortMappingResponse "
300 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";
302 struct NameValueParserData data;
303 char * int_ip, * int_port, * ext_port, * protocol, * desc;
304 char * leaseduration_str;
305 unsigned int leaseduration;
306 char * r_host;
307 unsigned short iport, eport;
309 struct hostent *hp; /* getbyhostname() */
310 char ** ptr; /* getbyhostname() */
311 struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
313 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
314 int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
315 if (!int_ip)
317 ClearNameValueList(&data);
318 SoapError(h, 402, "Invalid Args");
319 return;
322 /* IGD 2 MUST support both wildcard and specific IP address values
323 * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
324 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
325 #ifndef SUPPORT_REMOTEHOST
326 #ifdef UPNP_STRICT
327 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
329 ClearNameValueList(&data);
330 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
331 return;
333 #endif
334 #endif
336 /* if ip not valid assume hostname and convert */
337 if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
339 hp = gethostbyname(int_ip);
340 if(hp && hp->h_addrtype == AF_INET)
342 for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
344 int_ip = inet_ntoa(*((struct in_addr *) *ptr));
345 result_ip = *((struct in_addr *) *ptr);
346 /* TODO : deal with more than one ip per hostname */
347 break;
350 else
352 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
353 ClearNameValueList(&data);
354 SoapError(h, 402, "Invalid Args");
355 return;
359 /* check if NewInternalAddress is the client address */
360 if(GETFLAG(SECUREMODEMASK))
362 if(h->clientaddr.s_addr != result_ip.s_addr)
364 syslog(LOG_INFO, "Client %s tried to redirect port to %s",
365 inet_ntoa(h->clientaddr), int_ip);
366 ClearNameValueList(&data);
367 SoapError(h, 718, "ConflictInMappingEntry");
368 return;
372 int_port = GetValueFromNameValueList(&data, "NewInternalPort");
373 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
374 protocol = GetValueFromNameValueList(&data, "NewProtocol");
375 desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
376 leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
378 if (!int_port || !ext_port || !protocol)
380 ClearNameValueList(&data);
381 SoapError(h, 402, "Invalid Args");
382 return;
385 eport = (unsigned short)atoi(ext_port);
386 iport = (unsigned short)atoi(int_port);
388 leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
389 #ifdef IGD_V2
390 /* PortMappingLeaseDuration can be either a value between 1 and
391 * 604800 seconds or the zero value (for infinite lease time).
392 * Note that an infinite lease time can be only set by out-of-band
393 * mechanisms like WWW-administration, remote management or local
394 * management.
395 * If a control point uses the value 0 to indicate an infinite lease
396 * time mapping, it is REQUIRED that gateway uses the maximum value
397 * instead (e.g. 604800 seconds) */
398 if(leaseduration == 0 || leaseduration > 604800)
399 leaseduration = 604800;
400 #endif
402 syslog(LOG_INFO, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
403 action, eport, int_ip, iport, protocol, desc, leaseduration, r_host);
405 r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
407 ClearNameValueList(&data);
409 /* possible error codes for AddPortMapping :
410 * 402 - Invalid Args
411 * 501 - Action Failed
412 * 715 - Wildcard not permited in SrcAddr
413 * 716 - Wildcard not permited in ExtPort
414 * 718 - ConflictInMappingEntry
415 * 724 - SamePortValuesRequired (deprecated in IGD v2)
416 * 725 - OnlyPermanentLeasesSupported
417 The NAT implementation only supports permanent lease times on
418 port mappings (deprecated in IGD v2)
419 * 726 - RemoteHostOnlySupportsWildcard
420 RemoteHost must be a wildcard and cannot be a specific IP
421 address or DNS name (deprecated in IGD v2)
422 * 727 - ExternalPortOnlySupportsWildcard
423 ExternalPort must be a wildcard and cannot be a specific port
424 value (deprecated in IGD v2)
425 * 728 - NoPortMapsAvailable
426 There are not enough free prots available to complete the mapping
427 (added in IGD v2)
428 * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
429 switch(r)
431 case 0: /* success */
432 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
433 break;
434 case -2: /* already redirected */
435 case -3: /* not permitted */
436 SoapError(h, 718, "ConflictInMappingEntry");
437 break;
438 default:
439 SoapError(h, 501, "ActionFailed");
443 /* AddAnyPortMapping was added in WANIPConnection v2 */
444 static void
445 AddAnyPortMapping(struct upnphttp * h, const char * action)
447 int r;
448 static const char resp[] =
449 "<u:%sResponse "
450 "xmlns:u=\"%s\">"
451 "<NewReservedPort>%hu</NewReservedPort>"
452 "</u:%sResponse>";
454 char body[512];
455 int bodylen;
457 struct NameValueParserData data;
458 const char * int_ip, * int_port, * ext_port, * protocol, * desc;
459 const char * r_host;
460 unsigned short iport, eport;
461 const char * leaseduration_str;
462 unsigned int leaseduration;
464 struct hostent *hp; /* getbyhostname() */
465 char ** ptr; /* getbyhostname() */
466 struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
468 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
469 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
470 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
471 protocol = GetValueFromNameValueList(&data, "NewProtocol");
472 int_port = GetValueFromNameValueList(&data, "NewInternalPort");
473 int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
474 /* NewEnabled */
475 desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
476 leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
478 leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
479 if(leaseduration == 0)
480 leaseduration = 604800;
482 eport = (unsigned short)atoi(ext_port);
483 iport = (unsigned short)atoi(int_port);
485 if (!int_ip)
487 ClearNameValueList(&data);
488 SoapError(h, 402, "Invalid Args");
489 return;
491 #ifndef SUPPORT_REMOTEHOST
492 #ifdef UPNP_STRICT
493 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
495 ClearNameValueList(&data);
496 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
497 return;
499 #endif
500 #endif
502 /* if ip not valid assume hostname and convert */
503 if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
505 hp = gethostbyname(int_ip);
506 if(hp && hp->h_addrtype == AF_INET)
508 for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
510 int_ip = inet_ntoa(*((struct in_addr *) *ptr));
511 result_ip = *((struct in_addr *) *ptr);
512 /* TODO : deal with more than one ip per hostname */
513 break;
516 else
518 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
519 ClearNameValueList(&data);
520 SoapError(h, 402, "Invalid Args");
521 return;
525 /* check if NewInternalAddress is the client address */
526 if(GETFLAG(SECUREMODEMASK))
528 if(h->clientaddr.s_addr != result_ip.s_addr)
530 syslog(LOG_INFO, "Client %s tried to redirect port to %s",
531 inet_ntoa(h->clientaddr), int_ip);
532 ClearNameValueList(&data);
533 SoapError(h, 606, "Action not authorized");
534 return;
538 /* TODO : accept a different external port
539 * have some smart strategy to choose the port */
540 for(;;) {
541 r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
542 if(r==-2 && eport < 65535) {
543 eport++;
544 } else {
545 break;
549 ClearNameValueList(&data);
551 switch(r)
553 case 0: /* success */
554 bodylen = snprintf(body, sizeof(body), resp,
555 action, SERVICE_TYPE_WANIPC,
556 eport, action);
557 BuildSendAndCloseSoapResp(h, body, bodylen);
558 break;
559 case -2: /* already redirected */
560 SoapError(h, 718, "ConflictInMappingEntry");
561 break;
562 case -3: /* not permitted */
563 SoapError(h, 606, "Action not authorized");
564 break;
565 default:
566 SoapError(h, 501, "ActionFailed");
570 static void
571 GetSpecificPortMappingEntry(struct upnphttp * h, const char * action)
573 int r;
575 static const char resp[] =
576 "<u:%sResponse "
577 "xmlns:u=\"%s\">"
578 "<NewInternalPort>%u</NewInternalPort>"
579 "<NewInternalClient>%s</NewInternalClient>"
580 "<NewEnabled>1</NewEnabled>"
581 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
582 "<NewLeaseDuration>%u</NewLeaseDuration>"
583 "</u:%sResponse>";
585 char body[1024];
586 int bodylen;
587 struct NameValueParserData data;
588 const char * r_host, * ext_port, * protocol;
589 unsigned short eport, iport;
590 char int_ip[32];
591 char desc[64];
592 unsigned int leaseduration = 0;
594 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
595 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
596 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
597 protocol = GetValueFromNameValueList(&data, "NewProtocol");
599 if(!ext_port || !protocol)
601 ClearNameValueList(&data);
602 SoapError(h, 402, "Invalid Args");
603 return;
605 #ifndef SUPPORT_REMOTEHOST
606 #ifdef UPNP_STRICT
607 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
609 ClearNameValueList(&data);
610 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
611 return;
613 #endif
614 #endif
616 eport = (unsigned short)atoi(ext_port);
618 /* TODO : add r_host as an input parameter ...
619 * We prevent several Port Mapping with same external port
620 * but different remoteHost to be set up, so that is not
621 * a priority. */
622 r = upnp_get_redirection_infos(eport, protocol, &iport,
623 int_ip, sizeof(int_ip),
624 desc, sizeof(desc),
625 NULL, 0,
626 &leaseduration);
628 if(r < 0)
630 SoapError(h, 714, "NoSuchEntryInArray");
632 else
634 syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
635 action,
636 r_host, ext_port, protocol, int_ip, (unsigned int)iport, desc);
637 bodylen = snprintf(body, sizeof(body), resp,
638 action, SERVICE_TYPE_WANIPC,
639 (unsigned int)iport, int_ip, desc, leaseduration,
640 action);
641 BuildSendAndCloseSoapResp(h, body, bodylen);
644 ClearNameValueList(&data);
647 static void
648 DeletePortMapping(struct upnphttp * h, const char * action)
650 int r;
652 static const char resp[] =
653 "<u:DeletePortMappingResponse "
654 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
655 "</u:DeletePortMappingResponse>";
657 struct NameValueParserData data;
658 const char * r_host, * ext_port, * protocol;
659 unsigned short eport;
661 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
662 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
663 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
664 protocol = GetValueFromNameValueList(&data, "NewProtocol");
666 if(!ext_port || !protocol)
668 ClearNameValueList(&data);
669 SoapError(h, 402, "Invalid Args");
670 return;
672 #ifndef SUPPORT_REMOTEHOST
673 #ifdef UPNP_STRICT
674 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
676 ClearNameValueList(&data);
677 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
678 return;
680 #endif
681 #endif
683 eport = (unsigned short)atoi(ext_port);
685 /* TODO : if in secure mode, check the IP
686 * Removing a redirection is not a security threat,
687 * just an annoyance for the user using it. So this is not
688 * a priority. */
690 syslog(LOG_INFO, "%s: external port: %hu, protocol: %s",
691 action, eport, protocol);
693 r = upnp_delete_redirection(eport, protocol);
695 if(r < 0)
697 SoapError(h, 714, "NoSuchEntryInArray");
699 else
701 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
704 ClearNameValueList(&data);
707 /* DeletePortMappingRange was added in IGD spec v2 */
708 static void
709 DeletePortMappingRange(struct upnphttp * h, const char * action)
711 int r = -1;
712 static const char resp[] =
713 "<u:DeletePortMappingRangeResponse "
714 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
715 "</u:DeletePortMappingRangeResponse>";
716 struct NameValueParserData data;
717 const char * protocol;
718 unsigned short startport, endport;
719 int manage;
720 unsigned short * port_list;
721 unsigned int i, number = 0;
723 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
724 startport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort"));
725 endport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewEndPort"));
726 protocol = GetValueFromNameValueList(&data, "NewProtocol");
727 manage = atoi(GetValueFromNameValueList(&data, "NewManage"));
729 /* possible errors :
730 606 - Action not authorized
731 730 - PortMappingNotFound
732 733 - InconsistentParameter
734 if(startport > endport)
736 SoapError(h, 733, "InconsistentParameter");
737 ClearNameValueList(&data);
738 return;
741 port_list = upnp_get_portmappings_in_range(startport, endport,
742 protocol, &number);
743 for(i = 0; i < number; i++)
745 r = upnp_delete_redirection(port_list[i], protocol);
746 /* TODO : check return value for errors */
748 free(port_list);
749 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
751 ClearNameValueList(&data);
754 static void
755 GetGenericPortMappingEntry(struct upnphttp * h, const char * action)
757 int r;
759 static const char resp[] =
760 "<u:%sResponse "
761 "xmlns:u=\"%s\">"
762 "<NewRemoteHost>%s</NewRemoteHost>"
763 "<NewExternalPort>%u</NewExternalPort>"
764 "<NewProtocol>%s</NewProtocol>"
765 "<NewInternalPort>%u</NewInternalPort>"
766 "<NewInternalClient>%s</NewInternalClient>"
767 "<NewEnabled>1</NewEnabled>"
768 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
769 "<NewLeaseDuration>%u</NewLeaseDuration>"
770 "</u:%sResponse>";
772 int index = 0;
773 unsigned short eport, iport;
774 const char * m_index;
775 char protocol[4], iaddr[32];
776 char desc[64];
777 char rhost[40];
778 unsigned int leaseduration = 0;
779 struct NameValueParserData data;
781 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
782 m_index = GetValueFromNameValueList(&data, "NewPortMappingIndex");
784 if(!m_index)
786 ClearNameValueList(&data);
787 SoapError(h, 402, "Invalid Args");
788 return;
791 index = (int)atoi(m_index);
793 syslog(LOG_INFO, "%s: index=%d", action, index);
795 rhost[0] = '\0';
796 r = upnp_get_redirection_infos_by_index(index, &eport, protocol, &iport,
797 iaddr, sizeof(iaddr),
798 desc, sizeof(desc),
799 rhost, sizeof(rhost),
800 &leaseduration);
802 if(r < 0)
804 SoapError(h, 713, "SpecifiedArrayIndexInvalid");
806 else
808 int bodylen;
809 char body[2048];
810 bodylen = snprintf(body, sizeof(body), resp,
811 action, SERVICE_TYPE_WANIPC, rhost,
812 (unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc,
813 leaseduration, action);
814 BuildSendAndCloseSoapResp(h, body, bodylen);
817 ClearNameValueList(&data);
820 /* GetListOfPortMappings was added in the IGD v2 specification */
821 static void
822 GetListOfPortMappings(struct upnphttp * h, const char * action)
824 static const char resp_start[] =
825 "<u:%sResponse "
826 "xmlns:u=\"%s\">"
827 "<NewPortListing><![CDATA[";
828 static const char resp_end[] =
829 "]]></NewPortListing>"
830 "</u:%sResponse>";
832 static const char list_start[] =
833 "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
834 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
835 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
836 " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
837 static const char list_end[] =
838 "</p:PortMappingList>";
840 static const char entry[] =
841 "<p:PortMappingEntry>"
842 "<p:NewRemoteHost>%s</p:NewRemoteHost>"
843 "<p:NewExternalPort>%hu</p:NewExternalPort>"
844 "<p:NewProtocol>%s</p:NewProtocol>"
845 "<p:NewInternalPort>%hu</p:NewInternalPort>"
846 "<p:NewInternalClient>%s</p:NewInternalClient>"
847 "<p:NewEnabled>1</p:NewEnabled>"
848 "<p:NewDescription>%s</p:NewDescription>"
849 "<p:NewLeaseTime>%u</p:NewLeaseTime>"
850 "</p:PortMappingEntry>";
852 char * body;
853 size_t bodyalloc;
854 int bodylen;
856 int r = -1;
857 unsigned short iport;
858 char int_ip[32];
859 char desc[64];
860 char rhost[64];
861 unsigned int leaseduration = 0;
863 struct NameValueParserData data;
864 unsigned short startport, endport;
865 const char * protocol;
866 int manage;
867 int number;
868 unsigned short * port_list;
869 unsigned int i, list_size = 0;
871 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
872 startport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort"));
873 endport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewEndPort"));
874 protocol = GetValueFromNameValueList(&data, "NewProtocol");
875 manage = atoi(GetValueFromNameValueList(&data, "NewManage"));
876 number = atoi(GetValueFromNameValueList(&data, "NewNumberOfPorts"));
877 if(number == 0) number = 1000; /* return up to 1000 mappings by default */
879 if(startport > endport)
881 SoapError(h, 733, "InconsistentParameter");
882 ClearNameValueList(&data);
883 return;
886 build the PortMappingList xml document :
888 <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
889 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
890 xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
891 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
892 <p:PortMappingEntry>
893 <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
894 <p:NewExternalPort>2345</p:NewExternalPort>
895 <p:NewProtocol>TCP</p:NewProtocol>
896 <p:NewInternalPort>2345</p:NewInternalPort>
897 <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
898 <p:NewEnabled>1</p:NewEnabled>
899 <p:NewDescription>dooom</p:NewDescription>
900 <p:NewLeaseTime>345</p:NewLeaseTime>
901 </p:PortMappingEntry>
902 </p:PortMappingList>
904 bodyalloc = 4096;
905 body = malloc(bodyalloc);
906 if(!body)
908 ClearNameValueList(&data);
909 SoapError(h, 501, "ActionFailed");
910 return;
912 bodylen = snprintf(body, bodyalloc, resp_start,
913 action, SERVICE_TYPE_WANIPC);
914 memcpy(body+bodylen, list_start, sizeof(list_start));
915 bodylen += (sizeof(list_start) - 1);
917 port_list = upnp_get_portmappings_in_range(startport, endport,
918 protocol, &list_size);
919 /* loop through port mappings */
920 for(i = 0; number > 0 && i < list_size; i++)
922 /* have a margin of 1024 bytes to store the new entry */
923 if(bodylen + 1024 > bodyalloc)
925 bodyalloc += 4096;
926 body = realloc(body, bodyalloc);
927 if(!body)
929 ClearNameValueList(&data);
930 SoapError(h, 501, "ActionFailed");
931 free(port_list);
932 return;
935 rhost[0] = '\0';
936 r = upnp_get_redirection_infos(port_list[i], protocol, &iport,
937 int_ip, sizeof(int_ip),
938 desc, sizeof(desc),
939 rhost, sizeof(rhost),
940 &leaseduration);
941 if(r == 0)
943 bodylen += snprintf(body+bodylen, bodyalloc-bodylen, entry,
944 rhost, port_list[i], protocol,
945 iport, int_ip, desc, leaseduration);
946 number--;
949 free(port_list);
950 port_list = NULL;
952 memcpy(body+bodylen, list_end, sizeof(list_end));
953 bodylen += (sizeof(list_end) - 1);
954 bodylen += snprintf(body+bodylen, bodyalloc-bodylen, resp_end,
955 action);
956 BuildSendAndCloseSoapResp(h, body, bodylen);
957 free(body);
959 ClearNameValueList(&data);
962 #ifdef ENABLE_L3F_SERVICE
963 static void
964 SetDefaultConnectionService(struct upnphttp * h, const char * action)
966 static const char resp[] =
967 "<u:SetDefaultConnectionServiceResponse "
968 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
969 "</u:SetDefaultConnectionServiceResponse>";
970 struct NameValueParserData data;
971 char * p;
972 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
973 p = GetValueFromNameValueList(&data, "NewDefaultConnectionService");
974 if(p) {
975 syslog(LOG_INFO, "%s(%s) : Ignored", action, p);
977 ClearNameValueList(&data);
978 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
981 static void
982 GetDefaultConnectionService(struct upnphttp * h, const char * action)
984 static const char resp[] =
985 "<u:%sResponse "
986 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
987 "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
988 SERVICE_ID_WANIPC "</NewDefaultConnectionService>"
989 "</u:%sResponse>";
990 /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
991 * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
992 * urn:upnp-org:serviceId:WANPPPConn1 */
993 char body[1024];
994 int bodylen;
996 bodylen = snprintf(body, sizeof(body), resp,
997 action, uuidvalue, action);
998 BuildSendAndCloseSoapResp(h, body, bodylen);
1000 #endif
1002 /* Added for compliance with WANIPConnection v2 */
1003 static void
1004 SetConnectionType(struct upnphttp * h, const char * action)
1006 const char * connection_type;
1007 struct NameValueParserData data;
1009 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1010 connection_type = GetValueFromNameValueList(&data, "NewConnectionType");
1011 /* Unconfigured, IP_Routed, IP_Bridged */
1012 ClearNameValueList(&data);
1013 /* always return a ReadOnly error */
1014 SoapError(h, 731, "ReadOnly");
1017 /* Added for compliance with WANIPConnection v2 */
1018 static void
1019 RequestConnection(struct upnphttp * h, const char * action)
1021 SoapError(h, 606, "Action not authorized");
1024 /* Added for compliance with WANIPConnection v2 */
1025 static void
1026 ForceTermination(struct upnphttp * h, const char * action)
1028 SoapError(h, 606, "Action not authorized");
1032 If a control point calls QueryStateVariable on a state variable that is not
1033 buffered in memory within (or otherwise available from) the service,
1034 the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1036 QueryStateVariable remains useful as a limited test tool but may not be
1037 part of some future versions of UPnP.
1039 static void
1040 QueryStateVariable(struct upnphttp * h, const char * action)
1042 static const char resp[] =
1043 "<u:%sResponse "
1044 "xmlns:u=\"%s\">"
1045 "<return>%s</return>"
1046 "</u:%sResponse>";
1048 char body[512];
1049 int bodylen;
1050 struct NameValueParserData data;
1051 const char * var_name;
1053 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1054 /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1055 /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1056 var_name = GetValueFromNameValueList(&data, "varName");
1058 /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1060 if(!var_name)
1062 SoapError(h, 402, "Invalid Args");
1064 else if(strcmp(var_name, "ConnectionStatus") == 0)
1066 const char * status;
1068 status = get_wan_connection_status_str(ext_if_name);
1069 bodylen = snprintf(body, sizeof(body), resp,
1070 action, "urn:schemas-upnp-org:control-1-0",
1071 status, action);
1072 BuildSendAndCloseSoapResp(h, body, bodylen);
1074 #if 0
1075 /* not usefull */
1076 else if(strcmp(var_name, "ConnectionType") == 0)
1078 bodylen = snprintf(body, sizeof(body), resp, "IP_Routed");
1079 BuildSendAndCloseSoapResp(h, body, bodylen);
1081 else if(strcmp(var_name, "LastConnectionError") == 0)
1083 bodylen = snprintf(body, sizeof(body), resp, "ERROR_NONE");
1084 BuildSendAndCloseSoapResp(h, body, bodylen);
1086 #endif
1087 else if(strcmp(var_name, "PortMappingNumberOfEntries") == 0)
1089 char strn[10];
1090 snprintf(strn, sizeof(strn), "%i",
1091 upnp_get_portmapping_number_of_entries());
1092 bodylen = snprintf(body, sizeof(body), resp,
1093 action, "urn:schemas-upnp-org:control-1-0",
1094 strn, action);
1095 BuildSendAndCloseSoapResp(h, body, bodylen);
1097 else
1099 syslog(LOG_NOTICE, "%s: Unknown: %s", action, var_name?var_name:"");
1100 SoapError(h, 404, "Invalid Var");
1103 ClearNameValueList(&data);
1106 #ifdef ENABLE_6FC_SERVICE
1107 #ifndef ENABLE_IPV6
1108 #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1109 #endif
1110 /* WANIPv6FirewallControl actions */
1111 static void
1112 GetFirewallStatus(struct upnphttp * h, const char * action)
1114 static const char resp[] =
1115 "<u:%sResponse "
1116 "xmlns:u=\"%s\">"
1117 "<FirewallEnabled>%d</FirewallEnabled>"
1118 "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1119 "</u:%sResponse>";
1121 char body[512];
1122 int bodylen;
1124 bodylen = snprintf(body, sizeof(body), resp,
1125 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1126 ipv6fc_firewall_enabled, ipv6fc_inbound_pinhole_allowed, action);
1127 BuildSendAndCloseSoapResp(h, body, bodylen);
1130 static int
1131 CheckStatus(struct upnphttp * h)
1133 if (!ipv6fc_firewall_enabled)
1135 SoapError(h, 702, "FirewallDisabed");
1136 return 0;
1138 else if(!ipv6fc_inbound_pinhole_allowed)
1140 SoapError(h, 703, "InboundPinholeNotAllowed");
1141 return 0;
1143 else
1144 return 1;
1147 static int
1148 DataVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port, const char * protocol, char * leaseTime)
1150 //int n;
1151 // ** Internal IP can't be wildcarded
1152 if (!int_ip)
1154 SoapError(h, 708, "WildCardNotPermittedInSrcIP");
1155 return 0;
1158 if (!strchr(int_ip, ':'))
1160 SoapError(h, 402, "Invalid Args");
1161 return 0;
1164 // ** Internal port can't be wilcarded.
1165 // printf("\tint_port: *%d*\n", *int_port);
1166 if (*int_port == 0)
1168 SoapError(h, 706, "InternalPortWilcardingNotAllowed");
1169 return 0;
1172 // ** Protocol can't be wilcarded and can't be an unknown port (here deal with only UDP, TCP, UDPLITE)
1173 // printf("\tprotocol: *%s*\n", protocol);
1174 if (atoi(protocol) == 65535)
1176 SoapError(h, 707, "ProtocolWilcardingNotAllowed");
1177 return 0;
1179 else if (atoi(protocol) != IPPROTO_UDP
1180 && atoi(protocol) != IPPROTO_TCP
1181 #ifdef IPPROTO_UDPITE
1182 && atoi(protocol) != IPPROTO_UDPLITE
1183 #endif
1186 SoapError(h, 705, "ProtocolNotSupported");
1187 return 0;
1190 // ** Lease Time can't be wilcarded nor >86400.
1191 // printf("\tlease time: %s\n", leaseTime);
1192 if(!leaseTime || !atoi(leaseTime) || atoi(leaseTime)>86400)
1194 /* lease duration is never infinite, nor wilcarded. In this case, use default value */
1195 syslog(LOG_WARNING, "LeaseTime=%s not supported, (ip=%s)", leaseTime, int_ip);
1196 SoapError(h, 402, "Invalid Args");
1197 return 0;
1200 return 1;
1203 #if 0
1204 static int connecthostport(const char * host, unsigned short port, char * result)
1206 int s, n;
1207 char hostname[INET6_ADDRSTRLEN];
1208 char port_str[8], ifname[8], tmp[4];
1209 struct addrinfo *ai, *p;
1210 struct addrinfo hints;
1212 memset(&hints, 0, sizeof(hints));
1213 /* hints.ai_flags = AI_ADDRCONFIG; */
1214 #ifdef AI_NUMERICSERV
1215 hints.ai_flags = AI_NUMERICSERV;
1216 #endif
1217 hints.ai_socktype = SOCK_STREAM;
1218 hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
1219 /* hints.ai_protocol = IPPROTO_TCP; */
1220 snprintf(port_str, sizeof(port_str), "%hu", port);
1221 strcpy(hostname, host);
1222 if(!strncmp(host, "fe80", 4))
1224 printf("Using an linklocal address\n");
1225 strcpy(ifname, "%");
1226 snprintf(tmp, sizeof(tmp), "%d", linklocal_index);
1227 strcat(ifname, tmp);
1228 strcat(hostname, ifname);
1229 printf("host: %s\n", hostname);
1231 n = getaddrinfo(hostname, port_str, &hints, &ai);
1232 if(n != 0)
1234 fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
1235 return -1;
1237 s = -1;
1238 for(p = ai; p; p = p->ai_next)
1240 #ifdef DEBUG
1241 char tmp_host[256];
1242 char tmp_service[256];
1243 printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1244 p->ai_family, p->ai_socktype, p->ai_protocol, p->ai_addrlen);
1245 getnameinfo(p->ai_addr, p->ai_addrlen, tmp_host, sizeof(tmp_host),
1246 tmp_service, sizeof(tmp_service),
1247 NI_NUMERICHOST | NI_NUMERICSERV);
1248 printf(" host=%s service=%s\n", tmp_host, tmp_service);
1249 #endif
1250 inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr), result, INET6_ADDRSTRLEN);
1251 return 0;
1253 freeaddrinfo(ai);
1255 #endif
1257 /* Check the security policy right */
1258 static int
1259 PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port)
1261 int n;
1262 /* Pinhole InternalClient address must correspond to the action sender */
1263 syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)");
1264 char senderAddr[INET6_ADDRSTRLEN]="";
1265 //char str[INET6_ADDRSTRLEN]="";
1266 //connecthostport(int_ip, *int_port, str);
1267 //printf("int_ip: %s / str: %s\n", int_ip, str);
1269 struct addrinfo hints, *ai, *p;
1270 struct in6_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */ //IPv6 Modification
1272 hints.ai_socktype = SOCK_STREAM;
1273 hints.ai_family = AF_UNSPEC;
1275 /* if ip not valid assume hostname and convert */
1276 if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0) //IPv6 Modification
1279 n = getaddrinfo(int_ip, NULL, &hints, &ai);//hp = gethostbyname(int_ip);
1280 if(!n && ai->ai_family == AF_INET6) //IPv6 Modification
1282 for(p = ai; p; p = p->ai_next)//ptr = hp->h_addr_list; ptr && *ptr; ptr++)
1284 inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); ///IPv6 Modification
1285 result_ip = *((struct in6_addr *) p);
1286 fprintf(stderr, "upnpsoap / AddPinhole: assuming int addr = %s", int_ip);
1287 /* TODO : deal with more than one ip per hostname */
1288 break;
1291 else
1293 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
1294 SoapError(h, 402, "Invalid Args");
1295 return -1;
1297 freeaddrinfo(p);
1300 if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN)<=0)
1302 //printf("Failed to inet_ntop\n");
1303 syslog(LOG_ERR, "inet_ntop: %m");
1305 #ifdef DEBUG
1306 printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr, int_ip);
1307 #endif
1308 if(strcmp(senderAddr, int_ip) != 0)
1309 if(h->clientaddr_v6.s6_addr != result_ip.s6_addr)
1311 syslog(LOG_INFO, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1312 senderAddr, int_ip);
1313 SoapError(h, 606, "Action not authorized");
1314 return 0;
1317 /* Pinhole InternalPort must be greater than or equal to 1024 */
1318 if (*int_port < 1024)
1320 syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1321 senderAddr);
1322 SoapError(h, 606, "Action not authorized");
1323 return 0;
1325 return 1;
1328 static void
1329 AddPinhole(struct upnphttp * h, const char * action)
1331 int r;
1332 static const char resp[] =
1333 "<u:%sResponse "
1334 "xmlns:u=\"%s\">"
1335 "<UniqueID>%d</UniqueID>"
1336 "</u:%sResponse>";
1337 char body[512];
1338 int bodylen;
1339 struct NameValueParserData data;
1340 char * rem_host, * rem_port, * int_ip, * int_port, * protocol, * leaseTime;
1341 int uid = 0;
1342 unsigned short iport, rport;
1344 if(CheckStatus(h)==0)
1345 return;
1347 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1348 rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1349 rem_port = GetValueFromNameValueList(&data, "RemotePort");
1350 int_ip = GetValueFromNameValueList(&data, "InternalClient");
1351 int_port = GetValueFromNameValueList(&data, "InternalPort");
1352 protocol = GetValueFromNameValueList(&data, "Protocol");
1353 leaseTime = GetValueFromNameValueList(&data, "LeaseTime");
1355 rport = (unsigned short)atoi(rem_port);
1356 iport = (unsigned short)atoi(int_port);
1358 // ** As there is no security policy, InternalClient must be equal to the CP's IP address.
1359 if(DataVerification(h, int_ip, &iport, protocol, leaseTime) == 0
1360 || PinholeVerification(h, int_ip, &iport) <= 0)
1362 ClearNameValueList(&data);
1363 return ;
1366 // ** RemoteHost can be wilcarded or an IDN.
1367 /*printf("\trem_host: %s\n", rem_host);*/
1368 if (rem_host!=NULL && !strchr(rem_host, ':'))
1370 ClearNameValueList(&data);
1371 SoapError(h, 402, "Invalid Args");
1372 return;
1374 /*printf("\tAddr check passed.\n");*/
1376 syslog(LOG_INFO, "%s: (inbound) from [%s]:%hu to [%s]:%hu with protocol %s during %ssec", action, rem_host?rem_host:"anywhere", rport, int_ip, iport, protocol, leaseTime);
1378 r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, protocol, leaseTime, &uid);
1380 switch(r)
1382 case 1: /* success */
1383 bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", uid, action);
1384 BuildSendAndCloseSoapResp(h, body, bodylen);
1385 break;
1386 case -1: /* not permitted */
1387 SoapError(h, 701, "PinholeSpaceExhausted");
1388 break;
1389 default:
1390 SoapError(h, 501, "ActionFailed");
1391 break;
1393 ClearNameValueList(&data);
1396 static void
1397 UpdatePinhole(struct upnphttp * h, const char * action)
1399 int r, n;
1400 static const char resp[] =
1401 "<u:UpdatePinholeResponse "
1402 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1403 "</u:UpdatePinholeResponse>";
1404 struct NameValueParserData data;
1405 const char * uid, * leaseTime;
1406 char iaddr[40], proto[6], lt[12];
1407 unsigned short iport;
1409 if(CheckStatus(h)==0)
1410 return;
1412 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1413 uid = GetValueFromNameValueList(&data, "UniqueID");
1414 leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime");
1416 if(!uid || !leaseTime || !atoi(leaseTime) || atoi(leaseTime) > 86400)
1418 ClearNameValueList(&data);
1419 SoapError(h, 402, "Invalid Args");
1420 return;
1423 // Check that client is not deleting an pinhole he doesn't have access to, because of its public access
1424 n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
1425 if (n > 0)
1427 if(PinholeVerification(h, iaddr, &iport)==0)
1429 ClearNameValueList(&data);
1430 return ;
1434 syslog(LOG_INFO, "%s: (inbound) updating lease duration to %s for pinhole with ID: %s", action, leaseTime, uid);
1436 r = upnp_update_inboundpinhole(uid, leaseTime);
1438 if(r < 0)
1440 if(r == -4 || r == -1)
1441 SoapError(h, 704, "NoSuchEntry");
1442 else
1443 SoapError(h, 501, "ActionFailed");
1445 else
1447 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
1449 ClearNameValueList(&data);
1452 static void
1453 GetOutboundPinholeTimeout(struct upnphttp * h, const char * action)
1455 if (!ipv6fc_firewall_enabled)
1457 SoapError(h, 702, "FirewallDisabed");
1458 return;
1460 int r;
1462 static const char resp[] =
1463 "<u:%sResponse "
1464 "xmlns:u=\"%s\">"
1465 "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1466 "</u:%sResponse>";
1468 char body[512];
1469 int bodylen;
1470 struct NameValueParserData data;
1471 char * int_ip, * int_port, * rem_host, * rem_port, * protocol;
1472 int opt=0, proto=0;
1473 unsigned short iport, rport;
1475 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1476 int_ip = GetValueFromNameValueList(&data, "InternalClient");
1477 int_port = GetValueFromNameValueList(&data, "InternalPort");
1478 rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1479 rem_port = GetValueFromNameValueList(&data, "RemotePort");
1480 protocol = GetValueFromNameValueList(&data, "Protocol");
1482 rport = (unsigned short)atoi(rem_port);
1483 iport = (unsigned short)atoi(int_port);
1484 proto = atoi(protocol);
1486 syslog(LOG_INFO, "%s: retrieving timeout for outbound pinhole from [%s]:%hu to [%s]:%hu protocol %s", action, int_ip, iport,rem_host, rport, protocol);
1488 r = upnp_check_outbound_pinhole(proto, &opt);
1490 switch(r)
1492 case 1: /* success */
1493 bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", opt, action);
1494 BuildSendAndCloseSoapResp(h, body, bodylen);
1495 break;
1496 case -5: /* Protocol not supported */
1497 SoapError(h, 705, "ProtocolNotSupported");
1498 break;
1499 default:
1500 SoapError(h, 501, "ActionFailed");
1502 ClearNameValueList(&data);
1505 static void
1506 DeletePinhole(struct upnphttp * h, const char * action)
1508 if(CheckStatus(h)==0)
1509 return;
1510 int r, n;
1512 static const char resp[] =
1513 "<u:DeletePinholeResponse "
1514 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1515 "</u:DeletePinholeResponse>";
1517 struct NameValueParserData data;
1518 const char * uid;
1519 char iaddr[40], proto[6], lt[12];
1520 unsigned short iport;
1522 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1523 uid = GetValueFromNameValueList(&data, "UniqueID");
1525 if(!uid)
1527 ClearNameValueList(&data);
1528 SoapError(h, 402, "Invalid Args");
1529 return;
1532 // Check that client is not deleting an pinhole he doesn't have access to, because of its public access
1533 n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
1534 if (n > 0)
1536 if(PinholeVerification(h, iaddr, &iport)==0)
1538 ClearNameValueList(&data);
1539 return ;
1543 syslog(LOG_INFO, "%s: (inbound) delete pinhole with ID: %s", action, uid);
1545 r = upnp_delete_inboundpinhole(uid);
1547 if(r <= 0)
1549 syslog(LOG_INFO, "%s: (inbound) failed to remove pinhole with ID: %s", action, uid);
1550 if(r==-4)
1551 SoapError(h, 704, "NoSuchEntry");
1552 else
1553 SoapError(h, 501, "ActionFailed");
1555 else
1557 syslog(LOG_INFO, "%s: (inbound) pinhole successfully removed", action);
1558 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
1560 ClearNameValueList(&data);
1563 static void
1564 CheckPinholeWorking(struct upnphttp * h, const char * action)
1566 if(CheckStatus(h)==0)
1567 return;
1568 int r, d;
1570 static const char resp[] =
1571 "<u:%sResponse "
1572 "xmlns:u=\"%s\">"
1573 "<IsWorking>%d</IsWorking>"
1574 "</u:%sResponse>";
1576 char body[512];
1577 int bodylen;
1578 struct NameValueParserData data;
1579 const char * uid;
1580 char eaddr[40], iaddr[40], proto[6], lt[12];
1581 unsigned short eport, iport;
1582 int isWorking = 0;
1584 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1585 uid = GetValueFromNameValueList(&data, "UniqueID");
1587 if(!uid)
1589 ClearNameValueList(&data);
1590 SoapError(h, 402, "Invalid Args");
1591 return;
1594 // Check that client is not checking a pinhole he doesn't have access to, because of its public access
1595 r = upnp_get_pinhole_info(eaddr, eport, iaddr, &iport, proto, uid, lt);
1596 if (r > 0)
1598 if(PinholeVerification(h, iaddr, &iport)==0)
1600 ClearNameValueList(&data);
1601 return ;
1603 else
1605 int rulenum_used, rulenum = 0;
1606 d = upnp_check_pinhole_working(uid, eaddr, iaddr, &eport, &iport, proto, &rulenum_used);
1607 if(d < 0)
1609 if(d == -4)
1611 syslog(LOG_INFO, "%s: rule for ID=%s, no trace found for this pinhole", action, uid);
1612 SoapError(h, 709, "NoPacketSent");
1613 ClearNameValueList(&data);
1614 return ;
1616 else
1618 // d==-5 not same table // d==-6 not same chain // d==-7 not found a rule but policy traced
1619 isWorking=0;
1620 syslog(LOG_INFO, "%s: rule for ID=%s is not working, packet going through %s", action, uid, (d==-5)?"the wrong table":((d==-6)?"the wrong chain":"a chain policy"));
1621 bodylen = snprintf(body, sizeof(body), resp,
1622 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1623 isWorking, action);
1624 BuildSendAndCloseSoapResp(h, body, bodylen);
1627 else
1629 /*check_rule_from_file(uid, &rulenum);*/
1630 if(rulenum_used == rulenum)
1632 isWorking=1;
1633 syslog(LOG_INFO, "%s: rule for ID=%s is working properly", action, uid);
1635 else
1637 isWorking=0;
1638 syslog(LOG_INFO, "%s: rule for ID=%s is not working", action, uid);
1640 bodylen = snprintf(body, sizeof(body), resp,
1641 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1642 isWorking, action);
1643 BuildSendAndCloseSoapResp(h, body, bodylen);
1647 else if(r == -4 || r == -1)
1649 SoapError(h, 704, "NoSuchEntry");
1651 else
1653 SoapError(h, 501, "ActionFailed");
1654 ClearNameValueList(&data);
1655 return ;
1657 ClearNameValueList(&data);
1660 static void
1661 GetPinholePackets(struct upnphttp * h, const char * action)
1663 if(CheckStatus(h)==0)
1664 return;
1665 int r, n;
1667 static const char resp[] =
1668 "<u:%sResponse "
1669 "xmlns:u=\"%s\">"
1670 "<PinholePackets>%d</PinholePackets>"
1671 "</u:%sResponse>";
1673 char body[512];
1674 int bodylen;
1675 struct NameValueParserData data;
1676 const char * uid;
1677 char iaddr[40], proto[6], lt[12];
1678 unsigned short iport;
1679 int pinholePackets = 0;
1681 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1682 uid = GetValueFromNameValueList(&data, "UniqueID");
1684 if(!uid)
1686 ClearNameValueList(&data);
1687 SoapError(h, 402, "Invalid Args");
1688 return;
1691 // Check that client is not getting infos of a pinhole he doesn't have access to, because of its public access
1692 r = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
1693 if (r > 0)
1695 if(PinholeVerification(h, iaddr, &iport)==0)
1697 ClearNameValueList(&data);
1698 return ;
1702 n = upnp_get_pinhole_packets(uid, &pinholePackets);
1703 if(n > 0)
1705 bodylen = snprintf(body, sizeof(body), resp,
1706 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1707 pinholePackets, action);
1708 BuildSendAndCloseSoapResp(h, body, bodylen);
1710 else if(r == -4 || r == -1)
1712 SoapError(h, 704, "NoSuchEntry");
1714 else
1716 SoapError(h, 501, "ActionFailed");
1717 ClearNameValueList(&data);
1718 return ;
1720 ClearNameValueList(&data);
1722 #endif
1725 /* Windows XP as client send the following requests :
1726 * GetConnectionTypeInfo
1727 * GetNATRSIPStatus
1728 * ? GetTotalBytesSent - WANCommonInterfaceConfig
1729 * ? GetTotalBytesReceived - idem
1730 * ? GetTotalPacketsSent - idem
1731 * ? GetTotalPacketsReceived - idem
1732 * GetCommonLinkProperties - idem
1733 * GetStatusInfo - WANIPConnection
1734 * GetExternalIPAddress
1735 * QueryStateVariable / ConnectionStatus!
1737 static const struct
1739 const char * methodName;
1740 void (*methodImpl)(struct upnphttp *, const char *);
1742 soapMethods[] =
1744 /* WANCommonInterfaceConfig */
1745 { "QueryStateVariable", QueryStateVariable},
1746 { "GetTotalBytesSent", GetTotalBytesSent},
1747 { "GetTotalBytesReceived", GetTotalBytesReceived},
1748 { "GetTotalPacketsSent", GetTotalPacketsSent},
1749 { "GetTotalPacketsReceived", GetTotalPacketsReceived},
1750 { "GetCommonLinkProperties", GetCommonLinkProperties},
1751 { "GetStatusInfo", GetStatusInfo},
1752 /* WANIPConnection */
1753 { "GetConnectionTypeInfo", GetConnectionTypeInfo },
1754 { "GetNATRSIPStatus", GetNATRSIPStatus},
1755 { "GetExternalIPAddress", GetExternalIPAddress},
1756 { "AddPortMapping", AddPortMapping},
1757 { "DeletePortMapping", DeletePortMapping},
1758 { "GetGenericPortMappingEntry", GetGenericPortMappingEntry},
1759 { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry},
1760 /* Required in WANIPConnection:2 */
1761 { "SetConnectionType", SetConnectionType},
1762 { "RequestConnection", RequestConnection},
1763 { "ForceTermination", ForceTermination},
1764 { "AddAnyPortMapping", AddAnyPortMapping},
1765 { "DeletePortMappingRange", DeletePortMappingRange},
1766 { "GetListOfPortMappings", GetListOfPortMappings},
1767 #ifdef ENABLE_L3F_SERVICE
1768 /* Layer3Forwarding */
1769 { "SetDefaultConnectionService", SetDefaultConnectionService},
1770 { "GetDefaultConnectionService", GetDefaultConnectionService},
1771 #endif
1772 #ifdef ENABLE_6FC_SERVICE
1773 /* WANIPv6FirewallControl */
1774 { "GetFirewallStatus", GetFirewallStatus},
1775 { "AddPinhole", AddPinhole},
1776 { "UpdatePinhole", UpdatePinhole},
1777 { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout},
1778 { "DeletePinhole", DeletePinhole},
1779 { "CheckPinholeWorking", CheckPinholeWorking},
1780 { "GetPinholePackets", GetPinholePackets},
1781 #endif
1782 { 0, 0 }
1785 void
1786 ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
1788 char * p;
1789 char * p2;
1790 int i, len, methodlen;
1792 i = 0;
1793 p = strchr(action, '#');
1795 if(p)
1797 p++;
1798 p2 = strchr(p, '"');
1799 if(p2)
1800 methodlen = p2 - p;
1801 else
1802 methodlen = n - (p - action);
1803 /*syslog(LOG_DEBUG, "SoapMethod: %.*s", methodlen, p);*/
1804 while(soapMethods[i].methodName)
1806 len = strlen(soapMethods[i].methodName);
1807 if(strncmp(p, soapMethods[i].methodName, len) == 0)
1809 soapMethods[i].methodImpl(h, soapMethods[i].methodName);
1810 return;
1812 i++;
1815 syslog(LOG_NOTICE, "SoapMethod: Unknown: %.*s", methodlen, p);
1818 SoapError(h, 401, "Invalid Action");
1821 /* Standard Errors:
1823 * errorCode errorDescription Description
1824 * -------- ---------------- -----------
1825 * 401 Invalid Action No action by that name at this service.
1826 * 402 Invalid Args Could be any of the following: not enough in args,
1827 * too many in args, no in arg by that name,
1828 * one or more in args are of the wrong data type.
1829 * 403 Out of Sync Out of synchronization.
1830 * 501 Action Failed May be returned in current state of service
1831 * prevents invoking that action.
1832 * 600-699 TBD Common action errors. Defined by UPnP Forum
1833 * Technical Committee.
1834 * 700-799 TBD Action-specific errors for standard actions.
1835 * Defined by UPnP Forum working committee.
1836 * 800-899 TBD Action-specific errors for non-standard actions.
1837 * Defined by UPnP vendor.
1839 void
1840 SoapError(struct upnphttp * h, int errCode, const char * errDesc)
1842 static const char resp[] =
1843 "<s:Envelope "
1844 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
1845 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
1846 "<s:Body>"
1847 "<s:Fault>"
1848 "<faultcode>s:Client</faultcode>"
1849 "<faultstring>UPnPError</faultstring>"
1850 "<detail>"
1851 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
1852 "<errorCode>%d</errorCode>"
1853 "<errorDescription>%s</errorDescription>"
1854 "</UPnPError>"
1855 "</detail>"
1856 "</s:Fault>"
1857 "</s:Body>"
1858 "</s:Envelope>";
1860 char body[2048];
1861 int bodylen;
1863 syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc);
1864 bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc);
1865 BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen);
1866 SendResp_upnphttp(h);