Home > Erlang探索 > Erlang集群未公开特性:IP网段限制

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 x@127.0.0.1
Erlang R14B04 (erts-5.8.5)  [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.5  (abort with ^G)
(x@127.0.0.1)1> dbg:tracer().
{ok,<0.39.0>}
(x@127.0.0.1)2> dbg:p(all,c).
{ok,[{matched,'x@127.0.0.1',32}]}
(x@127.0.0.1)3> dbg:tpl(inet_tcp_dist,check_ip, [{'_', [], [{return_trace}]}]).
{ok,[{matched,'x@127.0.0.1',2},{saved,1}]}
(x@127.0.0.1)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 y@127.0.0.1
Erlang R14B04 (erts-5.8.5)  [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.5  (abort with ^G)
(y@127.0.0.1)1> net_adm:ping('x@127.0.0.1').
pong
(y@127.0.0.1)2> 

通过跟踪我们确诊这个功能被打开了,而且在作用。如果没通过IP限制,SASL下会得到如下提示:
** Connection attempt from disallowed IP ~w **。

祝大家玩得开心,集群得安全!

Post Footer automatically generated by wp-posturl plugin for wordpress.