You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
7.9 KiB

пре 9 година
  1. %%%-------------------------------------------------------------------
  2. %%% @author Chandru Mullaparthi <>
  3. %%% @copyright (C) 2016, Chandru Mullaparthi
  4. %%% @doc
  5. %%%
  6. %%% @end
  7. %%% Created : 19 Apr 2016 by Chandru Mullaparthi <>
  8. %%%-------------------------------------------------------------------
  9. -module(ibrowse_socks_server).
  10. -behaviour(gen_server).
  11. %% API
  12. -export([start/2, stop/1]).
  13. %% gen_server callbacks
  14. -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
  15. terminate/2, code_change/3]).
  16. -define(SERVER, ?MODULE).
  17. -record(state, {listen_port, listen_socket, auth_method}).
  18. -define(NO_AUTH, 0).
  19. -define(AUTH_USER_PW, 2).
  20. %%%===================================================================
  21. %%% API
  22. %%%===================================================================
  23. start(Port, Auth_method) ->
  24. Name = make_proc_name(Port),
  25. gen_server:start({local, Name}, ?MODULE, [Port, Auth_method], []).
  26. stop(Port) ->
  27. make_proc_name(Port) ! stop.
  28. make_proc_name(Port) ->
  29. list_to_atom("ibrowse_socks_server_" ++ integer_to_list(Port)).
  30. %%%===================================================================
  31. %%% gen_server callbacks
  32. %%%===================================================================
  33. init([Port, Auth_method]) ->
  34. State = #state{listen_port = Port, auth_method = Auth_method},
  35. {ok, Sock} = gen_tcp:listen(State#state.listen_port, [{active, false}, binary, {reuseaddr, true}]),
  36. self() ! accept_connection,
  37. process_flag(trap_exit, true),
  38. {ok, State#state{listen_socket = Sock}}.
  39. handle_call(_Request, _From, State) ->
  40. Reply = ok,
  41. {reply, Reply, State}.
  42. handle_cast(_Msg, State) ->
  43. {noreply, State}.
  44. handle_info(accept_connection, State) ->
  45. case gen_tcp:accept(State#state.listen_socket, 1000) of
  46. {error, timeout} ->
  47. self() ! accept_connection,
  48. {noreply, State};
  49. {ok, Socket} ->
  50. Pid = proc_lib:spawn_link(fun() ->
  51. socks_server_loop(Socket, State#state.auth_method)
  52. end),
  53. gen_tcp:controlling_process(Socket, Pid),
  54. Pid ! ready,
  55. self() ! accept_connection,
  56. {noreply, State};
  57. _Err ->
  58. {stop, normal, State}
  59. end;
  60. handle_info(stop, State) ->
  61. {stop, normal, State};
  62. handle_info(_Info, State) ->
  63. {noreply, State}.
  64. terminate(_Reason, _State) ->
  65. ok.
  66. code_change(_OldVsn, State, _Extra) ->
  67. {ok, State}.
  68. %%%===================================================================
  69. %%% Internal functions
  70. %%%===================================================================
  71. socks_server_loop(In_socket, Auth_method) ->
  72. receive
  73. ready ->
  74. socks_server_loop(In_socket, Auth_method, <<>>, unauth)
  75. end.
  76. socks_server_loop(In_socket, Auth_method, Acc, unauth) ->
  77. inet:setopts(In_socket, [{active, once}]),
  78. receive
  79. {tcp, In_socket, Data} ->
  80. Acc_1 = list_to_binary([Acc, Data]),
  81. case Acc_1 of
  82. <<5, ?NO_AUTH>> when Auth_method == ?NO_AUTH ->
  83. ok = gen_tcp:send(In_socket, <<5, ?NO_AUTH>>),
  84. socks_server_loop(In_socket, Auth_method, <<>>, auth_done);
  85. <<5, Num_auth_methods, Auth_methods:Num_auth_methods/binary>> ->
  86. case lists:member(Auth_method, binary_to_list(Auth_methods)) of
  87. true ->
  88. ok = gen_tcp:send(In_socket, <<5, Auth_method>>),
  89. Conn_state = case Auth_method of
  90. ?NO_AUTH -> auth_done;
  91. _ -> auth_pending
  92. end,
  93. socks_server_loop(In_socket, Auth_method, <<>>, Conn_state);
  94. false ->
  95. ok = gen_tcp:send(In_socket, <<5, 16#ff>>),
  96. gen_tcp:close(In_socket)
  97. end;
  98. _ ->
  99. ok = gen_tcp:send(In_socket, <<5, 0>>),
  100. gen_tcp:close(In_socket)
  101. end;
  102. {tcp_closed, In_socket} ->
  103. ok;
  104. {tcp_error, In_socket, _Rsn} ->
  105. ok
  106. end;
  107. socks_server_loop(In_socket, Auth_method, Acc, auth_pending) ->
  108. inet:setopts(In_socket, [{active, once}]),
  109. receive
  110. {tcp, In_socket, Data} ->
  111. Acc_1 = list_to_binary([Acc, Data]),
  112. case Acc_1 of
  113. <<1, U_len, Username:U_len/binary, P_len, Password:P_len/binary>> ->
  114. case check_user_pw(Username, Password) of
  115. ok ->
  116. ok = gen_tcp:send(In_socket, <<1, 0>>),
  117. socks_server_loop(In_socket, Auth_method, <<>>, auth_done);
  118. notok ->
  119. ok = gen_tcp:send(In_socket, <<1, 1>>),
  120. gen_tcp:close(In_socket)
  121. end;
  122. _ ->
  123. socks_server_loop(In_socket, Auth_method, Acc_1, auth_pending)
  124. end;
  125. {tcp_closed, In_socket} ->
  126. ok;
  127. {tcp_error, In_socket, _Rsn} ->
  128. ok
  129. end;
  130. socks_server_loop(In_socket, Auth_method, Acc, auth_done) ->
  131. inet:setopts(In_socket, [{active, once}]),
  132. receive
  133. {tcp, In_socket, Data} ->
  134. Acc_1 = list_to_binary([Acc, Data]),
  135. case Acc_1 of
  136. <<5, 1, 0, Addr_type, Dest_ip:4/binary, Dest_port:16>> when Addr_type == 1->
  137. handle_connect(In_socket, Addr_type, Dest_ip, Dest_port);
  138. <<5, 1, 0, Addr_type, Dest_len, Dest_hostname:Dest_len/binary, Dest_port:16>> when Addr_type == 3 ->
  139. handle_connect(In_socket, Addr_type, Dest_hostname, Dest_port);
  140. <<5, 1, 0, Addr_type, Dest_ip:16/binary, Dest_port:16>> when Addr_type == 4->
  141. handle_connect(In_socket, Addr_type, Dest_ip, Dest_port);
  142. _ ->
  143. socks_server_loop(In_socket, Auth_method, Acc_1, auth_done)
  144. end;
  145. {tcp_closed, In_socket} ->
  146. ok;
  147. {tcp_error, In_socket, _Rsn} ->
  148. ok
  149. end.
  150. handle_connect(In_socket, Addr_type, Dest_host, Dest_port) ->
  151. Dest_host_1 = case Addr_type of
  152. 1 ->
  153. list_to_tuple(binary_to_list(Dest_host));
  154. 3 ->
  155. binary_to_list(Dest_host);
  156. 4 ->
  157. list_to_tuple(binary_to_list(Dest_host))
  158. end,
  159. case gen_tcp:connect(Dest_host_1, Dest_port, [binary, {active, once}]) of
  160. {ok, Out_socket} ->
  161. Addr = case Addr_type of
  162. 1 ->
  163. <<Dest_host/binary, Dest_port:16>>;
  164. 3 ->
  165. Len = size(Dest_host),
  166. <<Len, Dest_host/binary, Dest_port:16>>;
  167. 4 ->
  168. <<Dest_host/binary, Dest_port:16>>
  169. end,
  170. ok = gen_tcp:send(In_socket, <<5, 0, 0, Addr_type, Addr/binary>>),
  171. inet:setopts(In_socket, [{active, once}]),
  172. inet:setopts(Out_socket, [{active, once}]),
  173. connected_loop(In_socket, Out_socket);
  174. _Err ->
  175. ok = gen_tcp:send(<<5, 1>>),
  176. gen_tcp:close(In_socket)
  177. end.
  178. check_user_pw(<<"user">>, <<"password">>) ->
  179. ok;
  180. check_user_pw(_, _) ->
  181. notok.
  182. connected_loop(In_socket, Out_socket) ->
  183. receive
  184. {tcp, In_socket, Data} ->
  185. inet:setopts(In_socket, [{active, once}]),
  186. ok = gen_tcp:send(Out_socket, Data),
  187. connected_loop(In_socket, Out_socket);
  188. {tcp, Out_socket, Data} ->
  189. inet:setopts(Out_socket, [{active, once}]),
  190. ok = gen_tcp:send(In_socket, Data),
  191. connected_loop(In_socket, Out_socket);
  192. _ ->
  193. ok
  194. end.