1. 程式人生 > >Erlang叢集未公開特性:IP網段限制

Erlang叢集未公開特性:IP網段限制

Erlang叢集二個節點之間的通訊是通過一個tcp長連線進行的,而且是全聯通的,一旦cookie論證通過了,任何一個節點就獲得全叢集的訪問權,可以參考Erlang分佈的核心技術淺析

。erlang的這個授權模式特定搞的這麼簡單,但是在實際使用中還是有安全性的問題。我們退而求其次,來個IP網段限制,這個功能Erlang是有的只是沒有文件化。 我們來看下程式碼:
inet_tcp_dist.erl:L157

do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
    receive
        {AcceptPid, controller} ->
            Timer = dist_util:start_timer(SetupTime),
            case check_ip(Socket) of
                true ->
                   ...
                   dist_util:handshake_other_started(HSData);
                {false,IP} ->
                    error_msg("** Connection attempt from "
                              "disallowed IP ~w ** ~n", [IP]),
                    ?shutdown(no_node)
            end
    end.
 
 
%% ------------------------------------------------------------                                                            
check_ip(Socket) ->
    case application:get_env(check_ip) of
        {ok, true} ->
            case get_ifs(Socket) of
                {ok, IFs, IP} ->
                    check_ip(IFs, IP);
                _ ->
                    ?shutdown(no_node)
            end;
        _ ->
            true
    end.
 
get_ifs(Socket) ->
    case inet:peername(Socket) of
        {ok, {IP, _}} ->
            case inet:getif(Socket) of
                {ok, IFs} -> {ok, IFs, IP};
                Error     -> Error
            end;
        Error ->
            Error
    end.
check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) ->
    case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of
        {M, M} -> true;
        _      -> check_ip(IFs, PeerIP)
    end;
check_ip([], PeerIP) ->
    {false, PeerIP}.
 
mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
    {M1 band IP1,
     M2 band IP2,
     M3 band IP3,
     M4 band IP4}.
這個功能可以用-kernel check_ip true開啟。 接著我們來實驗下,在其中一個終端開:
$ erl -kernel check_ip true -name [email protected]
Erlang R14B04 (erts-5.8.5) 1 [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
 
Eshell V5.8.5  (abort with ^G)
([email protected])1> dbg:tracer().
{ok,<0.39.0>}
([email protected]
)2> dbg:p(all,c). {ok,[{matched,'[email protected]',32}]} ([email protected])3> dbg:tpl(inet_tcp_dist,check_ip, [{'_', [], [{return_trace}]}]). {ok,[{matched,'[email protected]',2},{saved,1}]} ([email protected])4> dbg:tpl(inet_tcp_dist,check_ip, [{'_', [], [{return_trace}]}])(<0.44.0>) call inet_tcp_dist:check_ip(#Port<0.623>) (<0.44.0>) call inet_tcp_dist:check_ip([{{172,16,64,1},{172,16,64,255},{255,255,255,0}}, {{172,16,213,1},{172,16,213,255},{255,255,255,0}}, {{192,168,1,3},{192,168,1,255},{255,255,255,0}}, {{127,0,0,1},undefined,{255,0,0,0}}],{127,0,0,1}) (<0.44.0>) call inet_tcp_dist:check_ip([{{172,16,213,1},{172,16,213,255},{255,255,255,0}}, {{192,168,1,3},{192,168,1,255},{255,255,255,0}}, {{127,0,0,1},undefined,{255,0,0,0}}],{127,0,0,1}) (<0.44.0>) call inet_tcp_dist:check_ip([{{192,168,1,3},{192,168,1,255},{255,255,255,0}}, {{127,0,0,1},undefined,{255,0,0,0}}],{127,0,0,1}) (<0.44.0>) call inet_tcp_dist:check_ip([{{127,0,0,1},undefined,{255,0,0,0}}],{127,0,0,1}) (<0.44.0>) returned from inet_tcp_dist:check_ip/2 -> true (<0.44.0>) returned from inet_tcp_dist:check_ip/2 -> true (<0.44.0>) returned from inet_tcp_dist:check_ip/2 -> true (<0.44.0>) returned from inet_tcp_dist:check_ip/2 -> true (<0.44.0>) returned from inet_tcp_dist:check_ip/1 -> true
在另外一個終端開:
$ erl -name [email protected]
Erlang R14B04 (erts-5.8.5) 1 [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
 
Eshell V5.8.5  (abort with ^G)
([email protected])1> net_adm:ping('[email protected]').
pong
([email protected])2>
通過跟蹤我們確診這個功能被打開了,而且在作用。如果沒通過IP限制,SASL下會得到如下提示: ** Connection attempt from disallowed IP ~w **。 祝大家玩得開心,叢集得安全!