mirror of
https://github.com/seriyps/mtproto_proxy.git
synced 2026-05-13 08:46:46 +00:00
Modernisations
* Add variable-length ClientHello * Make it compile on OTP 27+ * Upgrade OTP versions in CI
This commit is contained in:
parent
f9c2d32d4f
commit
0cc2e02c8c
10 changed files with 126 additions and 33 deletions
|
|
@ -33,7 +33,7 @@ connect(Host, Port, 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().
|
||||
mtp_codec:packet_codec() | {mtp_fake_tls, binary()} | {mtp_fake_tls, binary(), pos_integer()}) -> client().
|
||||
connect(Host, Port, Seed, Secret, DcId, Protocol0) ->
|
||||
Opts = [{packet, raw},
|
||||
{mode, binary},
|
||||
|
|
@ -51,6 +51,14 @@ connect(Host, Port, Seed, Secret, DcId, Protocol0) ->
|
|||
%% 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()};
|
||||
{mtp_fake_tls, Domain, TlsPacketLen} ->
|
||||
ClientHello = mtp_fake_tls:make_client_hello(Secret, Domain, TlsPacketLen),
|
||||
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),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
-include_lib("proper/include/proper.hrl").
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
|
||||
-export([prop_codec_small/1, prop_codec_big/1, prop_stream/1]).
|
||||
-export([prop_codec_small/1, prop_codec_big/1, prop_stream/1, prop_variable_length_hello/1]).
|
||||
|
||||
prop_codec_small(doc) ->
|
||||
"Tests that any binary below 65535 bytes can be encoded and decoded back as single frame".
|
||||
|
|
@ -60,3 +60,28 @@ decode_stream(BinStream, Codec, Acc) ->
|
|||
{ok, DecPacket, Tail, Codec1} ->
|
||||
decode_stream(Tail, Codec1, [DecPacket | Acc])
|
||||
end.
|
||||
|
||||
|
||||
prop_variable_length_hello(doc) ->
|
||||
"Tests that ClientHello with various packet lengths can be parsed correctly".
|
||||
|
||||
prop_variable_length_hello() ->
|
||||
?FORALL({TlsPacketLen, Secret, Domain},
|
||||
{proper_types:integer(512, 4096),
|
||||
proper_types:binary(16),
|
||||
<<"example.com">>},
|
||||
variable_length_hello(TlsPacketLen, Secret, Domain)).
|
||||
|
||||
variable_length_hello(TlsPacketLen, Secret, Domain) ->
|
||||
Timestamp = erlang:system_time(second),
|
||||
SessionId = crypto:strong_rand_bytes(32),
|
||||
ClientHello = mtp_fake_tls:make_client_hello(Timestamp, SessionId, Secret, Domain, TlsPacketLen),
|
||||
%% Verify packet has correct length
|
||||
?assertEqual(5 + TlsPacketLen, byte_size(ClientHello)),
|
||||
%% Verify handshake can be parsed
|
||||
{ok, _Response, Meta, _Codec} = mtp_fake_tls:from_client_hello(ClientHello, Secret),
|
||||
%% Verify metadata
|
||||
?assertEqual(SessionId, maps:get(session_id, Meta)),
|
||||
?assertEqual(Timestamp, maps:get(timestamp, Meta)),
|
||||
?assertEqual(Domain, maps:get(sni_domain, Meta)),
|
||||
true.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
echo_secure_case/1,
|
||||
echo_abridged_many_packets_case/1,
|
||||
echo_tls_case/1,
|
||||
echo_tls_long_hello_case/1,
|
||||
ipv6_connect_case/1,
|
||||
packet_too_large_case/1,
|
||||
policy_max_conns_case/1,
|
||||
|
|
@ -138,6 +139,25 @@ echo_tls_case(Cfg) when is_list(Cfg) ->
|
|||
ok = mtp_test_client:close(Cli1).
|
||||
|
||||
|
||||
%% @doc Test TLS handshake with long ClientHello (2000 bytes) to simulate newer Telegram clients
|
||||
echo_tls_long_hello_case({pre, Cfg}) ->
|
||||
setup_single(?FUNCTION_NAME, 10000 + ?LINE, #{}, Cfg);
|
||||
echo_tls_long_hello_case({post, Cfg}) ->
|
||||
stop_single(Cfg);
|
||||
echo_tls_long_hello_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),
|
||||
%% Test with 2000-byte ClientHello (newer Telegram clients send longer packets)
|
||||
Cli0 = mtp_test_client:connect(Host, Port, Secret, DcId, {mtp_fake_tls, <<"example.com">>, 2000}),
|
||||
Cli1 = ping(Cli0),
|
||||
?assertEqual(
|
||||
1, mtp_test_metric:get_tags(
|
||||
count, [?APP, protocol_ok, total], [?FUNCTION_NAME, mtp_secure_fake_tls])),
|
||||
ok = mtp_test_client:close(Cli1).
|
||||
|
||||
|
||||
%% @doc test that client trying to send too big packets will be force-disconnected
|
||||
packet_too_large_case({pre, Cfg}) ->
|
||||
setup_single(?FUNCTION_NAME, 10000 + ?LINE, #{}, Cfg);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue