25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-24 17:29:28 +01:00

Merge branch '2.2.x' of gitorious.process-one.net:+ejabberd-developers/ejabberd/maincustomers into 2.2.x

This commit is contained in:
Eric Cestari 2011-02-08 16:39:38 +01:00
commit bde46896d6
9 changed files with 245 additions and 66 deletions

2
README
View File

@ -20,7 +20,7 @@ To compile ejabberd you need:
- GNU Iconv 1.8 or higher, for the IRC Transport
(mod_irc). Optional. Not needed on systems with GNU Libc.
- ImageMagick's Convert program. Optional. For CAPTCHA challenges.
- exmpp 0.9.2 or higher. Optional. For import/export XEP-0227 files.
- exmpp 0.9.6 or higher. Optional. For import/export XEP-0227 files.
1. Compile and install on *nix systems

View File

@ -356,7 +356,7 @@ Don&#X2019;t use R14A or R14B because <A HREF="http://www.erlang.org/cgi-bin/ezm
</LI><LI CLASS="li-itemize">PAM library. Optional. For Pluggable Authentication Modules (PAM). See section <A HREF="#pam">3.1.4</A>.
</LI><LI CLASS="li-itemize">GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not needed on systems with GNU Libc. See section <A HREF="#modirc">3.3.8</A>.
</LI><LI CLASS="li-itemize">ImageMagick&#X2019;s Convert program. Optional. For CAPTCHA challenges. See section <A HREF="#captcha">3.1.8</A>.
</LI><LI CLASS="li-itemize">exmpp 0.9.2 or higher. Optional. For import/export user data with <A HREF="http://xmpp.org/extensions/xep-0227.html">XEP-0227</A> XML files.
</LI><LI CLASS="li-itemize">exmpp 0.9.6 or higher. Optional. For import/export user data with <A HREF="http://xmpp.org/extensions/xep-0227.html">XEP-0227</A> XML files.
</LI></UL><P> <A NAME="download"></A> </P><!--TOC subsection Download Source Code-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc10">2.4.2</A>&#XA0;&#XA0;<A HREF="#download">Download Source Code</A></H3><!--SEC END --><P> <A NAME="download"></A>
</P><P>Released versions of <TT>ejabberd</TT> are available in the ProcessOne <TT>ejabberd</TT> downloads page:
@ -2994,7 +2994,7 @@ The default option value is an empty list: <TT>[]</TT>.
This option sets the minimum informational entropy for passwords. The value <TT>Entropy</TT>
is a number of bits of entropy. The recommended minimum is 32 bits.
The default is 0, i.e. no checks are performed.
</DD><DT CLASS="dt-description"><B><TT>{welcome_message, Message}</TT></B></DT><DD CLASS="dd-description"> Set a welcome message that
</DD><DT CLASS="dt-description"><B><TT>{welcome_message, {Subject, Body}}</TT></B></DT><DD CLASS="dd-description"> Set a welcome message that
is sent to each newly registered account. The first string is the subject, and
the second string is the message body.
In the body you can set a newline with the characters: <CODE>\n</CODE>

View File

@ -80,6 +80,7 @@
\newcommand{\modoffline}{\module{mod\_offline}}
\newcommand{\modofflineodbc}{\module{mod\_offline\_odbc}}
\newcommand{\modping}{\module{mod\_ping}}
\newcommand{\modprescounter}{\module{mod\_pres\_counter}}
\newcommand{\modprivacy}{\module{mod\_privacy}}
\newcommand{\modprivacyodbc}{\module{mod\_privacy\_odbc}}
\newcommand{\modprivate}{\module{mod\_private}}
@ -321,7 +322,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need:
\item PAM library. Optional. For Pluggable Authentication Modules (PAM). See section \ref{pam}.
\item GNU Iconv 1.8 or higher, for the IRC Transport (mod\_irc). Optional. Not needed on systems with GNU Libc. See section \ref{modirc}.
\item ImageMagick's Convert program. Optional. For CAPTCHA challenges. See section \ref{captcha}.
\item exmpp 0.9.2 or higher. Optional. For import/export user data with \xepref{0227} XML files.
\item exmpp 0.9.6 or higher. Optional. For import/export user data with \xepref{0227} XML files.
\end{itemize}
\makesubsection{download}{Download Source Code}
@ -2540,6 +2541,7 @@ The following table lists all modules included in \ejabberd{}.
\hline \ahrefloc{modoffline}{\modoffline{}} & Offline message storage (\xepref{0160}) & \\
\hline \ahrefloc{modoffline}{\modofflineodbc{}} & Offline message storage (\xepref{0160}) & supported DB (*) \\
\hline \ahrefloc{modping}{\modping{}} & XMPP Ping and periodic keepalives (\xepref{0199}) & \\
\hline \ahrefloc{modprescounter}{\modprivacy{}} & Detect presence subscription flood & \\
\hline \ahrefloc{modprivacy}{\modprivacy{}} & Blocking Communication (XMPP IM) & \\
\hline \ahrefloc{modprivacy}{\modprivacyodbc{}} & Blocking Communication (XMPP IM) & supported DB (*) \\
\hline \ahrefloc{modprivate}{\modprivate{}} & Private XML Storage (\xepref{0049}) & \\
@ -3564,6 +3566,39 @@ and if a client does not answer to the ping in less than 32 seconds, its connect
]}.
\end{verbatim}
\makesubsection{modprescounter}{\modprescounter{}}
\ind{modules!\modprescounter{}}
This module detects flood/spam in presence subscription stanza traffic.
If a user sends or receives more of those stanzas in a time interval,
the exceeding stanzas are silently dropped, and warning is logged.
Configuration options:
\begin{description}
\titem{\{count, StanzaNumber\}}\ind{options!count}
The number of subscription presence stanzas
(subscribe, unsubscribe, subscribed, unsubscribed)
allowed for any direction (input or output)
per time interval.
Please note that two users subscribing to each other usually generate
4 stanzas, so the recommended value is 4 or more.
The default value is: 5.
\titem{\{interval, Seconds\}}\ind{options!interval}
The time interval defined in seconds.
The default value is 60.
\end{description}
This example enables the module, and allows up to 5 presence subscription stanzas
to be sent or received by the users in 60 seconds:
\begin{verbatim}
{modules,
[
...
{mod_pres_counter, [{count, 5}, {interval, 60}]},
...
]}.
\end{verbatim}
\makesubsection{modprivacy}{\modprivacy{}}
\ind{modules!\modprivacy{}}\ind{Blocking Communication}\ind{Privacy Rules}\ind{protocols!RFC 3921: XMPP IM}
@ -3808,7 +3843,7 @@ Protect registrations with CAPTCHA (see section \ref{captcha}). The default is \
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.
The default is 0, i.e. no checks are performed.
\titem{\{welcome\_message, Message\}} \ind{options!welcomem}Set a welcome message that
\titem{\{welcome\_message, \{Subject, Body\}\}} \ind{options!welcomem}Set a welcome message that
is sent to each newly registered account. The first string is the subject, and
the second string is the message body.
In the body you can set a newline with the characters: \verb|\n|

View File

@ -511,6 +511,7 @@
%%{mod_muc_log,[]},
{mod_offline, [{access_max_user_messages, max_user_offline_messages}]},
{mod_ping, []},
%%{mod_pres_counter,[{count, 5}, {interval, 60}]},
{mod_privacy, []},
{mod_private, []},
%%{mod_proxy65,[]},
@ -545,9 +546,17 @@
%%
%%{registration_watchers, ["admin1@example.org"]},
%%
%% Only clients in the server machine can register accounts
%%
{ip_access, [{allow, "127.0.0.0/8"},
{deny, "0.0.0.0/0"}]},
%%
%% Local c2s or remote s2s users cannot register accounts
%%
%%{access_from, deny},
{access, register}
]},
%%{mod_register_web, [

View File

@ -2422,7 +2422,7 @@ resend_offline_messages(StateData) ->
Rs when is_list(Rs) ->
lists:foreach(
fun({route,
From, To, {xmlelement, Name, Attrs, Els} = Packet}) ->
From, To, {xmlelement, _Name, _Attrs, _Els} = Packet}) ->
Pass = case privacy_check_packet(StateData, From, To, Packet, in) of
allow ->
true;
@ -2431,11 +2431,11 @@ resend_offline_messages(StateData) ->
end,
if
Pass ->
Attrs2 = jlib:replace_from_to_attrs(
jlib:jid_to_string(From),
jlib:jid_to_string(To),
Attrs),
FixedPacket = {xmlelement, Name, Attrs2, Els},
%% Attrs2 = jlib:replace_from_to_attrs(
%% jlib:jid_to_string(From),
%% jlib:jid_to_string(To),
%% Attrs),
%% FixedPacket = {xmlelement, Name, Attrs2, Els},
%% Use route instead of send_element to go through standard workflow
ejabberd_router:route(From, To, Packet);
%% send_element(StateData, FixedPacket),

View File

@ -54,7 +54,7 @@ init(ProcessName, ExtPrg) ->
register(ProcessName, self()),
process_flag(trap_exit,true),
Port = open_port({spawn, ExtPrg}, [{packet,2}]),
loop(Port, ?INIT_TIMEOUT).
loop(Port, ?INIT_TIMEOUT, ProcessName, ExtPrg).
stop(Host) ->
lists:foreach(
@ -108,23 +108,27 @@ get_instances(Server) ->
_ -> 1
end.
loop(Port, Timeout) ->
loop(Port, Timeout, ProcessName, ExtPrg) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, encode(Msg)}},
port_command(Port, encode(Msg)),
receive
{Port, {data, Data}} ->
?DEBUG("extauth call '~p' received data response:~n~p", [Msg, Data]),
Caller ! {eauth, decode(Data)};
Caller ! {eauth, decode(Data)},
loop(Port, ?CALL_TIMEOUT, ProcessName, ExtPrg);
{Port, Other} ->
?ERROR_MSG("extauth call '~p' received strange response:~n~p", [Msg, Other]),
Caller ! {eauth, false}
Caller ! {eauth, false},
loop(Port, ?CALL_TIMEOUT, ProcessName, ExtPrg)
after
Timeout ->
?ERROR_MSG("extauth call '~p' didn't receive response", [Msg]),
Caller ! {eauth, false}
end,
loop(Port, ?CALL_TIMEOUT);
Caller ! {eauth, false},
unregister(ProcessName),
spawn(?MODULE, init, [ProcessName, ExtPrg]),
exit(port_terminated)
end;
stop ->
Port ! {self(), close},
receive

134
src/mod_pres_counter.erl Normal file
View File

@ -0,0 +1,134 @@
%%%----------------------------------------------------------------------
%%% File : mod_pres_counter.erl
%%% Author : Ahmed Omar
%%% Purpose : Presence subscription flood prevention
%%% Created : 23 Sep 2010 by Ahmed Omar
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
-module(mod_pres_counter).
-behavior(gen_mod).
-export([start/2,
stop/1,
check_packet/6]).
-include("ejabberd.hrl").
-include("jlib.hrl").
-record(pres_counter, {dir, start, count, logged = false}).
start(Host, _Opts) ->
ejabberd_hooks:add(privacy_check_packet, Host,
?MODULE, check_packet, 25),
ok.
stop(Host) ->
ejabberd_hooks:delete(privacy_check_packet, Host,
?MODULE, check_packet, 25),
ok.
check_packet(_, _User, Server,
_PrivacyList,
{From, To, {xmlelement, Name, Attrs, _}},
Dir) ->
case Name of
"presence" ->
IsSubscription =
case xml:get_attr_s("type", Attrs) of
"subscribe" -> true;
"subscribed" -> true;
"unsubscribe" -> true;
"unsubscribed" -> true;
_ -> false
end,
if
IsSubscription ->
JID = case Dir of
in -> To;
out -> From
end,
update(Server, JID, Dir);
true ->
allow
end;
_ ->
allow
end.
update(Server, JID, Dir) ->
%% get options
StormCount = gen_mod:get_module_opt(Server, ?MODULE, count, 5),
TimeInterval = gen_mod:get_module_opt(Server, ?MODULE, interval, 60),
{MegaSecs, Secs, _MicroSecs} = now(),
TimeStamp = MegaSecs * 1000000 + Secs,
case read(Dir) of
undefined ->
write(Dir, #pres_counter{dir = Dir,
start = TimeStamp,
count = 1}),
allow;
#pres_counter{start = TimeStart, count = Count, logged = Logged} = R ->
%% record for this key exists, check if we're
%% within TimeInterval seconds, and whether the StormCount is
%% high enough. or else just increment the count.
if
TimeStamp - TimeStart > TimeInterval ->
write(Dir, R#pres_counter{
start = TimeStamp,
count = 1}),
allow;
(Count =:= StormCount) and Logged ->
{stop, deny};
Count =:= StormCount ->
write(Dir, R#pres_counter{logged = true}),
case Dir of
in ->
?WARNING_MSG(
"User ~s is being flooded, "
"ignoring received presence subscriptions",
[jlib:jid_to_string(JID)]);
out ->
IP = ejabberd_sm:get_user_ip(
JID#jid.luser,
JID#jid.lserver,
JID#jid.lresource),
?WARNING_MSG(
"Flooder detected: ~s, on IP: ~s "
"ignoring sent presence subscriptions~n",
[jlib:jid_to_string(JID),
jlib:ip_to_list(IP)])
end,
{stop, deny};
true ->
write(Dir, R#pres_counter{
start = TimeStamp,
count = Count + 1}),
allow
end
end.
read(K)->
get({pres_counter, K}).
write(K, V)->
put({pres_counter, K}, V).

View File

@ -554,9 +554,12 @@ get_user_list(_, User, Server) ->
end.
%% From is the sender, To is the destination.
%% If Dir = out, User@Server is the sender account (From).
%% If Dir = in, User@Server is the destination account (To).
check_packet(_, User, Server,
#userlist{list = List, needdb = NeedDb},
{From, To, {xmlelement, PName, _, _}},
{From, To, {xmlelement, PName, Attrs, _}},
Dir) ->
case List of
[] ->
@ -565,48 +568,36 @@ check_packet(_, User, Server,
PType = case PName of
"message" -> message;
"iq" -> iq;
"presence" -> presence
"presence" ->
case xml:get_attr_s("type", Attrs) of
%% notification
"" -> presence;
"unavailable" -> presence;
%% subscribe, subscribed, unsubscribe,
%% unsubscribed, error, probe, or other
_ -> other
end
end,
case {PType, Dir} of
{message, in} ->
LJID = jlib:jid_tolower(From),
{Subscription, Groups} =
case NeedDb of
true -> ejabberd_hooks:run_fold(roster_get_jid_info, jlib:nameprep(Server), {none, []}, [User, Server, LJID]);
false -> {[], []}
end,
check_packet_aux(List, message,
LJID, Subscription, Groups);
{iq, in} ->
LJID = jlib:jid_tolower(From),
{Subscription, Groups} =
case NeedDb of
true -> ejabberd_hooks:run_fold(roster_get_jid_info, jlib:nameprep(Server), {none, []}, [User, Server, LJID]);
false -> {[], []}
end,
check_packet_aux(List, iq,
LJID, Subscription, Groups);
{presence, in} ->
LJID = jlib:jid_tolower(From),
{Subscription, Groups} =
case NeedDb of
true -> ejabberd_hooks:run_fold(roster_get_jid_info, jlib:nameprep(Server), {none, []}, [User, Server, LJID]);
false -> {[], []}
end,
check_packet_aux(List, presence_in,
LJID, Subscription, Groups);
{presence, out} ->
LJID = jlib:jid_tolower(To),
{Subscription, Groups} =
case NeedDb of
true -> ejabberd_hooks:run_fold(roster_get_jid_info, jlib:nameprep(Server), {none, []}, [User, Server, LJID]);
false -> {[], []}
end,
check_packet_aux(List, presence_out,
LJID, Subscription, Groups);
_ ->
allow
end
PType2 = case {PType, Dir} of
{message, in} -> message;
{iq, in} -> iq;
{presence, in} -> presence_in;
{presence, out} -> presence_out;
{_, _} -> other
end,
LJID = case Dir of
in -> jlib:jid_tolower(From);
out -> jlib:jid_tolower(To)
end,
{Subscription, Groups} =
case NeedDb of
true -> ejabberd_hooks:run_fold(roster_get_jid_info,
jlib:nameprep(Server),
{none, []},
[User, Server, LJID]);
false -> {[], []}
end,
check_packet_aux(List, PType2, LJID, Subscription, Groups)
end.
check_packet_aux([], _PType, _JID, _Subscription, _Groups) ->
@ -646,7 +637,9 @@ is_ptype_match(Item, PType) ->
presence_in ->
Item#listitem.match_presence_in;
presence_out ->
Item#listitem.match_presence_out
Item#listitem.match_presence_out;
other ->
false
end
end.

View File

@ -1271,10 +1271,14 @@ check_default_xmlns(El) ->
%% Print a warning in log file if this is not the case.
check_bind_module(XmppDomain) ->
case gen_mod:is_loaded(XmppDomain, mod_http_bind) of
true -> true;
false -> ?ERROR_MSG("You are trying to use BOSH (HTTP Bind), but the module mod_http_bind is not started.~n"
"Check your 'modules' section in your ejabberd configuration file.",[]),
false
true -> ok;
false -> ?ERROR_MSG("You are trying to use BOSH (HTTP Bind) in host ~p,"
" but the module mod_http_bind is not started in"
" that host. Configure your BOSH client to connect"
" to the correct host, or add your desired host to"
" the configuration, or check your 'modules'"
" section in your ejabberd configuration file.",
[XmppDomain])
end.
make_sid() ->