File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / upnpsoap.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:55:57 2012 UTC (12 years, 2 months ago) by misho
Branches: miniupnpd, elwix, MAIN
CVS tags: v1_6elwix, HEAD
miniupnpd 1.6+patches

    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>