1: /* $Id: upnpsoap.c,v 1.1.1.2 2012/05/29 12:55:57 misho Exp $ */
2: /* MiniUPnP project
3: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4: * (c) 2006-2011 Thomas Bernard
5: * This software is subject to the conditions detailed
6: * in the LICENCE file provided within the distribution */
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"
27: #include "getconnstatus.h"
28: #include "upnpurns.h"
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 "
65: "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
66: "<NewConnectionType>IP_Routed</NewConnectionType>"
67: "<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
68: "</u:GetConnectionTypeInfoResponse>";
69: BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
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;
214: const char * status;
215: /* ConnectionStatus possible values :
216: * Unconfigured, Connecting, Connected, PendingDisconnect,
217: * Disconnecting, Disconnected */
218:
219: status = get_wan_connection_status_str(ext_if_name);
220: uptime = (time(NULL) - startup_time);
221: bodylen = snprintf(body, sizeof(body), resp,
222: action, SERVICE_TYPE_WANIPC,
223: status, (long)uptime, action);
224: BuildSendAndCloseSoapResp(h, body, bodylen);
225: }
226:
227: static void
228: GetNATRSIPStatus(struct upnphttp * h, const char * action)
229: {
230: static const char resp[] =
231: "<u:GetNATRSIPStatusResponse "
232: "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
233: "<NewRSIPAvailable>0</NewRSIPAvailable>"
234: "<NewNATEnabled>1</NewNATEnabled>"
235: "</u:GetNATRSIPStatusResponse>";
236: /* 2.2.9. RSIPAvailable
237: * This variable indicates if Realm-specific IP (RSIP) is available
238: * as a feature on the InternetGatewayDevice. RSIP is being defined
239: * in the NAT working group in the IETF to allow host-NATing using
240: * a standard set of message exchanges. It also allows end-to-end
241: * applications that otherwise break if NAT is introduced
242: * (e.g. IPsec-based VPNs).
243: * A gateway that does not support RSIP should set this variable to 0. */
244: BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
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];
259: /* Does that method need to work with IPv6 ?
260: * There is usually no NAT with IPv6 */
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
274: struct lan_addr_s * lan_addr;
275: strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN);
276: for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
277: {
278: if( (h->clientaddr.s_addr & lan_addr->mask.s_addr)
279: == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
280: {
281: strncpy(ext_ip_addr, lan_addr->ext_ip_str, INET_ADDRSTRLEN);
282: break;
283: }
284: }
285: #endif
286: bodylen = snprintf(body, sizeof(body), resp,
287: action, SERVICE_TYPE_WANIPC,
288: ext_ip_addr, action);
289: BuildSendAndCloseSoapResp(h, body, bodylen);
290: }
291:
292: /* AddPortMapping method of WANIPConnection Service
293: * Ignored argument : NewEnabled */
294: static void
295: AddPortMapping(struct upnphttp * h, const char * action)
296: {
297: int r;
298:
299: static const char resp[] =
300: "<u:AddPortMappingResponse "
301: "xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";
302:
303: struct NameValueParserData data;
304: char * int_ip, * int_port, * ext_port, * protocol, * desc;
305: char * leaseduration_str;
306: unsigned int leaseduration;
307: char * r_host;
308: unsigned short iport, eport;
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:
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:
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");
377: leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
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:
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
402:
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);
405:
406: r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
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
416: * 724 - SamePortValuesRequired (deprecated in IGD v2)
417: * 725 - OnlyPermanentLeasesSupported
418: The NAT implementation only supports permanent lease times on
419: port mappings (deprecated in IGD v2)
420: * 726 - RemoteHostOnlySupportsWildcard
421: RemoteHost must be a wildcard and cannot be a specific IP
422: address or DNS name (deprecated in IGD v2)
423: * 727 - ExternalPortOnlySupportsWildcard
424: ExternalPort must be a wildcard and cannot be a specific port
425: value (deprecated in IGD v2)
426: * 728 - NoPortMapsAvailable
427: There are not enough free prots available to complete the mapping
428: (added in IGD v2)
429: * 729 - ConflictWithOtherMechanisms (added in IGD v2) */
430: switch(r)
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;
462: const char * leaseduration_str;
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");
477: leaseduration_str = GetValueFromNameValueList(&data, "NewLeaseDuration");
478:
479: leaseduration = leaseduration_str ? atoi(leaseduration_str) : 0;
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: }
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
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:
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: }
549:
550: ClearNameValueList(&data);
551:
552: switch(r)
553: {
554: case 0: /* success */
555: bodylen = snprintf(body, sizeof(body), resp,
556: action, SERVICE_TYPE_WANIPC,
557: eport, action);
558: BuildSendAndCloseSoapResp(h, body, bodylen);
559: break;
560: case -2: /* already redirected */
561: SoapError(h, 718, "ConflictInMappingEntry");
562: break;
563: case -3: /* not permitted */
564: SoapError(h, 606, "Action not authorized");
565: break;
566: default:
567: SoapError(h, 501, "ActionFailed");
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>"
583: "<NewLeaseDuration>%u</NewLeaseDuration>"
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];
593: unsigned int leaseduration = 0;
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: }
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
616:
617: eport = (unsigned short)atoi(ext_port);
618:
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. */
623: r = upnp_get_redirection_infos(eport, protocol, &iport,
624: int_ip, sizeof(int_ip),
625: desc, sizeof(desc),
626: NULL, 0,
627: &leaseduration);
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,
639: action, SERVICE_TYPE_WANIPC,
640: (unsigned int)iport, int_ip, desc, leaseduration,
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 "
655: "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
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: }
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
683:
684: eport = (unsigned short)atoi(ext_port);
685:
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. */
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: {
712: int r = -1;
713: static const char resp[] =
714: "<u:DeletePortMappingRangeResponse "
715: "xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
716: "</u:DeletePortMappingRangeResponse>";
717: struct NameValueParserData data;
718: const char * protocol;
719: unsigned short startport, endport;
720: int manage;
721: unsigned short * port_list;
722: unsigned int i, number = 0;
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: */
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);
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\">"
763: "<NewRemoteHost>%s</NewRemoteHost>"
764: "<NewExternalPort>%u</NewExternalPort>"
765: "<NewProtocol>%s</NewProtocol>"
766: "<NewInternalPort>%u</NewInternalPort>"
767: "<NewInternalClient>%s</NewInternalClient>"
768: "<NewEnabled>1</NewEnabled>"
769: "<NewPortMappingDescription>%s</NewPortMappingDescription>"
770: "<NewLeaseDuration>%u</NewLeaseDuration>"
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];
778: char rhost[40];
779: unsigned int leaseduration = 0;
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:
796: rhost[0] = '\0';
797: r = upnp_get_redirection_infos_by_index(index, &eport, protocol, &iport,
798: iaddr, sizeof(iaddr),
799: desc, sizeof(desc),
800: rhost, sizeof(rhost),
801: &leaseduration);
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,
812: action, SERVICE_TYPE_WANIPC, rhost,
813: (unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc,
814: leaseduration, action);
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: {
825: static const char resp_start[] =
826: "<u:%sResponse "
827: "xmlns:u=\"%s\">"
828: "<NewPortListing><![CDATA[";
829: static const char resp_end[] =
830: "]]></NewPortListing>"
831: "</u:%sResponse>";
832:
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;
855: int bodylen;
856:
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:
864: struct NameValueParserData data;
865: unsigned short startport, endport;
866: const char * protocol;
867: int manage;
868: int number;
869: unsigned short * port_list;
870: unsigned int i, list_size = 0;
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"));
878: if(number == 0) number = 1000; /* return up to 1000 mappings by default */
879:
880: if(startport > endport)
881: {
882: SoapError(h, 733, "InconsistentParameter");
883: ClearNameValueList(&data);
884: return;
885: }
886: /*
887: build the PortMappingList xml document :
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: */
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);
957: BuildSendAndCloseSoapResp(h, body, bodylen);
958: free(body);
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,"
989: SERVICE_ID_WANIPC "</NewDefaultConnectionService>"
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: {
1067: const char * status;
1068:
1069: status = get_wan_connection_status_str(ext_if_name);
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:
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:
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: {
1745: /* WANCommonInterfaceConfig */
1746: { "QueryStateVariable", QueryStateVariable},
1747: { "GetTotalBytesSent", GetTotalBytesSent},
1748: { "GetTotalBytesReceived", GetTotalBytesReceived},
1749: { "GetTotalPacketsSent", GetTotalPacketsSent},
1750: { "GetTotalPacketsReceived", GetTotalPacketsReceived},
1751: { "GetCommonLinkProperties", GetCommonLinkProperties},
1752: { "GetStatusInfo", GetStatusInfo},
1753: /* WANIPConnection */
1754: { "GetConnectionTypeInfo", GetConnectionTypeInfo },
1755: { "GetNATRSIPStatus", GetNATRSIPStatus},
1756: { "GetExternalIPAddress", GetExternalIPAddress},
1757: { "AddPortMapping", AddPortMapping},
1758: { "DeletePortMapping", DeletePortMapping},
1759: { "GetGenericPortMappingEntry", GetGenericPortMappingEntry},
1760: { "GetSpecificPortMappingEntry", GetSpecificPortMappingEntry},
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
1769: /* Layer3Forwarding */
1770: { "SetDefaultConnectionService", SetDefaultConnectionService},
1771: { "GetDefaultConnectionService", GetDefaultConnectionService},
1772: #endif
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
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>