1 /*
2 * Copyright (C) 2011, 2012, 2013 Citrix Systems
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30 
31 #include <err.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37 
38 #include "ns_turn_utils.h"
39 #include "apputils.h"
40 #include "stun_buffer.h"
41 
42 #ifdef __cplusplus
43 #include "TurnMsgLib.h"
44 #endif
45 
46 ////////////////////////////////////////////////////
47 static int udp_fd = -1;
48 static int udp_fd2 = -1;
49 
50 static int counter = 0;
51 
52 #ifdef __cplusplus
53 
54 
init_socket(int * socketfd,ioa_addr * local_addr,int local_port,ioa_addr * remote_addr)55 static int init_socket(int *socketfd, ioa_addr *local_addr, int local_port, ioa_addr *remote_addr){
56 	int ret=0;
57 
58 	if (local_port >= 0) {
59 		addr_set_port(local_addr, local_port);
60 	}
61 
62 	*socketfd = socket(remote_addr->ss.sa_family, SOCK_DGRAM, 0);
63 	if (udp_fd < 0)
64 	err(-1, NULL);
65 
66 	if (!addr_any(local_addr)) {
67 		if (addr_bind(*socketfd, local_addr,0,1,UDP_SOCKET) < 0)
68 		err(-1, NULL);
69 	}
70 
71 	return ret;
72 }
73 
74 
stunclient_send(int sockfd,ioa_addr * local_addr,int * local_port,ioa_addr * remote_addr,int change_ip,int change_port,int padding,int response_port)75 static int stunclient_send(int sockfd, ioa_addr *local_addr, int *local_port, ioa_addr *remote_addr, int change_ip, int change_port, int padding, int response_port){
76 	int ret=0;
77 
78 	turn::StunMsgRequest req(STUN_METHOD_BINDING);
79 
80 	req.constructBindingRequest();
81 
82 	if (response_port >= 0) {
83 		turn::StunAttrResponsePort rpa;
84 		rpa.setResponsePort((uint16_t)response_port);
85 		try {
86 			req.addAttr(rpa);
87 		} catch(turn::WrongStunAttrFormatException &ex1) {
88 			printf("Wrong rp attr format\n");
89 			exit(-1);
90 		} catch(turn::WrongStunBufferFormatException &ex2) {
91 			printf("Wrong stun buffer format (1)\n");
92 			exit(-1);
93 		} catch(...) {
94 			printf("Wrong something (1)\n");
95 			exit(-1);
96 		}
97 	}
98 	if (change_ip || change_port) {
99 		turn::StunAttrChangeRequest cra;
100 		cra.setChangeIp(change_ip);
101 		cra.setChangePort(change_port);
102 		try {
103 			req.addAttr(cra);
104 		} catch(turn::WrongStunAttrFormatException &ex1) {
105 			printf("Wrong cr attr format\n");
106 			exit(-1);
107 		} catch(turn::WrongStunBufferFormatException &ex2) {
108 			printf("Wrong stun buffer format (2)\n");
109 			exit(-1);
110 		} catch(...) {
111 			printf("Wrong something (2)\n");
112 			exit(-1);
113 		}
114 	}
115 	if (padding) {
116 		turn::StunAttrPadding pa;
117 		pa.setPadding(1500);
118 		try {
119 			req.addAttr(pa);
120 		} catch(turn::WrongStunAttrFormatException &ex1) {
121 			printf("Wrong p attr format\n");
122 			exit(-1);
123 		} catch(turn::WrongStunBufferFormatException &ex2) {
124 			printf("Wrong stun buffer format (3)\n");
125 			exit(-1);
126 		} catch(...) {
127 			printf("Wrong something (3)\n");
128 			exit(-1);
129 		}
130 	}
131 
132 	{
133 		int len = 0;
134 		int slen = get_ioa_addr_len(remote_addr);
135 
136 		do {
137 			len = sendto(sockfd, req.getRawBuffer(), req.getSize(), 0, (struct sockaddr*) remote_addr, (socklen_t) slen);
138 		} while (len < 0 && ((errno == EINTR) || (errno == ENOBUFS) || (errno == EAGAIN)));
139 
140 		if (len < 0)
141 		err(-1, NULL);
142 
143 	}
144 
145 	if (addr_get_from_sock(sockfd, local_addr) < 0) {
146 		printf("%s: Cannot get address from local socket\n", __FUNCTION__);
147 	} else {
148 		*local_port = addr_get_port(local_addr);
149 	}
150 
151 	return ret;
152 }
153 
154 
stunclient_receive(int sockfd,ioa_addr * local_addr,ioa_addr * reflexive_addr,ioa_addr * other_addr,int * rfc5780)155 static int stunclient_receive(int sockfd, ioa_addr *local_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *rfc5780){
156 	int ret=0;
157 
158 
159 	{
160 		int len = 0;
161 		stun_buffer buf;
162 		uint8_t *ptr = buf.buf;
163 		int recvd = 0;
164 		const int to_recv = sizeof(buf.buf);
165 		struct timeval tv;
166 
167 		tv.tv_sec = 3;  /* 3 Secs Timeout */
168 		tv.tv_usec = 0;  // Not init'ing this can cause strange errors
169 
170 		setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
171 
172 		do {
173 			len = recv(sockfd, ptr, to_recv - recvd, 0);
174 			if (len > 0) {
175 				recvd += len;
176 				ptr += len;
177 				break;
178 			}
179 		} while (len < 0 && (errno == EINTR));
180 
181 		if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
182 			printf("STUN receive timeout..\n");
183 			ret = 1;
184 			return ret;
185 		}
186 		if (recvd > 0)
187 		len = recvd;
188 		buf.len = len;
189 
190 		try {
191 			turn::StunMsgResponse res(buf.buf, sizeof(buf.buf), (size_t)buf.len, true);
192 
193 			if (res.isCommand()) {
194 				if(res.isSuccess()) {
195 
196 					if (res.isBindingResponse()) {
197 
198 						turn::StunAttrIterator iter(res,STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS);
199 						if (!iter.eof()) {
200 
201 							turn::StunAttrAddr addr(iter);
202 							addr.getAddr(*reflexive_addr);
203 
204 							turn::StunAttrIterator iter1(res,STUN_ATTRIBUTE_OTHER_ADDRESS);
205 							if (!iter1.eof()) {
206 								*rfc5780 = 1;
207 								printf("\n========================================\n");
208 								printf("RFC 5780 response %d\n",++counter);
209 								turn::StunAttrIterator iter2(res,STUN_ATTRIBUTE_MAPPED_ADDRESS);
210 								if (!iter2.eof()) {
211 									ioa_addr mapped_addr;
212 									addr_set_any(&mapped_addr);
213 									turn::StunAttrAddr addr2(iter2);
214 									addr2.getAddr(mapped_addr);
215 									if (!addr_eq(&mapped_addr,reflexive_addr)){
216 										printf("-= ALG detected! Mapped and XOR-Mapped differ! =-\n");
217 										addr_debug_print(1, &mapped_addr, "Mapped Address: ");
218 									} else {
219 										printf("No ALG: Mapped == XOR-Mapped\n");
220 									}
221 								} else {
222 									printf("Not received mapped address attribute!\n");
223 								}									turn::StunAttrAddr addr1(iter1);
224 								addr1.getAddr(*other_addr);
225 								turn::StunAttrIterator iter3(res,STUN_ATTRIBUTE_RESPONSE_ORIGIN);
226 								if (!iter3.eof()) {
227 									ioa_addr response_origin;
228 									turn::StunAttrAddr addr3(iter3);
229 									addr3.getAddr(response_origin);
230 									addr_debug_print(1, &response_origin, "Response origin: ");
231 								}
232 								addr_debug_print(1, other_addr, "Other addr: ");
233 							}
234 							addr_debug_print(1, reflexive_addr, "UDP reflexive addr");
235 							addr_debug_print(1, local_addr, "Local addr: ");
236 						} else {
237 							printf("Cannot read the response\n");
238 						}
239 					} else {
240 						printf("Wrong type of response\n");
241 					}
242 				} else {
243 					int err_code = res.getError();
244 					std::string reason = res.getReason();
245 
246 					printf("The response is an error %d (%s)\n", err_code, reason.c_str());
247 				}
248 			} else {
249 				printf("The response is not a response message\n");
250 			}
251 		} catch(...) {
252 			turn::StunMsgRequest msg(buf.buf, sizeof(buf.buf), (size_t)buf.len, true);
253 			if (msg.isRequest(buf.buf,(size_t)buf.len)) {
254 				printf("Received a request (maybe a successful hairpinning)\n");
255 				return ret;
256 			} else {
257 				printf("The response is not a well formed STUN message\n");
258 			}
259 			ret=1;
260 		}
261 	}
262 
263 	return ret;
264 }
265 
266 
run_stunclient(ioa_addr * local_addr,ioa_addr * remote_addr,ioa_addr * reflexive_addr,ioa_addr * other_addr,int * local_port,int * rfc5780,int change_ip,int change_port,int padding)267 static int run_stunclient(ioa_addr *local_addr, ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *local_port, int *rfc5780,	int change_ip, int change_port, int padding){
268 	int ret=0;
269 
270 	ret=init_socket(&udp_fd, local_addr, *local_port, remote_addr);
271 	ret=stunclient_send(udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1);
272 	ret=stunclient_receive(udp_fd, local_addr, reflexive_addr, other_addr, rfc5780);
273 	close(udp_fd);
274 
275 	return ret;
276 }
277 
278 
run_stunclient_hairpinning(ioa_addr * local_addr,ioa_addr * remote_addr,ioa_addr * reflexive_addr,ioa_addr * other_addr,int * local_port,int * rfc5780,int change_ip,int change_port,int padding)279 static int run_stunclient_hairpinning(ioa_addr *local_addr, ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *local_port, int *rfc5780,	int change_ip, int change_port, int padding){
280 	int ret=0;
281 
282 	init_socket(&udp_fd,local_addr,*local_port,remote_addr);
283 
284 	ret=stunclient_send(udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1);
285 	ret=stunclient_receive(udp_fd, local_addr, reflexive_addr, other_addr, rfc5780);
286 
287 
288 	addr_cpy(remote_addr,reflexive_addr);
289 	addr_set_port(local_addr, 0);
290 
291 	init_socket(&udp_fd2,local_addr,0,remote_addr);
292 
293 	ret=stunclient_send(udp_fd2, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1);
294 	ret=stunclient_receive(udp_fd, local_addr, reflexive_addr, other_addr, rfc5780);
295 
296 	if(ret){
297 		ret=stunclient_receive(udp_fd2, local_addr, reflexive_addr, other_addr, rfc5780);
298 	}
299 	close(udp_fd);
300 	close(udp_fd2);
301 
302 	return ret;
303 }
304 
run_stunclient_lifetime(int timer,ioa_addr * local_addr,ioa_addr * remote_addr,ioa_addr * reflexive_addr,ioa_addr * other_addr,int * local_port,int * rfc5780,int change_ip,int change_port,int padding)305 static int run_stunclient_lifetime(int timer,ioa_addr *local_addr, ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *local_port, int *rfc5780, int change_ip, int change_port, int padding){
306 	int ret=0;
307 	int response_port;
308 
309 	init_socket(&udp_fd, local_addr, *local_port, remote_addr);
310 
311 	ret=stunclient_send(udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1);
312 	ret=stunclient_receive(udp_fd, local_addr, reflexive_addr, other_addr, rfc5780);
313 
314 	addr_set_port(local_addr, 0);
315 	sleep(timer);
316 
317 	init_socket(&udp_fd2,local_addr,0,remote_addr);
318 	response_port=addr_get_port(reflexive_addr);
319 
320 	ret=stunclient_send(udp_fd2, local_addr, local_port, remote_addr, change_ip, change_port, padding, response_port);
321 	ret=stunclient_receive(udp_fd, local_addr, reflexive_addr, other_addr, rfc5780);
322 
323 	socket_closesocket(udp_fd);
324 	socket_closesocket(udp_fd2);
325 
326 	return ret;
327 }
328 
329 #else
330 
init_socket(int * socketfd,ioa_addr * local_addr,int local_port,ioa_addr * remote_addr)331 static int init_socket(int *socketfd, ioa_addr *local_addr, int local_port, ioa_addr *remote_addr){
332 	int ret=0;
333 
334 	*socketfd = socket(remote_addr->ss.sa_family, CLIENT_DGRAM_SOCKET_TYPE, CLIENT_DGRAM_SOCKET_PROTOCOL);
335 	if (udp_fd < 0)
336 	err(-1, NULL);
337 
338 	if (local_port >= 0) {
339 		addr_set_port(local_addr, local_port);
340 	}
341 	if (!addr_any(local_addr)) {
342 		if (addr_bind(*socketfd, local_addr,0,1,UDP_SOCKET) < 0) {
343 			err(-1, NULL);
344 		}
345 	}
346 
347 	return ret;
348 }
349 
stunclient_send(stun_buffer * buf,int sockfd,ioa_addr * local_addr,int * local_port,ioa_addr * remote_addr,int change_ip,int change_port,int padding,int response_port)350 static int stunclient_send(stun_buffer *buf, int sockfd, ioa_addr *local_addr, int *local_port, ioa_addr *remote_addr, int change_ip, int change_port, int padding, int response_port){
351 	int ret=0;
352 
353 	stun_prepare_binding_request(buf);
354 
355 	if (response_port >= 0) {
356 		stun_attr_add_response_port_str((uint8_t*) (buf->buf), (size_t*) &(buf->len), (uint16_t) response_port);
357 	}
358 	if (change_ip || change_port) {
359 		stun_attr_add_change_request_str((uint8_t*) buf->buf, (size_t*) &(buf->len), change_ip, change_port);
360 	}
361 	if (padding) {
362 		if(stun_attr_add_padding_str((uint8_t*) buf->buf, (size_t*) &(buf->len), 1500)<0) {
363 			printf("%s: ERROR: Cannot add padding\n",__FUNCTION__);
364 		}
365 	}
366 
367 	{
368 		int len = 0;
369 		int slen = get_ioa_addr_len(remote_addr);
370 
371 		do {
372 			len = sendto(sockfd, buf->buf, buf->len, 0, (struct sockaddr*) remote_addr, (socklen_t) slen);
373 		} while (len < 0 && ((errno == EINTR) || (errno == ENOBUFS) || (errno == EAGAIN)));
374 
375 		if (len < 0)
376 		err(-1, NULL);
377 
378 	}
379 
380 	if (addr_get_from_sock(sockfd, local_addr) < 0) {
381 		printf("%s: Cannot get address from local socket\n", __FUNCTION__);
382 	} else {
383 		*local_port = addr_get_port(local_addr);
384 	}
385 
386 	return ret;
387 }
388 
389 
stunclient_receive(stun_buffer * buf,int sockfd,ioa_addr * local_addr,ioa_addr * reflexive_addr,ioa_addr * other_addr,int * rfc5780)390 static int stunclient_receive(stun_buffer *buf, int sockfd, ioa_addr *local_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *rfc5780){
391 	int ret=0;
392 
393 
394 	{
395 		int len = 0;
396 		uint8_t *ptr = buf->buf;
397 		int recvd = 0;
398 		const int to_recv = sizeof(buf->buf);
399 		struct timeval tv;
400 
401 		tv.tv_sec = 3;  /* 3 Secs Timeout */
402 		tv.tv_usec = 0;  // Not init'ing this can cause strange errors
403 
404 		setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
405 
406 		do {
407 			len = recv(sockfd, ptr, to_recv - recvd, 0);
408 			if (len > 0) {
409 				recvd += len;
410 				ptr += len;
411 				break;
412 			}
413 		} while (len < 0 && (errno == EINTR));
414 
415 		if (recvd > 0)
416 		len = recvd;
417 		buf->len = len;
418 
419 		if (stun_is_command_message(buf)) {
420 
421 			if (stun_is_response(buf)) {
422 
423 				if (stun_is_success_response(buf)) {
424 
425 					if (stun_is_binding_response(buf)) {
426 
427 						addr_set_any(reflexive_addr);
428 						if (stun_attr_get_first_addr(buf, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, reflexive_addr, NULL) >= 0) {
429 
430 							stun_attr_ref sar = stun_attr_get_first_by_type_str(buf->buf, buf->len, STUN_ATTRIBUTE_OTHER_ADDRESS);
431 							if (sar) {
432 								*rfc5780 = 1;
433 								printf("\n========================================\n");
434 								printf("RFC 5780 response %d\n",++counter);
435 								ioa_addr mapped_addr;
436 								addr_set_any(&mapped_addr);
437 								if (stun_attr_get_first_addr(buf, STUN_ATTRIBUTE_MAPPED_ADDRESS, &mapped_addr, NULL) >= 0) {
438 									if (!addr_eq(&mapped_addr,reflexive_addr)){
439 										printf("-= ALG detected! Mapped and XOR-Mapped differ! =-\n");
440 										addr_debug_print(1, &mapped_addr, "Mapped Address: ");
441 									}else {
442 										printf("No ALG: Mapped == XOR-Mapped\n");
443 									}
444 								} else {
445 									printf("Not received mapped address attribute.\n");
446 								}
447 								stun_attr_get_addr_str((uint8_t *) buf->buf, (size_t) buf->len, sar, other_addr, NULL);
448 								sar = stun_attr_get_first_by_type_str(buf->buf, buf->len, STUN_ATTRIBUTE_RESPONSE_ORIGIN);
449 								if (sar) {
450 									ioa_addr response_origin;
451 									stun_attr_get_addr_str((uint8_t *) buf->buf, (size_t) buf->len, sar, &response_origin, NULL);
452 									addr_debug_print(1, &response_origin, "Response origin: ");
453 								}
454 								addr_debug_print(1, other_addr, "Other addr: ");
455 							}
456 							addr_debug_print(1, reflexive_addr, "UDP reflexive addr");
457 							addr_debug_print(1, local_addr, "Local addr: ");
458 						} else {
459 							printf("Cannot read the response\n");
460 						}
461 					} else {
462 						printf("Wrong type of response\n");
463 					}
464 				} else {
465 					int err_code = 0;
466 					uint8_t err_msg[1025] = "\0";
467 					size_t err_msg_size = sizeof(err_msg);
468 					if (stun_is_error_response(buf, &err_code, err_msg, err_msg_size)) {
469 						printf("The response is an error %d (%s)\n", err_code, (char*) err_msg);
470 					} else {
471 						printf("The response is an unrecognized error\n");
472 					}
473 				}
474 			} else if (stun_is_request(buf)) {
475 				printf("Received a request (maybe a successful hairpinning)\n");
476 			} else {
477 				printf("The response is not a response message\n");
478 				ret=1;
479 			}
480 		} else {
481 			if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
482 				printf("STUN receive timeout..\n");
483 			}else{
484 				printf("The response is not a STUN message\n");
485 			}
486 			ret=1;
487 		}
488 	}
489 
490 	return ret;
491 }
492 
493 
run_stunclient(ioa_addr * local_addr,ioa_addr * remote_addr,ioa_addr * reflexive_addr,ioa_addr * other_addr,int * local_port,int * rfc5780,int change_ip,int change_port,int padding)494 static int run_stunclient(ioa_addr *local_addr, ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *local_port, int *rfc5780, int change_ip, int change_port, int padding){
495 	int ret=0;
496 	stun_buffer buf;
497 
498 	init_socket(&udp_fd, local_addr, *local_port, remote_addr);
499 
500 	ret=stunclient_send(&buf, udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1);
501 	ret=stunclient_receive(&buf, udp_fd, local_addr, reflexive_addr, other_addr, rfc5780);
502 
503 	socket_closesocket(udp_fd);
504 
505 	return ret;
506 }
507 
run_stunclient_hairpinning(ioa_addr * local_addr,ioa_addr * remote_addr,ioa_addr * reflexive_addr,ioa_addr * other_addr,int * local_port,int * rfc5780,int change_ip,int change_port,int padding)508 static int run_stunclient_hairpinning(ioa_addr *local_addr, ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *local_port, int *rfc5780, int change_ip, int change_port, int padding){
509 	int ret=0;
510 	stun_buffer buf;
511 	stun_buffer buf2;
512 
513 	init_socket(&udp_fd, local_addr, *local_port, remote_addr);
514 
515 	ret=stunclient_send(&buf, udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1);
516 	ret=stunclient_receive(&buf, udp_fd, local_addr, reflexive_addr, other_addr, rfc5780);
517 
518 
519 	addr_cpy(remote_addr,reflexive_addr);
520 	addr_set_port(local_addr, 0);
521 
522 	init_socket(&udp_fd2,local_addr,0,remote_addr);
523 
524 	ret=stunclient_send(&buf2, udp_fd2, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1);
525 	ret=stunclient_receive(&buf, udp_fd, local_addr, reflexive_addr, other_addr, rfc5780);
526 
527 	if(ret){
528 		ret=stunclient_receive(&buf2, udp_fd2, local_addr, reflexive_addr, other_addr, rfc5780);
529 	}
530 
531 	socket_closesocket(udp_fd);
532 	socket_closesocket(udp_fd2);
533 
534 	return ret;
535 }
536 
537 
run_stunclient_lifetime(int timer,ioa_addr * local_addr,ioa_addr * remote_addr,ioa_addr * reflexive_addr,ioa_addr * other_addr,int * local_port,int * rfc5780,int change_ip,int change_port,int padding)538 static int run_stunclient_lifetime(int timer,ioa_addr *local_addr, ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *local_port, int *rfc5780, int change_ip, int change_port, int padding){
539 	int ret=0;
540 	stun_buffer buf;
541 	stun_buffer buf2;
542 	int response_port;
543 
544 	init_socket(&udp_fd, local_addr, *local_port, remote_addr);
545 
546 	ret=stunclient_send(&buf, udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1);
547 	ret=stunclient_receive(&buf, udp_fd, local_addr, reflexive_addr, other_addr, rfc5780);
548 
549 	addr_set_port(local_addr, 0);
550 	sleep(timer);
551 
552 	init_socket(&udp_fd2,local_addr,0,remote_addr);
553 	response_port=addr_get_port(reflexive_addr);
554 
555 	ret=stunclient_send(&buf2, udp_fd2, local_addr, local_port, remote_addr, change_ip, change_port, padding, response_port);
556 	ret=stunclient_receive(&buf, udp_fd, local_addr, reflexive_addr, other_addr, rfc5780);
557 
558 	socket_closesocket(udp_fd);
559 	socket_closesocket(udp_fd2);
560 
561 	return ret;
562 }
563 
564 #endif
565 
566 //////////////// local definitions /////////////////
567 
568 static char Usage[] =
569 "Usage: natdiscovery [options] address\n"
570 "Options:\n"
571 "        -m      NAT mapping behavior discovery\n"
572 "        -f      NAT filtering behavior discovery\n"
573 "        -t      NAT mapping lifetime behavior discovery\n"
574 "                Requires a timer (-T)\n"
575 "        -c      NAT collision behavior discovery\n"
576 "                Requires an alternative IP address (-A)\n"
577 "        -H      NAT hairpinning behavior discovery\n"
578 "        -P      Add 1500 byte Padding to the behavior discovery\n"
579 "                Applicable with all except NAT mapping Lifetime discovery\n"
580 "        -p      STUN server port (Default: 3478)\n"
581 "        -L      Local address to use (optional)\n"
582 "        -l      Local port to use (use with -L)\n"
583 "        -A      Local alrernative address to use\n"
584 "                Used by collision behavior discovery\n"
585 "        -T      Mapping lifetime timer (sec)\n"
586 "                Used by mapping lifetime behavior discovery\n";
587 
588 //////////////////////////////////////////////////
589 
init(int first,ioa_addr * local_addr,ioa_addr * remote_addr,int * local_port,int port,int * rfc5780,char * local_addr_string,char * remote_param)590 static void init(int first, ioa_addr *local_addr, ioa_addr *remote_addr, int *local_port, int port, int *rfc5780, char* local_addr_string, char* remote_param)
591 {
592 	addr_set_any(local_addr);
593 
594 	if(local_addr_string[0]) {
595 		if(make_ioa_addr((const uint8_t*)local_addr_string, 0, local_addr)<0) {
596 			err(-1,NULL);
597 		}
598 	}
599 	if (!first) *local_port=-1;
600 	*rfc5780 = 0;
601 
602 	if (make_ioa_addr((const uint8_t*)remote_param, port, remote_addr) < 0)
603 	err(-1, NULL);
604 }
605 
discoveryresult(const char * decision)606 static void discoveryresult(const char *decision){
607 	printf("\n========================================\n");
608 	printf("%s",decision);
609 	printf("\n========================================\n");
610 }
611 
main(int argc,char ** argv)612 int main(int argc, char **argv)
613 {
614 	int remote_port = DEFAULT_STUN_PORT;
615 	char local_addr_string[256]="\0";
616 	char local2_addr_string[256]="\0";
617 	int c=0;
618 	int mapping = 0;
619 	int filtering = 0;
620 	int lifetime=0;
621 	int timer=-1;
622 	int collision = 0;
623 	int padding = 0;
624 	int hairpinning = 0;
625 	int local_port=-1;
626 	int rfc5780;
627 	int first=1;
628 	ioa_addr other_addr, reflexive_addr, tmp_addr, remote_addr, local_addr, local2_addr;
629 
630 
631 	set_logfile("stdout");
632 	set_system_parameters(0);
633 
634 	bzero(local_addr_string, sizeof(local_addr_string));
635 	bzero(local2_addr_string, sizeof(local2_addr_string));
636 	addr_set_any(&remote_addr);
637 	addr_set_any(&other_addr);
638 	addr_set_any(&reflexive_addr);
639 	addr_set_any(&tmp_addr);
640 
641 	while ((c = getopt(argc, argv, "mftcPHp:L:l:A:T:")) != -1) {
642 		switch(c) {
643 			case 'm':
644 			mapping=1;
645 			break;
646 			case 'f':
647 			filtering=1;
648 			break;
649 			case 't':
650 			lifetime=1;
651 			break;
652 			case 'c':
653 			collision=1;
654 			break;
655 			case 'H':
656 			hairpinning=1;
657 			break;
658 			case 'P':
659 			padding=1;
660 			break;
661 			case 'p':
662 			remote_port = atoi(optarg);
663 			break;
664 			case 'L':
665 			STRCPY(local_addr_string, optarg);
666 			break;
667 			case 'l':
668 			local_port = atoi(optarg);
669 			break;
670 			case 'A':
671 			STRCPY(local2_addr_string, optarg);
672 			break;
673 			case 'T':
674 			timer = atoi(optarg);
675 			break;
676 			default:
677 			fprintf(stderr,"%s\n", Usage);
678 			exit(1);
679 		}
680 	}
681 
682 	if(optind>=argc) {
683 		fprintf(stderr, "%s\n", Usage);
684 		exit(-1);
685 	}
686 
687 	if(collision && !strcmp(local2_addr_string,"\0")){
688 		fprintf(stderr, "Use \"-A\" to add an Alternative local IP address.\n");
689 		fprintf(stderr, "It is mandatory with \"-c\" collision behavior detection..\n");
690 		exit(-1);
691 	}
692 
693 	if(lifetime && timer==-1){
694 		fprintf(stderr, "Use \"-T\" to add a timer value (in sec).\n");
695 		fprintf(stderr, "It is mandatory with \"-b\" mapping lifetime behavior detection..\n");
696 		exit(-1);
697 	}
698 
699 	if(local_port>=0 && !strcmp(local_addr_string,"\0")){
700 		fprintf(stderr, "To use local port please specify local address \"-L\"!\n");
701 		fprintf(stderr, "We need to know the address familly to set the port.\n");
702 		exit(-1);
703 	}
704 
705 
706 	if(lifetime) {
707 		printf("\n-= Mapping Lifetime Behavior Discovery =-\n");
708 		init(first, &local_addr, &remote_addr, &local_port, remote_port, &rfc5780, local_addr_string, argv[optind]);
709 		first=0;
710 		run_stunclient_lifetime(timer, &local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding);
711 	}
712 
713 	if(hairpinning) {
714 		printf("\n-= Hairpinning Behavior Discovery =-\n");
715 		init(first, &local_addr, &remote_addr, &local_port, remote_port, &rfc5780, local_addr_string, argv[optind]);
716 		first=0;
717 		run_stunclient_hairpinning(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding);
718 	}
719 
720 
721 	if(mapping) {
722 		printf("\n-= Mapping Behavior Discovery =-\n");
723 		init(first,&local_addr, &remote_addr, &local_port, remote_port, &rfc5780, local_addr_string, argv[optind]);
724 		first=0;
725 
726 		run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding);
727 		if (addr_eq(&local_addr,&reflexive_addr)){
728 			discoveryresult("No NAT! (Endpoint Independent Mapping)");
729 		}
730 		if(rfc5780) {
731 			if(!addr_any(&other_addr)){
732 				addr_cpy(&tmp_addr, &reflexive_addr);
733 
734 				addr_cpy(&remote_addr, &other_addr);
735 				addr_set_port(&remote_addr, remote_port);
736 
737 				run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding);
738 
739 				if(addr_eq(&tmp_addr,&reflexive_addr)){
740 					discoveryresult("NAT with Endpoint Independent Mapping!");
741 				} else {
742 					addr_cpy(&tmp_addr, &reflexive_addr);
743 					addr_cpy(&remote_addr, &other_addr);
744 					run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding);
745 					if(addr_eq(&tmp_addr,&reflexive_addr)){
746 						discoveryresult("NAT with Address Dependent Mapping!");
747 					} else {
748 						discoveryresult("NAT with Address and Port Dependent Mapping!");
749 					}
750 				}
751 			}
752 		}
753 	}
754 
755 
756 	if(filtering) {
757 		printf("\n-= Filtering Behavior Discovery =-\n");
758 		init(first,&local_addr, &remote_addr, &local_port, remote_port, &rfc5780, local_addr_string, argv[optind]);
759 		first=0;
760 
761 		run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding);
762 		if(addr_eq(&local_addr, &reflexive_addr)){
763 			discoveryresult("No NAT! (Endpoint Independent Mapping)");
764 		}
765 		if(rfc5780) {
766 			if(!addr_any(&other_addr)){
767 				int res=0;
768 				res=run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,1,1,padding);
769 				if (!res) {
770 					discoveryresult("NAT with Endpoint Independent Filtering!");
771 				} else {
772 					res=0;
773 					res=run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,1,padding);
774 					if(!res){
775 						discoveryresult("NAT with Address Dependent Filtering!");
776 					} else {
777 						discoveryresult("NAT with Address and Port Dependent Filtering!");
778 					}
779 				}
780 			}
781 		}
782 	}
783 
784 
785 
786 	if(collision) {
787 		printf("\n-= Collision Behavior Discovery =-\n");
788 		init(first,&local_addr, &remote_addr, &local_port, remote_port, &rfc5780, local_addr_string, argv[optind]);
789 		first=0;
790 
791 		addr_set_any(&local2_addr);
792 
793 		if(local2_addr_string[0]) {
794 			if(make_ioa_addr((const uint8_t*)local2_addr_string, 0, &local2_addr)<0) {
795 				err(-1,NULL);
796 			}
797 		}
798 
799 		run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding);
800 		addr_set_port(&local2_addr,addr_get_port(&local_addr));
801 		run_stunclient(&local2_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding);
802 	}
803 
804 	if (!filtering && !mapping && !collision && !hairpinning && !lifetime) {
805 		printf("Please use either -f or -m or -c or -t or -H parameter for Filtering or Mapping behavior discovery.\n");
806 	}
807 	socket_closesocket(udp_fd);
808 	socket_closesocket(udp_fd2);
809 
810 	return 0;
811 }
812