upnpc.c 27 KB

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