diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ac4b08 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +Makefile +bin +build +include +lib diff --git a/README.turnutils b/README.turnutils index 91c09b4..76f9c8a 100644 --- a/README.turnutils +++ b/README.turnutils @@ -1,41 +1,41 @@ GENERAL INFORMATION A set of turnutils_* programs provides some utility functionality to be used -for testing and for setting up the TURN server. - -1. turnutils_uclient: emulates multiple UDP,TCP,TLS or DTLS clients. +for testing and for setting up the TURN server. + +1. turnutils_uclient: emulates multiple UDP,TCP,TLS or DTLS clients. (this program is provided for the testing purposes only !) -The compiled binary image of this program is located in bin/ +The compiled binary image of this program is located in bin/ sub-directory. -2. turnutils_peer: a simple stateless UDP-only "echo" server, -to be used as the final server in relay pattern ("peer"). For every incoming +2. turnutils_peer: a simple stateless UDP-only "echo" server, +to be used as the final server in relay pattern ("peer"). For every incoming UDP packet, it simply echoes it back. -(this program is provided for the testing purposes only !) -When the test clients are communicating in the client-to-client manner -(when the "turnutils_uclient" program is used with "-y" option) then the +(this program is provided for the testing purposes only !) +When the test clients are communicating in the client-to-client manner +(when the "turnutils_uclient" program is used with "-y" option) then the turnutils_peer is not needed. - + The compiled binary image of this program is located in bin/ subdirectory. - -3. turnutils_stunclient: a simple STUN client example. + +3. turnutils_stunclient: a simple STUN client example. The compiled binary image of this program is located in bin/ subdirectory. - -4. turnutils_rfc5769check: a utility that checks the correctness of the + +4. turnutils_rfc5769check: a utility that checks the correctness of the STUN/TURN protocol implementation. This utility is used only for the compilation check procedure, it is not copied to the installation destination. -In the "examples/scripts" subdirectory, you will find the examples of command lines to be used +In the "examples/scripts" subdirectory, you will find the examples of command lines to be used to run the programs. The scripts are meant to be run from examples/ subdirectory, for example: $ cd examples $ ./scripts/secure_relay.sh -5. turnutils_natdiscovery: a utility that provides NAT behavior discovery -according RFC5780. This utility discovers the actual NAT Mapping and Filtering -behavior. Be aweare that at least two different listening IP addresses should -be configured to be able to work properly! +5. turnutils_natdiscovery: a utility that provides NAT behavior discovery +according RFC5780. This utility discovers the actual NAT Mapping and Filtering +behavior, etc. Be aware that on TURN server side two different listening IP +addresses should be configured to be able to work properly! 6. turnutils_oauth: a utility that provides OAuth access_token generation(AEAD encryption), validation and decryption. This utility inputs @@ -49,34 +49,34 @@ script in examples/scripts/oauth.sh. ===================================== - + NAME - + turnutils_uclient - this client emulation application is supplied for the test purposes only. - - SYNOPSIS + + SYNOPSIS $ turnutils_uclient [-tTSvsyhcxg] [options] - + DESCRIPTION - -It was designed to simulate multiple clients. It uses asynch IO API in -libevent to handle multiple clients. A client connects to the relay, -negotiates the session, and sends multiple (configured number) messages to the server (relay), -expecting the same number of replies. The length of the messages is configurable. -The message is an arbitrary octet stream. + +It was designed to simulate multiple clients. It uses asynch IO API in +libevent to handle multiple clients. A client connects to the relay, +negotiates the session, and sends multiple (configured number) messages to the server (relay), +expecting the same number of replies. The length of the messages is configurable. +The message is an arbitrary octet stream. The number of the messages to send is configurable. -Flags: +Flags: -t Use TCP for communications between client and TURN server (default is UDP). -b Use SCTP for communications between client and TURN server (default is UDP). --T Use TCP for the relay transport (default - UDP). Implies options -t, -y, -c, +-T Use TCP for the relay transport (default - UDP). Implies options -t, -y, -c, and ignores flags and options -s, -e, -r and -g. Can be used together with -b. - + -P Passive TCP (RFC6062 with active peer). Implies -T. -S Secure SSL connection: SSL/TLS for TCP, DTLS for UDP, TLS/SCTP for SCTP. @@ -87,11 +87,11 @@ Flags: -s Use "Send" method in TURN; by default, it uses TURN Channels. --y Use client-to-client connections: +-y Use client-to-client connections: RTP/RTCP pair of channels to another RTP/RTCP pair of channels. with this option the turnutils_peer application is not used, as the allocated relay endpoints are talking to each other. - + -h Hang on indefinitely after the last sent packet. -c Do not create rtcp connections. @@ -109,12 +109,12 @@ Flags: -R do negative protocol tests. -O DOS attack mode. - + -M Use TURN ICE Mobility. -I Do not set permissions on TURN relay endpoints (for testing the non-standard server relay functionality). - + -G Generate extra requests (create permissions, channel bind). -B Random disconnect after a few initial packets. @@ -123,7 +123,7 @@ Flags: -J Use oAuth with default test key kid='north'. -Options with required values: +Options with required values: -l Message length (Default: 100 Bytes). @@ -159,7 +159,7 @@ Options with required values: table in the database if dynamic, or the static-auth-secret value set in the configuration file if using static. --C This is the timestamp/username separator symbol (character) in +-C This is the timestamp/username separator symbol (character) in TURN REST API. The default value is :. -F Cipher suite for TLS/DTLS. Default value is DEFAULT. @@ -171,23 +171,23 @@ Options with required values: See the examples in the "examples/scripts" directory. ====================================== - + NAME - -turnutils_peer - a simple UDP-only echo backend server. - + +turnutils_peer - a simple UDP-only echo backend server. + SYNOPSIS $ turnutils_peer [-v] [options] - + DESCRIPTION - + This application is used for the test purposes only, as a peer for the turnutils_uclient application. -Options with required values: +Options with required values: -p Listening UDP port (Default: 3480). - + -d Listening interface device (optional) -L Listening address of turnutils_peer server. Multiple listening addresses can be used, IPv4 and IPv6. @@ -198,50 +198,50 @@ If no listener address(es) defined, then it listens on all IPv4 and IPv6 address ======================================== NAME - -turnutils_stunclient - a basic STUN client. - + +turnutils_stunclient - a basic STUN client. + SYNOPSIS $ turnutils_stunclient [options] - + DESCRIPTION - + It sends a "new" STUN RFC 5389 request (over UDP) and shows the reply information. -Options with required values: +Options with required values: -p STUN server port (Default: 3478). - + -L Local address to use (optional). -f Force RFC 5780 processing. -The turnutils_stunclient program checks the results of the first request, -and if it finds that the STUN server supports RFC 5780 -(the binding response reveals that) then the turnutils_stunclient makes a couple more +The turnutils_stunclient program checks the results of the first request, +and if it finds that the STUN server supports RFC 5780 +(the binding response reveals that) then the turnutils_stunclient makes a couple more requests with different parameters, to demonstrate the NAT discovery capabilities. This utility does not support the "old" "classic" STUN protocol (RFC 3489). - + ===================================== NAME - -turnutils_rfc5769check - a utility that tests the correctness of STUN protocol implementation. - + +turnutils_rfc5769check - a utility that tests the correctness of STUN protocol implementation. + SYNOPSIS - + $ turnutils_rfc5769check - + DESCRIPTION -turnutils_rfc5769check tests the correctness of STUN protocol implementation -against the test vectors predefined in RFC 5769 and prints the results of the +turnutils_rfc5769check tests the correctness of STUN protocol implementation +against the test vectors predefined in RFC 5769 and prints the results of the tests on the screen. This utility is used only for the compilation check procedure, it is not copied to the installation destination. - -Usage: + +Usage: $ turnutils_rfc5769check @@ -249,7 +249,7 @@ $ turnutils_rfc5769check NAME -turnutils_natdiscovery - a utility that discovers NAT mapping and filtering +turnutils_natdiscovery - a utility that discovers NAT mapping and filtering behavior according RFC5780. SYNOPSIS @@ -258,13 +258,13 @@ $ turnutils_natdiscovery [options] DESCRIPTION -turnutils_natdiscovery discovers the NAT Mapping and Filtering behavior, to -determine if that NAT is currently using Endpoint-Independent, -Address-Dependent, or Address and Port-Dependent Mapping and/or to determine if -that NAT is currently using Endpoint-Independent, Address-Dependent, or Address -and Port-Dependent Filtering. +turnutils_natdiscovery discovers the NAT Mapping and Filtering behavior, to +determine if that NAT is currently using Endpoint-Independent, +Address-Dependent, or Address and Port-Dependent Mapping and/or to determine if +that NAT is currently using Endpoint-Independent, Address-Dependent, or Address +and Port-Dependent Filtering. -Use either -m and/or -f flag to discover NAT Mapping and/or Filtering. +Use either -m, -f, -c, -H flag to discover NAT behavior. Flags: @@ -272,12 +272,30 @@ Flags: -f NAT filtering behavior discovery +-t NAT mapping lifetime behavior discovery + Requires a timer (-T) + +-c NAT collision behavior discovery + +-H NAT hairpinning behavior discovery + +-P Add 1500 byte Padding to the behavior discovery + Applicable with all except NAT mapping Lifetime discovery + Options with required values: -p STUN server port (Default: 3478) -L Local address to use (optional) +-l Local port to use (use with -L) + +-A Secondary Local address (optional) + Required for collision discovery + +-T Mapping lifetime timer (sec) + Used by mapping lifetime behavior discovery + Usage: $ turnutils_natdiscovery -m -f stun.example.com @@ -351,7 +369,7 @@ Usage: $ turnutils_natdiscovery =================================== - + DOCS After installation, run the command: @@ -397,7 +415,7 @@ new STUN RFC 5389 TURN RFC 5766 TURN-TCP extension RFC 6062 - + TURN IPv6 extension RFC 6156 STUN/TURN test vectors RFC 5769 @@ -443,17 +461,17 @@ SEE ALSO Erik Johnston Roman Lisagor - + Vladimir Tsanev - + Po-sheng Lin - + Peter Dunkley - + Mutsutoshi Yoshimoto - + Federico Pinna Bradley T. Hughes - Mihaly Meszaros + Mihaly Meszaros diff --git a/man/man1/turnadmin.1 b/man/man1/turnadmin.1 index cd2c585..9ffb8a0 100644 --- a/man/man1/turnadmin.1 +++ b/man/man1/turnadmin.1 @@ -1,5 +1,5 @@ .\" Text automatically generated by txt2man -.TH TURN 1 "13 November 2016" "" "" +.TH TURN 1 "29 September 2017" "" "" .SH GENERAL INFORMATION \fIturnadmin\fP is a TURN administration tool. This tool can be used to manage diff --git a/man/man1/turnserver.1 b/man/man1/turnserver.1 index 8852fb5..70258b1 100644 --- a/man/man1/turnserver.1 +++ b/man/man1/turnserver.1 @@ -1,5 +1,5 @@ .\" Text automatically generated by txt2man -.TH TURN 1 "13 November 2016" "" "" +.TH TURN 1 "29 September 2017" "" "" .SH GENERAL INFORMATION The \fBTURN Server\fP project contains the source code of a TURN server and TURN client diff --git a/man/man1/turnutils.1 b/man/man1/turnutils.1 index 8182b99..fc9c9ec 100644 --- a/man/man1/turnutils.1 +++ b/man/man1/turnutils.1 @@ -1,41 +1,41 @@ .\" Text automatically generated by txt2man -.TH TURN 1 "13 November 2016" "" "" +.TH TURN 1 "29 September 2017" "" "" .SH GENERAL INFORMATION A set of turnutils_* programs provides some utility functionality to be used -for testing and for setting up the TURN server. +for testing and for setting up the TURN server. .TP .B 1. -\fIturnutils_uclient\fP: emulates multiple UDP,TCP,TLS or DTLS clients. +\fIturnutils_uclient\fP: emulates multiple UDP,TCP,TLS or DTLS clients. (this program is provided for the testing purposes only !) -The compiled binary image of this program is located in bin/ +The compiled binary image of this program is located in bin/ sub\-directory. .TP .B 2. -\fIturnutils_peer\fP: a simple stateless UDP\-only "echo" server, -to be used as the final server in relay pattern ("peer"). For every incoming +\fIturnutils_peer\fP: a simple stateless UDP\-only "echo" server, +to be used as the final server in relay pattern ("peer"). For every incoming UDP packet, it simply echoes it back. -(this program is provided for the testing purposes only !) -When the test clients are communicating in the client\-to\-client manner -(when the "\fIturnutils_uclient\fP" program is used with "\fB\-y\fP" option) then the +(this program is provided for the testing purposes only !) +When the test clients are communicating in the client\-to\-client manner +(when the "\fIturnutils_uclient\fP" program is used with "\fB\-y\fP" option) then the \fIturnutils_peer\fP is not needed. .PP The compiled binary image of this program is located in bin/ subdirectory. .TP .B 3. -\fIturnutils_stunclient\fP: a simple STUN client example. +\fIturnutils_stunclient\fP: a simple STUN client example. The compiled binary image of this program is located in bin/ subdirectory. .TP .B 4. -\fIturnutils_rfc5769check\fP: a utility that checks the correctness of the +\fIturnutils_rfc5769check\fP: a utility that checks the correctness of the STUN/TURN protocol implementation. This utility is used only for the compilation check procedure, it is not copied to the installation destination. .PP -In the "examples/scripts" subdirectory, you will find the examples of command lines to be used +In the "examples/scripts" subdirectory, you will find the examples of command lines to be used to run the programs. The scripts are meant to be run from examples/ subdirectory, for example: .PP $ cd examples @@ -44,10 +44,10 @@ $ ./scripts/secure_relay.sh .TP .B 5. -\fIturnutils_natdiscovery\fP: a utility that provides NAT behavior discovery -according RFC5780. This utility discovers the actual NAT Mapping and Filtering -behavior. Be aweare that at least two different listening IP addresses should -be configured to be able to work properly! +\fIturnutils_natdiscovery\fP: a utility that provides NAT behavior discovery +according RFC5780. This utility discovers the actual NAT Mapping and Filtering +behavior, etc. Be aware that on TURN server side two different listening IP +addresses should be configured to be able to work properly! .TP .B 6. @@ -69,19 +69,25 @@ script in examples/scripts/oauth.sh. \fB \fBturnutils_uclient \fP\- this client emulation application is supplied for the test purposes only. \fB -.SS SYNOPSIS +.SS SYNOPSIS +.nf +.fam C -$ \fIturnutils_uclient\fP [\fB\-tTSvsyhcxg\fP] [options] +$ \fIturnutils_uclient\fP [\fB\-tTSvsyhcxg\fP] [\fIoptions\fP] + +.fam T +.fi +.fam T +.fi .SS DESCRIPTION -It was designed to simulate multiple clients. It uses asynch IO API in -libevent to handle multiple clients. A client connects to the relay, -negotiates the session, and sends multiple (configured number) messages to the server (relay), -expecting the same number of replies. The length of the messages is configurable. -The message is an arbitrary octet stream. +It was designed to simulate multiple clients. It uses asynch IO API in +libevent to handle multiple clients. A client connects to the relay, +negotiates the session, and sends multiple (configured number) messages to the server (relay), +expecting the same number of replies. The length of the messages is configurable. +The message is an arbitrary octet stream. The number of the messages to send is configurable. -.TP -.B +.PP Flags: .TP .B @@ -94,8 +100,8 @@ Use SCTP for communications between client and TURN server (default is UDP). .TP .B \fB\-T\fP -Use TCP for the relay transport (default \- UDP). Implies options \fB\-t\fP, \fB\-y\fP, \fB\-c\fP, -and ignores flags and options \fB\-s\fP, \fB\-e\fP, \fB\-r\fP and \fB\-g\fP. Can be used together +Use TCP for the relay transport (default \- UDP). Implies \fIoptions\fP \fB\-t\fP, \fB\-y\fP, \fB\-c\fP, +and ignores flags and \fIoptions\fP \fB\-s\fP, \fB\-e\fP, \fB\-r\fP and \fB\-g\fP. Can be used together with \fB\-b\fP. .TP .B @@ -120,7 +126,7 @@ Use "Send" method in TURN; by default, it uses TURN Channels. .TP .B \fB\-y\fP -Use client\-to\-client connections: +Use client\-to\-client connections: RTP/RTCP pair of channels to another RTP/RTCP pair of channels. with this option the \fIturnutils_peer\fP application is not used, as the allocated relay endpoints are talking to each other. @@ -185,8 +191,7 @@ Dual allocation (SSODA). Implies \fB\-c\fP option. .B \fB\-J\fP Use oAuth with default test key kid='north'. -.TP -.B +.PP Options with required values: .TP .B @@ -224,7 +229,7 @@ Local IP address (optional). .TP .B \fB\-m\fP -Number of clients (Default: 1, 2 or 4, depending on options). +Number of clients (Default: 1, 2 or 4, depending on \fIoptions\fP). .TP .B \fB\-e\fP @@ -255,7 +260,7 @@ value set in the configuration file if using static. .TP .B \fB\-C\fP -This is the timestamp/username separator symbol (character) in +This is the timestamp/username separator symbol (character) in TURN REST API. The default value is :. .TP .B @@ -290,8 +295,7 @@ $ \fIturnutils_peer\fP [\fB\-v\fP] [\fIoptions\fP] .SS DESCRIPTION This application is used for the test purposes only, as a peer for the \fIturnutils_uclient\fP application. -.TP -.B +.PP Options with required values: .TP .B @@ -329,8 +333,7 @@ $ \fIturnutils_stunclient\fP [\fIoptions\fP] .SS DESCRIPTION It sends a "new" STUN RFC 5389 request (over UDP) and shows the reply information. -.TP -.B +.PP Options with required values: .TP .B @@ -345,9 +348,9 @@ Local address to use (optional). \fB\-f\fP Force RFC 5780 processing. .PP -The \fIturnutils_stunclient\fP program checks the results of the first request, -and if it finds that the STUN server supports RFC 5780 -(the binding response reveals that) then the \fIturnutils_stunclient\fP makes a couple more +The \fIturnutils_stunclient\fP program checks the results of the first request, +and if it finds that the STUN server supports RFC 5780 +(the binding response reveals that) then the \fIturnutils_stunclient\fP makes a couple more requests with different parameters, to demonstrate the NAT discovery capabilities. .PP This utility does not support the "old" "classic" STUN protocol (RFC 3489). @@ -369,12 +372,11 @@ $ \fIturnutils_rfc5769check\fP .fi .SS DESCRIPTION -\fIturnutils_rfc5769check\fP tests the correctness of STUN protocol implementation -against the test vectors predefined in RFC 5769 and prints the results of the +\fIturnutils_rfc5769check\fP tests the correctness of STUN protocol implementation +against the test vectors predefined in RFC 5769 and prints the results of the tests on the screen. This utility is used only for the compilation check procedure, it is not copied to the installation destination. -.TP -.B +.PP Usage: .PP $ \fIturnutils_rfc5769check\fP @@ -397,13 +399,13 @@ $ \fIturnutils_natdiscovery\fP [\fIoptions\fP] Federico Pinna .PP Bradley T. Hughes +.RE .PP Mihaly Meszaros diff --git a/src/apps/natdiscovery/natdiscovery.c b/src/apps/natdiscovery/natdiscovery.c index 28c225c..a8080c2 100644 --- a/src/apps/natdiscovery/natdiscovery.c +++ b/src/apps/natdiscovery/natdiscovery.c @@ -1,32 +1,32 @@ /* - * Copyright (C) 2011, 2012, 2013 Citrix Systems - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ +* Copyright (C) 2011, 2012, 2013 Citrix Systems +* +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the project nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +*/ #include #include @@ -44,38 +44,43 @@ #endif //////////////////////////////////////////////////// - static int udp_fd = -1; -static ioa_addr real_local_addr; +static int udp_fd2 = -1; + static int counter = 0; #ifdef __cplusplus -static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *port, int *rfc5780, int response_port, int change_ip, int change_port, int padding) -{ + +static int init_socket(int *socketfd, ioa_addr *local_addr, int local_port, ioa_addr *remote_addr){ int ret=0; - if (response_port >= 0) { - addr_set_port(&real_local_addr, response_port); + if (local_port >= 0) { + addr_set_port(local_addr, local_port); } - udp_fd = socket(remote_addr->ss.sa_family, SOCK_DGRAM, 0); + + *socketfd = socket(remote_addr->ss.sa_family, SOCK_DGRAM, 0); if (udp_fd < 0) - err(-1, NULL); + err(-1, NULL); - if (!addr_any(&real_local_addr)) { - if (addr_bind(udp_fd, &real_local_addr,0,1,UDP_SOCKET) < 0) - err(-1, NULL); + if (!addr_any(local_addr)) { + if (addr_bind(*socketfd, local_addr,0,1,UDP_SOCKET) < 0) + err(-1, NULL); } + return ret; +} +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){ + int ret=0; turn::StunMsgRequest req(STUN_METHOD_BINDING); req.constructBindingRequest(); if (response_port >= 0) { - turn::StunAttrResponsePort rpa; + turn::StunAttrResponsePort rpa; rpa.setResponsePort((u16bits)response_port); try { req.addAttr(rpa); @@ -129,20 +134,28 @@ static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_a int slen = get_ioa_addr_len(remote_addr); do { - len = sendto(udp_fd, req.getRawBuffer(), req.getSize(), 0, (struct sockaddr*) remote_addr, (socklen_t) slen); + len = sendto(sockfd, req.getRawBuffer(), req.getSize(), 0, (struct sockaddr*) remote_addr, (socklen_t) slen); } while (len < 0 && ((errno == EINTR) || (errno == ENOBUFS) || (errno == EAGAIN))); if (len < 0) - err(-1, NULL); + err(-1, NULL); } - if (addr_get_from_sock(udp_fd, &real_local_addr) < 0) { + if (addr_get_from_sock(sockfd, local_addr) < 0) { printf("%s: Cannot get address from local socket\n", __FUNCTION__); } else { - *port = addr_get_port(&real_local_addr); + *local_port = addr_get_port(local_addr); } + return ret; +} + + +static int stunclient_receive(int sockfd, ioa_addr *local_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *rfc5780){ + int ret=0; + + { int len = 0; stun_buffer buf; @@ -154,10 +167,10 @@ static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_a tv.tv_sec = 3; /* 3 Secs Timeout */ tv.tv_usec = 0; // Not init'ing this can cause strange errors - setsockopt(udp_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval)); + setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval)); do { - len = recv(udp_fd, ptr, to_recv - recvd, 0); + len = recv(sockfd, ptr, to_recv - recvd, 0); if (len > 0) { recvd += len; ptr += len; @@ -165,15 +178,19 @@ static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_a } } while (len < 0 && (errno == EINTR)); + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { + printf("STUN receive timeout..\n"); + ret = 1; + return ret; + } if (recvd > 0) - len = recvd; + len = recvd; buf.len = len; try { turn::StunMsgResponse res(buf.buf, sizeof(buf.buf), (size_t)buf.len, true); if (res.isCommand()) { - if(res.isSuccess()) { if (res.isBindingResponse()) { @@ -189,20 +206,33 @@ static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_a *rfc5780 = 1; printf("\n========================================\n"); printf("RFC 5780 response %d\n",++counter); - turn::StunAttrAddr addr1(iter1); - addr1.getAddr(*other_addr); - turn::StunAttrIterator iter2(res,STUN_ATTRIBUTE_RESPONSE_ORIGIN); + turn::StunAttrIterator iter2(res,STUN_ATTRIBUTE_MAPPED_ADDRESS); if (!iter2.eof()) { - ioa_addr response_origin; + ioa_addr mapped_addr; + addr_set_any(&mapped_addr); turn::StunAttrAddr addr2(iter2); - addr2.getAddr(response_origin); + addr2.getAddr(mapped_addr); + if (!addr_eq(&mapped_addr,reflexive_addr)){ + printf("-= ALG detected! Mapped and XOR-Mapped differ! =-\n"); + addr_debug_print(1, &mapped_addr, "Mapped Address: "); + } else { + printf("No ALG: Mapped == XOR-Mapped\n"); + } + } else { + printf("Not received mapped address attribute!\n"); + } turn::StunAttrAddr addr1(iter1); + addr1.getAddr(*other_addr); + turn::StunAttrIterator iter3(res,STUN_ATTRIBUTE_RESPONSE_ORIGIN); + if (!iter3.eof()) { + ioa_addr response_origin; + turn::StunAttrAddr addr3(iter3); + addr3.getAddr(response_origin); addr_debug_print(1, &response_origin, "Response origin: "); } addr_debug_print(1, other_addr, "Other addr: "); } addr_debug_print(1, reflexive_addr, "UDP reflexive addr"); - addr_debug_print(1, &real_local_addr, "Local addr: "); - + addr_debug_print(1, local_addr, "Local addr: "); } else { printf("Cannot read the response\n"); } @@ -219,50 +249,117 @@ static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_a printf("The response is not a reponse message\n"); } } catch(...) { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { - printf("STUN receive timeout..\n"); - }else{ + turn::StunMsgRequest msg(buf.buf, sizeof(buf.buf), (size_t)buf.len, true); + if (msg.isRequest(buf.buf,(size_t)buf.len)) { + printf("Received a request (maybe a successful hairpinning)\n"); + return ret; + } else { printf("The response is not a well formed STUN message\n"); } - ret=1; + ret=1; } } + + return ret; +} + + +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){ + int ret=0; + + ret=init_socket(&udp_fd, local_addr, *local_port, remote_addr); + ret=stunclient_send(udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1); + ret=stunclient_receive(udp_fd, local_addr, reflexive_addr, other_addr, rfc5780); close(udp_fd); return ret; } + +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){ + int ret=0; + + init_socket(&udp_fd,local_addr,*local_port,remote_addr); + + ret=stunclient_send(udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1); + ret=stunclient_receive(udp_fd, local_addr, reflexive_addr, other_addr, rfc5780); + + + addr_cpy(remote_addr,reflexive_addr); + addr_set_port(local_addr, 0); + + init_socket(&udp_fd2,local_addr,0,remote_addr); + + ret=stunclient_send(udp_fd2, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1); + ret=stunclient_receive(udp_fd, local_addr, reflexive_addr, other_addr, rfc5780); + + if(ret){ + ret=stunclient_receive(udp_fd2, local_addr, reflexive_addr, other_addr, rfc5780); + } + close(udp_fd); + close(udp_fd2); + + return ret; +} + +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){ + int ret=0; + int response_port; + + init_socket(&udp_fd, local_addr, *local_port, remote_addr); + + ret=stunclient_send(udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1); + ret=stunclient_receive(udp_fd, local_addr, reflexive_addr, other_addr, rfc5780); + + addr_set_port(local_addr, 0); + sleep(timer); + + init_socket(&udp_fd2,local_addr,0,remote_addr); + response_port=addr_get_port(reflexive_addr); + + ret=stunclient_send(udp_fd2, local_addr, local_port, remote_addr, change_ip, change_port, padding, response_port); + ret=stunclient_receive(udp_fd, local_addr, reflexive_addr, other_addr, rfc5780); + + socket_closesocket(udp_fd); + socket_closesocket(udp_fd2); + + return ret; +} + #else -static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *port, int *rfc5780, int response_port, int change_ip, int change_port, int padding) -{ +static int init_socket(int *socketfd, ioa_addr *local_addr, int local_port, ioa_addr *remote_addr){ int ret=0; - stun_buffer buf; - udp_fd = socket(remote_addr->ss.sa_family, CLIENT_DGRAM_SOCKET_TYPE, CLIENT_DGRAM_SOCKET_PROTOCOL); + *socketfd = socket(remote_addr->ss.sa_family, CLIENT_DGRAM_SOCKET_TYPE, CLIENT_DGRAM_SOCKET_PROTOCOL); if (udp_fd < 0) - err(-1, NULL); + err(-1, NULL); - if (!addr_any(&real_local_addr)) { - if (response_port >= 0) { - addr_set_port(&real_local_addr, response_port); - } - if (addr_bind(udp_fd, &real_local_addr,0,1,UDP_SOCKET) < 0) { + if (local_port >= 0) { + addr_set_port(local_addr, local_port); + } + if (!addr_any(local_addr)) { + if (addr_bind(*socketfd, local_addr,0,1,UDP_SOCKET) < 0) { err(-1, NULL); - } + } } + return ret; +} - stun_prepare_binding_request(&buf); +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){ + int ret=0; + + stun_prepare_binding_request(buf); if (response_port >= 0) { - stun_attr_add_response_port_str((u08bits*) (buf.buf), (size_t*) &(buf.len), (u16bits) response_port); + stun_attr_add_response_port_str((u08bits*) (buf->buf), (size_t*) &(buf->len), (u16bits) response_port); } if (change_ip || change_port) { - stun_attr_add_change_request_str((u08bits*) buf.buf, (size_t*) &(buf.len), change_ip, change_port); + stun_attr_add_change_request_str((u08bits*) buf->buf, (size_t*) &(buf->len), change_ip, change_port); } if (padding) { - if(stun_attr_add_padding_str((u08bits*) buf.buf, (size_t*) &(buf.len), 1500)<0) { + if(stun_attr_add_padding_str((u08bits*) buf->buf, (size_t*) &(buf->len), 1500)<0) { printf("%s: ERROR: Cannot add padding\n",__FUNCTION__); } } @@ -272,35 +369,42 @@ static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_a int slen = get_ioa_addr_len(remote_addr); do { - len = sendto(udp_fd, buf.buf, buf.len, 0, (struct sockaddr*) remote_addr, (socklen_t) slen); + len = sendto(sockfd, buf->buf, buf->len, 0, (struct sockaddr*) remote_addr, (socklen_t) slen); } while (len < 0 && ((errno == EINTR) || (errno == ENOBUFS) || (errno == EAGAIN))); if (len < 0) - err(-1, NULL); + err(-1, NULL); } - if (addr_get_from_sock(udp_fd, &real_local_addr) < 0) { + if (addr_get_from_sock(sockfd, local_addr) < 0) { printf("%s: Cannot get address from local socket\n", __FUNCTION__); } else { - *port = addr_get_port(&real_local_addr); + *local_port = addr_get_port(local_addr); } - + return ret; +} + + +static int stunclient_receive(stun_buffer *buf, int sockfd, ioa_addr *local_addr, ioa_addr *reflexive_addr, ioa_addr *other_addr, int *rfc5780){ + int ret=0; + + { int len = 0; - u08bits *ptr = buf.buf; + u08bits *ptr = buf->buf; int recvd = 0; - const int to_recv = sizeof(buf.buf); + const int to_recv = sizeof(buf->buf); struct timeval tv; tv.tv_sec = 3; /* 3 Secs Timeout */ tv.tv_usec = 0; // Not init'ing this can cause strange errors - setsockopt(udp_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval)); + setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval)); do { - len = recv(udp_fd, ptr, to_recv - recvd, 0); + len = recv(sockfd, ptr, to_recv - recvd, 0); if (len > 0) { recvd += len; ptr += len; @@ -309,37 +413,48 @@ static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_a } while (len < 0 && (errno == EINTR)); if (recvd > 0) - len = recvd; - buf.len = len; + len = recvd; + buf->len = len; - if (stun_is_command_message(&buf)) { + if (stun_is_command_message(buf)) { - if (stun_is_response(&buf)) { + if (stun_is_response(buf)) { - if (stun_is_success_response(&buf)) { + if (stun_is_success_response(buf)) { - if (stun_is_binding_response(&buf)) { + if (stun_is_binding_response(buf)) { addr_set_any(reflexive_addr); - if (stun_attr_get_first_addr(&buf, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, reflexive_addr, NULL) >= 0) { + if (stun_attr_get_first_addr(buf, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, reflexive_addr, NULL) >= 0) { - stun_attr_ref sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_OTHER_ADDRESS); + stun_attr_ref sar = stun_attr_get_first_by_type_str(buf->buf, buf->len, STUN_ATTRIBUTE_OTHER_ADDRESS); if (sar) { *rfc5780 = 1; printf("\n========================================\n"); printf("RFC 5780 response %d\n",++counter); - stun_attr_get_addr_str((u08bits *) buf.buf, (size_t) buf.len, sar, other_addr, NULL); - sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_RESPONSE_ORIGIN); + ioa_addr mapped_addr; + addr_set_any(&mapped_addr); + if (stun_attr_get_first_addr(buf, STUN_ATTRIBUTE_MAPPED_ADDRESS, &mapped_addr, NULL) >= 0) { + if (!addr_eq(&mapped_addr,reflexive_addr)){ + printf("-= ALG detected! Mapped and XOR-Mapped differ! =-\n"); + addr_debug_print(1, &mapped_addr, "Mapped Address: "); + }else { + printf("No ALG: Mapped == XOR-Mapped\n"); + } + } else { + printf("Not received mapped address attribute.\n"); + } + stun_attr_get_addr_str((u08bits *) buf->buf, (size_t) buf->len, sar, other_addr, NULL); + sar = stun_attr_get_first_by_type_str(buf->buf, buf->len, STUN_ATTRIBUTE_RESPONSE_ORIGIN); if (sar) { ioa_addr response_origin; - stun_attr_get_addr_str((u08bits *) buf.buf, (size_t) buf.len, sar, &response_origin, NULL); + stun_attr_get_addr_str((u08bits *) buf->buf, (size_t) buf->len, sar, &response_origin, NULL); addr_debug_print(1, &response_origin, "Response origin: "); } addr_debug_print(1, other_addr, "Other addr: "); } addr_debug_print(1, reflexive_addr, "UDP reflexive addr"); - addr_debug_print(1, &real_local_addr, "Local addr: "); - + addr_debug_print(1, local_addr, "Local addr: "); } else { printf("Cannot read the response\n"); } @@ -350,12 +465,14 @@ static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_a int err_code = 0; u08bits err_msg[1025] = "\0"; size_t err_msg_size = sizeof(err_msg); - if (stun_is_error_response(&buf, &err_code, err_msg, err_msg_size)) { + if (stun_is_error_response(buf, &err_code, err_msg, err_msg_size)) { printf("The response is an error %d (%s)\n", err_code, (char*) err_msg); } else { printf("The response is an unrecognized error\n"); } } + } else if (stun_is_request(buf)) { + printf("Received a request (maybe a successful hairpinning)\n"); } else { printf("The response is not a reponse message\n"); ret=1; @@ -370,40 +487,120 @@ static int run_stunclient(ioa_addr *remote_addr, ioa_addr *reflexive_addr, ioa_a } } - socket_closesocket(udp_fd); return ret; } + + +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){ + int ret=0; + stun_buffer buf; + + init_socket(&udp_fd, local_addr, *local_port, remote_addr); + + ret=stunclient_send(&buf, udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1); + ret=stunclient_receive(&buf, udp_fd, local_addr, reflexive_addr, other_addr, rfc5780); + + socket_closesocket(udp_fd); + + return ret; +} + +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){ + int ret=0; + stun_buffer buf; + stun_buffer buf2; + + init_socket(&udp_fd, local_addr, *local_port, remote_addr); + + ret=stunclient_send(&buf, udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1); + ret=stunclient_receive(&buf, udp_fd, local_addr, reflexive_addr, other_addr, rfc5780); + + + addr_cpy(remote_addr,reflexive_addr); + addr_set_port(local_addr, 0); + + init_socket(&udp_fd2,local_addr,0,remote_addr); + + ret=stunclient_send(&buf2, udp_fd2, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1); + ret=stunclient_receive(&buf, udp_fd, local_addr, reflexive_addr, other_addr, rfc5780); + + if(ret){ + ret=stunclient_receive(&buf2, udp_fd2, local_addr, reflexive_addr, other_addr, rfc5780); + } + + socket_closesocket(udp_fd); + socket_closesocket(udp_fd2); + + return ret; +} + + +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){ + int ret=0; + stun_buffer buf; + stun_buffer buf2; + int response_port; + + init_socket(&udp_fd, local_addr, *local_port, remote_addr); + + ret=stunclient_send(&buf, udp_fd, local_addr, local_port, remote_addr, change_ip, change_port, padding, -1); + ret=stunclient_receive(&buf, udp_fd, local_addr, reflexive_addr, other_addr, rfc5780); + + addr_set_port(local_addr, 0); + sleep(timer); + + init_socket(&udp_fd2,local_addr,0,remote_addr); + response_port=addr_get_port(reflexive_addr); + + ret=stunclient_send(&buf2, udp_fd2, local_addr, local_port, remote_addr, change_ip, change_port, padding, response_port); + ret=stunclient_receive(&buf, udp_fd, local_addr, reflexive_addr, other_addr, rfc5780); + + socket_closesocket(udp_fd); + socket_closesocket(udp_fd2); + + return ret; +} + #endif //////////////// local definitions ///////////////// static char Usage[] = - "Usage: natdiscovery [options] address\n" - "Options:\n" - " -m NAT mapping behavior discovery\n" - " -f NAT filtering behavior discovery\n" - " -p STUN server port (Default: 3478)\n" - " -L Local address to use (optional)\n"; +"Usage: natdiscovery [options] address\n" +"Options:\n" +" -m NAT mapping behavior discovery\n" +" -f NAT filtering behavior discovery\n" +" -t NAT mapping lifetime behavior discovery\n" +" Requires a timer (-T)\n" +" -c NAT collision behavior discovery\n" +" Requires an alternative IP address (-A)\n" +" -H NAT hairpinning behavior discovery\n" +" -P Add 1500 byte Padding to the behavior discovery\n" +" Applicable with all except NAT mapping Lifetime discovery\n" +" -p STUN server port (Default: 3478)\n" +" -L Local address to use (optional)\n" +" -l Local port to use (use with -L)\n" +" -A Local alrernative address to use\n" +" Used by collision behavior discovery\n" +" -T Mapping lifetime timer (sec)\n" +" Used by mapping lifetime behavior discovery\n"; ////////////////////////////////////////////////// -static void init(ioa_addr *real_local_addr,ioa_addr *remote_addr,int *local_port,int port, int *rfc5780, char* local_addr, char* remote_param) +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) { - addr_set_any(real_local_addr); + addr_set_any(local_addr); - if(local_addr[0]) { - if(make_ioa_addr((const u08bits*)local_addr, 0, real_local_addr)<0) { - err(-1,NULL); - } - } + if(local_addr_string[0]) { + if(make_ioa_addr((const u08bits*)local_addr_string, 0, local_addr)<0) { + err(-1,NULL); + } + } + if (!first) *local_port=-1; + *rfc5780 = 0; - *local_port = -1; - *rfc5780 = 0; - if (addr_any(remote_addr)){ - if (make_ioa_addr((const u08bits*)remote_param, port, remote_addr) < 0) { - err(-1, NULL); - } - } + if (make_ioa_addr((const u08bits*)remote_param, port, remote_addr) < 0) + err(-1, NULL); } static void discoveryresult(const char *decision){ @@ -414,113 +611,201 @@ static void discoveryresult(const char *decision){ int main(int argc, char **argv) { - int port = DEFAULT_STUN_PORT; - char local_addr[256]="\0"; - int c=0; - int mapping = 0; - int filtering = 0; - int local_port, rfc5780; - ioa_addr other_addr, reflexive_addr, tmp_addr, remote_addr, remote_tmp_addr; - + int remote_port = DEFAULT_STUN_PORT; + char local_addr_string[256]="\0"; + char local2_addr_string[256]="\0"; + int c=0; + int mapping = 0; + int filtering = 0; + int lifetime=0; + int timer=-1; + int collision = 0; + int padding = 0; + int hairpinning = 0; + int local_port=-1; + int rfc5780; + int first=1; + ioa_addr other_addr, reflexive_addr, tmp_addr, remote_addr, local_addr, local2_addr; - set_logfile("stdout"); - set_system_parameters(0); - - ns_bzero(local_addr, sizeof(local_addr)); - addr_set_any(&remote_addr); - addr_set_any(&remote_tmp_addr); - addr_set_any(&other_addr); - addr_set_any(&reflexive_addr); - addr_set_any(&tmp_addr); - while ((c = getopt(argc, argv, "mfp:L:")) != -1) { - switch(c) { - case 'm': - mapping=1; - break; - case 'f': - filtering=1; - break; - case 'p': - port = atoi(optarg); - break; - case 'L': - STRCPY(local_addr, optarg); - break; - default: - fprintf(stderr,"%s\n", Usage); - exit(1); - } - } + set_logfile("stdout"); + set_system_parameters(0); - if(optind>=argc) { - fprintf(stderr, "%s\n", Usage); - exit(-1); - } + ns_bzero(local_addr_string, sizeof(local_addr_string)); + ns_bzero(local2_addr_string, sizeof(local2_addr_string)); + addr_set_any(&remote_addr); + addr_set_any(&other_addr); + addr_set_any(&reflexive_addr); + addr_set_any(&tmp_addr); - init(&real_local_addr, &remote_addr, &local_port, port, &rfc5780, local_addr, argv[optind]); - - if (mapping) { - run_stunclient(&remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,0,0,0); - if (addr_eq(&real_local_addr,&reflexive_addr)){ - discoveryresult("No NAT! (Endpoint Independent Mapping)"); + while ((c = getopt(argc, argv, "mftcPHp:L:l:A:T:")) != -1) { + switch(c) { + case 'm': + mapping=1; + break; + case 'f': + filtering=1; + break; + case 't': + lifetime=1; + break; + case 'c': + collision=1; + break; + case 'H': + hairpinning=1; + break; + case 'P': + padding=1; + break; + case 'p': + remote_port = atoi(optarg); + break; + case 'L': + STRCPY(local_addr_string, optarg); + break; + case 'l': + local_port = atoi(optarg); + break; + case 'A': + STRCPY(local2_addr_string, optarg); + break; + case 'T': + timer = atoi(optarg); + break; + default: + fprintf(stderr,"%s\n", Usage); + exit(1); + } } - if(rfc5780) { - if(!addr_any(&other_addr)){ - addr_cpy(&tmp_addr, &reflexive_addr); - addr_cpy(&remote_tmp_addr, &other_addr); - addr_set_port(&remote_tmp_addr, port); + if(optind>=argc) { + fprintf(stderr, "%s\n", Usage); + exit(-1); + } - run_stunclient(&remote_tmp_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,0,0,0); + if(collision && !strcmp(local2_addr_string,"\0")){ + fprintf(stderr, "Use \"-A\" to add an Alternative local IP address.\n"); + fprintf(stderr, "It is mandatory with \"-c\" collision behavior detection..\n"); + exit(-1); + } - if(addr_eq(&tmp_addr,&reflexive_addr)){ - discoveryresult("NAT with Endpoint Independent Mapping!"); - } else { + if(lifetime && timer==-1){ + fprintf(stderr, "Use \"-T\" to add a timer value (in sec).\n"); + fprintf(stderr, "It is mandatory with \"-b\" mapping lifetime behavior detection..\n"); + exit(-1); + } + + if(local_port>=0 && !strcmp(local_addr_string,"\0")){ + fprintf(stderr, "To use local port please specify local address \"-L\"!\n"); + fprintf(stderr, "We need to know the address familly to set the port.\n"); + exit(-1); + } + + + if(lifetime) { + printf("\n-= Mapping Lifetime Behavior Discovery =-\n"); + init(first, &local_addr, &remote_addr, &local_port, remote_port, &rfc5780, local_addr_string, argv[optind]); + first=0; + run_stunclient_lifetime(timer, &local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding); + } + + if(hairpinning) { + printf("\n-= Hairpinning Behavior Discovery =-\n"); + init(first, &local_addr, &remote_addr, &local_port, remote_port, &rfc5780, local_addr_string, argv[optind]); + first=0; + run_stunclient_hairpinning(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding); + } + + + if(mapping) { + printf("\n-= Mapping Behavior Discovery =-\n"); + init(first,&local_addr, &remote_addr, &local_port, remote_port, &rfc5780, local_addr_string, argv[optind]); + first=0; + + run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding); + if (addr_eq(&local_addr,&reflexive_addr)){ + discoveryresult("No NAT! (Endpoint Independent Mapping)"); + } + if(rfc5780) { + if(!addr_any(&other_addr)){ addr_cpy(&tmp_addr, &reflexive_addr); - addr_cpy(&remote_tmp_addr, &other_addr); - run_stunclient(&remote_tmp_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,0,0,0); + + addr_cpy(&remote_addr, &other_addr); + addr_set_port(&remote_addr, remote_port); + + run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding); + if(addr_eq(&tmp_addr,&reflexive_addr)){ - discoveryresult("NAT with Address Dependent Mapping!"); + discoveryresult("NAT with Enpoint Independent Mapping!"); } else { - discoveryresult("NAT with Address and Port Dependent Mapping!"); + addr_cpy(&tmp_addr, &reflexive_addr); + addr_cpy(&remote_addr, &other_addr); + run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding); + if(addr_eq(&tmp_addr,&reflexive_addr)){ + discoveryresult("NAT with Address Dependent Mapping!"); + } else { + discoveryresult("NAT with Address and Port Dependent Mapping!"); + } } - }; - - } - } - } - - init(&real_local_addr, &remote_addr, &local_port, port, &rfc5780, local_addr, argv[optind]); - - if (filtering) { - run_stunclient(&remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,0,0,0); - if (addr_eq(&real_local_addr,&reflexive_addr)){ - discoveryresult("No NAT! (Endpoint Independent Mapping)"); + } + } } - if(rfc5780) { - if(!addr_any(&other_addr)){ - int res=0; - res=run_stunclient(&remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,1,1,0); - if (!res) { - discoveryresult("NAT with Endpoint Independent Filtering!"); - } else { - res=0; - res=run_stunclient(&remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,0,1,0); - if(!res){ - discoveryresult("NAT with Address Dependent Filtering!"); + + + if(filtering) { + printf("\n-= Filtering Behavior Discovery =-\n"); + init(first,&local_addr, &remote_addr, &local_port, remote_port, &rfc5780, local_addr_string, argv[optind]); + first=0; + + run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding); + if(addr_eq(&local_addr, &reflexive_addr)){ + discoveryresult("No NAT! (Endpoint Independent Mapping)"); + } + if(rfc5780) { + if(!addr_any(&other_addr)){ + int res=0; + res=run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,1,1,padding); + if (!res) { + discoveryresult("NAT with Enpoint Independent Filtering!"); } else { - discoveryresult("NAT with Address and Port Dependent Filtering!"); + res=0; + res=run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,1,padding); + if(!res){ + discoveryresult("NAT with Address Dependent Filtering!"); + } else { + discoveryresult("NAT with Address and Port Dependent Filtering!"); + } } - }; + } + } + } - } - } - } - if (!filtering && !mapping) { - printf("Please use either -f or -m parameter for Filtering or Mapping behavior discovery.\n"); - } - socket_closesocket(udp_fd); - return 0; + + if(collision) { + printf("\n-= Collision Behavior Discovery =-\n"); + init(first,&local_addr, &remote_addr, &local_port, remote_port, &rfc5780, local_addr_string, argv[optind]); + first=0; + + addr_set_any(&local2_addr); + + if(local2_addr_string[0]) { + if(make_ioa_addr((const u08bits*)local2_addr_string, 0, &local2_addr)<0) { + err(-1,NULL); + } + } + + run_stunclient(&local_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding); + addr_set_port(&local2_addr,addr_get_port(&local_addr)); + run_stunclient(&local2_addr, &remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,0,0,padding); + } + + if (!filtering && !mapping && !collision && !hairpinning && !lifetime) { + printf("Please use either -f or -m or -c or -t or -H parameter for Filtering or Mapping behavior discovery.\n"); + } + socket_closesocket(udp_fd); + socket_closesocket(udp_fd2); + + return 0; }