From 7cb6154bb57720e438ef8515138264311440d38f Mon Sep 17 00:00:00 2001 From: Oleg Moskalenko Date: Sun, 10 Dec 2017 20:06:27 -0800 Subject: [PATCH] Imported Upstream version 4.5.0.7 --- ChangeLog | 6 + Dockerfile.build | 11 + README.turnutils | 182 ++++--- build-docker.sh | 15 + examples/etc/turnserver.conf | 7 + man/man1/turnadmin.1 | 2 +- man/man1/turnserver.1 | 2 +- man/man1/turnutils.1 | 133 +++-- rpm/CentOS7.pre.build.sh | 2 +- rpm/build.settings.sh | 2 +- rpm/turnserver.spec | 4 +- src/apps/natdiscovery/natdiscovery.c | 698 +++++++++++++++++-------- src/apps/relay/mainrelay.c | 8 +- src/apps/relay/netengine.c | 2 +- src/apps/relay/ns_ioalib_engine_impl.c | 8 + src/apps/relay/turn_admin_server.c | 5 +- src/apps/relay/turn_admin_server.h | 2 + src/ns_turn_defs.h | 2 +- src/server/ns_turn_server.c | 52 +- src/server/ns_turn_server.h | 6 +- turndb/schema.stats.redis | 6 + 21 files changed, 785 insertions(+), 370 deletions(-) create mode 100644 Dockerfile.build create mode 100755 build-docker.sh diff --git a/ChangeLog b/ChangeLog index 892cbcf6..d9821135 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,15 @@ +12/10/2017 Oleg Moskalenko +Version 4.5.0.7 'dan Eider': + - Misc security improvements. + 10/17/2016 Oleg Moskalenko Version 4.5.0.6 'dan Eider': - Typos in the text fixed. - TLS1.2 support fixed. - uclient minor performance tweak. - Issue #113 fixed (by David Benjamin) + - Report total traffic used per allocation via Redis (by Bradley T. Hughes) + - Add the realm parameter in the example config file (by Domenico) 08/27/2016 Oleg Moskalenko Version 4.5.0.5 'dan Eider': diff --git a/Dockerfile.build b/Dockerfile.build new file mode 100644 index 00000000..3c360a00 --- /dev/null +++ b/Dockerfile.build @@ -0,0 +1,11 @@ +FROM ubuntu:16.04 + +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ + emacs-nox \ + build-essential \ + libssl-dev sqlite3 \ + libsqlite3-dev \ + libevent-dev \ + g++ \ + libboost-dev \ + libevent-dev diff --git a/README.turnutils b/README.turnutils index 91c09b49..76f9c8a1 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/build-docker.sh b/build-docker.sh new file mode 100755 index 00000000..abb51138 --- /dev/null +++ b/build-docker.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -o xtrace + +dir=`pwd` +echo "$dir" + +build_image=coturnbuild +dockerargs="--privileged -v ${dir}:/root/coturn -w /root/coturn" +container_env=' -e "INSIDECONTAINER=-incontainer=true"' +docker="docker run --rm -it ${dockerargs} ${container_env} ${build_image}" + +docker build -f Dockerfile.build -t ${build_image} . + +${docker} bash -c "./configure && make" + diff --git a/examples/etc/turnserver.conf b/examples/etc/turnserver.conf index f701b206..1eaefe4f 100644 --- a/examples/etc/turnserver.conf +++ b/examples/etc/turnserver.conf @@ -217,8 +217,15 @@ # #oauth +#The default realm to be used for the users when no explicit origin/realm +#relationship was found in the database. Must be used with long-term +#credentials mechanism or with TURN REST API. +# +#realm=realm + # 'Static' user accounts for long term credentials mechanism, only. # This option cannot be used with TURN REST API. +# This option require a realm. # 'Static' user accounts are NOT dynamically checked by the turnserver process, # so that they can NOT be changed while the turnserver is running. # diff --git a/man/man1/turnadmin.1 b/man/man1/turnadmin.1 index cd2c5852..9ffb8a08 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 8852fb51..70258b14 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 8182b992..fc9c9ec0 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/rpm/CentOS7.pre.build.sh b/rpm/CentOS7.pre.build.sh index e7be72ef..85a39864 100755 --- a/rpm/CentOS7.pre.build.sh +++ b/rpm/CentOS7.pre.build.sh @@ -26,7 +26,7 @@ cd ${CPWD} # Platform file -echo "CentOS7.2" > ${BUILDDIR}/platform +echo "CentOS7.4" > ${BUILDDIR}/platform cp ${CPWD}/epel7.install.sh ${BUILDDIR}/install.sh diff --git a/rpm/build.settings.sh b/rpm/build.settings.sh index 4000fb9a..cf95b46e 100755 --- a/rpm/build.settings.sh +++ b/rpm/build.settings.sh @@ -2,7 +2,7 @@ # Common settings script. -TURNVERSION=4.5.0.6 +TURNVERSION=4.5.0.7 BUILDDIR=~/rpmbuild ARCH=`uname -p` TURNSERVER_GIT_URL=https://github.com/coturn/coturn.git diff --git a/rpm/turnserver.spec b/rpm/turnserver.spec index 255be3ca..516b7934 100644 --- a/rpm/turnserver.spec +++ b/rpm/turnserver.spec @@ -1,5 +1,5 @@ Name: turnserver -Version: 4.5.0.6 +Version: 4.5.0.7 Release: 0%{dist} Summary: Coturn TURN Server @@ -295,6 +295,8 @@ fi %{_includedir}/turn/client/TurnMsgLib.h %changelog +* Sun Dec 10 2017 Oleg Moskalenko + - Sync to 4.5.0.7 * Mon Oct 17 2016 Oleg Moskalenko - Sync to 4.5.0.6 * Sat Aug 27 2016 Oleg Moskalenko diff --git a/src/apps/natdiscovery/natdiscovery.c b/src/apps/natdiscovery/natdiscovery.c index 8c8ae67f..a8080c23 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,19 +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, local_addr, "Local addr: "); } else { printf("Cannot read the response\n"); } @@ -218,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__); } } @@ -271,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; @@ -308,36 +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, local_addr, "Local addr: "); } else { printf("Cannot read the response\n"); } @@ -348,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; @@ -368,38 +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 (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){ @@ -410,112 +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; - + 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(&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_addr, &other_addr); - addr_set_port(&remote_addr, port); + if(optind>=argc) { + fprintf(stderr, "%s\n", Usage); + exit(-1); + } - run_stunclient(&remote_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 Enpoint 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_addr, &other_addr); - run_stunclient(&remote_addr, &reflexive_addr, &other_addr, &local_port, &rfc5780,-1,0,0,0); + 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 Enpoint 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; } diff --git a/src/apps/relay/mainrelay.c b/src/apps/relay/mainrelay.c index 7aba10c2..9089b263 100644 --- a/src/apps/relay/mainrelay.c +++ b/src/apps/relay/mainrelay.c @@ -598,6 +598,7 @@ static char Usage[] = "Usage: turnserver [options]\n" " After the initialization, the turnserver process\n" " will make an attempt to change the current group ID to that group.\n" " --mobility Mobility with ICE (MICE) specs support.\n" +" --no-http Turn OFF the HTTP-Admin-Interface. By default it is always ON.\n" " --no-cli Turn OFF the CLI support. By default it is always ON.\n" " --cli-ip= Local system IP address to be used for CLI server endpoint. Default value\n" " is 127.0.0.1.\n" @@ -742,7 +743,8 @@ enum EXTRA_OPTS { ADMIN_USER_QUOTA_OPT, SERVER_NAME_OPT, OAUTH_OPT, - PROD_OPT + PROD_OPT, + NO_HTTP_OPT }; struct myoption { @@ -849,6 +851,7 @@ static const struct myoption long_options[] = { { "cli-ip", required_argument, NULL, CLI_IP_OPT }, { "cli-port", required_argument, NULL, CLI_PORT_OPT }, { "cli-password", required_argument, NULL, CLI_PASSWORD_OPT }, + { "no-http", optional_argument, NULL, NO_HTTP_OPT }, { "server-relay", optional_argument, NULL, SERVER_RELAY_OPT }, { "cli-max-output-sessions", required_argument, NULL, CLI_MAX_SESSIONS_OPT }, { "ec-curve-name", required_argument, NULL, EC_CURVE_NAME_OPT }, @@ -992,6 +995,9 @@ static void set_option(int c, char *value) case NO_CLI_OPT: use_cli = !get_bool_value(value); break; + case NO_HTTP_OPT: + use_http = !get_bool_value(value); + break; case CLI_IP_OPT: if(make_ioa_addr((const u08bits*)value,0,&cli_addr)<0) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"Cannot set cli address: %s\n",value); diff --git a/src/apps/relay/netengine.c b/src/apps/relay/netengine.c index 11a6fec3..d7d98cf8 100644 --- a/src/apps/relay/netengine.c +++ b/src/apps/relay/netengine.c @@ -1651,7 +1651,7 @@ static void setup_relay_server(struct relay_server *rs, ioa_engine_handle e, int send_turn_session_info, send_https_socket, allocate_bps, - turn_params.oauth, turn_params.oauth_server_name); + turn_params.oauth, turn_params.oauth_server_name, use_http); if(to_set_rfc5780) { set_rfc5780(&(rs->server), get_alt_addr, send_message_from_listener_to_client); diff --git a/src/apps/relay/ns_ioalib_engine_impl.c b/src/apps/relay/ns_ioalib_engine_impl.c index 6db53525..825f4736 100644 --- a/src/apps/relay/ns_ioalib_engine_impl.c +++ b/src/apps/relay/ns_ioalib_engine_impl.c @@ -3596,6 +3596,14 @@ void turn_report_allocation_delete(void *a) } send_message_to_redis(e->rch, "del", key, ""); send_message_to_redis(e->rch, "publish", key, "deleted"); + + // report total traffic usage for this allocation + if(ss->realm_options.name[0]) { + snprintf(key, sizeof(key), "turn/realm/%s/user/%s/allocation/%018llu/total_traffic", ss->realm_options.name, (char*)ss->username, (unsigned long long)ss->id); + } else { + snprintf(key, sizeof(key), "turn/user/%s/allocation/%018llu/total_traffic", (char*)ss->username, (unsigned long long)ss->id); + } + send_message_to_redis(e->rch, "publish", key, "rcvp=%lu, rcvb=%lu, sentp=%lu, sentb=%lu", (unsigned long)(ss->t_received_packets), (unsigned long)(ss->t_received_bytes), (unsigned long)(ss->t_sent_packets), (unsigned long)(ss->t_sent_bytes)); } #endif } diff --git a/src/apps/relay/turn_admin_server.c b/src/apps/relay/turn_admin_server.c index 54c40a16..14c3ae9b 100644 --- a/src/apps/relay/turn_admin_server.c +++ b/src/apps/relay/turn_admin_server.c @@ -77,6 +77,8 @@ struct admin_server adminserver; int use_cli = 1; +int use_http = 1; + ioa_addr cli_addr; int cli_addr_set = 0; @@ -1210,8 +1212,7 @@ void setup_admin_thread(void) bufferevent_setcb(adminserver.in_buf, admin_server_receive_message, NULL, NULL, &adminserver); bufferevent_enable(adminserver.in_buf, EV_READ); } - - { + if (use_http) { struct bufferevent *pair[2]; bufferevent_pair_new(adminserver.event_base, TURN_BUFFEREVENTS_OPTIONS, pair); diff --git a/src/apps/relay/turn_admin_server.h b/src/apps/relay/turn_admin_server.h index a1e5570c..eb8e877f 100644 --- a/src/apps/relay/turn_admin_server.h +++ b/src/apps/relay/turn_admin_server.h @@ -81,6 +81,8 @@ extern struct admin_server adminserver; extern int use_cli; +extern int use_http; + #define CLI_DEFAULT_IP ("127.0.0.1") extern ioa_addr cli_addr; extern int cli_addr_set; diff --git a/src/ns_turn_defs.h b/src/ns_turn_defs.h index a0d18eab..225968c5 100644 --- a/src/ns_turn_defs.h +++ b/src/ns_turn_defs.h @@ -31,7 +31,7 @@ #ifndef __IOADEFS__ #define __IOADEFS__ -#define TURN_SERVER_VERSION "4.5.0.6" +#define TURN_SERVER_VERSION "4.5.0.7" #define TURN_SERVER_VERSION_NAME "dan Eider" #define TURN_SOFTWARE "Coturn-" TURN_SERVER_VERSION " '" TURN_SERVER_VERSION_NAME "'" diff --git a/src/server/ns_turn_server.c b/src/server/ns_turn_server.c index 1045ba95..fa957e68 100644 --- a/src/server/ns_turn_server.c +++ b/src/server/ns_turn_server.c @@ -4543,32 +4543,34 @@ static int read_client_connection(turn_turnserver *server, } } else { - SOCKET_TYPE st = get_ioa_socket_type(ss->client_socket); - if(is_stream_socket(st)) { - if(is_http((char*)ioa_network_buffer_data(in_buffer->nbh), ioa_network_buffer_get_size(in_buffer->nbh))) { - const char *proto = "HTTP"; - ioa_network_buffer_data(in_buffer->nbh)[ioa_network_buffer_get_size(in_buffer->nbh)] = 0; - if(st==TLS_SOCKET) { - proto = "HTTPS"; - set_ioa_socket_app_type(ss->client_socket,HTTPS_CLIENT_SOCKET); - TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: %s (%s %s) request: %s\n", __FUNCTION__, proto, get_ioa_socket_cipher(ss->client_socket), get_ioa_socket_ssl_method(ss->client_socket), (char*)ioa_network_buffer_data(in_buffer->nbh)); - if(server->send_https_socket) { - TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s socket to be detached: 0x%lx, st=%d, sat=%d\n", __FUNCTION__,(long)ss->client_socket, get_ioa_socket_type(ss->client_socket), get_ioa_socket_app_type(ss->client_socket)); - ioa_socket_handle new_s = detach_ioa_socket(ss->client_socket); - if(new_s) { - TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s new detached socket: 0x%lx, st=%d, sat=%d\n", __FUNCTION__,(long)new_s, get_ioa_socket_type(new_s), get_ioa_socket_app_type(new_s)); - server->send_https_socket(new_s); + if (server->use_http) { + SOCKET_TYPE st = get_ioa_socket_type(ss->client_socket); + if(is_stream_socket(st)) { + if(is_http((char*)ioa_network_buffer_data(in_buffer->nbh), ioa_network_buffer_get_size(in_buffer->nbh))) { + const char *proto = "HTTP"; + ioa_network_buffer_data(in_buffer->nbh)[ioa_network_buffer_get_size(in_buffer->nbh)] = 0; + if(st==TLS_SOCKET) { + proto = "HTTPS"; + set_ioa_socket_app_type(ss->client_socket,HTTPS_CLIENT_SOCKET); + TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: %s (%s %s) request: %s\n", __FUNCTION__, proto, get_ioa_socket_cipher(ss->client_socket), get_ioa_socket_ssl_method(ss->client_socket), (char*)ioa_network_buffer_data(in_buffer->nbh)); + if(server->send_https_socket) { + TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s socket to be detached: 0x%lx, st=%d, sat=%d\n", __FUNCTION__,(long)ss->client_socket, get_ioa_socket_type(ss->client_socket), get_ioa_socket_app_type(ss->client_socket)); + ioa_socket_handle new_s = detach_ioa_socket(ss->client_socket); + if(new_s) { + TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s new detached socket: 0x%lx, st=%d, sat=%d\n", __FUNCTION__,(long)new_s, get_ioa_socket_type(new_s), get_ioa_socket_app_type(new_s)); + server->send_https_socket(new_s); + } + ss->to_be_closed = 1; } - ss->to_be_closed = 1; + } else { + set_ioa_socket_app_type(ss->client_socket,HTTP_CLIENT_SOCKET); + if(server->verbose) { + TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: %s request: %s\n", __FUNCTION__, proto, (char*)ioa_network_buffer_data(in_buffer->nbh)); + } + handle_http_echo(ss->client_socket); } - } else { - set_ioa_socket_app_type(ss->client_socket,HTTP_CLIENT_SOCKET); - if(server->verbose) { - TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: %s request: %s\n", __FUNCTION__, proto, (char*)ioa_network_buffer_data(in_buffer->nbh)); - } - handle_http_echo(ss->client_socket); + return 0; } - return 0; } } } @@ -4825,7 +4827,7 @@ void init_turn_server(turn_turnserver* server, send_turn_session_info_cb send_turn_session_info, send_https_socket_cb send_https_socket, allocate_bps_cb allocate_bps_func, - int oauth, const char* oauth_server_name) { + int oauth, const char* oauth_server_name, int use_http) { if (!server) return; @@ -4892,6 +4894,8 @@ void init_turn_server(turn_turnserver* server, server->allocate_bps_func = allocate_bps_func; + server->use_http = use_http; + set_ioa_timer(server->e, 1, 0, timer_timeout_handler, server, 1, "timer_timeout_handler"); } diff --git a/src/server/ns_turn_server.h b/src/server/ns_turn_server.h index 7c1cfd45..4c419421 100644 --- a/src/server/ns_turn_server.h +++ b/src/server/ns_turn_server.h @@ -169,6 +169,9 @@ struct _turn_turnserver { /* oAuth: */ int oauth; const char* oauth_server_name; + + /* HTTP-Admin-Server: */ + int use_http; }; const char * get_version(turn_turnserver *server); @@ -212,7 +215,8 @@ void init_turn_server(turn_turnserver* server, send_https_socket_cb send_https_socket, allocate_bps_cb allocate_bps_func, int oauth, - const char* oauth_server_name); + const char* oauth_server_name, + int use_http); ioa_engine_handle turn_server_get_engine(turn_turnserver *s); diff --git a/turndb/schema.stats.redis b/turndb/schema.stats.redis index c35fd0e0..428074cf 100644 --- a/turndb/schema.stats.redis +++ b/turndb/schema.stats.redis @@ -16,6 +16,12 @@ The keys are "turn/user//allocation//traffic". The application tha in the traffic information must subscribe to the events as: psubscribe turn/realm/*/user/*/allocation/*/traffic + +Total traffic information is also reported when the allocation is deleted. The keys are +"turn/user//allocation//total_traffic". Applications interested in the total amount +of traffic per allocation can subscribe to these events as: + + psubscribe turn/realm/*/user/*/allocation/*/total_traffic Or, to receive all allocation events: