]> granicus.if.org Git - ejabberd/commitdiff
Backport C2S blacklist support from trunk
authorChristophe Romain <christophe.romain@process-one.net>
Fri, 11 Jul 2008 06:59:45 +0000 (06:59 +0000)
committerChristophe Romain <christophe.romain@process-one.net>
Fri, 11 Jul 2008 06:59:45 +0000 (06:59 +0000)
SVN Revision: 1431

ChangeLog
src/ejabberd_c2s.erl
src/mod_ip_blacklist.erl [new file with mode: 0644]

index f9c68ed70401f03a970b21846c7e8a70961b288a..5ae9516974ef04f225a99d4a684bd63bec84c363 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2008-07-11  Christophe Romain  <christophe.romain@process-one.net>
+
+       * src/ejabberd_c2s.erl: Backport C2S blacklist support from trunk
+       was (EJAB-625).
+       * src/mod_ip_blacklist.erl: Likewise.
+
 2008-07-10  Badlop  <badlop@process-one.net>
 
        * src/configure.ac: Don't check for erlang header file (EJAB-232)
index 3810edf40dcf41aa521cebbd573c9bc33f8980da..2d8e315e16f456cdc241df3b7365441159233005 100644 (file)
@@ -176,26 +176,34 @@ init([{SockMod, Socket}, Opts]) ->
                              (_) -> false
                           end, Opts),
     IP = peerip(SockMod, Socket),
-    Socket1 =
-       if
-           TLSEnabled ->
-               SockMod:starttls(Socket, TLSOpts);
-           true ->
-               Socket
-       end,
-    SocketMonitor = SockMod:monitor(Socket1),
-    {ok, wait_for_stream, #state{socket         = Socket1,
-                                sockmod        = SockMod,
-                                socket_monitor = SocketMonitor,
-                                zlib           = Zlib,
-                                tls            = TLS,
-                                tls_required   = StartTLSRequired,
-                                tls_enabled    = TLSEnabled,
-                                tls_options    = TLSOpts,
-                                streamid       = new_id(),
-                                access         = Access,
-                                shaper         = Shaper,
-                                ip             = IP}, ?C2S_OPEN_TIMEOUT}.
+    %% Check if IP is blacklisted:
+    case is_ip_blacklisted(IP) of
+       true ->
+           ?INFO_MSG("Connection attempt from blacklisted IP: ~s",
+                     [jlib:ip_to_list(IP)]),
+           {stop, normal};
+       false ->
+           Socket1 =
+               if
+                   TLSEnabled ->
+                       SockMod:starttls(Socket, TLSOpts);
+                   true ->
+                       Socket
+               end,
+           SocketMonitor = SockMod:monitor(Socket1),
+           {ok, wait_for_stream, #state{socket         = Socket1,
+                                       sockmod        = SockMod,
+                                       socket_monitor = SocketMonitor,
+                                       zlib           = Zlib,
+                                       tls            = TLS,
+                                       tls_required   = StartTLSRequired,
+                                       tls_enabled    = TLSEnabled,
+                                       tls_options    = TLSOpts,
+                                       streamid       = new_id(),
+                                       access         = Access,
+                                       shaper         = Shaper,
+                                       ip             = IP}, ?C2S_OPEN_TIMEOUT}
+    end.
 
 %% Return list of all available resources of contacts,
 %% in form [{JID, Caps}].
@@ -1955,3 +1963,7 @@ fsm_reply(Reply, session_established, StateData) ->
     {reply, Reply, session_established, StateData, ?C2S_HIBERNATE_TIMEOUT};
 fsm_reply(Reply, StateName, StateData) ->
     {reply, Reply, StateName, StateData, ?C2S_OPEN_TIMEOUT}.
+
+%% Used by c2s blacklist plugins
+is_ip_blacklisted({IP,_Port}) ->
+    ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]).
diff --git a/src/mod_ip_blacklist.erl b/src/mod_ip_blacklist.erl
new file mode 100644 (file)
index 0000000..6a0cc39
--- /dev/null
@@ -0,0 +1,119 @@
+%%%----------------------------------------------------------------------
+%%% File    : mod_ip_blacklist.erl
+%%% Author  : Mickael Remond <mremond@process-one.net>
+%%% Purpose : Download blacklists from ProcessOne
+%%% Created : 5 May 2008 by Mickael Remond <mremond@process-one.net>
+%%% Usage   : Add the following line in modules section of ejabberd.cfg:
+%%%              {mod_ip_blacklist, []}
+%%%
+%%%
+%%% ejabberd, Copyright (C) 2002-2008   Process-one
+%%%
+%%% 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_ip_blacklist).
+-author('mremond@process-one.net').
+
+-behaviour(gen_mod).
+
+%% API:
+-export([start/2,
+         init/1,
+         stop/1]).
+-export([update_bl_c2s/0]).
+%% Hooks:
+-export([is_ip_in_c2s_blacklist/2]).
+
+-include("ejabberd.hrl").
+
+-define(PROCNAME, ?MODULE).
+-define(BLC2S, "http://xaai.process-one.net/bl_c2s.txt").
+-define(UPDATE_INTERVAL, 6). %% in hours
+
+-record(state, {timer}).
+-record(bl_c2s, {ip}).
+
+%% Start once for all vhost
+start(Host, Opts) ->
+    case whereis(?PROCNAME) of
+        undefined ->
+            ?DEBUG("Starting mod_ip_blacklist ~p  ~p~n", [Host, Opts]),
+              register(?PROCNAME,
+                     spawn(?MODULE, init, [#state{}]));
+        _ ->
+            ok
+    end.
+
+%% TODO:
+stop(_Host) ->
+    ok.
+
+init(State)->
+    inets:start(),
+    ets:new(bl_c2s, [named_table, public, {keypos, #bl_c2s.ip}]),
+    update_bl_c2s(),
+    %% Register hooks for blacklist
+    ejabberd_hooks:add(check_bl_c2s, ?MODULE, is_ip_in_c2s_blacklist, 50),
+    %% Set timer: Download the blacklist file every 6 hours
+    timer:apply_interval(timer:hours(?UPDATE_INTERVAL), ?MODULE, update_bl_c2s, []),
+    loop(State).
+
+%% Remove timer when stop is received.
+loop(_State) ->
+    receive
+       stop ->
+           ok
+    end.
+
+%% Download blacklist file from ProcessOne XAAI
+%% and update the table internal table
+%% TODO: Support comment lines starting by %
+update_bl_c2s() ->
+    ?INFO_MSG("Updating C2S Blacklist", []),
+    case http:request(?BLC2S) of
+       {ok, {{_Version, 200, _Reason}, _Headers, Body}} ->
+           IPs = string:tokens(Body,"\n"),
+           ets:delete_all_objects(bl_c2s),
+           lists:foreach(
+             fun(IP) ->
+                     ets:insert(bl_c2s, #bl_c2s{ip=list_to_binary(IP)})
+             end, IPs);
+       {error, Reason} ->
+           ?ERROR_MSG("Cannot download C2S blacklist file. Reason: ~p",
+                      [Reason])
+    end.
+
+%% Hook is run with:
+%% ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]),
+%% Return: false: IP not blacklisted
+%%         true: IP is blacklisted
+%% IPV4 IP tuple:
+is_ip_in_c2s_blacklist(_Val, IP) when is_tuple(IP) ->
+    BinaryIP = list_to_binary(jlib:ip_to_list(IP)),
+    case ets:lookup(bl_c2s, BinaryIP) of
+       [] -> %% Not in blacklist
+           false;
+       [_] -> %% Blacklisted!
+           {stop, true}
+    end;
+is_ip_in_c2s_blacklist(_Val, _IP) ->
+    false.
+
+%% TODO:
+%% - For now, we do not kick user already logged on a given IP after
+%%    we update the blacklist.