Miniupnpd v. 1.5 (20110618)
[tomato.git] / release / src / router / miniupnpd / upnpsoap.c
blob1577542d1272efb731d3e37c84d252f556a7c559
1 /* $Id: upnpsoap.c,v 1.85 2011/06/17 23:24:14 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);
57 CloseSocket_upnphttp(h);
60 static void
61 GetConnectionTypeInfo(struct upnphttp * h, const char * action)
63 static const char resp[] =
64 "<u:GetConnectionTypeInfoResponse "
65 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
66 "<NewConnectionType>IP_Routed</NewConnectionType>"
67 "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
68 "</u:GetConnectionTypeInfoResponse>";
69 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
72 static void
73 GetTotalBytesSent(struct upnphttp * h, const char * action)
75 int r;
77 static const char resp[] =
78 "<u:%sResponse "
79 "xmlns:u=\"%s\">"
80 "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
81 "</u:%sResponse>";
83 char body[512];
84 int bodylen;
85 struct ifdata data;
87 r = getifstats(ext_if_name, &data);
88 bodylen = snprintf(body, sizeof(body), resp,
89 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
90 r<0?0:data.obytes, action);
91 BuildSendAndCloseSoapResp(h, body, bodylen);
94 static void
95 GetTotalBytesReceived(struct upnphttp * h, const char * action)
97 int r;
99 static const char resp[] =
100 "<u:%sResponse "
101 "xmlns:u=\"%s\">"
102 "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
103 "</u:%sResponse>";
105 char body[512];
106 int bodylen;
107 struct ifdata data;
109 r = getifstats(ext_if_name, &data);
110 bodylen = snprintf(body, sizeof(body), resp,
111 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
112 r<0?0:data.ibytes, action);
113 BuildSendAndCloseSoapResp(h, body, bodylen);
116 static void
117 GetTotalPacketsSent(struct upnphttp * h, const char * action)
119 int r;
121 static const char resp[] =
122 "<u:%sResponse "
123 "xmlns:u=\"%s\">"
124 "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
125 "</u:%sResponse>";
127 char body[512];
128 int bodylen;
129 struct ifdata data;
131 r = getifstats(ext_if_name, &data);
132 bodylen = snprintf(body, sizeof(body), resp,
133 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
134 r<0?0:data.opackets, action);
135 BuildSendAndCloseSoapResp(h, body, bodylen);
138 static void
139 GetTotalPacketsReceived(struct upnphttp * h, const char * action)
141 int r;
143 static const char resp[] =
144 "<u:%sResponse "
145 "xmlns:u=\"%s\">"
146 "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
147 "</u:%sResponse>";
149 char body[512];
150 int bodylen;
151 struct ifdata data;
153 r = getifstats(ext_if_name, &data);
154 bodylen = snprintf(body, sizeof(body), resp,
155 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
156 r<0?0:data.ipackets, action);
157 BuildSendAndCloseSoapResp(h, body, bodylen);
160 static void
161 GetCommonLinkProperties(struct upnphttp * h, const char * action)
163 /* WANAccessType : set depending on the hardware :
164 * DSL, POTS (plain old Telephone service), Cable, Ethernet */
165 static const char resp[] =
166 "<u:%sResponse "
167 "xmlns:u=\"%s\">"
168 /*"<NewWANAccessType>DSL</NewWANAccessType>"*/
169 "<NewWANAccessType>Cable</NewWANAccessType>"
170 "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
171 "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
172 "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
173 "</u:%sResponse>";
175 char body[2048];
176 int bodylen;
177 struct ifdata data;
178 const char * status = "Up"; /* Up, Down (Required),
179 * Initializing, Unavailable (Optional) */
180 char ext_ip_addr[INET_ADDRSTRLEN];
182 if((downstream_bitrate == 0) || (upstream_bitrate == 0))
184 if(getifstats(ext_if_name, &data) >= 0)
186 if(downstream_bitrate == 0) downstream_bitrate = data.baudrate;
187 if(upstream_bitrate == 0) upstream_bitrate = data.baudrate;
190 if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0) {
191 status = "Down";
193 bodylen = snprintf(body, sizeof(body), resp,
194 action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
195 upstream_bitrate, downstream_bitrate,
196 status, action);
197 BuildSendAndCloseSoapResp(h, body, bodylen);
200 static void
201 GetStatusInfo(struct upnphttp * h, const char * action)
203 static const char resp[] =
204 "<u:%sResponse "
205 "xmlns:u=\"%s\">"
206 "<NewConnectionStatus>%s</NewConnectionStatus>"
207 "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
208 "<NewUptime>%ld</NewUptime>"
209 "</u:%sResponse>";
211 char body[512];
212 int bodylen;
213 time_t uptime;
214 const char * status;
215 /* ConnectionStatus possible values :
216 * Unconfigured, Connecting, Connected, PendingDisconnect,
217 * Disconnecting, Disconnected */
219 status = get_wan_connection_status_str(ext_if_name);
220 uptime = (time(NULL) - startup_time);
221 bodylen = snprintf(body, sizeof(body), resp,
222 action, SERVICE_TYPE_WANIPC,
223 status, (long)uptime, action);
224 BuildSendAndCloseSoapResp(h, body, bodylen);
227 static void
228 GetNATRSIPStatus(struct upnphttp * h, const char * action)
230 static const char resp[] =
231 "<u:GetNATRSIPStatusResponse "
232 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
233 "<NewRSIPAvailable>0</NewRSIPAvailable>"
234 "<NewNATEnabled>1</NewNATEnabled>"
235 "</u:GetNATRSIPStatusResponse>";
236 /* 2.2.9. RSIPAvailable
237 * This variable indicates if Realm-specific IP (RSIP) is available
238 * as a feature on the InternetGatewayDevice. RSIP is being defined
239 * in the NAT working group in the IETF to allow host-NATing using
240 * a standard set of message exchanges. It also allows end-to-end
241 * applications that otherwise break if NAT is introduced
242 * (e.g. IPsec-based VPNs).
243 * A gateway that does not support RSIP should set this variable to 0. */
244 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
247 static void
248 GetExternalIPAddress(struct upnphttp * h, const char * action)
250 static const char resp[] =
251 "<u:%sResponse "
252 "xmlns:u=\"%s\">"
253 "<NewExternalIPAddress>%s</NewExternalIPAddress>"
254 "</u:%sResponse>";
256 char body[512];
257 int bodylen;
258 char ext_ip_addr[INET_ADDRSTRLEN];
259 /* Does that method need to work with IPv6 ?
260 * There is usually no NAT with IPv6 */
262 #ifndef MULTIPLE_EXTERNAL_IP
263 if(use_ext_ip_addr)
265 strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN);
267 else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0)
269 syslog(LOG_ERR, "Failed to get ip address for interface %s",
270 ext_if_name);
271 strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
273 #else
274 int i;
275 strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
276 for(i = 0; i<n_lan_addr; i++)
278 if( (h->clientaddr.s_addr & lan_addr[i].mask.s_addr)
279 == (lan_addr[i].addr.s_addr & lan_addr[i].mask.s_addr))
281 strncpy(ext_ip_addr, lan_addr[i].ext_ip_str, INET_ADDRSTRLEN);
282 break;
285 #endif
286 bodylen = snprintf(body, sizeof(body), resp,
287 action, SERVICE_TYPE_WANIPC,
288 ext_ip_addr, action);
289 BuildSendAndCloseSoapResp(h, body, bodylen);
292 /* AddPortMapping method of WANIPConnection Service
293 * Ignored argument : NewEnabled */
294 static void
295 AddPortMapping(struct upnphttp * h, const char * action)
297 int r;
299 static const char resp[] =
300 "<u:AddPortMappingResponse "
301 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";
303 struct NameValueParserData data;
304 char * int_ip, * int_port, * ext_port, * protocol, * desc;
305 char * leaseduration_str;
306 unsigned int leaseduration;
307 char * r_host;
308 unsigned short iport, eport;
310 struct hostent *hp; /* getbyhostname() */
311 char ** ptr; /* getbyhostname() */
312 struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
314 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
315 int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
316 if (!int_ip)
318 ClearNameValueList(&data);
319 SoapError(h, 402, "Invalid Args");
320 return;
323 /* IGD 2 MUST support both wildcard and specific IP address values
324 * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
325 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
326 #ifndef SUPPORT_REMOTEHOST
327 #ifdef UPNP_STRICT
328 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
330 ClearNameValueList(&data);
331 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
332 return;
334 #endif
335 #endif
337 /* if ip not valid assume hostname and convert */
338 if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
340 hp = gethostbyname(int_ip);
341 if(hp && hp->h_addrtype == AF_INET)
343 for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
345 int_ip = inet_ntoa(*((struct in_addr *) *ptr));
346 result_ip = *((struct in_addr *) *ptr);
347 /* TODO : deal with more than one ip per hostname */
348 break;
351 else
353 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
354 ClearNameValueList(&data);
355 SoapError(h, 402, "Invalid Args");
356 return;
360 /* check if NewInternalAddress is the client address */
361 if(GETFLAG(SECUREMODEMASK))
363 if(h->clientaddr.s_addr != result_ip.s_addr)
365 syslog(LOG_INFO, "Client %s tried to redirect port to %s",
366 inet_ntoa(h->clientaddr), int_ip);
367 ClearNameValueList(&data);
368 SoapError(h, 718, "ConflictInMappingEntry");
369 return;
373 int_port = GetValueFromNameValueList(&data, "NewInternalPort");
374 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
375 protocol = GetValueFromNameValueList(&data, "NewProtocol");
376 desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
377 leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
379 if (!int_port || !ext_port || !protocol)
381 ClearNameValueList(&data);
382 SoapError(h, 402, "Invalid Args");
383 return;
386 eport = (unsigned short)atoi(ext_port);
387 iport = (unsigned short)atoi(int_port);
389 leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
390 #ifdef IGD_V2
391 /* PortMappingLeaseDuration can be either a value between 1 and
392 * 604800 seconds or the zero value (for infinite lease time).
393 * Note that an infinite lease time can be only set by out-of-band
394 * mechanisms like WWW-administration, remote management or local
395 * management.
396 * If a control point uses the value 0 to indicate an infinite lease
397 * time mapping, it is REQUIRED that gateway uses the maximum value
398 * instead (e.g. 604800 seconds) */
399 if(leaseduration == 0 || leaseduration > 604800)
400 leaseduration = 604800;
401 #endif
403 syslog(LOG_INFO, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
404 action, eport, int_ip, iport, protocol, desc, leaseduration, r_host);
406 r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
408 ClearNameValueList(&data);
410 /* possible error codes for AddPortMapping :
411 * 402 - Invalid Args
412 * 501 - Action Failed
413 * 715 - Wildcard not permited in SrcAddr
414 * 716 - Wildcard not permited in ExtPort
415 * 718 - ConflictInMappingEntry
416 * 724 - SamePortValuesRequired (deprecated in IGD v2)
417 * 725 - OnlyPermanentLeasesSupported
418 The NAT implementation only supports permanent lease times on
419 port mappings (deprecated in IGD v2)
420 * 726 - RemoteHostOnlySupportsWildcard
421 RemoteHost must be a wildcard and cannot be a specific IP
422 address or DNS name (deprecated in IGD v2)
423 * 727 - ExternalPortOnlySupportsWildcard
424 ExternalPort must be a wildcard and cannot be a specific port
425 value (deprecated in IGD v2)
426 * 728 - NoPortMapsAvailable
427 There are not enough free prots available to complete the mapping
428 (added in IGD v2)
429 * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
430 switch(r)
432 case 0: /* success */
433 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
434 break;
435 case -2: /* already redirected */
436 case -3: /* not permitted */
437 SoapError(h, 718, "ConflictInMappingEntry");
438 break;
439 default:
440 SoapError(h, 501, "ActionFailed");
444 /* AddAnyPortMapping was added in WANIPConnection v2 */
445 static void
446 AddAnyPortMapping(struct upnphttp * h, const char * action)
448 int r;
449 static const char resp[] =
450 "<u:%sResponse "
451 "xmlns:u=\"%s\">"
452 "<NewReservedPort>%hu</NewReservedPort>"
453 "</u:%sResponse>";
455 char body[512];
456 int bodylen;
458 struct NameValueParserData data;
459 const char * int_ip, * int_port, * ext_port, * protocol, * desc;
460 const char * r_host;
461 unsigned short iport, eport;
462 const char * leaseduration_str;
463 unsigned int leaseduration;
465 struct hostent *hp; /* getbyhostname() */
466 char ** ptr; /* getbyhostname() */
467 struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
469 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
470 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
471 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
472 protocol = GetValueFromNameValueList(&data, "NewProtocol");
473 int_port = GetValueFromNameValueList(&data, "NewInternalPort");
474 int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
475 /* NewEnabled */
476 desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
477 leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
479 leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
480 if(leaseduration == 0)
481 leaseduration = 604800;
483 eport = (unsigned short)atoi(ext_port);
484 iport = (unsigned short)atoi(int_port);
486 if (!int_ip)
488 ClearNameValueList(&data);
489 SoapError(h, 402, "Invalid Args");
490 return;
492 #ifndef SUPPORT_REMOTEHOST
493 #ifdef UPNP_STRICT
494 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
496 ClearNameValueList(&data);
497 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
498 return;
500 #endif
501 #endif
503 /* if ip not valid assume hostname and convert */
504 if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
506 hp = gethostbyname(int_ip);
507 if(hp && hp->h_addrtype == AF_INET)
509 for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
511 int_ip = inet_ntoa(*((struct in_addr *) *ptr));
512 result_ip = *((struct in_addr *) *ptr);
513 /* TODO : deal with more than one ip per hostname */
514 break;
517 else
519 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
520 ClearNameValueList(&data);
521 SoapError(h, 402, "Invalid Args");
522 return;
526 /* check if NewInternalAddress is the client address */
527 if(GETFLAG(SECUREMODEMASK))
529 if(h->clientaddr.s_addr != result_ip.s_addr)
531 syslog(LOG_INFO, "Client %s tried to redirect port to %s",
532 inet_ntoa(h->clientaddr), int_ip);
533 ClearNameValueList(&data);
534 SoapError(h, 606, "Action not authorized");
535 return;
539 /* TODO : accept a different external port
540 * have some smart strategy to choose the port */
541 for(;;) {
542 r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
543 if(r==-2 && eport < 65535) {
544 eport++;
545 } else {
546 break;
550 ClearNameValueList(&data);
552 switch(r)
554 case 0: /* success */
555 bodylen = snprintf(body, sizeof(body), resp,
556 action, SERVICE_TYPE_WANIPC,
557 eport, action);
558 BuildSendAndCloseSoapResp(h, body, bodylen);
559 break;
560 case -2: /* already redirected */
561 SoapError(h, 718, "ConflictInMappingEntry");
562 break;
563 case -3: /* not permitted */
564 SoapError(h, 606, "Action not authorized");
565 break;
566 default:
567 SoapError(h, 501, "ActionFailed");
571 static void
572 GetSpecificPortMappingEntry(struct upnphttp * h, const char * action)
574 int r;
576 static const char resp[] =
577 "<u:%sResponse "
578 "xmlns:u=\"%s\">"
579 "<NewInternalPort>%u</NewInternalPort>"
580 "<NewInternalClient>%s</NewInternalClient>"
581 "<NewEnabled>1</NewEnabled>"
582 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
583 "<NewLeaseDuration>%u</NewLeaseDuration>"
584 "</u:%sResponse>";
586 char body[1024];
587 int bodylen;
588 struct NameValueParserData data;
589 const char * r_host, * ext_port, * protocol;
590 unsigned short eport, iport;
591 char int_ip[32];
592 char desc[64];
593 unsigned int leaseduration = 0;
595 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
596 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
597 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
598 protocol = GetValueFromNameValueList(&data, "NewProtocol");
600 if(!ext_port || !protocol)
602 ClearNameValueList(&data);
603 SoapError(h, 402, "Invalid Args");
604 return;
606 #ifndef SUPPORT_REMOTEHOST
607 #ifdef UPNP_STRICT
608 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
610 ClearNameValueList(&data);
611 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
612 return;
614 #endif
615 #endif
617 eport = (unsigned short)atoi(ext_port);
619 /* add r_host ? */
620 r = upnp_get_redirection_infos(eport, protocol, &iport,
621 int_ip, sizeof(int_ip),
622 desc, sizeof(desc),
623 &leaseduration);
625 if(r < 0)
627 SoapError(h, 714, "NoSuchEntryInArray");
629 else
631 syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
632 action,
633 r_host, ext_port, protocol, int_ip, (unsigned int)iport, desc);
634 bodylen = snprintf(body, sizeof(body), resp,
635 action, SERVICE_TYPE_WANIPC,
636 (unsigned int)iport, int_ip, desc, leaseduration,
637 action);
638 BuildSendAndCloseSoapResp(h, body, bodylen);
641 ClearNameValueList(&data);
644 static void
645 DeletePortMapping(struct upnphttp * h, const char * action)
647 int r;
649 static const char resp[] =
650 "<u:DeletePortMappingResponse "
651 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
652 "</u:DeletePortMappingResponse>";
654 struct NameValueParserData data;
655 const char * r_host, * ext_port, * protocol;
656 unsigned short eport;
658 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
659 r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
660 ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
661 protocol = GetValueFromNameValueList(&data, "NewProtocol");
663 if(!ext_port || !protocol)
665 ClearNameValueList(&data);
666 SoapError(h, 402, "Invalid Args");
667 return;
669 #ifndef SUPPORT_REMOTEHOST
670 #ifdef UPNP_STRICT
671 if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
673 ClearNameValueList(&data);
674 SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
675 return;
677 #endif
678 #endif
680 eport = (unsigned short)atoi(ext_port);
682 /* TODO : if in secure mode, check the IP
683 * Removing a redirection is not a security threat,
684 * just an annoyance for the user using it. So this is not
685 * a priority. */
687 syslog(LOG_INFO, "%s: external port: %hu, protocol: %s",
688 action, eport, protocol);
690 r = upnp_delete_redirection(eport, protocol);
692 if(r < 0)
694 SoapError(h, 714, "NoSuchEntryInArray");
696 else
698 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
701 ClearNameValueList(&data);
704 /* DeletePortMappingRange was added in IGD spec v2 */
705 static void
706 DeletePortMappingRange(struct upnphttp * h, const char * action)
708 int r = -1;
709 static const char resp[] =
710 "<u:DeletePortMappingRangeResponse "
711 "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
712 "</u:DeletePortMappingRangeResponse>";
713 struct NameValueParserData data;
714 const char * protocol;
715 unsigned short startport, endport;
716 int manage;
717 unsigned short * port_list;
718 unsigned int i, number = 0;
720 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
721 startport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort"));
722 endport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewEndPort"));
723 protocol = GetValueFromNameValueList(&data, "NewProtocol");
724 manage = atoi(GetValueFromNameValueList(&data, "NewManage"));
726 /* possible errors :
727 606 - Action not authorized
728 730 - PortMappingNotFound
729 733 - InconsistentParameter
731 if(startport > endport)
733 SoapError(h, 733, "InconsistentParameter");
734 ClearNameValueList(&data);
735 return;
738 port_list = upnp_get_portmappings_in_range(startport, endport,
739 protocol, &number);
740 for(i = 0; i < number; i++)
742 r = upnp_delete_redirection(port_list[i], protocol);
743 /* TODO : check return value for errors */
745 free(port_list);
746 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
748 ClearNameValueList(&data);
751 static void
752 GetGenericPortMappingEntry(struct upnphttp * h, const char * action)
754 int r;
756 static const char resp[] =
757 "<u:%sResponse "
758 "xmlns:u=\"%s\">"
759 "<NewRemoteHost>%s</NewRemoteHost>"
760 "<NewExternalPort>%u</NewExternalPort>"
761 "<NewProtocol>%s</NewProtocol>"
762 "<NewInternalPort>%u</NewInternalPort>"
763 "<NewInternalClient>%s</NewInternalClient>"
764 "<NewEnabled>1</NewEnabled>"
765 "<NewPortMappingDescription>%s</NewPortMappingDescription>"
766 "<NewLeaseDuration>%u</NewLeaseDuration>"
767 "</u:%sResponse>";
769 int index = 0;
770 unsigned short eport, iport;
771 const char * m_index;
772 char protocol[4], iaddr[32];
773 char desc[64];
774 char rhost[40];
775 unsigned int leaseduration = 0;
776 struct NameValueParserData data;
778 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
779 m_index = GetValueFromNameValueList(&data, "NewPortMappingIndex");
781 if(!m_index)
783 ClearNameValueList(&data);
784 SoapError(h, 402, "Invalid Args");
785 return;
788 index = (int)atoi(m_index);
790 syslog(LOG_INFO, "%s: index=%d", action, index);
792 rhost[0] = '\0';
793 r = upnp_get_redirection_infos_by_index(index, &eport, protocol, &iport,
794 iaddr, sizeof(iaddr),
795 desc, sizeof(desc),
796 rhost, sizeof(rhost),
797 &leaseduration);
799 if(r < 0)
801 SoapError(h, 713, "SpecifiedArrayIndexInvalid");
803 else
805 int bodylen;
806 char body[2048];
807 bodylen = snprintf(body, sizeof(body), resp,
808 action, SERVICE_TYPE_WANIPC, rhost,
809 (unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc,
810 leaseduration, action);
811 BuildSendAndCloseSoapResp(h, body, bodylen);
814 ClearNameValueList(&data);
817 /* GetListOfPortMappings was added in the IGD v2 specification */
818 static void
819 GetListOfPortMappings(struct upnphttp * h, const char * action)
821 static const char resp_start[] =
822 "<u:%sResponse "
823 "xmlns:u=\"%s\">"
824 "<NewPortListing><![CDATA[";
825 static const char resp_end[] =
826 "]]></NewPortListing>"
827 "</u:%sResponse>";
829 static const char list_start[] =
830 "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
831 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
832 " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
833 " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
834 static const char list_end[] =
835 "</p:PortMappingList>";
837 static const char entry[] =
838 "<p:PortMappingEntry>"
839 "<p:NewRemoteHost>%s</p:NewRemoteHost>"
840 "<p:NewExternalPort>%hu</p:NewExternalPort>"
841 "<p:NewProtocol>%s</p:NewProtocol>"
842 "<p:NewInternalPort>%hu</p:NewInternalPort>"
843 "<p:NewInternalClient>%s</p:NewInternalClient>"
844 "<p:NewEnabled>1</p:NewEnabled>"
845 "<p:NewDescription>%s</p:NewDescription>"
846 "<p:NewLeaseTime>%u</p:NewLeaseTime>"
847 "</p:PortMappingEntry>";
849 char * body;
850 size_t bodyalloc;
851 int bodylen;
853 int r = -1;
854 unsigned short iport;
855 char int_ip[32];
856 char desc[64];
857 char rhost[64];
858 unsigned int leaseduration = 0;
860 struct NameValueParserData data;
861 unsigned short startport, endport;
862 const char * protocol;
863 int manage;
864 int number;
865 unsigned short * port_list;
866 unsigned int i, list_size = 0;
868 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
869 startport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewStartPort"));
870 endport = (unsigned short)atoi(GetValueFromNameValueList(&data, "NewEndPort"));
871 protocol = GetValueFromNameValueList(&data, "NewProtocol");
872 manage = atoi(GetValueFromNameValueList(&data, "NewManage"));
873 number = atoi(GetValueFromNameValueList(&data, "NewNumberOfPorts"));
874 if(number == 0) number = 1000; /* return up to 1000 mappings by default */
876 if(startport > endport)
878 SoapError(h, 733, "InconsistentParameter");
879 ClearNameValueList(&data);
880 return;
883 TODO : build the PortMappingList xml document :
885 <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
886 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
887 xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
888 http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
889 <p:PortMappingEntry>
890 <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
891 <p:NewExternalPort>2345</p:NewExternalPort>
892 <p:NewProtocol>TCP</p:NewProtocol>
893 <p:NewInternalPort>2345</p:NewInternalPort>
894 <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
895 <p:NewEnabled>1</p:NewEnabled>
896 <p:NewDescription>dooom</p:NewDescription>
897 <p:NewLeaseTime>345</p:NewLeaseTime>
898 </p:PortMappingEntry>
899 </p:PortMappingList>
901 bodyalloc = 4096;
902 body = malloc(bodyalloc);
903 if(!body)
905 ClearNameValueList(&data);
906 SoapError(h, 501, "ActionFailed");
907 return;
909 bodylen = snprintf(body, bodyalloc, resp_start,
910 action, SERVICE_TYPE_WANIPC);
911 memcpy(body+bodylen, list_start, sizeof(list_start));
912 bodylen += (sizeof(list_start) - 1);
914 port_list = upnp_get_portmappings_in_range(startport, endport,
915 protocol, &list_size);
916 /* loop through port mappings */
917 for(i = 0; number > 0 && i < list_size; i++)
919 /* have a margin of 1024 bytes to store the new entry */
920 if(bodylen + 1024 > bodyalloc)
922 bodyalloc += 4096;
923 body = realloc(body, bodyalloc);
924 if(!body)
926 ClearNameValueList(&data);
927 SoapError(h, 501, "ActionFailed");
928 free(port_list);
929 return;
932 r = upnp_get_redirection_infos(port_list[i], protocol, &iport,
933 int_ip, sizeof(int_ip),
934 desc, sizeof(desc), &leaseduration);
935 /* TODO : rhost */
936 rhost[0] = '\0';
937 if(r == 0)
939 bodylen += snprintf(body+bodylen, bodyalloc-bodylen, entry,
940 rhost, port_list[i], protocol,
941 iport, int_ip, desc, leaseduration);
942 number--;
945 free(port_list);
946 port_list = NULL;
948 memcpy(body+bodylen, list_end, sizeof(list_end));
949 bodylen += (sizeof(list_end) - 1);
950 bodylen += snprintf(body+bodylen, bodyalloc-bodylen, resp_end,
951 action);
952 BuildSendAndCloseSoapResp(h, body, bodylen);
953 free(body);
955 ClearNameValueList(&data);
958 #ifdef ENABLE_L3F_SERVICE
959 static void
960 SetDefaultConnectionService(struct upnphttp * h, const char * action)
962 static const char resp[] =
963 "<u:SetDefaultConnectionServiceResponse "
964 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
965 "</u:SetDefaultConnectionServiceResponse>";
966 struct NameValueParserData data;
967 char * p;
968 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
969 p = GetValueFromNameValueList(&data, "NewDefaultConnectionService");
970 if(p) {
971 syslog(LOG_INFO, "%s(%s) : Ignored", action, p);
973 ClearNameValueList(&data);
974 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
977 static void
978 GetDefaultConnectionService(struct upnphttp * h, const char * action)
980 static const char resp[] =
981 "<u:%sResponse "
982 "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
983 "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
984 SERVICE_ID_WANIPC "</NewDefaultConnectionService>"
985 "</u:%sResponse>";
986 /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
987 * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
988 * urn:upnp-org:serviceId:WANPPPConn1 */
989 char body[1024];
990 int bodylen;
992 bodylen = snprintf(body, sizeof(body), resp,
993 action, uuidvalue, action);
994 BuildSendAndCloseSoapResp(h, body, bodylen);
996 #endif
998 /* Added for compliance with WANIPConnection v2 */
999 static void
1000 SetConnectionType(struct upnphttp * h, const char * action)
1002 const char * connection_type;
1003 struct NameValueParserData data;
1005 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1006 connection_type = GetValueFromNameValueList(&data, "NewConnectionType");
1007 /* Unconfigured, IP_Routed, IP_Bridged */
1008 ClearNameValueList(&data);
1009 /* always return a ReadOnly error */
1010 SoapError(h, 731, "ReadOnly");
1013 /* Added for compliance with WANIPConnection v2 */
1014 static void
1015 RequestConnection(struct upnphttp * h, const char * action)
1017 SoapError(h, 606, "Action not authorized");
1020 /* Added for compliance with WANIPConnection v2 */
1021 static void
1022 ForceTermination(struct upnphttp * h, const char * action)
1024 SoapError(h, 606, "Action not authorized");
1028 If a control point calls QueryStateVariable on a state variable that is not
1029 buffered in memory within (or otherwise available from) the service,
1030 the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1032 QueryStateVariable remains useful as a limited test tool but may not be
1033 part of some future versions of UPnP.
1035 static void
1036 QueryStateVariable(struct upnphttp * h, const char * action)
1038 static const char resp[] =
1039 "<u:%sResponse "
1040 "xmlns:u=\"%s\">"
1041 "<return>%s</return>"
1042 "</u:%sResponse>";
1044 char body[512];
1045 int bodylen;
1046 struct NameValueParserData data;
1047 const char * var_name;
1049 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1050 /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1051 /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1052 var_name = GetValueFromNameValueList(&data, "varName");
1054 /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1056 if(!var_name)
1058 SoapError(h, 402, "Invalid Args");
1060 else if(strcmp(var_name, "ConnectionStatus") == 0)
1062 const char * status;
1064 status = get_wan_connection_status_str(ext_if_name);
1065 bodylen = snprintf(body, sizeof(body), resp,
1066 action, "urn:schemas-upnp-org:control-1-0",
1067 status, action);
1068 BuildSendAndCloseSoapResp(h, body, bodylen);
1070 #if 0
1071 /* not usefull */
1072 else if(strcmp(var_name, "ConnectionType") == 0)
1074 bodylen = snprintf(body, sizeof(body), resp, "IP_Routed");
1075 BuildSendAndCloseSoapResp(h, body, bodylen);
1077 else if(strcmp(var_name, "LastConnectionError") == 0)
1079 bodylen = snprintf(body, sizeof(body), resp, "ERROR_NONE");
1080 BuildSendAndCloseSoapResp(h, body, bodylen);
1082 #endif
1083 else if(strcmp(var_name, "PortMappingNumberOfEntries") == 0)
1085 char strn[10];
1086 snprintf(strn, sizeof(strn), "%i",
1087 upnp_get_portmapping_number_of_entries());
1088 bodylen = snprintf(body, sizeof(body), resp,
1089 action, "urn:schemas-upnp-org:control-1-0",
1090 strn, action);
1091 BuildSendAndCloseSoapResp(h, body, bodylen);
1093 else
1095 syslog(LOG_NOTICE, "%s: Unknown: %s", action, var_name?var_name:"");
1096 SoapError(h, 404, "Invalid Var");
1099 ClearNameValueList(&data);
1102 #ifdef ENABLE_6FC_SERVICE
1103 #ifndef ENABLE_IPV6
1104 #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1105 #endif
1106 /* WANIPv6FirewallControl actions */
1107 static void
1108 GetFirewallStatus(struct upnphttp * h, const char * action)
1110 static const char resp[] =
1111 "<u:%sResponse "
1112 "xmlns:u=\"%s\">"
1113 "<FirewallEnabled>%d</FirewallEnabled>"
1114 "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1115 "</u:%sResponse>";
1117 char body[512];
1118 int bodylen;
1120 bodylen = snprintf(body, sizeof(body), resp,
1121 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1122 ipv6fc_firewall_enabled, ipv6fc_inbound_pinhole_allowed, action);
1123 BuildSendAndCloseSoapResp(h, body, bodylen);
1126 static int
1127 CheckStatus(struct upnphttp * h)
1129 if (!ipv6fc_firewall_enabled)
1131 SoapError(h, 702, "FirewallDisabed");
1132 return 0;
1134 else if(!ipv6fc_inbound_pinhole_allowed)
1136 SoapError(h, 703, "InboundPinholeNotAllowed");
1137 return 0;
1139 else
1140 return 1;
1143 static int
1144 DataVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port, const char * protocol, char * leaseTime)
1146 //int n;
1147 // ** Internal IP can't be wildcarded
1148 if (!int_ip)
1150 SoapError(h, 708, "WildCardNotPermittedInSrcIP");
1151 return 0;
1154 if (!strchr(int_ip, ':'))
1156 SoapError(h, 402, "Invalid Args");
1157 return 0;
1160 // ** Internal port can't be wilcarded.
1161 // printf("\tint_port: *%d*\n", *int_port);
1162 if (*int_port == 0)
1164 SoapError(h, 706, "InternalPortWilcardingNotAllowed");
1165 return 0;
1168 // ** Protocol can't be wilcarded and can't be an unknown port (here deal with only UDP, TCP, UDPLITE)
1169 // printf("\tprotocol: *%s*\n", protocol);
1170 if (atoi(protocol) == 65535)
1172 SoapError(h, 707, "ProtocolWilcardingNotAllowed");
1173 return 0;
1175 else if (atoi(protocol) != IPPROTO_UDP
1176 && atoi(protocol) != IPPROTO_TCP
1177 #ifdef IPPROTO_UDPITE
1178 && atoi(protocol) != IPPROTO_UDPLITE
1179 #endif
1182 SoapError(h, 705, "ProtocolNotSupported");
1183 return 0;
1186 // ** Lease Time can't be wilcarded nor >86400.
1187 // printf("\tlease time: %s\n", leaseTime);
1188 if(!leaseTime || !atoi(leaseTime) || atoi(leaseTime)>86400)
1190 /* lease duration is never infinite, nor wilcarded. In this case, use default value */
1191 syslog(LOG_WARNING, "LeaseTime=%s not supported, (ip=%s)", leaseTime, int_ip);
1192 SoapError(h, 402, "Invalid Args");
1193 return 0;
1196 return 1;
1199 #if 0
1200 static int connecthostport(const char * host, unsigned short port, char * result)
1202 int s, n;
1203 char hostname[INET6_ADDRSTRLEN];
1204 char port_str[8], ifname[8], tmp[4];
1205 struct addrinfo *ai, *p;
1206 struct addrinfo hints;
1208 memset(&hints, 0, sizeof(hints));
1209 /* hints.ai_flags = AI_ADDRCONFIG; */
1210 #ifdef AI_NUMERICSERV
1211 hints.ai_flags = AI_NUMERICSERV;
1212 #endif
1213 hints.ai_socktype = SOCK_STREAM;
1214 hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
1215 /* hints.ai_protocol = IPPROTO_TCP; */
1216 snprintf(port_str, sizeof(port_str), "%hu", port);
1217 strcpy(hostname, host);
1218 if(!strncmp(host, "fe80", 4))
1220 printf("Using an linklocal address\n");
1221 strcpy(ifname, "%");
1222 snprintf(tmp, sizeof(tmp), "%d", linklocal_index);
1223 strcat(ifname, tmp);
1224 strcat(hostname, ifname);
1225 printf("host: %s\n", hostname);
1227 n = getaddrinfo(hostname, port_str, &hints, &ai);
1228 if(n != 0)
1230 fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
1231 return -1;
1233 s = -1;
1234 for(p = ai; p; p = p->ai_next)
1236 #ifdef DEBUG
1237 char tmp_host[256];
1238 char tmp_service[256];
1239 printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1240 p->ai_family, p->ai_socktype, p->ai_protocol, p->ai_addrlen);
1241 getnameinfo(p->ai_addr, p->ai_addrlen, tmp_host, sizeof(tmp_host),
1242 tmp_service, sizeof(tmp_service),
1243 NI_NUMERICHOST | NI_NUMERICSERV);
1244 printf(" host=%s service=%s\n", tmp_host, tmp_service);
1245 #endif
1246 inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr), result, INET6_ADDRSTRLEN);
1247 return 0;
1249 freeaddrinfo(ai);
1251 #endif
1253 /* Check the security policy right */
1254 static int
1255 PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port)
1257 int n;
1258 /* Pinhole InternalClient address must correspond to the action sender */
1259 syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)");
1260 char senderAddr[INET6_ADDRSTRLEN]="";
1261 //char str[INET6_ADDRSTRLEN]="";
1262 //connecthostport(int_ip, *int_port, str);
1263 //printf("int_ip: %s / str: %s\n", int_ip, str);
1265 struct addrinfo hints, *ai, *p;
1266 struct in6_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */ //IPv6 Modification
1268 hints.ai_socktype = SOCK_STREAM;
1269 hints.ai_family = AF_UNSPEC;
1271 /* if ip not valid assume hostname and convert */
1272 if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0) //IPv6 Modification
1275 n = getaddrinfo(int_ip, NULL, &hints, &ai);//hp = gethostbyname(int_ip);
1276 if(!n && ai->ai_family == AF_INET6) //IPv6 Modification
1278 for(p = ai; p; p = p->ai_next)//ptr = hp->h_addr_list; ptr && *ptr; ptr++)
1280 inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); ///IPv6 Modification
1281 result_ip = *((struct in6_addr *) p);
1282 fprintf(stderr, "upnpsoap / AddPinhole: assuming int addr = %s", int_ip);
1283 /* TODO : deal with more than one ip per hostname */
1284 break;
1287 else
1289 syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
1290 SoapError(h, 402, "Invalid Args");
1291 return -1;
1293 freeaddrinfo(p);
1296 if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN)<=0)
1298 //printf("Failed to inet_ntop\n");
1299 syslog(LOG_ERR, "inet_ntop: %m");
1301 #ifdef DEBUG
1302 printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr, int_ip);
1303 #endif
1304 if(strcmp(senderAddr, int_ip) != 0)
1305 if(h->clientaddr_v6.s6_addr != result_ip.s6_addr)
1307 syslog(LOG_INFO, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1308 senderAddr, int_ip);
1309 SoapError(h, 606, "Action not authorized");
1310 return 0;
1313 /* Pinhole InternalPort must be greater than or equal to 1024 */
1314 if (*int_port < 1024)
1316 syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1317 senderAddr);
1318 SoapError(h, 606, "Action not authorized");
1319 return 0;
1321 return 1;
1324 static void
1325 AddPinhole(struct upnphttp * h, const char * action)
1327 int r;
1328 static const char resp[] =
1329 "<u:%sResponse "
1330 "xmlns:u=\"%s\">"
1331 "<UniqueID>%d</UniqueID>"
1332 "</u:%sResponse>";
1333 char body[512];
1334 int bodylen;
1335 struct NameValueParserData data;
1336 char * rem_host, * rem_port, * int_ip, * int_port, * protocol, * leaseTime;
1337 int uid = 0;
1338 unsigned short iport, rport;
1340 if(CheckStatus(h)==0)
1341 return;
1343 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1344 rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1345 rem_port = GetValueFromNameValueList(&data, "RemotePort");
1346 int_ip = GetValueFromNameValueList(&data, "InternalClient");
1347 int_port = GetValueFromNameValueList(&data, "InternalPort");
1348 protocol = GetValueFromNameValueList(&data, "Protocol");
1349 leaseTime = GetValueFromNameValueList(&data, "LeaseTime");
1351 rport = (unsigned short)atoi(rem_port);
1352 iport = (unsigned short)atoi(int_port);
1354 // ** As there is no security policy, InternalClient must be equal to the CP's IP address.
1355 if(DataVerification(h, int_ip, &iport, protocol, leaseTime) == 0
1356 || PinholeVerification(h, int_ip, &iport) <= 0)
1358 ClearNameValueList(&data);
1359 return ;
1362 // ** RemoteHost can be wilcarded or an IDN.
1363 /*printf("\trem_host: %s\n", rem_host);*/
1364 if (rem_host!=NULL && !strchr(rem_host, ':'))
1366 ClearNameValueList(&data);
1367 SoapError(h, 402, "Invalid Args");
1368 return;
1370 /*printf("\tAddr check passed.\n");*/
1372 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);
1374 r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, protocol, leaseTime, &uid);
1376 switch(r)
1378 case 1: /* success */
1379 bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", uid, action);
1380 BuildSendAndCloseSoapResp(h, body, bodylen);
1381 break;
1382 case -1: /* not permitted */
1383 SoapError(h, 701, "PinholeSpaceExhausted");
1384 break;
1385 default:
1386 SoapError(h, 501, "ActionFailed");
1387 break;
1389 ClearNameValueList(&data);
1392 static void
1393 UpdatePinhole(struct upnphttp * h, const char * action)
1395 int r, n;
1396 static const char resp[] =
1397 "<u:UpdatePinholeResponse "
1398 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1399 "</u:UpdatePinholeResponse>";
1400 struct NameValueParserData data;
1401 const char * uid, * leaseTime;
1402 char iaddr[40], proto[6], lt[12];
1403 unsigned short iport;
1405 if(CheckStatus(h)==0)
1406 return;
1408 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1409 uid = GetValueFromNameValueList(&data, "UniqueID");
1410 leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime");
1412 if(!uid || !leaseTime || !atoi(leaseTime) || atoi(leaseTime) > 86400)
1414 ClearNameValueList(&data);
1415 SoapError(h, 402, "Invalid Args");
1416 return;
1419 // Check that client is not deleting an pinhole he doesn't have access to, because of its public access
1420 n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
1421 if (n > 0)
1423 if(PinholeVerification(h, iaddr, &iport)==0)
1425 ClearNameValueList(&data);
1426 return ;
1430 syslog(LOG_INFO, "%s: (inbound) updating lease duration to %s for pinhole with ID: %s", action, leaseTime, uid);
1432 r = upnp_update_inboundpinhole(uid, leaseTime);
1434 if(r < 0)
1436 if(r == -4 || r == -1)
1437 SoapError(h, 704, "NoSuchEntry");
1438 else
1439 SoapError(h, 501, "ActionFailed");
1441 else
1443 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
1445 ClearNameValueList(&data);
1448 static void
1449 GetOutboundPinholeTimeout(struct upnphttp * h, const char * action)
1451 if (!ipv6fc_firewall_enabled)
1453 SoapError(h, 702, "FirewallDisabed");
1454 return;
1456 int r;
1458 static const char resp[] =
1459 "<u:%sResponse "
1460 "xmlns:u=\"%s\">"
1461 "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1462 "</u:%sResponse>";
1464 char body[512];
1465 int bodylen;
1466 struct NameValueParserData data;
1467 char * int_ip, * int_port, * rem_host, * rem_port, * protocol;
1468 int opt=0, proto=0;
1469 unsigned short iport, rport;
1471 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1472 int_ip = GetValueFromNameValueList(&data, "InternalClient");
1473 int_port = GetValueFromNameValueList(&data, "InternalPort");
1474 rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1475 rem_port = GetValueFromNameValueList(&data, "RemotePort");
1476 protocol = GetValueFromNameValueList(&data, "Protocol");
1478 rport = (unsigned short)atoi(rem_port);
1479 iport = (unsigned short)atoi(int_port);
1480 proto = atoi(protocol);
1482 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);
1484 r = upnp_check_outbound_pinhole(proto, &opt);
1486 switch(r)
1488 case 1: /* success */
1489 bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", opt, action);
1490 BuildSendAndCloseSoapResp(h, body, bodylen);
1491 break;
1492 case -5: /* Protocol not supported */
1493 SoapError(h, 705, "ProtocolNotSupported");
1494 break;
1495 default:
1496 SoapError(h, 501, "ActionFailed");
1498 ClearNameValueList(&data);
1501 static void
1502 DeletePinhole(struct upnphttp * h, const char * action)
1504 if(CheckStatus(h)==0)
1505 return;
1506 int r, n;
1508 static const char resp[] =
1509 "<u:DeletePinholeResponse "
1510 "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1511 "</u:DeletePinholeResponse>";
1513 struct NameValueParserData data;
1514 const char * uid;
1515 char iaddr[40], proto[6], lt[12];
1516 unsigned short iport;
1518 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1519 uid = GetValueFromNameValueList(&data, "UniqueID");
1521 if(!uid)
1523 ClearNameValueList(&data);
1524 SoapError(h, 402, "Invalid Args");
1525 return;
1528 // Check that client is not deleting an pinhole he doesn't have access to, because of its public access
1529 n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
1530 if (n > 0)
1532 if(PinholeVerification(h, iaddr, &iport)==0)
1534 ClearNameValueList(&data);
1535 return ;
1539 syslog(LOG_INFO, "%s: (inbound) delete pinhole with ID: %s", action, uid);
1541 r = upnp_delete_inboundpinhole(uid);
1543 if(r <= 0)
1545 syslog(LOG_INFO, "%s: (inbound) failed to remove pinhole with ID: %s", action, uid);
1546 if(r==-4)
1547 SoapError(h, 704, "NoSuchEntry");
1548 else
1549 SoapError(h, 501, "ActionFailed");
1551 else
1553 syslog(LOG_INFO, "%s: (inbound) pinhole successfully removed", action);
1554 BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
1556 ClearNameValueList(&data);
1559 static void
1560 CheckPinholeWorking(struct upnphttp * h, const char * action)
1562 if(CheckStatus(h)==0)
1563 return;
1564 int r, d;
1566 static const char resp[] =
1567 "<u:%sResponse "
1568 "xmlns:u=\"%s\">"
1569 "<IsWorking>%d</IsWorking>"
1570 "</u:%sResponse>";
1572 char body[512];
1573 int bodylen;
1574 struct NameValueParserData data;
1575 const char * uid;
1576 char eaddr[40], iaddr[40], proto[6], lt[12];
1577 unsigned short eport, iport;
1578 int isWorking = 0;
1580 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1581 uid = GetValueFromNameValueList(&data, "UniqueID");
1583 if(!uid)
1585 ClearNameValueList(&data);
1586 SoapError(h, 402, "Invalid Args");
1587 return;
1590 // Check that client is not checking a pinhole he doesn't have access to, because of its public access
1591 r = upnp_get_pinhole_info(eaddr, eport, iaddr, &iport, proto, uid, lt);
1592 if (r > 0)
1594 if(PinholeVerification(h, iaddr, &iport)==0)
1596 ClearNameValueList(&data);
1597 return ;
1599 else
1601 int rulenum_used, rulenum = 0;
1602 d = upnp_check_pinhole_working(uid, eaddr, iaddr, &eport, &iport, proto, &rulenum_used);
1603 if(d < 0)
1605 if(d == -4)
1607 syslog(LOG_INFO, "%s: rule for ID=%s, no trace found for this pinhole", action, uid);
1608 SoapError(h, 709, "NoPacketSent");
1609 ClearNameValueList(&data);
1610 return ;
1612 else
1614 // d==-5 not same table // d==-6 not same chain // d==-7 not found a rule but policy traced
1615 isWorking=0;
1616 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"));
1617 bodylen = snprintf(body, sizeof(body), resp,
1618 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1619 isWorking, action);
1620 BuildSendAndCloseSoapResp(h, body, bodylen);
1623 else
1625 /*check_rule_from_file(uid, &rulenum);*/
1626 if(rulenum_used == rulenum)
1628 isWorking=1;
1629 syslog(LOG_INFO, "%s: rule for ID=%s is working properly", action, uid);
1631 else
1633 isWorking=0;
1634 syslog(LOG_INFO, "%s: rule for ID=%s is not working", action, uid);
1636 bodylen = snprintf(body, sizeof(body), resp,
1637 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1638 isWorking, action);
1639 BuildSendAndCloseSoapResp(h, body, bodylen);
1643 else if(r == -4 || r == -1)
1645 SoapError(h, 704, "NoSuchEntry");
1647 else
1649 SoapError(h, 501, "ActionFailed");
1650 ClearNameValueList(&data);
1651 return ;
1653 ClearNameValueList(&data);
1656 static void
1657 GetPinholePackets(struct upnphttp * h, const char * action)
1659 if(CheckStatus(h)==0)
1660 return;
1661 int r, n;
1663 static const char resp[] =
1664 "<u:%sResponse "
1665 "xmlns:u=\"%s\">"
1666 "<PinholePackets>%d</PinholePackets>"
1667 "</u:%sResponse>";
1669 char body[512];
1670 int bodylen;
1671 struct NameValueParserData data;
1672 const char * uid;
1673 char iaddr[40], proto[6], lt[12];
1674 unsigned short iport;
1675 int pinholePackets = 0;
1677 ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1678 uid = GetValueFromNameValueList(&data, "UniqueID");
1680 if(!uid)
1682 ClearNameValueList(&data);
1683 SoapError(h, 402, "Invalid Args");
1684 return;
1687 // Check that client is not getting infos of a pinhole he doesn't have access to, because of its public access
1688 r = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
1689 if (r > 0)
1691 if(PinholeVerification(h, iaddr, &iport)==0)
1693 ClearNameValueList(&data);
1694 return ;
1698 n = upnp_get_pinhole_packets(uid, &pinholePackets);
1699 if(n > 0)
1701 bodylen = snprintf(body, sizeof(body), resp,
1702 action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1703 pinholePackets, action);
1704 BuildSendAndCloseSoapResp(h, body, bodylen);
1706 else if(r == -4 || r == -1)
1708 SoapError(h, 704, "NoSuchEntry");
1710 else
1712 SoapError(h, 501, "ActionFailed");
1713 ClearNameValueList(&data);
1714 return ;
1716 ClearNameValueList(&data);
1718 #endif
1721 /* Windows XP as client send the following requests :
1722 * GetConnectionTypeInfo
1723 * GetNATRSIPStatus
1724 * ? GetTotalBytesSent - WANCommonInterfaceConfig
1725 * ? GetTotalBytesReceived - idem
1726 * ? GetTotalPacketsSent - idem
1727 * ? GetTotalPacketsReceived - idem
1728 * GetCommonLinkProperties - idem
1729 * GetStatusInfo - WANIPConnection
1730 * GetExternalIPAddress
1731 * QueryStateVariable / ConnectionStatus!
1733 static const struct
1735 const char * methodName;
1736 void (*methodImpl)(struct upnphttp *, const char *);
1738 soapMethods[] =
1740 /* WANCommonInterfaceConfig */
1741 { "QueryStateVariable", QueryStateVariable},
1742 { "GetTotalBytesSent", GetTotalBytesSent},
1743 { "GetTotalBytesReceived", GetTotalBytesReceived},
1744 { "GetTotalPacketsSent", GetTotalPacketsSent},
1745 { "GetTotalPacketsReceived", GetTotalPacketsReceived},
1746 { "GetCommonLinkProperties", GetCommonLinkProperties},
1747 { "GetStatusInfo", GetStatusInfo},
1748 /* WANIPConnection */
1749 { "GetConnectionTypeInfo", GetConnectionTypeInfo },
1750 { "GetNATRSIPStatus", GetNATRSIPStatus},
1751 { "GetExternalIPAddress", GetExternalIPAddress},
1752 { "AddPortMapping", AddPortMapping},
1753 { "DeletePortMapping", DeletePortMapping},
1754 { "GetGenericPortMappingEntry", GetGenericPortMappingEntry},
1755 { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry},
1756 /* Required in WANIPConnection:2 */
1757 { "SetConnectionType", SetConnectionType},
1758 { "RequestConnection", RequestConnection},
1759 { "ForceTermination", ForceTermination},
1760 { "AddAnyPortMapping", AddAnyPortMapping},
1761 { "DeletePortMappingRange", DeletePortMappingRange},
1762 { "GetListOfPortMappings", GetListOfPortMappings},
1763 #ifdef ENABLE_L3F_SERVICE
1764 /* Layer3Forwarding */
1765 { "SetDefaultConnectionService", SetDefaultConnectionService},
1766 { "GetDefaultConnectionService", GetDefaultConnectionService},
1767 #endif
1768 #ifdef ENABLE_6FC_SERVICE
1769 /* WANIPv6FirewallControl */
1770 { "GetFirewallStatus", GetFirewallStatus},
1771 { "AddPinhole", AddPinhole},
1772 { "UpdatePinhole", UpdatePinhole},
1773 { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout},
1774 { "DeletePinhole", DeletePinhole},
1775 { "CheckPinholeWorking", CheckPinholeWorking},
1776 { "GetPinholePackets", GetPinholePackets},
1777 #endif
1778 { 0, 0 }
1781 void
1782 ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
1784 char * p;
1785 char * p2;
1786 int i, len, methodlen;
1788 i = 0;
1789 p = strchr(action, '#');
1791 if(p)
1793 p++;
1794 p2 = strchr(p, '"');
1795 if(p2)
1796 methodlen = p2 - p;
1797 else
1798 methodlen = n - (p - action);
1799 /*syslog(LOG_DEBUG, "SoapMethod: %.*s", methodlen, p);*/
1800 while(soapMethods[i].methodName)
1802 len = strlen(soapMethods[i].methodName);
1803 if(strncmp(p, soapMethods[i].methodName, len) == 0)
1805 soapMethods[i].methodImpl(h, soapMethods[i].methodName);
1806 return;
1808 i++;
1811 syslog(LOG_NOTICE, "SoapMethod: Unknown: %.*s", methodlen, p);
1814 SoapError(h, 401, "Invalid Action");
1817 /* Standard Errors:
1819 * errorCode errorDescription Description
1820 * -------- ---------------- -----------
1821 * 401 Invalid Action No action by that name at this service.
1822 * 402 Invalid Args Could be any of the following: not enough in args,
1823 * too many in args, no in arg by that name,
1824 * one or more in args are of the wrong data type.
1825 * 403 Out of Sync Out of synchronization.
1826 * 501 Action Failed May be returned in current state of service
1827 * prevents invoking that action.
1828 * 600-699 TBD Common action errors. Defined by UPnP Forum
1829 * Technical Committee.
1830 * 700-799 TBD Action-specific errors for standard actions.
1831 * Defined by UPnP Forum working committee.
1832 * 800-899 TBD Action-specific errors for non-standard actions.
1833 * Defined by UPnP vendor.
1835 void
1836 SoapError(struct upnphttp * h, int errCode, const char * errDesc)
1838 static const char resp[] =
1839 "<s:Envelope "
1840 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
1841 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
1842 "<s:Body>"
1843 "<s:Fault>"
1844 "<faultcode>s:Client</faultcode>"
1845 "<faultstring>UPnPError</faultstring>"
1846 "<detail>"
1847 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
1848 "<errorCode>%d</errorCode>"
1849 "<errorDescription>%s</errorDescription>"
1850 "</UPnPError>"
1851 "</detail>"
1852 "</s:Fault>"
1853 "</s:Body>"
1854 "</s:Envelope>";
1856 char body[2048];
1857 int bodylen;
1859 syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc);
1860 bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc);
1861 BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen);
1862 SendResp_upnphttp(h);
1863 CloseSocket_upnphttp(h);