TURN support (EJAB-1017)
This commit is contained in:
parent
115da54557
commit
90a5c054d4
102
doc/guide.tex
102
doc/guide.tex
|
@ -398,7 +398,7 @@ Some options that you may be interested in modifying:
|
||||||
Enable Stream Compression (XEP-0138) using zlib.
|
Enable Stream Compression (XEP-0138) using zlib.
|
||||||
|
|
||||||
\titem{--enable-stun}
|
\titem{--enable-stun}
|
||||||
Enable STUN support (see section \ref{stun}).
|
Enable STUN/TURN support (see section \ref{stun}).
|
||||||
|
|
||||||
\titem{--enable-iconv}
|
\titem{--enable-iconv}
|
||||||
Enable iconv support. This is needed for \term{mod\_irc} (see seciont \ref{modirc}).
|
Enable iconv support. This is needed for \term{mod\_irc} (see seciont \ref{modirc}).
|
||||||
|
@ -891,9 +891,13 @@ The available modules, their purpose and the options allowed by each one are:
|
||||||
\footahref{http://tools.ietf.org/html/rfc3261}{RFC 3261}.\\
|
\footahref{http://tools.ietf.org/html/rfc3261}{RFC 3261}.\\
|
||||||
Options: \texttt{certfile}, \texttt{tls}
|
Options: \texttt{certfile}, \texttt{tls}
|
||||||
\titem{\texttt{ejabberd\_stun}}
|
\titem{\texttt{ejabberd\_stun}}
|
||||||
Handles STUN Binding requests as defined in
|
Handles STUN/TURN requests as defined in
|
||||||
\footahref{http://tools.ietf.org/html/rfc5389}{RFC 5389}.\\
|
\footahref{http://tools.ietf.org/html/rfc5389}{RFC 5389} and
|
||||||
Options: \texttt{certfile}
|
\footahref{http://tools.ietf.org/html/rfc5766}{RFC 5766}.\\
|
||||||
|
Options: \texttt{certfile}, \texttt{tls}, \texttt{use\_turn}, \texttt{turn\_ip},
|
||||||
|
\texttt{turn\_port\_range}, \texttt{turn\_max\_allocations},
|
||||||
|
\texttt{turn\_max\_permissions}, \texttt{shaper}, \texttt{server\_name},
|
||||||
|
\texttt{auth\_realm}, \texttt{auth\_type}
|
||||||
\titem{\texttt{ejabberd\_http}}
|
\titem{\texttt{ejabberd\_http}}
|
||||||
Handles incoming HTTP connections.\\
|
Handles incoming HTTP connections.\\
|
||||||
Options: \texttt{captcha}, \texttt{certfile}, \texttt{default\_host}, \texttt{http\_bind}, \texttt{http\_poll},
|
Options: \texttt{captcha}, \texttt{certfile}, \texttt{default\_host}, \texttt{http\_bind}, \texttt{http\_poll},
|
||||||
|
@ -1991,22 +1995,57 @@ listen:
|
||||||
...
|
...
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
||||||
\makesubsection{stun}{STUN}
|
\makesubsection{stun}{STUN and TURN}
|
||||||
\ind{options!stun}\ind{stun}
|
\ind{options!stun}\ind{stun}
|
||||||
|
|
||||||
\ejabberd{} is able to act as a stand-alone STUN server
|
\ejabberd{} is able to act as a stand-alone STUN/TURN server
|
||||||
(\footahref{http://tools.ietf.org/html/rfc5389}{RFC 5389}). Currently only Binding usage
|
(\footahref{http://tools.ietf.org/html/rfc5389}{RFC 5389}/\footahref{http://tools.ietf.org/html/rfc5766}{RFC 5766}). In that role \ejabberd{} helps clients with ICE (\footahref{http://tools.ietf.org/html/rfc5245}{RFC 5245}) or Jingle ICE (\xepref{0176}) support to discover their external addresses and ports and to relay media traffic when it is impossible to establish direct
|
||||||
is supported. In that role \ejabberd{} helps clients with ICE (\footahref{http://tools.ietf.org/html/rfc5245}{RFC 5245}) or Jingle ICE (\xepref{0176}) support to discover their external addresses and ports.
|
peer-to-peer connection.
|
||||||
|
|
||||||
You should configure \term{ejabberd\_stun} listening module as described in \ref{listened} section.
|
You should configure \term{ejabberd\_stun} listening module as described in \ref{listened} section.
|
||||||
If \option{certfile} option is defined, \ejabberd{} multiplexes TCP and
|
The specific configurable options are:
|
||||||
TLS over TCP connections on the same port. Obviously, \option{certfile} option
|
\begin{description}
|
||||||
is defined for \term{tcp} only. Note however that TCP or TLS over TCP
|
\titem{tls: true|false}
|
||||||
support is not required for Binding usage and is reserved for
|
If enabled, \option{certfile} option must be set, otherwise \ejabberd{}
|
||||||
\footahref{http://tools.ietf.org/html/draft-ietf-behave-turn-16}{TURN}
|
will not be able to accept TLS connections. Obviously, this option
|
||||||
functionality. Feel free to configure \term{udp} transport only.
|
makes sense for \term{tcp} transport only. The default is \term{false}.
|
||||||
|
\titem{certfile: Path}
|
||||||
|
Path to the certificate file. Only makes sense when \option{tls} is set.
|
||||||
|
\titem{use\_turn: true|false}
|
||||||
|
Enables/disables TURN (media relay) functionality. The default is \term{false}.
|
||||||
|
\titem{turn\_ip: String}
|
||||||
|
The IPv4 address advertised by your TURN server. The address should not be NAT'ed
|
||||||
|
or firewalled. There is not default, so you should set this option explicitly.
|
||||||
|
Implies \term{use\_turn}.
|
||||||
|
\titem{turn\_min\_port: Integer}
|
||||||
|
Together with \option{turn\_max\_port} forms port range to allocate from.
|
||||||
|
The default is 49152. Implies \term{use\_turn}.
|
||||||
|
\titem{turn\_max\_port: Integer}
|
||||||
|
Together with \option{turn\_min\_port} forms port range to allocate from.
|
||||||
|
The default is 65535. Implies \term{use\_turn}.
|
||||||
|
\titem{turn\_max\_allocations: Integer|unlimited}
|
||||||
|
Maximum number of TURN allocations available from the particular IP address.
|
||||||
|
The default value is 10. Implies \term{use\_turn}.
|
||||||
|
\titem{turn\_max\_permissions: Integer|unlimited}
|
||||||
|
Maximum number of TURN permissions available from the particular IP address.
|
||||||
|
The default value is 10. Implies \term{use\_turn}.
|
||||||
|
\titem{auth\_type: user|anonymous}
|
||||||
|
Which authentication type to use for TURN allocation requests. When type \term{user}
|
||||||
|
is set, ejabberd authentication backend is used. For \term{anonymous} type
|
||||||
|
no authentication is performed (not recommended for public services).
|
||||||
|
The default is \term{user}. Implies \term{use\_turn}.
|
||||||
|
\titem{auth\_realm: String}
|
||||||
|
When \option{auth\_type} is set to \term{user} and you have several virtual
|
||||||
|
hosts configured you should set this option explicitly to the virtual host
|
||||||
|
you want to serve on this particular listening port. Implies \term{use\_turn}.
|
||||||
|
\titem{shaper: Atom}
|
||||||
|
For \term{tcp} transports defines shaper to use. The default is \term{none}.
|
||||||
|
\titem{server\_name: String}
|
||||||
|
Defines software version to return with every response. The default is the
|
||||||
|
STUN library version.
|
||||||
|
\end{description}
|
||||||
|
|
||||||
Example configuration:
|
Example configuration with disabled TURN functionality (STUN only):
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
listen:
|
listen:
|
||||||
...
|
...
|
||||||
|
@ -2024,18 +2063,41 @@ listen:
|
||||||
...
|
...
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
||||||
You also need to configure DNS SRV records properly so clients can easily discover a
|
Example configuration with TURN functionality. Note that STUN is always
|
||||||
STUN server serving your XMPP domain. Refer to section
|
enabled if TURN is enabled. Here, only UDP section is shown:
|
||||||
\footahref{http://tools.ietf.org/html/rfc5389\#section-9}{DNS Discovery of a Server}
|
\begin{verbatim}
|
||||||
of \footahref{http://tools.ietf.org/html/rfc5389}{RFC 5389} for details.
|
listen:
|
||||||
|
...
|
||||||
|
-
|
||||||
|
port: 3478
|
||||||
|
transport: udp
|
||||||
|
use_turn: true
|
||||||
|
turn_ip: 10.20.30.1
|
||||||
|
module: ejabberd_stun
|
||||||
|
...
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
Example DNS SRV configuration:
|
You also need to configure DNS SRV records properly so clients can easily discover a
|
||||||
|
STUN/TURN server serving your XMPP domain. Refer to section
|
||||||
|
\footahref{http://tools.ietf.org/html/rfc5389\#section-9}{DNS Discovery of a Server}
|
||||||
|
of \footahref{http://tools.ietf.org/html/rfc5389}{RFC 5389} and section
|
||||||
|
\footahref{http://tools.ietf.org/html/rfc5766\#section-6}{Creating an Allocation}
|
||||||
|
of \footahref{http://tools.ietf.org/html/rfc5766}{RFC 5766} for details.
|
||||||
|
|
||||||
|
Example DNS SRV configuration for STUN only:
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
_stun._udp IN SRV 0 0 3478 stun.example.com.
|
_stun._udp IN SRV 0 0 3478 stun.example.com.
|
||||||
_stun._tcp IN SRV 0 0 3478 stun.example.com.
|
_stun._tcp IN SRV 0 0 3478 stun.example.com.
|
||||||
_stuns._tcp IN SRV 0 0 5349 stun.example.com.
|
_stuns._tcp IN SRV 0 0 5349 stun.example.com.
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
||||||
|
And you should also add these in the case if TURN is enabled:
|
||||||
|
\begin{verbatim}
|
||||||
|
_turn._udp IN SRV 0 0 3478 turn.example.com.
|
||||||
|
_turn._tcp IN SRV 0 0 3478 turn.example.com.
|
||||||
|
_turns._tcp IN SRV 0 0 5349 turn.example.com.
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
\makesubsection{sip}{SIP}
|
\makesubsection{sip}{SIP}
|
||||||
\ind{options!sip}\ind{sip}
|
\ind{options!sip}\ind{sip}
|
||||||
|
|
||||||
|
|
|
@ -366,7 +366,6 @@ start_listener2(Port, Module, Opts) ->
|
||||||
%% It is only required to start the supervisor in some cases.
|
%% It is only required to start the supervisor in some cases.
|
||||||
%% But it doesn't hurt to attempt to start it for any listener.
|
%% But it doesn't hurt to attempt to start it for any listener.
|
||||||
%% So, it's normal (and harmless) that in most cases this call returns: {error, {already_started, pid()}}
|
%% So, it's normal (and harmless) that in most cases this call returns: {error, {already_started, pid()}}
|
||||||
maybe_start_stun(Module),
|
|
||||||
maybe_start_sip(Module),
|
maybe_start_sip(Module),
|
||||||
start_module_sup(Port, Module),
|
start_module_sup(Port, Module),
|
||||||
start_listener_sup(Port, Module, Opts).
|
start_listener_sup(Port, Module, Opts).
|
||||||
|
@ -482,13 +481,6 @@ is_frontend(_) -> false.
|
||||||
strip_frontend({frontend, Module}) -> Module;
|
strip_frontend({frontend, Module}) -> Module;
|
||||||
strip_frontend(Module) when is_atom(Module) -> Module.
|
strip_frontend(Module) when is_atom(Module) -> Module.
|
||||||
|
|
||||||
-spec maybe_start_stun(module()) -> any().
|
|
||||||
|
|
||||||
maybe_start_stun(ejabberd_stun) ->
|
|
||||||
ejabberd:start_app(p1_stun);
|
|
||||||
maybe_start_stun(_) ->
|
|
||||||
ok.
|
|
||||||
|
|
||||||
maybe_start_sip(esip_socket) ->
|
maybe_start_sip(esip_socket) ->
|
||||||
ejabberd:start_app(esip);
|
ejabberd:start_app(esip);
|
||||||
maybe_start_sip(_) ->
|
maybe_start_sip(_) ->
|
||||||
|
@ -671,12 +663,8 @@ prepare_ip(IP) when is_list(IP) ->
|
||||||
prepare_ip(IP) when is_binary(IP) ->
|
prepare_ip(IP) when is_binary(IP) ->
|
||||||
prepare_ip(binary_to_list(IP)).
|
prepare_ip(binary_to_list(IP)).
|
||||||
|
|
||||||
prepare_mod(ejabberd_stun) ->
|
|
||||||
prepare_mod(stun);
|
|
||||||
prepare_mod(ejabberd_sip) ->
|
prepare_mod(ejabberd_sip) ->
|
||||||
prepare_mod(sip);
|
prepare_mod(sip);
|
||||||
prepare_mod(stun) ->
|
|
||||||
stun;
|
|
||||||
prepare_mod(sip) ->
|
prepare_mod(sip) ->
|
||||||
esip_socket;
|
esip_socket;
|
||||||
prepare_mod(Mod) when is_atom(Mod) ->
|
prepare_mod(Mod) when is_atom(Mod) ->
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||||
|
%%% @copyright (C) 2014, Evgeny Khramtsov
|
||||||
|
%%% @doc
|
||||||
|
%%%
|
||||||
|
%%% @end
|
||||||
|
%%% Created : 8 May 2014 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
-module(ejabberd_stun).
|
||||||
|
|
||||||
|
%% API
|
||||||
|
-export([tcp_init/2, udp_init/2, udp_recv/5, start/2, socket_type/0]).
|
||||||
|
|
||||||
|
-include("ejabberd.hrl").
|
||||||
|
-include("logger.hrl").
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% API
|
||||||
|
%%%===================================================================
|
||||||
|
tcp_init(Socket, Opts) ->
|
||||||
|
ejabberd:start_app(p1_stun),
|
||||||
|
stun:tcp_init(Socket, prepare_turn_opts(Opts)).
|
||||||
|
|
||||||
|
udp_init(Socket, Opts) ->
|
||||||
|
ejabberd:start_app(p1_stun),
|
||||||
|
stun:udp_init(Socket, prepare_turn_opts(Opts)).
|
||||||
|
|
||||||
|
udp_recv(Socket, Addr, Port, Packet, Opts) ->
|
||||||
|
stun:udp_recv(Socket, Addr, Port, Packet, Opts).
|
||||||
|
|
||||||
|
start(Opaque, Opts) ->
|
||||||
|
stun:start(Opaque, Opts).
|
||||||
|
|
||||||
|
socket_type() ->
|
||||||
|
raw.
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Internal functions
|
||||||
|
%%%===================================================================
|
||||||
|
prepare_turn_opts(Opts) ->
|
||||||
|
UseTurn = proplists:get_bool(use_turn, Opts),
|
||||||
|
prepare_turn_opts(Opts, UseTurn).
|
||||||
|
|
||||||
|
prepare_turn_opts(Opts, _UseTurn = false) ->
|
||||||
|
Opts;
|
||||||
|
prepare_turn_opts(Opts, _UseTurn = true) ->
|
||||||
|
NumberOfMyHosts = length(?MYHOSTS),
|
||||||
|
case proplists:get_value(turn_ip, Opts) of
|
||||||
|
undefined ->
|
||||||
|
?WARNING_MSG("option 'turn_ip' is undefined, "
|
||||||
|
"more likely the TURN relay won't be working "
|
||||||
|
"properly", []);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
AuthFun = fun ejabberd_auth:get_password_s/2,
|
||||||
|
Shaper = gen_mod:get_opt(shaper, Opts,
|
||||||
|
fun(S) when is_atom(S) -> S end,
|
||||||
|
none),
|
||||||
|
AuthType = gen_mod:get_opt(auth_type, Opts,
|
||||||
|
fun(anonymous) -> anonymous;
|
||||||
|
(user) -> user
|
||||||
|
end, user),
|
||||||
|
Realm = case gen_mod:get_opt(auth_realm, Opts, fun iolist_to_binary/1) of
|
||||||
|
undefined when AuthType == user ->
|
||||||
|
if NumberOfMyHosts > 1 ->
|
||||||
|
?WARNING_MSG("you have several virtual "
|
||||||
|
"hosts configured, but option "
|
||||||
|
"'auth_realm' is undefined and "
|
||||||
|
"'auth_type' is set to 'user', "
|
||||||
|
"more likely the TURN relay won't "
|
||||||
|
"be working properly. Using ~s as "
|
||||||
|
"a fallback", [?MYNAME]);
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
[{auth_realm, ?MYNAME}];
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
end,
|
||||||
|
MaxRate = shaper:get_max_rate(Shaper),
|
||||||
|
Realm ++ [{auth_fun, AuthFun},{shaper, MaxRate} |
|
||||||
|
lists:keydelete(shaper, 1, Opts)].
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
-author('alexey@process-one.net').
|
-author('alexey@process-one.net').
|
||||||
|
|
||||||
-export([start/0, new/1, new1/1, update/2,
|
-export([start/0, new/1, new1/1, update/2, get_max_rate/1,
|
||||||
transform_options/1, load_from_config/0]).
|
transform_options/1, load_from_config/0]).
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
|
@ -74,6 +74,18 @@ load_from_config() ->
|
||||||
{error, Err}
|
{error, Err}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec get_max_rate(atom()) -> none | non_neg_integer().
|
||||||
|
|
||||||
|
get_max_rate(none) ->
|
||||||
|
none;
|
||||||
|
get_max_rate(Name) ->
|
||||||
|
case ets:lookup(shaper, {Name, global}) of
|
||||||
|
[#shaper{maxrate = R}] ->
|
||||||
|
R;
|
||||||
|
[] ->
|
||||||
|
none
|
||||||
|
end.
|
||||||
|
|
||||||
-spec new(atom()) -> shaper().
|
-spec new(atom()) -> shaper().
|
||||||
|
|
||||||
new(none) ->
|
new(none) ->
|
||||||
|
|
Loading…
Reference in New Issue