File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / upnpsoap.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 00:32:35 2013 UTC (10 years, 11 months ago) by misho
Branches: miniupnpd, elwix, MAIN
CVS tags: v1_8p0, v1_8, HEAD
1.8

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>