1 /* $Id: upnpstun.c,v 1.5 2020/04/21 21:21:59 nanard Exp $ */
2 /* vim: tabstop=4 shiftwidth=4 noexpandtab
3  * MiniUPnP project
4  * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
5  * (c) 2020 Thomas Bernard
6  * (c) 2018 Pali Rohár
7  * This software is subject to the conditions detailed
8  * in the LICENCE file provided within the distribution */
9 
10 #include <sys/select.h>
11 #include <sys/time.h>
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <unistd.h>
16 #include <netdb.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <syslog.h>
20 #include <string.h>
21 #include <errno.h>
22 
23 #ifndef TEST_LINUX_DEBUG_APP
24 #include "config.h"
25 #endif
26 
27 #include "upnputils.h"
28 #include "upnpstun.h"
29 
30 #if defined(USE_NETFILTER)
31 #include "netfilter/iptcrdr.h"
32 #endif
33 #if defined(USE_PF)
34 #include "pf/obsdrdr.h"
35 #endif
36 #if defined(USE_IPF)
37 #include "ipf/ipfrdr.h"
38 #endif
39 #if defined(USE_IPFW)
40 #include "ipfw/ipfwrdr.h"
41 #endif
42 
43 #ifdef TEST_LINUX_DEBUG_APP
44 static int add_filter_rule2(const char *ifname, const char *rhost, const char *iaddr, unsigned short eport, unsigned short iport, int proto, const char *desc);
45 static int delete_filter_rule(const char * ifname, unsigned short port, int proto);
46 #define syslog(priority, format, ...) do { switch(priority) { case LOG_ERR: printf("Error: "); break; case LOG_WARNING: printf("Warning: "); } printf(format, ##__VA_ARGS__); putchar('\n'); } while (0)
47 #endif
48 
49 /* Generate random STUN Transaction Id */
generate_transaction_id(unsigned char transaction_id[12])50 static void generate_transaction_id(unsigned char transaction_id[12])
51 {
52 	size_t i;
53 
54 	for (i = 0; i < 12; i++)
55 		transaction_id[i] = random() & 255;
56 }
57 
58 /* Create and fill STUN Binding Request */
fill_request(unsigned char buffer[28],int change_ip,int change_port)59 static void fill_request(unsigned char buffer[28], int change_ip, int change_port)
60 {
61 	/* Type: Binding Request */
62 	buffer[0] = 0x00;
63 	buffer[1] = 0x01;
64 
65 	/* Length: One 8-byte attribute */
66 	buffer[2] = 0x00;
67 	buffer[3] = 0x08;
68 
69 	/* RFC5389 Magic Cookie: 0x2120A442 */
70 	buffer[4] = 0x21;
71 	buffer[5] = 0x12;
72 	buffer[6] = 0xA4;
73 	buffer[7] = 0x42;
74 
75 	/* Transaction Id */
76 	generate_transaction_id(buffer+8);
77 
78 	/* Attribute Type: Change Request */
79 	buffer[20] = 0x00;
80 	buffer[21] = 0x03;
81 
82 	/* Attribute Length: 4 bytes */
83 	buffer[22] = 0x00;
84 	buffer[23] = 0x04;
85 
86 	buffer[24] = 0x00;
87 	buffer[25] = 0x00;
88 	buffer[26] = 0x00;
89 	buffer[27] = 0x00;
90 
91 	/* Change IP */
92 	buffer[27] |= change_ip ? 0x4 : 0x00;
93 
94 	/* Change Port */
95 	buffer[27] |= change_port ? 0x2 : 0x00;
96 }
97 
98 /* Resolve STUN host+port and return sockaddr_in structure */
99 /* When port is 0 then use default STUN port */
resolve_stun_host(const char * stun_host,unsigned short stun_port,struct sockaddr_in * sock_addr)100 static int resolve_stun_host(const char *stun_host, unsigned short stun_port, struct sockaddr_in *sock_addr)
101 {
102 	int have_sock;
103 	struct addrinfo hints;
104 	struct addrinfo *result, *rp;
105 	char service[6];
106 	int r;
107 
108 	if (stun_port == 0)
109 		stun_port = (unsigned short)3478;
110 	snprintf(service, sizeof(service), "%hu", stun_port);
111 
112 	memset(&hints, 0, sizeof(hints));
113 	hints.ai_family = AF_INET;
114 	hints.ai_socktype = SOCK_DGRAM;
115 	hints.ai_protocol = IPPROTO_UDP;
116 	hints.ai_flags = AI_NUMERICSERV;
117 
118 	r = getaddrinfo(stun_host, service, &hints, &result);
119 	if (r != 0) {
120 		syslog(LOG_ERR, "%s: getaddrinfo(%s, %s, ...) failed : %s",
121 		       "resolve_stun_host", stun_host, service, gai_strerror(r));
122 		errno = EHOSTUNREACH;
123 		return -1;
124 	}
125 
126 	have_sock = 0;
127 	for (rp = result; rp != NULL; rp = rp->ai_next) {
128 		if (rp->ai_addrlen > sizeof(*sock_addr) || rp->ai_addr->sa_family != AF_INET)
129 			continue;
130 		memcpy(sock_addr, rp->ai_addr, rp->ai_addrlen);
131 		have_sock = 1;
132 		break;
133 	}
134 
135 	freeaddrinfo(result);
136 
137 	if (!have_sock) {
138 		syslog(LOG_WARNING, "%s: failed to resolve IPv4 address for %s:%s",
139 		       "resolve_stun_host", stun_host, service);
140 		errno = EHOSTUNREACH;
141 		return -1;
142 	} else {
143 		char addr_str[48];
144 		if (sockaddr_to_string((struct sockaddr *)sock_addr, addr_str, sizeof(addr_str)) > 0) {
145 			syslog(LOG_DEBUG, "%s: %s:%s => %s",
146 			       "resolve_stun_host", stun_host, service, addr_str);
147 		}
148 	}
149 
150 	return 0;
151 }
152 
153 /* Create a new UDP socket for STUN connection and return file descriptor and local UDP port */
stun_socket(unsigned short * local_port)154 static int stun_socket(unsigned short *local_port)
155 {
156 	int fd;
157 	socklen_t addr_len;
158 	struct sockaddr_in local_addr;
159 
160 	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
161 	if (fd < 0) {
162 		syslog(LOG_ERR, "%s: socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP): %m",
163 		       "stun_socket");
164 		return -1;
165 	}
166 
167 	memset(&local_addr, 0, sizeof(local_addr));
168 	local_addr.sin_family = AF_INET;
169 	local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
170 	local_addr.sin_port = 0;
171 
172 	if (bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr)) != 0) {
173 		syslog(LOG_ERR, "%s: bind(): %m",
174 		       "stun_socket");
175 		close(fd);
176 		return -1;
177 	}
178 
179 	addr_len = sizeof(local_addr);
180 	if (getsockname(fd, (struct sockaddr *)&local_addr, &addr_len) != 0) {
181 		syslog(LOG_ERR, "%s: getsockname(): %m",
182 		       "stun_socket");
183 		close(fd);
184 		return -1;
185 	}
186 
187 	*local_port = ntohs(local_addr.sin_port);
188 
189 	return fd;
190 }
191 
192 /* Receive STUN response message for specified Transaction Id and returns message and peer address */
receive_stun_response(int fd,unsigned char * buffer,unsigned char transaction_id[12],size_t buffer_len,struct sockaddr_in * peer_addr)193 static size_t receive_stun_response(int fd, unsigned char *buffer, unsigned char transaction_id[12], size_t buffer_len, struct sockaddr_in *peer_addr)
194 {
195 	ssize_t len;
196 	socklen_t peer_addr_len = sizeof(*peer_addr);
197 
198 	len = recvfrom(fd, buffer, buffer_len, 0, (struct sockaddr *)peer_addr, &peer_addr_len);
199 	if (len < 0) {
200 		syslog(LOG_ERR, "%s: recvfrom(): %m", "receive_stun_response");
201 		return 0;
202 	}
203 	if (peer_addr_len != sizeof(*peer_addr)) {
204 		syslog(LOG_ERR, "%s: recvfrom(): peer_addr_len mismatch",
205 		       "receive_stun_response");
206 		return 0;
207 	}
208 	if (len < 20) {
209 		syslog(LOG_WARNING, "%s: response too short : %ld",
210 		       "receive_stun_response", (long)len);
211 		return 0;
212 	}
213 
214 	/* Check that buffer is STUN message with class Response
215 	 * and Binding method with transaction id */
216 	if ((buffer[0] & 0xFF) != 0x01 || (buffer[1] & 0xEF) != 0x01) {
217 		syslog(LOG_WARNING, "%s: STUN message type is 0x%02x%02x",
218 		       "receive_stun_response", buffer[0], buffer[1]);
219 		return 0;
220 	}
221 	if (memcmp(buffer+8, transaction_id, 12) != 0) {
222 		syslog(LOG_WARNING, "%s: transaction id mismatch",
223 		       "receive_stun_response");
224 		return 0;
225 	}
226 
227 	return len;
228 }
229 
230 /* Wait for STUN response messages and try to receive them */
wait_for_stun_responses(int fds[4],unsigned char * transaction_ids[4],unsigned char * buffers[4],size_t buffers_lens[4],struct sockaddr_in peer_addrs[4],size_t lens[4])231 static int wait_for_stun_responses(int fds[4], unsigned char *transaction_ids[4], unsigned char *buffers[4], size_t buffers_lens[4], struct sockaddr_in peer_addrs[4], size_t lens[4])
232 {
233 	fd_set fdset;
234 	struct timeval timeout;
235 	int max_fd;
236 	int ret;
237 	int i;
238 
239 	max_fd = fds[0];
240 	for (i = 1; i < 4; i++) {
241 		if (fds[i] > max_fd)
242 			max_fd = fds[i];
243 	}
244 
245 	timeout.tv_sec = 3;
246 	timeout.tv_usec = 0;
247 
248 	while (timeout.tv_sec > 0 || timeout.tv_usec > 0) {
249 
250 		FD_ZERO(&fdset);
251 		for (i = 0; i < 4; i++) {
252 			FD_SET(fds[i], &fdset);
253 		}
254 
255 		syslog(LOG_DEBUG, "%s: waiting %ld secs and %ld usecs", "wait_for_stun_responses", (long)timeout.tv_sec, (long)timeout.tv_usec);
256 		ret = select(max_fd+1, &fdset, NULL, NULL, &timeout);
257 		if (ret < 0) {
258 			if (errno == EINTR)
259 				continue;
260 			syslog(LOG_ERR, "%s: select(): %m", "wait_for_stun_responses");
261 			return -1;
262 		}
263 		if (ret == 0) {
264 			syslog(LOG_DEBUG, "%s: select(): no more responses", "wait_for_stun_responses");
265 			return 0;
266 		}
267 
268 		for (i = 0; i < 4; ++i)
269 			if (FD_ISSET(fds[i], &fdset))
270 				lens[i] = receive_stun_response(fds[i], buffers[i], transaction_ids[i], buffers_lens[i], &peer_addrs[i]);
271 
272 		syslog(LOG_DEBUG, "%s: received responses: %u", "wait_for_stun_responses", (unsigned)(!!lens[0] + !!lens[1] + !!lens[2] + !!lens[3]));
273 
274 		if (lens[0] && lens[1] && lens[2] && lens[3])
275 			return 0;
276 	}
277 
278 	return 0;
279 }
280 
281 /* Parse Mapped Address (with port) from STUN response message */
parse_stun_response(unsigned char * buffer,size_t len,struct sockaddr_in * mapped_addr)282 static int parse_stun_response(unsigned char *buffer, size_t len, struct sockaddr_in *mapped_addr)
283 {
284 	unsigned char *ptr, *end;
285 	uint16_t attr_type;
286 	uint16_t attr_len;
287 	int have_address;
288 	int have_xor_mapped_address;
289 
290 	if (len < 20)
291 		return -1;
292 
293 	syslog(LOG_DEBUG, "%s: Type 0x%04x, Length %hu, Magic Cookie %02x%02x%02x%02x",
294 	       "parse_stun_response", ((uint16_t)buffer[0] << 8) + buffer[1],
295 	       (uint16_t)((buffer[2] << 8) + buffer[3]),
296 	       buffer[4], buffer[5], buffer[6], buffer[7]);
297 
298 	/* Check that buffer is STUN message with class Response and Binding method */
299 	if (buffer[0] != 0x01 || (buffer[1] & 0xEF) != 0x01)
300 		return -1;
301 
302 	/* Check that STUN message is not longer as buffer length */
303 	if (((size_t)buffer[2] << 8) + buffer[3] + 20 > len) {
304 		syslog(LOG_ERR, "%s: truncated STUN response", "parse_stun_response");
305 		return -1;
306 	}
307 
308 	ptr = buffer + 20;
309 	end = buffer + len;
310 	have_address = 0;
311 	have_xor_mapped_address = 0;
312 
313 	while (ptr + 4 <= end) {
314 
315 		attr_type = ((uint16_t)ptr[0] << 8) + ptr[1];
316 		attr_len = ((uint16_t)ptr[2] << 8) + ptr[3];
317 		ptr += 4;
318 
319 		if (ptr + attr_len > end) {
320 			syslog(LOG_WARNING, "%s: truncated attribute", "parse_stun_response");
321 			break;
322 		}
323 
324 		switch (attr_type) {
325 		case 0x0001:	/* MAPPED-ADDRESS */
326 		case 0x0020:	/* XOR-MAPPED-ADDRESS (RFC 5389) */
327 		case 0x8020:	/* XOR-MAPPED-ADDRESS (2005 draft) */
328 			/* Mapped Address or XOR Mapped Address */
329 			if (attr_len == 8 && ptr[1] == 1) {
330 				/* IPv4 address */
331 				if ((attr_type & 0x7fff) == 0x0020) {
332 					/* Restore XOR Mapped Address */
333 					ptr[2] ^= buffer[4];
334 					ptr[3] ^= buffer[5];
335 					ptr[4] ^= buffer[4];
336 					ptr[5] ^= buffer[5];
337 					ptr[6] ^= buffer[6];
338 					ptr[7] ^= buffer[7];
339 				}
340 
341 				syslog(LOG_DEBUG, "%s: %s %hhu.%hhu.%hhu.%hhu:%hu",
342 				       "parse_stun_response",
343 				       ((attr_type & 0x7fff) == 0x0020) ? "XOR-MAPPED-ADDRESS" : "MAPPED-ADDRESS",
344 				       ptr[4], ptr[5], ptr[6], ptr[7],
345 				       (uint16_t)((ptr[2] << 8) + ptr[3]));
346 
347 				/* Prefer XOR Mapped Address, some NATs change IP addresses in UDP packets */
348 				if (!have_xor_mapped_address) {
349 					mapped_addr->sin_family = AF_INET;
350 					mapped_addr->sin_port = htons(((uint16_t)ptr[2] << 8) + ptr[3]);
351 					mapped_addr->sin_addr.s_addr = htonl(((uint32_t)ptr[4] << 24) + (ptr[5] << 16) + (ptr[6] << 8) + ptr[7]);
352 				}
353 
354 				if ((attr_type & 0x7fff) == 0x0020)
355 					have_xor_mapped_address = 1;
356 
357 				have_address = 1;
358 			}
359 			break;
360 		case 0x0009:	/* ERROR-CODE */
361 			if (attr_len >= 4) {
362 				syslog(LOG_WARNING, "%s: ERROR-CODE %u %.*s",
363 			       "parse_stun_response", (unsigned)ptr[2] * 100 + ptr[3],
364 			       attr_len - 4, ptr + 4);
365 			}
366 			break;
367 		case 0x0004:	/* SOURCE-ADDRESS (RFC 3489) */
368 		case 0x0005:	/* CHANGED-ADDRESS (RFC 3489) */
369 		case 0x802b:	/* RESPONSE-ORIGIN (RFC 5780) */
370 		case 0x802c:	/* OTHER-ADDRESS (RFC 5780) */
371 			if (attr_len == 8 && ptr[1] == 1) {
372 				syslog(LOG_DEBUG, "%s: %s %hhu.%hhu.%hhu.%hhu:%hu",
373 				       "parse_stun_response",
374 				       (attr_type == 0x0004) ? "SOURCE-ADDRESS" :
375 				       (attr_type == 0x0005) ? "CHANGED-ADDRESS" :
376 				       (attr_type == 0x802b) ? "RESPONSE-ORIGIN" : "OTHER-ADDRESS",
377 				       ptr[4], ptr[5], ptr[6], ptr[7],
378 				       (uint16_t)((ptr[2] << 8) + ptr[3]));
379 			}
380 			break;
381 		case 0x8022:	/* SOFTWARE (RFC 5780) */
382 			syslog(LOG_DEBUG, "%s: SOFTWARE %.*s", "parse_stun_response", attr_len, ptr);
383 			break;
384 		default:
385 			syslog(LOG_WARNING, "%s: unknown attribute type 0x%04x (len=%hu)",
386 			       "parse_stun_response", attr_type, attr_len);
387 		}
388 
389 		ptr += attr_len;
390 	}
391 
392 	return have_address ? 0 : -1;
393 }
394 
395 /* Perform main STUN operation, return external IP address and check
396  * if host is behind restrictive, symmetric NAT or behind firewall.
397  * Restrictive NAT means any NAT which do some filtering and
398  * which is not static full-cone NAT 1:1, basically NAT which is not usable
399  * for port forwarding */
perform_stun(const char * if_name,const char * if_addr,const char * stun_host,unsigned short stun_port,struct in_addr * ext_addr,int * restrictive_nat)400 int perform_stun(const char *if_name, const char *if_addr, const char *stun_host, unsigned short stun_port, struct in_addr *ext_addr, int *restrictive_nat)
401 {
402 	int fds[4];
403 	size_t responses_lens[4];
404 	unsigned char responses_bufs[4][1024];
405 	unsigned char *responses[4];
406 	size_t responses_sizes[4];
407 	unsigned char requests[4][28];
408 	unsigned char *transaction_ids[4];
409 	int have_mapped_addr, mapped_addrs_count;
410 	struct sockaddr_in remote_addr, peer_addrs[4], mapped_addrs[4];
411 	unsigned short local_ports[4];
412 	int have_ext_addr;
413 	int i, j;
414 
415 	if (resolve_stun_host(stun_host, stun_port, &remote_addr) != 0)
416 		return -1;
417 
418 	/* Prepare four different STUN requests */
419 	for (i = 0; i < 4; ++i) {
420 
421 		responses_lens[i] = 0;
422 		responses[i] = responses_bufs[i];
423 		responses_sizes[i] = sizeof(responses_bufs[i]);
424 
425 		fds[i] = stun_socket(&local_ports[i]);
426 		if (fds[i] < 0) {
427 			for (j = 0; j < i; ++j)
428 				close(fds[j]);
429 			return -1;
430 		}
431 
432 		fill_request(requests[i], i/2, i%2);
433 		transaction_ids[i] = requests[i]+8;
434 	}
435 
436 	syslog(LOG_INFO, "%s: local ports %hu %hu %hu %hu",
437 	       "perform_stun", local_ports[0], local_ports[1],
438 	       local_ports[2], local_ports[3]);
439 
440 	/* Unblock local ports */
441 	for (i = 0; i < 4; ++i) {
442 		if (add_filter_rule2(if_name, NULL, if_addr, local_ports[i], local_ports[i], IPPROTO_UDP, "stun test") < 0) {
443 			syslog(LOG_ERR, "%s: add_filter_rule2(..., %hu, ...) FAILED",
444 			       "perform_stun", local_ports[i]);
445 		}
446 	}
447 
448 	/* Send STUN requests and wait for responses */
449 	for (j = 0; j < 3; ++j) {
450 
451 		for (i = 0; i < 4; ++i) {
452 			ssize_t n;
453 			if (responses_lens[i])
454 				continue;
455 			n = sendto(fds[i], requests[i], sizeof(requests[i]), 0, (struct sockaddr *)&remote_addr, sizeof(remote_addr));
456 			if (n != sizeof(requests[i])) {
457 				syslog(LOG_ERR, "%s: #%d,%d sendto(): %m", "perform_stun", j, i);
458 				break;
459 			}
460 		}
461 
462 		if (wait_for_stun_responses(fds, transaction_ids, responses, responses_sizes, peer_addrs, responses_lens) != 0)
463 			break;
464 
465 		if (responses_lens[0] && responses_lens[1] && responses_lens[2] && responses_lens[3])
466 			break;
467 
468 	}
469 
470 	/* Remove unblock for local ports */
471 	for (i = 0; i < 4; ++i) {
472 		delete_filter_rule(if_name, local_ports[i], IPPROTO_UDP);
473 		close(fds[i]);
474 	}
475 
476 	/* Parse received STUN messages */
477 	have_ext_addr = 0;
478 	have_mapped_addr = 0;
479 	mapped_addrs_count = 0;
480 	for (i = 0; i < 4; ++i) {
481 		if (parse_stun_response(responses[i], responses_lens[i], &mapped_addrs[i]) == 0) {
482 			mapped_addrs_count++;
483 			have_mapped_addr |= (1 << i);
484 			if (!have_ext_addr) {
485 				memcpy(ext_addr, &mapped_addrs[i].sin_addr, sizeof(*ext_addr));
486 				have_ext_addr = 1;
487 			}
488 		}
489 	}
490 
491 	/* We have no external address */
492 	if (!have_ext_addr) {
493 		errno = ENXIO;
494 		return -1;
495 	}
496 
497 	*restrictive_nat = 0;
498 
499 	if (mapped_addrs_count < 4) {
500 		/* We have not received all four responses,
501 		 * therefore NAT or firewall is doing some filtering */
502 		syslog(LOG_NOTICE, "%s: %d response out of 4 received",
503 		       "perform_stun", mapped_addrs_count);
504 		*restrictive_nat = 1;
505 	}
506 
507 	if (memcmp(&remote_addr, &peer_addrs[0], sizeof(peer_addrs[0])) != 0) {
508 		/* We received STUN response from different address
509 		 * even we did not asked for it, so some strange NAT is active */
510 		syslog(LOG_NOTICE, "%s: address changed",
511 		       "perform_stun");
512 		*restrictive_nat = 1;
513 	}
514 
515 	for (i = 0; i < 4; ++i) {
516 		if (!(have_mapped_addr & (1 << i)))
517 			continue;
518 		if (ntohs(mapped_addrs[i].sin_port) != local_ports[i] || memcmp(&mapped_addrs[i].sin_addr, ext_addr, sizeof(*ext_addr)) != 0) {
519 			/* External IP address or port was changed,
520 			 * therefore symmetric NAT is active */
521 			syslog(LOG_NOTICE, "%s: #%d external address or port changed",
522 			       "perform_stun", i);
523 			*restrictive_nat = 1;
524 		}
525 	}
526 
527 	/* Otherwise we are either directly connected or behind unrestricted full-cone NAT 1:1 without filtering */
528 	/* There is no filtering, so port forwarding would work fine */
529 	return 0;
530 }
531 
532 #ifdef TEST_LINUX_DEBUG_APP
533 
534 /* This linux test application for debugging purposes can be compiled as: */
535 /* gcc upnpstun.c upnputils.o -o upnpstun -g3 -W -Wall -O2 -DTEST_LINUX_DEBUG_APP */
536 
537 #include <arpa/inet.h>
538 #include <time.h>
539 
540 #include "upnpglobalvars.h"
541 struct lan_addr_list lan_addrs;
542 int runtime_flags = 0;
543 time_t startup_time = 0;
544 
add_filter_rule2(const char * ifname,const char * rhost,const char * iaddr,unsigned short eport,unsigned short iport,int proto,const char * desc)545 static int add_filter_rule2(const char *ifname, const char *rhost, const char *iaddr, unsigned short eport, unsigned short iport, int proto, const char *desc)
546 {
547 	char buffer[100];
548 	ifname = ifname;
549 	rhost = rhost;
550 	iaddr = iaddr;
551 	iport = iport;
552 	desc = desc;
553 	snprintf(buffer, sizeof(buffer), "/sbin/iptables -t filter -I INPUT -p %d --dport %hu -j ACCEPT", proto, eport);
554 	printf("Executing: %s\n", buffer);
555 	return system(buffer);
556 }
557 
delete_filter_rule(const char * ifname,unsigned short port,int proto)558 static int delete_filter_rule(const char * ifname, unsigned short port, int proto)
559 {
560 	char buffer[100];
561 	ifname = ifname;
562 	snprintf(buffer, sizeof(buffer), "/sbin/iptables -t filter -D INPUT -p %d --dport %hu -j ACCEPT", proto, port);
563 	printf("Executing: %s\n", buffer);
564 	return system(buffer);
565 }
566 
main(int argc,char * argv[])567 int main(int argc, char *argv[])
568 {
569 	struct in_addr ext_addr;
570 	int restrictive_nat;
571 	int ret;
572 	char str[INET_ADDRSTRLEN];
573 
574 	if (argc != 3 && argc != 2) {
575 		printf("Usage: %s stun_host [stun_port]\n", argv[0]);
576 		return 1;
577 	}
578 
579 	if (geteuid() != 0) {
580 		printf("You need to run this application as root\n");
581 		return 1;
582 	}
583 
584 	if (argc == 2)
585 		argv[2] = "0";
586 
587 	srandom(time(NULL) * getpid());
588 
589 	ret = perform_stun(NULL, NULL, argv[1], atoi(argv[2]), &ext_addr, &restrictive_nat);
590 	if (ret != 0) {
591 		printf("STUN Failed: %s\n", strerror(errno));
592 		return 1;
593 	}
594 
595 	if (!inet_ntop(AF_INET, &ext_addr, str, INET_ADDRSTRLEN))
596 		str[0] = 0;
597 
598 	printf("External IP address: %s\n", str);
599 	printf("Restrictive NAT: %s\n", restrictive_nat ? "active (port forwarding impossible)" : "not used (ready for port forwarding)");
600 	return 0;
601 }
602 
603 #endif
604