-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathhttps_proxy_c.erl
More file actions
129 lines (120 loc) · 4.78 KB
/
https_proxy_c.erl
File metadata and controls
129 lines (120 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
-module(https_proxy_c).
-export([start/0]).
-define(PROXY_C_PORT, 10088).
-define(PROXY_S_IP, "your.vps.ip.address").
-define(PROXY_S_PORT, 10099).
-define(PROXY_C_S_KEY, "your-secret-password").
start() ->
{ok, Lsock} = gen_tcp:listen(?PROXY_C_PORT, [binary, {packet, http}, {active, false}, {reuseaddr, true}]),
io:format("listen sock: ~w~n", [Lsock]),
accept(Lsock).
tunnel(Sock, Tsock) ->
Pid1 = spawn(fun F() ->
case gen_tcp:recv(Sock, 0) of
{ok, B} ->
io:format("data from sock arrive ~w ~w ~w~n", [byte_size(B), Sock, Tsock]),
case gen_tcp:send(Tsock, B) of
ok -> F();
{error, R} ->
io:format("error from tsock: ~p ~w ~w~n", [R, Tsock, Sock]),
gen_tcp:close(Tsock), gen_tcp:close(Sock)
end;
{error, R} ->
io:format("error from sock: ~p ~w ~w~n", [R, Sock, Tsock]),
gen_tcp:close(Sock), gen_tcp:close(Tsock)
end end),
gen_tcp:controlling_process(Sock, Pid1),
Pid2 = spawn(fun F() ->
case gen_tcp:recv(Tsock, 0) of
{ok, B} ->
io:format("data from tsock arrive ~w ~w ~w~n", [byte_size(B), Tsock, Sock]),
case gen_tcp:send(Sock, B) of
ok -> F();
{error, R} ->
io:format("error from sock: ~p ~w ~w~n", [R, Sock, Tsock]),
gen_tcp:close(Sock), gen_tcp:close(Tsock)
end;
{error, R} ->
io:format("error from tsock: ~p ~w ~w~n", [R, Tsock, Sock]),
gen_tcp:close(Tsock), gen_tcp:close(Sock)
end end),
gen_tcp:controlling_process(Tsock, Pid2).
encrypt_binary(Bin) ->
Seeds = [29,220,39,154,155,183,36,101,240,97,60,232,246,60,81,32,173,79,158,172],
fun F(_, <<>>) -> <<>>; F(Idx, Rest) ->
Seed = lists:nth(Idx rem 20 + 1, Seeds),
<<H, R/binary>> = Rest,
Val = (H + Seed) rem 256,
<<Val, (F(Idx + 1, R))/binary>>
end(0, Bin).
decrypt_binary(Bin) ->
Seeds = [29,220,39,154,155,183,36,101,240,97,60,232,246,60,81,32,173,79,158,172],
fun F(_, <<>>) -> <<>>; F(Idx, Rest) ->
Seed = lists:nth(Idx rem 20 + 1, Seeds),
<<H, R/binary>> = Rest,
if
H - Seed < 0 -> Val = 256 + H - Seed;
true -> Val = H - Seed
end,
<<Val, (F(Idx + 1, R))/binary>>
end(0, Bin).
recv_with_host(Sock, TargetHost) ->
inet:setopts(Sock, [{active, once}]),
receive
{http, Sock, http_eoh} ->
io:format("head end received: ~w ~w~n", [http_eoh, Sock]),
inet:setopts(Sock, [{packet, 0}]),
io:format("targethost................: ~s ~w~n", [TargetHost, Sock]),
case gen_tcp:connect(?PROXY_S_IP, ?PROXY_S_PORT, [binary, {active, false}, {packet, 4}]) of
{ok, Ssock} ->
io:format("connect to proxy server success: ~p ~w ~w~n", [?PROXY_S_IP, Ssock, Sock]),
InitReq = {init, TargetHost, 443, ?PROXY_C_S_KEY},
ok = gen_tcp:send(Ssock, encrypt_binary(term_to_binary(InitReq))),
{ok, Bin} = gen_tcp:recv(Ssock, 0),
InitRsp = binary_to_term(Bin),
io:format("recv init rsp from server: ~p ~w ~w~n", [InitRsp, Ssock, Sock]),
case gen_tcp:send(Sock, "HTTP/1.1 200 Connection Established\r\n\r\n") of
ok ->
io:format("send browser established success: ~w ~w~n", [Sock, Ssock]),
tunnel(Sock, Ssock);
{error, R} ->
io:format("send browser established failed: ~p ~w ~w~n", [R, Sock, Ssock]),
gen_tcp:close(Sock), gen_tcp:close(Ssock)
end;
{error, R} ->
io:format("connect to proxy server failed: ~p ~w ~w~n", [TargetHost, R, Sock]),
gen_tcp:close(Sock)
end;
{http, Sock, Data} ->
io:format("http data: ~p ~w~n", [Data, Sock]),
recv_with_host(Sock, TargetHost);
Other -> io:format("other in target: ~w ~w~n", [Other, Sock])
end.
recv(Sock) ->
inet:setopts(Sock, [{active, once}]),
receive
{http, Sock, {http_header, _, 'Host', _, Hostport} = Data} ->
io:format("http data: ~p ~w~n", [Data, Sock]),
[TargetHost|_] = string:split(Hostport, ":"),
recv_with_host(Sock, TargetHost);
{http, Sock, {http_error, R}} ->
io:format("http error: ~p~n", [R]),
gen_tcp:close(Sock);
{http, Sock, Data} ->
io:format("http data: ~p ~w~n", [Data, Sock]),
recv(Sock);
{tcp, Sock, Data} -> io:format("tcp data: ~p ~w~n", [Data, Sock]);
{tcp_passive, Sock} -> io:format("tcp passive: ~w~n", [Sock]);
{tcp_closed, Sock} ->
io:format("tcp closed: ~w~n", [Sock]);
{tcp_error, Sock, Reason} ->
io:format("tcp error reason: ~p ~w~n", [Reason, Sock]),
gen_tcp:close(Sock);
Other -> io:format("other in recv: ~p ~w~n", [Other, Sock])
end.
accept(Lsock) ->
{ok, Sock} = gen_tcp:accept(Lsock),
io:format("accept sock: ~w~n", [Sock]),
Pid = spawn(fun() -> recv(Sock) end),
gen_tcp:controlling_process(Sock, Pid),
accept(Lsock).