1: /* $Id: upnpsoap.c,v 1.1.1.3 2013/07/22 00:32:35 misho Exp $ */
2: /* MiniUPnP project
3: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4: * (c) 2006-2012 Thomas Bernard
5: * This software is subject to the conditions detailed
6: * in the LICENCE file provided within the distribution */
7:
8: #include <stdio.h>
9: #include <stdlib.h>
10: #include <string.h>
11: #include <errno.h>
12: #include <sys/socket.h>
13: #include <unistd.h>
14: #include <syslog.h>
15: #include <sys/types.h>
16: #include <netinet/in.h>
17: #include <arpa/inet.h>
18: #include <netdb.h>
19:
20: #include "macros.h"
21: #include "config.h"
22: #include "upnpglobalvars.h"
23: #include "upnphttp.h"
24: #include "upnpsoap.h"
25: #include "upnpreplyparse.h"
26: #include "upnpredirect.h"
27: #include "upnppinhole.h"
28: #include "getifaddr.h"
29: #include "getifstats.h"
30: #include "getconnstatus.h"
31: #include "upnpurns.h"
32:
33: static void
34: BuildSendAndCloseSoapResp(struct upnphttp * h,
35: const char * body, int bodylen)
36: {
37: static const char beforebody[] =
38: "<?xml version=\"1.0\"?>\r\n"
39: "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
40: "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
41: "<s:Body>";
42:
43: static const char afterbody[] =
44: "</s:Body>"
45: "</s:Envelope>\r\n";
46:
47: BuildHeader_upnphttp(h, 200, "OK", sizeof(beforebody) - 1
48: + sizeof(afterbody) - 1 + bodylen );
49:
50: memcpy(h->res_buf + h->res_buflen, beforebody, sizeof(beforebody) - 1);
51: h->res_buflen += sizeof(beforebody) - 1;
52:
53: memcpy(h->res_buf + h->res_buflen, body, bodylen);
54: h->res_buflen += bodylen;
55:
56: memcpy(h->res_buf + h->res_buflen, afterbody, sizeof(afterbody) - 1);
57: h->res_buflen += sizeof(afterbody) - 1;
58:
59: SendRespAndClose_upnphttp(h);
60: }
61:
62: static void
63: GetConnectionTypeInfo(struct upnphttp * h, const char * action)
64: {
65: static const char resp[] =
66: "<u:GetConnectionTypeInfoResponse "
67: "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
68: "<NewConnectionType>IP_Routed</NewConnectionType>"
69: "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
70: "</u:GetConnectionTypeInfoResponse>";
71: UNUSED(action);
72:
73: BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
74: }
75:
76: static void
77: GetTotalBytesSent(struct upnphttp * h, const char * action)
78: {
79: int r;
80:
81: static const char resp[] =
82: "<u:%sResponse "
83: "xmlns:u=\"%s\">"
84: "<NewTotalBytesSent>%lu</NewTotalBytesSent>"
85: "</u:%sResponse>";
86:
87: char body[512];
88: int bodylen;
89: struct ifdata data;
90:
91: r = getifstats(ext_if_name, &data);
92: bodylen = snprintf(body, sizeof(body), resp,
93: action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
94: r<0?0:data.obytes, action);
95: BuildSendAndCloseSoapResp(h, body, bodylen);
96: }
97:
98: static void
99: GetTotalBytesReceived(struct upnphttp * h, const char * action)
100: {
101: int r;
102:
103: static const char resp[] =
104: "<u:%sResponse "
105: "xmlns:u=\"%s\">"
106: "<NewTotalBytesReceived>%lu</NewTotalBytesReceived>"
107: "</u:%sResponse>";
108:
109: char body[512];
110: int bodylen;
111: struct ifdata data;
112:
113: r = getifstats(ext_if_name, &data);
114: bodylen = snprintf(body, sizeof(body), resp,
115: action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
116: r<0?0:data.ibytes, action);
117: BuildSendAndCloseSoapResp(h, body, bodylen);
118: }
119:
120: static void
121: GetTotalPacketsSent(struct upnphttp * h, const char * action)
122: {
123: int r;
124:
125: static const char resp[] =
126: "<u:%sResponse "
127: "xmlns:u=\"%s\">"
128: "<NewTotalPacketsSent>%lu</NewTotalPacketsSent>"
129: "</u:%sResponse>";
130:
131: char body[512];
132: int bodylen;
133: struct ifdata data;
134:
135: r = getifstats(ext_if_name, &data);
136: bodylen = snprintf(body, sizeof(body), resp,
137: action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
138: r<0?0:data.opackets, action);
139: BuildSendAndCloseSoapResp(h, body, bodylen);
140: }
141:
142: static void
143: GetTotalPacketsReceived(struct upnphttp * h, const char * action)
144: {
145: int r;
146:
147: static const char resp[] =
148: "<u:%sResponse "
149: "xmlns:u=\"%s\">"
150: "<NewTotalPacketsReceived>%lu</NewTotalPacketsReceived>"
151: "</u:%sResponse>";
152:
153: char body[512];
154: int bodylen;
155: struct ifdata data;
156:
157: r = getifstats(ext_if_name, &data);
158: bodylen = snprintf(body, sizeof(body), resp,
159: action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
160: r<0?0:data.ipackets, action);
161: BuildSendAndCloseSoapResp(h, body, bodylen);
162: }
163:
164: static void
165: GetCommonLinkProperties(struct upnphttp * h, const char * action)
166: {
167: /* WANAccessType : set depending on the hardware :
168: * DSL, POTS (plain old Telephone service), Cable, Ethernet */
169: static const char resp[] =
170: "<u:%sResponse "
171: "xmlns:u=\"%s\">"
172: /*"<NewWANAccessType>DSL</NewWANAccessType>"*/
173: "<NewWANAccessType>Cable</NewWANAccessType>"
174: "<NewLayer1UpstreamMaxBitRate>%lu</NewLayer1UpstreamMaxBitRate>"
175: "<NewLayer1DownstreamMaxBitRate>%lu</NewLayer1DownstreamMaxBitRate>"
176: "<NewPhysicalLinkStatus>%s</NewPhysicalLinkStatus>"
177: "</u:%sResponse>";
178:
179: char body[2048];
180: int bodylen;
181: struct ifdata data;
182: const char * status = "Up"; /* Up, Down (Required),
183: * Initializing, Unavailable (Optional) */
184: char ext_ip_addr[INET_ADDRSTRLEN];
185:
186: if((downstream_bitrate == 0) || (upstream_bitrate == 0))
187: {
188: if(getifstats(ext_if_name, &data) >= 0)
189: {
190: if(downstream_bitrate == 0) downstream_bitrate = data.baudrate;
191: if(upstream_bitrate == 0) upstream_bitrate = data.baudrate;
192: }
193: }
194: if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0) {
195: status = "Down";
196: }
197: bodylen = snprintf(body, sizeof(body), resp,
198: action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
199: upstream_bitrate, downstream_bitrate,
200: status, action);
201: BuildSendAndCloseSoapResp(h, body, bodylen);
202: }
203:
204: static void
205: GetStatusInfo(struct upnphttp * h, const char * action)
206: {
207: static const char resp[] =
208: "<u:%sResponse "
209: "xmlns:u=\"%s\">"
210: "<NewConnectionStatus>%s</NewConnectionStatus>"
211: "<NewLastConnectionError>ERROR_NONE</NewLastConnectionError>"
212: "<NewUptime>%ld</NewUptime>"
213: "</u:%sResponse>";
214:
215: char body[512];
216: int bodylen;
217: time_t uptime;
218: const char * status;
219: /* ConnectionStatus possible values :
220: * Unconfigured, Connecting, Connected, PendingDisconnect,
221: * Disconnecting, Disconnected */
222:
223: status = get_wan_connection_status_str(ext_if_name);
224: uptime = (time(NULL) - startup_time);
225: bodylen = snprintf(body, sizeof(body), resp,
226: action, SERVICE_TYPE_WANIPC,
227: status, (long)uptime, action);
228: BuildSendAndCloseSoapResp(h, body, bodylen);
229: }
230:
231: static void
232: GetNATRSIPStatus(struct upnphttp * h, const char * action)
233: {
234: static const char resp[] =
235: "<u:GetNATRSIPStatusResponse "
236: "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
237: "<NewRSIPAvailable>0</NewRSIPAvailable>"
238: "<NewNATEnabled>1</NewNATEnabled>"
239: "</u:GetNATRSIPStatusResponse>";
240: UNUSED(action);
241: /* 2.2.9. RSIPAvailable
242: * This variable indicates if Realm-specific IP (RSIP) is available
243: * as a feature on the InternetGatewayDevice. RSIP is being defined
244: * in the NAT working group in the IETF to allow host-NATing using
245: * a standard set of message exchanges. It also allows end-to-end
246: * applications that otherwise break if NAT is introduced
247: * (e.g. IPsec-based VPNs).
248: * A gateway that does not support RSIP should set this variable to 0. */
249: BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
250: }
251:
252: static void
253: GetExternalIPAddress(struct upnphttp * h, const char * action)
254: {
255: static const char resp[] =
256: "<u:%sResponse "
257: "xmlns:u=\"%s\">"
258: "<NewExternalIPAddress>%s</NewExternalIPAddress>"
259: "</u:%sResponse>";
260:
261: char body[512];
262: int bodylen;
263: char ext_ip_addr[INET_ADDRSTRLEN];
264: /* Does that method need to work with IPv6 ?
265: * There is usually no NAT with IPv6 */
266:
267: #ifndef MULTIPLE_EXTERNAL_IP
268: if(use_ext_ip_addr)
269: {
270: strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN);
271: }
272: else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN) < 0)
273: {
274: syslog(LOG_ERR, "Failed to get ip address for interface %s",
275: ext_if_name);
276: strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
277: }
278: #else
279: struct lan_addr_s * lan_addr;
280: strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
281: for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
282: {
283: if( (h->clientaddr.s_addr & lan_addr->mask.s_addr)
284: == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
285: {
286: strncpy(ext_ip_addr, lan_addr->ext_ip_str, INET_ADDRSTRLEN);
287: break;
288: }
289: }
290: #endif
291: bodylen = snprintf(body, sizeof(body), resp,
292: action, SERVICE_TYPE_WANIPC,
293: ext_ip_addr, action);
294: BuildSendAndCloseSoapResp(h, body, bodylen);
295: }
296:
297: /* AddPortMapping method of WANIPConnection Service
298: * Ignored argument : NewEnabled */
299: static void
300: AddPortMapping(struct upnphttp * h, const char * action)
301: {
302: int r;
303:
304: static const char resp[] =
305: "<u:AddPortMappingResponse "
306: "xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";
307:
308: struct NameValueParserData data;
309: char * int_ip, * int_port, * ext_port, * protocol, * desc;
310: char * leaseduration_str;
311: unsigned int leaseduration;
312: char * r_host;
313: unsigned short iport, eport;
314:
315: struct hostent *hp; /* getbyhostname() */
316: char ** ptr; /* getbyhostname() */
317: struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
318:
319: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
320: int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
321: if (!int_ip)
322: {
323: ClearNameValueList(&data);
324: SoapError(h, 402, "Invalid Args");
325: return;
326: }
327:
328: /* IGD 2 MUST support both wildcard and specific IP address values
329: * for RemoteHost (only the wildcard value was REQUIRED in release 1.0) */
330: r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
331: #ifndef SUPPORT_REMOTEHOST
332: #ifdef UPNP_STRICT
333: if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
334: {
335: ClearNameValueList(&data);
336: SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
337: return;
338: }
339: #endif
340: #endif
341:
342: /* if ip not valid assume hostname and convert */
343: if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
344: {
345: hp = gethostbyname(int_ip);
346: if(hp && hp->h_addrtype == AF_INET)
347: {
348: for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
349: {
350: int_ip = inet_ntoa(*((struct in_addr *) *ptr));
351: result_ip = *((struct in_addr *) *ptr);
352: /* TODO : deal with more than one ip per hostname */
353: break;
354: }
355: }
356: else
357: {
358: syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
359: ClearNameValueList(&data);
360: SoapError(h, 402, "Invalid Args");
361: return;
362: }
363: }
364:
365: /* check if NewInternalAddress is the client address */
366: if(GETFLAG(SECUREMODEMASK))
367: {
368: if(h->clientaddr.s_addr != result_ip.s_addr)
369: {
370: syslog(LOG_INFO, "Client %s tried to redirect port to %s",
371: inet_ntoa(h->clientaddr), int_ip);
372: ClearNameValueList(&data);
373: SoapError(h, 718, "ConflictInMappingEntry");
374: return;
375: }
376: }
377:
378: int_port = GetValueFromNameValueList(&data, "NewInternalPort");
379: ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
380: protocol = GetValueFromNameValueList(&data, "NewProtocol");
381: desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
382: leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
383:
384: if (!int_port || !ext_port || !protocol)
385: {
386: ClearNameValueList(&data);
387: SoapError(h, 402, "Invalid Args");
388: return;
389: }
390:
391: eport = (unsigned short)atoi(ext_port);
392: iport = (unsigned short)atoi(int_port);
393:
394: leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
395: #ifdef IGD_V2
396: /* PortMappingLeaseDuration can be either a value between 1 and
397: * 604800 seconds or the zero value (for infinite lease time).
398: * Note that an infinite lease time can be only set by out-of-band
399: * mechanisms like WWW-administration, remote management or local
400: * management.
401: * If a control point uses the value 0 to indicate an infinite lease
402: * time mapping, it is REQUIRED that gateway uses the maximum value
403: * instead (e.g. 604800 seconds) */
404: if(leaseduration == 0 || leaseduration > 604800)
405: leaseduration = 604800;
406: #endif
407:
408: syslog(LOG_INFO, "%s: ext port %hu to %s:%hu protocol %s for: %s leaseduration=%u rhost=%s",
409: action, eport, int_ip, iport, protocol, desc, leaseduration,
410: r_host ? r_host : "NULL");
411:
412: r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
413:
414: ClearNameValueList(&data);
415:
416: /* possible error codes for AddPortMapping :
417: * 402 - Invalid Args
418: * 501 - Action Failed
419: * 715 - Wildcard not permited in SrcAddr
420: * 716 - Wildcard not permited in ExtPort
421: * 718 - ConflictInMappingEntry
422: * 724 - SamePortValuesRequired (deprecated in IGD v2)
423: * 725 - OnlyPermanentLeasesSupported
424: The NAT implementation only supports permanent lease times on
425: port mappings (deprecated in IGD v2)
426: * 726 - RemoteHostOnlySupportsWildcard
427: RemoteHost must be a wildcard and cannot be a specific IP
428: address or DNS name (deprecated in IGD v2)
429: * 727 - ExternalPortOnlySupportsWildcard
430: ExternalPort must be a wildcard and cannot be a specific port
431: value (deprecated in IGD v2)
432: * 728 - NoPortMapsAvailable
433: There are not enough free prots available to complete the mapping
434: (added in IGD v2)
435: * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
436: switch(r)
437: {
438: case 0: /* success */
439: BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
440: break;
441: case -2: /* already redirected */
442: case -3: /* not permitted */
443: SoapError(h, 718, "ConflictInMappingEntry");
444: break;
445: default:
446: SoapError(h, 501, "ActionFailed");
447: }
448: }
449:
450: /* AddAnyPortMapping was added in WANIPConnection v2 */
451: static void
452: AddAnyPortMapping(struct upnphttp * h, const char * action)
453: {
454: int r;
455: static const char resp[] =
456: "<u:%sResponse "
457: "xmlns:u=\"%s\">"
458: "<NewReservedPort>%hu</NewReservedPort>"
459: "</u:%sResponse>";
460:
461: char body[512];
462: int bodylen;
463:
464: struct NameValueParserData data;
465: const char * int_ip, * int_port, * ext_port, * protocol, * desc;
466: const char * r_host;
467: unsigned short iport, eport;
468: const char * leaseduration_str;
469: unsigned int leaseduration;
470:
471: struct hostent *hp; /* getbyhostname() */
472: char ** ptr; /* getbyhostname() */
473: struct in_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */
474:
475: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
476: r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
477: ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
478: protocol = GetValueFromNameValueList(&data, "NewProtocol");
479: int_port = GetValueFromNameValueList(&data, "NewInternalPort");
480: int_ip = GetValueFromNameValueList(&data, "NewInternalClient");
481: /* NewEnabled */
482: desc = GetValueFromNameValueList(&data, "NewPortMappingDescription");
483: leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
484:
485: leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
486: if(leaseduration == 0)
487: leaseduration = 604800;
488:
489: if (!int_ip || !ext_port || !int_port)
490: {
491: ClearNameValueList(&data);
492: SoapError(h, 402, "Invalid Args");
493: return;
494: }
495:
496: eport = (unsigned short)atoi(ext_port);
497: iport = (unsigned short)atoi(int_port);
498: #ifndef SUPPORT_REMOTEHOST
499: #ifdef UPNP_STRICT
500: if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
501: {
502: ClearNameValueList(&data);
503: SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
504: return;
505: }
506: #endif
507: #endif
508:
509: /* if ip not valid assume hostname and convert */
510: if (inet_pton(AF_INET, int_ip, &result_ip) <= 0)
511: {
512: hp = gethostbyname(int_ip);
513: if(hp && hp->h_addrtype == AF_INET)
514: {
515: for(ptr = hp->h_addr_list; ptr && *ptr; ptr++)
516: {
517: int_ip = inet_ntoa(*((struct in_addr *) *ptr));
518: result_ip = *((struct in_addr *) *ptr);
519: /* TODO : deal with more than one ip per hostname */
520: break;
521: }
522: }
523: else
524: {
525: syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
526: ClearNameValueList(&data);
527: SoapError(h, 402, "Invalid Args");
528: return;
529: }
530: }
531:
532: /* check if NewInternalAddress is the client address */
533: if(GETFLAG(SECUREMODEMASK))
534: {
535: if(h->clientaddr.s_addr != result_ip.s_addr)
536: {
537: syslog(LOG_INFO, "Client %s tried to redirect port to %s",
538: inet_ntoa(h->clientaddr), int_ip);
539: ClearNameValueList(&data);
540: SoapError(h, 606, "Action not authorized");
541: return;
542: }
543: }
544:
545: /* TODO : accept a different external port
546: * have some smart strategy to choose the port */
547: for(;;) {
548: r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
549: if(r==-2 && eport < 65535) {
550: eport++;
551: } else {
552: break;
553: }
554: }
555:
556: ClearNameValueList(&data);
557:
558: switch(r)
559: {
560: case 0: /* success */
561: bodylen = snprintf(body, sizeof(body), resp,
562: action, SERVICE_TYPE_WANIPC,
563: eport, action);
564: BuildSendAndCloseSoapResp(h, body, bodylen);
565: break;
566: case -2: /* already redirected */
567: SoapError(h, 718, "ConflictInMappingEntry");
568: break;
569: case -3: /* not permitted */
570: SoapError(h, 606, "Action not authorized");
571: break;
572: default:
573: SoapError(h, 501, "ActionFailed");
574: }
575: }
576:
577: static void
578: GetSpecificPortMappingEntry(struct upnphttp * h, const char * action)
579: {
580: int r;
581:
582: static const char resp[] =
583: "<u:%sResponse "
584: "xmlns:u=\"%s\">"
585: "<NewInternalPort>%u</NewInternalPort>"
586: "<NewInternalClient>%s</NewInternalClient>"
587: "<NewEnabled>1</NewEnabled>"
588: "<NewPortMappingDescription>%s</NewPortMappingDescription>"
589: "<NewLeaseDuration>%u</NewLeaseDuration>"
590: "</u:%sResponse>";
591:
592: char body[1024];
593: int bodylen;
594: struct NameValueParserData data;
595: const char * r_host, * ext_port, * protocol;
596: unsigned short eport, iport;
597: char int_ip[32];
598: char desc[64];
599: unsigned int leaseduration = 0;
600:
601: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
602: r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
603: ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
604: protocol = GetValueFromNameValueList(&data, "NewProtocol");
605:
606: #ifdef UPNP_STRICT
607: if(!ext_port || !protocol || !r_host)
608: #else
609: if(!ext_port || !protocol)
610: #endif
611: {
612: ClearNameValueList(&data);
613: SoapError(h, 402, "Invalid Args");
614: return;
615: }
616: #ifndef SUPPORT_REMOTEHOST
617: #ifdef UPNP_STRICT
618: if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
619: {
620: ClearNameValueList(&data);
621: SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
622: return;
623: }
624: #endif
625: #endif
626:
627: eport = (unsigned short)atoi(ext_port);
628:
629: /* TODO : add r_host as an input parameter ...
630: * We prevent several Port Mapping with same external port
631: * but different remoteHost to be set up, so that is not
632: * a priority. */
633: r = upnp_get_redirection_infos(eport, protocol, &iport,
634: int_ip, sizeof(int_ip),
635: desc, sizeof(desc),
636: NULL, 0,
637: &leaseduration);
638:
639: if(r < 0)
640: {
641: SoapError(h, 714, "NoSuchEntryInArray");
642: }
643: else
644: {
645: syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s'",
646: action,
647: r_host ? r_host : "NULL", ext_port, protocol, int_ip,
648: (unsigned int)iport, desc);
649: bodylen = snprintf(body, sizeof(body), resp,
650: action, SERVICE_TYPE_WANIPC,
651: (unsigned int)iport, int_ip, desc, leaseduration,
652: action);
653: BuildSendAndCloseSoapResp(h, body, bodylen);
654: }
655:
656: ClearNameValueList(&data);
657: }
658:
659: static void
660: DeletePortMapping(struct upnphttp * h, const char * action)
661: {
662: int r;
663:
664: static const char resp[] =
665: "<u:DeletePortMappingResponse "
666: "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
667: "</u:DeletePortMappingResponse>";
668:
669: struct NameValueParserData data;
670: const char * r_host, * ext_port, * protocol;
671: unsigned short eport;
672:
673: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
674: r_host = GetValueFromNameValueList(&data, "NewRemoteHost");
675: ext_port = GetValueFromNameValueList(&data, "NewExternalPort");
676: protocol = GetValueFromNameValueList(&data, "NewProtocol");
677:
678: #ifdef UPNP_STRICT
679: if(!ext_port || !protocol || !r_host)
680: #else
681: if(!ext_port || !protocol)
682: #endif
683: {
684: ClearNameValueList(&data);
685: SoapError(h, 402, "Invalid Args");
686: return;
687: }
688: #ifndef SUPPORT_REMOTEHOST
689: #ifdef UPNP_STRICT
690: if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*")))
691: {
692: ClearNameValueList(&data);
693: SoapError(h, 726, "RemoteHostOnlySupportsWildcard");
694: return;
695: }
696: #endif
697: #endif
698:
699: eport = (unsigned short)atoi(ext_port);
700:
701: /* TODO : if in secure mode, check the IP
702: * Removing a redirection is not a security threat,
703: * just an annoyance for the user using it. So this is not
704: * a priority. */
705:
706: syslog(LOG_INFO, "%s: external port: %hu, protocol: %s",
707: action, eport, protocol);
708:
709: r = upnp_delete_redirection(eport, protocol);
710:
711: if(r < 0)
712: {
713: SoapError(h, 714, "NoSuchEntryInArray");
714: }
715: else
716: {
717: BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
718: }
719:
720: ClearNameValueList(&data);
721: }
722:
723: /* DeletePortMappingRange was added in IGD spec v2 */
724: static void
725: DeletePortMappingRange(struct upnphttp * h, const char * action)
726: {
727: int r = -1;
728: static const char resp[] =
729: "<u:DeletePortMappingRangeResponse "
730: "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
731: "</u:DeletePortMappingRangeResponse>";
732: struct NameValueParserData data;
733: const char * protocol;
734: const char * startport_s, * endport_s;
735: unsigned short startport, endport;
736: /*int manage;*/
737: unsigned short * port_list;
738: unsigned int i, number = 0;
739: UNUSED(action);
740:
741: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
742: startport_s = GetValueFromNameValueList(&data, "NewStartPort");
743: endport_s = GetValueFromNameValueList(&data, "NewEndPort");
744: protocol = GetValueFromNameValueList(&data, "NewProtocol");
745: /*manage = atoi(GetValueFromNameValueList(&data, "NewManage"));*/
746: if(startport_s == NULL || endport_s == NULL || protocol == NULL) {
747: SoapError(h, 402, "Invalid Args");
748: ClearNameValueList(&data);
749: return;
750: }
751: startport = (unsigned short)atoi(startport_s);
752: endport = (unsigned short)atoi(endport_s);
753:
754: /* possible errors :
755: 606 - Action not authorized
756: 730 - PortMappingNotFound
757: 733 - InconsistentParameter
758: */
759: if(startport > endport)
760: {
761: SoapError(h, 733, "InconsistentParameter");
762: ClearNameValueList(&data);
763: return;
764: }
765:
766: port_list = upnp_get_portmappings_in_range(startport, endport,
767: protocol, &number);
768: for(i = 0; i < number; i++)
769: {
770: r = upnp_delete_redirection(port_list[i], protocol);
771: /* TODO : check return value for errors */
772: }
773: free(port_list);
774: BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
775:
776: ClearNameValueList(&data);
777: }
778:
779: static void
780: GetGenericPortMappingEntry(struct upnphttp * h, const char * action)
781: {
782: int r;
783:
784: static const char resp[] =
785: "<u:%sResponse "
786: "xmlns:u=\"%s\">"
787: "<NewRemoteHost>%s</NewRemoteHost>"
788: "<NewExternalPort>%u</NewExternalPort>"
789: "<NewProtocol>%s</NewProtocol>"
790: "<NewInternalPort>%u</NewInternalPort>"
791: "<NewInternalClient>%s</NewInternalClient>"
792: "<NewEnabled>1</NewEnabled>"
793: "<NewPortMappingDescription>%s</NewPortMappingDescription>"
794: "<NewLeaseDuration>%u</NewLeaseDuration>"
795: "</u:%sResponse>";
796:
797: int index = 0;
798: unsigned short eport, iport;
799: const char * m_index;
800: char protocol[4], iaddr[32];
801: char desc[64];
802: char rhost[40];
803: unsigned int leaseduration = 0;
804: struct NameValueParserData data;
805:
806: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
807: m_index = GetValueFromNameValueList(&data, "NewPortMappingIndex");
808:
809: if(!m_index)
810: {
811: ClearNameValueList(&data);
812: SoapError(h, 402, "Invalid Args");
813: return;
814: }
815:
816: index = (int)atoi(m_index);
817:
818: syslog(LOG_INFO, "%s: index=%d", action, index);
819:
820: rhost[0] = '\0';
821: r = upnp_get_redirection_infos_by_index(index, &eport, protocol, &iport,
822: iaddr, sizeof(iaddr),
823: desc, sizeof(desc),
824: rhost, sizeof(rhost),
825: &leaseduration);
826:
827: if(r < 0)
828: {
829: SoapError(h, 713, "SpecifiedArrayIndexInvalid");
830: }
831: else
832: {
833: int bodylen;
834: char body[2048];
835: bodylen = snprintf(body, sizeof(body), resp,
836: action, SERVICE_TYPE_WANIPC, rhost,
837: (unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc,
838: leaseduration, action);
839: BuildSendAndCloseSoapResp(h, body, bodylen);
840: }
841:
842: ClearNameValueList(&data);
843: }
844:
845: /* GetListOfPortMappings was added in the IGD v2 specification */
846: static void
847: GetListOfPortMappings(struct upnphttp * h, const char * action)
848: {
849: static const char resp_start[] =
850: "<u:%sResponse "
851: "xmlns:u=\"%s\">"
852: "<NewPortListing><![CDATA[";
853: static const char resp_end[] =
854: "]]></NewPortListing>"
855: "</u:%sResponse>";
856:
857: static const char list_start[] =
858: "<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\""
859: " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
860: " xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection"
861: " http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">";
862: static const char list_end[] =
863: "</p:PortMappingList>";
864:
865: static const char entry[] =
866: "<p:PortMappingEntry>"
867: "<p:NewRemoteHost>%s</p:NewRemoteHost>"
868: "<p:NewExternalPort>%hu</p:NewExternalPort>"
869: "<p:NewProtocol>%s</p:NewProtocol>"
870: "<p:NewInternalPort>%hu</p:NewInternalPort>"
871: "<p:NewInternalClient>%s</p:NewInternalClient>"
872: "<p:NewEnabled>1</p:NewEnabled>"
873: "<p:NewDescription>%s</p:NewDescription>"
874: "<p:NewLeaseTime>%u</p:NewLeaseTime>"
875: "</p:PortMappingEntry>";
876:
877: char * body;
878: size_t bodyalloc;
879: int bodylen;
880:
881: int r = -1;
882: unsigned short iport;
883: char int_ip[32];
884: char desc[64];
885: char rhost[64];
886: unsigned int leaseduration = 0;
887:
888: struct NameValueParserData data;
889: const char * startport_s, * endport_s;
890: unsigned short startport, endport;
891: const char * protocol;
892: /*int manage;*/
893: const char * number_s;
894: int number;
895: unsigned short * port_list;
896: unsigned int i, list_size = 0;
897:
898: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
899: startport_s = GetValueFromNameValueList(&data, "NewStartPort");
900: endport_s = GetValueFromNameValueList(&data, "NewEndPort");
901: protocol = GetValueFromNameValueList(&data, "NewProtocol");
902: /*manage_s = GetValueFromNameValueList(&data, "NewManage");*/
903: number_s = GetValueFromNameValueList(&data, "NewNumberOfPorts");
904: if(startport_s == NULL || endport_s == NULL || protocol == NULL ||
905: number_s == NULL) {
906: SoapError(h, 402, "Invalid Args");
907: ClearNameValueList(&data);
908: return;
909: }
910:
911: startport = (unsigned short)atoi(startport_s);
912: endport = (unsigned short)atoi(endport_s);
913: /*manage = atoi(manage_s);*/
914: number = atoi(number_s);
915: if(number == 0) number = 1000; /* return up to 1000 mappings by default */
916:
917: if(startport > endport)
918: {
919: SoapError(h, 733, "InconsistentParameter");
920: ClearNameValueList(&data);
921: return;
922: }
923: /*
924: build the PortMappingList xml document :
925:
926: <p:PortMappingList xmlns:p="urn:schemas-upnp-org:gw:WANIPConnection"
927: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
928: xsi:schemaLocation="urn:schemas-upnp-org:gw:WANIPConnection
929: http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
930: <p:PortMappingEntry>
931: <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
932: <p:NewExternalPort>2345</p:NewExternalPort>
933: <p:NewProtocol>TCP</p:NewProtocol>
934: <p:NewInternalPort>2345</p:NewInternalPort>
935: <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
936: <p:NewEnabled>1</p:NewEnabled>
937: <p:NewDescription>dooom</p:NewDescription>
938: <p:NewLeaseTime>345</p:NewLeaseTime>
939: </p:PortMappingEntry>
940: </p:PortMappingList>
941: */
942: bodyalloc = 4096;
943: body = malloc(bodyalloc);
944: if(!body)
945: {
946: ClearNameValueList(&data);
947: SoapError(h, 501, "ActionFailed");
948: return;
949: }
950: bodylen = snprintf(body, bodyalloc, resp_start,
951: action, SERVICE_TYPE_WANIPC);
952: if(bodylen < 0)
953: {
954: SoapError(h, 501, "ActionFailed");
955: free(body);
956: return;
957: }
958: memcpy(body+bodylen, list_start, sizeof(list_start));
959: bodylen += (sizeof(list_start) - 1);
960:
961: port_list = upnp_get_portmappings_in_range(startport, endport,
962: protocol, &list_size);
963: /* loop through port mappings */
964: for(i = 0; number > 0 && i < list_size; i++)
965: {
966: /* have a margin of 1024 bytes to store the new entry */
967: if((unsigned int)bodylen + 1024 > bodyalloc)
968: {
969: char * body_sav = body;
970: bodyalloc += 4096;
971: body = realloc(body, bodyalloc);
972: if(!body)
973: {
974: ClearNameValueList(&data);
975: SoapError(h, 501, "ActionFailed");
976: free(body_sav);
977: free(port_list);
978: return;
979: }
980: }
981: rhost[0] = '\0';
982: r = upnp_get_redirection_infos(port_list[i], protocol, &iport,
983: int_ip, sizeof(int_ip),
984: desc, sizeof(desc),
985: rhost, sizeof(rhost),
986: &leaseduration);
987: if(r == 0)
988: {
989: bodylen += snprintf(body+bodylen, bodyalloc-bodylen, entry,
990: rhost, port_list[i], protocol,
991: iport, int_ip, desc, leaseduration);
992: number--;
993: }
994: }
995: free(port_list);
996: port_list = NULL;
997:
998: memcpy(body+bodylen, list_end, sizeof(list_end));
999: bodylen += (sizeof(list_end) - 1);
1000: bodylen += snprintf(body+bodylen, bodyalloc-bodylen, resp_end,
1001: action);
1002: BuildSendAndCloseSoapResp(h, body, bodylen);
1003: free(body);
1004:
1005: ClearNameValueList(&data);
1006: }
1007:
1008: #ifdef ENABLE_L3F_SERVICE
1009: static void
1010: SetDefaultConnectionService(struct upnphttp * h, const char * action)
1011: {
1012: static const char resp[] =
1013: "<u:SetDefaultConnectionServiceResponse "
1014: "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1015: "</u:SetDefaultConnectionServiceResponse>";
1016: struct NameValueParserData data;
1017: char * p;
1018: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1019: p = GetValueFromNameValueList(&data, "NewDefaultConnectionService");
1020: if(p) {
1021: /* 720 InvalidDeviceUUID
1022: * 721 InvalidServiceID
1023: * 723 InvalidConnServiceSelection */
1024: #ifdef UPNP_STRICT
1025: if(0 != memcmp(uuidvalue, p, sizeof("uuid:00000000-0000-0000-0000-000000000000") - 1)) {
1026: SoapError(h, 720, "InvalidDeviceUUID");
1027: } else
1028: #endif
1029: {
1030: syslog(LOG_INFO, "%s(%s) : Ignored", action, p);
1031: BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
1032: }
1033: } else {
1034: /* missing argument */
1035: SoapError(h, 402, "Invalid Args");
1036: }
1037: ClearNameValueList(&data);
1038: }
1039:
1040: static void
1041: GetDefaultConnectionService(struct upnphttp * h, const char * action)
1042: {
1043: static const char resp[] =
1044: "<u:%sResponse "
1045: "xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
1046: "<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
1047: SERVICE_ID_WANIPC "</NewDefaultConnectionService>"
1048: "</u:%sResponse>";
1049: /* example from UPnP_IGD_Layer3Forwarding 1.0.pdf :
1050: * uuid:44f5824f-c57d-418c-a131-f22b34e14111:WANConnectionDevice:1,
1051: * urn:upnp-org:serviceId:WANPPPConn1 */
1052: char body[1024];
1053: int bodylen;
1054:
1055: bodylen = snprintf(body, sizeof(body), resp,
1056: action, uuidvalue, action);
1057: BuildSendAndCloseSoapResp(h, body, bodylen);
1058: }
1059: #endif
1060:
1061: /* Added for compliance with WANIPConnection v2 */
1062: static void
1063: SetConnectionType(struct upnphttp * h, const char * action)
1064: {
1065: const char * connection_type;
1066: struct NameValueParserData data;
1067: UNUSED(action);
1068:
1069: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1070: connection_type = GetValueFromNameValueList(&data, "NewConnectionType");
1071: #ifdef UPNP_STRICT
1072: if(!connection_type) {
1073: ClearNameValueList(&data);
1074: SoapError(h, 402, "Invalid Args");
1075: return;
1076: }
1077: #endif
1078: /* Unconfigured, IP_Routed, IP_Bridged */
1079: ClearNameValueList(&data);
1080: /* always return a ReadOnly error */
1081: SoapError(h, 731, "ReadOnly");
1082: }
1083:
1084: /* Added for compliance with WANIPConnection v2 */
1085: static void
1086: RequestConnection(struct upnphttp * h, const char * action)
1087: {
1088: UNUSED(action);
1089: SoapError(h, 606, "Action not authorized");
1090: }
1091:
1092: /* Added for compliance with WANIPConnection v2 */
1093: static void
1094: ForceTermination(struct upnphttp * h, const char * action)
1095: {
1096: UNUSED(action);
1097: SoapError(h, 606, "Action not authorized");
1098: }
1099:
1100: /*
1101: If a control point calls QueryStateVariable on a state variable that is not
1102: buffered in memory within (or otherwise available from) the service,
1103: the service must return a SOAP fault with an errorCode of 404 Invalid Var.
1104:
1105: QueryStateVariable remains useful as a limited test tool but may not be
1106: part of some future versions of UPnP.
1107: */
1108: static void
1109: QueryStateVariable(struct upnphttp * h, const char * action)
1110: {
1111: static const char resp[] =
1112: "<u:%sResponse "
1113: "xmlns:u=\"%s\">"
1114: "<return>%s</return>"
1115: "</u:%sResponse>";
1116:
1117: char body[512];
1118: int bodylen;
1119: struct NameValueParserData data;
1120: const char * var_name;
1121:
1122: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1123: /*var_name = GetValueFromNameValueList(&data, "QueryStateVariable"); */
1124: /*var_name = GetValueFromNameValueListIgnoreNS(&data, "varName");*/
1125: var_name = GetValueFromNameValueList(&data, "varName");
1126:
1127: /*syslog(LOG_INFO, "QueryStateVariable(%.40s)", var_name); */
1128:
1129: if(!var_name)
1130: {
1131: SoapError(h, 402, "Invalid Args");
1132: }
1133: else if(strcmp(var_name, "ConnectionStatus") == 0)
1134: {
1135: const char * status;
1136:
1137: status = get_wan_connection_status_str(ext_if_name);
1138: bodylen = snprintf(body, sizeof(body), resp,
1139: action, "urn:schemas-upnp-org:control-1-0",
1140: status, action);
1141: BuildSendAndCloseSoapResp(h, body, bodylen);
1142: }
1143: #if 0
1144: /* not usefull */
1145: else if(strcmp(var_name, "ConnectionType") == 0)
1146: {
1147: bodylen = snprintf(body, sizeof(body), resp, "IP_Routed");
1148: BuildSendAndCloseSoapResp(h, body, bodylen);
1149: }
1150: else if(strcmp(var_name, "LastConnectionError") == 0)
1151: {
1152: bodylen = snprintf(body, sizeof(body), resp, "ERROR_NONE");
1153: BuildSendAndCloseSoapResp(h, body, bodylen);
1154: }
1155: #endif
1156: else if(strcmp(var_name, "PortMappingNumberOfEntries") == 0)
1157: {
1158: char strn[10];
1159: snprintf(strn, sizeof(strn), "%i",
1160: upnp_get_portmapping_number_of_entries());
1161: bodylen = snprintf(body, sizeof(body), resp,
1162: action, "urn:schemas-upnp-org:control-1-0",
1163: strn, action);
1164: BuildSendAndCloseSoapResp(h, body, bodylen);
1165: }
1166: else
1167: {
1168: syslog(LOG_NOTICE, "%s: Unknown: %s", action, var_name?var_name:"");
1169: SoapError(h, 404, "Invalid Var");
1170: }
1171:
1172: ClearNameValueList(&data);
1173: }
1174:
1175: #ifdef ENABLE_6FC_SERVICE
1176: #ifndef ENABLE_IPV6
1177: #error "ENABLE_6FC_SERVICE needs ENABLE_IPV6"
1178: #endif
1179: /* WANIPv6FirewallControl actions */
1180: static void
1181: GetFirewallStatus(struct upnphttp * h, const char * action)
1182: {
1183: static const char resp[] =
1184: "<u:%sResponse "
1185: "xmlns:u=\"%s\">"
1186: "<FirewallEnabled>%d</FirewallEnabled>"
1187: "<InboundPinholeAllowed>%d</InboundPinholeAllowed>"
1188: "</u:%sResponse>";
1189:
1190: char body[512];
1191: int bodylen;
1192:
1193: bodylen = snprintf(body, sizeof(body), resp,
1194: action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1195: ipv6fc_firewall_enabled, ipv6fc_inbound_pinhole_allowed, action);
1196: BuildSendAndCloseSoapResp(h, body, bodylen);
1197: }
1198:
1199: static int
1200: CheckStatus(struct upnphttp * h)
1201: {
1202: if (!ipv6fc_firewall_enabled)
1203: {
1204: SoapError(h, 702, "FirewallDisabled");
1205: return 0;
1206: }
1207: else if(!ipv6fc_inbound_pinhole_allowed)
1208: {
1209: SoapError(h, 703, "InboundPinholeNotAllowed");
1210: return 0;
1211: }
1212: else
1213: return 1;
1214: }
1215:
1216: #if 0
1217: static int connecthostport(const char * host, unsigned short port, char * result)
1218: {
1219: int s, n;
1220: char hostname[INET6_ADDRSTRLEN];
1221: char port_str[8], ifname[8], tmp[4];
1222: struct addrinfo *ai, *p;
1223: struct addrinfo hints;
1224:
1225: memset(&hints, 0, sizeof(hints));
1226: /* hints.ai_flags = AI_ADDRCONFIG; */
1227: #ifdef AI_NUMERICSERV
1228: hints.ai_flags = AI_NUMERICSERV;
1229: #endif
1230: hints.ai_socktype = SOCK_STREAM;
1231: hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
1232: /* hints.ai_protocol = IPPROTO_TCP; */
1233: snprintf(port_str, sizeof(port_str), "%hu", port);
1234: strcpy(hostname, host);
1235: if(!strncmp(host, "fe80", 4))
1236: {
1237: printf("Using an linklocal address\n");
1238: strcpy(ifname, "%");
1239: snprintf(tmp, sizeof(tmp), "%d", linklocal_index);
1240: strcat(ifname, tmp);
1241: strcat(hostname, ifname);
1242: printf("host: %s\n", hostname);
1243: }
1244: n = getaddrinfo(hostname, port_str, &hints, &ai);
1245: if(n != 0)
1246: {
1247: fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
1248: return -1;
1249: }
1250: s = -1;
1251: for(p = ai; p; p = p->ai_next)
1252: {
1253: #ifdef DEBUG
1254: char tmp_host[256];
1255: char tmp_service[256];
1256: printf("ai_family=%d ai_socktype=%d ai_protocol=%d ai_addrlen=%d\n ",
1257: p->ai_family, p->ai_socktype, p->ai_protocol, p->ai_addrlen);
1258: getnameinfo(p->ai_addr, p->ai_addrlen, tmp_host, sizeof(tmp_host),
1259: tmp_service, sizeof(tmp_service),
1260: NI_NUMERICHOST | NI_NUMERICSERV);
1261: printf(" host=%s service=%s\n", tmp_host, tmp_service);
1262: #endif
1263: inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr), result, INET6_ADDRSTRLEN);
1264: return 0;
1265: }
1266: freeaddrinfo(ai);
1267: }
1268: #endif
1269:
1270: /* Check the security policy right */
1271: static int
1272: PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short int_port)
1273: {
1274: int n;
1275: char senderAddr[INET6_ADDRSTRLEN]="";
1276: struct addrinfo hints, *ai, *p;
1277: struct in6_addr result_ip;
1278:
1279: /* Pinhole InternalClient address must correspond to the action sender */
1280: syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)");
1281:
1282: hints.ai_socktype = SOCK_STREAM;
1283: hints.ai_family = AF_UNSPEC;
1284:
1285: /* if ip not valid assume hostname and convert */
1286: if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0)
1287: {
1288: n = getaddrinfo(int_ip, NULL, &hints, &ai);
1289: if(!n && ai->ai_family == AF_INET6)
1290: {
1291: for(p = ai; p; p = p->ai_next)
1292: {
1293: inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr));
1294: result_ip = *((struct in6_addr *) p);
1295: /* TODO : deal with more than one ip per hostname */
1296: break;
1297: }
1298: }
1299: else
1300: {
1301: syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
1302: SoapError(h, 402, "Invalid Args");
1303: return -1;
1304: }
1305: freeaddrinfo(p);
1306: }
1307:
1308: if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN) == NULL)
1309: {
1310: syslog(LOG_ERR, "inet_ntop: %m");
1311: }
1312: #ifdef DEBUG
1313: printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr, int_ip);
1314: #endif
1315: if(strcmp(senderAddr, int_ip) != 0)
1316: if(h->clientaddr_v6.s6_addr != result_ip.s6_addr)
1317: {
1318: syslog(LOG_INFO, "Client %s tried to access pinhole for internal %s and is not authorized to do it",
1319: senderAddr, int_ip);
1320: SoapError(h, 606, "Action not authorized");
1321: return 0;
1322: }
1323:
1324: /* Pinhole InternalPort must be greater than or equal to 1024 */
1325: if (int_port < 1024)
1326: {
1327: syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
1328: senderAddr);
1329: SoapError(h, 606, "Action not authorized");
1330: return 0;
1331: }
1332: return 1;
1333: }
1334:
1335: static void
1336: AddPinhole(struct upnphttp * h, const char * action)
1337: {
1338: int r;
1339: static const char resp[] =
1340: "<u:%sResponse "
1341: "xmlns:u=\"%s\">"
1342: "<UniqueID>%d</UniqueID>"
1343: "</u:%sResponse>";
1344: char body[512];
1345: int bodylen;
1346: struct NameValueParserData data;
1347: char * rem_host, * rem_port, * int_ip, * int_port, * protocol, * leaseTime;
1348: int uid = 0;
1349: unsigned short iport, rport;
1350: int ltime;
1351: long proto;
1352: char rem_ip[INET6_ADDRSTRLEN];
1353:
1354: if(CheckStatus(h)==0)
1355: return;
1356:
1357: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1358: rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1359: rem_port = GetValueFromNameValueList(&data, "RemotePort");
1360: int_ip = GetValueFromNameValueList(&data, "InternalClient");
1361: int_port = GetValueFromNameValueList(&data, "InternalPort");
1362: protocol = GetValueFromNameValueList(&data, "Protocol");
1363: leaseTime = GetValueFromNameValueList(&data, "LeaseTime");
1364:
1365: rport = (unsigned short)(rem_port ? atoi(rem_port) : 0);
1366: iport = (unsigned short)(int_port ? atoi(int_port) : 0);
1367: ltime = leaseTime ? atoi(leaseTime) : -1;
1368: errno = 0;
1369: proto = protocol ? strtol(protocol, NULL, 0) : -1;
1370: if(errno != 0 || proto > 65535 || proto < 0)
1371: {
1372: SoapError(h, 402, "Invalid Args");
1373: goto clear_and_exit;
1374: }
1375: if(iport == 0)
1376: {
1377: SoapError(h, 706, "InternalPortWilcardingNotAllowed");
1378: goto clear_and_exit;
1379: }
1380:
1381: /* In particular, [IGD2] RECOMMENDS that unauthenticated and
1382: * unauthorized control points are only allowed to invoke
1383: * this action with:
1384: * - InternalPort value greater than or equal to 1024,
1385: * - InternalClient value equals to the control point's IP address.
1386: * It is REQUIRED that InternalClient cannot be one of IPv6
1387: * addresses used by the gateway. */
1388: if(!int_ip || 0 == strlen(int_ip) || 0 == strcmp(int_ip, "*"))
1389: {
1390: SoapError(h, 708, "WildCardNotPermittedInSrcIP");
1391: goto clear_and_exit;
1392: }
1393: /* I guess it is useless to convert int_ip to literal ipv6 address */
1394: /* rem_host should be converted to literal ipv6 : */
1395: if(rem_host)
1396: {
1397: struct addrinfo *ai, *p;
1398: struct addrinfo hints;
1399: int err;
1400: memset(&hints, 0, sizeof(struct addrinfo));
1401: hints.ai_family = AF_INET6;
1402: /*hints.ai_flags = */
1403: /* hints.ai_protocol = proto; */
1404: err = getaddrinfo(rem_host, rem_port, &hints, &ai);
1405: if(err == 0)
1406: {
1407: /* take the 1st IPv6 address */
1408: for(p = ai; p; p = p->ai_next)
1409: {
1410: if(p->ai_family == AF_INET6)
1411: {
1412: inet_ntop(AF_INET6,
1413: &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr),
1414: rem_ip, sizeof(rem_ip));
1415: syslog(LOG_INFO, "resolved '%s' to '%s'", rem_host, rem_ip);
1416: rem_host = rem_ip;
1417: break;
1418: }
1419: }
1420: freeaddrinfo(ai);
1421: }
1422: else
1423: {
1424: syslog(LOG_WARNING, "AddPinhole : getaddrinfo(%s) : %s",
1425: rem_host, gai_strerror(err));
1426: #if 0
1427: SoapError(h, 402, "Invalid Args");
1428: goto clear_and_exit;
1429: #endif
1430: }
1431: }
1432:
1433: if(proto == 65535)
1434: {
1435: SoapError(h, 707, "ProtocolWilcardingNotAllowed");
1436: goto clear_and_exit;
1437: }
1438: if(proto != IPPROTO_UDP && proto != IPPROTO_TCP
1439: #ifdef IPPROTO_UDPITE
1440: && atoi(protocol) != IPPROTO_UDPLITE
1441: #endif
1442: )
1443: {
1444: SoapError(h, 705, "ProtocolNotSupported");
1445: goto clear_and_exit;
1446: }
1447: if(ltime < 1 || ltime > 86400)
1448: {
1449: syslog(LOG_WARNING, "%s: LeaseTime=%d not supported, (ip=%s)",
1450: action, ltime, int_ip);
1451: SoapError(h, 402, "Invalid Args");
1452: goto clear_and_exit;
1453: }
1454:
1455: if(PinholeVerification(h, int_ip, iport) <= 0)
1456: goto clear_and_exit;
1457:
1458: syslog(LOG_INFO, "%s: (inbound) from [%s]:%hu to [%s]:%hu with proto %ld during %d sec",
1459: action, rem_host?rem_host:"any",
1460: rport, int_ip, iport,
1461: proto, ltime);
1462:
1463: /* In cases where the RemoteHost, RemotePort, InternalPort,
1464: * InternalClient and Protocol are the same than an existing pinhole,
1465: * but LeaseTime is different, the device MUST extend the existing
1466: * pinhole's lease time and return the UniqueID of the existing pinhole. */
1467: r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, proto, ltime, &uid);
1468:
1469: switch(r)
1470: {
1471: case 1: /* success */
1472: bodylen = snprintf(body, sizeof(body),
1473: resp, action,
1474: "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1475: uid, action);
1476: BuildSendAndCloseSoapResp(h, body, bodylen);
1477: break;
1478: case -1: /* not permitted */
1479: SoapError(h, 701, "PinholeSpaceExhausted");
1480: break;
1481: default:
1482: SoapError(h, 501, "ActionFailed");
1483: break;
1484: }
1485: /* 606 Action not authorized
1486: * 701 PinholeSpaceExhausted
1487: * 702 FirewallDisabled
1488: * 703 InboundPinholeNotAllowed
1489: * 705 ProtocolNotSupported
1490: * 706 InternalPortWildcardingNotAllowed
1491: * 707 ProtocolWildcardingNotAllowed
1492: * 708 WildCardNotPermittedInSrcIP */
1493: clear_and_exit:
1494: ClearNameValueList(&data);
1495: }
1496:
1497: static void
1498: UpdatePinhole(struct upnphttp * h, const char * action)
1499: {
1500: static const char resp[] =
1501: "<u:UpdatePinholeResponse "
1502: "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1503: "</u:UpdatePinholeResponse>";
1504: struct NameValueParserData data;
1505: const char * uid_str, * leaseTime;
1506: char iaddr[INET6_ADDRSTRLEN];
1507: unsigned short iport;
1508: int ltime;
1509: int uid;
1510: int n;
1511:
1512: if(CheckStatus(h)==0)
1513: return;
1514:
1515: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1516: uid_str = GetValueFromNameValueList(&data, "UniqueID");
1517: leaseTime = GetValueFromNameValueList(&data, "NewLeaseTime");
1518: uid = uid_str ? atoi(uid_str) : -1;
1519: ltime = leaseTime ? atoi(leaseTime) : -1;
1520: ClearNameValueList(&data);
1521:
1522: if(uid < 0 || uid > 65535 || ltime <= 0 || ltime > 86400)
1523: {
1524: SoapError(h, 402, "Invalid Args");
1525: return;
1526: }
1527:
1528: /* Check that client is not updating an pinhole
1529: * it doesn't have access to, because of its public access */
1530: n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
1531: iaddr, sizeof(iaddr), &iport,
1532: NULL, NULL, NULL);
1533: if (n >= 0)
1534: {
1535: if(PinholeVerification(h, iaddr, iport) <= 0)
1536: return;
1537: }
1538: else if(n == -2)
1539: {
1540: SoapError(h, 704, "NoSuchEntry");
1541: return;
1542: }
1543: else
1544: {
1545: SoapError(h, 501, "ActionFailed");
1546: return;
1547: }
1548:
1549: syslog(LOG_INFO, "%s: (inbound) updating lease duration to %d for pinhole with ID: %d",
1550: action, ltime, uid);
1551:
1552: n = upnp_update_inboundpinhole(uid, ltime);
1553: if(n == -1)
1554: SoapError(h, 704, "NoSuchEntry");
1555: else if(n < 0)
1556: SoapError(h, 501, "ActionFailed");
1557: else
1558: BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
1559: }
1560:
1561: static void
1562: GetOutboundPinholeTimeout(struct upnphttp * h, const char * action)
1563: {
1564: int r;
1565:
1566: static const char resp[] =
1567: "<u:%sResponse "
1568: "xmlns:u=\"%s\">"
1569: "<OutboundPinholeTimeout>%d</OutboundPinholeTimeout>"
1570: "</u:%sResponse>";
1571:
1572: char body[512];
1573: int bodylen;
1574: struct NameValueParserData data;
1575: char * int_ip, * int_port, * rem_host, * rem_port, * protocol;
1576: int opt=0, proto=0;
1577: unsigned short iport, rport;
1578:
1579: if (!ipv6fc_firewall_enabled)
1580: {
1581: SoapError(h, 702, "FirewallDisabled");
1582: return;
1583: }
1584:
1585: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1586: int_ip = GetValueFromNameValueList(&data, "InternalClient");
1587: int_port = GetValueFromNameValueList(&data, "InternalPort");
1588: rem_host = GetValueFromNameValueList(&data, "RemoteHost");
1589: rem_port = GetValueFromNameValueList(&data, "RemotePort");
1590: protocol = GetValueFromNameValueList(&data, "Protocol");
1591:
1592: rport = (unsigned short)atoi(rem_port);
1593: iport = (unsigned short)atoi(int_port);
1594: proto = atoi(protocol);
1595:
1596: 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);
1597:
1598: /* TODO */
1599: r = -1;/*upnp_check_outbound_pinhole(proto, &opt);*/
1600:
1601: switch(r)
1602: {
1603: case 1: /* success */
1604: bodylen = snprintf(body, sizeof(body), resp,
1605: action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1606: opt, action);
1607: BuildSendAndCloseSoapResp(h, body, bodylen);
1608: break;
1609: case -5: /* Protocol not supported */
1610: SoapError(h, 705, "ProtocolNotSupported");
1611: break;
1612: default:
1613: SoapError(h, 501, "ActionFailed");
1614: }
1615: ClearNameValueList(&data);
1616: }
1617:
1618: static void
1619: DeletePinhole(struct upnphttp * h, const char * action)
1620: {
1621: int n;
1622:
1623: static const char resp[] =
1624: "<u:DeletePinholeResponse "
1625: "xmlns:u=\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">"
1626: "</u:DeletePinholeResponse>";
1627:
1628: struct NameValueParserData data;
1629: const char * uid_str;
1630: char iaddr[INET6_ADDRSTRLEN];
1631: int proto;
1632: unsigned short iport;
1633: unsigned int leasetime;
1634: int uid;
1635:
1636: if(CheckStatus(h)==0)
1637: return;
1638:
1639: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1640: uid_str = GetValueFromNameValueList(&data, "UniqueID");
1641: uid = uid_str ? atoi(uid_str) : -1;
1642: ClearNameValueList(&data);
1643:
1644: if(uid < 0 || uid > 65535)
1645: {
1646: SoapError(h, 402, "Invalid Args");
1647: return;
1648: }
1649:
1650: /* Check that client is not deleting an pinhole
1651: * it doesn't have access to, because of its public access */
1652: n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
1653: iaddr, sizeof(iaddr), &iport,
1654: &proto, &leasetime, NULL);
1655: if (n >= 0)
1656: {
1657: if(PinholeVerification(h, iaddr, iport) <= 0)
1658: return;
1659: }
1660: else if(n == -2)
1661: {
1662: SoapError(h, 704, "NoSuchEntry");
1663: return;
1664: }
1665: else
1666: {
1667: SoapError(h, 501, "ActionFailed");
1668: return;
1669: }
1670:
1671: n = upnp_delete_inboundpinhole(uid);
1672: if(n < 0)
1673: {
1674: syslog(LOG_INFO, "%s: (inbound) failed to remove pinhole with ID: %d",
1675: action, uid);
1676: SoapError(h, 501, "ActionFailed");
1677: return;
1678: }
1679: syslog(LOG_INFO, "%s: (inbound) pinhole with ID %d successfully removed",
1680: action, uid);
1681: BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
1682: }
1683:
1684: static void
1685: CheckPinholeWorking(struct upnphttp * h, const char * action)
1686: {
1687: static const char resp[] =
1688: "<u:%sResponse "
1689: "xmlns:u=\"%s\">"
1690: "<IsWorking>%d</IsWorking>"
1691: "</u:%sResponse>";
1692: char body[512];
1693: int bodylen;
1694: int r;
1695: struct NameValueParserData data;
1696: const char * uid_str;
1697: int uid;
1698: char iaddr[INET6_ADDRSTRLEN];
1699: unsigned short iport;
1700: unsigned int packets;
1701:
1702: if(CheckStatus(h)==0)
1703: return;
1704:
1705: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1706: uid_str = GetValueFromNameValueList(&data, "UniqueID");
1707: uid = uid_str ? atoi(uid_str) : -1;
1708: ClearNameValueList(&data);
1709:
1710: if(uid < 0 || uid > 65535)
1711: {
1712: SoapError(h, 402, "Invalid Args");
1713: return;
1714: }
1715:
1716: /* Check that client is not checking a pinhole
1717: * it doesn't have access to, because of its public access */
1718: r = upnp_get_pinhole_info(uid,
1719: NULL, 0, NULL,
1720: iaddr, sizeof(iaddr), &iport,
1721: NULL, NULL, &packets);
1722: if (r >= 0)
1723: {
1724: if(PinholeVerification(h, iaddr, iport) <= 0)
1725: return ;
1726: if(packets == 0)
1727: {
1728: SoapError(h, 709, "NoPacketSent");
1729: return;
1730: }
1731: bodylen = snprintf(body, sizeof(body), resp,
1732: action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1733: 1, action);
1734: BuildSendAndCloseSoapResp(h, body, bodylen);
1735: }
1736: else if(r == -2)
1737: SoapError(h, 704, "NoSuchEntry");
1738: else
1739: SoapError(h, 501, "ActionFailed");
1740: }
1741:
1742: static void
1743: GetPinholePackets(struct upnphttp * h, const char * action)
1744: {
1745: static const char resp[] =
1746: "<u:%sResponse "
1747: "xmlns:u=\"%s\">"
1748: "<PinholePackets>%u</PinholePackets>"
1749: "</u:%sResponse>";
1750: char body[512];
1751: int bodylen;
1752: struct NameValueParserData data;
1753: const char * uid_str;
1754: int n;
1755: char iaddr[INET6_ADDRSTRLEN];
1756: unsigned short iport;
1757: unsigned int packets = 0;
1758: int uid;
1759: int proto;
1760: unsigned int leasetime;
1761:
1762: if(CheckStatus(h)==0)
1763: return;
1764:
1765: ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
1766: uid_str = GetValueFromNameValueList(&data, "UniqueID");
1767: uid = uid_str ? atoi(uid_str) : -1;
1768: ClearNameValueList(&data);
1769:
1770: if(uid < 0 || uid > 65535)
1771: {
1772: SoapError(h, 402, "Invalid Args");
1773: return;
1774: }
1775:
1776: /* Check that client is not getting infos of a pinhole
1777: * it doesn't have access to, because of its public access */
1778: n = upnp_get_pinhole_info(uid, NULL, 0, NULL,
1779: iaddr, sizeof(iaddr), &iport,
1780: &proto, &leasetime, &packets);
1781: if (n >= 0)
1782: {
1783: if(PinholeVerification(h, iaddr, iport)<=0)
1784: return ;
1785: }
1786: #if 0
1787: else if(r == -4 || r == -1)
1788: {
1789: SoapError(h, 704, "NoSuchEntry");
1790: }
1791: #endif
1792:
1793: bodylen = snprintf(body, sizeof(body), resp,
1794: action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
1795: packets, action);
1796: BuildSendAndCloseSoapResp(h, body, bodylen);
1797: }
1798: #endif
1799:
1800:
1801: /* Windows XP as client send the following requests :
1802: * GetConnectionTypeInfo
1803: * GetNATRSIPStatus
1804: * ? GetTotalBytesSent - WANCommonInterfaceConfig
1805: * ? GetTotalBytesReceived - idem
1806: * ? GetTotalPacketsSent - idem
1807: * ? GetTotalPacketsReceived - idem
1808: * GetCommonLinkProperties - idem
1809: * GetStatusInfo - WANIPConnection
1810: * GetExternalIPAddress
1811: * QueryStateVariable / ConnectionStatus!
1812: */
1813: static const struct
1814: {
1815: const char * methodName;
1816: void (*methodImpl)(struct upnphttp *, const char *);
1817: }
1818: soapMethods[] =
1819: {
1820: /* WANCommonInterfaceConfig */
1821: { "QueryStateVariable", QueryStateVariable},
1822: { "GetTotalBytesSent", GetTotalBytesSent},
1823: { "GetTotalBytesReceived", GetTotalBytesReceived},
1824: { "GetTotalPacketsSent", GetTotalPacketsSent},
1825: { "GetTotalPacketsReceived", GetTotalPacketsReceived},
1826: { "GetCommonLinkProperties", GetCommonLinkProperties},
1827: { "GetStatusInfo", GetStatusInfo},
1828: /* WANIPConnection */
1829: { "GetConnectionTypeInfo", GetConnectionTypeInfo },
1830: { "GetNATRSIPStatus", GetNATRSIPStatus},
1831: { "GetExternalIPAddress", GetExternalIPAddress},
1832: { "AddPortMapping", AddPortMapping},
1833: { "DeletePortMapping", DeletePortMapping},
1834: { "GetGenericPortMappingEntry", GetGenericPortMappingEntry},
1835: { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry},
1836: /* Required in WANIPConnection:2 */
1837: { "SetConnectionType", SetConnectionType},
1838: { "RequestConnection", RequestConnection},
1839: { "ForceTermination", ForceTermination},
1840: { "AddAnyPortMapping", AddAnyPortMapping},
1841: { "DeletePortMappingRange", DeletePortMappingRange},
1842: { "GetListOfPortMappings", GetListOfPortMappings},
1843: #ifdef ENABLE_L3F_SERVICE
1844: /* Layer3Forwarding */
1845: { "SetDefaultConnectionService", SetDefaultConnectionService},
1846: { "GetDefaultConnectionService", GetDefaultConnectionService},
1847: #endif
1848: #ifdef ENABLE_6FC_SERVICE
1849: /* WANIPv6FirewallControl */
1850: { "GetFirewallStatus", GetFirewallStatus}, /* Required */
1851: { "AddPinhole", AddPinhole}, /* Required */
1852: { "UpdatePinhole", UpdatePinhole}, /* Required */
1853: { "GetOutboundPinholeTimeout", GetOutboundPinholeTimeout}, /* Optional */
1854: { "DeletePinhole", DeletePinhole}, /* Required */
1855: { "CheckPinholeWorking", CheckPinholeWorking}, /* Optional */
1856: { "GetPinholePackets", GetPinholePackets}, /* Required */
1857: #endif
1858: { 0, 0 }
1859: };
1860:
1861: void
1862: ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
1863: {
1864: char * p;
1865: char * p2;
1866: int i, len, methodlen;
1867:
1868: i = 0;
1869: p = strchr(action, '#');
1870:
1871: if(p)
1872: {
1873: p++;
1874: p2 = strchr(p, '"');
1875: if(p2)
1876: methodlen = p2 - p;
1877: else
1878: methodlen = n - (p - action);
1879: /*syslog(LOG_DEBUG, "SoapMethod: %.*s", methodlen, p);*/
1880: while(soapMethods[i].methodName)
1881: {
1882: len = strlen(soapMethods[i].methodName);
1883: if(strncmp(p, soapMethods[i].methodName, len) == 0)
1884: {
1885: soapMethods[i].methodImpl(h, soapMethods[i].methodName);
1886: return;
1887: }
1888: i++;
1889: }
1890:
1891: syslog(LOG_NOTICE, "SoapMethod: Unknown: %.*s", methodlen, p);
1892: }
1893:
1894: SoapError(h, 401, "Invalid Action");
1895: }
1896:
1897: /* Standard Errors:
1898: *
1899: * errorCode errorDescription Description
1900: * -------- ---------------- -----------
1901: * 401 Invalid Action No action by that name at this service.
1902: * 402 Invalid Args Could be any of the following: not enough in args,
1903: * too many in args, no in arg by that name,
1904: * one or more in args are of the wrong data type.
1905: * 403 Out of Sync Out of synchronization.
1906: * 501 Action Failed May be returned in current state of service
1907: * prevents invoking that action.
1908: * 600-699 TBD Common action errors. Defined by UPnP Forum
1909: * Technical Committee.
1910: * 700-799 TBD Action-specific errors for standard actions.
1911: * Defined by UPnP Forum working committee.
1912: * 800-899 TBD Action-specific errors for non-standard actions.
1913: * Defined by UPnP vendor.
1914: */
1915: void
1916: SoapError(struct upnphttp * h, int errCode, const char * errDesc)
1917: {
1918: static const char resp[] =
1919: "<s:Envelope "
1920: "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
1921: "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
1922: "<s:Body>"
1923: "<s:Fault>"
1924: "<faultcode>s:Client</faultcode>"
1925: "<faultstring>UPnPError</faultstring>"
1926: "<detail>"
1927: "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">"
1928: "<errorCode>%d</errorCode>"
1929: "<errorDescription>%s</errorDescription>"
1930: "</UPnPError>"
1931: "</detail>"
1932: "</s:Fault>"
1933: "</s:Body>"
1934: "</s:Envelope>";
1935:
1936: char body[2048];
1937: int bodylen;
1938:
1939: syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc);
1940: bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc);
1941: BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen);
1942: SendRespAndClose_upnphttp(h);
1943: }
1944:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>