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