From 83fa637569ad5242b940d3798bcb9a8dfbd450e5 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Tue, 19 May 2020 21:42:41 +0200 Subject: [PATCH] ejabberd_stun: Support IPv6 for TURN The stun application now supports RFC 6156: TURN Extension for IPv6, and therefore needs separate IPv4 and IPv6 relay addresses. --- ejabberd.yml.example | 4 +++- mix.exs | 2 +- rebar.config | 2 +- src/ejabberd_config_transformer.erl | 22 ++++++++++++++++++++-- src/ejabberd_stun.erl | 15 +++++++++------ src/mod_stun_disco.erl | 20 ++++++++++---------- 6 files changed, 44 insertions(+), 21 deletions(-) diff --git a/ejabberd.yml.example b/ejabberd.yml.example index ba1a5a77b..141b8f470 100644 --- a/ejabberd.yml.example +++ b/ejabberd.yml.example @@ -64,7 +64,9 @@ listen: module: ejabberd_stun use_turn: true ## The server's public IPv4 address: - # turn_ip: 203.0.113.3 + # turn_v4_ip: "203.0.113.3" + ## The server's public IPv6 address: + # turn_v6_ip: "2001:db8::3" - port: 1883 ip: "::" diff --git a/mix.exs b/mix.exs index 8cb2c097d..c578b24c4 100644 --- a/mix.exs +++ b/mix.exs @@ -90,7 +90,7 @@ defmodule Ejabberd.Mixfile do {:stringprep, "~> 1.0"}, {:fast_yaml, "~> 1.0"}, {:fast_tls, "~> 1.1"}, - {:stun, git: "https://github.com/processone/stun", ref: "cb6549387e23737f39f44ba7656a351fd7b88c14", override: true}, + {:stun, git: "https://github.com/processone/stun", ref: "481f4dbb8b5793659aedf44048d7c5fde968bfbb", override: true}, {:esip, "~> 1.0.32"}, {:p1_mysql, "~> 1.0"}, {:mqtree, "~> 1.0"}, diff --git a/rebar.config b/rebar.config index 214ccc192..75ea5a7d7 100644 --- a/rebar.config +++ b/rebar.config @@ -36,7 +36,7 @@ {mqtree, ".*", {git, "https://github.com/processone/mqtree", {tag, "1.0.7"}}}, {p1_acme, ".*", {git, "https://github.com/processone/p1_acme.git", {tag, "1.0.5"}}}, {base64url, ".*", {git, "https://github.com/dvv/base64url.git", {tag, "v1.0"}}}, - {if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", "cb6549387e23737f39f44ba7656a351fd7b88c14"}}}, + {if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", "481f4dbb8b5793659aedf44048d7c5fde968bfbb"}}}, {if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.33"}}}}, {if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql", {tag, "1.0.15"}}}}, diff --git a/src/ejabberd_config_transformer.erl b/src/ejabberd_config_transformer.erl index 26a475f3d..2256d48c3 100644 --- a/src/ejabberd_config_transformer.erl +++ b/src/ejabberd_config_transformer.erl @@ -245,8 +245,9 @@ filter(_, _, _, _) -> %%%=================================================================== transform_listener(Opts, Acc) -> Opts1 = transform_request_handlers(Opts), - Opts2 = remove_inet_options(Opts1), - collect_listener_certfiles(Opts2, Acc). + Opts2 = transform_turn_ip(Opts1), + Opts3 = remove_inet_options(Opts2), + collect_listener_certfiles(Opts3, Acc). transform_request_handlers(Opts) -> case lists:keyfind(module, 1, Opts) of @@ -258,6 +259,14 @@ transform_request_handlers(Opts) -> Opts end. +transform_turn_ip(Opts) -> + case lists:keyfind(module, 1, Opts) of + {_, ejabberd_stun} -> + replace_turn_ip(Opts); + _ -> + Opts + end. + replace_request_handlers(Opts) -> Handlers = proplists:get_value(request_handlers, Opts, []), Handlers1 = @@ -322,6 +331,15 @@ remove_xmlrpc_access_commands(Opts) -> true end, Opts). +replace_turn_ip(Opts) -> + lists:filtermap( + fun({turn_ip, Val}) -> + warn_replaced_option(turn_ip, turn_v4_ip), + {true, {turn_v4_ip, Val}}; + (_) -> + true + end, Opts). + remove_inet_options(Opts) -> lists:filter( fun({Opt, _}) when Opt == inet; Opt == inet6 -> diff --git a/src/ejabberd_stun.erl b/src/ejabberd_stun.erl index 459697255..68e74d861 100644 --- a/src/ejabberd_stun.erl +++ b/src/ejabberd_stun.erl @@ -101,20 +101,20 @@ prepare_turn_opts(Opts, _UseTurn = false) -> set_certfile(Opts); prepare_turn_opts(Opts, _UseTurn = true) -> NumberOfMyHosts = length(ejabberd_option:hosts()), - TurnIP = case proplists:get_value(turn_ip, Opts) of + TurnIP = case proplists:get_value(turn_v4_ip, Opts) of undefined -> MyIP = misc:get_my_ip(), case MyIP of {127, _, _, _} -> - ?WARNING_MSG("Option 'turn_ip' is undefined and " - "the server's hostname doesn't " + ?WARNING_MSG("Option 'turn_v4_ip' is undefined " + "and the server's hostname doesn't " "resolve to a public IPv4 address, " "most likely the TURN relay won't be " "working properly", []); _ -> ok end, - [{turn_ip, MyIP}]; + [{turn_v4_ip, MyIP}]; _ -> [] end, @@ -161,8 +161,10 @@ listen_opt_type(use_turn) -> econf:bool(); listen_opt_type(ip) -> econf:ip(); -listen_opt_type(turn_ip) -> +listen_opt_type(turn_v4_ip) -> econf:ipv4(); +listen_opt_type(turn_v6_ip) -> + econf:ipv6(); listen_opt_type(auth_type) -> econf:enum([anonymous, user]); listen_opt_type(auth_realm) -> @@ -183,7 +185,8 @@ listen_opt_type(certfile) -> listen_options() -> [{shaper, none}, {use_turn, false}, - {turn_ip, undefined}, + {turn_v4_ip, undefined}, + {turn_v6_ip, undefined}, {auth_type, user}, {auth_realm, undefined}, {tls, false}, diff --git a/src/mod_stun_disco.erl b/src/mod_stun_disco.erl index 377d25227..32b0cae98 100644 --- a/src/mod_stun_disco.erl +++ b/src/mod_stun_disco.erl @@ -602,8 +602,8 @@ parse_listener({{Port, _Addr, Transport}, ?STUN_MODULE, Opts}) -> case get_listener_ip(Opts) of {127, _, _, _} = Addr -> ?INFO_MSG("Won't auto-announce STUN/TURN service with loopback " - "address: ~s:~B (~s), please specify a public 'turn_ip'", - [misc:ip_to_list(Addr), Port, Transport]), + "address: ~s:~B (~s), please specify a public " + "'turn_v4_ip'", [misc:ip_to_list(Addr), Port, Transport]), []; Addr -> Host = maybe_resolve(Addr), @@ -632,16 +632,16 @@ parse_listener({_EndPoint, Module, _Opts}) -> []. -spec get_listener_ip(map()) -> inet:ip_address(). -get_listener_ip(#{ip := { 0, 0, 0, 0}} = Opts) -> get_turn_ip(Opts); -get_listener_ip(#{ip := {127, _, _, _}} = Opts) -> get_turn_ip(Opts); -get_listener_ip(#{ip := { 10, _, _, _}} = Opts) -> get_turn_ip(Opts); -get_listener_ip(#{ip := {172, 16, _, _}} = Opts) -> get_turn_ip(Opts); -get_listener_ip(#{ip := {192, 168, _, _}} = Opts) -> get_turn_ip(Opts); +get_listener_ip(#{ip := { 0, 0, 0, 0}} = Opts) -> get_turn_v4_ip(Opts); +get_listener_ip(#{ip := {127, _, _, _}} = Opts) -> get_turn_v4_ip(Opts); +get_listener_ip(#{ip := { 10, _, _, _}} = Opts) -> get_turn_v4_ip(Opts); +get_listener_ip(#{ip := {172, 16, _, _}} = Opts) -> get_turn_v4_ip(Opts); +get_listener_ip(#{ip := {192, 168, _, _}} = Opts) -> get_turn_v4_ip(Opts); get_listener_ip(#{ip := IP}) -> IP. --spec get_turn_ip(map()) -> inet:ip_address(). -get_turn_ip(#{turn_ip := {_, _, _, _} = TurnIP}) -> TurnIP; -get_turn_ip(#{turn_ip := undefined}) -> misc:get_my_ip(). +-spec get_turn_v4_ip(map()) -> inet:ip_address(). +get_turn_v4_ip(#{turn_v4_ip := {_, _, _, _} = TurnIP}) -> TurnIP; +get_turn_v4_ip(#{turn_v4_ip := undefined}) -> misc:get_my_ip(). -spec is_restricted(map()) -> boolean(). is_restricted(#{auth_type := user}) -> true;