mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
New ip_access option restricts which IPs can register (thanks to Alexey Shchepin)(EJAB-915)
This commit is contained in:
parent
6f3713a67d
commit
7f3a5066c6
@ -3779,6 +3779,12 @@ change it by defining access rule in this option. Use with care: allowing regist
|
||||
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.
|
||||
@ -3806,7 +3812,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, "??"}}.
|
||||
@ -3819,7 +3826,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}
|
||||
|
@ -545,6 +545,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, [
|
||||
|
@ -88,7 +88,7 @@ unauthenticated_iq_register(Acc, _Server, _IQ, _IP) ->
|
||||
Acc.
|
||||
|
||||
process_iq(From, To, IQ) ->
|
||||
process_iq(From, To, IQ, jlib:jid_tolower(jlib:jid_remove_resource(From))).
|
||||
process_iq(From, To, IQ, jlib:jid_tolower(From)).
|
||||
|
||||
process_iq(From, To,
|
||||
#iq{type = Type, lang = Lang, sub_el = SubEl, id = ID} = IQ,
|
||||
@ -311,17 +311,22 @@ try_set_password(User, Server, Password, IQ, SubEl, Lang) ->
|
||||
sub_el = [SubEl, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)]}
|
||||
end.
|
||||
|
||||
try_register(User, Server, Password, Source, Lang) ->
|
||||
try_register(User, Server, Password, SourceRaw, Lang) ->
|
||||
case jlib:is_nodename(User) of
|
||||
false ->
|
||||
{error, ?ERR_BAD_REQUEST};
|
||||
_ ->
|
||||
JID = jlib:make_jid(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, ?ERR_FORBIDDEN};
|
||||
allow ->
|
||||
{_, deny} ->
|
||||
{error, ?ERR_FORBIDDEN};
|
||||
{allow, allow} ->
|
||||
Source = may_remove_resource(SourceRaw),
|
||||
case check_timeout(Source) of
|
||||
true ->
|
||||
case is_strong_password(Server, Password) of
|
||||
@ -536,3 +541,95 @@ is_strong_password(Server, Password) ->
|
||||
[Wrong]),
|
||||
true
|
||||
end.
|
||||
|
||||
%%%
|
||||
%%% ip_access management
|
||||
%%%
|
||||
|
||||
may_remove_resource({_, _, _} = From) ->
|
||||
jlib:jid_remove_resource(From);
|
||||
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
Block a user