Return to upnpc.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / miniupnpc / src |
1.1 ! misho 1: /* $Id: upnpc.c,v 1.131 2022/02/19 23:22:54 nanard 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(×tarted)); ! 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: "0", ! 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: "0", ! 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: r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); ! 469: printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); ! 470: if(r!=UPNPCOMMAND_SUCCESS) ! 471: printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); ! 472: if(isWorking || r==709) ! 473: { ! 474: r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time); ! 475: printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time); ! 476: if(r!=UPNPCOMMAND_SUCCESS) ! 477: printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r)); ! 478: } ! 479: } ! 480: ! 481: /* Test function ! 482: * Get pinhole timeout ! 483: */ ! 484: static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data, ! 485: const char * remoteaddr, const char * eport, ! 486: const char * intaddr, const char * iport, ! 487: const char * proto) ! 488: { ! 489: int timeout = 0; ! 490: int r; ! 491: ! 492: if(!intaddr || !remoteaddr || !iport || !eport || !proto) ! 493: { ! 494: fprintf(stderr, "Wrong arguments\n"); ! 495: return; ! 496: } ! 497: ! 498: r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout); ! 499: if(r!=UPNPCOMMAND_SUCCESS) ! 500: printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", ! 501: intaddr, iport, remoteaddr, eport, r, strupnperror(r)); ! 502: else ! 503: printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout); ! 504: } ! 505: ! 506: static void ! 507: GetPinholePackets(struct UPNPUrls * urls, ! 508: struct IGDdatas * data, const char * uniqueID) ! 509: { ! 510: int r, pinholePackets = 0; ! 511: if(!uniqueID) ! 512: { ! 513: fprintf(stderr, "invalid arguments\n"); ! 514: return; ! 515: } ! 516: r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets); ! 517: if(r!=UPNPCOMMAND_SUCCESS) ! 518: printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r)); ! 519: else ! 520: printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets); ! 521: } ! 522: ! 523: static void ! 524: CheckPinhole(struct UPNPUrls * urls, ! 525: struct IGDdatas * data, const char * uniqueID) ! 526: { ! 527: int r, isWorking = 0; ! 528: if(!uniqueID) ! 529: { ! 530: fprintf(stderr, "invalid arguments\n"); ! 531: return; ! 532: } ! 533: r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); ! 534: if(r!=UPNPCOMMAND_SUCCESS) ! 535: printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); ! 536: else ! 537: printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); ! 538: } ! 539: ! 540: static void ! 541: RemovePinhole(struct UPNPUrls * urls, ! 542: struct IGDdatas * data, const char * uniqueID) ! 543: { ! 544: int r; ! 545: if(!uniqueID) ! 546: { ! 547: fprintf(stderr, "invalid arguments\n"); ! 548: return; ! 549: } ! 550: r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID); ! 551: printf("UPNP_DeletePinhole() returned : %d\n", r); ! 552: } ! 553: ! 554: ! 555: /* sample upnp client program */ ! 556: int main(int argc, char ** argv) ! 557: { ! 558: char command = 0; ! 559: char ** commandargv = 0; ! 560: int commandargc = 0; ! 561: struct UPNPDev * devlist = 0; ! 562: char lanaddr[64] = "unset"; /* my ip address on the LAN */ ! 563: int i; ! 564: const char * rootdescurl = 0; ! 565: const char * multicastif = 0; ! 566: const char * minissdpdpath = 0; ! 567: int localport = UPNP_LOCAL_PORT_ANY; ! 568: int retcode = 0; ! 569: int error = 0; ! 570: int ipv6 = 0; ! 571: int ignore = 0; ! 572: unsigned char ttl = 2; /* defaulting to 2 */ ! 573: const char * description = 0; ! 574: ! 575: #ifdef _WIN32 ! 576: WSADATA wsaData; ! 577: int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); ! 578: if(nResult != NO_ERROR) ! 579: { ! 580: fprintf(stderr, "WSAStartup() failed.\n"); ! 581: return -1; ! 582: } ! 583: #endif ! 584: printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING); ! 585: printf(" (c) 2005-2023 Thomas Bernard.\n"); ! 586: printf("Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/\n" ! 587: "for more information.\n"); ! 588: /* command line processing */ ! 589: for(i=1; i<argc; i++) ! 590: { ! 591: if(0 == strcmp(argv[i], "--help") || 0 == strcmp(argv[i], "-h")) ! 592: { ! 593: command = 0; ! 594: break; ! 595: } ! 596: if(argv[i][0] == '-') ! 597: { ! 598: if(argv[i][1] == 'u') ! 599: rootdescurl = argv[++i]; ! 600: else if(argv[i][1] == 'm') ! 601: { ! 602: multicastif = argv[++i]; ! 603: minissdpdpath = ""; /* Disable usage of minissdpd */ ! 604: } ! 605: else if(argv[i][1] == 'z') ! 606: { ! 607: char junk; ! 608: if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 || ! 609: localport<0 || localport>65535 || ! 610: (localport >1 && localport < 1024)) ! 611: { ! 612: fprintf(stderr, "Invalid localport '%s'\n", argv[i]); ! 613: localport = UPNP_LOCAL_PORT_ANY; ! 614: break; ! 615: } ! 616: } ! 617: else if(argv[i][1] == 'p') ! 618: minissdpdpath = argv[++i]; ! 619: else if(argv[i][1] == '6') ! 620: ipv6 = 1; ! 621: else if(argv[i][1] == 'e') ! 622: description = argv[++i]; ! 623: else if(argv[i][1] == 't') ! 624: ttl = (unsigned char)atoi(argv[++i]); ! 625: else if(argv[i][1] == 'i') ! 626: ignore = 1; ! 627: else ! 628: { ! 629: command = argv[i][1]; ! 630: i++; ! 631: commandargv = argv + i; ! 632: commandargc = argc - i; ! 633: break; ! 634: } ! 635: } ! 636: else ! 637: { ! 638: fprintf(stderr, "option '%s' invalid\n", argv[i]); ! 639: } ! 640: } ! 641: ! 642: if(!command ! 643: || (command == 'a' && commandargc<4) ! 644: || (command == 'd' && argc<2) ! 645: || (command == 'r' && argc<2) ! 646: || (command == 'A' && commandargc<6) ! 647: || (command == 'U' && commandargc<2) ! 648: || (command == 'D' && commandargc<1)) ! 649: { ! 650: fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration] [remote host]\n\t\tAdd port redirection\n", argv[0]); ! 651: fprintf(stderr, " \t%s [options] -d external_port protocol [remote host]\n\t\tDelete port redirection\n", argv[0]); ! 652: fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]); ! 653: fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]); ! 654: fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]); ! 655: 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]); ! 656: 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]); ! 657: 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]); ! 658: 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]); ! 659: fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]); ! 660: fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]); ! 661: fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]); ! 662: fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]); ! 663: fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]); ! 664: 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]); ! 665: fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]); ! 666: fprintf(stderr, "\nprotocol is UDP or TCP\n"); ! 667: fprintf(stderr, "@ can be used in option -a, -n, -A and -G to represent local LAN address.\n"); ! 668: fprintf(stderr, "Options:\n"); ! 669: fprintf(stderr, " -e description : set description for port mapping.\n"); ! 670: fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n"); ! 671: fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n"); ! 672: 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"); ! 673: fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n"); ! 674: fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n"); ! 675: fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n"); ! 676: fprintf(stderr, " -i : ignore errors and try to use also disconnected IGD or non-IGD device.\n"); ! 677: return 1; ! 678: } ! 679: ! 680: if( rootdescurl ! 681: || (devlist = upnpDiscover(2000, multicastif, minissdpdpath, ! 682: localport, ipv6, ttl, &error))) ! 683: { ! 684: struct UPNPDev * device; ! 685: struct UPNPUrls urls; ! 686: struct IGDdatas data; ! 687: if(devlist) ! 688: { ! 689: printf("List of UPNP devices found on the network :\n"); ! 690: for(device = devlist; device; device = device->pNext) ! 691: { ! 692: printf(" desc: %s\n st: %s\n\n", ! 693: device->descURL, device->st); ! 694: } ! 695: } ! 696: else if(!rootdescurl) ! 697: { ! 698: printf("upnpDiscover() error code=%d\n", error); ! 699: } ! 700: i = 1; ! 701: if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr))) ! 702: || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))) ! 703: { ! 704: switch(i) { ! 705: case 1: ! 706: printf("Found valid IGD : %s\n", urls.controlURL); ! 707: break; ! 708: case 2: ! 709: printf("Found a (not connected?) IGD : %s\n", urls.controlURL); ! 710: if (ignore) printf("Trying to continue anyway\n"); ! 711: break; ! 712: case 3: ! 713: printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL); ! 714: if (ignore) printf("Trying to continue anyway\n"); ! 715: break; ! 716: default: ! 717: printf("Found device (igd ?) : %s\n", urls.controlURL); ! 718: if (ignore) printf("Trying to continue anyway\n"); ! 719: } ! 720: if(i==1 || ignore) { ! 721: ! 722: printf("Local LAN ip address : %s\n", lanaddr); ! 723: #if 0 ! 724: printf("getting \"%s\"\n", urls.ipcondescURL); ! 725: descXML = miniwget(urls.ipcondescURL, &descXMLsize); ! 726: if(descXML) ! 727: { ! 728: /*fwrite(descXML, 1, descXMLsize, stdout);*/ ! 729: free(descXML); descXML = NULL; ! 730: } ! 731: #endif ! 732: ! 733: /* replace '@' with the local LAN ip address */ ! 734: if ((command == 'a' || command == 'n') && 0 == strcmp(commandargv[0], "@")) ! 735: commandargv[0] = lanaddr; ! 736: else if ((command == 'A' || command == 'G') && 0 == strcmp(commandargv[2], "@")) ! 737: commandargv[2] = lanaddr; ! 738: ! 739: switch(command) ! 740: { ! 741: case 'l': ! 742: DisplayInfos(&urls, &data); ! 743: ListRedirections(&urls, &data); ! 744: break; ! 745: case 'L': ! 746: NewListRedirections(&urls, &data); ! 747: break; ! 748: case 'a': ! 749: if (SetRedirectAndTest(&urls, &data, ! 750: commandargv[0], commandargv[1], ! 751: commandargv[2], commandargv[3], ! 752: (commandargc > 4) && is_int(commandargv[4]) ? commandargv[4] : "0", ! 753: (commandargc > 4) && !is_int(commandargv[4]) ? commandargv[4] : (commandargc > 5) ? commandargv[5] : NULL, ! 754: description, 0) < 0) ! 755: retcode = 2; ! 756: break; ! 757: case 'd': ! 758: if (RemoveRedirect(&urls, &data, commandargv[0], commandargv[1], ! 759: commandargc > 2 ? commandargv[2] : NULL) < 0) ! 760: retcode = 2; ! 761: break; ! 762: case 'n': /* aNy */ ! 763: if (SetRedirectAndTest(&urls, &data, ! 764: commandargv[0], commandargv[1], ! 765: commandargv[2], commandargv[3], ! 766: (commandargc > 4) && is_int(commandargv[4]) ? commandargv[4] : "0", ! 767: (commandargc > 4) && !is_int(commandargv[4]) ? commandargv[4] : (commandargc > 5) ? commandargv[5] : NULL, ! 768: description, 1) < 0) ! 769: retcode = 2; ! 770: break; ! 771: case 'N': ! 772: if (commandargc < 3) ! 773: fprintf(stderr, "too few arguments\n"); ! 774: ! 775: if (RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2], ! 776: commandargc > 3 ? commandargv[3] : NULL) < 0) ! 777: retcode = 2; ! 778: break; ! 779: case 's': ! 780: GetConnectionStatus(&urls, &data); ! 781: break; ! 782: case 'r': ! 783: i = 0; ! 784: while(i<commandargc) ! 785: { ! 786: if(!is_int(commandargv[i])) { ! 787: /* 1st parameter not an integer : error */ ! 788: fprintf(stderr, "command -r : %s is not an port number\n", commandargv[i]); ! 789: retcode = 1; ! 790: break; ! 791: } else if(is_int(commandargv[i+1])){ ! 792: /* 2nd parameter is an integer : <port> <external_port> <protocol> */ ! 793: if (SetRedirectAndTest(&urls, &data, ! 794: lanaddr, commandargv[i], ! 795: commandargv[i+1], commandargv[i+2], "0", NULL, ! 796: description, 0) < 0) ! 797: retcode = 2; ! 798: i+=3; /* 3 parameters parsed */ ! 799: } else { ! 800: /* 2nd parameter not an integer : <port> <protocol> */ ! 801: if (SetRedirectAndTest(&urls, &data, ! 802: lanaddr, commandargv[i], ! 803: commandargv[i], commandargv[i+1], "0", NULL, ! 804: description, 0) < 0) ! 805: retcode = 2; ! 806: i+=2; /* 2 parameters parsed */ ! 807: } ! 808: } ! 809: break; ! 810: case 'A': ! 811: SetPinholeAndTest(&urls, &data, ! 812: commandargv[0], commandargv[1], ! 813: commandargv[2], commandargv[3], ! 814: commandargv[4], commandargv[5]); ! 815: break; ! 816: case 'U': ! 817: GetPinholeAndUpdate(&urls, &data, ! 818: commandargv[0], commandargv[1]); ! 819: break; ! 820: case 'C': ! 821: for(i=0; i<commandargc; i++) ! 822: { ! 823: CheckPinhole(&urls, &data, commandargv[i]); ! 824: } ! 825: break; ! 826: case 'K': ! 827: for(i=0; i<commandargc; i++) ! 828: { ! 829: GetPinholePackets(&urls, &data, commandargv[i]); ! 830: } ! 831: break; ! 832: case 'D': ! 833: for(i=0; i<commandargc; i++) ! 834: { ! 835: RemovePinhole(&urls, &data, commandargv[i]); ! 836: } ! 837: break; ! 838: case 'S': ! 839: GetFirewallStatus(&urls, &data); ! 840: break; ! 841: case 'G': ! 842: GetPinholeOutboundTimeout(&urls, &data, ! 843: commandargv[0], commandargv[1], ! 844: commandargv[2], commandargv[3], ! 845: commandargv[4]); ! 846: break; ! 847: case 'P': ! 848: printf("Presentation URL found:\n"); ! 849: printf(" %s\n", data.presentationurl); ! 850: break; ! 851: default: ! 852: fprintf(stderr, "Unknown switch -%c\n", command); ! 853: retcode = 1; ! 854: } ! 855: ! 856: } else { ! 857: fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n"); ! 858: retcode = 1; ! 859: } ! 860: FreeUPNPUrls(&urls); ! 861: } ! 862: else ! 863: { ! 864: fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n"); ! 865: retcode = 1; ! 866: } ! 867: freeUPNPDevlist(devlist); devlist = 0; ! 868: } ! 869: else ! 870: { ! 871: fprintf(stderr, "No IGD UPnP Device found on the network !\n"); ! 872: retcode = 1; ! 873: } ! 874: #ifdef _WIN32 ! 875: nResult = WSACleanup(); ! 876: if(nResult != NO_ERROR) { ! 877: fprintf(stderr, "WSACleanup() failed.\n"); ! 878: } ! 879: #endif /* _WIN32 */ ! 880: return retcode; ! 881: } ! 882: