mod_stun_disco: Offer local IPv6 services
Also announce local STUN/TURN services listening on IPv6 sockets (unless the 'offer_local_services' option is set to 'false').
This commit is contained in:
parent
83fa637569
commit
f19b975e8d
|
@ -103,7 +103,7 @@ prepare_turn_opts(Opts, _UseTurn = true) ->
|
||||||
NumberOfMyHosts = length(ejabberd_option:hosts()),
|
NumberOfMyHosts = length(ejabberd_option:hosts()),
|
||||||
TurnIP = case proplists:get_value(turn_v4_ip, Opts) of
|
TurnIP = case proplists:get_value(turn_v4_ip, Opts) of
|
||||||
undefined ->
|
undefined ->
|
||||||
MyIP = misc:get_my_ip(),
|
MyIP = misc:get_my_v4_ip(),
|
||||||
case MyIP of
|
case MyIP of
|
||||||
{127, _, _, _} ->
|
{127, _, _, _} ->
|
||||||
?WARNING_MSG("Option 'turn_v4_ip' is undefined "
|
?WARNING_MSG("Option 'turn_v4_ip' is undefined "
|
||||||
|
|
16
src/misc.erl
16
src/misc.erl
|
@ -40,8 +40,8 @@
|
||||||
read_css/1, read_img/1, read_js/1, read_lua/1, try_url/1,
|
read_css/1, read_img/1, read_js/1, read_lua/1, try_url/1,
|
||||||
intersection/2, format_val/1, cancel_timer/1, unique_timestamp/0,
|
intersection/2, format_val/1, cancel_timer/1, unique_timestamp/0,
|
||||||
is_mucsub_message/1, best_match/2, pmap/2, peach/2, format_exception/4,
|
is_mucsub_message/1, best_match/2, pmap/2, peach/2, format_exception/4,
|
||||||
get_my_ip/0, parse_ip_mask/1, match_ip_mask/3, format_hosts_list/1,
|
get_my_v4_ip/0, get_my_v6_ip/0, parse_ip_mask/1, match_ip_mask/3,
|
||||||
format_cycle/1, delete_dir/1]).
|
format_hosts_list/1, format_cycle/1, delete_dir/1]).
|
||||||
|
|
||||||
%% Deprecated functions
|
%% Deprecated functions
|
||||||
-export([decode_base64/1, encode_base64/1]).
|
-export([decode_base64/1, encode_base64/1]).
|
||||||
|
@ -509,14 +509,22 @@ format_exception(Level, Class, Reason, Stacktrace) ->
|
||||||
end).
|
end).
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
-spec get_my_ip() -> inet:ip_address().
|
-spec get_my_v4_ip() -> inet:ip4_address().
|
||||||
get_my_ip() ->
|
get_my_v4_ip() ->
|
||||||
{ok, MyHostName} = inet:gethostname(),
|
{ok, MyHostName} = inet:gethostname(),
|
||||||
case inet:getaddr(MyHostName, inet) of
|
case inet:getaddr(MyHostName, inet) of
|
||||||
{ok, Addr} -> Addr;
|
{ok, Addr} -> Addr;
|
||||||
{error, _} -> {127, 0, 0, 1}
|
{error, _} -> {127, 0, 0, 1}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec get_my_v6_ip() -> inet:ip6_address().
|
||||||
|
get_my_v6_ip() ->
|
||||||
|
{ok, MyHostName} = inet:gethostname(),
|
||||||
|
case inet:getaddr(MyHostName, inet6) of
|
||||||
|
{ok, Addr} -> Addr;
|
||||||
|
{error, _} -> {0, 0, 0, 0, 0, 0, 0, 1}
|
||||||
|
end.
|
||||||
|
|
||||||
-spec parse_ip_mask(binary()) -> {ok, {inet:ip4_address(), 0..32}} |
|
-spec parse_ip_mask(binary()) -> {ok, {inet:ip4_address(), 0..32}} |
|
||||||
{ok, {inet:ip6_address(), 0..128}} |
|
{ok, {inet:ip6_address(), 0..128}} |
|
||||||
error.
|
error.
|
||||||
|
|
|
@ -266,7 +266,7 @@ get_streamhost(Host, ServerHost) ->
|
||||||
get_endpoint(Host) ->
|
get_endpoint(Host) ->
|
||||||
Port = mod_proxy65_opt:port(Host),
|
Port = mod_proxy65_opt:port(Host),
|
||||||
IP = case mod_proxy65_opt:ip(Host) of
|
IP = case mod_proxy65_opt:ip(Host) of
|
||||||
undefined -> misc:get_my_ip();
|
undefined -> misc:get_my_v4_ip();
|
||||||
Addr -> Addr
|
Addr -> Addr
|
||||||
end,
|
end,
|
||||||
{Port, IP, tcp}.
|
{Port, IP, tcp}.
|
||||||
|
|
|
@ -233,6 +233,30 @@ mod_doc() ->
|
||||||
" transport: tcp",
|
" transport: tcp",
|
||||||
" restricted: true",
|
" restricted: true",
|
||||||
" -",
|
" -",
|
||||||
|
" host: 2001:db8::3",
|
||||||
|
" port: 3478",
|
||||||
|
" type: stun",
|
||||||
|
" transport: udp",
|
||||||
|
" restricted: false",
|
||||||
|
" -",
|
||||||
|
" host: 2001:db8::3",
|
||||||
|
" port: 3478",
|
||||||
|
" type: turn",
|
||||||
|
" transport: udp",
|
||||||
|
" restricted: true",
|
||||||
|
" -",
|
||||||
|
" host: 2001:db8::3",
|
||||||
|
" port: 3478",
|
||||||
|
" type: stun",
|
||||||
|
" transport: tcp",
|
||||||
|
" restricted: false",
|
||||||
|
" -",
|
||||||
|
" host: 2001:db8::3",
|
||||||
|
" port: 3478",
|
||||||
|
" type: turn",
|
||||||
|
" transport: tcp",
|
||||||
|
" restricted: true",
|
||||||
|
" -",
|
||||||
" host: server.example.com",
|
" host: server.example.com",
|
||||||
" port: 5349",
|
" port: 5349",
|
||||||
" type: stuns",
|
" type: stuns",
|
||||||
|
@ -599,76 +623,87 @@ parse_listener({_EndPoint, ?STUN_MODULE, #{tls := true}}) ->
|
||||||
?DEBUG("Ignoring TLS-enabled STUN/TURN listener", []),
|
?DEBUG("Ignoring TLS-enabled STUN/TURN listener", []),
|
||||||
[]; % Avoid certificate hostname issues.
|
[]; % Avoid certificate hostname issues.
|
||||||
parse_listener({{Port, _Addr, Transport}, ?STUN_MODULE, Opts}) ->
|
parse_listener({{Port, _Addr, Transport}, ?STUN_MODULE, Opts}) ->
|
||||||
case get_listener_ip(Opts) of
|
case get_listener_ips(Opts) of
|
||||||
{127, _, _, _} = Addr ->
|
{undefined, undefined} ->
|
||||||
?INFO_MSG("Won't auto-announce STUN/TURN service with loopback "
|
?INFO_MSG("Won't auto-announce STUN/TURN service on port ~B (~s) "
|
||||||
"address: ~s:~B (~s), please specify a public "
|
"without public address, please specify 'turn_v4_ip' and "
|
||||||
"'turn_v4_ip'", [misc:ip_to_list(Addr), Port, Transport]),
|
"optionally 'turn_v6_ip'", [Port, Transport]),
|
||||||
[];
|
[];
|
||||||
Addr ->
|
{IPv4Addr, IPv6Addr} ->
|
||||||
Host = maybe_resolve(Addr),
|
lists:flatmap(
|
||||||
StunService = #service{host = Host,
|
fun(undefined) ->
|
||||||
port = Port,
|
[];
|
||||||
transport = Transport,
|
(Addr) ->
|
||||||
restricted = false,
|
StunService = #service{host = Addr,
|
||||||
type = stun},
|
port = Port,
|
||||||
case Opts of
|
transport = Transport,
|
||||||
#{use_turn := true} ->
|
restricted = false,
|
||||||
?INFO_MSG("Going to offer STUN/TURN listener: ~s:~B (~s)",
|
type = stun},
|
||||||
[misc:ip_to_list(Addr), Port, Transport]),
|
case Opts of
|
||||||
[StunService, #service{host = Host,
|
#{use_turn := true} ->
|
||||||
port = Port,
|
?INFO_MSG("Going to offer STUN/TURN service: "
|
||||||
transport = Transport,
|
"~s (~s)",
|
||||||
restricted = is_restricted(Opts),
|
[addr_to_str(Addr, Port), Transport]),
|
||||||
type = turn}];
|
[StunService,
|
||||||
#{use_turn := false} ->
|
#service{host = Addr,
|
||||||
?INFO_MSG("Going to offer STUN listener: ~s:~B (~s)",
|
port = Port,
|
||||||
[misc:ip_to_list(Addr), Port, Transport]),
|
transport = Transport,
|
||||||
[StunService]
|
restricted = is_restricted(Opts),
|
||||||
end
|
type = turn}];
|
||||||
|
#{use_turn := false} ->
|
||||||
|
?INFO_MSG("Going to offer STUN service: "
|
||||||
|
"~s (~s)",
|
||||||
|
[addr_to_str(Addr, Port), Transport]),
|
||||||
|
[StunService]
|
||||||
|
end
|
||||||
|
end, [IPv4Addr, IPv6Addr])
|
||||||
end;
|
end;
|
||||||
parse_listener({_EndPoint, Module, _Opts}) ->
|
parse_listener({_EndPoint, Module, _Opts}) ->
|
||||||
?DEBUG("Ignoring ~s listener", [Module]),
|
?DEBUG("Ignoring ~s listener", [Module]),
|
||||||
[].
|
[].
|
||||||
|
|
||||||
-spec get_listener_ip(map()) -> inet:ip_address().
|
-spec get_listener_ips(map()) -> {inet:ip4_address() | undefined,
|
||||||
get_listener_ip(#{ip := { 0, 0, 0, 0}} = Opts) -> get_turn_v4_ip(Opts);
|
inet:ip6_address() | undefined}.
|
||||||
get_listener_ip(#{ip := {127, _, _, _}} = Opts) -> get_turn_v4_ip(Opts);
|
get_listener_ips(#{ip := {0, 0, 0, 0}} = Opts) ->
|
||||||
get_listener_ip(#{ip := { 10, _, _, _}} = Opts) -> get_turn_v4_ip(Opts);
|
{get_turn_v4_ip(Opts), undefined};
|
||||||
get_listener_ip(#{ip := {172, 16, _, _}} = Opts) -> get_turn_v4_ip(Opts);
|
get_listener_ips(#{ip := {0, 0, 0, 0, 0, 0, 0, 0}} = Opts) ->
|
||||||
get_listener_ip(#{ip := {192, 168, _, _}} = Opts) -> get_turn_v4_ip(Opts);
|
{get_turn_v4_ip(Opts), get_turn_v6_ip(Opts)}; % Assume dual-stack socket.
|
||||||
get_listener_ip(#{ip := IP}) -> IP.
|
get_listener_ips(#{ip := {127, _, _, _}} = Opts) ->
|
||||||
|
{get_turn_v4_ip(Opts), undefined};
|
||||||
|
get_listener_ips(#{ip := {0, 0, 0, 0, 0, 0, 0, 1}} = Opts) ->
|
||||||
|
{undefined, get_turn_v6_ip(Opts)};
|
||||||
|
get_listener_ips(#{ip := {_, _, _, _} = IP}) ->
|
||||||
|
{IP, undefined};
|
||||||
|
get_listener_ips(#{ip := {_, _, _, _, _,_, _, _, _} = IP}) ->
|
||||||
|
{undefined, IP}.
|
||||||
|
|
||||||
-spec get_turn_v4_ip(map()) -> inet:ip_address().
|
-spec get_turn_v4_ip(map()) -> inet:ip4_address() | undefined.
|
||||||
get_turn_v4_ip(#{turn_v4_ip := {_, _, _, _} = TurnIP}) -> TurnIP;
|
get_turn_v4_ip(#{turn_v4_ip := {_, _, _, _} = TurnIP}) ->
|
||||||
get_turn_v4_ip(#{turn_v4_ip := undefined}) -> misc:get_my_ip().
|
TurnIP;
|
||||||
|
get_turn_v4_ip(#{turn_v4_ip := undefined}) ->
|
||||||
-spec is_restricted(map()) -> boolean().
|
case misc:get_my_v4_ip() of
|
||||||
is_restricted(#{auth_type := user}) -> true;
|
{127, _, _, _} ->
|
||||||
is_restricted(#{auth_type := anonymous}) -> false.
|
undefined;
|
||||||
|
IP ->
|
||||||
-spec maybe_resolve(inet:ip_address()) -> binary() | inet:ip_address().
|
IP
|
||||||
maybe_resolve(Addr) ->
|
|
||||||
case lookup(Addr, ptr) of
|
|
||||||
[Name] when is_list(Name) ->
|
|
||||||
case {lookup(Name, a), lookup(Name, aaaa)} of
|
|
||||||
{[Addr], []} ->
|
|
||||||
?DEBUG("Resolved address ~s to hostname ~s",
|
|
||||||
[misc:ip_to_list(Addr), Name]),
|
|
||||||
list_to_binary(Name);
|
|
||||||
{_, _} ->
|
|
||||||
?DEBUG("Won't resolve address ~s to hostname ~s",
|
|
||||||
[misc:ip_to_list(Addr), Name]),
|
|
||||||
Addr
|
|
||||||
end;
|
|
||||||
_ ->
|
|
||||||
?DEBUG("Cannot resolve address: ~s", [misc:ip_to_list(Addr)]),
|
|
||||||
Addr
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec lookup(string() | inet:ip_address(), a | aaaa | ptr) -> [any()].
|
-spec get_turn_v6_ip(map()) -> inet:ip6_address() | undefined.
|
||||||
lookup(Name, Type) ->
|
get_turn_v6_ip(#{turn_v6_ip := {_, _, _, _, _, _, _, _} = TurnIP}) ->
|
||||||
inet_res:lookup(Name, in, Type, [], timer:seconds(3)).
|
TurnIP;
|
||||||
|
get_turn_v6_ip(#{turn_v6_ip := undefined}) ->
|
||||||
|
case misc:get_my_v6_ip() of
|
||||||
|
{0, 0, 0, 0, 0, 0, 0, 1} ->
|
||||||
|
undefined;
|
||||||
|
IP ->
|
||||||
|
IP
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec is_restricted(map()) -> boolean().
|
||||||
|
is_restricted(#{auth_type := user}) ->
|
||||||
|
true;
|
||||||
|
is_restricted(#{auth_type := anonymous}) ->
|
||||||
|
false.
|
||||||
|
|
||||||
-spec call(host_or_hash(), term()) -> term().
|
-spec call(host_or_hash(), term()) -> term().
|
||||||
call(Host, Request) ->
|
call(Host, Request) ->
|
||||||
|
@ -697,3 +732,9 @@ dedup([H | T]) -> [H | [E || E <- dedup(T), E /= H]].
|
||||||
-spec seconds_to_timestamp(non_neg_integer()) -> erlang:timestamp().
|
-spec seconds_to_timestamp(non_neg_integer()) -> erlang:timestamp().
|
||||||
seconds_to_timestamp(Seconds) ->
|
seconds_to_timestamp(Seconds) ->
|
||||||
{Seconds div 1000000, Seconds rem 1000000, 0}.
|
{Seconds div 1000000, Seconds rem 1000000, 0}.
|
||||||
|
|
||||||
|
-spec addr_to_str(inet:ip_address(), 0..65535) -> string().
|
||||||
|
addr_to_str({_, _, _, _, _, _, _, _} = Addr, Port) ->
|
||||||
|
[$[, inet_parse:ntoa(Addr), $], $:, integer_to_list(Port)];
|
||||||
|
addr_to_str({_, _, _, _} = Addr, Port) ->
|
||||||
|
[inet_parse:ntoa(Addr), $:, integer_to_list(Port)].
|
||||||
|
|
Loading…
Reference in New Issue