File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpc / src / upnpc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:21:37 2023 UTC (9 months, 1 week ago) by misho
Branches: miniupnpc, MAIN
CVS tags: v2_2_5p0, HEAD
Version 2.2.5p0

    1: /* $Id: upnpc.c,v 1.1.1.1 2023/09/27 11:21:37 misho Exp $ */
    2: /* Project : miniupnp
    3:  * Author : Thomas Bernard
    4:  * Copyright (c) 2005-2023 Thomas Bernard
    5:  * This software is subject to the conditions detailed in the
    6:  * LICENCE file provided in this distribution. */
    7: 
    8: #include <stdio.h>
    9: #include <stdlib.h>
   10: #include <string.h>
   11: #include <time.h>
   12: #ifdef _WIN32
   13: #include <winsock2.h>
   14: #include "win32_snprintf.h"
   15: #else
   16: /* for IPPROTO_TCP / IPPROTO_UDP */
   17: #include <netinet/in.h>
   18: #endif
   19: #include <ctype.h>
   20: #include "miniwget.h"
   21: #include "miniupnpc.h"
   22: #include "upnpcommands.h"
   23: #include "portlistingparse.h"
   24: #include "upnperrors.h"
   25: #include "miniupnpcstrings.h"
   26: 
   27: /* protofix() checks if protocol is "UDP" or "TCP"
   28:  * returns NULL if not */
   29: const char * protofix(const char * proto)
   30: {
   31: 	static const char proto_tcp[4] = { 'T', 'C', 'P', 0};
   32: 	static const char proto_udp[4] = { 'U', 'D', 'P', 0};
   33: 	int i, b;
   34: 	for(i=0, b=1; i<4; i++)
   35: 		b = b && (   (proto[i] == proto_tcp[i])
   36: 		          || (proto[i] == (proto_tcp[i] | 32)) );
   37: 	if(b)
   38: 		return proto_tcp;
   39: 	for(i=0, b=1; i<4; i++)
   40: 		b = b && (   (proto[i] == proto_udp[i])
   41: 		          || (proto[i] == (proto_udp[i] | 32)) );
   42: 	if(b)
   43: 		return proto_udp;
   44: 	return 0;
   45: }
   46: 
   47: /* is_int() checks if parameter is an integer or not
   48:  * 1 for integer
   49:  * 0 for not an integer */
   50: int is_int(char const* s)
   51: {
   52: 	if(s == NULL)
   53: 		return 0;
   54: 	while(*s) {
   55: 		/* #define isdigit(c) ((c) >= '0' && (c) <= '9') */
   56: 		if(!isdigit(*s))
   57: 			return 0;
   58: 		s++;
   59: 	}
   60: 	return 1;
   61: }
   62: 
   63: static void DisplayInfos(struct UPNPUrls * urls,
   64:                          struct IGDdatas * data)
   65: {
   66: 	char externalIPAddress[40];
   67: 	char connectionType[64];
   68: 	char status[64];
   69: 	char lastconnerr[64];
   70: 	unsigned int uptime = 0;
   71: 	unsigned int brUp, brDown;
   72: 	time_t timenow, timestarted;
   73: 	int r;
   74: 	if(UPNP_GetConnectionTypeInfo(urls->controlURL,
   75: 	                              data->first.servicetype,
   76: 	                              connectionType) != UPNPCOMMAND_SUCCESS)
   77: 		printf("GetConnectionTypeInfo failed.\n");
   78: 	else
   79: 		printf("Connection Type : %s\n", connectionType);
   80: 	if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
   81: 	                      status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS)
   82: 		printf("GetStatusInfo failed.\n");
   83: 	else
   84: 		printf("Status : %s, uptime=%us, LastConnectionError : %s\n",
   85: 		       status, uptime, lastconnerr);
   86: 	if(uptime > 0) {
   87: 		timenow = time(NULL);
   88: 		timestarted = timenow - uptime;
   89: 		printf("  Time started : %s", ctime(&timestarted));
   90: 	}
   91: 	if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype,
   92: 	                                &brDown, &brUp) != UPNPCOMMAND_SUCCESS) {
   93: 		printf("GetLinkLayerMaxBitRates failed.\n");
   94: 	} else {
   95: 		printf("MaxBitRateDown : %u bps", brDown);
   96: 		if(brDown >= 1000000) {
   97: 			printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10);
   98: 		} else if(brDown >= 1000) {
   99: 			printf(" (%u Kbps)", brDown / 1000);
  100: 		}
  101: 		printf("   MaxBitRateUp %u bps", brUp);
  102: 		if(brUp >= 1000000) {
  103: 			printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10);
  104: 		} else if(brUp >= 1000) {
  105: 			printf(" (%u Kbps)", brUp / 1000);
  106: 		}
  107: 		printf("\n");
  108: 	}
  109: 	r = UPNP_GetExternalIPAddress(urls->controlURL,
  110: 	                          data->first.servicetype,
  111: 							  externalIPAddress);
  112: 	if(r != UPNPCOMMAND_SUCCESS) {
  113: 		printf("GetExternalIPAddress failed. (errorcode=%d)\n", r);
  114: 	} else if(!externalIPAddress[0]) {
  115: 		printf("GetExternalIPAddress failed. (empty string)\n");
  116: 	} else {
  117: 		printf("ExternalIPAddress = %s\n", externalIPAddress);
  118: 	}
  119: }
  120: 
  121: static void GetConnectionStatus(struct UPNPUrls * urls,
  122:                                struct IGDdatas * data)
  123: {
  124: 	unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
  125: 	DisplayInfos(urls, data);
  126: 	bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
  127: 	bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
  128: 	packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
  129: 	packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
  130: 	printf("Bytes:   Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
  131: 	printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
  132: }
  133: 
  134: static void ListRedirections(struct UPNPUrls * urls,
  135:                              struct IGDdatas * data)
  136: {
  137: 	int r;
  138: 	unsigned short i = 0;
  139: 	char index[6];
  140: 	char intClient[40];
  141: 	char intPort[6];
  142: 	char extPort[6];
  143: 	char protocol[4];
  144: 	char desc[80];
  145: 	char enabled[6];
  146: 	char rHost[64];
  147: 	char duration[16];
  148: 	/*unsigned int num=0;
  149: 	UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num);
  150: 	printf("PortMappingNumberOfEntries : %u\n", num);*/
  151: 	printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
  152: 	do {
  153: 		snprintf(index, 6, "%hu", i);
  154: 		rHost[0] = '\0'; enabled[0] = '\0';
  155: 		duration[0] = '\0'; desc[0] = '\0';
  156: 		extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
  157: 		r = UPNP_GetGenericPortMappingEntry(urls->controlURL,
  158: 		                               data->first.servicetype,
  159: 		                               index,
  160: 		                               extPort, intClient, intPort,
  161: 									   protocol, desc, enabled,
  162: 									   rHost, duration);
  163: 		if(r==0)
  164: 		/*
  165: 			printf("%02hu - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n"
  166: 			       "     desc='%s' rHost='%s'\n",
  167: 			       i, protocol, extPort, intClient, intPort,
  168: 				   enabled, duration,
  169: 				   desc, rHost);
  170: 				   */
  171: 			printf("%2hu %s %5s->%s:%-5s '%s' '%s' %s\n",
  172: 			       i, protocol, extPort, intClient, intPort,
  173: 			       desc, rHost, duration);
  174: 		else
  175: 			printf("GetGenericPortMappingEntry() returned %d (%s)\n",
  176: 			       r, strupnperror(r));
  177: 	} while(r == 0 && i++ < 65535);
  178: }
  179: 
  180: static void NewListRedirections(struct UPNPUrls * urls,
  181:                                 struct IGDdatas * data)
  182: {
  183: 	int r;
  184: 	int i = 0;
  185: 	struct PortMappingParserData pdata;
  186: 	struct PortMapping * pm;
  187: 
  188: 	memset(&pdata, 0, sizeof(struct PortMappingParserData));
  189: 	r = UPNP_GetListOfPortMappings(urls->controlURL,
  190:                                    data->first.servicetype,
  191: 	                               "1",
  192: 	                               "65535",
  193: 	                               "TCP",
  194: 	                               "1000",
  195: 	                               &pdata);
  196: 	if(r == UPNPCOMMAND_SUCCESS)
  197: 	{
  198: 		printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
  199: 		for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
  200: 		{
  201: 			printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
  202: 			       i, pm->protocol, pm->externalPort, pm->internalClient,
  203: 			       pm->internalPort,
  204: 			       pm->description, pm->remoteHost,
  205: 			       (unsigned)pm->leaseTime);
  206: 			i++;
  207: 		}
  208: 		FreePortListing(&pdata);
  209: 	}
  210: 	else
  211: 	{
  212: 		printf("GetListOfPortMappings() returned %d (%s)\n",
  213: 		       r, strupnperror(r));
  214: 	}
  215: 	r = UPNP_GetListOfPortMappings(urls->controlURL,
  216:                                    data->first.servicetype,
  217: 	                               "1",
  218: 	                               "65535",
  219: 	                               "UDP",
  220: 	                               "1000",
  221: 	                               &pdata);
  222: 	if(r == UPNPCOMMAND_SUCCESS)
  223: 	{
  224: 		for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
  225: 		{
  226: 			printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
  227: 			       i, pm->protocol, pm->externalPort, pm->internalClient,
  228: 			       pm->internalPort,
  229: 			       pm->description, pm->remoteHost,
  230: 			       (unsigned)pm->leaseTime);
  231: 			i++;
  232: 		}
  233: 		FreePortListing(&pdata);
  234: 	}
  235: 	else
  236: 	{
  237: 		printf("GetListOfPortMappings() returned %d (%s)\n",
  238: 		       r, strupnperror(r));
  239: 	}
  240: }
  241: 
  242: /* Test function
  243:  * 1 - get connection type
  244:  * 2 - get extenal ip address
  245:  * 3 - Add port mapping
  246:  * 4 - get this port mapping from the IGD */
  247: static int SetRedirectAndTest(struct UPNPUrls * urls,
  248: 			       struct IGDdatas * data,
  249: 			       const char * iaddr,
  250: 			       const char * iport,
  251: 			       const char * eport,
  252: 			       const char * proto,
  253: 			       const char * leaseDuration,
  254: 			       const char * remoteHost,
  255: 			       const char * description,
  256: 			       int addAny)
  257: {
  258: 	char externalIPAddress[40];
  259: 	char intClient[40];
  260: 	char intPort[6];
  261: 	char reservedPort[6];
  262: 	char duration[16];
  263: 	int r;
  264: 
  265: 	if(!iaddr || !iport || !eport || !proto)
  266: 	{
  267: 		fprintf(stderr, "Wrong arguments\n");
  268: 		return -1;
  269: 	}
  270: 	proto = protofix(proto);
  271: 	if(!proto)
  272: 	{
  273: 		fprintf(stderr, "invalid protocol\n");
  274: 		return -1;
  275: 	}
  276: 
  277: 	r = UPNP_GetExternalIPAddress(urls->controlURL,
  278: 				      data->first.servicetype,
  279: 				      externalIPAddress);
  280: 	if(r!=UPNPCOMMAND_SUCCESS)
  281: 		printf("GetExternalIPAddress failed.\n");
  282: 	else
  283: 		printf("ExternalIPAddress = %s\n", externalIPAddress);
  284: 
  285: 	if (addAny) {
  286: 		r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype,
  287: 					   eport, iport, iaddr, description,
  288: 					   proto, remoteHost, leaseDuration, reservedPort);
  289: 		if(r==UPNPCOMMAND_SUCCESS)
  290: 			eport = reservedPort;
  291: 		else
  292: 			printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n",
  293: 			       eport, iport, iaddr, r, strupnperror(r));
  294: 	} else {
  295: 		r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype,
  296: 					eport, iport, iaddr, description,
  297: 					proto, remoteHost, leaseDuration);
  298: 		if(r!=UPNPCOMMAND_SUCCESS) {
  299: 			printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
  300: 			       eport, iport, iaddr, r, strupnperror(r));
  301: 			return -2;
  302: 	}
  303: 	}
  304: 
  305: 	r = UPNP_GetSpecificPortMappingEntry(urls->controlURL,
  306: 					     data->first.servicetype,
  307: 					     eport, proto, remoteHost,
  308: 					     intClient, intPort, NULL/*desc*/,
  309: 					     NULL/*enabled*/, duration);
  310: 	if(r!=UPNPCOMMAND_SUCCESS) {
  311: 		printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n",
  312: 		       r, strupnperror(r));
  313: 		return -2;
  314: 	} else {
  315: 		printf("InternalIP:Port = %s:%s\n", intClient, intPort);
  316: 		printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n",
  317: 		       externalIPAddress, eport, proto, intClient, intPort, duration);
  318: 	}
  319: 	return 0;
  320: }
  321: 
  322: static int
  323: RemoveRedirect(struct UPNPUrls * urls,
  324:                struct IGDdatas * data,
  325:                const char * eport,
  326:                const char * proto,
  327:                const char * remoteHost)
  328: {
  329: 	int r;
  330: 	if(!proto || !eport)
  331: 	{
  332: 		fprintf(stderr, "invalid arguments\n");
  333: 		return -1;
  334: 	}
  335: 	proto = protofix(proto);
  336: 	if(!proto)
  337: 	{
  338: 		fprintf(stderr, "protocol invalid\n");
  339: 		return -1;
  340: 	}
  341: 	r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, remoteHost);
  342: 	if(r!=UPNPCOMMAND_SUCCESS) {
  343: 		printf("UPNP_DeletePortMapping() failed with code : %d\n", r);
  344: 		return -2;
  345: 	}else {
  346: 		printf("UPNP_DeletePortMapping() returned : %d\n", r);
  347: 	}
  348: 	return 0;
  349: }
  350: 
  351: static int
  352: RemoveRedirectRange(struct UPNPUrls * urls,
  353: 		    struct IGDdatas * data,
  354: 		    const char * ePortStart, char const * ePortEnd,
  355: 		    const char * proto, const char * manage)
  356: {
  357: 	int r;
  358: 
  359: 	if (!manage)
  360: 		manage = "0";
  361: 
  362: 	if(!proto || !ePortStart || !ePortEnd)
  363: 	{
  364: 		fprintf(stderr, "invalid arguments\n");
  365: 		return -1;
  366: 	}
  367: 	proto = protofix(proto);
  368: 	if(!proto)
  369: 	{
  370: 		fprintf(stderr, "protocol invalid\n");
  371: 		return -1;
  372: 	}
  373: 	r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage);
  374: 	if(r!=UPNPCOMMAND_SUCCESS) {
  375: 		printf("UPNP_DeletePortMappingRange() failed with code : %d\n", r);
  376: 		return -2;
  377: 	}else {
  378: 		printf("UPNP_DeletePortMappingRange() returned : %d\n", r);
  379: 	}
  380: 	return 0;
  381: }
  382: 
  383: /* IGD:2, functions for service WANIPv6FirewallControl:1 */
  384: static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data)
  385: {
  386: 	unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
  387: 	int firewallEnabled = 0, inboundPinholeAllowed = 0;
  388: 
  389: 	UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed);
  390: 	printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed);
  391: 	printf("GetFirewallStatus:\n   Firewall Enabled: %s\n   Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No");
  392: 
  393: 	bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
  394: 	bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
  395: 	packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
  396: 	packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
  397: 	printf("Bytes:   Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
  398: 	printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
  399: }
  400: 
  401: /* Test function
  402:  * 1 - Add pinhole
  403:  * 2 - Check if pinhole is working from the IGD side */
  404: static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data,
  405: 					const char * remoteaddr, const char * eport,
  406: 					const char * intaddr, const char * iport,
  407: 					const char * proto, const char * lease_time)
  408: {
  409: 	char uniqueID[8];
  410: 	/*int isWorking = 0;*/
  411: 	int r;
  412: 	char proto_tmp[8];
  413: 
  414: 	if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time)
  415: 	{
  416: 		fprintf(stderr, "Wrong arguments\n");
  417: 		return;
  418: 	}
  419: 	if(atoi(proto) == 0)
  420: 	{
  421: 		const char * protocol;
  422: 		protocol = protofix(proto);
  423: 		if(protocol && (strcmp("TCP", protocol) == 0))
  424: 		{
  425: 			snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP);
  426: 			proto = proto_tmp;
  427: 		}
  428: 		else if(protocol && (strcmp("UDP", protocol) == 0))
  429: 		{
  430: 			snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP);
  431: 			proto = proto_tmp;
  432: 		}
  433: 		else
  434: 		{
  435: 			fprintf(stderr, "invalid protocol\n");
  436: 			return;
  437: 		}
  438: 	}
  439: 	r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID);
  440: 	if(r!=UPNPCOMMAND_SUCCESS)
  441: 		printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
  442: 		       remoteaddr, eport, intaddr, iport, r, strupnperror(r));
  443: 	else
  444: 	{
  445: 		printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n",
  446: 		       remoteaddr, eport, intaddr, iport, uniqueID);
  447: 		/*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking);
  448: 		if(r!=UPNPCOMMAND_SUCCESS)
  449: 			printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
  450: 		printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/
  451: 	}
  452: }
  453: 
  454: /* Test function
  455:  * 1 - Check if pinhole is working from the IGD side
  456:  * 2 - Update pinhole */
  457: static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data,
  458: 					const char * uniqueID, const char * lease_time)
  459: {
  460: 	int isWorking = 0;
  461: 	int r;
  462: 
  463: 	if(!uniqueID || !lease_time)
  464: 	{
  465: 		fprintf(stderr, "Wrong arguments\n");
  466: 		return;
  467: 	}
  468: 	/* CheckPinholeWorking is an Optional Action, error 602 should be
  469: 	 * returned if it is not implemented */
  470: 	r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
  471: 	if(r==UPNPCOMMAND_SUCCESS)
  472: 		printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
  473: 	else
  474: 		printf("CheckPinholeWorking(%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r));
  475: 	/* 702 FirewallDisabled Firewall is disabled and this action is disabled
  476: 	 * 703 InboundPinholeNotAllowed Creation of inbound pinholes by UPnP CPs
  477: 	 *                              are not allowed and this action is disabled
  478: 	 * 704 NoSuchEntry There is no pinhole with the specified UniqueID.
  479: 	 * 709 NoTrafficReceived No traffic corresponding to this pinhole has
  480: 	 *                       been received by the gateway. */
  481: 	if(isWorking || (r!=702 && r!=703 && r!=704))
  482: 	{
  483: 		r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time);
  484: 		printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time);
  485: 		if(r!=UPNPCOMMAND_SUCCESS)
  486: 			printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r));
  487: 	}
  488: }
  489: 
  490: /* Test function
  491:  * Get pinhole timeout
  492:  */
  493: static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data,
  494: 					const char * remoteaddr, const char * eport,
  495: 					const char * intaddr, const char * iport,
  496: 					const char * proto)
  497: {
  498: 	int timeout = 0;
  499: 	int r;
  500: 
  501: 	if(!intaddr || !remoteaddr || !iport || !eport || !proto)
  502: 	{
  503: 		fprintf(stderr, "Wrong arguments\n");
  504: 		return;
  505: 	}
  506: 
  507: 	r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout);
  508: 	if(r!=UPNPCOMMAND_SUCCESS)
  509: 		printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
  510: 		       intaddr, iport, remoteaddr, eport, r, strupnperror(r));
  511: 	else
  512: 		printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout);
  513: }
  514: 
  515: static void
  516: GetPinholePackets(struct UPNPUrls * urls,
  517:                struct IGDdatas * data, const char * uniqueID)
  518: {
  519: 	int r, pinholePackets = 0;
  520: 	if(!uniqueID)
  521: 	{
  522: 		fprintf(stderr, "invalid arguments\n");
  523: 		return;
  524: 	}
  525: 	r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets);
  526: 	if(r!=UPNPCOMMAND_SUCCESS)
  527: 		printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r));
  528: 	else
  529: 		printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets);
  530: }
  531: 
  532: static void
  533: CheckPinhole(struct UPNPUrls * urls,
  534:                struct IGDdatas * data, const char * uniqueID)
  535: {
  536: 	int r, isWorking = 0;
  537: 	if(!uniqueID)
  538: 	{
  539: 		fprintf(stderr, "invalid arguments\n");
  540: 		return;
  541: 	}
  542: 	r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
  543: 	if(r!=UPNPCOMMAND_SUCCESS)
  544: 		printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
  545: 	else
  546: 		printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
  547: }
  548: 
  549: static void
  550: RemovePinhole(struct UPNPUrls * urls,
  551:                struct IGDdatas * data, const char * uniqueID)
  552: {
  553: 	int r;
  554: 	if(!uniqueID)
  555: 	{
  556: 		fprintf(stderr, "invalid arguments\n");
  557: 		return;
  558: 	}
  559: 	r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID);
  560: 	printf("UPNP_DeletePinhole() returned : %d\n", r);
  561: }
  562: 
  563: 
  564: /* sample upnp client program */
  565: int main(int argc, char ** argv)
  566: {
  567: 	char command = 0;
  568: 	char ** commandargv = 0;
  569: 	int commandargc = 0;
  570: 	struct UPNPDev * devlist = 0;
  571: 	char lanaddr[64] = "unset";	/* my ip address on the LAN */
  572: 	int i;
  573: 	const char * rootdescurl = 0;
  574: 	const char * multicastif = 0;
  575: 	const char * minissdpdpath = 0;
  576: 	int localport = UPNP_LOCAL_PORT_ANY;
  577: 	int retcode = 0;
  578: 	int error = 0;
  579: 	int ipv6 = 0;
  580: 	int ignore = 0;
  581: 	unsigned char ttl = 2;	/* defaulting to 2 */
  582: 	const char * description = 0;
  583: 
  584: #ifdef _WIN32
  585: 	WSADATA wsaData;
  586: 	int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
  587: 	if(nResult != NO_ERROR)
  588: 	{
  589: 		fprintf(stderr, "WSAStartup() failed.\n");
  590: 		return -1;
  591: 	}
  592: #endif
  593:     printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
  594: 	printf(" (c) 2005-2023 Thomas Bernard.\n");
  595:     printf("Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/\n"
  596: 	       "for more information.\n");
  597: 	/* command line processing */
  598: 	for(i=1; i<argc; i++)
  599: 	{
  600: 		if(0 == strcmp(argv[i], "--help") || 0 == strcmp(argv[i], "-h"))
  601: 		{
  602: 			command = 0;
  603: 			break;
  604: 		}
  605: 		if(argv[i][0] == '-')
  606: 		{
  607: 			if(argv[i][1] == 'u')
  608: 				rootdescurl = argv[++i];
  609: 			else if(argv[i][1] == 'm')
  610: 			{
  611: 				multicastif = argv[++i];
  612: 				minissdpdpath = "";	/* Disable usage of minissdpd */
  613: 			}
  614: 			else if(argv[i][1] == 'z')
  615: 			{
  616: 				char junk;
  617: 				if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 ||
  618: 					localport<0 || localport>65535 ||
  619: 				   (localport >1 && localport < 1024))
  620: 				{
  621: 					fprintf(stderr, "Invalid localport '%s'\n", argv[i]);
  622: 					localport = UPNP_LOCAL_PORT_ANY;
  623: 					break;
  624: 				}
  625: 			}
  626: 			else if(argv[i][1] == 'p')
  627: 				minissdpdpath = argv[++i];
  628: 			else if(argv[i][1] == '6')
  629: 				ipv6 = 1;
  630: 			else if(argv[i][1] == 'e')
  631: 				description = argv[++i];
  632: 			else if(argv[i][1] == 't')
  633: 				ttl = (unsigned char)atoi(argv[++i]);
  634: 			else if(argv[i][1] == 'i')
  635: 				ignore = 1;
  636: 			else
  637: 			{
  638: 				command = argv[i][1];
  639: 				i++;
  640: 				commandargv = argv + i;
  641: 				commandargc = argc - i;
  642: 				break;
  643: 			}
  644: 		}
  645: 		else
  646: 		{
  647: 			fprintf(stderr, "option '%s' invalid\n", argv[i]);
  648: 		}
  649: 	}
  650: 
  651: 	if(!command
  652: 	   || (command == 'a' && commandargc<4)
  653: 	   || (command == 'd' && argc<2)
  654: 	   || (command == 'r' && argc<2)
  655: 	   || (command == 'A' && commandargc<6)
  656: 	   || (command == 'U' && commandargc<2)
  657: 	   || (command == 'D' && commandargc<1))
  658: 	{
  659: 		fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration] [remote host]\n\t\tAdd port redirection\n", argv[0]);
  660: 		fprintf(stderr, "       \t%s [options] -d external_port protocol [remote host]\n\t\tDelete port redirection\n", argv[0]);
  661: 		fprintf(stderr, "       \t%s [options] -s\n\t\tGet Connection status\n", argv[0]);
  662: 		fprintf(stderr, "       \t%s [options] -l\n\t\tList redirections\n", argv[0]);
  663: 		fprintf(stderr, "       \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]);
  664: 		fprintf(stderr, "       \t%s [options] -n ip port external_port protocol [duration] [remote host]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]);
  665: 		fprintf(stderr, "       \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]);
  666: 		fprintf(stderr, "       \t%s [options] -r port1 [external_port1] protocol1 [port2 [external_port2] protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]);
  667: 		fprintf(stderr, "       \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]);
  668: 		fprintf(stderr, "       \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]);
  669: 		fprintf(stderr, "       \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]);
  670: 		fprintf(stderr, "       \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]);
  671: 		fprintf(stderr, "       \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]);
  672: 		fprintf(stderr, "       \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]);
  673: 		fprintf(stderr, "       \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]);
  674: 		fprintf(stderr, "       \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]);
  675: 		fprintf(stderr, "\nprotocol is UDP or TCP\n");
  676: 		fprintf(stderr, "@ can be used in option -a, -n, -A and -G to represent local LAN address.\n");
  677: 		fprintf(stderr, "Options:\n");
  678: 		fprintf(stderr, "  -e description : set description for port mapping.\n");
  679: 		fprintf(stderr, "  -6 : use ip v6 instead of ip v4.\n");
  680: 		fprintf(stderr, "  -u url : bypass discovery process by providing the XML root description url.\n");
  681: 		fprintf(stderr, "  -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n");
  682: 		fprintf(stderr, "  -z localport : SSDP packets local (source) port (1024-65535).\n");
  683: 		fprintf(stderr, "  -p path : use this path for MiniSSDPd socket.\n");
  684: 		fprintf(stderr, "  -t ttl : set multicast TTL. Default value is 2.\n");
  685: 		fprintf(stderr, "  -i : ignore errors and try to use also disconnected IGD or non-IGD device.\n");
  686: 		return 1;
  687: 	}
  688: 
  689: 	if( rootdescurl
  690: 	  || (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
  691: 	                             localport, ipv6, ttl, &error)))
  692: 	{
  693: 		struct UPNPDev * device;
  694: 		struct UPNPUrls urls;
  695: 		struct IGDdatas data;
  696: 		if(devlist)
  697: 		{
  698: 			printf("List of UPNP devices found on the network :\n");
  699: 			for(device = devlist; device; device = device->pNext)
  700: 			{
  701: 				printf(" desc: %s\n st: %s\n\n",
  702: 					   device->descURL, device->st);
  703: 			}
  704: 		}
  705: 		else if(!rootdescurl)
  706: 		{
  707: 			printf("upnpDiscover() error code=%d\n", error);
  708: 		}
  709: 		i = 1;
  710: 		if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr)))
  711: 		  || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))))
  712: 		{
  713: 			switch(i) {
  714: 			case 1:
  715: 				printf("Found valid IGD : %s\n", urls.controlURL);
  716: 				break;
  717: 			case 2:
  718: 				printf("Found a (not connected?) IGD : %s\n", urls.controlURL);
  719: 				if (ignore) printf("Trying to continue anyway\n");
  720: 				break;
  721: 			case 3:
  722: 				printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL);
  723: 				if (ignore) printf("Trying to continue anyway\n");
  724: 				break;
  725: 			default:
  726: 				printf("Found device (igd ?) : %s\n", urls.controlURL);
  727: 				if (ignore) printf("Trying to continue anyway\n");
  728: 			}
  729: 			if(i==1 || ignore) {
  730: 
  731: 			printf("Local LAN ip address : %s\n", lanaddr);
  732: 			#if 0
  733: 			printf("getting \"%s\"\n", urls.ipcondescURL);
  734: 			descXML = miniwget(urls.ipcondescURL, &descXMLsize);
  735: 			if(descXML)
  736: 			{
  737: 				/*fwrite(descXML, 1, descXMLsize, stdout);*/
  738: 				free(descXML); descXML = NULL;
  739: 			}
  740: 			#endif
  741: 
  742: 			/* replace '@' with the local LAN ip address */
  743: 			if ((command == 'a' || command == 'n') && 0 == strcmp(commandargv[0], "@"))
  744: 				commandargv[0] = lanaddr;
  745: 			else if ((command == 'A' || command == 'G') && 0 == strcmp(commandargv[2], "@"))
  746: 				commandargv[2] = lanaddr;
  747: 
  748: 			switch(command)
  749: 			{
  750: 			case 'l':
  751: 				DisplayInfos(&urls, &data);
  752: 				ListRedirections(&urls, &data);
  753: 				break;
  754: 			case 'L':
  755: 				NewListRedirections(&urls, &data);
  756: 				break;
  757: 			case 'a':
  758: 				if (SetRedirectAndTest(&urls, &data,
  759: 						   commandargv[0], commandargv[1],
  760: 						   commandargv[2], commandargv[3],
  761: 						   (commandargc > 4) && is_int(commandargv[4]) ? commandargv[4] : "0",
  762: 						   (commandargc > 4) && !is_int(commandargv[4]) ? commandargv[4] : (commandargc > 5) ? commandargv[5] : NULL,
  763: 						   description, 0) < 0)
  764: 					retcode = 2;
  765: 				break;
  766: 			case 'd':
  767: 				if (RemoveRedirect(&urls, &data, commandargv[0], commandargv[1],
  768: 				               commandargc > 2 ? commandargv[2] : NULL) < 0)
  769: 					retcode = 2;
  770: 				break;
  771: 			case 'n':	/* aNy */
  772: 				if (SetRedirectAndTest(&urls, &data,
  773: 						   commandargv[0], commandargv[1],
  774: 						   commandargv[2], commandargv[3],
  775: 						   (commandargc > 4) && is_int(commandargv[4]) ? commandargv[4] : "0",
  776: 						   (commandargc > 4) && !is_int(commandargv[4]) ? commandargv[4] : (commandargc > 5) ? commandargv[5] : NULL,
  777: 						   description, 1) < 0)
  778: 					retcode = 2;
  779: 				break;
  780: 			case 'N':
  781: 				if (commandargc < 3)
  782: 					fprintf(stderr, "too few arguments\n");
  783: 
  784: 				if (RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2],
  785: 						    commandargc > 3 ? commandargv[3] : NULL) < 0)
  786: 					retcode = 2;
  787: 				break;
  788: 			case 's':
  789: 				GetConnectionStatus(&urls, &data);
  790: 				break;
  791: 			case 'r':
  792: 				i = 0;
  793: 				while(i<commandargc)
  794: 				{
  795: 					if(!is_int(commandargv[i])) {
  796: 						/* 1st parameter not an integer : error */
  797: 						fprintf(stderr, "command -r : %s is not an port number\n", commandargv[i]);
  798: 						retcode = 1;
  799: 						break;
  800: 					} else if(is_int(commandargv[i+1])){
  801: 						/* 2nd parameter is an integer : <port> <external_port> <protocol> */
  802: 						if (SetRedirectAndTest(&urls, &data,
  803: 								   lanaddr, commandargv[i],
  804: 								   commandargv[i+1], commandargv[i+2], "0", NULL,
  805: 								   description, 0) < 0)
  806: 							retcode = 2;
  807: 						i+=3;	/* 3 parameters parsed */
  808: 					} else {
  809: 						/* 2nd parameter not an integer : <port> <protocol> */
  810: 						if (SetRedirectAndTest(&urls, &data,
  811: 								   lanaddr, commandargv[i],
  812: 								   commandargv[i], commandargv[i+1], "0", NULL,
  813: 								   description, 0) < 0)
  814: 							retcode = 2;
  815: 						i+=2;	/* 2 parameters parsed */
  816: 					}
  817: 				}
  818: 				break;
  819: 			case 'A':
  820: 				SetPinholeAndTest(&urls, &data,
  821: 				                  commandargv[0], commandargv[1],
  822: 				                  commandargv[2], commandargv[3],
  823: 				                  commandargv[4], commandargv[5]);
  824: 				break;
  825: 			case 'U':
  826: 				GetPinholeAndUpdate(&urls, &data,
  827: 				                   commandargv[0], commandargv[1]);
  828: 				break;
  829: 			case 'C':
  830: 				for(i=0; i<commandargc; i++)
  831: 				{
  832: 					CheckPinhole(&urls, &data, commandargv[i]);
  833: 				}
  834: 				break;
  835: 			case 'K':
  836: 				for(i=0; i<commandargc; i++)
  837: 				{
  838: 					GetPinholePackets(&urls, &data, commandargv[i]);
  839: 				}
  840: 				break;
  841: 			case 'D':
  842: 				for(i=0; i<commandargc; i++)
  843: 				{
  844: 					RemovePinhole(&urls, &data, commandargv[i]);
  845: 				}
  846: 				break;
  847: 			case 'S':
  848: 				GetFirewallStatus(&urls, &data);
  849: 				break;
  850: 			case 'G':
  851: 				GetPinholeOutboundTimeout(&urls, &data,
  852: 							commandargv[0], commandargv[1],
  853: 							commandargv[2], commandargv[3],
  854: 							commandargv[4]);
  855: 				break;
  856: 			case 'P':
  857: 				printf("Presentation URL found:\n");
  858: 				printf("            %s\n", data.presentationurl);
  859: 				break;
  860: 			default:
  861: 				fprintf(stderr, "Unknown switch -%c\n", command);
  862: 				retcode = 1;
  863: 			}
  864: 
  865: 			} else {
  866: 				fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
  867: 				retcode = 1;
  868: 			}
  869: 			FreeUPNPUrls(&urls);
  870: 		}
  871: 		else
  872: 		{
  873: 			fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
  874: 			retcode = 1;
  875: 		}
  876: 		freeUPNPDevlist(devlist); devlist = 0;
  877: 	}
  878: 	else
  879: 	{
  880: 		fprintf(stderr, "No IGD UPnP Device found on the network !\n");
  881: 		retcode = 1;
  882: 	}
  883: #ifdef _WIN32
  884: 	nResult = WSACleanup();
  885: 	if(nResult != NO_ERROR) {
  886: 		fprintf(stderr, "WSACleanup() failed.\n");
  887: 	}
  888: #endif /* _WIN32 */
  889: 	return retcode;
  890: }
  891: 

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