Add fake-tls support to mtp_test_client; added TLS networking tests

parent 5fd6971f
This diff is collapsed.
...@@ -7,9 +7,7 @@ ...@@ -7,9 +7,7 @@
-module(mtp_obfuscated). -module(mtp_obfuscated).
-behaviour(mtp_codec). -behaviour(mtp_codec).
-export([client_create/3, -export([from_header/2,
client_create/4,
from_header/2,
new/4, new/4,
encrypt/2, encrypt/2,
decrypt/2, decrypt/2,
...@@ -17,6 +15,10 @@ ...@@ -17,6 +15,10 @@
encode_packet/2 encode_packet/2
]). ]).
-export([bin_rev/1]). -export([bin_rev/1]).
-ifdef(TEST).
-export([client_create/3,
client_create/4]).
-endif.
-export_type([codec/0]). -export_type([codec/0]).
...@@ -32,7 +34,7 @@ ...@@ -32,7 +34,7 @@
-opaque codec() :: #st{}. -opaque codec() :: #st{}.
-ifdef(TEST).
client_create(Secret, Protocol, DcId) -> client_create(Secret, Protocol, DcId) ->
client_create(crypto:strong_rand_bytes(58), client_create(crypto:strong_rand_bytes(58),
Secret, Protocol, DcId). Secret, Protocol, DcId).
...@@ -90,6 +92,7 @@ encode_protocol(mtp_secure) -> ...@@ -90,6 +92,7 @@ encode_protocol(mtp_secure) ->
%% 4byte %% 4byte
encode_dc_id(DcId) -> encode_dc_id(DcId) ->
<<DcId:16/signed-little-integer>>. <<DcId:16/signed-little-integer>>.
-endif.
%% @doc creates new obfuscated stream (MTProto proxy format) %% @doc creates new obfuscated stream (MTProto proxy format)
-spec from_header(binary(), binary()) -> {ok, integer(), mtp_codec:packet_codec(), codec()} -spec from_header(binary(), binary()) -> {ok, integer(), mtp_codec:packet_codec(), codec()}
......
...@@ -20,20 +20,43 @@ connect(Host, Port, Secret, DcId, Protocol) -> ...@@ -20,20 +20,43 @@ connect(Host, Port, Secret, DcId, Protocol) ->
Seed = crypto:strong_rand_bytes(58), Seed = crypto:strong_rand_bytes(58),
connect(Host, Port, Seed, Secret, DcId, Protocol). connect(Host, Port, Seed, Secret, DcId, Protocol).
connect(Host, Port, Seed, Secret, DcId, Protocol) -> -spec connect(inet:socket_address() | inet:hostname(),
inet:port_number(),
binary(), binary(), integer(),
mtp_codec:packet_codec() | {mtp_fake_tls, binary()}) -> client().
connect(Host, Port, Seed, Secret, DcId, Protocol0) ->
Opts = [{packet, raw}, Opts = [{packet, raw},
{mode, binary}, {mode, binary},
{active, false}, {active, false},
{buffer, 1024}, {buffer, 1024},
{send_timeout, 5000}], {send_timeout, 5000}],
{ok, Sock} = gen_tcp:connect(Host, Port, Opts, 1000), {ok, Sock} = gen_tcp:connect(Host, Port, Opts, 1000),
{Header, _, _, CryptoLayer} = mtp_obfuscated:client_create(Seed, Secret, Protocol, DcId), {Protocol, TlsEnabled, TlsSt} =
case Protocol0 of
{mtp_fake_tls, Domain} ->
ClientHello = mtp_fake_tls:make_client_hello(Secret, Domain),
ok = gen_tcp:send(Sock, ClientHello),
%% Let's hope whole server hello will arrive in a single chunk
{ok, ServerHello} = gen_tcp:recv(Sock, 0, 5000),
%% TODO: if Tail is not empty, use codec:push_back(first, ..)
{_HS, _CC, _D, <<>>} = mtp_fake_tls:parse_server_hello(ServerHello),
{mtp_secure, true, mtp_fake_tls:new()};
_ -> {Protocol0, false, undefined}
end,
{Header0, _, _, CryptoLayer} = mtp_obfuscated:client_create(Seed, Secret, Protocol, DcId),
NoopSt = mtp_noop_codec:new(),
%% First, create codec with just TLS (which might be noop as well) to encode "obfuscated" header
Codec0 = mtp_codec:new(mtp_noop_codec, NoopSt,
mtp_noop_codec, NoopSt,
TlsEnabled, TlsSt,
25 * 1024 * 1024),
{Header, Codec1} = mtp_codec:encode_packet(Header0, Codec0),
ok = gen_tcp:send(Sock, Header), ok = gen_tcp:send(Sock, Header),
PacketLayer = Protocol:new(), PacketLayer = Protocol:new(),
Codec = mtp_codec:new(mtp_obfuscated, CryptoLayer, Codec2 = mtp_codec:replace(crypto, mtp_obfuscated, CryptoLayer, Codec1),
Protocol, PacketLayer, false, undefined, 25 * 1024 * 1024), Codec3 = mtp_codec:replace(packet, Protocol, PacketLayer, Codec2),
#client{sock = Sock, #client{sock = Sock,
codec = Codec}. codec = Codec3}.
send(Data, #client{sock = Sock, codec = Codec} = Client) -> send(Data, #client{sock = Sock, codec = Codec} = Client) ->
{Enc, Codec1} = mtp_codec:encode_packet(Data, Codec), {Enc, Codec1} = mtp_codec:encode_packet(Data, Codec),
......
...@@ -46,7 +46,9 @@ command(#st{open = [], ever_opened = EO}) -> ...@@ -46,7 +46,9 @@ command(#st{open = [], ever_opened = EO}) ->
command(#st{open = L, ever_opened = EO}) -> command(#st{open = L, ever_opened = EO}) ->
proper_types:frequency( proper_types:frequency(
[ [
{1, {call, ?MODULE, connect, [EO, mtp_prop_gen:codec()]}}, {1, {call, ?MODULE, connect, [EO, proper_types:oneof(
[mtp_prop_gen:codec(),
{mtp_fake_tls, <<"en.wikipedia.org">>}])]}},
{5, {call, ?MODULE, echo_packet, [proper_types:oneof(L), proper_types:binary()]}}, {5, {call, ?MODULE, echo_packet, [proper_types:oneof(L), proper_types:binary()]}},
{2, {call, ?MODULE, close, [proper_types:oneof(L)]}}, {2, {call, ?MODULE, close, [proper_types:oneof(L)]}},
{2, {call, ?MODULE, ask_for_close, [proper_types:oneof(L)]}} {2, {call, ?MODULE, ask_for_close, [proper_types:oneof(L)]}}
...@@ -108,8 +110,9 @@ run_cmds(Cmds) -> ...@@ -108,8 +110,9 @@ run_cmds(Cmds) ->
?WHENFAIL(io:format("History: ~p\n" ?WHENFAIL(io:format("History: ~p\n"
"State: ~w\n" "State: ~w\n"
"ServerState: ~p\n" "ServerState: ~p\n"
"Metrics: ~p\n"
"Result: ~p\n", "Result: ~p\n",
[History, State, ServerState, Result]), [History, State, ServerState, Metrics, Result]),
proper:conjunction( proper:conjunction(
[{state_ok, check_state(State, ServerState, Metrics, ShimDump)}, [{state_ok, check_state(State, ServerState, Metrics, ShimDump)},
{result_ok, Result =:= ok}])). {result_ok, Result =:= ok}])).
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
-export([echo_secure_case/1, -export([echo_secure_case/1,
echo_abridged_many_packets_case/1, echo_abridged_many_packets_case/1,
echo_tls_case/1,
packet_too_large_case/1, packet_too_large_case/1,
downstream_size_backpressure_case/1, downstream_size_backpressure_case/1,
downstream_qlen_backpressure_case/1, downstream_qlen_backpressure_case/1,
...@@ -117,6 +118,24 @@ echo_abridged_many_packets_case(Cfg) when is_list(Cfg) -> ...@@ -117,6 +118,24 @@ echo_abridged_many_packets_case(Cfg) when is_list(Cfg) ->
[upstream_to_downstream])). [upstream_to_downstream])).
%% @doc tests that it's possible to connect and communicate using fake-tls protocol
echo_tls_case({pre, Cfg}) ->
setup_single(?FUNCTION_NAME, 10000 + ?LINE, #{}, Cfg);
echo_tls_case({post, Cfg}) ->
stop_single(Cfg);
echo_tls_case(Cfg) when is_list(Cfg) ->
DcId = ?config(dc_id, Cfg),
Host = ?config(mtp_host, Cfg),
Port = ?config(mtp_port, Cfg),
Secret = ?config(mtp_secret, Cfg),
Cli0 = mtp_test_client:connect(Host, Port, Secret, DcId, {mtp_fake_tls, <<"example.com">>}),
Data = crypto:strong_rand_bytes(64),
Cli1 = mtp_test_client:send(Data, Cli0),
{ok, Packet, Cli2} = mtp_test_client:recv_packet(Cli1, 1000),
ok = mtp_test_client:close(Cli2),
?assertEqual(Data, Packet).
%% @doc test that client trying to send too big packets will be force-disconnected %% @doc test that client trying to send too big packets will be force-disconnected
packet_too_large_case({pre, Cfg}) -> packet_too_large_case({pre, Cfg}) ->
setup_single(?FUNCTION_NAME, 10000 + ?LINE, #{}, Cfg); setup_single(?FUNCTION_NAME, 10000 + ?LINE, #{}, Cfg);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
{listen_ip, "127.0.0.1"}, {listen_ip, "127.0.0.1"},
{num_acceptors, 2}, {num_acceptors, 2},
{init_dc_connections, 1}, {init_dc_connections, 1},
{tls_allowed_domains, any},
{metric_backend, mtp_test_metric} {metric_backend, mtp_test_metric}
]}, ]},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment