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