New ip_access option restricts which IPs can register (thanks to Alexey Shchepin)(EJAB-915)

This commit is contained in:
Badlop 2010-11-05 19:00:16 +01:00
parent b9c6f6e627
commit 4a1d8c2cd2
3 changed files with 116 additions and 6 deletions

View File

@ -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}

View File

@ -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, [

View File

@ -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.