upnpc.c 26 KB

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