upnpc.c 27 KB

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