aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/ssl/inet_proxy_dist.erl228
-rw-r--r--lib/ssl/proxy_server.erl218
-rw-r--r--lib/ssl/src/inet_ssl_dist.erl9
3 files changed, 449 insertions, 6 deletions
diff --git a/lib/ssl/inet_proxy_dist.erl b/lib/ssl/inet_proxy_dist.erl
new file mode 100644
index 0000000000..6308deabe6
--- /dev/null
+++ b/lib/ssl/inet_proxy_dist.erl
@@ -0,0 +1,228 @@
+%%%-------------------------------------------------------------------
+%%% @author Dan Gudmundsson <[email protected]>
+%%% @copyright (C) 2010, Dan Gudmundsson
+%%% @doc
+%%%
+%%% @end
+%%% Created : 22 Jun 2010 by Dan Gudmundsson <[email protected]>
+%%%-------------------------------------------------------------------
+-module(inet_proxy_dist).
+
+-export([childspecs/0, listen/1, accept/1, accept_connection/5,
+ setup/5, close/1, select/1, is_node_name/1, tick/1]).
+
+-include_lib("kernel/src/net_address.hrl").
+-include_lib("kernel/src/dist.hrl").
+-include_lib("kernel/src/dist_util.hrl").
+
+-import(error_logger,[error_msg/2]).
+
+childspecs() ->
+ io:format("childspecs called~n",[]),
+ {ok, [{proxy_server,{proxy_server, start_link, []},
+ permanent, 2000, worker, [proxy_server]}]}.
+
+select(Node) ->
+ io:format("Select called~n",[]),
+ inet_ssl_dist:select(Node).
+
+is_node_name(Name) ->
+ io:format("is_node_name~n",[]),
+ inet_ssl_dist:is_node_name(Name).
+
+listen(Name) ->
+ io:format("listen called~n",[]),
+ gen_server:call(proxy_server, {listen, Name}, infinity).
+
+accept(Listen) ->
+ io:format("accept called~n",[]),
+ gen_server:call(proxy_server, {accept, Listen}, infinity).
+
+accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
+ io:format("accept_connection called ~n",[]),
+ Kernel = self(),
+ spawn_link(fun() -> do_accept(Kernel, AcceptPid, Socket,
+ MyNode, Allowed, SetupTime) end).
+
+setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
+ io:format("setup called~n",[]),
+ Kernel = self(),
+ spawn(fun() -> do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end).
+
+do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
+ [Name, Address] = splitnode(Node, LongOrShortNames),
+ case inet:getaddr(Address, inet) of
+ {ok, Ip} ->
+ Timer = dist_util:start_timer(SetupTime),
+ case erl_epmd:port_please(Name, Ip) of
+ {port, TcpPort, Version} ->
+ ?trace("port_please(~p) -> version ~p~n",
+ [Node,Version]),
+ dist_util:reset_timer(Timer),
+ case gen_server:call(proxy_server, {connect, Ip, TcpPort}, infinity) of
+ {ok, Socket} ->
+ HSData = #hs_data{
+ kernel_pid = Kernel,
+ other_node = Node,
+ this_node = MyNode,
+ socket = Socket,
+ timer = Timer,
+ this_flags = 0,
+ other_version = Version,
+ f_send = fun(S,D) ->
+ io:format("Kernel call send~n",[]),
+ gen_tcp:send(S,D)
+ end,
+ f_recv = fun(S,N,T) ->
+ io:format("Kernel call receive~n",[]),
+ gen_tcp:recv(S,N,T)
+ end,
+ f_setopts_pre_nodeup =
+ fun(S) ->
+ io:format("Kernel pre nodeup~n",[]),
+ inet:setopts(S, [{active, false}, {packet, 4}])
+ end,
+ f_setopts_post_nodeup =
+ fun(S) ->
+ io:format("Kernel post nodeup~n",[]),
+ inet:setopts(S, [{deliver, port},{active, true}])
+ end,
+ f_getll = fun(S) -> inet:getll(S) end,
+ f_address =
+ fun(_,_) ->
+ #net_address{address = {Ip,TcpPort},
+ host = Address,
+ protocol = proxy,
+ family = inet}
+ end,
+ mf_tick = fun(S) -> gen_tcp:send(S, <<>>) end,
+ mf_getstat = fun(S) ->
+ {ok, Stats} = inet:getstat(S, [recv_cnt, send_cnt, send_pend]),
+ R = proplists:get_value(recv_cnt, Stats, 0),
+ W = proplists:get_value(send_cnt, Stats, 0),
+ P = proplists:get_value(send_pend, Stats, 0),
+ {ok, R,W,P}
+ end,
+ request_type = Type
+ },
+ dist_util:handshake_we_started(HSData);
+ _ ->
+ %% Other Node may have closed since
+ %% port_please !
+ ?trace("other node (~p) "
+ "closed since port_please.~n",
+ [Node]),
+ ?shutdown(Node)
+ end;
+ _ ->
+ ?trace("port_please (~p) "
+ "failed.~n", [Node]),
+ ?shutdown(Node)
+ end;
+ _Other ->
+ ?trace("inet_getaddr(~p) "
+ "failed (~p).~n", [Node,Other]),
+ ?shutdown(Node)
+ end.
+
+close(Socket) ->
+ io:format("close called~n",[]),
+ gen_tcp:close(Socket),
+ ok.
+
+do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
+ process_flag(priority, max),
+ io:format("~p: in do_accept~n", [self()]),
+ receive
+ {AcceptPid, controller} ->
+ io:format("~p: do_accept controller~n", [self()]),
+ Timer = dist_util:start_timer(SetupTime),
+ case check_ip(Socket) of
+ true ->
+ HSData = #hs_data{
+ kernel_pid = Kernel,
+ this_node = MyNode,
+ socket = Socket,
+ timer = Timer,
+ this_flags = 0,
+ allowed = Allowed,
+ f_send = fun(S,D) ->
+ io:format("Kernel call send~n",[]),
+ gen_tcp:send(S,D) end,
+ f_recv = fun(S,N,T) ->
+ io:format("Kernel call receive~n",[]),
+ gen_tcp:recv(S,N,T) end,
+ f_setopts_pre_nodeup =
+ fun(S) ->
+ io:format("Kernel pre nodeup~n",[]),
+ inet:setopts(S, [{active, false}, {packet, 4}])
+ end,
+ f_setopts_post_nodeup =
+ fun(S) ->
+ io:format("Kernel post nodeup~n",[]),
+ inet:setopts(S, [{deliver, port},{active, true}])
+ end,
+ f_getll = fun(S) -> inet:getll(S) end,
+ f_address = fun get_remote_id/2,
+ mf_tick = fun(S) -> gen_tcp:send(S, <<>>) end,
+ mf_getstat = fun(S) ->
+ {ok, Stats} = inet:getstat(S, [recv_cnt, send_cnt, send_pend]),
+ R = proplists:get_value(recv_cnt, Stats, 0),
+ W = proplists:get_value(send_cnt, Stats, 0),
+ P = proplists:get_value(send_pend, Stats, 0),
+ {ok, R,W,P}
+ end
+ },
+ dist_util:handshake_other_started(HSData);
+ {false,IP} ->
+ error_logger:error_msg("** Connection attempt from "
+ "disallowed IP ~w ** ~n", [IP]),
+ ?shutdown(no_node)
+ end
+ end.
+
+get_remote_id(Socket, Node) ->
+ gen_server:call(proxy_server, {get_remote_id, {Socket,Node}}, infinity).
+
+tick(Socket) ->
+ gen_tcp:send(Socket, <<>>).
+
+check_ip(_) ->
+ true.
+
+
+%% If Node is illegal terminate the connection setup!!
+splitnode(Node, LongOrShortNames) ->
+ case split_node(atom_to_list(Node), $@, []) of
+ [Name|Tail] when Tail =/= [] ->
+ Host = lists:append(Tail),
+ case split_node(Host, $., []) of
+ [_] when LongOrShortNames == longnames ->
+ error_msg("** System running to use "
+ "fully qualified "
+ "hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown(Node);
+ [_, _ | _] when LongOrShortNames == shortnames ->
+ error_msg("** System NOT running to use fully qualified "
+ "hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown(Node);
+ _ ->
+ [Name, Host]
+ end;
+ [_] ->
+ error_msg("** Nodename ~p illegal, no '@' character **~n",
+ [Node]),
+ ?shutdown(Node);
+ _ ->
+ error_msg("** Nodename ~p illegal **~n", [Node]),
+ ?shutdown(Node)
+ end.
+
+split_node([Chr|T], Chr, Ack) -> [lists:reverse(Ack)|split_node(T, Chr, [])];
+split_node([H|T], Chr, Ack) -> split_node(T, Chr, [H|Ack]);
+split_node([], _, Ack) -> [lists:reverse(Ack)].
+
diff --git a/lib/ssl/proxy_server.erl b/lib/ssl/proxy_server.erl
new file mode 100644
index 0000000000..9b0d1f2400
--- /dev/null
+++ b/lib/ssl/proxy_server.erl
@@ -0,0 +1,218 @@
+%%%-------------------------------------------------------------------
+%%% @author Dan Gudmundsson <[email protected]>
+%%% @copyright (C) 2010, Dan Gudmundsson
+%%% @doc start server with -proto_dist inet_proxy and net_kernel:start([s@faenor, shortnames]).
+%%%
+%%% @end
+%%% Created : 22 Jun 2010 by Dan Gudmundsson <[email protected]>
+%%%-------------------------------------------------------------------
+-module(proxy_server).
+
+-export([init/1, start_link/0, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-include_lib("kernel/src/net_address.hrl").
+-include_lib("kernel/src/dist.hrl").
+-include_lib("kernel/src/dist_util.hrl").
+
+-record(state,
+ {listen,
+ accept_loop
+ }).
+
+start_link() ->
+ gen_server:start_link({local, proxy_server}, proxy_server, [], []).
+
+init([]) ->
+ io:format("~p: init~n",[self()]),
+ process_flag(priority, max),
+ {ok, #state{}}.
+
+handle_call(What = {listen, Name}, _From, State) ->
+ io:format("~p: call listen ~p~n",[self(), What]),
+ case gen_tcp:listen(0, [{active, false}, {packet,2}]) of
+ {ok, Socket} ->
+ {ok, World} = gen_tcp:listen(0, [{active, false}, binary, {packet,2}]),
+ TcpAddress = get_tcp_address(Socket),
+ WorldTcpAddress = get_tcp_address(World),
+ {_,Port} = WorldTcpAddress#net_address.address,
+ {ok, Creation} = erl_epmd:register_node(Name, Port),
+ {reply, {ok, {Socket, TcpAddress, Creation}},
+ State#state{listen={Socket, World}}};
+ Error ->
+ {reply, Error, State}
+ end;
+
+handle_call(What = {accept, Listen}, {From, _}, State = #state{listen={_, World}}) ->
+ io:format("~p: call accept ~p~n",[self(), What]),
+ Self = self(),
+ ErtsPid = spawn_link(fun() -> accept_loop(Self, erts, Listen, From) end),
+ WorldPid = spawn_link(fun() -> accept_loop(Self, world, World, Listen) end),
+ {reply, ErtsPid, State#state{accept_loop={ErtsPid, WorldPid}}};
+
+handle_call({connect, Ip, Port}, {From, _}, State) ->
+ Me = self(),
+ Pid = spawn_link(fun() -> setup_proxy(Ip, Port, Me) end),
+ receive
+ {Pid, go_ahead, LPort} ->
+ Res = {ok, Socket} = try_connect(LPort),
+ ok = gen_tcp:controlling_process(Socket, From),
+ {reply, Res, State};
+ {Pid, Error} ->
+ {reply, Error, State}
+ end;
+
+handle_call({get_remote_id, {Socket,_Node}}, _From, State) ->
+ Address = get_tcp_address(Socket),
+ io:format("~p: get_remote_id ~p~n",[self(), Address]),
+ {reply, Address, State};
+
+handle_call(What, _From, State) ->
+ io:format("~p: call ~p~n",[self(), What]),
+ {reply, ok, State}.
+
+handle_cast(What, State) ->
+ io:format("~p: cast ~p~n",[self(), What]),
+ {noreply, State}.
+
+handle_info(What, State) ->
+ io:format("~p: info ~p~n",[self(), What]),
+ {noreply, State}.
+
+terminate(_Reason, _St) ->
+ ok.
+
+code_change(_OldVsn, St, _Extra) ->
+ {ok, St}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+get_tcp_address(Socket) ->
+ {ok, Address} = inet:sockname(Socket),
+ {ok, Host} = inet:gethostname(),
+ #net_address{
+ address = Address,
+ host = Host,
+ protocol = proxy,
+ family = inet
+ }.
+
+accept_loop(Proxy, Type, Listen, Extra) ->
+ process_flag(priority, max),
+ case gen_tcp:accept(Listen) of
+ {ok, Socket} ->
+ case Type of
+ erts ->
+ io:format("~p: erts accept~n",[self()]),
+ Extra ! {accept,self(),Socket,inet,proxy},
+ receive
+ {_Kernel, controller, Pid} ->
+ ok = gen_tcp:controlling_process(Socket, Pid),
+ Pid ! {self(), controller};
+ {_Kernel, unsupported_protocol} ->
+ exit(unsupported_protocol)
+ end;
+ _ ->
+ io:format("~p: world accept~n",[self()]),
+ PairHandler = spawn(fun() -> setup_connection(Socket, Extra) end),
+ ok = gen_tcp:controlling_process(Socket, PairHandler)
+ end,
+ accept_loop(Proxy, Type, Listen, Extra);
+ Error ->
+ exit(Error)
+ end.
+
+
+try_connect(Port) ->
+ case gen_tcp:connect({127,0,0,1}, Port, [{active, false}, {packet,2}]) of
+ R = {ok, _S} ->
+ R;
+ {error, _R} ->
+ io:format("Failed ~p~n",[_R]),
+ try_connect(Port)
+ end.
+
+setup_proxy(Ip, Port, Parent) ->
+ case gen_tcp:connect(Ip, Port, [{active, true}, binary, {packet,2}]) of
+ {ok, World} ->
+ {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, binary, {packet,2}]),
+ #net_address{address={_,LPort}} = get_tcp_address(ErtsL),
+ Parent ! {self(), go_ahead, LPort},
+ case gen_tcp:accept(ErtsL) of
+ {ok, Erts} ->
+ %% gen_tcp:close(ErtsL),
+ io:format("World ~p Erts ~p~n",[World, Erts]),
+ loop_conn_setup(World, Erts);
+ Err ->
+ Parent ! {self(), Err}
+ end;
+ Err ->
+ Parent ! {self(), Err}
+ end.
+
+setup_connection(World, ErtsListen) ->
+ io:format("Setup connection ~n",[]),
+ TcpAddress = get_tcp_address(ErtsListen),
+ {_Addr,Port} = TcpAddress#net_address.address,
+ {ok, Erts} = gen_tcp:connect({127,0,0,1}, Port, [{active, true}, binary, {packet,2}]),
+ inet:setopts(World, [{active,true}, {packet, 2}]),
+ io:format("~p ~n",[?LINE]),
+ loop_conn_setup(World, Erts).
+
+loop_conn_setup(World, Erts) ->
+ receive
+ {tcp, World, Data = <<a, _/binary>>} ->
+ gen_tcp:send(Erts, Data),
+ io:format("Handshake finished World -> Erts ~p ~c~n",[size(Data), a]),
+ inet:setopts(World, [{packet, 4}]),
+ inet:setopts(Erts, [{packet, 4}]),
+ loop_conn(World, Erts);
+ {tcp, Erts, Data = <<a, _/binary>>} ->
+ gen_tcp:send(World, Data),
+ io:format("Handshake finished Erts -> World ~p ~c~n",[size(Data), a]),
+ inet:setopts(World, [{packet, 4}]),
+ inet:setopts(Erts, [{packet, 4}]),
+ loop_conn(World, Erts);
+
+ {tcp, World, Data = <<H, _/binary>>} ->
+ gen_tcp:send(Erts, Data),
+ io:format("Handshake World -> Erts ~p ~c~n",[size(Data), H]),
+ loop_conn_setup(World, Erts);
+ {tcp, Erts, Data = <<H, _/binary>>} ->
+ gen_tcp:send(World, Data),
+ io:format("Handshake Erts -> World ~p ~c~n",[size(Data), H]),
+ loop_conn_setup(World, Erts);
+ {tcp, World, Data} ->
+ gen_tcp:send(Erts, Data),
+ io:format("World -> Erts ~p <<>>~n",[size(Data)]),
+ loop_conn(World, Erts);
+ {tcp, Erts, Data} ->
+ gen_tcp:send(World, Data),
+ io:format("Erts -> World ~p <<>>~n",[size(Data)]),
+ loop_conn(World, Erts);
+ Other ->
+ io:format("~p ~p~n",[?LINE, Other])
+ end.
+
+
+loop_conn(World, Erts) ->
+ receive
+ {tcp, World, Data = <<H, _/binary>>} ->
+ gen_tcp:send(Erts, Data),
+ io:format("World -> Erts ~p ~c~n",[size(Data), H]),
+ loop_conn(World, Erts);
+ {tcp, Erts, Data = <<H, _/binary>>} ->
+ gen_tcp:send(World, Data),
+ io:format("Erts -> World ~p ~c~n",[size(Data), H]),
+ loop_conn(World, Erts);
+ {tcp, World, Data} ->
+ gen_tcp:send(Erts, Data),
+ io:format("World -> Erts ~p <<>>~n",[size(Data)]),
+ loop_conn(World, Erts);
+ {tcp, Erts, Data} ->
+ gen_tcp:send(World, Data),
+ io:format("Erts -> World ~p <<>>~n",[size(Data)]),
+ loop_conn(World, Erts);
+
+ Other ->
+ io:format("~p ~p~n",[?LINE, Other])
+ end.
diff --git a/lib/ssl/src/inet_ssl_dist.erl b/lib/ssl/src/inet_ssl_dist.erl
index 6c0fbc0618..f4bcb593d0 100644
--- a/lib/ssl/src/inet_ssl_dist.erl
+++ b/lib/ssl/src/inet_ssl_dist.erl
@@ -31,9 +31,7 @@
-import(error_logger,[error_msg/2]).
--include("net_address.hrl").
-
-
+-include_lib("kernel/src/net_address.hrl").
-define(to_port(Socket, Data, Opts),
case ssl_prim:send(Socket, Data, Opts) of
@@ -44,9 +42,8 @@
R
end).
-
--include("dist.hrl").
--include("dist_util.hrl").
+-include_lib("kernel/src/dist.hrl").
+-include_lib("kernel/src/dist_util.hrl").
%% -------------------------------------------------------------
%% This function should return a valid childspec, so that