Guest User

Untitled

a guest
Jan 17th, 2018
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.33 KB | None | 0 0
  1. #!/usr/bin/env escript
  2.  
  3. cDS_PACKET_RELAY_DELAY() -> 1. % delay inserted between splitted segments sent by downstream (in ms)
  4. cUS_PACKET_RELAY_DELAY() -> 1. % delay inserted between splitted segments sent by upstream (in ms)
  5. cSPLIT_DS_SEGMENT_LEN() -> 1. % downstream segment length to split into (in byte)
  6. cSPLIT_US_SEGMENT_LEN() -> 1. % upstream segment length to split into (in byte)
  7. cSPLIT_DS_PACKET() -> true. % whether split packet sent by downstream into segments before relaying to upstream
  8. cSPLIT_US_PACKET() -> true. % whether split packet sent by upstream into segments before relaying to downstream
  9. cFORCE_ACCURATE_SPLIT() -> false. % whether force accurate splitting (don't relay if there's not enough data for a segment)
  10. cCLOSE_INSTEAD_OF_DELAY() -> false. % close upstream/downstream connection instead of delay a certain time when packet is being splitting
  11. cDEFAULT_DEST_ADDR() -> {127, 0, 0, 1}.
  12. cLSOCK_OPTS() -> [binary, {packet, 0}, {reuseaddr, true}]. % Listening socket default options
  13. cCSOCK_OPTS() -> [binary, {packet, 0}, {nodelay, true}]. % Client socket default options (upstream/downstream)
  14. main([Src, Dest]) ->
  15. SrcPort = list_to_integer(Src),
  16. {DestAddr, DestPort} = parse_addr(Dest),
  17. run_proxy(SrcPort, DestAddr, DestPort);
  18. main(_) -> usage().
  19. run_proxy(SP, DA, DP) ->
  20. io:format("Proxy tcp traffic from port ~b to ~p:~b~n", [SP, DA, DP]),
  21. {ok, LS} = gen_tcp:listen(SP, [{active, false} | cLSOCK_OPTS()]),
  22. proxy_server_loop(LS, DA, DP).
  23. proxy_server_loop(LSock, DA, DP) ->
  24. {ok, DS} = gen_tcp:accept(LSock),
  25. {ok, {SAddr, SPort}} = inet:peername(DS),
  26. {ok, {DAddr, DPort}} = inet:sockname(DS),
  27. io:format("*** Incoming connection from ~p:~b to ~p:~b~n", [SAddr, SPort, DAddr, DPort]),
  28. Pid = spawn(
  29. fun () ->
  30. receive start -> ok end,
  31. ok = inet:setopts(DS, [{active, true} | cCSOCK_OPTS()]),
  32. run_proxy_client(DS, DA, DP),
  33. gen_tcp:close(DS)
  34. end
  35. ),
  36. ok = gen_tcp:controlling_process(DS, Pid),
  37. Pid ! start,
  38. proxy_server_loop(LSock, DA, DP).
  39. run_proxy_client(DS, DA, DP) ->
  40. {ok, US} = gen_tcp:connect(DA, DP, [{active, true} | cCSOCK_OPTS()]),
  41. proxy_client_loop(DS, US),
  42. gen_tcp:close(US).
  43. proxy_client_loop(DS, US) ->
  44. receive
  45. {tcp, DS, Data} ->
  46. relay_downstream_packet(DS, US, Data, false),
  47. proxy_client_loop(DS, US);
  48. {tcp_error, DS, Reason} ->
  49. io:format("*** Error occured on downstream socket: ~p~n", [Reason]),
  50. % flushing all pending downstream packets to upstream socket
  51. relay_downstream_packet(DS, US, <<>>, true),
  52. done;
  53. {tcp_closed, DS} ->
  54. io:format("*** Downstream socket closed~n"),
  55. % flushing all pending downstream packets to upstream socket
  56. relay_downstream_packet(DS, US, <<>>, true),
  57. done;
  58. {tcp, US, Data} ->
  59. relay_upstream_packet(DS, US, Data, false),
  60. proxy_client_loop(DS, US);
  61. {tcp_error, US, Reason} ->
  62. io:format("*** Error occured on upstream socket: ~p~n", [Reason]),
  63. % flushing all pending upstream packets to downstream socket
  64. relay_upstream_packet(DS, US, <<>>, true),
  65. done;
  66. {tcp_closed, US} ->
  67. io:format("*** Upstream socket closed~n"),
  68. % flushing all pending upstream packets to downstream socket
  69. relay_upstream_packet(DS, US, <<>>, true),
  70. done;
  71. Other ->
  72. io:format("*** Invalid message: ~p~n", [Other]),
  73. proxy_client_loop(DS, US)
  74. end.
  75. usage() ->
  76. io:format("Usage: etcproxy <src port> [<dest addr>:]<dest port>~n").
  77. parse_addr(L) ->
  78. case string:tokens(L, ":") of
  79. [PortL] ->
  80. Addr = cDEFAULT_DEST_ADDR(),
  81. Port = list_to_integer(PortL),
  82. {Addr, Port};
  83. [AddrL, PortL] ->
  84. {ok, Addr} = inet_parse:ipv4_address(AddrL),
  85. Port = list_to_integer(PortL),
  86. {Addr, Port};
  87. _ ->
  88. erlang:error("invalid destination", L)
  89. end.
  90. relay_downstream_packet(DS, US, Data, Flush) ->
  91. io:format("*** Proxy ~b bytes from downstream to upstream: ~n~p~n", [byte_size(Data), Data]),
  92. SplitDsPacket = cSPLIT_DS_PACKET(),
  93. CloseInsteadOfDelay = cCLOSE_INSTEAD_OF_DELAY(),
  94. SegSize = if
  95. SplitDsPacket -> cSPLIT_DS_SEGMENT_LEN();
  96. true -> 0
  97. end,
  98. BinL = merge_packet('downstream', Data, SegSize, cFORCE_ACCURATE_SPLIT(), Flush),
  99. % io:format("~p~n", [BinL]),
  100. if SplitDsPacket and CloseInsteadOfDelay -> % send the first packet, then close connection
  101. gen_tcp:send(US, hd(BinL)),
  102. gen_tcp:close(US),
  103. gen_tcp:close(DS);
  104. SegSize =:= 0 -> % no splitting occured, send data immediately without delay
  105. gen_tcp:send(US, BinL);
  106. true -> % send all packets to upstream with delay inserted among them
  107. lists:foreach(
  108. fun (Bin) ->
  109. gen_tcp:send(US, Bin),
  110. % Emulate network packet delay
  111. sleep(cDS_PACKET_RELAY_DELAY())
  112. end,
  113. BinL
  114. )
  115. end,
  116. io:format("*** Transferred~n"),
  117. ok.
  118. relay_upstream_packet(DS, US, Data, Flush) ->
  119. io:format("*** Proxy ~b bytes from upstream to downstream: ~n~p~n", [byte_size(Data), Data]),
  120. SplitUsPacket = cSPLIT_US_PACKET(),
  121. CloseInsteadOfDelay = cCLOSE_INSTEAD_OF_DELAY(),
  122. SegSize = if
  123. SplitUsPacket -> cSPLIT_US_SEGMENT_LEN();
  124. true -> 0
  125. end,
  126. BinL = merge_packet('upstream', Data, SegSize, cFORCE_ACCURATE_SPLIT(), Flush),
  127. % io:format("~p~n", [BinL]),
  128. if SplitUsPacket and CloseInsteadOfDelay -> % send the first packet, then close connection
  129. gen_tcp:send(DS, hd(BinL)),
  130. gen_tcp:close(US),
  131. gen_tcp:close(DS);
  132. SegSize =:= 0 -> % no splitting occured, send data immediately without delay
  133. gen_tcp:send(DS, BinL);
  134. true -> % send all packets to downstream with delay inserted among them
  135. lists:foreach(
  136. fun (Bin) ->
  137. gen_tcp:send(DS, Bin),
  138. % Emulate network packet delay
  139. sleep(cUS_PACKET_RELAY_DELAY())
  140. end,
  141. BinL
  142. )
  143. end,
  144. io:format("*** Transferred~n"),
  145. ok.
  146. % @doc Merge new upstream / downstream packet with previous remaining data, and
  147. % return those data which can be sent to downstream / upstream. If 'Flush' is
  148. % true, the new packet along with all remaining data will be returned, in order
  149. % to flush buffered data.
  150. % @end
  151. merge_packet(Key, Data, SegSize, AccuSplit, Flush) ->
  152. PrevB = case get(Key) of
  153. undefined -> <<>>;
  154. Val -> Val
  155. end,
  156. if Flush -> % flush previous remaining data along with current packet
  157. put(Key, <<>>),
  158. [iolist_to_binary([PrevB, Data])];
  159. true ->
  160. if SegSize > 0 -> % need splitting to segments
  161. {Segs, Remain} = split_to_segments(
  162. SegSize,
  163. iolist_to_binary([PrevB, Data])
  164. ),
  165. if AccuSplit -> % force accurate splitting
  166. put(Key, Remain),
  167. Segs;
  168. true -> % no accurate splitting, return data even if it's not long enough for a segment
  169. put(Key, <<>>),
  170. lists:flatten([Segs, Remain])
  171. end;
  172. true -> % no limiting to data length
  173. put(Key, <<>>),
  174. [iolist_to_binary([PrevB, Data])]
  175. end
  176. end.
  177. split_to_segments(N, Bin) when N > 0 -> split_to_segments(N, Bin, {[], <<>>}).
  178. split_to_segments(_, <<>>, {L, Remain}) -> {lists:reverse(L), Remain};
  179. split_to_segments(N, Bin, {L, _}) when byte_size(Bin) < N -> split_to_segments(N, <<>>, {L, Bin});
  180. split_to_segments(N, Bin, {L, _}) ->
  181. <<Seg:N/binary, Remain/binary>> = Bin,
  182. split_to_segments(N, Remain, {[Seg | L], <<>>}).
  183. sleep(N) when N >= 0 ->
  184. receive
  185. after N -> ok
  186. end.
Add Comment
Please, Sign In to add comment