1/* $Id: upnpc.c,v 1.105 2014/11/01 10:37:32 nanard Exp $ */
2/* Project : miniupnp
3 * Author : Thomas Bernard
4 * Copyright (c) 2005-2014 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#define snprintf _snprintf
15#else
16/* for IPPROTO_TCP / IPPROTO_UDP */
17#include <netinet/in.h>
18#endif
19#include "miniwget.h"
20#include "miniupnpc.h"
21#include "upnpcommands.h"
22#include "upnperrors.h"
23
24#include <shared.h>
25#include <sys/ipc.h>
26#include <sys/shm.h>
27#include <sys/sysinfo.h>
28#include <errno.h>
29
30#ifdef RTCONFIG_JFFS2USERICON
31#define JFFS_ICON_PATH	"/jffs/usericon"
32#define UPNP_ICON_PATH	"/tmp/upnpicon"
33
34typedef struct {
35        unsigned char   ip_addr[255][4];
36        unsigned char   mac_addr[255][6];
37        unsigned char   user_define[255][16];
38        unsigned char   device_name[255][32];
39        unsigned char   apl_dev[255][16];
40        int             type[255];
41        int             http[255];
42        int             printer[255];
43        int             itune[255];
44        int             exist[255];
45#ifdef RTCONFIG_BWDPI
46        char            bwdpi_hostname[255][32];
47        char            bwdpi_devicetype[255][100];
48#endif
49        int             ip_mac_num;
50        int             detail_info_num;
51} CLIENT_DETAIL_INFO_TABLE, *P_CLIENT_DETAIL_INFO_TABLE;
52
53//the crc32 of Windows related icon
54unsigned long default_icon_crc[] = {
55        0xeefa6488,
56        0x0798893a,
57        0xe06e1235,
58        0xb54fd1af,
59        0xc9c2b6c4,
60        0xbaa4c50b,
61	0xcec591e3,
62        0
63};
64
65typedef struct IconFile {
66    char                name[12];
67    struct IconFile     *next;
68}IconFile;
69
70struct IconFile *IconList = NULL;
71
72struct UPNPDevInfo IGDInfo;
73
74static char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
75
76int
77openvpn_base64_encode(const void *data, int size, char **str) {
78    char *s, *p;
79    int i;
80    int c;
81    const unsigned char *q;
82
83    if (size < 0)
84                return -1;
85    p = s = (char *) malloc(size * 4 / 3 + 4);
86    if (p == NULL)
87                return -1;
88    q = (const unsigned char *) data;
89    i = 0;
90    for (i = 0; i < size;) {
91                c = q[i++];
92                c *= 256;
93                if (i < size)
94                        c += q[i];
95                i++;
96                c *= 256;
97                if (i < size)
98                        c += q[i];
99                i++;
100                p[0] = base64_chars[(c & 0x00fc0000) >> 18];
101                p[1] = base64_chars[(c & 0x0003f000) >> 12];
102                p[2] = base64_chars[(c & 0x00000fc0) >> 6];
103                p[3] = base64_chars[(c & 0x0000003f) >> 0];
104                if (i > size)
105                        p[3] = '=';
106                if (i > size + 1)
107                        p[2] = '=';
108                p += 4;
109    }
110    *p = 0;
111    *str = s;
112
113    return strlen(s);
114}
115
116int
117image_to_base64(char *file_path,  char *client_mac) {
118        FILE * pFile;
119        long lSize;
120        char *buffer;
121        char *base64;
122        size_t result;
123        int i;
124        char client_mac_temp[15];
125        memset(client_mac_temp, 0, sizeof(client_mac_temp));
126        sprintf(client_mac_temp, client_mac);
127
128printf("Store %s to jffs -> %s!!!\n", file_path, client_mac);
129        int idex = 0;
130        while ( client_mac_temp[idex] != 0 ) {
131                if ( ( client_mac_temp[idex] >= 'a' ) && ( client_mac_temp[idex] <= 'z' ) ) {
132                        client_mac_temp[idex] = client_mac_temp[idex] - 'a' + 'A';
133                }
134                idex++;
135        }
136
137        pFile = fopen (file_path , "rb");
138        if (pFile == NULL) {
139                printf("File error\n");
140                i = 0;
141                return i;
142        }
143
144        fseek (pFile , 0 , SEEK_END);
145        lSize = ftell (pFile);
146        rewind (pFile);
147
148        buffer = (char*) malloc (sizeof(char)*lSize);
149        base64 = (char*) malloc (sizeof(char)*lSize);
150
151        if (buffer == NULL) {
152                printf("Memory error\n");
153                i = 0;
154                return i;
155        }
156
157        result = fread (buffer,1,lSize,pFile);
158        if (result != lSize) {
159                printf("Reading error\n");
160                i = 0;
161                return i;
162        }
163
164        if (openvpn_base64_encode (buffer, lSize, &base64) <= 0) {
165                printf("binary encode error \n");
166                i = 0;
167                return i;
168        }
169
170        char image_base64[(strlen(base64) + 25)];
171        memset(image_base64, 0, sizeof(image_base64));
172
173        sprintf(image_base64, "data:image/jpeg;base64,");
174        strcat(image_base64, base64);
175
176        fclose (pFile);
177        free (buffer);
178        free (base64);
179
180        char write_file_path[35];
181        memset(write_file_path, 0, sizeof(write_file_path));
182
183        if(!check_if_dir_exist("/jffs/usericon"))
184                system("mkdir /jffs/usericon");
185
186        sprintf(write_file_path, "/jffs/usericon/%s.log", client_mac_temp);
187
188        if(!check_if_file_exist(write_file_path)) {
189                int str_len = strlen(image_base64);
190                int i;
191                FILE * pFile;
192                pFile = fopen (write_file_path , "w");
193
194                if (pFile == NULL) {
195                        printf("File error\n");
196                        i = 0;
197                        return i;
198                }
199
200                for(i = 0; i < str_len; i++) {
201                        fputc(image_base64[i], pFile);
202                }
203                fclose (pFile);
204        }
205
206        i = 1;
207        return i;
208}
209
210unsigned long get_icon_crc32(char *icon_path)
211{
212	FILE *icon_fd;
213        unsigned long calc_crc = 0;
214        long iconlen;
215        char buf[4096] = {0};
216
217	//printf("get icon crc32 open: %s\n", icon_path);
218
219	icon_fd = fopen(icon_path, "rb");
220
221	if(icon_fd == NULL) {
222		printf("Get Icon Failed!!!\n");
223		return -1;
224	}
225
226        fseek (icon_fd , 0 , SEEK_END);
227        iconlen = ftell (icon_fd);
228        rewind (icon_fd);
229
230        while(iconlen>0)
231        {
232                if (iconlen > sizeof(buf))
233                {
234                        fread(buf, 1, sizeof(buf), icon_fd);
235                        calc_crc = crc_calc(calc_crc, (unsigned char*)buf, sizeof(buf));
236                        iconlen-=sizeof(buf);
237                }
238                else
239                {
240                        fread(buf, 1, iconlen, icon_fd);
241                        calc_crc = crc_calc(calc_crc, (unsigned char*)buf, iconlen);
242                        iconlen=0;
243                }
244        }
245
246	return calc_crc;
247}
248
249void get_icon_files(void)
250{
251        FILE *fp;
252        char *ico_ptr;
253        char buf[128];
254        struct IconFile *NextIcon = NULL, *ShowIcon;
255
256        sprintf(buf, "ls -1 %s/*.log", JFFS_ICON_PATH);
257
258        fp = popen(buf, "r");
259        if (fp == NULL) {
260                perror("popen");
261                return;
262        }
263
264#ifdef DEBUG
265printf("======= Get Icon Files =========\n");
266#endif
267        while(fgets(buf, sizeof(buf), fp))
268        {
269                IconFile *CurIcon = (IconFile *)malloc(sizeof(IconFile));
270
271                ico_ptr = buf;
272                ico_ptr+= strlen(JFFS_ICON_PATH)+1;
273
274                memcpy(CurIcon->name, ico_ptr, 12);
275                CurIcon->next = NULL;
276
277                if( IconList == NULL )
278                        IconList = CurIcon;
279                else
280                        NextIcon->next = CurIcon;
281                NextIcon = CurIcon;
282        }
283
284        ShowIcon = IconList;
285        while(ShowIcon != NULL)
286        {
287#ifdef DEBUG
288                printf("%s->", ShowIcon->name);
289#endif
290                ShowIcon = ShowIcon->next;
291        }
292#ifdef DEBUG
293        printf("\n===================================\n");
294#endif
295}
296
297void TransferUpnpIcon(P_CLIENT_DETAIL_INFO_TABLE nmp_client)
298{
299        FILE *fp;
300        char *ico_ptr, *ico_end;
301	char ico_ip[16], ico_mac[13], nmp_client_ip[16];
302        char buf[128];
303        struct IconFile *icon = NULL;
304	unsigned long icon_crc32;
305	int i, default_icon=0;
306
307        sprintf(buf, "ls -1 %s/*.ico", UPNP_ICON_PATH);
308
309        fp = popen(buf, "r");
310        if (fp == NULL) {
311                perror("popen");
312                return;
313        }
314
315#ifdef DEBUG
316printf("======= Transfer UPnP Icon Files =========\n");
317#endif
318        while(fgets(buf, sizeof(buf), fp))
319        {
320
321                ico_ptr = buf;
322                ico_ptr += strlen(UPNP_ICON_PATH)+1;
323		ico_end = strstr(buf, ".ico");
324
325		i = 0;
326		while(ico_ptr < ico_end)
327			ico_ip[i++] = *ico_ptr++;
328		ico_ip[i] = '\0';
329		ico_end = ico_end+4;
330		*ico_end = '\0';
331		icon_crc32 = get_icon_crc32(buf);
332
333		//default icon crc32 check
334		i = 0;
335		default_icon = 0;
336		while((default_icon_crc[i] !=0 )) {
337			if(default_icon_crc[i] == icon_crc32) {
338				#ifdef DEBUG
339				printf("GET DEFAULT ICON CRC!!! %s\n", buf);
340				#endif
341				default_icon = 1;
342				break;
343			}
344			i++;
345		}
346
347		if(!default_icon) {
348		    i = 0;
349		    while( (nmp_client->ip_addr[i][0] != 0) && (i < 255) ) {
350			sprintf(nmp_client_ip, "%d.%d.%d.%d", nmp_client->ip_addr[i][0],
351				nmp_client->ip_addr[i][1],nmp_client->ip_addr[i][2],
352				nmp_client->ip_addr[i][3]);
353			if(!strcmp(ico_ip, nmp_client_ip)) {
354				sprintf(ico_mac, "%02X%02X%02X%02X%02X%02X",
355					nmp_client->mac_addr[i][0],
356					nmp_client->mac_addr[i][1],
357                                        nmp_client->mac_addr[i][2],
358                                        nmp_client->mac_addr[i][3],
359                                        nmp_client->mac_addr[i][4],
360                                        nmp_client->mac_addr[i][5]);
361				/* Compare icon in /jffs/usericon */
362                		icon = IconList;
363                		while( icon != NULL ) {
364                        		if( memcmp(icon->name, ico_mac, 12) == 0) {
365						break;
366                		        }
367                        		icon = icon->next;
368                		}
369
370            			if( icon == NULL ) { /* new icon store to /jffs/usericon */
371					image_to_base64(buf, ico_mac);
372
373            			}
374				break;
375			}
376			i++;
377		    }
378		}
379	}
380}
381#endif
382
383/* protofix() checks if protocol is "UDP" or "TCP"
384 * returns NULL if not */
385const char * protofix(const char * proto)
386{
387	static const char proto_tcp[4] = { 'T', 'C', 'P', 0};
388	static const char proto_udp[4] = { 'U', 'D', 'P', 0};
389	int i, b;
390	for(i=0, b=1; i<4; i++)
391		b = b && (   (proto[i] == proto_tcp[i])
392		          || (proto[i] == (proto_tcp[i] | 32)) );
393	if(b)
394		return proto_tcp;
395	for(i=0, b=1; i<4; i++)
396		b = b && (   (proto[i] == proto_udp[i])
397		          || (proto[i] == (proto_udp[i] | 32)) );
398	if(b)
399		return proto_udp;
400	return 0;
401}
402
403static void DisplayInfos(struct UPNPUrls * urls,
404                         struct IGDdatas * data)
405{
406	char externalIPAddress[40];
407	char connectionType[64];
408	char status[64];
409	char lastconnerr[64];
410	unsigned int uptime;
411	unsigned int brUp, brDown;
412	time_t timenow, timestarted;
413	int r;
414/*
415printf("===== DisplayInfos ====\n");
416printf("controlURL:   %s\n", urls->controlURL);
417printf("ipcondescURL: %s\n", urls->ipcondescURL);
418printf("rootdescURL:  %s\n", urls->rootdescURL);
419printf("controlURL_CIF: %s\n", urls->controlURL_CIF);
420printf("controlURL_6FC: %s\n", urls->controlURL_6FC);
421printf("=======================\n");
422*/
423	if(UPNP_GetConnectionTypeInfo(urls->controlURL,
424	                              data->first.servicetype,
425	                              connectionType) != UPNPCOMMAND_SUCCESS)
426		printf("GetConnectionTypeInfo failed.\n");
427	else
428		printf("Connection Type : %s\n", connectionType);
429	if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
430	                      status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS)
431		printf("GetStatusInfo failed.\n");
432	else
433		printf("Status : %s, uptime=%us, LastConnectionError : %s\n",
434		       status, uptime, lastconnerr);
435	timenow = time(NULL);
436	timestarted = timenow - uptime;
437	printf("  Time started : %s", ctime(&timestarted));
438	if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype,
439	                                &brDown, &brUp) != UPNPCOMMAND_SUCCESS) {
440		printf("GetLinkLayerMaxBitRates failed.\n");
441	} else {
442		printf("MaxBitRateDown : %u bps", brDown);
443		if(brDown >= 1000000) {
444			printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10);
445		} else if(brDown >= 1000) {
446			printf(" (%u Kbps)", brDown / 1000);
447		}
448		printf("   MaxBitRateUp %u bps", brUp);
449		if(brUp >= 1000000) {
450			printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10);
451		} else if(brUp >= 1000) {
452			printf(" (%u Kbps)", brUp / 1000);
453		}
454		printf("\n");
455	}
456	r = UPNP_GetExternalIPAddress(urls->controlURL,
457	                          data->first.servicetype,
458							  externalIPAddress);
459	if(r != UPNPCOMMAND_SUCCESS) {
460		printf("GetExternalIPAddress failed. (errorcode=%d)\n", r);
461	} else {
462		printf("ExternalIPAddress = %s\n", externalIPAddress);
463	}
464}
465
466static void GetConnectionStatus(struct UPNPUrls * urls,
467                               struct IGDdatas * data)
468{
469	unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
470	DisplayInfos(urls, data);
471	bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
472	bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
473	packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
474	packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
475	printf("Bytes:   Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
476	printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
477}
478
479static void ListRedirections(struct UPNPUrls * urls,
480                             struct IGDdatas * data)
481{
482	int r;
483	int i = 0;
484	char index[6];
485	char intClient[40];
486	char intPort[6];
487	char extPort[6];
488	char protocol[4];
489	char desc[80];
490	char enabled[6];
491	char rHost[64];
492	char duration[16];
493	/*unsigned int num=0;
494	UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num);
495	printf("PortMappingNumberOfEntries : %u\n", num);*/
496	printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
497	do {
498		snprintf(index, 6, "%d", i);
499		rHost[0] = '\0'; enabled[0] = '\0';
500		duration[0] = '\0'; desc[0] = '\0';
501		extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
502		r = UPNP_GetGenericPortMappingEntry(urls->controlURL,
503		                               data->first.servicetype,
504		                               index,
505		                               extPort, intClient, intPort,
506									   protocol, desc, enabled,
507									   rHost, duration);
508		if(r==0)
509		/*
510			printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n"
511			       "     desc='%s' rHost='%s'\n",
512			       i, protocol, extPort, intClient, intPort,
513				   enabled, duration,
514				   desc, rHost);
515				   */
516			printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n",
517			       i, protocol, extPort, intClient, intPort,
518			       desc, rHost, duration);
519		else
520			printf("GetGenericPortMappingEntry() returned %d (%s)\n",
521			       r, strupnperror(r));
522		i++;
523	} while(r==0);
524}
525
526static void NewListRedirections(struct UPNPUrls * urls,
527                                struct IGDdatas * data)
528{
529	int r;
530	int i = 0;
531	struct PortMappingParserData pdata;
532	struct PortMapping * pm;
533
534	memset(&pdata, 0, sizeof(struct PortMappingParserData));
535	r = UPNP_GetListOfPortMappings(urls->controlURL,
536                                   data->first.servicetype,
537	                               "0",
538	                               "65535",
539	                               "TCP",
540	                               "1000",
541	                               &pdata);
542	if(r == UPNPCOMMAND_SUCCESS)
543	{
544		printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
545		for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
546		{
547			printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
548			       i, pm->protocol, pm->externalPort, pm->internalClient,
549			       pm->internalPort,
550			       pm->description, pm->remoteHost,
551			       (unsigned)pm->leaseTime);
552			i++;
553		}
554		FreePortListing(&pdata);
555	}
556	else
557	{
558		printf("GetListOfPortMappings() returned %d (%s)\n",
559		       r, strupnperror(r));
560	}
561	r = UPNP_GetListOfPortMappings(urls->controlURL,
562                                   data->first.servicetype,
563	                               "0",
564	                               "65535",
565	                               "UDP",
566	                               "1000",
567	                               &pdata);
568	if(r == UPNPCOMMAND_SUCCESS)
569	{
570		for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
571		{
572			printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
573			       i, pm->protocol, pm->externalPort, pm->internalClient,
574			       pm->internalPort,
575			       pm->description, pm->remoteHost,
576			       (unsigned)pm->leaseTime);
577			i++;
578		}
579		FreePortListing(&pdata);
580	}
581	else
582	{
583		printf("GetListOfPortMappings() returned %d (%s)\n",
584		       r, strupnperror(r));
585	}
586}
587
588/* Test function
589 * 1 - get connection type
590 * 2 - get extenal ip address
591 * 3 - Add port mapping
592 * 4 - get this port mapping from the IGD */
593static void SetRedirectAndTest(struct UPNPUrls * urls,
594			       struct IGDdatas * data,
595			       const char * iaddr,
596			       const char * iport,
597			       const char * eport,
598			       const char * proto,
599			       const char * leaseDuration,
600			       const char * description,
601			       int addAny)
602{
603	char externalIPAddress[40];
604	char intClient[40];
605	char intPort[6];
606	char reservedPort[6];
607	char duration[16];
608	int r;
609
610	if(!iaddr || !iport || !eport || !proto)
611	{
612		fprintf(stderr, "Wrong arguments\n");
613		return;
614	}
615	proto = protofix(proto);
616	if(!proto)
617	{
618		fprintf(stderr, "invalid protocol\n");
619		return;
620	}
621
622	r = UPNP_GetExternalIPAddress(urls->controlURL,
623				      data->first.servicetype,
624				      externalIPAddress);
625	if(r!=UPNPCOMMAND_SUCCESS)
626		printf("GetExternalIPAddress failed.\n");
627	else
628		printf("ExternalIPAddress = %s\n", externalIPAddress);
629
630	if (addAny) {
631		r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype,
632					   eport, iport, iaddr, description,
633					   proto, 0, leaseDuration, reservedPort);
634		if(r==UPNPCOMMAND_SUCCESS)
635			eport = reservedPort;
636		else
637			printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n",
638			       eport, iport, iaddr, r, strupnperror(r));
639	} else {
640		r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype,
641					eport, iport, iaddr, description,
642					proto, 0, leaseDuration);
643		if(r!=UPNPCOMMAND_SUCCESS)
644			printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
645			       eport, iport, iaddr, r, strupnperror(r));
646	}
647
648	r = UPNP_GetSpecificPortMappingEntry(urls->controlURL,
649					     data->first.servicetype,
650					     eport, proto, NULL/*remoteHost*/,
651					     intClient, intPort, NULL/*desc*/,
652					     NULL/*enabled*/, duration);
653	if(r!=UPNPCOMMAND_SUCCESS)
654		printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n",
655		       r, strupnperror(r));
656	else {
657		printf("InternalIP:Port = %s:%s\n", intClient, intPort);
658		printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n",
659		       externalIPAddress, eport, proto, intClient, intPort, duration);
660	}
661}
662
663static void
664RemoveRedirect(struct UPNPUrls * urls,
665               struct IGDdatas * data,
666               const char * eport,
667               const char * proto,
668               const char * remoteHost)
669{
670	int r;
671	if(!proto || !eport)
672	{
673		fprintf(stderr, "invalid arguments\n");
674		return;
675	}
676	proto = protofix(proto);
677	if(!proto)
678	{
679		fprintf(stderr, "protocol invalid\n");
680		return;
681	}
682	r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, remoteHost);
683	printf("UPNP_DeletePortMapping() returned : %d\n", r);
684}
685
686static void
687RemoveRedirectRange(struct UPNPUrls * urls,
688		    struct IGDdatas * data,
689		    const char * ePortStart, char const * ePortEnd,
690		    const char * proto, const char * manage)
691{
692	int r;
693
694	if (!manage)
695		manage = "0";
696
697	if(!proto || !ePortStart || !ePortEnd)
698	{
699		fprintf(stderr, "invalid arguments\n");
700		return;
701	}
702	proto = protofix(proto);
703	if(!proto)
704	{
705		fprintf(stderr, "protocol invalid\n");
706		return;
707	}
708	r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage);
709	printf("UPNP_DeletePortMappingRange() returned : %d\n", r);
710}
711
712/* IGD:2, functions for service WANIPv6FirewallControl:1 */
713static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data)
714{
715	unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
716	int firewallEnabled = 0, inboundPinholeAllowed = 0;
717
718	UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed);
719	printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed);
720	printf("GetFirewallStatus:\n   Firewall Enabled: %s\n   Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No");
721
722	bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
723	bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
724	packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
725	packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
726	printf("Bytes:   Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
727	printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
728}
729
730/* Test function
731 * 1 - Add pinhole
732 * 2 - Check if pinhole is working from the IGD side */
733static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data,
734					const char * remoteaddr, const char * eport,
735					const char * intaddr, const char * iport,
736					const char * proto, const char * lease_time)
737{
738	char uniqueID[8];
739	/*int isWorking = 0;*/
740	int r;
741	char proto_tmp[8];
742
743	if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time)
744	{
745		fprintf(stderr, "Wrong arguments\n");
746		return;
747	}
748	if(atoi(proto) == 0)
749	{
750		const char * protocol;
751		protocol = protofix(proto);
752		if(protocol && (strcmp("TCP", protocol) == 0))
753		{
754			snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP);
755			proto = proto_tmp;
756		}
757		else if(protocol && (strcmp("UDP", protocol) == 0))
758		{
759			snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP);
760			proto = proto_tmp;
761		}
762		else
763		{
764			fprintf(stderr, "invalid protocol\n");
765			return;
766		}
767	}
768	r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID);
769	if(r!=UPNPCOMMAND_SUCCESS)
770		printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
771		       remoteaddr, eport, intaddr, iport, r, strupnperror(r));
772	else
773	{
774		printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n",
775		       remoteaddr, eport, intaddr, iport, uniqueID);
776		/*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking);
777		if(r!=UPNPCOMMAND_SUCCESS)
778			printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
779		printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/
780	}
781}
782
783/* Test function
784 * 1 - Check if pinhole is working from the IGD side
785 * 2 - Update pinhole */
786static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data,
787					const char * uniqueID, const char * lease_time)
788{
789	int isWorking = 0;
790	int r;
791
792	if(!uniqueID || !lease_time)
793	{
794		fprintf(stderr, "Wrong arguments\n");
795		return;
796	}
797	r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
798	printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
799	if(r!=UPNPCOMMAND_SUCCESS)
800		printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
801	if(isWorking || r==709)
802	{
803		r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time);
804		printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time);
805		if(r!=UPNPCOMMAND_SUCCESS)
806			printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r));
807	}
808}
809
810/* Test function
811 * Get pinhole timeout
812 */
813static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data,
814					const char * remoteaddr, const char * eport,
815					const char * intaddr, const char * iport,
816					const char * proto)
817{
818	int timeout = 0;
819	int r;
820
821	if(!intaddr || !remoteaddr || !iport || !eport || !proto)
822	{
823		fprintf(stderr, "Wrong arguments\n");
824		return;
825	}
826
827	r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout);
828	if(r!=UPNPCOMMAND_SUCCESS)
829		printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
830		       intaddr, iport, remoteaddr, eport, r, strupnperror(r));
831	else
832		printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout);
833}
834
835static void
836GetPinholePackets(struct UPNPUrls * urls,
837               struct IGDdatas * data, const char * uniqueID)
838{
839	int r, pinholePackets = 0;
840	if(!uniqueID)
841	{
842		fprintf(stderr, "invalid arguments\n");
843		return;
844	}
845	r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets);
846	if(r!=UPNPCOMMAND_SUCCESS)
847		printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r));
848	else
849		printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets);
850}
851
852static void
853CheckPinhole(struct UPNPUrls * urls,
854               struct IGDdatas * data, const char * uniqueID)
855{
856	int r, isWorking = 0;
857	if(!uniqueID)
858	{
859		fprintf(stderr, "invalid arguments\n");
860		return;
861	}
862	r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
863	if(r!=UPNPCOMMAND_SUCCESS)
864		printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
865	else
866		printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
867}
868
869static void
870RemovePinhole(struct UPNPUrls * urls,
871               struct IGDdatas * data, const char * uniqueID)
872{
873	int r;
874	if(!uniqueID)
875	{
876		fprintf(stderr, "invalid arguments\n");
877		return;
878	}
879	r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID);
880	printf("UPNP_DeletePinhole() returned : %d\n", r);
881}
882
883
884/* sample upnp client program */
885int main(int argc, char ** argv)
886{
887	char command = 0;
888	char ** commandargv = 0;
889	int commandargc = 0;
890	struct UPNPDev * devlist = 0;
891	char lanaddr[64];	/* my ip address on the LAN */
892	int i;
893	const char * rootdescurl = 0;
894	const char * multicastif = 0;
895	const char * minissdpdpath = 0;
896	int retcode = 0;
897	int error = 0;
898	int ipv6 = 0;
899	const char * description = 0;
900
901#ifdef _WIN32
902	WSADATA wsaData;
903	int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
904	if(nResult != NO_ERROR)
905	{
906		fprintf(stderr, "WSAStartup() failed.\n");
907		return -1;
908	}
909#endif
910/*
911    printf("upnpc : miniupnpc library test client. (c) 2005-2014 Thomas Bernard\n");
912    printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n"
913           "for more information.\n");
914*/
915
916	/* command line processing */
917	for(i=1; i<argc; i++)
918	{
919		if(0 == strcmp(argv[i], "--help") || 0 == strcmp(argv[i], "-h"))
920		{
921			command = 0;
922			break;
923		}
924		if(argv[i][0] == '-')
925		{
926			if(argv[i][1] == 'u')
927				rootdescurl = argv[++i];
928			else if(argv[i][1] == 'm')
929				multicastif = argv[++i];
930			else if(argv[i][1] == 'p')
931				minissdpdpath = argv[++i];
932			else if(argv[i][1] == '6')
933				ipv6 = 1;
934			else if(argv[i][1] == 'e')
935				description = argv[++i];
936			else
937			{
938				command = argv[i][1];
939				i++;
940				commandargv = argv + i;
941				commandargc = argc - i;
942				break;
943			}
944		}
945		else
946		{
947			fprintf(stderr, "option '%s' invalid\n", argv[i]);
948		}
949	}
950
951	if(!command || (command == 'a' && commandargc<4)
952	   || (command == 'd' && argc<2)
953	   || (command == 'r' && argc<2)
954	   || (command == 'A' && commandargc<6)
955	   || (command == 'U' && commandargc<2)
956	   || (command == 'D' && commandargc<1))
957	{
958		fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration]\n\t\tAdd port redirection\n", argv[0]);
959		fprintf(stderr, "       \t%s [options] -d external_port protocol <remote host>\n\t\tDelete port redirection\n", argv[0]);
960		fprintf(stderr, "       \t%s [options] -s\n\t\tGet Connection status\n", argv[0]);
961		fprintf(stderr, "       \t%s [options] -l\n\t\tList redirections\n", argv[0]);
962		fprintf(stderr, "       \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]);
963		fprintf(stderr, "       \t%s [options] -n ip port external_port protocol [duration]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]);
964		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]);
965		fprintf(stderr, "       \t%s [options] -r port1 protocol1 [port2 protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]);
966		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]);
967		fprintf(stderr, "       \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]);
968		fprintf(stderr, "       \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]);
969		fprintf(stderr, "       \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]);
970		fprintf(stderr, "       \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]);
971		fprintf(stderr, "       \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]);
972		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]);
973		fprintf(stderr, "       \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]);
974		fprintf(stderr, "\nprotocol is UDP or TCP\n");
975		fprintf(stderr, "Options:\n");
976		fprintf(stderr, "  -e description : set description for port mapping.\n");
977		fprintf(stderr, "  -6 : use ip v6 instead of ip v4.\n");
978		fprintf(stderr, "  -u url : bypass discovery process by providing the XML root description url.\n");
979		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");
980		fprintf(stderr, "  -p path : use this path for MiniSSDPd socket.\n");
981		return 1;
982	}
983
984#if 0
985	if( rootdescurl
986	  || (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
987	                             0/*sameport*/, ipv6, &error)))
988#endif
989
990#ifdef RTCONFIG_JFFS2USERICON
991        if(!check_if_dir_exist("/tmp/upnpicon"))
992                system("mkdir /tmp/upnpicon");
993#endif
994
995	int x = 0;
996	while(x<3)
997	{
998		devlist = upnpDiscoverAll(2000, multicastif, minissdpdpath, 1, ipv6, &error);
999		if(devlist)
1000			break;
1001		x++;
1002		sleep(6);
1003	}
1004
1005	if(devlist)
1006	{
1007		struct UPNPDev * device;
1008		struct UPNPUrls urls;
1009		struct IGDdatas data;
1010		if(devlist)
1011		{
1012#ifdef DEBUG
1013			printf("List of UPNP devices found on the network :\n");
1014			for(device = devlist; device; device = device->pNext)
1015			{
1016				printf(" desc: %s\n st: %s\n\n",
1017					   device->descURL, device->st);
1018			}
1019#endif
1020		}
1021		else
1022		{
1023			printf("upnpDiscover() error code=%d\n", error);
1024		}
1025
1026		i = 1;
1027
1028		if(i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))
1029		{
1030			FILE *fp;
1031		        int i, shm_client_info_id;
1032		        void *shared_client_info=(void *) 0;
1033		        int lock;
1034
1035			if(fp = fopen("/tmp/miniupnpc.log", "w"))
1036			{
1037				for(device = devlist; device; device = device->pNext)
1038			        {
1039					if(strcmp(device->DevInfo.hostname, ""))
1040					{
1041				                fprintf(fp,"%s>", device->DevInfo.hostname);
1042				                fprintf(fp,"%s>", device->DevInfo.type);
1043				                fprintf(fp,"%s\n", device->DevInfo.friendlyName);
1044					}
1045				}
1046				fclose(fp);
1047			}
1048
1049#ifdef RTCONFIG_JFFS2USERICON
1050			get_icon_files();
1051		        lock = file_lock("networkmap");
1052		        shm_client_info_id = shmget((key_t)1001, sizeof(CLIENT_DETAIL_INFO_TABLE), 0666| IPC_CREAT);
1053		        if (shm_client_info_id == -1){
1054		            	perror("shmget failed:\n");
1055		            	file_unlock(lock);
1056		            	return 0;
1057		        }
1058
1059		        shared_client_info = shmat(shm_client_info_id,(void *) 0,SHM_RDONLY);
1060		        if (shared_client_info == (void *)-1){
1061		                printf("shmat failed\n");
1062                		file_unlock(lock);
1063		                return 0;
1064		        }
1065
1066			TransferUpnpIcon(shared_client_info);
1067#endif
1068
1069#ifdef DEBUG
1070			switch(i) {
1071			case 1:
1072				printf("Found valid IGD : %s\n", urls.controlURL);
1073				break;
1074			case 2:
1075				printf("Found a (not connected?) IGD : %s\n", urls.controlURL);
1076				printf("Trying to continue anyway\n");
1077				break;
1078			case 3:
1079				printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL);
1080				printf("Trying to continue anyway\n");
1081				break;
1082			default:
1083				printf("Found device (igd ?) : %s\n", urls.controlURL);
1084				printf("Trying to continue anyway\n");
1085			}
1086			printf("Local LAN ip address : %s\n", lanaddr);
1087#endif
1088			#if 0
1089			printf("getting \"%s\"\n", urls.ipcondescURL);
1090			descXML = miniwget(urls.ipcondescURL, &descXMLsize);
1091			if(descXML)
1092			{
1093				/*fwrite(descXML, 1, descXMLsize, stdout);*/
1094				free(descXML); descXML = NULL;
1095			}
1096			#endif
1097
1098			switch(command)
1099			{
1100			case 'l':
1101				DisplayInfos(&urls, &data);
1102				ListRedirections(&urls, &data);
1103				break;
1104			case 'L':
1105				NewListRedirections(&urls, &data);
1106				break;
1107			case 'a':
1108				SetRedirectAndTest(&urls, &data,
1109						   commandargv[0], commandargv[1],
1110						   commandargv[2], commandargv[3],
1111						   (commandargc > 4)?commandargv[4]:"0",
1112						   description, 0);
1113				break;
1114			case 'd':
1115				RemoveRedirect(&urls, &data, commandargv[0], commandargv[1],
1116				               commandargc > 2 ? commandargv[2] : NULL);
1117				break;
1118			case 'n':	/* aNy */
1119				SetRedirectAndTest(&urls, &data,
1120						   commandargv[0], commandargv[1],
1121						   commandargv[2], commandargv[3],
1122						   (commandargc > 4)?commandargv[4]:"0",
1123						   description, 1);
1124				break;
1125			case 'N':
1126				if (commandargc < 3)
1127					fprintf(stderr, "too few arguments\n");
1128
1129				RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2],
1130						    commandargc > 3 ? commandargv[3] : NULL);
1131				break;
1132			case 's':
1133				GetConnectionStatus(&urls, &data);
1134				break;
1135			case 'r':
1136				for(i=0; i<commandargc; i+=2)
1137				{
1138					/*printf("port %s protocol %s\n", argv[i], argv[i+1]);*/
1139					SetRedirectAndTest(&urls, &data,
1140							   lanaddr, commandargv[i],
1141							   commandargv[i], commandargv[i+1], "0",
1142							   description, 0);
1143				}
1144				break;
1145			case 'A':
1146				SetPinholeAndTest(&urls, &data,
1147				                  commandargv[0], commandargv[1],
1148				                  commandargv[2], commandargv[3],
1149				                  commandargv[4], commandargv[5]);
1150				break;
1151			case 'U':
1152				GetPinholeAndUpdate(&urls, &data,
1153				                   commandargv[0], commandargv[1]);
1154				break;
1155			case 'C':
1156				for(i=0; i<commandargc; i++)
1157				{
1158					CheckPinhole(&urls, &data, commandargv[i]);
1159				}
1160				break;
1161			case 'K':
1162				for(i=0; i<commandargc; i++)
1163				{
1164					GetPinholePackets(&urls, &data, commandargv[i]);
1165				}
1166				break;
1167			case 'D':
1168				for(i=0; i<commandargc; i++)
1169				{
1170					RemovePinhole(&urls, &data, commandargv[i]);
1171				}
1172				break;
1173			case 'S':
1174				GetFirewallStatus(&urls, &data);
1175				break;
1176			case 'G':
1177				GetPinholeOutboundTimeout(&urls, &data,
1178							commandargv[0], commandargv[1],
1179							commandargv[2], commandargv[3],
1180							commandargv[4]);
1181				break;
1182			case 'P':
1183				printf("Presentation URL found:\n");
1184				printf("            %s\n", data.presentationurl);
1185				break;
1186			case 't':
1187				break;
1188			default:
1189				fprintf(stderr, "Unknown switch -%c\n", command);
1190				retcode = 1;
1191			}
1192
1193			FreeUPNPUrls(&urls);
1194		}
1195		else
1196		{
1197			fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
1198			retcode = 1;
1199		}
1200
1201		freeUPNPDevlist(devlist); devlist = 0;
1202	}
1203	else
1204	{
1205		fprintf(stderr, "No IGD UPnP Device found on the network !\n");
1206		retcode = 1;
1207	}
1208	return retcode;
1209}
1210
1211