mirror of
https://github.com/seriyps/mtproto_proxy.git
synced 2026-05-13 08:46:46 +00:00
tests: add encoder and decoder for unencrypted mtproto messages
req_pq and resPQ messages
This commit is contained in:
parent
d9d812e9cf
commit
7b4c5dde9c
2 changed files with 109 additions and 6 deletions
|
|
@ -52,16 +52,16 @@ try_decode_packet_len(Len, LenStripped, St) ->
|
|||
{incomplete, St}
|
||||
end.
|
||||
|
||||
-spec encode_packet(binary(), codec()) -> {iodata(), codec()}.
|
||||
encode_packet(Bin, St) ->
|
||||
Size = byte_size(Bin),
|
||||
-spec encode_packet(iodata(), codec()) -> {iodata(), codec()}.
|
||||
encode_packet(Data, St) ->
|
||||
Size = iolist_size(Data),
|
||||
Len = Size div 4,
|
||||
Packet =
|
||||
case Len < 127 of
|
||||
true ->
|
||||
[Len | Bin];
|
||||
[Len | Data];
|
||||
false ->
|
||||
[<<127, Len:24/unsigned-little-integer>> | Bin]
|
||||
[<<127, Len:24/unsigned-little-integer>> | Data]
|
||||
end,
|
||||
{Packet, St}.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,17 @@
|
|||
send/2,
|
||||
recv_packet/2,
|
||||
recv_all/2,
|
||||
close/1]).
|
||||
close/1,
|
||||
ping_session/6]).
|
||||
|
||||
-export([unencrypted_cli_packet/1,
|
||||
unencrypted_cli_packet/3,
|
||||
parse_unencrypted_srv_packet/1]).
|
||||
-export([req_pq/0,
|
||||
res_pq_matches/2,
|
||||
ping/0,
|
||||
pong_matches/2]).
|
||||
|
||||
-export_type([client/0]).
|
||||
|
||||
-record(client,
|
||||
|
|
@ -128,3 +138,96 @@ tcp_recv_all_inner(Sock, Acc) ->
|
|||
|
||||
close(#client{sock = Sock}) ->
|
||||
ok = gen_tcp:close(Sock).
|
||||
|
||||
|
||||
ping_session(Host, Port, Secret, DcId, Protocol, Timeout) ->
|
||||
Cli0 = connect(Host, Port, Secret, DcId, Protocol),
|
||||
ReqPQ = req_pq(),
|
||||
Cli1 = send(unencrypted_cli_packet(ReqPQ), Cli0),
|
||||
{ok, Packet, Cli2} = recv_packet(Cli1, Timeout),
|
||||
ok = close(Cli2),
|
||||
{_MsgId, response, ResPQ} = parse_unencrypted_srv_packet(Packet),
|
||||
{res_pq_matches(ReqPQ, ResPQ),
|
||||
ReqPQ, ResPQ}.
|
||||
|
||||
%%
|
||||
%% Messages
|
||||
%%
|
||||
|
||||
%% @doc encodes payload as unencrypted client message
|
||||
%% https://core.telegram.org/mtproto/description#unencrypted-message
|
||||
unencrypted_cli_packet(Payload) ->
|
||||
Now = erlang:system_time(microsecond),
|
||||
%% Is 128 enough?
|
||||
PadSize = rand:uniform(128 div 4) * 4, % should be alined to 4b
|
||||
Padding = crypto:strong_rand_bytes(PadSize),
|
||||
unencrypted_cli_packet(Payload, Now, Padding).
|
||||
|
||||
unencrypted_cli_packet(Payload, Now, Pad) ->
|
||||
%% Client message identifiers are divisible by 4.
|
||||
Micro = 1000000,
|
||||
NowSec = Now div Micro,
|
||||
MicroFraction = Now rem Micro,
|
||||
MicroDiv4 = MicroFraction - (MicroFraction rem 4),
|
||||
%% MsgId = NowSec * (2 bsl 31) + MicroDiv4,
|
||||
[<<0:64,
|
||||
MicroDiv4:32/unsigned-little,
|
||||
NowSec:32/unsigned-little,
|
||||
(byte_size(Payload) + byte_size(Pad)):32/unsigned-little>>,
|
||||
Payload | Pad].
|
||||
|
||||
|
||||
%% @doc extracts payload from unencrypted server message
|
||||
parse_unencrypted_srv_packet(<<0:64, MsgId:64/unsigned-little,
|
||||
Size:32/unsigned-little,
|
||||
Payload:Size/binary>>) ->
|
||||
%% Server message identifiers modulo 4 yield 1 if the message is a response to a
|
||||
%% client message, and 3 otherwise.
|
||||
Kind =
|
||||
case MsgId rem 4 of
|
||||
1 -> response;
|
||||
3 -> event
|
||||
end,
|
||||
{MsgId, Kind, Payload}.
|
||||
|
||||
|
||||
|
||||
%% https://core.telegram.org/mtproto/serialize#base-types
|
||||
-define(int, 32/signed-little).
|
||||
-define(long, 64/signed-little).
|
||||
|
||||
-define(REQ_PQ, 16#60469778:?int).
|
||||
-define(RES_PQ, 16#05162463:?int).
|
||||
|
||||
%% @doc creates req_pq packet
|
||||
req_pq() ->
|
||||
%% req_pq#60469778 nonce:int128 = ResPQ;
|
||||
Nonce = <<(crypto:strong_rand_bytes(12)):12/binary,
|
||||
(erlang:unique_integer()):32/little>>,
|
||||
<<?REQ_PQ, Nonce:16/binary>>.
|
||||
|
||||
|
||||
%% @doc returns `true' if ResPQ nonce matches the nonce for ReqPQ
|
||||
%% @param ReqPQ: req_pq packet generated by req_pq/0
|
||||
%% @param ResPQ: resPQ packet received from server
|
||||
res_pq_matches(<<?REQ_PQ, Nonce:16/binary>>, <<?RES_PQ, Nonce:16/binary, _/binary>>) ->
|
||||
%% resPQ#05162463 nonce:int128 server_nonce:int128 pq:bytes \
|
||||
%% server_public_key_fingerprints:Vector<long> = ResPQ;
|
||||
true;
|
||||
res_pq_matches(_, _) ->
|
||||
false.
|
||||
|
||||
|
||||
-define(PING, 16#7abe77ec:?int).
|
||||
-define(PONG, 16#347773c5:?int).
|
||||
%% @doc constructs 'ping' message
|
||||
ping() ->
|
||||
%% ping#7abe77ec ping_id:long = Pong;
|
||||
PingId = erlang:unique_integer(),
|
||||
<<?PING, PingId:?long>>.
|
||||
|
||||
pong_matches(<<?PING, PingId:?long>>, <<?PONG, _MsgId1:?long, PingId:?long>>) ->
|
||||
%% pong#347773c5 msg_id:long ping_id:long = Pong;
|
||||
true;
|
||||
pong_matches(_, _) ->
|
||||
false.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue