upnpc.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. /* $Id: upnpc.c,v 1.114 2016/01/22 15:04:23 nanard Exp $ */
  2. /* Project : miniupnp
  3. * Author : Thomas Bernard
  4. * Copyright (c) 2005-2016 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 void 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;
  256. }
  257. proto = protofix(proto);
  258. if(!proto)
  259. {
  260. fprintf(stderr, "invalid protocol\n");
  261. return;
  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. }
  287. r = UPNP_GetSpecificPortMappingEntry(urls->controlURL,
  288. data->first.servicetype,
  289. eport, proto, NULL/*remoteHost*/,
  290. intClient, intPort, NULL/*desc*/,
  291. NULL/*enabled*/, duration);
  292. if(r!=UPNPCOMMAND_SUCCESS)
  293. printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n",
  294. r, strupnperror(r));
  295. else {
  296. printf("InternalIP:Port = %s:%s\n", intClient, intPort);
  297. printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n",
  298. externalIPAddress, eport, proto, intClient, intPort, duration);
  299. }
  300. }
  301. static void
  302. RemoveRedirect(struct UPNPUrls * urls,
  303. struct IGDdatas * data,
  304. const char * eport,
  305. const char * proto,
  306. const char * remoteHost)
  307. {
  308. int r;
  309. if(!proto || !eport)
  310. {
  311. fprintf(stderr, "invalid arguments\n");
  312. return;
  313. }
  314. proto = protofix(proto);
  315. if(!proto)
  316. {
  317. fprintf(stderr, "protocol invalid\n");
  318. return;
  319. }
  320. r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, remoteHost);
  321. printf("UPNP_DeletePortMapping() returned : %d\n", r);
  322. }
  323. static void
  324. RemoveRedirectRange(struct UPNPUrls * urls,
  325. struct IGDdatas * data,
  326. const char * ePortStart, char const * ePortEnd,
  327. const char * proto, const char * manage)
  328. {
  329. int r;
  330. if (!manage)
  331. manage = "0";
  332. if(!proto || !ePortStart || !ePortEnd)
  333. {
  334. fprintf(stderr, "invalid arguments\n");
  335. return;
  336. }
  337. proto = protofix(proto);
  338. if(!proto)
  339. {
  340. fprintf(stderr, "protocol invalid\n");
  341. return;
  342. }
  343. r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage);
  344. printf("UPNP_DeletePortMappingRange() returned : %d\n", r);
  345. }
  346. /* IGD:2, functions for service WANIPv6FirewallControl:1 */
  347. static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data)
  348. {
  349. unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
  350. int firewallEnabled = 0, inboundPinholeAllowed = 0;
  351. UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed);
  352. printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed);
  353. printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No");
  354. bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
  355. bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
  356. packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
  357. packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
  358. printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
  359. printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
  360. }
  361. /* Test function
  362. * 1 - Add pinhole
  363. * 2 - Check if pinhole is working from the IGD side */
  364. static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data,
  365. const char * remoteaddr, const char * eport,
  366. const char * intaddr, const char * iport,
  367. const char * proto, const char * lease_time)
  368. {
  369. char uniqueID[8];
  370. /*int isWorking = 0;*/
  371. int r;
  372. char proto_tmp[8];
  373. if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time)
  374. {
  375. fprintf(stderr, "Wrong arguments\n");
  376. return;
  377. }
  378. if(atoi(proto) == 0)
  379. {
  380. const char * protocol;
  381. protocol = protofix(proto);
  382. if(protocol && (strcmp("TCP", protocol) == 0))
  383. {
  384. snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP);
  385. proto = proto_tmp;
  386. }
  387. else if(protocol && (strcmp("UDP", protocol) == 0))
  388. {
  389. snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP);
  390. proto = proto_tmp;
  391. }
  392. else
  393. {
  394. fprintf(stderr, "invalid protocol\n");
  395. return;
  396. }
  397. }
  398. r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID);
  399. if(r!=UPNPCOMMAND_SUCCESS)
  400. printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
  401. remoteaddr, eport, intaddr, iport, r, strupnperror(r));
  402. else
  403. {
  404. printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n",
  405. remoteaddr, eport, intaddr, iport, uniqueID);
  406. /*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking);
  407. if(r!=UPNPCOMMAND_SUCCESS)
  408. printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
  409. printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/
  410. }
  411. }
  412. /* Test function
  413. * 1 - Check if pinhole is working from the IGD side
  414. * 2 - Update pinhole */
  415. static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data,
  416. const char * uniqueID, const char * lease_time)
  417. {
  418. int isWorking = 0;
  419. int r;
  420. if(!uniqueID || !lease_time)
  421. {
  422. fprintf(stderr, "Wrong arguments\n");
  423. return;
  424. }
  425. r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
  426. printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
  427. if(r!=UPNPCOMMAND_SUCCESS)
  428. printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
  429. if(isWorking || r==709)
  430. {
  431. r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time);
  432. printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time);
  433. if(r!=UPNPCOMMAND_SUCCESS)
  434. printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r));
  435. }
  436. }
  437. /* Test function
  438. * Get pinhole timeout
  439. */
  440. static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data,
  441. const char * remoteaddr, const char * eport,
  442. const char * intaddr, const char * iport,
  443. const char * proto)
  444. {
  445. int timeout = 0;
  446. int r;
  447. if(!intaddr || !remoteaddr || !iport || !eport || !proto)
  448. {
  449. fprintf(stderr, "Wrong arguments\n");
  450. return;
  451. }
  452. r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout);
  453. if(r!=UPNPCOMMAND_SUCCESS)
  454. printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
  455. intaddr, iport, remoteaddr, eport, r, strupnperror(r));
  456. else
  457. printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout);
  458. }
  459. static void
  460. GetPinholePackets(struct UPNPUrls * urls,
  461. struct IGDdatas * data, const char * uniqueID)
  462. {
  463. int r, pinholePackets = 0;
  464. if(!uniqueID)
  465. {
  466. fprintf(stderr, "invalid arguments\n");
  467. return;
  468. }
  469. r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets);
  470. if(r!=UPNPCOMMAND_SUCCESS)
  471. printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r));
  472. else
  473. printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets);
  474. }
  475. static void
  476. CheckPinhole(struct UPNPUrls * urls,
  477. struct IGDdatas * data, const char * uniqueID)
  478. {
  479. int r, isWorking = 0;
  480. if(!uniqueID)
  481. {
  482. fprintf(stderr, "invalid arguments\n");
  483. return;
  484. }
  485. r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
  486. if(r!=UPNPCOMMAND_SUCCESS)
  487. printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
  488. else
  489. printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
  490. }
  491. static void
  492. RemovePinhole(struct UPNPUrls * urls,
  493. struct IGDdatas * data, const char * uniqueID)
  494. {
  495. int r;
  496. if(!uniqueID)
  497. {
  498. fprintf(stderr, "invalid arguments\n");
  499. return;
  500. }
  501. r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID);
  502. printf("UPNP_DeletePinhole() returned : %d\n", r);
  503. }
  504. /* sample upnp client program */
  505. int main(int argc, char ** argv)
  506. {
  507. char command = 0;
  508. char ** commandargv = 0;
  509. int commandargc = 0;
  510. struct UPNPDev * devlist = 0;
  511. char lanaddr[64] = "unset"; /* my ip address on the LAN */
  512. int i;
  513. const char * rootdescurl = 0;
  514. const char * multicastif = 0;
  515. const char * minissdpdpath = 0;
  516. int localport = UPNP_LOCAL_PORT_ANY;
  517. int retcode = 0;
  518. int error = 0;
  519. int ipv6 = 0;
  520. unsigned char ttl = 2; /* defaulting to 2 */
  521. const char * description = 0;
  522. #ifdef _WIN32
  523. WSADATA wsaData;
  524. int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
  525. if(nResult != NO_ERROR)
  526. {
  527. fprintf(stderr, "WSAStartup() failed.\n");
  528. return -1;
  529. }
  530. #endif
  531. printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
  532. printf(" (c) 2005-2016 Thomas Bernard.\n");
  533. printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n"
  534. "for more information.\n");
  535. /* command line processing */
  536. for(i=1; i<argc; i++)
  537. {
  538. if(0 == strcmp(argv[i], "--help") || 0 == strcmp(argv[i], "-h"))
  539. {
  540. command = 0;
  541. break;
  542. }
  543. if(argv[i][0] == '-')
  544. {
  545. if(argv[i][1] == 'u')
  546. rootdescurl = argv[++i];
  547. else if(argv[i][1] == 'm')
  548. multicastif = argv[++i];
  549. else if(argv[i][1] == 'z')
  550. {
  551. char junk;
  552. if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 ||
  553. localport<0 || localport>65535 ||
  554. (localport >1 && localport < 1024))
  555. {
  556. fprintf(stderr, "Invalid localport '%s'\n", argv[i]);
  557. localport = UPNP_LOCAL_PORT_ANY;
  558. break;
  559. }
  560. }
  561. else if(argv[i][1] == 'p')
  562. minissdpdpath = argv[++i];
  563. else if(argv[i][1] == '6')
  564. ipv6 = 1;
  565. else if(argv[i][1] == 'e')
  566. description = argv[++i];
  567. else if(argv[i][1] == 't')
  568. ttl = (unsigned char)atoi(argv[++i]);
  569. else
  570. {
  571. command = argv[i][1];
  572. i++;
  573. commandargv = argv + i;
  574. commandargc = argc - i;
  575. break;
  576. }
  577. }
  578. else
  579. {
  580. fprintf(stderr, "option '%s' invalid\n", argv[i]);
  581. }
  582. }
  583. if(!command
  584. || (command == 'a' && commandargc<4)
  585. || (command == 'd' && argc<2)
  586. || (command == 'r' && argc<2)
  587. || (command == 'A' && commandargc<6)
  588. || (command == 'U' && commandargc<2)
  589. || (command == 'D' && commandargc<1))
  590. {
  591. fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration]\n\t\tAdd port redirection\n", argv[0]);
  592. fprintf(stderr, " \t%s [options] -d external_port protocol <remote host>\n\t\tDelete port redirection\n", argv[0]);
  593. fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]);
  594. fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]);
  595. fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]);
  596. 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]);
  597. 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]);
  598. 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]);
  599. 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]);
  600. fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]);
  601. fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]);
  602. fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]);
  603. fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]);
  604. fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]);
  605. 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]);
  606. fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]);
  607. fprintf(stderr, "\nprotocol is UDP or TCP\n");
  608. fprintf(stderr, "Options:\n");
  609. fprintf(stderr, " -e description : set description for port mapping.\n");
  610. fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n");
  611. fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n");
  612. 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");
  613. fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n");
  614. fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n");
  615. fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n");
  616. return 1;
  617. }
  618. if( rootdescurl
  619. || (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
  620. localport, ipv6, ttl, &error)))
  621. {
  622. struct UPNPDev * device;
  623. struct UPNPUrls urls;
  624. struct IGDdatas data;
  625. if(devlist)
  626. {
  627. printf("List of UPNP devices found on the network :\n");
  628. for(device = devlist; device; device = device->pNext)
  629. {
  630. printf(" desc: %s\n st: %s\n\n",
  631. device->descURL, device->st);
  632. }
  633. }
  634. else if(!rootdescurl)
  635. {
  636. printf("upnpDiscover() error code=%d\n", error);
  637. }
  638. i = 1;
  639. if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr)))
  640. || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))))
  641. {
  642. switch(i) {
  643. case 1:
  644. printf("Found valid IGD : %s\n", urls.controlURL);
  645. break;
  646. case 2:
  647. printf("Found a (not connected?) IGD : %s\n", urls.controlURL);
  648. printf("Trying to continue anyway\n");
  649. break;
  650. case 3:
  651. printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL);
  652. printf("Trying to continue anyway\n");
  653. break;
  654. default:
  655. printf("Found device (igd ?) : %s\n", urls.controlURL);
  656. printf("Trying to continue anyway\n");
  657. }
  658. printf("Local LAN ip address : %s\n", lanaddr);
  659. #if 0
  660. printf("getting \"%s\"\n", urls.ipcondescURL);
  661. descXML = miniwget(urls.ipcondescURL, &descXMLsize);
  662. if(descXML)
  663. {
  664. /*fwrite(descXML, 1, descXMLsize, stdout);*/
  665. free(descXML); descXML = NULL;
  666. }
  667. #endif
  668. switch(command)
  669. {
  670. case 'l':
  671. DisplayInfos(&urls, &data);
  672. ListRedirections(&urls, &data);
  673. break;
  674. case 'L':
  675. NewListRedirections(&urls, &data);
  676. break;
  677. case 'a':
  678. SetRedirectAndTest(&urls, &data,
  679. commandargv[0], commandargv[1],
  680. commandargv[2], commandargv[3],
  681. (commandargc > 4)?commandargv[4]:"0",
  682. description, 0);
  683. break;
  684. case 'd':
  685. RemoveRedirect(&urls, &data, commandargv[0], commandargv[1],
  686. commandargc > 2 ? commandargv[2] : NULL);
  687. break;
  688. case 'n': /* aNy */
  689. SetRedirectAndTest(&urls, &data,
  690. commandargv[0], commandargv[1],
  691. commandargv[2], commandargv[3],
  692. (commandargc > 4)?commandargv[4]:"0",
  693. description, 1);
  694. break;
  695. case 'N':
  696. if (commandargc < 3)
  697. fprintf(stderr, "too few arguments\n");
  698. RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2],
  699. commandargc > 3 ? commandargv[3] : NULL);
  700. break;
  701. case 's':
  702. GetConnectionStatus(&urls, &data);
  703. break;
  704. case 'r':
  705. i = 0;
  706. while(i<commandargc)
  707. {
  708. if(!is_int(commandargv[i])) {
  709. /* 1st parameter not an integer : error */
  710. fprintf(stderr, "command -r : %s is not an port number\n", commandargv[i]);
  711. retcode = 1;
  712. break;
  713. } else if(is_int(commandargv[i+1])){
  714. /* 2nd parameter is an integer : <port> <external_port> <protocol> */
  715. SetRedirectAndTest(&urls, &data,
  716. lanaddr, commandargv[i],
  717. commandargv[i+1], commandargv[i+2], "0",
  718. description, 0);
  719. i+=3; /* 3 parameters parsed */
  720. } else {
  721. /* 2nd parameter not an integer : <port> <protocol> */
  722. SetRedirectAndTest(&urls, &data,
  723. lanaddr, commandargv[i],
  724. commandargv[i], commandargv[i+1], "0",
  725. description, 0);
  726. i+=2; /* 2 parameters parsed */
  727. }
  728. }
  729. break;
  730. case 'A':
  731. SetPinholeAndTest(&urls, &data,
  732. commandargv[0], commandargv[1],
  733. commandargv[2], commandargv[3],
  734. commandargv[4], commandargv[5]);
  735. break;
  736. case 'U':
  737. GetPinholeAndUpdate(&urls, &data,
  738. commandargv[0], commandargv[1]);
  739. break;
  740. case 'C':
  741. for(i=0; i<commandargc; i++)
  742. {
  743. CheckPinhole(&urls, &data, commandargv[i]);
  744. }
  745. break;
  746. case 'K':
  747. for(i=0; i<commandargc; i++)
  748. {
  749. GetPinholePackets(&urls, &data, commandargv[i]);
  750. }
  751. break;
  752. case 'D':
  753. for(i=0; i<commandargc; i++)
  754. {
  755. RemovePinhole(&urls, &data, commandargv[i]);
  756. }
  757. break;
  758. case 'S':
  759. GetFirewallStatus(&urls, &data);
  760. break;
  761. case 'G':
  762. GetPinholeOutboundTimeout(&urls, &data,
  763. commandargv[0], commandargv[1],
  764. commandargv[2], commandargv[3],
  765. commandargv[4]);
  766. break;
  767. case 'P':
  768. printf("Presentation URL found:\n");
  769. printf(" %s\n", data.presentationurl);
  770. break;
  771. default:
  772. fprintf(stderr, "Unknown switch -%c\n", command);
  773. retcode = 1;
  774. }
  775. FreeUPNPUrls(&urls);
  776. }
  777. else
  778. {
  779. fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
  780. retcode = 1;
  781. }
  782. freeUPNPDevlist(devlist); devlist = 0;
  783. }
  784. else
  785. {
  786. fprintf(stderr, "No IGD UPnP Device found on the network !\n");
  787. retcode = 1;
  788. }
  789. #ifdef _WIN32
  790. nResult = WSACleanup();
  791. if(nResult != NO_ERROR) {
  792. fprintf(stderr, "WSACleanup() failed.\n");
  793. }
  794. #endif /* _WIN32 */
  795. return retcode;
  796. }