diff options
-rw-r--r-- | lib/ssl/inet_proxy_dist.erl | 228 | ||||
-rw-r--r-- | lib/ssl/proxy_server.erl | 218 | ||||
-rw-r--r-- | lib/ssl/src/inet_ssl_dist.erl | 9 |
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 |