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