New ip_access option restricts which IPs can register (thanks to Alexey Shchepin)(EJAB-915)
This commit is contained in:
parent
b9c6f6e627
commit
4a1d8c2cd2
|
@ -3796,6 +3796,12 @@ Options:
|
|||
from s2s leads to uncontrolled massive accounts creation by rogue users.
|
||||
\titem{\{captcha\_protected, false|true\}} \ind{options!captcha\_protected}
|
||||
Protect registrations with CAPTCHA (see section \ref{captcha}). The default is \term{false}.
|
||||
\titem{\{ip\_access, [ \{allow|deny, IPaddress\}, ...]\}} \ind{options!ip\_access}
|
||||
Define rules to allow or deny account registration depending
|
||||
in the IP address of the XMPP client.
|
||||
If there is no matching IP mask, the default rule is ``allow''.
|
||||
IPv6 addresses are supported, but not tested.
|
||||
The default option value is an empty list: \term{[]}.
|
||||
\titem{\{password\_strength, Entropy\}} \ind{options!password\_strength}
|
||||
This option sets the minimum informational entropy for passwords. The value \term{Entropy}
|
||||
is a number of bits of entropy. The recommended minimum is 32 bits.
|
||||
|
@ -3823,7 +3829,8 @@ Default value: 600 seconds.
|
|||
|
||||
Examples:
|
||||
\begin{itemize}
|
||||
\item Next example prohibits the registration of too short account names:
|
||||
\item Next example prohibits the registration of too short account names,
|
||||
and allows to create accounts only to clients of the local network:
|
||||
\begin{verbatim}
|
||||
{acl, shortname, {user_glob, "?"}}.
|
||||
{acl, shortname, {user_glob, "??"}}.
|
||||
|
@ -3836,7 +3843,10 @@ Examples:
|
|||
{modules,
|
||||
[
|
||||
...
|
||||
{mod_register, [{access, register}]},
|
||||
{mod_register, [{access, register},
|
||||
{ip_access, [{allow, "127.0.0.0/8"},
|
||||
{deny, "0.0.0.0/0"}]}
|
||||
]},
|
||||
...
|
||||
]}.
|
||||
\end{verbatim}
|
||||
|
|
|
@ -569,6 +569,9 @@
|
|||
%%
|
||||
%%{registration_watchers, ["admin1@example.org"]},
|
||||
|
||||
{ip_access, [{allow, "127.0.0.0/8"},
|
||||
{deny, "0.0.0.0/0"}]},
|
||||
|
||||
{access, register}
|
||||
]},
|
||||
%%{mod_register_web, [
|
||||
|
|
|
@ -324,17 +324,22 @@ try_register_strong(User, Server, Password, Source, _Lang, JID) ->
|
|||
end
|
||||
end.
|
||||
|
||||
try_register(User, Server, Password, Source, Lang) ->
|
||||
try_register(User, Server, Password, SourceRaw, Lang) ->
|
||||
case exmpp_stringprep:is_node(User) of
|
||||
false ->
|
||||
{error, 'bad-request'};
|
||||
_ ->
|
||||
JID = exmpp_jid:make(User, Server),
|
||||
Access = gen_mod:get_module_opt(Server, ?MODULE, access, all),
|
||||
case acl:match_rule(Server, Access, JID) of
|
||||
deny ->
|
||||
IPAccess = get_ip_access(Server),
|
||||
case {acl:match_rule(Server, Access, JID),
|
||||
check_ip_access(SourceRaw, IPAccess)} of
|
||||
{deny, _} ->
|
||||
{error, 'forbidden'};
|
||||
allow ->
|
||||
{_, deny} ->
|
||||
{error, 'forbidden'};
|
||||
{allow, allow} ->
|
||||
Source = may_remove_resource(SourceRaw),
|
||||
case check_timeout(Source) of
|
||||
true ->
|
||||
case is_strong_password(Server, Password) of
|
||||
|
@ -532,3 +537,95 @@ is_strong_password(Server, Password) ->
|
|||
[Wrong]),
|
||||
true
|
||||
end.
|
||||
|
||||
%%%
|
||||
%%% ip_access management
|
||||
%%%
|
||||
|
||||
may_remove_resource({U, S, _} = From) ->
|
||||
{U, S, ""};
|
||||
may_remove_resource(From) ->
|
||||
From.
|
||||
|
||||
get_ip_access(Host) ->
|
||||
IPAccess = gen_mod:get_module_opt(Host, ?MODULE, ip_access, []),
|
||||
lists:flatmap(
|
||||
fun({Access, S}) ->
|
||||
case parse_ip_netmask(S) of
|
||||
{ok, IP, Mask} ->
|
||||
[{Access, IP, Mask}];
|
||||
error ->
|
||||
?ERROR_MSG("mod_register: invalid "
|
||||
"network specification: ~p",
|
||||
[S]),
|
||||
[]
|
||||
end
|
||||
end, IPAccess).
|
||||
|
||||
parse_ip_netmask(S) ->
|
||||
case string:tokens(S, "/") of
|
||||
[IPStr] ->
|
||||
case inet_parse:address(IPStr) of
|
||||
{ok, {_, _, _, _} = IP} ->
|
||||
{ok, IP, 32};
|
||||
{ok, {_, _, _, _, _, _, _, _} = IP} ->
|
||||
{ok, IP, 128};
|
||||
_ ->
|
||||
error
|
||||
end;
|
||||
[IPStr, MaskStr] ->
|
||||
case catch list_to_integer(MaskStr) of
|
||||
Mask when is_integer(Mask),
|
||||
Mask >= 0 ->
|
||||
case inet_parse:address(IPStr) of
|
||||
{ok, {_, _, _, _} = IP} when Mask =< 32 ->
|
||||
{ok, IP, Mask};
|
||||
{ok, {_, _, _, _, _, _, _, _} = IP} when Mask =< 128 ->
|
||||
{ok, IP, Mask};
|
||||
_ ->
|
||||
error
|
||||
end;
|
||||
_ ->
|
||||
error
|
||||
end;
|
||||
_ ->
|
||||
error
|
||||
end.
|
||||
|
||||
check_ip_access(_Source, []) ->
|
||||
allow;
|
||||
check_ip_access({User, Server, Resource}, IPAccess) ->
|
||||
case ejabberd_sm:get_user_ip(User, Server, Resource) of
|
||||
{IPAddress, _PortNumber} -> check_ip_access(IPAddress, IPAccess);
|
||||
_ -> true
|
||||
end;
|
||||
check_ip_access({_, _, _, _} = IP,
|
||||
[{Access, {_, _, _, _} = Net, Mask} | IPAccess]) ->
|
||||
IPInt = ip_to_integer(IP),
|
||||
NetInt = ip_to_integer(Net),
|
||||
M = bnot ((1 bsl (32 - Mask)) - 1),
|
||||
if
|
||||
IPInt band M =:= NetInt band M ->
|
||||
Access;
|
||||
true ->
|
||||
check_ip_access(IP, IPAccess)
|
||||
end;
|
||||
check_ip_access({_, _, _, _, _, _, _, _} = IP,
|
||||
[{Access, {_, _, _, _, _, _, _, _} = Net, Mask} | IPAccess]) ->
|
||||
IPInt = ip_to_integer(IP),
|
||||
NetInt = ip_to_integer(Net),
|
||||
M = bnot ((1 bsl (128 - Mask)) - 1),
|
||||
if
|
||||
IPInt band M =:= NetInt band M ->
|
||||
Access;
|
||||
true ->
|
||||
check_ip_access(IP, IPAccess)
|
||||
end;
|
||||
check_ip_access(IP, [_ | IPAccess]) ->
|
||||
check_ip_access(IP, IPAccess).
|
||||
|
||||
ip_to_integer({IP1, IP2, IP3, IP4}) ->
|
||||
(((((IP1 bsl 8) bor IP2) bsl 8) bor IP3) bsl 8) bor IP4;
|
||||
ip_to_integer({IP1, IP2, IP3, IP4, IP5, IP6, IP7, IP8}) ->
|
||||
(((((((((((((IP1 bsl 16) bor IP2) bsl 16) bor IP3) bsl 16) bor IP4)
|
||||
bsl 16) bor IP5) bsl 16) bor IP6) bsl 16) bor IP7) bsl 16) bor IP8.
|
||||
|
|
Loading…
Reference in New Issue